Skip to content

Commit

Permalink
Rollup merge of #96727 - oli-obk:no_expect, r=lcnr
Browse files Browse the repository at this point in the history
Make TAIT behave exactly like RPIT

fixes #96552

This makes type-alias-impl-trait behave like return-position-impl-trait. Unfortunately it also causes some cases to stop compiling due to "needing type annotations" and makes panicking cause fallback for the hidden type to `()`.

All of these are addressable, but we should probably address them for RPIT and TAIT together

r? ``@lcnr``
  • Loading branch information
matthiaskrgr authored Jun 29, 2022
2 parents ddcbba0 + c33b127 commit 48170d5
Show file tree
Hide file tree
Showing 57 changed files with 378 additions and 246 deletions.
21 changes: 7 additions & 14 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use hir::{HirId, OpaqueTyOrigin};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::{
Expand Down Expand Up @@ -44,30 +44,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
body_id: HirId,
span: Span,
code: ObligationCauseCode<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> InferOk<'tcx, Ty<'tcx>> {
if !ty.has_opaque_types() {
return InferOk { value: ty, obligations: vec![] };
}
let mut obligations = vec![];
let replace_opaque_type = |def_id| self.opaque_type_origin(def_id, span).is_some();
let value = ty.fold_with(&mut ty::fold::BottomUpFolder {
tcx: self.tcx,
lt_op: |lt| lt,
ct_op: |ct| ct,
ty_op: |ty| match *ty.kind() {
// Closures can't create hidden types for opaque types of their parent, as they
// do not have all the outlives information available. Also `type_of` looks for
// hidden types in the owner (so the closure's parent), so it would not find these
// definitions.
ty::Opaque(def_id, _substs)
if matches!(
self.opaque_type_origin(def_id, span),
Some(OpaqueTyOrigin::FnReturn(..))
) =>
{
let span = if span.is_dummy() { self.tcx.def_span(def_id) } else { span };
let cause = ObligationCause::new(span, body_id, code.clone());
ty::Opaque(def_id, _substs) if replace_opaque_type(def_id) => {
let def_span = self.tcx.def_span(def_id);
let span = if span.contains(def_span) { def_span } else { span };
let code = traits::ObligationCauseCode::OpaqueReturnType(None);
let cause = ObligationCause::new(span, body_id, code);
// FIXME(compiler-errors): We probably should add a new TypeVariableOriginKind
// for opaque types, and then use that kind to fix the spans for type errors
// that we see later on.
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
declared_ret_ty,
body.value.hir_id,
DUMMY_SP,
traits::ObligationCauseCode::OpaqueReturnType(None),
decl.output.span(),
param_env,
));
// If we replaced declared_ret_ty with infer vars, then we must be infering
Expand Down
118 changes: 59 additions & 59 deletions compiler/rustc_typeck/src/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult};
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
use rustc_span::DUMMY_SP;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::ArgKind;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
Expand Down Expand Up @@ -429,14 +427,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// in this binder we are creating.
assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST));
let bound_sig = expected_sig.sig.map_bound(|sig| {
let output = self.hide_parent_opaque_types(
sig.output(),
expected_sig.cause_span.unwrap_or(DUMMY_SP),
body.id().hir_id,
);
self.tcx.mk_fn_sig(
sig.inputs().iter().cloned(),
output,
sig.output(),
sig.c_variadic,
hir::Unsafety::Normal,
Abi::RustCall,
Expand Down Expand Up @@ -608,23 +601,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// function.
Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => {
debug!("closure is async fn body");
self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| {
// AFAIK, deducing the future output
// always succeeds *except* in error cases
// like #65159. I'd like to return Error
// here, but I can't because I can't
// easily (and locally) prove that we
// *have* reported an
// error. --nikomatsakis
astconv.ty_infer(None, decl.output.span())
})
self.deduce_future_output_from_obligations(expr_def_id, body.id().hir_id)
.unwrap_or_else(|| {
// AFAIK, deducing the future output
// always succeeds *except* in error cases
// like #65159. I'd like to return Error
// here, but I can't because I can't
// easily (and locally) prove that we
// *have* reported an
// error. --nikomatsakis
astconv.ty_infer(None, decl.output.span())
})
}

_ => astconv.ty_infer(None, decl.output.span()),
},
};
let supplied_return =
self.hide_parent_opaque_types(supplied_return, decl.output.span(), body.id().hir_id);

let result = ty::Binder::bind_with_vars(
self.tcx.mk_fn_sig(
Expand All @@ -645,67 +637,75 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
result
}

fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
let InferOk { value, obligations } = self.replace_opaque_types_with_inference_vars(
ty,
body_id,
span,
ObligationCauseCode::MiscObligation,
self.param_env,
);
self.register_predicates(obligations);
value
}

/// Invoked when we are translating the generator that results
/// from desugaring an `async fn`. Returns the "sugared" return
/// type of the `async fn` -- that is, the return type that the
/// user specified. The "desugared" return type is an `impl
/// Future<Output = T>`, so we do this by searching through the
/// obligations to extract the `T`.
#[instrument(skip(self), level = "debug")]
fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty<'tcx>> {
fn deduce_future_output_from_obligations(
&self,
expr_def_id: DefId,
body_id: hir::HirId,
) -> Option<Ty<'tcx>> {
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn")
});

