diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
17 files changed, 892 insertions, 379 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 8e04da4f9be..aef2f8ff991 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -579,14 +579,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { pub fn is_of_param(&self, ty: Ty<'_>) -> bool { match ty.kind() { ty::Param(_) => true, - ty::Projection(p) => self.is_of_param(p.self_ty()), + ty::Alias(ty::Projection, p) => self.is_of_param(p.self_ty()), _ => false, } } fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { if let Some(ty) = p.term().skip_binder().ty() { - matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty) + matches!(ty.kind(), ty::Alias(ty::Projection, proj) if proj == &p.skip_binder().projection_ty) } else { false } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 899e30275a0..7c569621cfe 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -659,7 +659,7 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { | ty::RawPtr(..) | ty::Never | ty::Tuple(..) - | ty::Projection(..) => self.found_non_local_ty(ty), + | ty::Alias(ty::Projection, ..) => self.found_non_local_ty(ty), ty::Param(..) => self.found_param_ty(ty), @@ -704,7 +704,7 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { ); ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) } - ty::Opaque(..) => { + ty::Alias(ty::Opaque, ..) => { // This merits some explanation. // Normally, opaque types are not involved when performing // coherence checking, since it is illegal to directly diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index 752b53fbc3f..0c1717cff33 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -1,52 +1,101 @@ use rustc_hir::def_id::DefId; -use rustc_infer::infer::InferCtxt; +use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime}; +use rustc_infer::traits::util::elaborate_predicates_with_span; use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation}; -use rustc_span::DUMMY_SP; +use rustc_middle::ty; +use rustc_span::{Span, DUMMY_SP}; use crate::traits::ObligationCtxt; +pub enum Ambiguity { + DefId(DefId), + ParamEnv(Span), +} + pub fn recompute_applicable_impls<'tcx>( infcx: &InferCtxt<'tcx>, obligation: &TraitObligation<'tcx>, -) -> Vec<DefId> { +) -> Vec<Ambiguity> { let tcx = infcx.tcx; let param_env = obligation.param_env; - let dummy_cause = ObligationCause::dummy(); + let impl_may_apply = |impl_def_id| { let ocx = ObligationCtxt::new_in_snapshot(infcx); let placeholder_obligation = infcx.replace_bound_vars_with_placeholders(obligation.predicate); let obligation_trait_ref = - ocx.normalize(&dummy_cause, param_env, placeholder_obligation.trait_ref); + ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs); let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref); - if let Err(_) = ocx.eq(&dummy_cause, param_env, obligation_trait_ref, impl_trait_ref) { + if let Err(_) = + ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref) + { return false; } let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs); - ocx.register_obligations( - impl_predicates - .predicates - .iter() - .map(|&predicate| Obligation::new(tcx, dummy_cause.clone(), param_env, predicate)), + ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| { + Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) + })); + + ocx.select_where_possible().is_empty() + }; + + let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| { + let ocx = ObligationCtxt::new_in_snapshot(infcx); + let placeholder_obligation = + infcx.replace_bound_vars_with_placeholders(obligation.predicate); + let obligation_trait_ref = + ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); + + let param_env_predicate = infcx.replace_bound_vars_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::HigherRankedType, + poly_trait_predicate, ); + let param_env_trait_ref = + ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref); + + if let Err(_) = + ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, param_env_trait_ref) + { + return false; + } ocx.select_where_possible().is_empty() }; - let mut impls = Vec::new(); + let mut ambiguities = Vec::new(); + tcx.for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), |impl_def_id| { - if infcx.probe(move |_snapshot| impl_may_apply(impl_def_id)) { - impls.push(impl_def_id) + if infcx.probe(|_| impl_may_apply(impl_def_id)) { + ambiguities.push(Ambiguity::DefId(impl_def_id)) } }, ); - impls + + let predicates = + tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx); + for obligation in + elaborate_predicates_with_span(tcx, std::iter::zip(predicates.predicates, predicates.spans)) + { + let kind = obligation.predicate.kind(); + if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder() + && param_env_candidate_may_apply(kind.rebind(trait_pred)) + { + if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) { + ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id()))) + } else { + ambiguities.push(Ambiguity::ParamEnv(obligation.cause.span)) + } + } + } + + ambiguities } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs new file mode 100644 index 00000000000..cb373d65772 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs @@ -0,0 +1,74 @@ +use crate::infer::InferCtxt; + +use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +pub struct CollectAllMismatches<'a, 'tcx> { + pub infcx: &'a InferCtxt<'tcx>, + pub param_env: ty::ParamEnv<'tcx>, + pub errors: Vec<TypeError<'tcx>>, +} + +impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> { + fn tag(&self) -> &'static str { + "CollectAllMismatches" + } + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + fn intercrate(&self) -> bool { + false + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } + fn a_is_expected(&self) -> bool { + true + } // irrelevant + fn mark_ambiguous(&mut self) { + bug!() + } + fn relate_with_variance<T: Relate<'tcx>>( + &mut self, + _: ty::Variance, + _: ty::VarianceDiagInfo<'tcx>, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + self.relate(a, b) + } + fn regions( + &mut self, + a: ty::Region<'tcx>, + _b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + Ok(a) + } + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + if a == b || matches!(a.kind(), ty::Infer(_)) || matches!(b.kind(), ty::Infer(_)) { + return Ok(a); + } + relate::super_relate_tys(self, a, b).or_else(|e| { + self.errors.push(e); + Ok(a) + }) + } + fn consts( + &mut self, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + if a == b { + return Ok(a); + } + relate::super_relate_consts(self, a, b) // could do something similar here for constants! + } + fn binders<T: Relate<'tcx>>( + &mut self, + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> { + Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index dda7b2b2fa5..2dd2c568bab 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1,4 +1,5 @@ mod ambiguity; +pub mod method_chain; pub mod on_unimplemented; pub mod suggestions; @@ -34,14 +35,14 @@ use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::print::{FmtPrinter, Print}; +use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print}; use rustc_middle::ty::{ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitable, }; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::sym; use rustc_span::{ExpnKind, Span, DUMMY_SP}; use std::fmt; use std::iter; @@ -536,7 +537,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { |err| { self.note_obligation_cause_code( err, - &predicate, + predicate, obligation.param_env, obligation.cause.code(), &mut vec![], @@ -597,6 +598,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // can get a better error message by performing HIR-based well-formedness checking. if let ObligationCauseCode::WellFormed(Some(wf_loc)) = root_obligation.cause.code().peel_derives() + && !obligation.predicate.has_non_region_infer() { if let Some(cause) = self .tcx @@ -978,6 +980,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref, obligation.cause.body_id, &mut err, + true, ) { // This is *almost* equivalent to // `obligation.cause.code().peel_derives()`, but it gives us the @@ -1013,6 +1016,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref, obligation.cause.body_id, &mut err, + true, ); } } @@ -1032,7 +1036,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && self.fallback_has_occurred { let predicate = trait_predicate.map_bound(|trait_pred| { - trait_pred.with_self_type(self.tcx, self.tcx.mk_unit()) + trait_pred.with_self_ty(self.tcx, self.tcx.mk_unit()) }); let unit_obligation = obligation.with(tcx, predicate); if self.predicate_may_hold(&unit_obligation) { @@ -1232,6 +1236,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => None, }; + let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did)); let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did)); if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { @@ -1285,6 +1290,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { found_trait_ref, expected_trait_ref, obligation.cause.code(), + found_node, ) } else { let (closure_span, closure_arg_span, found) = found_did @@ -1430,6 +1436,7 @@ trait InferCtxtPrivExt<'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, body_id: hir::HirId, err: &mut Diagnostic, + other: bool, ) -> bool; /// Gets the parent trait chain start @@ -1480,7 +1487,7 @@ trait InferCtxtPrivExt<'tcx> { fn annotate_source_of_ambiguity( &self, err: &mut Diagnostic, - impls: &[DefId], + impls: &[ambiguity::Ambiguity], predicate: ty::Predicate<'tcx>, ); @@ -1586,7 +1593,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { self.note_obligation_cause_code( &mut diag, - &error.obligation.predicate, + error.obligation.predicate, error.obligation.param_env, code, &mut vec![], @@ -1629,18 +1636,30 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { infer::LateBoundRegionConversionTime::HigherRankedType, bound_predicate.rebind(data), ); - let normalized_ty = ocx.normalize( - &obligation.cause, - obligation.param_env, - self.tcx - .mk_projection(data.projection_ty.item_def_id, data.projection_ty.substs), - ); + let unnormalized_term = match data.term.unpack() { + ty::TermKind::Ty(_) => self + .tcx + .mk_projection(data.projection_ty.def_id, data.projection_ty.substs) + .into(), + ty::TermKind::Const(ct) => self + .tcx + .mk_const( + ty::UnevaluatedConst { + def: ty::WithOptConstParam::unknown(data.projection_ty.def_id), + substs: data.projection_ty.substs, + }, + ct.ty(), + ) + .into(), + }; + let normalized_term = + ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term); debug!(?obligation.cause, ?obligation.param_env); - debug!(?normalized_ty, data.ty = ?data.term); + debug!(?normalized_term, data.ty = ?data.term); - let is_normalized_ty_expected = !matches!( + let is_normalized_term_expected = !matches!( obligation.cause.code().peel_derives(), ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(_, _) @@ -1649,7 +1668,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ObjectCastObligation(..) | ObligationCauseCode::OpaqueType ); - let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error()); // constrain inference variables a bit more to nested obligations from normalize so // we can have more helpful errors. @@ -1658,11 +1676,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Err(new_err) = ocx.eq_exp( &obligation.cause, obligation.param_env, - is_normalized_ty_expected, - normalized_ty, - expected_ty, + is_normalized_term_expected, + normalized_term, + data.term, ) { - (Some((data, is_normalized_ty_expected, normalized_ty, expected_ty)), new_err) + (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err) } else { (None, error.err) } @@ -1671,12 +1689,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }; let msg = values - .and_then(|(predicate, _, normalized_ty, expected_ty)| { - self.maybe_detailed_projection_msg( - predicate, - normalized_ty.into(), - expected_ty.into(), - ) + .and_then(|(predicate, _, normalized_term, expected_term)| { + self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term) }) .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate)); let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}"); @@ -1684,10 +1698,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let secondary_span = match predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => self .tcx - .opt_associated_item(proj.projection_ty.item_def_id) + .opt_associated_item(proj.projection_ty.def_id) .and_then(|trait_assoc_item| { self.tcx - .trait_of_item(proj.projection_ty.item_def_id) + .trait_of_item(proj.projection_ty.def_id) .map(|id| (trait_assoc_item, id)) }) .and_then(|(trait_assoc_item, id)| { @@ -1743,21 +1757,26 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let trait_def_id = pred.projection_ty.trait_def_id(self.tcx); let self_ty = pred.projection_ty.self_ty(); - if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() { - Some(format!( - "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`", - fn_kind = self_ty.prefix_string(self.tcx) - )) - } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() { - Some(format!( - "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`" - )) - } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) { - Some(format!( - "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`" - )) - } else { - None + with_forced_trimmed_paths! { + if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() { + Some(format!( + "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it \ + returns `{normalized_ty}`", + fn_kind = self_ty.prefix_string(self.tcx) + )) + } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() { + Some(format!( + "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \ + resolves to `{normalized_ty}`" + )) + } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) { + Some(format!( + "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \ + yields `{normalized_ty}`" + )) + } else { + None + } } } @@ -1786,8 +1805,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Closure(..) => Some(9), ty::Tuple(..) => Some(10), ty::Param(..) => Some(11), - ty::Projection(..) => Some(12), - ty::Opaque(..) => Some(13), + ty::Alias(ty::Projection, ..) => Some(12), + ty::Alias(ty::Opaque, ..) => Some(13), ty::Never => Some(14), ty::Adt(..) => Some(15), ty::Generator(..) => Some(16), @@ -1885,7 +1904,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, body_id: hir::HirId, err: &mut Diagnostic, + other: bool, ) -> bool { + let other = if other { "other " } else { "" }; let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| { candidates.sort(); candidates.dedup(); @@ -1936,7 +1957,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { candidates.dedup(); let end = if candidates.len() <= 9 { candidates.len() } else { 8 }; err.help(&format!( - "the following other types implement trait `{}`:{}{}", + "the following {other}types implement trait `{}`:{}{}", trait_ref.print_only_trait_path(), candidates[..end].join(""), if len > 9 { format!("\nand {} others", len - 8) } else { String::new() } @@ -2077,8 +2098,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { param_env: ty::ParamEnv<'tcx>, trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, ) -> PredicateObligation<'tcx> { - let trait_pred = trait_ref_and_ty - .map_bound(|(tr, new_self_ty)| tr.with_self_type(self.tcx, new_self_ty)); + let trait_pred = + trait_ref_and_ty.map_bound(|(tr, new_self_ty)| tr.with_self_ty(self.tcx, new_self_ty)); Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred) } @@ -2172,19 +2193,40 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut selcx = SelectionContext::new(&self); match selcx.select_from_obligation(&obligation) { Ok(None) => { - let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation); + let ambiguities = + ambiguity::recompute_applicable_impls(self.infcx, &obligation); let has_non_region_infer = trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer()); // It doesn't make sense to talk about applicable impls if there are more // than a handful of them. - if impls.len() > 1 && impls.len() < 5 && has_non_region_infer { - self.annotate_source_of_ambiguity(&mut err, &impls, predicate); + if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer { + if self.tainted_by_errors().is_some() && subst.is_none() { + // If `subst.is_none()`, then this is probably two param-env + // candidates or impl candidates that are equal modulo lifetimes. + // Therefore, if we've already emitted an error, just skip this + // one, since it's not particularly actionable. + err.cancel(); + return; + } + self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate); } else { if self.tainted_by_errors().is_some() { err.cancel(); return; } err.note(&format!("cannot satisfy `{}`", predicate)); + let impl_candidates = self.find_similar_impl_candidates( + predicate.to_opt_poly_trait_pred().unwrap(), + ); + if impl_candidates.len() < 10 { + self.report_similar_impl_candidates( + impl_candidates, + trait_ref, + body_id.map(|id| id.hir_id).unwrap_or(obligation.cause.body_id), + &mut err, + false, + ); + } } } _ => { @@ -2196,60 +2238,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - if let ObligationCauseCode::ItemObligation(def_id) | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code() { - self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); - } else if let Ok(snippet) = &self.tcx.sess.source_map().span_to_snippet(span) - && let ObligationCauseCode::BindingObligation(def_id, _) | ObligationCauseCode::ExprBindingObligation(def_id, ..) - = *obligation.cause.code() + if let ObligationCauseCode::ItemObligation(def_id) + | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code() { - let generics = self.tcx.generics_of(def_id); - if generics.params.iter().any(|p| p.name != kw::SelfUpper) - && !snippet.ends_with('>') - && !generics.has_impl_trait() - && !self.tcx.is_fn_trait(def_id) - { - // FIXME: To avoid spurious suggestions in functions where type arguments - // where already supplied, we check the snippet to make sure it doesn't - // end with a turbofish. Ideally we would have access to a `PathSegment` - // instead. Otherwise we would produce the following output: - // - // error[E0283]: type annotations needed - // --> $DIR/issue-54954.rs:3:24 - // | - // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); - // | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - // | | - // | cannot infer type - // | help: consider specifying the type argument - // | in the function call: - // | `Tt::const_val::<[i8; 123]>::<T>` - // ... - // LL | const fn const_val<T: Sized>() -> usize { - // | - required by this bound in `Tt::const_val` - // | - // = note: cannot satisfy `_: Tt` - - // Clear any more general suggestions in favor of our specific one - err.clear_suggestions(); - - err.span_suggestion_verbose( - span.shrink_to_hi(), - &format!( - "consider specifying the type argument{} in the function call", - pluralize!(generics.params.len()), - ), - format!( - "::<{}>", - generics - .params - .iter() - .map(|p| p.name.to_string()) - .collect::<Vec<String>>() - .join(", ") - ), - Applicability::HasPlaceholders, - ); - } + self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); } if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) = @@ -2320,18 +2312,19 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id); if trait_impls.blanket_impls().is_empty() - && let Some((impl_ty, _)) = trait_impls.non_blanket_impls().iter().next() - && let Some(impl_def_id) = impl_ty.def() { - let message = if trait_impls.non_blanket_impls().len() == 1 { + && let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next() + { + let non_blanket_impl_count = trait_impls.non_blanket_impls().values().flatten().count(); + let message = if non_blanket_impl_count == 1 { "use the fully-qualified path to the only available implementation".to_string() } else { format!( "use a fully-qualified path to a specific available implementation ({} found)", - trait_impls.non_blanket_impls().len() + non_blanket_impl_count ) }; let mut suggestions = vec![( - trait_path_segment.ident.span.shrink_to_lo(), + path.span.shrink_to_lo(), format!("<{} as ", self.tcx.type_of(impl_def_id)) )]; if let Some(generic_arg) = trait_path_segment.args { @@ -2464,21 +2457,30 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn annotate_source_of_ambiguity( &self, err: &mut Diagnostic, - impls: &[DefId], + ambiguities: &[ambiguity::Ambiguity], predicate: ty::Predicate<'tcx>, ) { let mut spans = vec![]; let mut crates = vec![]; let mut post = vec![]; - for def_id in impls { - match self.tcx.span_of_impl(*def_id) { - Ok(span) => spans.push(span), - Err(name) => { - crates.push(name); - if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) { - post.push(header); + let mut has_param_env = false; + for ambiguity in ambiguities { + match ambiguity { + ambiguity::Ambiguity::DefId(impl_def_id) => { + match self.tcx.span_of_impl(*impl_def_id) { + Ok(span) => spans.push(span), + Err(name) => { + crates.push(name); + if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) { + post.push(header); + } + } } } + ambiguity::Ambiguity::ParamEnv(span) => { + has_param_env = true; + spans.push(*span); + } } } let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect(); @@ -2502,7 +2504,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return; } - let msg = format!("multiple `impl`s satisfying `{}` found", predicate); + let msg = format!( + "multiple `impl`s{} satisfying `{}` found", + if has_param_env { " or `where` clauses" } else { "" }, + predicate + ); let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) { format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),) } else if post.len() == 1 { @@ -2601,7 +2607,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { self.note_obligation_cause_code( err, - &obligation.predicate, + obligation.predicate, obligation.param_env, obligation.cause.code(), &mut vec![], diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 443d57aaf3d..d47a5ea3e37 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1,8 +1,10 @@ +// ignore-tidy-filelength + use super::{DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation}; use crate::autoderef::Autoderef; use crate::infer::InferCtxt; -use crate::traits::NormalizeExt; +use crate::traits::{NormalizeExt, ObligationCtxt}; use hir::def::CtorOf; use hir::HirId; @@ -22,21 +24,24 @@ use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime}; use rustc_middle::hir::map; +use rustc_middle::ty::error::TypeError::{self, Sorts}; +use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, - GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable, - ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, + GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts, + IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitable, TypeckResults, }; -use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP}; use rustc_target::spec::abi; -use std::fmt; +use std::ops::Deref; +use super::method_chain::CollectAllMismatches; use super::InferCtxtPrivExt; use crate::infer::InferCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; #[derive(Debug)] pub enum GeneratorInteriorOrUpvar { @@ -254,6 +259,7 @@ pub trait TypeErrCtxtExt<'tcx> { found: ty::PolyTraitRef<'tcx>, expected: ty::PolyTraitRef<'tcx>, cause: &ObligationCauseCode<'tcx>, + found_node: Option<Node<'_>>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; fn note_conflicting_closure_bounds( @@ -292,13 +298,13 @@ pub trait TypeErrCtxtExt<'tcx> { fn note_obligation_cause_code<T>( &self, err: &mut Diagnostic, - predicate: &T, + predicate: T, param_env: ty::ParamEnv<'tcx>, cause_code: &ObligationCauseCode<'tcx>, obligated_types: &mut Vec<Ty<'tcx>>, seen_requirements: &mut FxHashSet<DefId>, ) where - T: fmt::Display + ToPredicate<'tcx>; + T: ToPredicate<'tcx>; /// Suggest to await before try: future? => future.await? fn suggest_await_before_try( @@ -329,6 +335,31 @@ pub trait TypeErrCtxtExt<'tcx> { err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ); + fn function_argument_obligation( + &self, + arg_hir_id: HirId, + err: &mut Diagnostic, + parent_code: &ObligationCauseCode<'tcx>, + param_env: ty::ParamEnv<'tcx>, + predicate: ty::Predicate<'tcx>, + call_hir_id: HirId, + ); + fn point_at_chain( + &self, + expr: &hir::Expr<'_>, + typeck_results: &TypeckResults<'tcx>, + type_diffs: Vec<TypeError<'tcx>>, + param_env: ty::ParamEnv<'tcx>, + err: &mut Diagnostic, + ); + fn probe_assoc_types_at_expr( + &self, + type_diffs: &[TypeError<'tcx>], + span: Span, + prev_ty: Ty<'tcx>, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>; } fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) { @@ -348,7 +379,7 @@ fn suggest_restriction<'tcx>( msg: &str, err: &mut Diagnostic, fn_sig: Option<&hir::FnSig<'_>>, - projection: Option<&ty::ProjectionTy<'_>>, + projection: Option<&ty::AliasTy<'_>>, trait_pred: ty::PolyTraitPredicate<'tcx>, // When we are dealing with a trait, `super_traits` will be `Some`: // Given `trait T: A + B + C {}` @@ -474,7 +505,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let self_ty = trait_pred.skip_binder().self_ty(); let (param_ty, projection) = match self_ty.kind() { ty::Param(_) => (true, None), - ty::Projection(projection) => (false, Some(projection)), + ty::Alias(ty::Projection, projection) => (false, Some(projection)), _ => (false, None), }; @@ -673,7 +704,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { // It only make sense when suggesting dereferences for arguments - let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() + let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, call_hir_id, .. } = obligation.cause.code() else { return false; }; let Some(typeck_results) = &self.typeck_results else { return false; }; @@ -752,12 +783,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { real_trait_pred_and_base_ty, ); if self.predicate_may_hold(&obligation) { - err.span_suggestion_verbose( - span.shrink_to_lo(), - "consider dereferencing here", - "*", - Applicability::MachineApplicable, + let call_node = self.tcx.hir().get(*call_hir_id); + let msg = "consider dereferencing here"; + let is_receiver = matches!( + call_node, + Node::Expr(hir::Expr { + kind: hir::ExprKind::MethodCall(_, receiver_expr, ..), + .. + }) + if receiver_expr.hir_id == *arg_hir_id ); + if is_receiver { + err.multipart_suggestion_verbose( + msg, + vec![ + (span.shrink_to_lo(), "(*".to_string()), + (span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ) + } else { + err.span_suggestion_verbose( + span.shrink_to_lo(), + msg, + '*', + Applicability::MachineApplicable, + ) + }; return true; } } @@ -834,10 +886,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn_sig.inputs().map_bound(|inputs| &inputs[1..]), )) } - ty::Opaque(def_id, substs) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() - && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() + && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() // args tuple will always be substs[1] && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() { @@ -854,7 +906,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Dynamic(data, _, ty::Dyn) => { data.iter().find_map(|pred| { if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() - && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output() + && Some(proj.def_id) == self.tcx.lang_items().fn_once_output() // for existential projection, substs are shifted over by 1 && let ty::Tuple(args) = proj.substs.type_at(0).kind() { @@ -871,7 +923,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Param(_) => { obligation.param_env.caller_bounds().iter().find_map(|pred| { if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() - && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() + && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() && proj.projection_ty.self_ty() == found // args tuple will always be substs[1] && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() @@ -1574,7 +1626,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let trait_obj = if has_dyn { &snippet[4..] } else { &snippet }; if only_never_return { // No return paths, probably using `panic!()` or similar. - // Suggest `-> T`, `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`. + // Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`. suggest_trait_object_return_type_alternatives( err, ret_ty.span, @@ -1674,6 +1726,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { found: ty::PolyTraitRef<'tcx>, expected: ty::PolyTraitRef<'tcx>, cause: &ObligationCauseCode<'tcx>, + found_node: Option<Node<'_>>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { pub(crate) fn build_fn_sig_ty<'tcx>( infcx: &InferCtxt<'tcx>, @@ -1735,6 +1788,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.note_conflicting_closure_bounds(cause, &mut err); + if let Some(found_node) = found_node { + hint_missing_borrow(span, found_span, found, expected, found_node, &mut err); + } + err } @@ -1755,10 +1812,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && self.tcx.is_fn_trait(trait_pred.def_id()) { let expected_self = - self.tcx.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.self_ty())); + self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.self_ty())); let expected_substs = self .tcx - .anonymize_late_bound_regions(pred.kind().rebind(trait_pred.trait_ref.substs)); + .anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.substs)); // Find another predicate whose self-type is equal to the expected self type, // but whose substs don't match. @@ -1771,12 +1828,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Make sure that the self type matches // (i.e. constraining this closure) && expected_self - == self.tcx.anonymize_late_bound_regions( + == self.tcx.anonymize_bound_vars( pred.kind().rebind(trait_pred.self_ty()), ) // But the substs don't match (i.e. incompatible args) && expected_substs - != self.tcx.anonymize_late_bound_regions( + != self.tcx.anonymize_bound_vars( pred.kind().rebind(trait_pred.trait_ref.substs), ) => { @@ -2158,15 +2215,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path()) }; - let mut explain_yield = |interior_span: Span, - yield_span: Span, - scope_span: Option<Span>| { - let mut span = MultiSpan::from_span(yield_span); - if let Ok(snippet) = source_map.span_to_snippet(interior_span) { - // #70935: If snippet contains newlines, display "the value" instead - // so that we do not emit complex diagnostics. - let snippet = &format!("`{}`", snippet); - let snippet = if snippet.contains('\n') { "the value" } else { snippet }; + let mut explain_yield = + |interior_span: Span, yield_span: Span, scope_span: Option<Span>| { + let mut span = MultiSpan::from_span(yield_span); + let snippet = match source_map.span_to_snippet(interior_span) { + // #70935: If snippet contains newlines, display "the value" instead + // so that we do not emit complex diagnostics. + Ok(snippet) if !snippet.contains('\n') => format!("`{}`", snippet), + _ => "the value".to_string(), + }; // note: future is not `Send` as this value is used across an await // --> $DIR/issue-70935-complex-spans.rs:13:9 // | @@ -2191,17 +2248,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { interior_span, format!("has type `{}` which {}", target_ty, trait_explanation), ); - // If available, use the scope span to annotate the drop location. - let mut scope_note = None; if let Some(scope_span) = scope_span { let scope_span = source_map.end_point(scope_span); let msg = format!("{} is later dropped here", snippet); - if source_map.is_multiline(yield_span.between(scope_span)) { - span.push_span_label(scope_span, msg); - } else { - scope_note = Some((scope_span, msg)); - } + span.push_span_label(scope_span, msg); } err.span_note( span, @@ -2210,11 +2261,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { future_or_generator, trait_explanation, an_await_or_yield ), ); - if let Some((span, msg)) = scope_note { - err.span_note(span, &msg); - } - } - }; + }; match interior_or_upvar_span { GeneratorInteriorOrUpvar::Interior(interior_span, interior_extra_info) => { if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info { @@ -2336,7 +2383,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { debug!(?next_code); self.note_obligation_cause_code( err, - &obligation.predicate, + obligation.predicate, obligation.param_env, next_code.unwrap(), &mut Vec::new(), @@ -2347,15 +2394,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn note_obligation_cause_code<T>( &self, err: &mut Diagnostic, - predicate: &T, + predicate: T, param_env: ty::ParamEnv<'tcx>, cause_code: &ObligationCauseCode<'tcx>, obligated_types: &mut Vec<Ty<'tcx>>, seen_requirements: &mut FxHashSet<DefId>, ) where - T: fmt::Display + ToPredicate<'tcx>, + T: ToPredicate<'tcx>, { let tcx = self.tcx; + let predicate = predicate.to_predicate(tcx); match *cause_code { ObligationCauseCode::ExprAssignable | ObligationCauseCode::MatchExpressionArm { .. } @@ -2390,12 +2438,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note("only the last element of a tuple may have a dynamically sized type"); } ObligationCauseCode::ProjectionWf(data) => { - err.note(&format!("required so that the projection `{}` is well-formed", data,)); + err.note(&format!("required so that the projection `{data}` is well-formed")); } ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { err.note(&format!( - "required so that reference `{}` does not outlive its referent", - ref_ty, + "required so that reference `{ref_ty}` does not outlive its referent" )); } ObligationCauseCode::ObjectTypeBound(object_ty, region) => { @@ -2412,6 +2459,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::BindingObligation(item_def_id, span) | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..) => { let item_name = tcx.def_path_str(item_def_id); + let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id)); let mut multispan = MultiSpan::from(span); let sm = tcx.sess.source_map(); if let Some(ident) = tcx.opt_item_ident(item_def_id) { @@ -2424,9 +2472,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { multispan.push_span_label(ident.span, "required by a bound in this"); } } - let descr = format!("required by a bound in `{}`", item_name); + let descr = format!("required by a bound in `{item_name}`"); if span.is_visible(sm) { - let msg = format!("required by this bound in `{}`", item_name); + let msg = format!("required by this bound in `{short_item_name}`"); multispan.push_span_label(span, msg); err.span_note(multispan, &descr); } else { @@ -2500,6 +2548,25 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ObligationCauseCode::SizedArgumentType(sp) => { if let Some(span) = sp { + if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() + && let ty::Clause::Trait(trait_pred) = clause + && let ty::Dynamic(..) = trait_pred.self_ty().kind() + { + let span = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + && snippet.starts_with("dyn ") + { + let pos = snippet.len() - snippet[3..].trim_start().len(); + span.with_hi(span.lo() + BytePos(pos as u32)) + } else { + span.shrink_to_lo() + }; + err.span_suggestion_verbose( + span, + "you can use `impl Trait` as the argument type", + "impl ".to_string(), + Applicability::MaybeIncorrect, + ); + } err.span_suggestion_verbose( span.shrink_to_lo(), "function arguments must have a statically known size, borrowed types \ @@ -2622,7 +2689,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Some(ident) => err.span_note(ident.span, &msg), None => err.note(&msg), }, - ty::Opaque(def_id, _) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { // Avoid printing the future from `core::future::identity_future`, it's not helpful if tcx.parent(*def_id) == identity_future { break 'print; @@ -2688,7 +2755,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ensure_sufficient_stack(|| { self.note_obligation_cause_code( err, - &parent_predicate, + parent_predicate, param_env, &data.parent_code, obligated_types, @@ -2699,7 +2766,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ensure_sufficient_stack(|| { self.note_obligation_cause_code( err, - &parent_predicate, + parent_predicate, param_env, cause_code.peel_derives(), obligated_types, @@ -2808,7 +2875,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ensure_sufficient_stack(|| { self.note_obligation_cause_code( err, - &parent_predicate, + parent_predicate, param_env, &data.parent_code, obligated_types, @@ -2823,7 +2890,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ensure_sufficient_stack(|| { self.note_obligation_cause_code( err, - &parent_predicate, + parent_predicate, param_env, &data.parent_code, obligated_types, @@ -2835,44 +2902,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { arg_hir_id, call_hir_id, ref parent_code, + .. } => { - let hir = self.tcx.hir(); - if let Some(Node::Expr(expr @ hir::Expr { kind: hir::ExprKind::Block(..), .. })) = - hir.find(arg_hir_id) - { - let parent_id = hir.get_parent_item(arg_hir_id); - let typeck_results: &TypeckResults<'tcx> = match &self.typeck_results { - Some(t) if t.hir_owner == parent_id => t, - _ => self.tcx.typeck(parent_id.def_id), - }; - let expr = expr.peel_blocks(); - let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()); - let span = expr.span; - if Some(span) != err.span.primary_span() { - err.span_label( - span, - if ty.references_error() { - String::new() - } else { - format!("this tail expression is of type `{:?}`", ty) - }, - ); - } - } - if let Some(Node::Expr(hir::Expr { - kind: - hir::ExprKind::Call(hir::Expr { span, .. }, _) - | hir::ExprKind::MethodCall( - hir::PathSegment { ident: Ident { span, .. }, .. }, - .., - ), - .. - })) = hir.find(call_hir_id) - { - if Some(*span) != err.span.primary_span() { - err.span_label(*span, "required by a bound introduced by this call"); - } - } + self.function_argument_obligation( + arg_hir_id, + err, + parent_code, + param_env, + predicate, + call_hir_id, + ); ensure_sufficient_stack(|| { self.note_obligation_cause_code( err, @@ -2887,9 +2926,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => { let item_name = self.tcx.item_name(trait_item_def_id); let msg = format!( - "the requirement `{}` appears on the `impl`'s {kind} `{}` but not on the \ - corresponding trait's {kind}", - predicate, item_name, + "the requirement `{predicate}` appears on the `impl`'s {kind} \ + `{item_name}` but not on the corresponding trait's {kind}", ); let sp = self .tcx @@ -2899,7 +2937,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut assoc_span: MultiSpan = sp.into(); assoc_span.push_span_label( sp, - format!("this trait's {kind} doesn't have the requirement `{}`", predicate), + format!("this trait's {kind} doesn't have the requirement `{predicate}`"), ); if let Some(ident) = self .tcx @@ -2918,7 +2956,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ObligationCauseCode::OpaqueReturnType(expr_info) => { if let Some((expr_ty, expr_span)) = expr_info { - let expr_ty = self.resolve_vars_if_possible(expr_ty); + let expr_ty = with_forced_trimmed_paths!(self.ty_to_string(expr_ty)); err.span_label( expr_span, format!("return type was inferred to be `{expr_ty}` here"), @@ -2964,7 +3002,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.tcx.mk_projection( item_def_id, // Future::Output has no substs - self.tcx.mk_substs_trait(trait_pred.self_ty(), []), + [trait_pred.self_ty()], ) }); let InferOk { value: projection_ty, .. } = @@ -3098,6 +3136,392 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } } + fn function_argument_obligation( + &self, + arg_hir_id: HirId, + err: &mut Diagnostic, + parent_code: &ObligationCauseCode<'tcx>, + param_env: ty::ParamEnv<'tcx>, + predicate: ty::Predicate<'tcx>, + call_hir_id: HirId, + ) { + let tcx = self.tcx; + let hir = tcx.hir(); + if let Some(Node::Expr(expr)) = hir.find(arg_hir_id) { + let parent_id = hir.get_parent_item(arg_hir_id); + let typeck_results: &TypeckResults<'tcx> = match &self.typeck_results { + Some(t) if t.hir_owner == parent_id => t, + _ => self.tcx.typeck(parent_id.def_id), + }; + if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr { + let expr = expr.peel_blocks(); + let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()); + let span = expr.span; + if Some(span) != err.span.primary_span() { + err.span_label( + span, + if ty.references_error() { + String::new() + } else { + let ty = with_forced_trimmed_paths!(self.ty_to_string(ty)); + format!("this tail expression is of type `{ty}`") + }, + ); + } + } + + // FIXME: visit the ty to see if there's any closure involved, and if there is, + // check whether its evaluated return type is the same as the one corresponding + // to an associated type (as seen from `trait_pred`) in the predicate. Like in + // trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>` + let mut type_diffs = vec![]; + + if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref() + && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx) + && let Some(pred) = predicates.predicates.get(*idx) + { + if let Ok(trait_pred) = pred.kind().try_map_bound(|pred| match pred { + ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred), + _ => Err(()), + }) + && let Ok(trait_predicate) = predicate.kind().try_map_bound(|pred| match pred { + ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred), + _ => Err(()), + }) + { + let mut c = CollectAllMismatches { + infcx: self.infcx, + param_env, + errors: vec![], + }; + if let Ok(_) = c.relate(trait_pred, trait_predicate) { + type_diffs = c.errors; + } + } else if let ty::PredicateKind::Clause( + ty::Clause::Projection(proj) + ) = pred.kind().skip_binder() + && let ty::PredicateKind::Clause( + ty::Clause::Projection(projection) + ) = predicate.kind().skip_binder() + { + type_diffs = vec![ + Sorts(ty::error::ExpectedFound { + expected: self.tcx.mk_ty(ty::Alias(ty::Projection, proj.projection_ty)), + found: projection.term.ty().unwrap(), + }), + ]; + } + } + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path + && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) + && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id) + && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id) + && let Some(binding_expr) = local.init + { + // If the expression we're calling on is a binding, we want to point at the + // `let` when talking about the type. Otherwise we'll point at every part + // of the method chain with the type. + self.point_at_chain(binding_expr, typeck_results, type_diffs, param_env, err); + } else { + self.point_at_chain(expr, typeck_results, type_diffs, param_env, err); + } + } + let call_node = hir.find(call_hir_id); + if let Some(Node::Expr(hir::Expr { + kind: hir::ExprKind::MethodCall(path, rcvr, ..), .. + })) = call_node + { + if Some(rcvr.span) == err.span.primary_span() { + err.replace_span_with(path.ident.span); + } + } + if let Some(Node::Expr(hir::Expr { + kind: + hir::ExprKind::Call(hir::Expr { span, .. }, _) + | hir::ExprKind::MethodCall(hir::PathSegment { ident: Ident { span, .. }, .. }, ..), + .. + })) = hir.find(call_hir_id) + { + if Some(*span) != err.span.primary_span() { + err.span_label(*span, "required by a bound introduced by this call"); + } + } + } + + fn point_at_chain( + &self, + expr: &hir::Expr<'_>, + typeck_results: &TypeckResults<'tcx>, + type_diffs: Vec<TypeError<'tcx>>, + param_env: ty::ParamEnv<'tcx>, + err: &mut Diagnostic, + ) { + let mut primary_spans = vec![]; + let mut span_labels = vec![]; + + let tcx = self.tcx; + + let mut print_root_expr = true; + let mut assocs = vec![]; + let mut expr = expr; + let mut prev_ty = self.resolve_vars_if_possible( + typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()), + ); + while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind { + // Point at every method call in the chain with the resulting type. + // vec![1, 2, 3].iter().map(mapper).sum<i32>() + // ^^^^^^ ^^^^^^^^^^^ + expr = rcvr_expr; + let assocs_in_this_method = + self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env); + assocs.push(assocs_in_this_method); + prev_ty = self.resolve_vars_if_possible( + typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()), + ); + + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path + && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) + && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id) + && let Some(parent) = self.tcx.hir().find(parent_hir_id) + { + // We've reached the root of the method call chain... + if let hir::Node::Local(local) = parent + && let Some(binding_expr) = local.init + { + // ...and it is a binding. Get the binding creation and continue the chain. + expr = binding_expr; + } + if let hir::Node::Param(param) = parent { + // ...and it is a an fn argument. + let prev_ty = self.resolve_vars_if_possible( + typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error()), + ); + let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env); + if assocs_in_this_method.iter().any(|a| a.is_some()) { + assocs.push(assocs_in_this_method); + print_root_expr = false; + } + break; + } + } + } + // We want the type before deref coercions, otherwise we talk about `&[_]` + // instead of `Vec<_>`. + if let Some(ty) = typeck_results.expr_ty_opt(expr) && print_root_expr { + let ty = with_forced_trimmed_paths!(self.ty_to_string(ty)); + // Point at the root expression + // vec![1, 2, 3].iter().map(mapper).sum<i32>() + // ^^^^^^^^^^^^^ + span_labels.push((expr.span, format!("this expression has type `{ty}`"))); + }; + // Only show this if it is not a "trivial" expression (not a method + // chain) and there are associated types to talk about. + let mut assocs = assocs.into_iter().peekable(); + while let Some(assocs_in_method) = assocs.next() { + let Some(prev_assoc_in_method) = assocs.peek() else { + for entry in assocs_in_method { + let Some((span, (assoc, ty))) = entry else { continue; }; + if primary_spans.is_empty() || type_diffs.iter().any(|diff| { + let Sorts(expected_found) = diff else { return false; }; + self.can_eq(param_env, expected_found.found, ty).is_ok() + }) { + // FIXME: this doesn't quite work for `Iterator::collect` + // because we have `Vec<i32>` and `()`, but we'd want `i32` + // to point at the `.into_iter()` call, but as long as we + // still point at the other method calls that might have + // introduced the issue, this is fine for now. + primary_spans.push(span); + } + span_labels.push(( + span, + with_forced_trimmed_paths!(format!( + "`{}` is `{ty}` here", + self.tcx.def_path_str(assoc), + )), + )); + } + break; + }; + for (entry, prev_entry) in + assocs_in_method.into_iter().zip(prev_assoc_in_method.into_iter()) + { + match (entry, prev_entry) { + (Some((span, (assoc, ty))), Some((_, (_, prev_ty)))) => { + let ty_str = with_forced_trimmed_paths!(self.ty_to_string(ty)); + + let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc)); + if self.can_eq(param_env, ty, *prev_ty).is_err() { + if type_diffs.iter().any(|diff| { + let Sorts(expected_found) = diff else { return false; }; + self.can_eq(param_env, expected_found.found, ty).is_ok() + }) { + primary_spans.push(span); + } + span_labels + .push((span, format!("`{assoc}` changed to `{ty_str}` here"))); + } else { + span_labels.push((span, format!("`{assoc}` remains `{ty_str}` here"))); + } + } + (Some((span, (assoc, ty))), None) => { + span_labels.push(( + span, + with_forced_trimmed_paths!(format!( + "`{}` is `{}` here", + self.tcx.def_path_str(assoc), + self.ty_to_string(ty), + )), + )); + } + (None, Some(_)) | (None, None) => {} + } + } + } + if !primary_spans.is_empty() { + let mut multi_span: MultiSpan = primary_spans.into(); + for (span, label) in span_labels { + multi_span.push_span_label(span, label); + } + err.span_note( + multi_span, + format!("the method call chain might not have had the expected associated types"), + ); + } + } + + fn probe_assoc_types_at_expr( + &self, + type_diffs: &[TypeError<'tcx>], + span: Span, + prev_ty: Ty<'tcx>, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>> { + let ocx = ObligationCtxt::new_in_snapshot(self.infcx); + let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len()); + for diff in type_diffs { + let Sorts(expected_found) = diff else { continue; }; + let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { continue; }; + + let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }; + let trait_def_id = proj.trait_def_id(self.tcx); + // Make `Self` be equivalent to the type of the call chain + // expression we're looking at now, so that we can tell what + // for example `Iterator::Item` is at this point in the chain. + let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { + match param.kind { + ty::GenericParamDefKind::Type { .. } => { + if param.index == 0 { + return prev_ty.into(); + } + } + ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Const { .. } => {} + } + self.var_for_def(span, param) + }); + // This will hold the resolved type of the associated type, if the + // current expression implements the trait that associated type is + // in. For example, this would be what `Iterator::Item` is here. + let ty_var = self.infcx.next_ty_var(origin); + // This corresponds to `<ExprTy as Iterator>::Item = _`. + let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection( + ty::ProjectionPredicate { + projection_ty: self.tcx.mk_alias_ty(proj.def_id, substs), + term: ty_var.into(), + }, + ))); + // Add `<ExprTy as Iterator>::Item = _` obligation. + ocx.register_obligation(Obligation::misc( + self.tcx, span, body_id, param_env, projection, + )); + if ocx.select_where_possible().is_empty() { + // `ty_var` now holds the type that `Item` is for `ExprTy`. + let ty_var = self.resolve_vars_if_possible(ty_var); + assocs_in_this_method.push(Some((span, (proj.def_id, ty_var)))); + } else { + // `<ExprTy as Iterator>` didn't select, so likely we've + // reached the end of the iterator chain, like the originating + // `Vec<_>`. + // Keep the space consistent for later zipping. + assocs_in_this_method.push(None); + } + } + assocs_in_this_method + } +} + +/// Add a hint to add a missing borrow or remove an unnecessary one. +fn hint_missing_borrow<'tcx>( + span: Span, + found_span: Span, + found: Ty<'tcx>, + expected: Ty<'tcx>, + found_node: Node<'_>, + err: &mut Diagnostic, +) { + let found_args = match found.kind() { + ty::FnPtr(f) => f.inputs().skip_binder().iter(), + kind => { + span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind) + } + }; + let expected_args = match expected.kind() { + ty::FnPtr(f) => f.inputs().skip_binder().iter(), + kind => { + span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) + } + }; + + let fn_decl = found_node + .fn_decl() + .unwrap_or_else(|| span_bug!(found_span, "found node must be a function")); + + let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span); + + fn get_deref_type_and_refs<'tcx>(mut ty: Ty<'tcx>) -> (Ty<'tcx>, usize) { + let mut refs = 0; + + while let ty::Ref(_, new_ty, _) = ty.kind() { + ty = *new_ty; + refs += 1; + } + + (ty, refs) + } + + let mut to_borrow = Vec::new(); + let mut remove_borrow = Vec::new(); + + for ((found_arg, expected_arg), arg_span) in found_args.zip(expected_args).zip(arg_spans) { + let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg); + let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg); + + if found_ty == expected_ty { + if found_refs < expected_refs { + to_borrow.push((arg_span, expected_arg.to_string())); + } else if found_refs > expected_refs { + remove_borrow.push((arg_span, expected_arg.to_string())); + } + } + } + + if !to_borrow.is_empty() { + err.multipart_suggestion( + "consider borrowing the argument", + to_borrow, + Applicability::MaybeIncorrect, + ); + } + + if !remove_borrow.is_empty() { + err.multipart_suggestion( + "do not borrow the argument", + remove_borrow, + Applicability::MaybeIncorrect, + ); + } } /// Collect all the returned expressions within the input expression. @@ -3207,13 +3631,6 @@ fn suggest_trait_object_return_type_alternatives( ) { err.span_suggestion( ret_ty, - "use some type `T` that is `T: Sized` as the return type if all return paths have the \ - same type", - "T", - Applicability::MaybeIncorrect, - ); - err.span_suggestion( - ret_ty, &format!( "use `impl {}` as the return type if all return paths have the same type but you \ want to expose only the trait in the signature", diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index ea4bf42c515..2566d793d78 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -425,13 +425,8 @@ pub fn fully_solve_bound<'tcx>( bound: DefId, ) -> Vec<FulfillmentError<'tcx>> { let tcx = infcx.tcx; - let trait_ref = ty::TraitRef { def_id: bound, substs: tcx.mk_substs_trait(ty, []) }; - let obligation = Obligation { - cause, - recursion_depth: 0, - param_env, - predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), - }; + let trait_ref = tcx.mk_trait_ref(bound, [ty]); + let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref)); fully_solve_obligation(infcx, obligation) } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index a45749fe48c..8b1ced78f4e 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -589,7 +589,7 @@ fn object_ty_for_trait<'tcx>( let pred = obligation.predicate.to_opt_poly_projection_pred()?; Some(pred.map_bound(|p| { ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - item_def_id: p.projection_ty.item_def_id, + def_id: p.projection_ty.def_id, substs: p.projection_ty.substs, term: p.term, }) @@ -694,18 +694,12 @@ fn receiver_is_dispatchable<'tcx>( // U: Trait<Arg1, ..., ArgN> let trait_predicate = { - let substs = - InternalSubsts::for_item(tcx, method.trait_container(tcx).unwrap(), |param, _| { - if param.index == 0 { - unsized_self_ty.into() - } else { - tcx.mk_param_from_def(param) - } - }); + let trait_def_id = method.trait_container(tcx).unwrap(); + let substs = InternalSubsts::for_item(tcx, trait_def_id, |param, _| { + if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) } + }); - ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs }) - .without_const() - .to_predicate(tcx) + ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, substs)).to_predicate(tcx) }; let caller_bounds: Vec<Predicate<'tcx>> = @@ -794,13 +788,13 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( ControlFlow::CONTINUE } } - ty::Projection(ref data) - if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder => + ty::Alias(ty::Projection, ref data) + if self.tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder => { // We'll deny these later in their own pass ControlFlow::CONTINUE } - ty::Projection(ref data) => { + ty::Alias(ty::Projection, ref data) => { // This is a projected type `<Foo as SomeTrait>::X`. // Compute supertraits of current trait lazily. @@ -861,10 +855,10 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>( // FIXME(RPITIT): Perhaps we should use a visitor here? ty.skip_binder().walk().find_map(|arg| { if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Projection(proj) = ty.kind() - && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder + && let ty::Alias(ty::Projection, proj) = ty.kind() + && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder { - Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.item_def_id))) + Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id))) } else { None } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 5789754e4fc..84d7244c1db 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -45,7 +45,7 @@ pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPre pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'tcx>>; -pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>>; +pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::AliasTy<'tcx>>; pub(super) struct InProgress; @@ -496,7 +496,9 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // This is really important. While we *can* handle this, this has // severe performance implications for large opaque types with // late-bound regions. See `issue-88862` benchmark. - ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) + if !substs.has_escaping_bound_vars() => + { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), @@ -523,7 +525,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } } - ty::Projection(data) if !data.has_escaping_bound_vars() => { + ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => { // This branch is *mostly* just an optimization: when we don't // have escaping bound vars, we don't need to replace them with // placeholders (see branch below). *Also*, we know that we can @@ -562,7 +564,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { normalized_ty.ty().unwrap() } - ty::Projection(data) => { + ty::Alias(ty::Projection, data) => { // If there are escaping bound vars, we temporarily replace the // bound vars with placeholders. Note though, that in the case // that we still can't project for whatever reason (e.g. self @@ -957,7 +959,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { pub fn normalize_projection_type<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, + projection_ty: ty::AliasTy<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut Vec<PredicateObligation<'tcx>>, @@ -995,7 +997,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>( fn opt_normalize_projection_type<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, + projection_ty: ty::AliasTy<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut Vec<PredicateObligation<'tcx>>, @@ -1177,7 +1179,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( fn normalize_to_error<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, + projection_ty: ty::AliasTy<'tcx>, cause: ObligationCause<'tcx>, depth: usize, ) -> NormalizedTy<'tcx> { @@ -1189,10 +1191,9 @@ fn normalize_to_error<'a, 'tcx>( predicate: trait_ref.without_const().to_predicate(selcx.tcx()), }; let tcx = selcx.infcx.tcx; - let def_id = projection_ty.item_def_id; let new_value = selcx.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::NormalizeProjectionType, - span: tcx.def_span(def_id), + span: tcx.def_span(projection_ty.def_id), }); Normalized { value: new_value, obligations: vec![trait_obligation] } } @@ -1270,7 +1271,7 @@ fn project<'cx, 'tcx>( // need to investigate whether or not this is fine. selcx .tcx() - .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs) + .mk_projection(obligation.predicate.def_id, obligation.predicate.substs) .into(), )), // Error occurred while trying to processing impls. @@ -1290,13 +1291,12 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { let tcx = selcx.tcx(); - if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder { - let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id); + if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder { + let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id); // If we are trying to project an RPITIT with trait's default `Self` parameter, // then we must be within a default trait body. if obligation.predicate.self_ty() - == ty::InternalSubsts::identity_for_item(tcx, obligation.predicate.item_def_id) - .type_at(0) + == ty::InternalSubsts::identity_for_item(tcx, obligation.predicate.def_id).type_at(0) && tcx.associated_item(trait_fn_def_id).defaultness(tcx).has_value() { candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait( @@ -1309,8 +1309,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( let trait_substs = obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id)); // FIXME(named-returns): Binders - let trait_predicate = - ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs }); + let trait_predicate = ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, trait_substs)); let _ = selcx.infcx.commit_if_ok(|_| { match selcx.select(&obligation.with(tcx, trait_predicate)) { @@ -1377,8 +1376,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( // Check whether the self-type is itself a projection. // If so, extract what we know from the trait and try to come up with a good answer. let bounds = match *obligation.predicate.self_ty().kind() { - ty::Projection(ref data) => tcx.bound_item_bounds(data.item_def_id).subst(tcx, data.substs), - ty::Opaque(def_id, substs) => tcx.bound_item_bounds(def_id).subst(tcx, substs), + ty::Alias(_, ref data) => tcx.bound_item_bounds(data.def_id).subst(tcx, data.substs), ty::Infer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. @@ -1430,7 +1428,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( }; let env_predicates = data .projection_bounds() - .filter(|bound| bound.item_def_id() == obligation.predicate.item_def_id) + .filter(|bound| bound.item_def_id() == obligation.predicate.def_id) .map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx)); assemble_candidates_from_predicates( @@ -1462,7 +1460,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( predicate.kind().skip_binder() { let data = bound_predicate.rebind(data); - if data.projection_def_id() != obligation.predicate.item_def_id { + if data.projection_def_id() != obligation.predicate.def_id { continue; } @@ -1503,7 +1501,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { // Can't assemble candidate from impl for RPITIT - if selcx.tcx().def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder { + if selcx.tcx().def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder { return; } @@ -1555,7 +1553,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // NOTE: This should be kept in sync with the similar code in // `rustc_ty_utils::instance::resolve_associated_item()`. let node_item = - assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id) + assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.def_id) .map_err(|ErrorGuaranteed { .. }| ())?; if node_item.is_final() { @@ -1616,8 +1614,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // type parameters, opaques, and unnormalized projections have pointer // metadata if they're known (e.g. by the param_env) to be sized ty::Param(_) - | ty::Projection(..) - | ty::Opaque(..) + | ty::Alias(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) @@ -1671,7 +1668,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // type parameters, opaques, and unnormalized projections have pointer // metadata if they're known (e.g. by the param_env) to be sized - ty::Param(_) | ty::Projection(..) | ty::Opaque(..) + ty::Param(_) | ty::Alias(..) if selcx.infcx.predicate_must_hold_modulo_regions( &obligation.with( selcx.tcx(), @@ -1687,8 +1684,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? ty::Param(_) - | ty::Projection(..) - | ty::Opaque(..) + | ty::Alias(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) @@ -1788,7 +1784,7 @@ fn confirm_candidate<'cx, 'tcx>( ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Trait) => Progress { term: selcx .tcx() - .mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs) + .mk_opaque(obligation.predicate.def_id, obligation.predicate.substs) .into(), obligations: vec![], }, @@ -1860,7 +1856,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( gen_sig, ) .map_bound(|(trait_ref, yield_ty, return_ty)| { - let name = tcx.associated_item(obligation.predicate.item_def_id).name; + let name = tcx.associated_item(obligation.predicate.def_id).name; let ty = if name == sym::Return { return_ty } else if name == sym::Yield { @@ -1870,10 +1866,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( }; ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - substs: trait_ref.substs, - item_def_id: obligation.predicate.item_def_id, - }, + projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.substs), term: ty.into(), } }); @@ -1909,13 +1902,10 @@ fn confirm_future_candidate<'cx, 'tcx>( gen_sig, ) .map_bound(|(trait_ref, return_ty)| { - debug_assert_eq!(tcx.associated_item(obligation.predicate.item_def_id).name, sym::Output); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output); ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - substs: trait_ref.substs, - item_def_id: obligation.predicate.item_def_id, - }, + projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.substs), term: return_ty.into(), } }); @@ -1934,7 +1924,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( let self_ty = obligation.predicate.self_ty(); let substs = tcx.mk_substs([self_ty.into()].iter()); let lang_items = tcx.lang_items(); - let item_def_id = obligation.predicate.item_def_id; + let item_def_id = obligation.predicate.def_id; let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) { let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); @@ -1969,7 +1959,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( }; let predicate = - ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { substs, item_def_id }, term }; + ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(item_def_id, substs), term }; confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) .with_addl_obligations(obligations) @@ -2038,10 +2028,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( flag, ) .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - substs: trait_ref.substs, - item_def_id: fn_once_output_def_id, - }, + projection_ty: tcx.mk_alias_ty(fn_once_output_def_id, trait_ref.substs), term: ret_type.into(), }); @@ -2122,7 +2109,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let tcx = selcx.tcx(); let ImplSourceUserDefinedData { impl_def_id, substs, mut nested } = impl_impl_source; - let assoc_item_id = obligation.predicate.item_def_id; + let assoc_item_id = obligation.predicate.def_id; let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); let param_env = obligation.param_env; @@ -2222,7 +2209,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( let tcx = selcx.tcx(); let mut obligations = data.nested; - let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id); + let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id); let Ok(leaf_def) = assoc_def(selcx, data.impl_def_id, trait_fn_def_id) else { return Progress { term: tcx.ty_error().into(), obligations }; }; @@ -2233,9 +2220,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( // Use the default `impl Trait` for the trait, e.g., for a default trait body if leaf_def.item.container == ty::AssocItemContainer::TraitContainer { return Progress { - term: tcx - .mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs) - .into(), + term: tcx.mk_opaque(obligation.predicate.def_id, obligation.predicate.substs).into(), obligations, }; } @@ -2302,7 +2287,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( obligation.recursion_depth + 1, tcx.bound_trait_impl_trait_tys(impl_fn_def_id) .map_bound(|tys| { - tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id]) + tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.def_id]) }) .subst(tcx, impl_fn_substs), &mut obligations, @@ -2320,7 +2305,7 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( ) { let tcx = selcx.tcx(); let own = tcx - .predicates_of(obligation.predicate.item_def_id) + .predicates_of(obligation.predicate.def_id) .instantiate_own(tcx, obligation.predicate.substs); for (predicate, span) in std::iter::zip(own.predicates, own.spans) { let normalized = normalize_with_depth_to( @@ -2343,13 +2328,13 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( ObligationCause::new( obligation.cause.span, obligation.cause.body_id, - super::ItemObligation(obligation.predicate.item_def_id), + super::ItemObligation(obligation.predicate.def_id), ) } else { ObligationCause::new( obligation.cause.span, obligation.cause.body_id, - super::BindingObligation(obligation.predicate.item_def_id, span), + super::BindingObligation(obligation.predicate.def_id, span), ) }; nested.push(Obligation::with_depth( diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index aad3c37f84e..0f21813bc40 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -62,9 +62,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { // The following *might* require a destructor: needs deeper inspection. ty::Dynamic(..) - | ty::Projection(..) + | ty::Alias(..) | ty::Param(_) - | ty::Opaque(..) | ty::Placeholder(..) | ty::Infer(_) | ty::Bound(..) diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 7ad532d8a34..c6ef13e185b 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -205,7 +205,9 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // This is really important. While we *can* handle this, this has // severe performance implications for large opaque types with // late-bound regions. See `issue-88862` benchmark. - ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) + if !substs.has_escaping_bound_vars() => + { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.try_super_fold_with(self), @@ -242,7 +244,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } } - ty::Projection(data) if !data.has_escaping_bound_vars() => { + ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => { // This branch is just an optimization: when we don't have escaping bound vars, // we don't need to replace them with placeholders (see branch below). @@ -291,7 +293,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } } - ty::Projection(data) => { + ty::Alias(ty::Projection, data) => { // See note in `rustc_trait_selection::traits::project` let tcx = self.infcx.tcx; diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs index bfa318787e5..34b5fc4891e 100644 --- a/compiler/rustc_trait_selection/src/traits/relationships.rs +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -26,7 +26,7 @@ pub(crate) fn update<'tcx, T>( .kind() .rebind( // (*) binder moved here - ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_type(infcx.tcx, new_self_ty))) + ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(infcx.tcx, new_self_ty))) ), ); // Don't report overflow errors. Otherwise equivalent to may_hold. diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e4b70f0d2ff..c54d901e9b1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -138,7 +138,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. match obligation.predicate.skip_binder().trait_ref.self_ty().kind() { - ty::Projection(_) | ty::Opaque(..) => {} + ty::Alias(..) => {} ty::Infer(ty::TyVar(_)) => { span_bug!( obligation.cause.span, @@ -394,7 +394,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // still be provided by a manual implementation for // this trait and type. } - ty::Param(..) | ty::Projection(..) => { + ty::Param(..) | ty::Alias(ty::Projection, ..) => { // In these cases, we don't know what the actual // type is. Therefore, we cannot break it down // into its constituent types. So we don't @@ -536,10 +536,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let ty = traits::normalize_projection_type( self, param_env, - ty::ProjectionTy { - item_def_id: tcx.lang_items().deref_target()?, - substs: trait_ref.substs, - }, + tcx.mk_alias_ty(tcx.lang_items().deref_target()?, trait_ref.substs), cause.clone(), 0, // We're *intentionally* throwing these away, @@ -737,13 +734,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); match self_ty.skip_binder().kind() { - ty::Opaque(..) + ty::Alias(..) | ty::Dynamic(..) | ty::Error(_) | ty::Bound(..) | ty::Param(_) - | ty::Placeholder(_) - | ty::Projection(_) => { + | ty::Placeholder(_) => { // We don't know if these are `~const Destruct`, at least // not structurally... so don't push a candidate. } @@ -829,8 +825,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Generator(_, _, _) | ty::GeneratorWitness(_) | ty::Never - | ty::Projection(_) - | ty::Opaque(_, _) + | ty::Alias(..) | ty::Param(_) | ty::Bound(_, _) | ty::Error(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index fda415155c4..f6fe71fbd4f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -155,8 +155,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); let (def_id, substs) = match *placeholder_self_ty.kind() { - ty::Projection(proj) => (proj.item_def_id, proj.substs), - ty::Opaque(def_id, substs) => (def_id, substs), + ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs), _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty), }; @@ -184,7 +183,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|_| Unimplemented) })?); - if let ty::Projection(..) = placeholder_self_ty.kind() { + if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() { let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates; debug!(?predicates, "projection predicates"); for predicate in predicates { @@ -1279,7 +1278,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If we have a projection type, make sure to normalize it so we replace it // with a fresh infer variable - ty::Projection(..) => { + ty::Alias(ty::Projection, ..) => { let predicate = normalize_with_depth_to( self, obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 035deb61639..792933096b1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1595,8 +1595,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.infcx.tcx; let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { - ty::Projection(ref data) => (data.item_def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), + ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs), _ => { span_bug!( obligation.cause.span, @@ -1745,7 +1744,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); if is_match { - let generics = self.tcx().generics_of(obligation.predicate.item_def_id); + let generics = self.tcx().generics_of(obligation.predicate.def_id); // FIXME(generic-associated-types): Addresses aggressive inference in #92917. // If this type is a GAT, and of the GAT substs resolve to something new, // that means that we must have newly inferred something about the GAT. @@ -2067,7 +2066,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { })) } - ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None, + ty::Alias(..) | ty::Param(_) => None, ty::Infer(ty::TyVar(_)) => Ambiguous, ty::Placeholder(..) @@ -2167,7 +2166,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => { + ty::Adt(..) | ty::Alias(..) | ty::Param(..) => { // Fallback to whatever user-defined impls exist in this case. None } @@ -2220,7 +2219,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) - | ty::Projection(..) + | ty::Alias(ty::Projection, ..) | ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("asked to assemble constituent types of unexpected type: {:?}", t); @@ -2260,7 +2259,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect()) } - ty::Opaque(def_id, substs) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 4dc08e0f9da..892a7afd799 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -95,10 +95,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { ty::Foreign(_) => { return ControlFlow::Break(ty); } - ty::Opaque(..) => { - return ControlFlow::Break(ty); - } - ty::Projection(..) => { + ty::Alias(..) => { return ControlFlow::Break(ty); } ty::Closure(..) => { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index e47ba64245f..0e0a883d9f5 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -234,9 +234,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // projection coming from another associated type. See // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and // `traits-assoc-type-in-supertrait-bad.rs`. - if let Some(ty::Projection(projection_ty)) = proj.term.ty().map(|ty| ty.kind()) + if let Some(ty::Alias(ty::Projection, projection_ty)) = proj.term.ty().map(|ty| ty.kind()) && let Some(&impl_item_id) = - tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id) + tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id) && let Some(impl_item_span) = items .iter() .find(|item| item.id.owner_id.to_def_id() == impl_item_id) @@ -249,9 +249,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // An associated item obligation born out of the `trait` failed to be met. An example // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); - if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = *pred.self_ty().kind() + if let ty::Alias(ty::Projection, ty::AliasTy { def_id, .. }) = *pred.self_ty().kind() && let Some(&impl_item_id) = - tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id) + tcx.impl_item_implementor_ids(impl_def_id).get(&def_id) && let Some(impl_item_span) = items .iter() .find(|item| item.id.owner_id.to_def_id() == impl_item_id) @@ -369,7 +369,7 @@ impl<'tcx> WfPredicates<'tcx> { /// Pushes the obligations required for `trait_ref::Item` to be WF /// into `self.out`. - fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) { + fn compute_projection(&mut self, data: ty::AliasTy<'tcx>) { // A projection is well-formed if // // (a) its predicates hold (*) @@ -392,7 +392,7 @@ impl<'tcx> WfPredicates<'tcx> { // `i32: Copy` // ] // Projection types do not require const predicates. - let obligations = self.nominal_obligations_without_const(data.item_def_id, data.substs); + let obligations = self.nominal_obligations_without_const(data.def_id, data.substs); self.out.extend(obligations); let tcx = self.tcx(); @@ -451,19 +451,21 @@ impl<'tcx> WfPredicates<'tcx> { GenericArgKind::Const(ct) => { match ct.kind() { ty::ConstKind::Unevaluated(uv) => { - let obligations = self.nominal_obligations(uv.def.did, uv.substs); - self.out.extend(obligations); - - let predicate = - ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct)); - let cause = self.cause(traits::WellFormed(None)); - self.out.push(traits::Obligation::with_depth( - self.tcx(), - cause, - self.recursion_depth, - self.param_env, - predicate, - )); + if !ct.has_escaping_bound_vars() { + let obligations = self.nominal_obligations(uv.def.did, uv.substs); + self.out.extend(obligations); + + let predicate = + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct)); + let cause = self.cause(traits::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + self.tcx(), + cause, + self.recursion_depth, + self.param_env, + predicate, + )); + } } ty::ConstKind::Infer(_) => { let cause = self.cause(traits::WellFormed(None)); @@ -556,7 +558,7 @@ impl<'tcx> WfPredicates<'tcx> { // Simple cases that are WF if their type args are WF. } - ty::Projection(data) => { + ty::Alias(ty::Projection, data) => { walker.skip_current_subtree(); // Subtree handled by compute_projection. self.compute_projection(data); } @@ -648,12 +650,12 @@ impl<'tcx> WfPredicates<'tcx> { // types appearing in the fn signature } - ty::Opaque(did, substs) => { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { // All of the requirements on type parameters // have already been checked for `impl Trait` in // return position. We do need to check type-alias-impl-trait though. - if ty::is_impl_trait_defn(self.tcx, did).is_none() { - let obligations = self.nominal_obligations(did, substs); + if ty::is_impl_trait_defn(self.tcx, def_id).is_none() { + let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); } } |
