diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
8 files changed, 261 insertions, 143 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 4c4cd2af779..3be53a6591d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -394,10 +394,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Infer(ty::FloatVar(_)) => { // This causes a compiler error if any new float kinds are added. - let (ty::FloatTy::F32 | ty::FloatTy::F64); + let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128); let possible_floats = [ + SimplifiedType::Float(ty::FloatTy::F16), SimplifiedType::Float(ty::FloatTy::F32), SimplifiedType::Float(ty::FloatTy::F64), + SimplifiedType::Float(ty::FloatTy::F128), ]; for simp in possible_floats { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 3b902dd80f5..af533d8db71 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -281,7 +281,58 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( } // Coroutine-closures don't implement `Fn` traits the normal way. - ty::CoroutineClosure(..) => Err(NoSolution), + // Instead, they always implement `FnOnce`, but only implement + // `FnMut`/`Fn` if they capture no upvars, since those may borrow + // from the closure. + ty::CoroutineClosure(def_id, args) => { + let args = args.as_coroutine_closure(); + let kind_ty = args.kind_ty(); + let sig = args.coroutine_closure_sig().skip_binder(); + + let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + if !closure_kind.extends(goal_kind) { + return Err(NoSolution); + } + + // If `Fn`/`FnMut`, we only implement this goal if we + // have no captures. + let no_borrows = match args.tupled_upvars_ty().kind() { + ty::Tuple(tys) => tys.is_empty(), + ty::Error(_) => false, + _ => bug!("tuple_fields called on non-tuple"), + }; + if closure_kind != ty::ClosureKind::FnOnce && !no_borrows { + return Err(NoSolution); + } + + coroutine_closure_to_certain_coroutine( + tcx, + goal_kind, + // No captures by ref, so this doesn't matter. + tcx.lifetimes.re_static, + def_id, + args, + sig, + ) + } else { + // Closure kind is not yet determined, so we return ambiguity unless + // the expected kind is `FnOnce` as that is always implemented. + if goal_kind != ty::ClosureKind::FnOnce { + return Ok(None); + } + + coroutine_closure_to_ambiguous_coroutine( + tcx, + goal_kind, // No captures by ref, so this doesn't matter. + tcx.lifetimes.re_static, + def_id, + args, + sig, + ) + }; + + Ok(Some(args.coroutine_closure_sig().rebind((sig.tupled_inputs_ty, coroutine_ty)))) + } ty::Bool | ty::Char @@ -313,6 +364,19 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( } } +/// Relevant types for an async callable, including its inputs, output, +/// and the return type you get from awaiting the output. +#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)] +pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> { + pub tupled_inputs_ty: Ty<'tcx>, + /// Type returned by calling the closure + /// i.e. `f()`. + pub output_coroutine_ty: Ty<'tcx>, + /// Type returned by `await`ing the output + /// i.e. `f().await`. + pub coroutine_return_ty: Ty<'tcx>, +} + // Returns a binder of the tupled inputs types, output type, and coroutine type // from a builtin coroutine-closure type. If we don't yet know the closure kind of // the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper` @@ -323,8 +387,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc self_ty: Ty<'tcx>, goal_kind: ty::ClosureKind, env_region: ty::Region<'tcx>, -) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec<ty::Predicate<'tcx>>), NoSolution> -{ +) -> Result< + (ty::Binder<'tcx, AsyncCallableRelevantTypes<'tcx>>, Vec<ty::Predicate<'tcx>>), + NoSolution, +> { match *self_ty.kind() { ty::CoroutineClosure(def_id, args) => { let args = args.as_coroutine_closure(); @@ -335,24 +401,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc if !closure_kind.extends(goal_kind) { return Err(NoSolution); } - sig.to_coroutine_given_kind_and_upvars( - tcx, - args.parent_args(), - tcx.coroutine_for_closure(def_id), - goal_kind, - env_region, - args.tupled_upvars_ty(), - args.coroutine_captures_by_ref_ty(), + + coroutine_closure_to_certain_coroutine( + tcx, goal_kind, env_region, def_id, args, sig, ) } else { - let async_fn_kind_trait_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); - let upvars_projection_def_id = tcx - .associated_items(async_fn_kind_trait_def_id) - .filter_by_name_unhygienic(sym::Upvars) - .next() - .unwrap() - .def_id; // When we don't know the closure kind (and therefore also the closure's upvars, // which are computed at the same time), we must delay the computation of the // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait @@ -363,38 +416,23 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc nested.push( ty::TraitRef::new( tcx, - async_fn_kind_trait_def_id, + tcx.require_lang_item(LangItem::AsyncFnKindHelper, None), [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], ) .to_predicate(tcx), ); - let tupled_upvars_ty = Ty::new_projection( - tcx, - upvars_projection_def_id, - [ - ty::GenericArg::from(kind_ty), - Ty::from_closure_kind(tcx, goal_kind).into(), - env_region.into(), - sig.tupled_inputs_ty.into(), - args.tupled_upvars_ty().into(), - args.coroutine_captures_by_ref_ty().into(), - ], - ); - sig.to_coroutine( - tcx, - args.parent_args(), - Ty::from_closure_kind(tcx, goal_kind), - tcx.coroutine_for_closure(def_id), - tupled_upvars_ty, + + coroutine_closure_to_ambiguous_coroutine( + tcx, goal_kind, env_region, def_id, args, sig, ) }; Ok(( - args.coroutine_closure_sig().rebind(( - sig.tupled_inputs_ty, - sig.return_ty, - coroutine_ty, - )), + args.coroutine_closure_sig().rebind(AsyncCallableRelevantTypes { + tupled_inputs_ty: sig.tupled_inputs_ty, + output_coroutine_ty: coroutine_ty, + coroutine_return_ty: sig.return_ty, + }), nested, )) } @@ -418,7 +456,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc .def_id; let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); Ok(( - bound_sig.rebind((Ty::new_tup(tcx, sig.inputs()), sig.output(), future_output_ty)), + bound_sig.rebind(AsyncCallableRelevantTypes { + tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs()), + output_coroutine_ty: sig.output(), + coroutine_return_ty: future_output_ty, + }), nested, )) } @@ -469,7 +511,14 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc .unwrap() .def_id; let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); - Ok((bound_sig.rebind((sig.inputs()[0], sig.output(), future_output_ty)), nested)) + Ok(( + bound_sig.rebind(AsyncCallableRelevantTypes { + tupled_inputs_ty: sig.inputs()[0], + output_coroutine_ty: sig.output(), + coroutine_return_ty: future_output_ty, + }), + nested, + )) } ty::Bool @@ -502,6 +551,68 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc } } +/// Given a coroutine-closure, project to its returned coroutine when we are *certain* +/// that the closure's kind is compatible with the goal. +fn coroutine_closure_to_certain_coroutine<'tcx>( + tcx: TyCtxt<'tcx>, + goal_kind: ty::ClosureKind, + goal_region: ty::Region<'tcx>, + def_id: DefId, + args: ty::CoroutineClosureArgs<'tcx>, + sig: ty::CoroutineClosureSignature<'tcx>, +) -> Ty<'tcx> { + sig.to_coroutine_given_kind_and_upvars( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(def_id), + goal_kind, + goal_region, + args.tupled_upvars_ty(), + args.coroutine_captures_by_ref_ty(), + ) +} + +/// Given a coroutine-closure, project to its returned coroutine when we are *not certain* +/// that the closure's kind is compatible with the goal, and therefore also don't know +/// yet what the closure's upvars are. +/// +/// Note that we do not also push a `AsyncFnKindHelper` goal here. +fn coroutine_closure_to_ambiguous_coroutine<'tcx>( + tcx: TyCtxt<'tcx>, + goal_kind: ty::ClosureKind, + goal_region: ty::Region<'tcx>, + def_id: DefId, + args: ty::CoroutineClosureArgs<'tcx>, + sig: ty::CoroutineClosureSignature<'tcx>, +) -> Ty<'tcx> { + let async_fn_kind_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); + let upvars_projection_def_id = tcx + .associated_items(async_fn_kind_trait_def_id) + .filter_by_name_unhygienic(sym::Upvars) + .next() + .unwrap() + .def_id; + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(args.kind_ty()), + Ty::from_closure_kind(tcx, goal_kind).into(), + goal_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); + sig.to_coroutine( + tcx, + args.parent_args(), + Ty::from_closure_kind(tcx, goal_kind), + tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ) +} + /// Assemble a list of predicates that would be present on a theoretical /// user impl for an object type. These predicates must be checked any time /// we assemble a built-in object candidate for an object type, since they diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index ed428bb8e66..4a86f708632 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -874,7 +874,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn is_transmutable( &self, src_and_dst: rustc_transmute::Types<'tcx>, - scope: Ty<'tcx>, assume: rustc_transmute::Assume, ) -> Result<Certainty, NoSolution> { use rustc_transmute::Answer; @@ -882,7 +881,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( ObligationCause::dummy(), src_and_dst, - scope, assume, ) { Answer::Yes => Ok(Certainty::Yes), @@ -906,7 +904,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &ObligationCause::dummy(), param_env, hidden_ty, - true, &mut obligations, )?; self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index aa8cc3667cd..3aba5c85abc 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -1,5 +1,6 @@ use crate::traits::{check_args_compatible, specialization_graph}; +use super::assembly::structural_traits::AsyncCallableRelevantTypes; use super::assembly::{self, structural_traits, Candidate}; use super::{EvalCtxt, GoalSource}; use rustc_hir::def::DefKind; @@ -392,46 +393,56 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal_kind, env_region, )?; - let output_is_sized_pred = - tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| { - ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output]) - }); + let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( + |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { + ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_ty]) + }, + ); let pred = tupled_inputs_and_output_and_coroutine - .map_bound(|(inputs, output, coroutine)| { - let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) { - sym::CallOnceFuture => ( - ty::AliasTy::new( - tcx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), inputs], + .map_bound( + |AsyncCallableRelevantTypes { + tupled_inputs_ty, + output_coroutine_ty, + coroutine_return_ty, + }| { + let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) { + sym::CallOnceFuture => ( + ty::AliasTy::new( + tcx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), tupled_inputs_ty], + ), + output_coroutine_ty.into(), ), - coroutine.into(), - ), - sym::CallMutFuture | sym::CallFuture => ( - ty::AliasTy::new( - tcx, - goal.predicate.def_id(), - [ - ty::GenericArg::from(goal.predicate.self_ty()), - inputs.into(), - env_region.into(), - ], + sym::CallMutFuture | sym::CallFuture => ( + ty::AliasTy::new( + tcx, + goal.predicate.def_id(), + [ + ty::GenericArg::from(goal.predicate.self_ty()), + tupled_inputs_ty.into(), + env_region.into(), + ], + ), + output_coroutine_ty.into(), ), - coroutine.into(), - ), - sym::Output => ( - ty::AliasTy::new( - tcx, - goal.predicate.def_id(), - [ty::GenericArg::from(goal.predicate.self_ty()), inputs.into()], + sym::Output => ( + ty::AliasTy::new( + tcx, + goal.predicate.def_id(), + [ + ty::GenericArg::from(goal.predicate.self_ty()), + tupled_inputs_ty.into(), + ], + ), + coroutine_return_ty.into(), ), - output.into(), - ), - name => bug!("no such associated type: {name}"), - }; - ty::ProjectionPredicate { projection_ty, term } - }) + name => bug!("no such associated type: {name}"), + }; + ty::ProjectionPredicate { projection_ty, term } + }, + ) .to_predicate(tcx); // A built-in `AsyncFn` impl only holds if the output is sized. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 73bf66f6689..80198ba39f9 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -2,6 +2,7 @@ use crate::traits::supertrait_def_ids; +use super::assembly::structural_traits::AsyncCallableRelevantTypes; use super::assembly::{self, structural_traits, Candidate}; use super::{EvalCtxt, GoalSource, SolverMode}; use rustc_data_structures::fx::FxIndexSet; @@ -327,14 +328,19 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // This region doesn't matter because we're throwing away the coroutine type tcx.lifetimes.re_static, )?; - let output_is_sized_pred = - tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| { - ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output]) - }); + let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( + |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { + ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_coroutine_ty]) + }, + ); let pred = tupled_inputs_and_output_and_coroutine - .map_bound(|(inputs, _, _)| { - ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) + .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| { + ty::TraitRef::new( + tcx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), tupled_inputs_ty], + ) }) .to_predicate(tcx); // A built-in `AsyncFn` impl only holds if the output is sized. @@ -543,14 +549,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let args = ecx.tcx().erase_regions(goal.predicate.trait_ref.args); let Some(assume) = - rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(3)) + rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(2)) else { return Err(NoSolution); }; let certainty = ecx.is_transmutable( rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) }, - args.type_at(2), assume, )?; ecx.evaluate_added_goals_and_make_canonical_response(certainty) diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 1aaadf6cf04..9fbec174ce8 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -107,22 +107,13 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { self.register_infer_ok_obligations(infer_ok) } - /// Makes `expected <: actual`. - pub fn eq_exp<T>( + pub fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - a_is_expected: bool, - a: T, - b: T, - ) -> Result<(), TypeError<'tcx>> - where - T: ToTrace<'tcx>, - { - self.infcx - .at(cause, param_env) - .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, a, b) - .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + value: T, + ) -> Result<T, Vec<FulfillmentError<'tcx>>> { + self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) } pub fn eq<T: ToTrace<'tcx>>( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index dcbb63f00f7..7f7bd867f63 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -889,7 +889,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => self.report_opaque_type_auto_trait_leakage( + SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => return self.report_opaque_type_auto_trait_leakage( &obligation, def_id, ), @@ -1528,6 +1528,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::Coercion { .. } ); + let (expected, actual) = if is_normalized_term_expected { + (normalized_term, data.term) + } else { + (data.term, normalized_term) + }; + // constrain inference variables a bit more to nested obligations from normalize so // we can have more helpful errors. // @@ -1535,13 +1541,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // since the normalization is just done to improve the error message. let _ = ocx.select_where_possible(); - if let Err(new_err) = ocx.eq_exp( - &obligation.cause, - obligation.param_env, - is_normalized_term_expected, - normalized_term, - data.term, - ) { + if let Err(new_err) = + ocx.eq(&obligation.cause, obligation.param_env, expected, actual) + { (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err) } else { (None, error.err) @@ -2252,8 +2254,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ErrorCode::E0282, false, ); - err.stash(span, StashKey::MaybeForgetReturn); - return self.dcx().delayed_bug("stashed error never reported"); + return err.stash(span, StashKey::MaybeForgetReturn).unwrap(); } Some(e) => return e, } @@ -2766,7 +2767,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_unsized_bound_if_applicable(err, obligation); if let Some(span) = err.span.primary_span() && let Some(mut diag) = - self.tcx.dcx().steal_diagnostic(span, StashKey::AssociatedTypeSuggestion) + self.tcx.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion) && let Ok(ref mut s1) = err.suggestions && let Ok(ref mut s2) = diag.suggestions { @@ -2961,11 +2962,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { dst: trait_ref.args.type_at(0), src: trait_ref.args.type_at(1), }; - let scope = trait_ref.args.type_at(2); let Some(assume) = rustc_transmute::Assume::from_const( self.infcx.tcx, obligation.param_env, - trait_ref.args.const_at(3), + trait_ref.args.const_at(2), ) else { self.dcx().span_delayed_bug( span, @@ -2977,15 +2977,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( obligation.cause, src_and_dst, - scope, assume, ) { Answer::No(reason) => { let dst = trait_ref.args.type_at(0); let src = trait_ref.args.type_at(1); - let err_msg = format!( - "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`" - ); + let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); let safe_transmute_explanation = match reason { rustc_transmute::Reason::SrcIsUnspecified => { format!("`{src}` does not have a well-specified layout") @@ -2999,9 +2996,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("At least one value of `{src}` isn't a bit-valid value of `{dst}`") } - rustc_transmute::Reason::DstIsPrivate => format!( - "`{dst}` is or contains a type or field that is not visible in that scope" - ), + rustc_transmute::Reason::DstMayHaveSafetyInvariants => { + format!("`{dst}` may carry safety invariants") + } rustc_transmute::Reason::DstIsTooBig => { format!("The size of `{src}` is smaller than the size of `{dst}`") } @@ -3291,7 +3288,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, def_id: DefId, - ) -> Diag<'tcx> { + ) -> ErrorGuaranteed { let name = match self.tcx.opaque_type_origin(def_id.expect_local()) { hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => { "opaque type".to_string() @@ -3318,12 +3315,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }; - if let Some(diag) = self.dcx().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle) - { - diag.cancel(); - } - - err + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + self.dcx().try_steal_replace_and_emit_err(self.tcx.def_span(def_id), StashKey::Cycle, err) } fn report_signature_mismatch_error( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d316149731e..70f6b240ab7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -310,8 +310,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .collect(), Condition::IfTransmutable { src, dst } => { let trait_def_id = obligation.predicate.def_id(); - let scope = predicate.trait_ref.args.type_at(2); - let assume_const = predicate.trait_ref.args.const_at(3); + let assume_const = predicate.trait_ref.args.const_at(2); let make_obl = |from_ty, to_ty| { let trait_ref1 = ty::TraitRef::new( tcx, @@ -319,7 +318,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { [ ty::GenericArg::from(to_ty), ty::GenericArg::from(from_ty), - ty::GenericArg::from(scope), ty::GenericArg::from(assume_const), ], ); @@ -355,7 +353,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let Some(assume) = rustc_transmute::Assume::from_const( self.infcx.tcx, obligation.param_env, - predicate.trait_ref.args.const_at(3), + predicate.trait_ref.args.const_at(2), ) else { return Err(Unimplemented); }; @@ -367,7 +365,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let maybe_transmutable = transmute_env.is_transmutable( obligation.cause.clone(), rustc_transmute::Types { dst, src }, - predicate.trait_ref.args.type_at(2), assume, ); @@ -923,14 +920,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { [self_ty, Ty::new_tup(tcx, sig.inputs())], ) }); + // We must additionally check that the return type impls `Future`. + + // FIXME(async_closures): Investigate this before stabilization. + // We instantiate this binder eagerly because the `confirm_future_candidate` + // method doesn't support higher-ranked futures, which the `AsyncFn` + // traits expressly allow the user to write. To fix this correctly, + // we'd need to instantiate trait bounds before we get to selection, + // like the new trait solver does. let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let placeholder_output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); nested.push(obligation.with( tcx, - sig.map_bound(|sig| { - ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]) - }), + ty::TraitRef::new(tcx, future_trait_def_id, [placeholder_output_ty]), )); + (trait_ref, Ty::from_closure_kind(tcx, ty::ClosureKind::Fn)) } ty::Closure(_, args) => { @@ -943,14 +948,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { [self_ty, sig.inputs()[0]], ) }); + // We must additionally check that the return type impls `Future`. + // See FIXME in last branch for why we instantiate the binder eagerly. let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let placeholder_output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); nested.push(obligation.with( tcx, - sig.map_bound(|sig| { - ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]) - }), + ty::TraitRef::new(tcx, future_trait_def_id, [placeholder_output_ty]), )); + (trait_ref, args.kind_ty()) } _ => bug!("expected callable type for AsyncFn candidate"), |