let ret_ty = ret_coercion.borrow().expected_ty();
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
let (def_id, substs) = match *ret_ty.kind() {
ty::Opaque(def_id, substs) => (def_id, substs),

let get_future_output = |predicate: ty::Predicate<'tcx>, span| {
// Search for a pending obligation like
//
// `<R as Future>::Output = T`
//
// where R is the return type we are expecting. This type `T`
// will be our output.
let bound_predicate = predicate.kind();
if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
self.deduce_future_output_from_projection(
span,
bound_predicate.rebind(proj_predicate),
)
} else {
None
}
};

let output_ty = match *ret_ty.kind() {
ty::Infer(ty::TyVar(ret_vid)) => {
self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
get_future_output(obligation.predicate, obligation.cause.span)
})?
}
ty::Opaque(def_id, substs) => self
.tcx
.bound_explicit_item_bounds(def_id)
.transpose_iter()
.map(|e| e.map_bound(|e| *e).transpose_tuple2())
.find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?,
ty::Error(_) => return None,
_ => span_bug!(
self.tcx.def_span(expr_def_id),
"async fn generator return type not an inference variable"
),
};

let item_bounds = self.tcx.bound_explicit_item_bounds(def_id);

// Search for a pending obligation like
//
// `<R as Future>::Output = T`
//
// where R is the return type we are expecting. This type `T`
// will be our output.
let output_ty = item_bounds
.transpose_iter()
.map(|e| e.map_bound(|e| *e).transpose_tuple2())
.find_map(|(predicate, span)| {
let bound_predicate = predicate.subst(self.tcx, substs).kind();
if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder()
{
self.deduce_future_output_from_projection(
span.0,
bound_predicate.rebind(proj_predicate),
)
} else {
None
}
});
// async fn that have opaque types in their return type need to redo the conversion to inference variables
// as they fetch the still opaque version from the signature.
let InferOk { value: output_ty, obligations } = self
.replace_opaque_types_with_inference_vars(
output_ty,
body_id,
self.tcx.def_span(expr_def_id),
self.param_env,
);
self.register_predicates(obligations);

debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
output_ty
Some(output_ty)
}

/// Given a projection like
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Thing for AssocNoCopy {
type Out = Box<dyn Bar<Assoc: Copy>>;

fn func() -> Self::Out {
Box::new(AssocNoCopy)
//~^ ERROR the trait bound `String: Copy` is not satisfied
Box::new(AssocNoCopy)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
error[E0277]: the trait bound `String: Copy` is not satisfied
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:33:9
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:32:18
|
LL | Box::new(AssocNoCopy)
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
= note: required for the cast from `AssocNoCopy` to the object type `dyn Bar<Assoc = <AssocNoCopy as Thing>::Out::{opaque#0}>`
LL | fn func() -> Self::Out {
| ^^^^^^^^^ the trait `Copy` is not implemented for `String`

error: aborting due to previous error

Expand Down
1 change: 1 addition & 0 deletions src/test/ui/async-await/issues/issue-65159.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ async fn copy() -> Result<()>
//~^ ERROR this enum takes 2 generic arguments
{
Ok(())
//~^ ERROR type annotations needed
}

fn main() { }
16 changes: 14 additions & 2 deletions src/test/ui/async-await/issues/issue-65159.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ help: add missing generic argument
LL | async fn copy() -> Result<(), E>
| +++

error: aborting due to previous error
error[E0282]: type annotations needed
--> $DIR/issue-65159.rs:8:5
|
LL | Ok(())
| ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
|
help: consider specifying the generic arguments
|
LL | Ok::<(), E>(())
| +++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0107`.
Some errors have detailed explanations: E0107, E0282.
For more information about an error, try `rustc --explain E0107`.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
//~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
//~^^ ERROR this struct takes 1 generic argument but 0 generic arguments were supplied
LockedMarket(generator.lock().unwrap().buy())
//~^ ERROR cannot return value referencing temporary
}

struct LockedMarket<T>(T);
Expand Down
18 changes: 14 additions & 4 deletions src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_>
| expected 0 lifetime arguments
|
note: struct defined here, with 0 lifetime parameters
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8
|
LL | struct LockedMarket<T>(T);
| ^^^^^^^^^^^^
Expand All @@ -19,7 +19,7 @@ LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_>
| ^^^^^^^^^^^^ expected 1 generic argument
|
note: struct defined here, with 1 generic parameter: `T`
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8
|
LL | struct LockedMarket<T>(T);
| ^^^^^^^^^^^^ -
Expand All @@ -28,6 +28,16 @@ help: add missing generic argument
LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_, T> {
| +++

error: aborting due to 2 previous errors
error[E0515]: cannot return value referencing temporary value
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:19:5
|
LL | LockedMarket(generator.lock().unwrap().buy())
| ^^^^^^^^^^^^^-------------------------^^^^^^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0107`.
Some errors have detailed explanations: E0107, E0515.
For more information about an error, try `rustc --explain E0107`.
9 changes: 3 additions & 6 deletions src/test/ui/chalkify/bugs/async.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,10 @@ LL | T: Generator<ResumeTy, Yield = ()>,
| ^^^^^^^^^^ required by this bound in `std::future::from_generator`

error[E0280]: the requirement `<impl Future<Output = u32> as Future>::Output == u32` is not satisfied
--> $DIR/async.rs:7:29
--> $DIR/async.rs:7:25
|
LL | async fn foo(x: u32) -> u32 {
| _____________________________^
LL | | x
LL | | }
| |_^
LL | async fn foo(x: u32) -> u32 {
| ^^^

error: aborting due to 3 previous errors

Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/generic-associated-types/bugs/issue-89008.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0271]: type mismatch resolving `<Empty<_> as Stream>::Item == Repr`
--> $DIR/issue-89008.rs:40:9
--> $DIR/issue-89008.rs:39:43
|
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {
| ---- this type parameter
LL | async {empty()}
| ^^^^^^^^^^^^^^^ type mismatch resolving `<Empty<_> as Stream>::Item == Repr`
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Empty<_> as Stream>::Item == Repr`
| |
| this type parameter
|
note: expected this to be `()`
--> $DIR/issue-89008.rs:18:17
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/impl-trait/issue-55872-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ impl<S: Default> Bar for S {

fn foo<T: Default>() -> Self::E {
//~^ ERROR impl has stricter requirements than trait
(S::default(), T::default())
//~^ ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277]
//~| ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277]
//~| ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277]
(S::default(), T::default())
}
}

Expand Down
Loading

0 comments on commit 48170d5

Please sign in to comment.