diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:50 +0000 |
commit | 2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35 (patch) | |
tree | d325add32978dbdc1db975a438b3a77d571b1ab8 /compiler/rustc_trait_selection/src/traits | |
parent | Releasing progress-linux version 1.68.2+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35.tar.xz rustc-2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35.zip |
Merging upstream version 1.69.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits')
32 files changed, 1088 insertions, 652 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 948632ccc..1fb8659bb 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -9,7 +9,7 @@ use crate::infer::InferCtxt; use crate::traits::project::ProjectAndUnifyResult; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ImplPolarity, Region, RegionVid}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; @@ -350,14 +350,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { ) .map(|o| o.predicate); new_env = ty::ParamEnv::new( - tcx.mk_predicates(normalized_preds), + tcx.mk_predicates_from_iter(normalized_preds), param_env.reveal(), param_env.constness(), ); } let final_user_env = ty::ParamEnv::new( - tcx.mk_predicates(user_computed_preds.into_iter()), + tcx.mk_predicates_from_iter(user_computed_preds.into_iter()), user_env.reveal(), user_env.constness(), ); @@ -823,14 +823,18 @@ impl<'tcx> AutoTraitFinder<'tcx> { _ => return false, } } + // There's not really much we can do with these predicates - // we start out with a `ParamEnv` with no inference variables, // and these don't correspond to adding any new bounds to // the `ParamEnv`. ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::AliasEq(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) + // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} @@ -855,8 +859,8 @@ pub struct RegionReplacer<'a, 'tcx> { tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { +impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionReplacer<'a, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index e88950523..b42a49eb4 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -7,24 +7,18 @@ use crate::traits::{ ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, PredicateObligation, SelectionError, TraitEngine, }; -use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_middle::ty::{self, TypeVisitable}; +use rustc_data_structures::fx::FxIndexSet; +use rustc_middle::ty::TypeVisitableExt; pub struct FulfillmentContext<'tcx> { obligations: FxIndexSet<PredicateObligation<'tcx>>, - relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>, - usable_in_snapshot: bool, } impl FulfillmentContext<'_> { pub(super) fn new() -> Self { - FulfillmentContext { - obligations: FxIndexSet::default(), - relationships: FxHashMap::default(), - usable_in_snapshot: false, - } + FulfillmentContext { obligations: FxIndexSet::default(), usable_in_snapshot: false } } pub(crate) fn new_in_snapshot() -> Self { @@ -43,20 +37,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { } let obligation = infcx.resolve_vars_if_possible(obligation); - super::relationships::update(self, infcx, &obligation); - self.obligations.insert(obligation); } - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - { - let errors = self.select_where_possible(infcx); - - if !errors.is_empty() { - return errors; - } - } - + fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> { // any remaining obligations are errors self.obligations .iter() @@ -151,11 +135,14 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { errors } - fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { - self.obligations.iter().cloned().collect() + fn drain_unstalled_obligations( + &mut self, + _: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>> { + unimplemented!() } - fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> { - &mut self.relationships + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { + self.obligations.iter().cloned().collect() } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 225c1050c..6b688c322 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -17,12 +17,11 @@ use crate::traits::{ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_hir::CRATE_HIR_ID; use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor}; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; @@ -83,8 +82,8 @@ pub fn overlapping_impls( (Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs) .all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)), (None, None) => { - let self_ty1 = tcx.type_of(impl1_def_id); - let self_ty2 = tcx.type_of(impl2_def_id); + let self_ty1 = tcx.type_of(impl1_def_id).skip_binder(); + let self_ty2 = tcx.type_of(impl2_def_id).skip_binder(); drcx.types_may_unify(self_ty1, self_ty2) } _ => bug!("unexpected impls: {impl1_def_id:?} {impl2_def_id:?}"), @@ -125,7 +124,7 @@ fn with_fresh_ty_vars<'cx, 'tcx>( let header = ty::ImplHeader { impl_def_id, - self_ty: tcx.bound_type_of(impl_def_id).subst(tcx, impl_substs), + self_ty: tcx.type_of(impl_def_id).subst(tcx, impl_substs), trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)), predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates, }; @@ -218,6 +217,7 @@ fn equate_impl_headers<'cx, 'tcx>( selcx .infcx .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) + .define_opaque_types(true) .eq_impl_headers(impl1_header, impl2_header) .map(|infer_ok| infer_ok.obligations) .ok() @@ -382,18 +382,14 @@ fn resolve_negative_obligation<'tcx>( return false; } - let (body_id, body_def_id) = if let Some(body_def_id) = body_def_id.as_local() { - (tcx.hir().local_def_id_to_hir_id(body_def_id), body_def_id) - } else { - (CRATE_HIR_ID, CRATE_DEF_ID) - }; + let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID); let ocx = ObligationCtxt::new(&infcx); let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id); let outlives_env = OutlivesEnvironment::with_bounds( param_env, Some(&infcx), - infcx.implied_bounds_tys(param_env, body_id, wf_tys), + infcx.implied_bounds_tys(param_env, body_def_id, wf_tys), ); infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); @@ -632,7 +628,7 @@ enum OrphanCheckEarlyExit<'tcx> { LocalTy(Ty<'tcx>), } -impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> { type BreakTy = OrphanCheckEarlyExit<'tcx>; fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { ControlFlow::Continue(()) @@ -701,7 +697,9 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { // This should only be created when checking whether we have to check whether some // auto trait impl applies. There will never be multiple impls, so we can just // act as if it were a local type here. - ty::GeneratorWitness(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), + ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(..) => { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } ty::Alias(ty::Opaque, ..) => { // This merits some explanation. // Normally, opaque types are not involved when performing diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index f779d9dd8..345e84990 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::abstract_const::NotConstEvaluatable; -use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitor}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_span::Span; use std::ops::ControlFlow; @@ -171,7 +171,7 @@ fn satisfied_from_param_env<'tcx>( single_match: Option<Result<ty::Const<'tcx>, ()>>, } - impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> { + impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'a, 'tcx> { type BreakTy = (); fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { debug!("is_const_evaluatable: candidate={:?}", c); @@ -219,7 +219,7 @@ fn satisfied_from_param_env<'tcx>( } if let Some(Ok(c)) = single_match { - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_in_snapshot(infcx); assert!(ocx.eq(&ObligationCause::dummy(), param_env, c.ty(), ct.ty()).is_ok()); assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok()); assert!(ocx.select_all_or_error().is_empty()); diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 369f80139..b20636174 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -104,7 +104,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { }); } - pub fn normalize<T: TypeFoldable<'tcx>>( + pub fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -128,6 +128,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { { self.infcx .at(cause, param_env) + .define_opaque_types(true) .eq_exp(a_is_expected, a, b) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } @@ -141,6 +142,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { ) -> Result<(), TypeError<'tcx>> { self.infcx .at(cause, param_env) + .define_opaque_types(true) .eq(expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } @@ -155,6 +157,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { ) -> Result<(), TypeError<'tcx>> { self.infcx .at(cause, param_env) + .define_opaque_types(true) .sup(expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } @@ -169,6 +172,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { ) -> Result<(), TypeError<'tcx>> { self.infcx .at(cause, param_env) + .define_opaque_types(true) .sup(expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } @@ -190,8 +194,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { let tcx = self.infcx.tcx; let assumed_wf_types = tcx.assumed_wf_types(def_id); let mut implied_bounds = FxIndexSet::default(); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let cause = ObligationCause::misc(span, hir_id); + let cause = ObligationCause::misc(span, def_id); for ty in assumed_wf_types { // FIXME(@lcnr): rustc currently does not check wf for types // pre-normalization, meaning that implied bounds are sometimes @@ -217,7 +220,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { answer: T, ) -> Fallible<CanonicalQueryResponse<'tcx, T>> where - T: Debug + TypeFoldable<'tcx>, + T: Debug + TypeFoldable<TyCtxt<'tcx>>, Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, { self.infcx.make_canonicalized_query_response( 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 0419bb3f7..84045c4d0 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -22,7 +22,7 @@ pub fn recompute_applicable_impls<'tcx>( 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); + infcx.instantiate_binder_with_placeholders(obligation.predicate); let obligation_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); @@ -47,11 +47,11 @@ pub fn recompute_applicable_impls<'tcx>( 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); + infcx.instantiate_binder_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( + let param_env_predicate = infcx.instantiate_binder_with_fresh_vars( DUMMY_SP, LateBoundRegionConversionTime::HigherRankedType, poly_trait_predicate, @@ -81,7 +81,7 @@ pub fn recompute_applicable_impls<'tcx>( ); let predicates = - tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx); + tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx); for obligation in elaborate_predicates_with_span(tcx, predicates.into_iter()) { let kind = obligation.predicate.kind(); if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder() 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 index ba9ee57d4..1174efdbf 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs @@ -1,5 +1,7 @@ use crate::infer::InferCtxt; +use rustc_infer::infer::ObligationEmittingRelation; +use rustc_infer::traits::PredicateObligations; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -88,3 +90,16 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> { Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } } + +impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> { + fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) { + // FIXME(deferred_projection_equality) + } + + fn register_predicates( + &mut self, + _obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>, + ) { + // FIXME(deferred_projection_equality) + } +} 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 52971486c..a844a1494 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -38,7 +38,7 @@ use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print}; use rustc_middle::ty::{ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, - TypeVisitable, + TypeVisitable, TypeVisitableExt, }; use rustc_session::config::TraitSolver; use rustc_session::Limit; @@ -101,6 +101,18 @@ pub trait InferCtxtExt<'tcx> { } pub trait TypeErrCtxtExt<'tcx> { + fn build_overflow_error<T>( + &self, + predicate: &T, + span: Span, + suggest_increasing_limit: bool, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> + where + T: fmt::Display + + TypeFoldable<TyCtxt<'tcx>> + + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, + <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug; + fn report_overflow_error<T>( &self, predicate: &T, @@ -110,7 +122,7 @@ pub trait TypeErrCtxtExt<'tcx> { ) -> ! where T: fmt::Display - + TypeFoldable<'tcx> + + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug; @@ -480,7 +492,27 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) -> ! where T: fmt::Display - + TypeFoldable<'tcx> + + TypeFoldable<TyCtxt<'tcx>> + + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, + <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, + { + let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit); + mutate(&mut err); + err.emit(); + + self.tcx.sess.abort_if_errors(); + bug!(); + } + + fn build_overflow_error<T>( + &self, + predicate: &T, + span: Span, + suggest_increasing_limit: bool, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> + where + T: fmt::Display + + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, { @@ -511,11 +543,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_new_overflow_limit(&mut err); } - mutate(&mut err); - - err.emit(); - self.tcx.sess.abort_if_errors(); - bug!(); + err } /// Reports that an overflow has occurred and halts compilation. We @@ -839,14 +867,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note(s.as_str()); } if let Some(ref s) = parent_label { - let body = tcx - .hir() - .opt_local_def_id(obligation.cause.body_id) - .unwrap_or_else(|| { - tcx.hir().body_owner_def_id(hir::BodyId { - hir_id: obligation.cause.body_id, - }) - }); + let body = obligation.cause.body_id; err.span_label(tcx.def_span(body), s); } @@ -934,6 +955,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } + let body_hir_id = + self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); // Try to report a help message if is_fn_trait && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( @@ -1014,7 +1037,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if !self.report_similar_impl_candidates( impl_candidates, trait_ref, - obligation.cause.body_id, + body_hir_id, &mut err, true, ) { @@ -1050,7 +1073,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.report_similar_impl_candidates( impl_candidates, trait_ref, - obligation.cause.body_id, + body_hir_id, &mut err, true, ); @@ -1207,20 +1230,23 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ty::PredicateKind::WellFormed(ty) => { - if self.tcx.sess.opts.unstable_opts.trait_solver == TraitSolver::Classic { - // WF predicates cannot themselves make - // errors. They can only block due to - // ambiguity; otherwise, they always - // degenerate into other obligations - // (which may fail). - span_bug!(span, "WF predicate not satisfied for {:?}", ty); - } else { - // FIXME: we'll need a better message which takes into account - // which bounds actually failed to hold. - self.tcx.sess.struct_span_err( - span, - &format!("the type `{}` is not well-formed", ty), - ) + match self.tcx.sess.opts.unstable_opts.trait_solver { + TraitSolver::Classic => { + // WF predicates cannot themselves make + // errors. They can only block due to + // ambiguity; otherwise, they always + // degenerate into other obligations + // (which may fail). + span_bug!(span, "WF predicate not satisfied for {:?}", ty); + } + TraitSolver::Chalk | TraitSolver::Next => { + // FIXME: we'll need a better message which takes into account + // which bounds actually failed to hold. + self.tcx.sess.struct_span_err( + span, + &format!("the type `{}` is not well-formed", ty), + ) + } } } @@ -1252,6 +1278,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span, "TypeWellFormedFromEnv predicate should only exist in the environment" ), + + ty::PredicateKind::AliasEq(..) => span_bug!( + span, + "AliasEq predicate should never be the predicate cause of a SelectionError" + ), + + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + self.tcx.sess.struct_span_err( + span, + &format!("the constant `{}` is not of type `{}`", ct, ty), + ) + } } } @@ -1598,7 +1636,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Eventually I'll need to implement param-env-aware // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. let param_env = ty::ParamEnv::empty(); - if self.can_sub(param_env, error, implication).is_ok() { + if self.can_sub(param_env, error, implication) { debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication); return true; } @@ -1690,7 +1728,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) = bound_predicate.skip_binder() { - let data = self.replace_bound_vars_with_fresh_vars( + let data = self.instantiate_binder_with_fresh_vars( obligation.cause.span, infer::LateBoundRegionConversionTime::HigherRankedType, bound_predicate.rebind(data), @@ -1843,10 +1881,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { with_forced_trimmed_paths! { if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() { + let fn_kind = self_ty.prefix_string(self.tcx); + let item = match self_ty.kind() { + ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(), + _ => self_ty.to_string(), + }; Some(format!( - "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it \ + "expected `{item}` 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!( @@ -1896,6 +1938,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Generator(..) => Some(16), ty::Foreign(..) => Some(17), ty::GeneratorWitness(..) => Some(18), + ty::GeneratorWitnessMIR(..) => Some(19), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } @@ -2062,7 +2105,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Ignore automatically derived impls and `!Trait` impls. .filter(|&def_id| { self.tcx.impl_polarity(def_id) != ty::ImplPolarity::Negative - || self.tcx.is_builtin_derive(def_id) + || self.tcx.is_automatically_derived(def_id) }) .filter_map(|def_id| self.tcx.impl_trait_ref(def_id)) .map(ty::EarlyBinder::subst_identity) @@ -2305,10 +2348,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { predicate.to_opt_poly_trait_pred().unwrap(), ); if impl_candidates.len() < 10 { + let hir = + self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); self.report_similar_impl_candidates( impl_candidates, trait_ref, - body_id.map(|id| id.hir_id).unwrap_or(obligation.cause.body_id), + body_id.map(|id| id.hir_id).unwrap_or(hir), &mut err, false, ); @@ -2395,7 +2440,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }; let mut suggestions = vec![( path.span.shrink_to_lo(), - format!("<{} as ", self.tcx.type_of(impl_def_id)) + format!("<{} as ", self.tcx.type_of(impl_def_id).subst_identity()) )]; if let Some(generic_arg) = trait_path_segment.args { let between_span = trait_path_segment.ident.span.between(generic_arg.span_ext); @@ -2637,8 +2682,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>, } - impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ParamToVarFolder<'a, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -2828,7 +2873,7 @@ pub struct FindExprBySpan<'hir> { } impl<'hir> FindExprBySpan<'hir> { - fn new(span: Span) -> Self { + pub fn new(span: Span) -> Self { Self { span, result: None, ty_result: None } } } @@ -2926,7 +2971,7 @@ impl ArgKind { struct HasNumericInferVisitor; -impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor { +impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor { type BreakTy = (); fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 18d308f71..b3bf9ad59 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -60,7 +60,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) -> Option<(DefId, SubstsRef<'tcx>)> { let tcx = self.tcx; let param_env = obligation.param_env; - let trait_ref = tcx.erase_late_bound_regions(trait_ref); + let trait_ref = self.instantiate_binder_with_placeholders(trait_ref); let trait_self_ty = trait_ref.self_ty(); let mut self_match_impls = vec![]; @@ -72,7 +72,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let impl_self_ty = impl_trait_ref.self_ty(); - if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) { + if self.can_eq(param_env, trait_self_ty, impl_self_ty) { self_match_impls.push((def_id, impl_substs)); if iter::zip( @@ -149,10 +149,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs)); let trait_ref = trait_ref.skip_binder(); - let mut flags = vec![( - sym::ItemContext, - self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()), - )]; + let body_hir = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); + let mut flags = + vec![(sym::ItemContext, self.describe_enclosure(body_hir).map(|s| s.to_owned()))]; match obligation.cause.code() { ObligationCauseCode::BuiltinDerivedObligation(..) @@ -201,7 +200,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some(def) = self_ty.ty_adt_def() { // We also want to be able to select self's original // signature with no type arguments resolved - flags.push((sym::_Self, Some(self.tcx.type_of(def.did()).to_string()))); + flags.push(( + sym::_Self, + Some(self.tcx.type_of(def.did()).subst_identity().to_string()), + )); } for param in generics.params.iter() { @@ -219,7 +221,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some(def) = param_ty.ty_adt_def() { // We also want to be able to select the parameter's // original signature with no type arguments resolved - flags.push((name, Some(self.tcx.type_of(def.did()).to_string()))); + flags.push(( + name, + Some(self.tcx.type_of(def.did()).subst_identity().to_string()), + )); } } } @@ -252,7 +257,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some(def) = aty.ty_adt_def() { // We also want to be able to select the slice's type's original // signature with no type arguments resolved - flags.push((sym::_Self, Some(format!("[{}]", self.tcx.type_of(def.did()))))); + flags.push(( + sym::_Self, + Some(format!("[{}]", self.tcx.type_of(def.did()).subst_identity())), + )); } if aty.is_integral() { flags.push((sym::_Self, Some("[{integral}]".to_string()))); @@ -262,7 +270,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]` if let ty::Array(aty, len) = self_ty.kind() { flags.push((sym::_Self, Some("[]".to_string()))); - let len = len.kind().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx)); + let len = len.kind().try_to_value().and_then(|v| v.try_to_target_usize(self.tcx)); flags.push((sym::_Self, Some(format!("[{}; _]", aty)))); if let Some(n) = len { flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n)))); @@ -270,7 +278,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some(def) = aty.ty_adt_def() { // We also want to be able to select the array's type's original // signature with no type arguments resolved - let def_ty = self.tcx.type_of(def.did()); + let def_ty = self.tcx.type_of(def.did()).subst_identity(); flags.push((sym::_Self, Some(format!("[{def_ty}; _]")))); if let Some(n) = len { flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]")))); 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 39e50b2ac..66d74fd05 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -9,7 +9,6 @@ use crate::infer::InferCtxt; use crate::traits::{NormalizeExt, ObligationCtxt}; use hir::def::CtorOf; -use hir::{Expr, HirId}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ @@ -20,8 +19,10 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; +use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; +use rustc_hir::{Expr, HirId}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime}; @@ -32,8 +33,9 @@ use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts, IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitable, TypeckResults, + TypeSuperFoldable, TypeVisitableExt, TypeckResults, }; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; use rustc_target::spec::abi; @@ -80,11 +82,8 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> { upvars.iter().find_map(|(upvar_id, upvar)| { let upvar_ty = typeck_results.node_type(*upvar_id); let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty); - if ty_matches(ty::Binder::dummy(upvar_ty)) { - Some(GeneratorInteriorOrUpvar::Upvar(upvar.span)) - } else { - None - } + ty_matches(ty::Binder::dummy(upvar_ty)) + .then(|| GeneratorInteriorOrUpvar::Upvar(upvar.span)) }) }) } @@ -97,6 +96,7 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> { // obligation fn get_from_await_ty<F>( &self, + tcx: TyCtxt<'tcx>, visitor: AwaitsVisitor, hir: map::Map<'tcx>, ty_matches: F, @@ -132,10 +132,8 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> { .cloned() .unwrap_or_else(|| { bug!( - "node_type: no type for node `{}`", - ty::tls::with(|tcx| tcx - .hir() - .node_to_string(await_expr.hir_id)) + "node_type: no type for node {}", + tcx.hir().node_to_string(await_expr.hir_id) ) }) }, @@ -179,7 +177,7 @@ pub trait TypeErrCtxtExt<'tcx> { err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, associated_item: Option<(&'static str, Ty<'tcx>)>, - body_id: hir::HirId, + body_id: LocalDefId, ); fn suggest_dereferences( @@ -398,7 +396,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) - /// param for cleaner code. fn suggest_restriction<'tcx>( tcx: TyCtxt<'tcx>, - hir_id: HirId, + item_id: LocalDefId, hir_generics: &hir::Generics<'tcx>, msg: &str, err: &mut Diagnostic, @@ -417,7 +415,6 @@ fn suggest_restriction<'tcx>( { return; } - let Some(item_id) = hir_id.as_owner() else { return; }; let generics = tcx.generics_of(item_id); // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... if let Some((param, bound_str, fn_sig)) = @@ -522,7 +519,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { mut err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, associated_ty: Option<(&'static str, Ty<'tcx>)>, - body_id: hir::HirId, + mut body_id: LocalDefId, ) { let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); @@ -535,8 +532,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we // don't suggest `T: Sized + ?Sized`. - let mut hir_id = body_id; - while let Some(node) = self.tcx.hir().find(hir_id) { + while let Some(node) = self.tcx.hir().find_by_def_id(body_id) { match node { hir::Node::Item(hir::Item { ident, @@ -547,7 +543,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Restricting `Self` for a single method. suggest_restriction( self.tcx, - hir_id, + body_id, &generics, "`Self`", err, @@ -567,7 +563,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { assert!(param_ty); // Restricting `Self` for a single method. suggest_restriction( - self.tcx, hir_id, &generics, "`Self`", err, None, projection, trait_pred, + self.tcx, body_id, &generics, "`Self`", err, None, projection, trait_pred, None, ); return; @@ -589,7 +585,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( self.tcx, - hir_id, + body_id, &generics, "the associated type", err, @@ -609,7 +605,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( self.tcx, - hir_id, + body_id, &generics, "the associated type", err, @@ -680,6 +676,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ¶m_name, &constraint, Some(trait_pred.def_id()), + None, ) { return; } @@ -713,8 +710,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => {} } - - hir_id = self.tcx.hir().get_parent_item(hir_id).into(); + body_id = self.tcx.local_parent(body_id); } } @@ -749,10 +745,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let real_ty = real_trait_pred.self_ty(); // We `erase_late_bound_regions` here because `make_subregion` does not handle // `ReLateBound`, and we don't particularly care about the regions. - if self - .can_eq(obligation.param_env, self.tcx.erase_late_bound_regions(real_ty), arg_ty) - .is_err() - { + if !self.can_eq( + obligation.param_env, + self.tcx.erase_late_bound_regions(real_ty), + arg_ty, + ) { continue; } @@ -770,15 +767,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation.param_env, real_trait_pred_and_ty, ); - if obligations + let may_hold = obligations .iter() .chain([&obligation]) .all(|obligation| self.predicate_may_hold(obligation)) - { - Some(steps) - } else { - None - } + .then_some(steps); + + may_hold }) { if steps > 0 { @@ -899,14 +894,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return false; } - let self_ty = self.replace_bound_vars_with_fresh_vars( + let self_ty = self.instantiate_binder_with_fresh_vars( DUMMY_SP, LateBoundRegionConversionTime::FnCall, trait_pred.self_ty(), ); + let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); let Some((def_id_or_name, output, inputs)) = self.extract_callable_info( - obligation.cause.body_id, + body_hir_id, obligation.param_env, self_ty, ) else { return false; }; @@ -931,7 +927,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { DefKind::Ctor(CtorOf::Variant, _) => { "use parentheses to construct this tuple variant".to_string() } - kind => format!("use parentheses to call this {}", kind.descr(def_id)), + kind => format!( + "use parentheses to call this {}", + self.tcx.def_kind_descr(kind, def_id) + ), }, DefIdOrName::Name(name) => format!("use parentheses to call this {name}"), }; @@ -1004,8 +1003,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span.remove_mark(); } let mut expr_finder = FindExprBySpan::new(span); - let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { return; }; - expr_finder.visit_expr(&body); + let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return; }; + let body = self.tcx.hir().body(body_id); + expr_finder.visit_expr(body.value); let Some(expr) = expr_finder.result else { return; }; let Some(typeck) = &self.typeck_results else { return; }; let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { return; }; @@ -1059,9 +1059,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); - let ty = self.tcx.erase_late_bound_regions(self_ty); - let owner = self.tcx.hir().get_parent_item(obligation.cause.body_id); - let Some(generics) = self.tcx.hir().get_generics(owner.def_id) else { return false }; + let ty = self.instantiate_binder_with_placeholders(self_ty); + let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { return false }; let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false }; let ty::Param(param) = inner_ty.kind() else { return false }; let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() else { return false }; @@ -1088,6 +1087,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { param.name.as_str(), "Clone", Some(clone_trait), + None, ); } err.span_suggestion_verbose( @@ -1104,6 +1104,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// Extracts information about a callable type for diagnostics. This is a /// heuristic -- it doesn't necessarily mean that a type is always callable, /// because the callable type must also be well-formed to be called. + // FIXME(vincenzopalazzo): move the HirId to a LocalDefId fn extract_callable_info( &self, hir_id: HirId, @@ -1189,7 +1190,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }) else { return None; }; - let output = self.replace_bound_vars_with_fresh_vars( + let output = self.instantiate_binder_with_fresh_vars( DUMMY_SP, LateBoundRegionConversionTime::FnCall, output, @@ -1198,7 +1199,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .skip_binder() .iter() .map(|ty| { - self.replace_bound_vars_with_fresh_vars( + self.instantiate_binder_with_fresh_vars( DUMMY_SP, LateBoundRegionConversionTime::FnCall, inputs.rebind(*ty), @@ -1348,14 +1349,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Applicability::MaybeIncorrect, ); } else { + // Issue #104961, we need to add parentheses properly for compond expressions + // for example, `x.starts_with("hi".to_string() + "you")` + // should be `x.starts_with(&("hi".to_string() + "you"))` + let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; }; + let body = self.tcx.hir().body(body_id); + let mut expr_finder = FindExprBySpan::new(span); + expr_finder.visit_expr(body.value); + let Some(expr) = expr_finder.result else { return false; }; + let needs_parens = match expr.kind { + // parenthesize if needed (Issue #46756) + hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, + // parenthesize borrows of range literals (Issue #54505) + _ if is_range_literal(expr) => true, + _ => false, + }; + let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut; - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!( - "consider{} borrowing here", - if is_mut { " mutably" } else { "" } - ), - format!("&{}", if is_mut { "mut " } else { "" }), + let span = if needs_parens { span } else { span.shrink_to_lo() }; + let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" }); + let sugg_msg = &format!( + "consider{} borrowing here", + if is_mut { " mutably" } else { "" } + ); + + let suggestions = if !needs_parens { + vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))] + } else { + vec![ + (span.shrink_to_lo(), format!("{}(", sugg_prefix)), + (span.shrink_to_hi(), ")".to_string()), + ] + }; + err.multipart_suggestion_verbose( + sugg_msg, + suggestions, Applicability::MaybeIncorrect, ); } @@ -1429,10 +1457,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span.remove_mark(); } let mut expr_finder = super::FindExprBySpan::new(span); - let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { + let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; }; - expr_finder.visit_expr(&body); + let body = self.tcx.hir().body(body_id); + expr_finder.visit_expr(body.value); let mut maybe_suggest = |suggested_ty, count, suggestions| { // Remapping bound vars here let trait_pred_and_suggested_ty = @@ -1670,8 +1699,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { let hir = self.tcx.hir(); - let parent_node = hir.parent_id(obligation.cause.body_id); - let node = hir.find(parent_node); + let node = hir.find_by_def_id(obligation.cause.body_id); if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind && sig.decl.output.span().overlaps(span) @@ -1707,8 +1735,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> { let hir = self.tcx.hir(); - let parent_node = hir.parent_id(obligation.cause.body_id); - let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find(parent_node) else { + let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find_by_def_id(obligation.cause.body_id) else { return None; }; @@ -1732,8 +1759,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } let hir = self.tcx.hir(); - let fn_hir_id = hir.parent_id(obligation.cause.body_id); - let node = hir.find(fn_hir_id); + let fn_hir_id = hir.local_def_id_to_hir_id(obligation.cause.body_id); + let node = hir.find_by_def_id(obligation.cause.body_id); let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. @@ -1749,7 +1776,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`. predicates .principal_def_id() - .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty()) + .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id)) } // We only want to suggest `impl Trait` to `dyn Trait`s. // For example, `fn foo() -> str` needs to be filtered out. @@ -1806,7 +1833,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { match liberated_sig.output().kind() { ty::Dynamic(predicates, _, ty::Dyn) => { - let cause = ObligationCause::misc(ret_ty.span, fn_hir_id); + let cause = ObligationCause::misc(ret_ty.span, obligation.cause.body_id); let param_env = ty::ParamEnv::empty(); if !only_never_return { @@ -1944,8 +1971,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } let hir = self.tcx.hir(); - let parent_node = hir.parent_id(obligation.cause.body_id); - let node = hir.find(parent_node); + let node = hir.find_by_def_id(obligation.cause.body_id); if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) = node { @@ -1989,7 +2015,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let sig = match inputs.kind() { ty::Tuple(inputs) if infcx.tcx.is_fn_trait(trait_ref.def_id()) => { infcx.tcx.mk_fn_sig( - inputs.iter(), + *inputs, infcx.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, kind: TypeVariableOriginKind::MiscVariable, @@ -2000,7 +2026,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } _ => infcx.tcx.mk_fn_sig( - std::iter::once(inputs), + [inputs], infcx.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, kind: TypeVariableOriginKind::MiscVariable, @@ -2116,7 +2142,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note(&format!( "{}s cannot be accessed directly on a `trait`, they can only be \ accessed through a specific `impl`", - assoc_item.kind.as_def_kind().descr(item_def_id) + self.tcx.def_kind_descr(assoc_item.kind.as_def_kind(), item_def_id) )); err.span_suggestion( span, @@ -2225,7 +2251,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); match *ty.kind() { - ty::Generator(did, ..) => { + ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, _) => { generator = generator.or(Some(did)); outer_generator = Some(did); } @@ -2255,7 +2281,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); match *ty.kind() { - ty::Generator(did, ..) => { + ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, ..) => { generator = generator.or(Some(did)); outer_generator = Some(did); } @@ -2344,9 +2370,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => return false, }; + let generator_within_in_progress_typeck = match &self.typeck_results { + Some(t) => t.hir_owner.to_def_id() == generator_did_root, + _ => false, + }; + let mut interior_or_upvar_span = None; - let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches); + let from_awaited_ty = generator_data.get_from_await_ty(self.tcx, visitor, hir, ty_matches); debug!(?from_awaited_ty); // The generator interior types share the same binders @@ -2363,6 +2394,35 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { *span, Some((*scope_span, *yield_span, *expr, from_awaited_ty)), )); + + if interior_or_upvar_span.is_none() && generator_data.is_foreign() { + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span, None)); + } + } else if self.tcx.sess.opts.unstable_opts.drop_tracking_mir + // Avoid disclosing internal information to downstream crates. + && generator_did.is_local() + // Try to avoid cycles. + && !generator_within_in_progress_typeck + { + let generator_info = &self.tcx.mir_generator_witnesses(generator_did); + debug!(?generator_info); + + 'find_source: for (variant, source_info) in + generator_info.variant_fields.iter().zip(&generator_info.variant_source_info) + { + debug!(?variant); + for &local in variant { + let decl = &generator_info.field_tys[local]; + debug!(?decl); + if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.ignore_for_traits { + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior( + decl.source_info.span, + Some((None, source_info.span, None, from_awaited_ty)), + )); + break 'find_source; + } + } + } } if interior_or_upvar_span.is_none() { @@ -2727,7 +2787,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => true, }; if ident.span.is_visible(sm) && !ident.span.overlaps(span) && !same_line { - multispan.push_span_label(ident.span, "required by a bound in this"); + multispan.push_span_label( + ident.span, + format!( + "required by a bound in this {}", + tcx.def_kind(item_def_id).descr(item_def_id) + ), + ); } } let descr = format!("required by a bound in `{item_name}`"); @@ -3011,6 +3077,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } err.note(msg.trim_end_matches(", ")) } + ty::GeneratorWitnessMIR(def_id, substs) => { + use std::fmt::Write; + + // FIXME: this is kind of an unusual format for rustc, can we make it more clear? + // Maybe we should just remove this note altogether? + // FIXME: only print types which don't meet the trait requirement + let mut msg = + "required because it captures the following types: ".to_owned(); + for bty in tcx.generator_hidden_types(*def_id) { + let ty = bty.subst(tcx, substs); + write!(msg, "`{}`, ", ty).unwrap(); + } + err.note(msg.trim_end_matches(", ")) + } ty::Generator(def_id, _, _) => { let sp = self.tcx.def_span(def_id); @@ -3027,6 +3107,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.tcx.def_span(def_id), "required because it's used within this closure", ), + ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"), _ => err.note(&msg), }; } @@ -3072,7 +3153,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { parent_trait_pred.print_modifiers_and_trait_path() ); let mut is_auto_trait = false; - match self.tcx.hir().get_if_local(data.impl_def_id) { + match self.tcx.hir().get_if_local(data.impl_or_alias_def_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Trait(is_auto, ..), ident, @@ -3283,12 +3364,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ) { - let body_hir_id = obligation.cause.body_id; - let item_id = self.tcx.hir().parent_id(body_hir_id); - - if let Some(body_id) = - self.tcx.hir().maybe_body_owned_by(self.tcx.hir().local_def_id(item_id)) - { + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { let body = self.tcx.hir().body(body_id); if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); @@ -3459,7 +3535,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { 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 ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()); let span = expr.span; if Some(span) != err.span.primary_span() { err.span_label( @@ -3502,7 +3578,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { type_diffs = vec![ Sorts(ty::error::ExpectedFound { - expected: self.tcx.mk_ty(ty::Alias(ty::Projection, where_pred.skip_binder().projection_ty)), + expected: self.tcx.mk_alias(ty::Projection, where_pred.skip_binder().projection_ty), found, }), ]; @@ -3562,7 +3638,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { 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()), + typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()), ); 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. @@ -3573,7 +3649,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { 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()), + typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()), ); if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind @@ -3591,7 +3667,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { 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()), + typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error_misc()), ); 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()) { @@ -3620,7 +3696,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { 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() + self.can_eq(param_env, expected_found.found, ty) }) { // FIXME: this doesn't quite work for `Iterator::collect` // because we have `Vec<i32>` and `()`, but we'd want `i32` @@ -3647,10 +3723,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { 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 !self.can_eq(param_env, ty, *prev_ty) { 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() + self.can_eq(param_env, expected_found.found, ty) }) { primary_spans.push(span); } @@ -3727,9 +3803,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { term: ty_var.into(), }, ))); + let body_def_id = self.tcx.hir().enclosing_body_owner(body_id); // Add `<ExprTy as Iterator>::Item = _` obligation. ocx.register_obligation(Obligation::misc( - self.tcx, span, body_id, param_env, projection, + self.tcx, + span, + body_def_id, + param_env, + projection, )); if ocx.select_where_possible().is_empty() { // `ty_var` now holds the type that `Item` is for `ExprTy`. @@ -3758,13 +3839,13 @@ fn hint_missing_borrow<'tcx>( err: &mut Diagnostic, ) { let found_args = match found.kind() { - ty::FnPtr(f) => f.inputs().skip_binder().iter(), + ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().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(), + ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(), kind => { span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) } @@ -3775,12 +3856,12 @@ fn hint_missing_borrow<'tcx>( let args = fn_decl.inputs.iter().map(|ty| ty); - fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { - let mut refs = 0; + fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) { + let mut refs = vec![]; - while let ty::Ref(_, new_ty, _) = ty.kind() { + while let ty::Ref(_, new_ty, mutbl) = ty.kind() { ty = *new_ty; - refs += 1; + refs.push(*mutbl); } (ty, refs) @@ -3793,12 +3874,22 @@ fn hint_missing_borrow<'tcx>( 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 infcx.can_eq(param_env, found_ty, expected_ty).is_ok() { - if found_refs < expected_refs { - to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs))); - } else if found_refs > expected_refs { + if infcx.can_eq(param_env, found_ty, expected_ty) { + // FIXME: This could handle more exotic cases like mutability mismatches too! + if found_refs.len() < expected_refs.len() + && found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..] + { + to_borrow.push(( + arg.span.shrink_to_lo(), + expected_refs[..expected_refs.len() - found_refs.len()] + .iter() + .map(|mutbl| format!("&{}", mutbl.prefix_str())) + .collect::<Vec<_>>() + .join(""), + )); + } else if found_refs.len() > expected_refs.len() { let mut span = arg.span.shrink_to_lo(); - let mut left = found_refs - expected_refs; + let mut left = found_refs.len() - expected_refs.len(); let mut ty = arg; while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 { span = span.with_hi(mut_ty.ty.span.lo()); @@ -3996,7 +4087,7 @@ struct ReplaceImplTraitFolder<'tcx> { replace_ty: Ty<'tcx>, } -impl<'tcx> TypeFolder<'tcx> for ReplaceImplTraitFolder<'tcx> { +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceImplTraitFolder<'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if let ty::Param(ty::ParamTy { index, .. }) = t.kind() { if self.param.index == *index { @@ -4006,7 +4097,7 @@ impl<'tcx> TypeFolder<'tcx> for ReplaceImplTraitFolder<'tcx> { t.super_fold_with(self) } - fn tcx(&self) -> TyCtxt<'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { self.tcx } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 76a755ed9..944436ab8 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,5 +1,4 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; @@ -9,7 +8,7 @@ use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Binder, Const, TypeVisitable}; +use rustc_middle::ty::{self, Binder, Const, TypeVisitableExt}; use std::marker::PhantomData; use super::const_evaluatable; @@ -54,8 +53,6 @@ pub struct FulfillmentContext<'tcx> { // fulfillment context. predicates: ObligationForest<PendingPredicateObligation<'tcx>>, - relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>, - // Is it OK to register obligations into this infcx inside // an infcx snapshot? // @@ -85,19 +82,11 @@ static_assert_size!(PendingPredicateObligation<'_>, 72); impl<'a, 'tcx> FulfillmentContext<'tcx> { /// Creates a new fulfillment context. pub(super) fn new() -> FulfillmentContext<'tcx> { - FulfillmentContext { - predicates: ObligationForest::new(), - relationships: FxHashMap::default(), - usable_in_snapshot: false, - } + FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: false } } pub(super) fn new_in_snapshot() -> FulfillmentContext<'tcx> { - FulfillmentContext { - predicates: ObligationForest::new(), - relationships: FxHashMap::default(), - usable_in_snapshot: true, - } + FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: true } } /// Attempts to select obligations using `selcx`. @@ -139,20 +128,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); - super::relationships::update(self, infcx, &obligation); - self.predicates .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - { - let errors = self.select_where_possible(infcx); - if !errors.is_empty() { - return errors; - } - } - + fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> { self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() } @@ -161,12 +141,57 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.select(selcx) } - fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { - self.predicates.map_pending_obligations(|o| o.obligation.clone()) + fn drain_unstalled_obligations( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>> { + let mut processor = DrainProcessor { removed_predicates: Vec::new(), infcx }; + let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor); + assert!(outcome.errors.is_empty()); + return processor.removed_predicates; + + struct DrainProcessor<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + removed_predicates: Vec<PredicateObligation<'tcx>>, + } + + impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> { + type Obligation = PendingPredicateObligation<'tcx>; + type Error = !; + type OUT = Outcome<Self::Obligation, Self::Error>; + + fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool { + pending_obligation + .stalled_on + .iter() + .any(|&var| self.infcx.ty_or_const_infer_var_changed(var)) + } + + fn process_obligation( + &mut self, + pending_obligation: &mut PendingPredicateObligation<'tcx>, + ) -> ProcessResult<PendingPredicateObligation<'tcx>, !> { + assert!(self.needs_process_obligation(pending_obligation)); + self.removed_predicates.push(pending_obligation.obligation.clone()); + ProcessResult::Changed(vec![]) + } + + fn process_backedge<'c, I>( + &mut self, + cycle: I, + _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, + ) -> Result<(), !> + where + I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>, + { + self.removed_predicates.extend(cycle.map(|c| c.obligation.clone())); + Ok(()) + } + } } - fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> { - &mut self.relationships + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { + self.predicates.map_pending_obligations(|o| o.obligation.clone()) } } @@ -187,36 +212,44 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { /// Identifies whether a predicate obligation needs processing. /// - /// This is always inlined, despite its size, because it has a single - /// callsite and it is called *very* frequently. + /// This is always inlined because it has a single callsite and it is + /// called *very* frequently. Be careful modifying this code! Several + /// compile-time benchmarks are very sensitive to even small changes. #[inline(always)] fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool { // If we were stalled on some unresolved variables, first check whether // any of them have been resolved; if not, don't bother doing more work // yet. - match pending_obligation.stalled_on.len() { - // Match arms are in order of frequency, which matters because this - // code is so hot. 1 and 0 dominate; 2+ is fairly rare. - 1 => { - let infer_var = pending_obligation.stalled_on[0]; - self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) - } - 0 => { - // In this case we haven't changed, but wish to make a change. - true - } - _ => { - // This `for` loop was once a call to `all()`, but this lower-level - // form was a perf win. See #64545 for details. - (|| { - for &infer_var in &pending_obligation.stalled_on { - if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) { - return true; - } + let stalled_on = &pending_obligation.stalled_on; + match stalled_on.len() { + // This case is the hottest most of the time, being hit up to 99% + // of the time. `keccak` and `cranelift-codegen-0.82.1` are + // benchmarks that particularly stress this path. + 1 => self.selcx.infcx.ty_or_const_infer_var_changed(stalled_on[0]), + + // In this case we haven't changed, but wish to make a change. Note + // that this is a special case, and is not equivalent to the `_` + // case below, which would return `false` for an empty `stalled_on` + // vector. + // + // This case is usually hit only 1% of the time or less, though it + // reaches 20% in `wasmparser-0.101.0`. + 0 => true, + + // This case is usually hit only 1% of the time or less, though it + // reaches 95% in `mime-0.3.16`, 64% in `wast-54.0.0`, and 12% in + // `inflate-0.4.5`. + // + // The obvious way of writing this, with a call to `any()` and no + // closure, is currently slower than this version. + _ => (|| { + for &infer_var in stalled_on { + if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) { + return true; } - false - })() - } + } + false + })(), } } @@ -288,6 +321,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_)) | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) @@ -296,13 +330,16 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) => { let pred = - ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder)); + ty::Binder::dummy(infcx.instantiate_binder_with_placeholders(binder)); ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)])) } ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } + ty::PredicateKind::AliasEq(..) => { + bug!("AliasEq is only used for new solver") + } }, Some(pred) => match pred { ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { @@ -344,7 +381,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } ty::PredicateKind::ObjectSafe(trait_def_id) => { - if !self.selcx.tcx().is_object_safe(trait_def_id) { + if !self.selcx.tcx().check_is_object_safe(trait_def_id) { ProcessResult::Error(CodeSelectionError(Unimplemented)) } else { ProcessResult::Changed(vec![]) @@ -569,6 +606,22 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } + ty::PredicateKind::AliasEq(..) => { + bug!("AliasEq is only used for new solver") + } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + match self + .selcx + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(ct.ty(), ty) + { + Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), + Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + )), + } + } }, } } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index a41a601f2..b94346b09 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -1,12 +1,15 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. -use crate::traits::{self, ObligationCause}; +use crate::traits::{self, ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; +use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; +use rustc_infer::traits::query::NoSolution; use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::DUMMY_SP; use super::outlives_bounds::InferCtxtExt; @@ -131,3 +134,19 @@ pub fn type_allowed_to_implement_copy<'tcx>( Ok(()) } + +pub fn check_tys_might_be_eq<'tcx>( + tcx: TyCtxt<'tcx>, + canonical: Canonical<'tcx, (ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>, +) -> Result<(), NoSolution> { + let (infcx, (param_env, ty_a, ty_b), _) = + tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical); + let ocx = ObligationCtxt::new(&infcx); + + let result = ocx.eq(&ObligationCause::dummy(), param_env, ty_a, ty_b); + // use `select_where_possible` instead of `select_all_or_error` so that + // we don't get errors from obligations being ambiguous. + let errors = ocx.select_where_possible(); + + if errors.len() > 0 || result.is_err() { Err(NoSolution) } else { Ok(()) } +} diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index f036a311d..4e30108be 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -14,7 +14,6 @@ mod object_safety; pub mod outlives_bounds; mod project; pub mod query; -pub(crate) mod relationships; mod select; mod specialize; mod structural_match; @@ -27,12 +26,11 @@ use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::error_reporting::TypeErrCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeSuperVisitable}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; +use rustc_span::def_id::{DefId, CRATE_DEF_ID}; use rustc_span::Span; use std::fmt::Debug; @@ -143,7 +141,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( fn pred_known_to_hold_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - pred: impl ToPredicate<'tcx> + TypeVisitable<'tcx>, + pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>, span: Span, ) -> bool { let has_non_region_infer = pred.has_non_region_infer(); @@ -152,29 +150,29 @@ fn pred_known_to_hold_modulo_regions<'tcx>( // We can use a dummy node-id here because we won't pay any mind // to region obligations that arise (there shouldn't really be any // anyhow). - cause: ObligationCause::misc(span, hir::CRATE_HIR_ID), + cause: ObligationCause::misc(span, CRATE_DEF_ID), recursion_depth: 0, predicate: pred.to_predicate(infcx.tcx), }; - let result = infcx.predicate_must_hold_modulo_regions(&obligation); + let result = infcx.evaluate_obligation_no_overflow(&obligation); debug!(?result); - if result && has_non_region_infer { + if result.must_apply_modulo_regions() && !has_non_region_infer { + true + } else if result.may_apply() { // Because of inference "guessing", selection can sometimes claim // to succeed while the success requires a guess. To ensure // this function's result remains infallible, we must confirm // that guess. While imperfect, I believe this is sound. // FIXME(@lcnr): this function doesn't seem right. + // // The handling of regions in this area of the code is terrible, // see issue #29149. We should be able to improve on this with // NLL. let errors = fully_solve_obligation(infcx, obligation); - // Note: we only assume something is `Copy` if we can - // *definitively* show that it implements `Copy`. Otherwise, - // assume it is move; linear is always ok. match &errors[..] { [] => true, errors => { @@ -183,7 +181,7 @@ fn pred_known_to_hold_modulo_regions<'tcx>( } } } else { - result + false } } @@ -285,7 +283,7 @@ pub fn normalize_param_env_or_error<'tcx>( debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); let elaborated_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), + tcx.mk_predicates(&predicates), unnormalized_env.reveal(), unnormalized_env.constness(), ); @@ -337,10 +335,9 @@ pub fn normalize_param_env_or_error<'tcx>( // Not sure whether it is better to include the unnormalized TypeOutlives predicates // here. I believe they should not matter, because we are ignoring TypeOutlives param-env // predicates here anyway. Keeping them here anyway because it seems safer. - let outlives_env: Vec<_> = - non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect(); + let outlives_env = non_outlives_predicates.iter().chain(&outlives_predicates).cloned(); let outlives_env = ty::ParamEnv::new( - tcx.intern_predicates(&outlives_env), + tcx.mk_predicates_from_iter(outlives_env), unnormalized_env.reveal(), unnormalized_env.constness(), ); @@ -360,7 +357,7 @@ pub fn normalize_param_env_or_error<'tcx>( predicates.extend(outlives_predicates); debug!("normalize_param_env_or_error: final predicates={:?}", predicates); ty::ParamEnv::new( - tcx.intern_predicates(&predicates), + tcx.mk_predicates(&predicates), unnormalized_env.reveal(), unnormalized_env.constness(), ) @@ -375,7 +372,7 @@ pub fn fully_normalize<'tcx, T>( value: T, ) -> Result<T, Vec<FulfillmentError<'tcx>>> where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { let ocx = ObligationCtxt::new(infcx); debug!(?value); @@ -485,7 +482,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI generics: &'tcx ty::Generics, trait_item_def_id: DefId, } - impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> { + impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for ReferencesOnlyParentGenerics<'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { // If this is a parameter from the trait item's own generics, then bail @@ -527,16 +524,14 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id }; let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| { - if pred.visit_with(&mut visitor).is_continue() { - Some(Obligation::new( + pred.visit_with(&mut visitor).is_continue().then(|| { + Obligation::new( tcx, ObligationCause::dummy_with_span(*span), param_env, ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs), - )) - } else { - None - } + ) + }) }); let infcx = tcx.infer_ctxt().ignoring_regions().build(); @@ -558,6 +553,7 @@ pub fn provide(providers: &mut ty::query::Providers) { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, subst_and_check_impossible_predicates, + check_tys_might_be_eq: misc::check_tys_might_be_eq, is_impossible_method, ..*providers }; diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index c9121212c..4eacb5211 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -18,10 +18,10 @@ use rustc_errors::{DelayDm, FatalError, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; -use rustc_middle::ty::{Predicate, ToPredicate}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -62,11 +62,42 @@ fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [Object ) } +fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + let violations = tcx.object_safety_violations(trait_def_id); + + if violations.is_empty() { + return true; + } + + // If the trait contains any other violations, then let the error reporting path + // report it instead of emitting a warning here. + if violations.iter().all(|violation| { + matches!( + violation, + ObjectSafetyViolation::Method(_, MethodViolationCode::WhereClauseReferencesSelf, _) + ) + }) { + for violation in violations { + if let ObjectSafetyViolation::Method( + _, + MethodViolationCode::WhereClauseReferencesSelf, + span, + ) = violation + { + lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation); + } + } + return true; + } + + false +} + /// We say a method is *vtable safe* if it can be invoked on a trait /// object. Note that object-safe traits can have some /// non-vtable-safe methods, so long as they require `Self: Sized` or /// otherwise ensure that they cannot be used when `Self = Trait`. -pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: &ty::AssocItem) -> bool { +pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool { debug_assert!(tcx.generics_of(trait_def_id).has_self); debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); // Any method that has a `Self: Sized` bound cannot be called. @@ -89,23 +120,10 @@ fn object_safety_violations_for_trait( .associated_items(trait_def_id) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Fn) - .filter_map(|item| { - object_safety_violation_for_method(tcx, trait_def_id, &item) + .filter_map(|&item| { + object_safety_violation_for_method(tcx, trait_def_id, item) .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span)) }) - .filter(|violation| { - if let ObjectSafetyViolation::Method( - _, - MethodViolationCode::WhereClauseReferencesSelf, - span, - ) = violation - { - lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation); - false - } else { - true - } - }) .collect(); // Check the trait itself. @@ -289,7 +307,7 @@ fn predicate_references_self<'tcx>( match predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(ref data)) => { // In the case of a trait predicate, we can skip the "self" type. - if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None } + data.trait_ref.substs[1..].iter().any(has_self_ty).then_some(sp) } ty::PredicateKind::Clause(ty::Clause::Projection(ref data)) => { // And similarly for projections. This should be redundant with @@ -307,8 +325,14 @@ fn predicate_references_self<'tcx>( // // This is ALT2 in issue #56288, see that for discussion of the // possible alternatives. - if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None } + data.projection_ty.substs[1..].iter().any(has_self_ty).then_some(sp) + } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(_ct, ty)) => { + has_self_ty(&ty.into()).then_some(sp) } + + ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"), + ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) @@ -316,6 +340,7 @@ fn predicate_references_self<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) + // FIXME(generic_const_exprs): this can mention `Self` | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous @@ -341,6 +366,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) } ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) @@ -350,6 +376,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::AliasEq(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => false, } @@ -360,7 +387,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { fn object_safety_violation_for_method( tcx: TyCtxt<'_>, trait_def_id: DefId, - method: &ty::AssocItem, + method: ty::AssocItem, ) -> Option<(MethodViolationCode, Span)> { debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method); // Any method that has a `Self : Sized` requisite is otherwise @@ -393,9 +420,9 @@ fn object_safety_violation_for_method( fn virtual_call_violation_for_method<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, - method: &ty::AssocItem, + method: ty::AssocItem, ) -> Option<MethodViolationCode> { - let sig = tcx.fn_sig(method.def_id); + let sig = tcx.fn_sig(method.def_id).subst_identity(); // The method's first parameter must be named `self` if !method.fn_has_self_parameter { @@ -505,8 +532,7 @@ fn virtual_call_violation_for_method<'tcx>( } } - let trait_object_ty = - object_ty_for_trait(tcx, trait_def_id, tcx.mk_region(ty::ReStatic)); + let trait_object_ty = object_ty_for_trait(tcx, trait_def_id, tcx.lifetimes.re_static); // e.g., `Rc<dyn Trait>` let trait_object_receiver = @@ -529,16 +555,56 @@ fn virtual_call_violation_for_method<'tcx>( // NOTE: This check happens last, because it results in a lint, and not a // hard error. - if tcx - .predicates_of(method.def_id) - .predicates - .iter() - // A trait object can't claim to live more than the concrete type, - // so outlives predicates will always hold. - .cloned() - .filter(|(p, _)| p.to_opt_type_outlives().is_none()) - .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred)) - { + if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, span)| { + // dyn Trait is okay: + // + // trait Trait { + // fn f(&self) where Self: 'static; + // } + // + // because a trait object can't claim to live longer than the concrete + // type. If the lifetime bound holds on dyn Trait then it's guaranteed + // to hold as well on the concrete type. + if pred.to_opt_type_outlives().is_some() { + return false; + } + + // dyn Trait is okay: + // + // auto trait AutoTrait {} + // + // trait Trait { + // fn f(&self) where Self: AutoTrait; + // } + // + // because `impl AutoTrait for dyn Trait` is disallowed by coherence. + // Traits with a default impl are implemented for a trait object if and + // only if the autotrait is one of the trait object's trait bounds, like + // in `dyn Trait + AutoTrait`. This guarantees that trait objects only + // implement auto traits if the underlying type does as well. + if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { + trait_ref: pred_trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + })) = pred.kind().skip_binder() + && pred_trait_ref.self_ty() == tcx.types.self_param + && tcx.trait_is_auto(pred_trait_ref.def_id) + { + // Consider bounds like `Self: Bound<Self>`. Auto traits are not + // allowed to have generic parameters so `auto trait Bound<T> {}` + // would already have reported an error at the definition of the + // auto trait. + if pred_trait_ref.substs.len() != 1 { + tcx.sess.diagnostic().delay_span_bug( + span, + "auto traits cannot have generic parameters", + ); + } + return false; + } + + contains_illegal_self_type_reference(tcx, trait_def_id, pred) + }) { return Some(MethodViolationCode::WhereClauseReferencesSelf); } @@ -588,11 +654,9 @@ fn object_ty_for_trait<'tcx>( debug!(?obligation); let pred = obligation.predicate.to_opt_poly_projection_pred()?; Some(pred.map_bound(|p| { - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - def_id: p.projection_ty.def_id, - substs: p.projection_ty.substs, - term: p.term, - }) + ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty( + tcx, p, + )) })) }) .collect(); @@ -602,8 +666,9 @@ fn object_ty_for_trait<'tcx>( elaborated_predicates.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); elaborated_predicates.dedup(); - let existential_predicates = tcx - .mk_poly_existential_predicates(iter::once(trait_predicate).chain(elaborated_predicates)); + let existential_predicates = tcx.mk_poly_existential_predicates_from_iter( + iter::once(trait_predicate).chain(elaborated_predicates), + ); debug!(?existential_predicates); tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn) @@ -658,7 +723,7 @@ fn object_ty_for_trait<'tcx>( #[allow(dead_code)] fn receiver_is_dispatchable<'tcx>( tcx: TyCtxt<'tcx>, - method: &ty::AssocItem, + method: ty::AssocItem, receiver_ty: Ty<'tcx>, ) -> bool { debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty); @@ -702,11 +767,11 @@ fn receiver_is_dispatchable<'tcx>( ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, substs)).to_predicate(tcx) }; - let caller_bounds: Vec<Predicate<'tcx>> = - param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]).collect(); + let caller_bounds = + param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]); ty::ParamEnv::new( - tcx.intern_predicates(&caller_bounds), + tcx.mk_predicates_from_iter(caller_bounds), param_env.reveal(), param_env.constness(), ) @@ -726,7 +791,7 @@ fn receiver_is_dispatchable<'tcx>( infcx.predicate_must_hold_modulo_regions(&obligation) } -fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( +fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, value: T, @@ -776,7 +841,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( supertraits: Option<Vec<DefId>>, } - impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { + impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -866,5 +931,6 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>( } pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { object_safety_violations, ..*providers }; + *providers = + ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers }; } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index f2c5f730b..6cb64ad57 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -3,9 +3,8 @@ use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; use crate::traits::query::NoSolution; use crate::traits::ObligationCause; use rustc_data_structures::fx::FxIndexSet; -use rustc_hir as hir; -use rustc_hir::HirId; use rustc_middle::ty::{self, ParamEnv, Ty}; +use rustc_span::def_id::LocalDefId; pub use rustc_middle::traits::query::OutlivesBound; @@ -14,14 +13,14 @@ pub trait InferCtxtExt<'a, 'tcx> { fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, ty: Ty<'tcx>, ) -> Vec<OutlivesBound<'tcx>>; fn implied_bounds_tys( &'a self, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, tys: FxIndexSet<Ty<'tcx>>, ) -> Bounds<'a, 'tcx>; } @@ -50,10 +49,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, ty: Ty<'tcx>, ) -> Vec<OutlivesBound<'tcx>> { - let span = self.tcx.hir().span(body_id); + let span = self.tcx.def_span(body_id); let result = param_env .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) .fully_perform(self); @@ -102,7 +101,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { fn implied_bounds_tys( &'a self, param_env: ParamEnv<'tcx>, - body_id: HirId, + body_id: LocalDefId, tys: FxIndexSet<Ty<'tcx>>, ) -> Bounds<'a, 'tcx> { tys.into_iter() diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index fbc7ecced..870ecc2a9 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -31,7 +31,7 @@ use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::ImplSourceBuiltinData; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable}; +use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::DefIdTree; use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; @@ -53,11 +53,11 @@ pub trait NormalizeExt<'tcx> { /// /// This normalization should be used when the type contains inference variables or the /// projection may be fallible. - fn normalize<T: TypeFoldable<'tcx>>(&self, t: T) -> InferOk<'tcx, T>; + fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> InferOk<'tcx, T>; } impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> { - fn normalize<T: TypeFoldable<'tcx>>(&self, value: T) -> InferOk<'tcx, T> { + fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> { let mut selcx = SelectionContext::new(self.infcx); let Normalized { value, obligations } = normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value); @@ -90,15 +90,7 @@ enum ProjectionCandidate<'tcx> { /// From an "impl" (or a "pseudo-impl" returned by select) Select(Selection<'tcx>), - ImplTraitInTrait(ImplTraitInTraitCandidate<'tcx>), -} - -#[derive(PartialEq, Eq, Debug)] -enum ImplTraitInTraitCandidate<'tcx> { - // The `impl Trait` from a trait function's default body - Trait, - // A concrete type provided from a trait's `impl Trait` from an impl - Impl(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>), + ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>), } enum ProjectionCandidateSet<'tcx> { @@ -215,7 +207,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( let r = infcx.commit_if_ok(|_snapshot| { let old_universe = infcx.universe(); let placeholder_predicate = - infcx.replace_bound_vars_with_placeholders(obligation.predicate); + infcx.instantiate_binder_with_placeholders(obligation.predicate); let new_universe = infcx.universe(); let placeholder_obligation = obligation.with(infcx.tcx, placeholder_predicate); @@ -294,7 +286,12 @@ fn project_and_unify_type<'cx, 'tcx>( ); obligations.extend(new); - match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) { + match infcx + .at(&obligation.cause, obligation.param_env) + // This is needed to support nested opaque types like `impl Fn() -> impl Trait` + .define_opaque_types(true) + .eq(normalized, actual) + { Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); ProjectAndUnifyResult::Holds(obligations) @@ -315,7 +312,7 @@ pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>( value: T, ) -> Normalized<'tcx, T> where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { let mut obligations = Vec::new(); let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations); @@ -332,7 +329,7 @@ pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>( obligations: &mut Vec<PredicateObligation<'tcx>>, ) -> T where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { debug!(obligations.len = obligations.len()); let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); @@ -352,7 +349,7 @@ pub(crate) fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>( obligations: &mut Vec<PredicateObligation<'tcx>>, ) -> T where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { debug!(obligations.len = obligations.len()); let mut normalizer = AssocTypeNormalizer::new_without_eager_inference_replacement( @@ -368,7 +365,10 @@ where result } -pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<'tcx>>(value: &T, reveal: Reveal) -> bool { +pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>( + value: &T, + reveal: Reveal, +) -> bool { match reveal { Reveal::UserFacing => value .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION), @@ -430,7 +430,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { } } - fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T { + fn fold<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T { let value = self.selcx.infcx.resolve_vars_if_possible(value); debug!(?value); @@ -448,12 +448,12 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { } } -impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { +impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { self.selcx.tcx() } - fn fold_binder<T: TypeFoldable<'tcx>>( + fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>( &mut self, t: ty::Binder<'tcx, T>, ) -> ty::Binder<'tcx, T> { @@ -503,7 +503,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { Reveal::UserFacing => ty.super_fold_with(self), Reveal::All => { - let recursion_limit = self.tcx().recursion_limit(); + let recursion_limit = self.interner().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { self.selcx.infcx.err_ctxt().report_overflow_error( &ty, @@ -514,8 +514,8 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } let substs = substs.fold_with(self); - let generic_ty = self.tcx().bound_type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx(), substs); + let generic_ty = self.interner().type_of(def_id); + let concrete_ty = generic_ty.subst(self.interner(), substs); self.depth += 1; let folded_ty = self.fold_ty(concrete_ty); self.depth -= 1; @@ -672,7 +672,12 @@ pub struct BoundVarReplacer<'me, 'tcx> { /// /// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during /// normalization as well, at which point this function will be unnecessary and can be removed. -pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: TypeFoldable<'tcx>>( +pub fn with_replaced_escaping_bound_vars< + 'a, + 'tcx, + T: TypeFoldable<TyCtxt<'tcx>>, + R: TypeFoldable<TyCtxt<'tcx>>, +>( infcx: &'a InferCtxt<'tcx>, universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>, value: T, @@ -698,7 +703,7 @@ pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: Typ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that /// use a binding level above `universe_indices.len()`, we fail. - pub fn replace_bound_vars<T: TypeFoldable<'tcx>>( + pub fn replace_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>( infcx: &'me InferCtxt<'tcx>, universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>, value: T, @@ -740,12 +745,12 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { } } -impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { self.infcx.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>( + fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>( &mut self, t: ty::Binder<'tcx, T>, ) -> ty::Binder<'tcx, T> { @@ -767,7 +772,7 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> { let universe = self.universe_for(debruijn); let p = ty::PlaceholderRegion { universe, name: br.kind }; self.mapped_regions.insert(p, br); - self.infcx.tcx.mk_region(ty::RePlaceholder(p)) + self.infcx.tcx.mk_re_placeholder(p) } _ => r, } @@ -783,9 +788,9 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> { } ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); - let p = ty::PlaceholderType { universe, name: bound_ty.var }; + let p = ty::PlaceholderType { universe, name: bound_ty.kind }; self.mapped_types.insert(p, bound_ty); - self.infcx.tcx.mk_ty(ty::Placeholder(p)) + self.infcx.tcx.mk_placeholder(p) } _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), _ => t, @@ -826,7 +831,7 @@ pub struct PlaceholderReplacer<'me, 'tcx> { } impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { - pub fn replace_placeholders<T: TypeFoldable<'tcx>>( + pub fn replace_placeholders<T: TypeFoldable<TyCtxt<'tcx>>>( infcx: &'me InferCtxt<'tcx>, mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>, mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>, @@ -846,12 +851,12 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { } } -impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { self.infcx.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>( + fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>( &mut self, t: ty::Binder<'tcx, T>, ) -> ty::Binder<'tcx, T> { @@ -888,7 +893,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.tcx().mk_region(ty::ReLateBound(db, *replace_var)) + self.interner().mk_re_late_bound(db, *replace_var) } None => r1, } @@ -915,7 +920,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.tcx().mk_ty(ty::Bound(db, *replace_var)) + self.interner().mk_bound(db, *replace_var) } None => ty, } @@ -939,7 +944,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.tcx().mk_const(ty::ConstKind::Bound(db, *replace_var), ct.ty()) + self.interner().mk_const(ty::ConstKind::Bound(db, *replace_var), ct.ty()) } None => ct, } @@ -1170,7 +1175,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( /// paths you want to take. To make things worse, it was possible for /// cycles to arise, where you basically had a setup like `<MyType<$0> /// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as -/// Trait>::Foo> to `[type error]` would lead to an obligation of +/// Trait>::Foo>` to `[type error]` would lead to an obligation of /// `<MyType<[type error]> as Trait>::Foo`. We are supposed to report /// an error for this obligation, but we legitimately should not, /// because it contains `[type error]`. Yuck! (See issue #29857 for @@ -1208,8 +1213,8 @@ struct Progress<'tcx> { } impl<'tcx> Progress<'tcx> { - fn error(tcx: TyCtxt<'tcx>) -> Self { - Progress { term: tcx.ty_error().into(), obligations: vec![] } + fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self { + Progress { term: tcx.ty_error(guar).into(), obligations: vec![] } } fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self { @@ -1235,8 +1240,8 @@ fn project<'cx, 'tcx>( ))); } - if obligation.predicate.references_error() { - return Ok(Projected::Progress(Progress::error(selcx.tcx()))); + if let Err(guar) = obligation.predicate.error_reported() { + return Ok(Projected::Progress(Progress::error(selcx.tcx(), guar))); } let mut candidates = ProjectionCandidateSet::None; @@ -1292,17 +1297,6 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( let tcx = selcx.tcx(); 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.def_id).type_at(0) - && tcx.associated_item(trait_fn_def_id).defaultness(tcx).has_value() - { - candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait( - ImplTraitInTraitCandidate::Trait, - )); - return; - } let trait_def_id = tcx.parent(trait_fn_def_id); let trait_substs = @@ -1313,23 +1307,21 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( let _ = selcx.infcx.commit_if_ok(|_| { match selcx.select(&obligation.with(tcx, trait_predicate)) { Ok(Some(super::ImplSource::UserDefined(data))) => { - candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait( - ImplTraitInTraitCandidate::Impl(data), - )); + candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data)); Ok(()) } Ok(None) => { candidate_set.mark_ambiguous(); - return Err(()); + Err(()) } Ok(Some(_)) => { // Don't know enough about the impl to provide a useful signature - return Err(()); + Err(()) } Err(e) => { debug!(error = ?e, "selection error"); candidate_set.mark_error(e); - return Err(()); + Err(()) } } }); @@ -1605,6 +1597,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(..) // Integers and floats always have `u8` as their discriminant. @@ -1654,6 +1647,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never // Extern types have unit metadata, according to RFC 2850 | ty::Foreign(_) @@ -1775,18 +1769,9 @@ fn confirm_candidate<'cx, 'tcx>( ProjectionCandidate::Select(impl_source) => { confirm_select_candidate(selcx, obligation, impl_source) } - ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Impl(data)) => { + ProjectionCandidate::ImplTraitInTrait(data) => { confirm_impl_trait_in_trait_candidate(selcx, obligation, data) } - // If we're projecting an RPITIT for a default trait body, that's just - // the same def-id, but as an opaque type (with regular RPIT semantics). - ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Trait) => Progress { - term: selcx - .tcx() - .mk_opaque(obligation.predicate.def_id, obligation.predicate.substs) - .into(), - obligations: vec![], - }, }; // When checking for cycle during evaluation, we compare predicates with @@ -1921,7 +1906,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { let tcx = selcx.tcx(); let self_ty = obligation.predicate.self_ty(); - let substs = tcx.mk_substs([self_ty.into()].iter()); + let substs = tcx.mk_substs(&[self_ty.into()]); let lang_items = tcx.lang_items(); let item_def_id = obligation.predicate.def_id; let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); @@ -2044,7 +2029,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( let cause = &obligation.cause; let param_env = obligation.param_env; - let cache_entry = infcx.replace_bound_vars_with_fresh_vars( + let cache_entry = infcx.instantiate_binder_with_fresh_vars( cause.span, LateBoundRegionConversionTime::HigherRankedType, poly_cache_entry, @@ -2112,8 +2097,9 @@ fn confirm_impl_candidate<'cx, 'tcx>( let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); let param_env = obligation.param_env; - let Ok(assoc_ty) = specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) else { - return Progress { term: tcx.ty_error().into(), obligations: nested }; + let assoc_ty = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) { + Ok(assoc_ty) => assoc_ty, + Err(guar) => return Progress::error(tcx, guar), }; if !assoc_ty.item.defaultness(tcx).has_value() { @@ -2125,7 +2111,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( "confirm_impl_candidate: no associated type {:?} for {:?}", assoc_ty.item.name, obligation.predicate ); - return Progress { term: tcx.ty_error().into(), obligations: nested }; + return Progress { term: tcx.ty_error_misc().into(), obligations: nested }; } // If we're trying to normalize `<Vec<u32> as X>::A<S>` using //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then: @@ -2136,7 +2122,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); let substs = translate_substs(selcx.infcx, param_env, impl_def_id, substs, assoc_ty.defining_node); - let ty = tcx.bound_type_of(assoc_ty.item.def_id); + let ty = tcx.type_of(assoc_ty.item.def_id); let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const { let identity_substs = @@ -2147,7 +2133,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( } else { ty.map_bound(|ty| ty.into()) }; - if !check_substs_compatible(tcx, &assoc_ty.item, substs) { + if !check_substs_compatible(tcx, assoc_ty.item, substs) { let err = tcx.ty_error_with_message( obligation.cause.span, "impl item and trait item have different parameters", @@ -2162,7 +2148,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( // Verify that the trait item and its implementation have compatible substs lists fn check_substs_compatible<'tcx>( tcx: TyCtxt<'tcx>, - assoc_item: &ty::AssocItem, + assoc_item: ty::AssocItem, substs: ty::SubstsRef<'tcx>, ) -> bool { fn check_substs_compatible_inner<'tcx>( @@ -2209,11 +2195,13 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( let mut obligations = data.nested; let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id); - let Ok(leaf_def) = specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) else { - return Progress { term: tcx.ty_error().into(), obligations }; + let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) { + Ok(assoc_ty) => assoc_ty, + Err(guar) => return Progress::error(tcx, guar), }; - if !leaf_def.item.defaultness(tcx).has_value() { - return Progress { term: tcx.ty_error().into(), obligations }; + // We don't support specialization for RPITITs anyways... yet. + if !leaf_def.is_final() { + return Progress { term: tcx.ty_error_misc().into(), obligations }; } // Use the default `impl Trait` for the trait, e.g., for a default trait body @@ -2236,7 +2224,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( leaf_def.defining_node, ); - if !check_substs_compatible(tcx, &leaf_def.item, impl_fn_substs) { + if !check_substs_compatible(tcx, leaf_def.item, impl_fn_substs) { let err = tcx.ty_error_with_message( obligation.cause.span, "impl method and trait method have different parameters", @@ -2284,7 +2272,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( obligation.recursion_depth + 1, tcx.bound_return_position_impl_trait_in_trait_tys(impl_fn_def_id) .map_bound(|tys| { - tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.def_id]) + tys.map_or_else(|guar| tcx.ty_error(guar), |tys| tys[&obligation.predicate.def_id]) }) .subst(tcx, impl_fn_substs), &mut obligations, 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 0f21813bc..455b53bfb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -31,6 +31,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::FnPtr(_) | ty::Char | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::RawPtr(_) | ty::Ref(..) | ty::Str diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 09b58894d..f183248f2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,7 +1,9 @@ use rustc_middle::ty; +use rustc_session::config::TraitSolver; use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; +use crate::solve::{Certainty, Goal, InferCtxtEvalExt, MaybeCause}; use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext}; pub trait InferCtxtExt<'tcx> { @@ -77,12 +79,38 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { _ => obligation.param_env.without_const(), }; - let c_pred = self - .canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values); - // Run canonical query. If overflow occurs, rerun from scratch but this time - // in standard trait query mode so that overflow is handled appropriately - // within `SelectionContext`. - self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) + if self.tcx.sess.opts.unstable_opts.trait_solver != TraitSolver::Next { + let c_pred = self.canonicalize_query_keep_static( + param_env.and(obligation.predicate), + &mut _orig_values, + ); + self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) + } else { + self.probe(|snapshot| { + if let Ok((_, certainty)) = + self.evaluate_root_goal(Goal::new(self.tcx, param_env, obligation.predicate)) + { + match certainty { + Certainty::Yes => { + if self.opaque_types_added_in_snapshot(snapshot) { + Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes) + } else if self.region_constraints_added_in_snapshot(snapshot).is_some() + { + Ok(EvaluationResult::EvaluatedToOkModuloRegions) + } else { + Ok(EvaluationResult::EvaluatedToOk) + } + } + Certainty::Maybe(MaybeCause::Ambiguity) => { + Ok(EvaluationResult::EvaluatedToAmbig) + } + Certainty::Maybe(MaybeCause::Overflow) => Err(OverflowError::Canonical), + } + } else { + Ok(EvaluationResult::EvaluatedToErr) + } + }) + } } // Helper function that canonicalizes and runs the query. If an @@ -92,6 +120,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, ) -> EvaluationResult { + // Run canonical query. If overflow occurs, rerun from scratch but this time + // in standard trait query mode so that overflow is handled appropriately + // within `SelectionContext`. match self.evaluate_obligation(obligation) { Ok(result) => result, Err(OverflowError::Canonical) => { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 27247271d..b0cec3ce7 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -12,7 +12,7 @@ use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::Normalized; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; -use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable}; +use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; use rustc_span::DUMMY_SP; @@ -32,7 +32,7 @@ pub trait QueryNormalizeExt<'tcx> { /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure. fn query_normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution> where - T: TypeFoldable<'tcx>; + T: TypeFoldable<TyCtxt<'tcx>>; } impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { @@ -51,7 +51,7 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> { /// and other details are still "under development". fn query_normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution> where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { debug!( "normalize::<{}>(value={:?}, param_env={:?}, cause={:?})", @@ -115,8 +115,8 @@ struct MaxEscapingBoundVarVisitor { escaping: usize, } -impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { - fn visit_binder<T: TypeVisitable<'tcx>>( +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor { + fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( &mut self, t: &ty::Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy> { @@ -170,14 +170,14 @@ struct QueryNormalizer<'cx, 'tcx> { universes: Vec<Option<ty::UniverseIndex>>, } -impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { +impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> { type Error = NoSolution; - fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { self.infcx.tcx } - fn try_fold_binder<T: TypeFoldable<'tcx>>( + fn try_fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>( &mut self, t: ty::Binder<'tcx, T>, ) -> Result<ty::Binder<'tcx, T>, Self::Error> { @@ -214,18 +214,22 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { Reveal::All => { let substs = substs.try_fold_with(self)?; - let recursion_limit = self.tcx().recursion_limit(); + let recursion_limit = self.interner().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { - self.infcx.err_ctxt().report_overflow_error( - &ty, - self.cause.span, - true, - |_| {}, - ); + // A closure or generator may have itself as in its upvars. + // This should be checked handled by the recursion check for opaque + // types, but we may end up here before that check can happen. + // In that case, we delay a bug to mark the trip, and continue without + // revealing the opaque. + self.infcx + .err_ctxt() + .build_overflow_error(&ty, self.cause.span, true) + .delay_as_bug(); + return ty.try_super_fold_with(self); } - let generic_ty = self.tcx().bound_type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx(), substs); + let generic_ty = self.interner().type_of(def_id); + let concrete_ty = generic_ty.subst(self.interner(), substs); self.anon_depth += 1; if concrete_ty == ty { bug!( diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 97002b461..9e8bc8bce 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -54,8 +54,8 @@ pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> { /// which produces the resulting query region constraints. /// /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html -pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx { - type QueryResponse: TypeFoldable<'tcx>; +pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 'tcx { + type QueryResponse: TypeFoldable<TyCtxt<'tcx>>; /// Give query the option for a simple fast path that never /// actually hits the tcx cache lookup etc. Return `Some(r)` with diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index 8f0b4de31..5b216c076 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -1,7 +1,7 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; use crate::traits::query::Fallible; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt}; +use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use std::fmt; pub use rustc_middle::traits::query::type_op::Normalize; @@ -24,7 +24,7 @@ where } } -pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Copy { +pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<'tcx> + Copy { fn type_op_method( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs index 0d42cd825..21ef4e24f 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -21,11 +21,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>, ) -> Option<Self::QueryResponse> { - if trivial_dropck_outlives(tcx, key.value.dropped_ty) { - Some(DropckOutlivesResult::default()) - } else { - None - } + trivial_dropck_outlives(tcx, key.value.dropped_ty).then(DropckOutlivesResult::default) } fn perform_query( diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs deleted file mode 100644 index 34b5fc489..000000000 --- a/compiler/rustc_trait_selection/src/traits/relationships.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::infer::InferCtxt; -use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::PredicateObligation; -use rustc_infer::traits::TraitEngine; -use rustc_middle::ty; - -pub(crate) fn update<'tcx, T>( - engine: &mut T, - infcx: &InferCtxt<'tcx>, - obligation: &PredicateObligation<'tcx>, -) where - T: TraitEngine<'tcx>, -{ - // (*) binder skipped - if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder() - && let Some(ty) = infcx.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| infcx.root_var(t)) - && infcx.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id) - { - let new_self_ty = infcx.tcx.types.unit; - - // Then construct a new obligation with Self = () added - // to the ParamEnv, and see if it holds. - let o = obligation.with(infcx.tcx, - obligation - .predicate - .kind() - .rebind( - // (*) binder moved here - 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. - if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) && result.may_apply() { - engine.relationships().entry(ty).or_default().self_in_trait = true; - } - } - - if let ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) = - obligation.predicate.kind().skip_binder() - { - // If the projection predicate (Foo::Bar == X) has X as a non-TyVid, - // we need to make it into one. - if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) { - debug!("relationship: {:?}.output = true", vid); - engine.relationships().entry(vid).or_default().output = true; - } - } -} 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 2733d9643..e91057356 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -9,7 +9,7 @@ use hir::LangItem; use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; -use rustc_middle::ty::{self, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_target::spec::abi::Abi; use crate::traits; @@ -94,7 +94,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_for_transmutability(obligation, &mut candidates); } else if lang_items.tuple_trait() == Some(def_id) { self.assemble_candidate_for_tuple(obligation, &mut candidates); - } else if lang_items.pointer_sized() == Some(def_id) { + } else if lang_items.pointer_like() == Some(def_id) { self.assemble_candidate_for_ptr_sized(obligation, &mut candidates); } else { if lang_items.clone_trait() == Some(def_id) { @@ -174,8 +174,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .param_env .caller_bounds() .iter() - .filter_map(|p| p.to_opt_poly_trait_pred()) - .filter(|p| !p.references_error()); + .filter(|p| !p.references_error()) + .filter_map(|p| p.to_opt_poly_trait_pred()); // Micro-optimization: filter out predicates relating to different traits. let matching_bounds = @@ -339,7 +339,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Essentially any user-written impl will match with an error type, // so creating `ImplCandidates` isn't useful. However, we might - // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized) + // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized`) // This helps us avoid overflow: see issue #72839 // Since compilation is already guaranteed to fail, this is just // to try to show the 'nicest' possible errors to the user. @@ -396,7 +396,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // still be provided by a manual implementation for // this trait and type. } - ty::Param(..) | ty::Alias(ty::Projection, ..) => { + ty::Param(..) + | ty::Alias(ty::Projection, ..) + | ty::Placeholder(..) + | ty::Bound(..) => { // 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 @@ -448,6 +451,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); self.infcx.probe(|_snapshot| { + if obligation.has_non_region_late_bound() { + return; + } + // The code below doesn't care about regions, and the // self-ty here doesn't escape this probe, so just erase // any LBR. @@ -466,7 +473,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(principal) = data.principal() { if !self.infcx.tcx.features().object_safe_for_dispatch { principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().is_object_safe(principal.def_id()) { + } else if self.tcx().check_is_object_safe(principal.def_id()) { principal.with_self_ty(self.tcx(), self_ty) } else { return; @@ -488,7 +495,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = - self.infcx.replace_bound_vars_with_placeholders(poly_trait_predicate); + self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate); // Count only those upcast versions that match the trait-ref // we are looking for. Specifically, do not only check for the @@ -765,7 +772,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::Tuple(_) - | ty::GeneratorWitness(_) => { + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) => { // These are built-in, and cannot have a custom `impl const Destruct`. candidates.vec.push(ConstDestructCandidate(None)); } @@ -826,6 +834,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Closure(_, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Alias(..) | ty::Param(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 82a59831b..21c158fd0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -8,12 +8,11 @@ //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_middle::ty::{ - self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef, - ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, + self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, + TraitRef, Ty, TyCtxt, TypeVisitableExt, }; use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; @@ -152,7 +151,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_predicate = self.infcx.shallow_resolve(obligation.predicate); let placeholder_trait_predicate = - self.infcx.replace_bound_vars_with_placeholders(trait_predicate).trait_ref; + self.infcx.instantiate_binder_with_placeholders(trait_predicate).trait_ref; 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() { @@ -337,7 +336,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cause = obligation.derived_cause(BuiltinDerivedObligation); let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref); + let trait_ref = self.infcx.instantiate_binder_with_placeholders(poly_trait_ref); let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations( &cause, obligation.recursion_depth + 1, @@ -428,7 +427,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); debug!(?obligation, ?index, "confirm_object_candidate"); - let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate); + let trait_predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate); let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty()); let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref); let ty::Dynamic(data, ..) = *self_ty.kind() else { @@ -438,7 +437,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let object_trait_ref = data.principal().unwrap_or_else(|| { span_bug!(obligation.cause.span, "object candidate with no principal") }); - let object_trait_ref = self.infcx.replace_bound_vars_with_fresh_vars( + let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, HigherRankedType, object_trait_ref, @@ -525,29 +524,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .kind { GenericParamDefKind::Type { .. } => { - let kind = ty::BoundTyKind::Param(param.name); + let kind = ty::BoundTyKind::Param(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Ty(kind); bound_vars.push(bound_var); - tcx.mk_ty(ty::Bound( + tcx.mk_bound( ty::INNERMOST, ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind, }, - )) + ) .into() } GenericParamDefKind::Lifetime => { let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); - tcx.mk_region(ty::ReLateBound( + tcx.mk_re_late_bound( ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind, }, - )) + ) .into() } GenericParamDefKind::Const { .. } => { @@ -558,15 +557,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1), ), - tcx.type_of(param.def_id), + tcx.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), ) .into() } }); - let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter()); - let assoc_ty_substs = tcx.intern_substs(&substs); - - let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter()); + let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); + let assoc_ty_substs = tcx.mk_substs(&substs); let bound = bound.map_bound(|b| b.kind().skip_binder()).subst(tcx, assoc_ty_substs); tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars)) @@ -630,7 +629,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Confirm the `type Output: Sized;` bound that is present on `FnOnce` - let output_ty = self.infcx.replace_bound_vars_with_placeholders(sig.output()); + let output_ty = self.infcx.instantiate_binder_with_placeholders(sig.output()); let output_ty = normalize_with_depth_to( self, obligation.param_env, @@ -653,7 +652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, "confirm_trait_alias_candidate"); let alias_def_id = obligation.predicate.def_id(); - let predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate); + let predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; let substs = trait_ref.substs; @@ -822,6 +821,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx .at(&obligation.cause, obligation.param_env) + // needed for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs + .define_opaque_types(true) .sup(obligation_trait_ref, expected_trait_ref) .map(|InferOk { mut obligations, .. }| { obligations.extend(nested); @@ -879,7 +880,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::ExistentialPredicate::AutoTrait) .map(ty::Binder::dummy), ); - let existential_predicates = tcx.mk_poly_existential_predicates(iter); + let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter); let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_a); // Require that the traits involved in this upcast are **equal**; @@ -978,7 +979,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::ExistentialPredicate::AutoTrait) .map(ty::Binder::dummy), ); - let existential_predicates = tcx.mk_poly_existential_predicates(iter); + let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter); let source_trait = tcx.mk_dynamic(existential_predicates, r_b, dyn_a); // Require that the traits involved in this upcast are **equal**; @@ -1009,7 +1010,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `T` -> `Trait` (_, &ty::Dynamic(ref data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); - if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { + if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)); } @@ -1064,51 +1065,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Struct<T>` -> `Struct<U>` (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { - let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind() { - ty::Param(p) => Some(p.index), - _ => None, - }, - - // Lifetimes aren't allowed to change during unsizing. - GenericArgKind::Lifetime(_) => None, - - GenericArgKind::Const(ct) => match ct.kind() { - ty::ConstKind::Param(p) => Some(p.index), - _ => None, - }, - }; - - // FIXME(eddyb) cache this (including computing `unsizing_params`) - // by putting it in a query; it would only need the `DefId` as it - // looks at declared field types, not anything substituted. - - // The last field of the structure has to exist and contain type/const parameters. - let (tail_field, prefix_fields) = - def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?; - let tail_field_ty = tcx.bound_type_of(tail_field.did); - - let mut unsizing_params = GrowableBitSet::new_empty(); - for arg in tail_field_ty.0.walk() { - if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.insert(i); - } - } - - // Ensure none of the other fields mention the parameters used - // in unsizing. - for field in prefix_fields { - for arg in tcx.type_of(field.did).walk() { - if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.remove(i); - } - } - } - + let unsizing_params = tcx.unsizing_params_for_adt(def.did()); if unsizing_params.is_empty() { return Err(Unimplemented); } + let tail_field = def + .non_enum_variant() + .fields + .last() + .expect("expected unsized ADT to have a tail field"); + let tail_field_ty = tcx.type_of(tail_field.did); + // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`, // normalizing in the process, since `type_of` returns something directly from // astconv (which means it's un-normalized). @@ -1131,7 +1099,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Check that the source struct with the target's // unsizing parameters is equal to the target. - let substs = tcx.mk_substs(substs_a.iter().enumerate().map(|(i, k)| { + let substs = tcx.mk_substs_from_iter(substs_a.iter().enumerate().map(|(i, k)| { if unsizing_params.contains(i as u32) { substs_b[i] } else { k } })); let new_struct = tcx.mk_adt(def, substs); @@ -1163,7 +1131,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Check that the source tuple with the target's // last element is equal to the target. - let new_tuple = tcx.mk_tup(a_mid.iter().copied().chain(iter::once(b_last))); + let new_tuple = + tcx.mk_tup_from_iter(a_mid.iter().copied().chain(iter::once(b_last))); let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) @@ -1223,7 +1192,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cause = obligation.derived_cause(|derived| { ImplDerivedObligation(Box::new(ImplDerivedObligationCause { derived, - impl_def_id, + impl_or_alias_def_id: impl_def_id, + impl_def_predicate_index: None, span: obligation.cause.span, })) }); @@ -1285,6 +1255,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::GeneratorWitness(tys) => { stack.extend(tcx.erase_late_bound_regions(tys).to_vec()); } + ty::GeneratorWitnessMIR(def_id, substs) => { + let tcx = self.tcx(); + stack.extend(tcx.generator_hidden_types(def_id).map(|bty| { + let ty = bty.subst(tcx, substs); + debug_assert!(!ty.has_late_bound_regions()); + ty + })) + } // If we have a projection type, make sure to normalize it so we replace it // with a fresh infer variable diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f90da95d5..7f454fbb3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -27,6 +27,7 @@ use super::{ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::traits::error_reporting::TypeErrCtxtExt; +use crate::traits::project::try_normalize_with_depth_to; use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; @@ -38,6 +39,8 @@ use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; +use rustc_infer::traits::TraitEngine; +use rustc_infer::traits::TraitEngineExt; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -46,7 +49,8 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; -use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable}; +use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_session::config::TraitSolver; use rustc_span::symbol::sym; use std::cell::{Cell, RefCell}; @@ -147,7 +151,7 @@ struct TraitObligationStack<'prev, 'tcx> { /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait` /// is `EvaluatedToOk`; this is because they were only considered /// ok on the premise that if `A: AutoTrait` held, but we indeed - /// encountered a problem (later on) with `A: AutoTrait. So we + /// encountered a problem (later on) with `A: AutoTrait`. So we /// currently set a flag on the stack node for `B: AutoTrait` (as /// well as the second instance of `A: AutoTrait`) to suppress /// caching. @@ -374,11 +378,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = trait_ref.self_ty(); let (trait_desc, self_desc) = with_no_trimmed_paths!({ let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }; + let self_desc = + self_ty.has_concrete_skeleton().then(|| self_ty.to_string()); (trait_desc, self_desc) }); let cause = if let Conflict::Upstream = conflict { @@ -544,10 +545,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { self.evaluation_probe(|this| { - this.evaluate_predicate_recursively( - TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), - obligation.clone(), - ) + if this.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next { + this.evaluate_predicate_recursively( + TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), + obligation.clone(), + ) + } else { + this.evaluate_predicates_recursively_in_new_solver([obligation.clone()]) + } }) } @@ -586,18 +591,40 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { where I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug, { - let mut result = EvaluatedToOk; - for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; - if let EvaluatedToErr = eval { - // fast-path - EvaluatedToErr is the top of the lattice, - // so we don't need to look on the other predicates. - return Ok(EvaluatedToErr); - } else { - result = cmp::max(result, eval); + if self.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next { + let mut result = EvaluatedToOk; + for obligation in predicates { + let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; + if let EvaluatedToErr = eval { + // fast-path - EvaluatedToErr is the top of the lattice, + // so we don't need to look on the other predicates. + return Ok(EvaluatedToErr); + } else { + result = cmp::max(result, eval); + } } + Ok(result) + } else { + self.evaluate_predicates_recursively_in_new_solver(predicates) } - Ok(result) + } + + /// Evaluates the predicates using the new solver when `-Ztrait-solver=next` is enabled + fn evaluate_predicates_recursively_in_new_solver( + &mut self, + predicates: impl IntoIterator<Item = PredicateObligation<'tcx>>, + ) -> Result<EvaluationResult, OverflowError> { + let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(); + fulfill_cx.register_predicate_obligations(self.infcx, predicates); + // True errors + if !fulfill_cx.select_where_possible(self.infcx).is_empty() { + return Ok(EvaluatedToErr); + } + if !fulfill_cx.select_all_or_error(self.infcx).is_empty() { + return Ok(EvaluatedToAmbig); + } + // Regions and opaques are handled in the `evaluation_probe` by looking at the snapshot + Ok(EvaluatedToOk) } #[instrument( @@ -700,7 +727,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Otherwise, we can say that `T: NonAutoTrait` is // true. // Let's imagine we have a predicate stack like - // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto + // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto` // depth ^1 ^2 ^3 // and the current predicate is `WF(T)`. `wf_args` // would contain `(T, 1)`. We want to check all @@ -768,7 +795,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::ObjectSafe(trait_def_id) => { - if self.tcx().is_object_safe(trait_def_id) { + if self.tcx().check_is_object_safe(trait_def_id) { Ok(EvaluatedToOk) } else { Ok(EvaluatedToErr) @@ -962,7 +989,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for chalk") } + ty::PredicateKind::AliasEq(..) => { + bug!("AliasEq is only used for new solver") + } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + match self.infcx.at(&obligation.cause, obligation.param_env).eq(ct.ty(), ty) { + Ok(inf_ok) => self.evaluate_predicates_recursively( + previous_stack, + inf_ok.into_obligations(), + ), + Err(_) => Ok(EvaluatedToErr), + } + } } }) } @@ -1017,7 +1056,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(cycle_result); } - let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); + let (result, dep_node) = self.in_task(|this| { + let mut result = this.evaluate_stack(&stack)?; + + // fix issue #103563, we don't normalize + // nested obligations which produced by `TraitDef` candidate + // (i.e. using bounds on assoc items as assumptions). + // because we don't have enough information to + // normalize these obligations before evaluating. + // so we will try to normalize the obligation and evaluate again. + // we will replace it with new solver in the future. + if EvaluationResult::EvaluatedToErr == result + && fresh_trait_pred.has_projections() + && fresh_trait_pred.is_global() + { + let mut nested_obligations = Vec::new(); + let predicate = try_normalize_with_depth_to( + this, + param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.predicate, + &mut nested_obligations, + ); + if predicate != obligation.predicate { + let mut nested_result = EvaluationResult::EvaluatedToOk; + for obligation in nested_obligations { + nested_result = cmp::max( + this.evaluate_predicate_recursively(previous_stack, obligation)?, + nested_result, + ); + } + + if nested_result.must_apply_modulo_regions() { + let obligation = obligation.with(this.tcx(), predicate); + result = cmp::max( + nested_result, + this.evaluate_trait_predicate_recursively(previous_stack, obligation)?, + ); + } + } + } + + Ok::<_, OverflowError>(result) + }); + let result = result?; if !result.must_apply_modulo_regions() { @@ -1323,7 +1406,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// The weird return type of this function allows it to be used with the `try` (`?`) /// operator within certain functions. #[inline(always)] - fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V>( + fn check_recursion_limit<T: Display + TypeFoldable<TyCtxt<'tcx>>, V>( &self, obligation: &Obligation<'tcx, T>, error_obligation: &Obligation<'tcx, V>, @@ -1589,7 +1672,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> smallvec::SmallVec<[(usize, ty::BoundConstness); 2]> { let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = - self.infcx.replace_bound_vars_with_placeholders(poly_trait_predicate); + self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate); debug!(?placeholder_trait_predicate); let tcx = self.infcx.tcx; @@ -1669,7 +1752,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); self.infcx .at(&obligation.cause, obligation.param_env) - .define_opaque_types(false) .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) .map(|InferOk { obligations: _, value: () }| { // This method is called within a probe, so we can't have @@ -1709,7 +1791,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { potentially_unnormalized_candidates: bool, ) -> ProjectionMatchesProjection { let mut nested_obligations = Vec::new(); - let infer_predicate = self.infcx.replace_bound_vars_with_fresh_vars( + let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, LateBoundRegionConversionTime::HigherRankedType, env_predicate, @@ -1732,7 +1814,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let is_match = self .infcx .at(&obligation.cause, obligation.param_env) - .define_opaque_types(false) .sup(obligation.predicate, infer_projection) .map_or(false, |InferOk { obligations, value: () }| { self.evaluate_predicates_recursively( @@ -2037,6 +2118,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Ref(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Array(..) | ty::Closure(..) | ty::Never @@ -2064,12 +2146,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { })) } - ty::Alias(..) | ty::Param(_) => None, + ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None, ty::Infer(ty::TyVar(_)) => Ambiguous, - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + // We can make this an ICE if/once we actually instantiate the trait obligation. + ty::Bound(..) => None, + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } } @@ -2147,12 +2230,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } // (*) binder moved here - let all_vars = self.tcx().mk_bound_variable_kinds( + let all_vars = self.tcx().mk_bound_variable_kinds_from_iter( obligation.predicate.bound_vars().iter().chain(binder.bound_vars().iter()), ); Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars)) } + ty::GeneratorWitnessMIR(def_id, ref substs) => { + let hidden_types = bind_generator_hidden_types_above( + self.infcx, + def_id, + substs, + obligation.predicate.bound_vars(), + ); + Where(hidden_types) + } + ty::Closure(_, substs) => { // (*) binder moved here let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); @@ -2207,12 +2300,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Float(_) | ty::FnDef(..) | ty::FnPtr(_) - | ty::Str | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never | ty::Char => ty::Binder::dummy(Vec::new()), + // Treat this like `struct str([u8]);` + ty::Str => ty::Binder::dummy(vec![self.tcx().mk_slice(self.tcx().types.u8)]), + ty::Placeholder(..) | ty::Dynamic(..) | ty::Param(..) @@ -2250,6 +2345,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { types.map_bound(|types| types.to_vec()) } + ty::GeneratorWitnessMIR(def_id, ref substs) => { + bind_generator_hidden_types_above(self.infcx, def_id, substs, t.bound_vars()) + } + // For `PhantomData<T>`, we pass `T`. ty::Adt(def, substs) if def.is_phantom_data() => t.rebind(substs.types().collect()), @@ -2261,7 +2360,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - t.rebind(vec![self.tcx().bound_type_of(def_id).subst(self.tcx(), substs)]) + t.rebind(vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)]) } } } @@ -2295,7 +2394,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .flat_map(|ty| { let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/ - let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); + let placeholder_ty = self.infcx.instantiate_binder_with_placeholders(ty); let Normalized { value: normalized_ty, mut obligations } = ensure_sufficient_stack(|| { project::normalize_with_depth( @@ -2346,7 +2445,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // the placeholder trait ref may fail due the Generalizer relation // raising a CyclicalTy error due to a sub_root_var relation // for a variable being generalized... - self.infcx.tcx.sess.delay_span_bug( + let guar = self.infcx.tcx.sess.delay_span_bug( obligation.cause.span, &format!( "Impl {:?} was matchable against {:?} but now is not", @@ -2354,7 +2453,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ), ); let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); - let err = self.tcx().ty_error(); + let err = self.tcx().ty_error(guar); let value = value.fold_with(&mut BottomUpFolder { tcx: self.tcx(), ty_op: |_| err, @@ -2374,7 +2473,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> { let placeholder_obligation = - self.infcx.replace_bound_vars_with_placeholders(obligation.predicate); + self.infcx.instantiate_binder_with_placeholders(obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); @@ -2408,9 +2507,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&cause, obligation.param_env) - .define_opaque_types(false) .eq(placeholder_obligation_trait_ref, impl_trait_ref) - .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{e}`"))?; + .map_err(|e| { + debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx())) + })?; nested_obligations.extend(obligations); if !self.is_intercrate() @@ -2457,11 +2557,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { self.infcx .at(&obligation.cause, obligation.param_env) - // We don't want predicates for opaque types to just match all other types, - // if there is an obligation on the opaque type, then that obligation must be met - // opaquely. Otherwise we'd match any obligation to the opaque type and then error - // out later. - .define_opaque_types(false) .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| ()) @@ -2562,11 +2657,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { assert_eq!(predicates.parent, None); let predicates = predicates.instantiate_own(tcx, substs); let mut obligations = Vec::with_capacity(predicates.len()); - for (predicate, span) in predicates { + for (index, (predicate, span)) in predicates.into_iter().enumerate() { let cause = cause.clone().derived_cause(parent_trait_pred, |derived| { ImplDerivedObligation(Box::new(ImplDerivedObligationCause { derived, - impl_def_id: def_id, + impl_or_alias_def_id: def_id, + impl_def_predicate_index: Some(index), span, })) }); @@ -2892,3 +2988,56 @@ pub enum ProjectionMatchesProjection { Ambiguous, No, } + +/// Replace all regions inside the generator interior with late bound regions. +/// Note that each region slot in the types gets a new fresh late bound region, which means that +/// none of the regions inside relate to any other, even if typeck had previously found constraints +/// that would cause them to be related. +#[instrument(level = "trace", skip(infcx), ret)] +fn bind_generator_hidden_types_above<'tcx>( + infcx: &InferCtxt<'tcx>, + def_id: DefId, + substs: ty::SubstsRef<'tcx>, + bound_vars: &ty::List<ty::BoundVariableKind>, +) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { + let tcx = infcx.tcx; + let mut seen_tys = FxHashSet::default(); + + let considering_regions = infcx.considering_regions; + + let num_bound_variables = bound_vars.len() as u32; + let mut counter = num_bound_variables; + + let hidden_types: Vec<_> = tcx + .generator_hidden_types(def_id) + // Deduplicate tys to avoid repeated work. + .filter(|bty| seen_tys.insert(*bty)) + .map(|bty| { + let mut ty = bty.subst(tcx, substs); + + // Only remap erased regions if we use them. + if considering_regions { + ty = tcx.fold_regions(ty, |mut r, current_depth| { + if let ty::ReErased = r.kind() { + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(counter), + kind: ty::BrAnon(counter, None), + }; + counter += 1; + r = tcx.mk_re_late_bound(current_depth, br); + } + r + }) + } + + ty + }) + .collect(); + if considering_regions { + debug_assert!(!hidden_types.has_erased_regions()); + } + let bound_vars = tcx.mk_bound_variable_kinds_from_iter(bound_vars.iter().chain( + (num_bound_variables..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))), + )); + ty::Binder::bind_with_vars(hidden_types, bound_vars) +} diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 3b796c623..d1d6a7a90 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -455,7 +455,13 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti w.push('>'); } - write!(w, " {} for {}", trait_ref.print_only_trait_path(), tcx.type_of(impl_def_id)).unwrap(); + write!( + w, + " {} for {}", + trait_ref.print_only_trait_path(), + tcx.type_of(impl_def_id).subst_identity() + ) + .unwrap(); // The predicates will contain default bounds like `T: Sized`. We need to // remove these bounds, and add `T: ?Sized` to any untouched type parameters. diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 0f9196de4..61ed9ef2e 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -4,7 +4,7 @@ use crate::traits; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; -use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; pub use rustc_middle::traits::specialization_graph::*; @@ -113,7 +113,7 @@ impl<'tcx> ChildrenExt<'tcx> for Children { // Only report the `Self` type if it has at least // some outer concrete shell; otherwise, it's // not adding much information. - self_ty: if self_ty.has_concrete_skeleton() { Some(self_ty) } else { None }, + self_ty: self_ty.has_concrete_skeleton().then_some(self_ty), intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, involves_placeholder: overlap.involves_placeholder, } @@ -399,7 +399,7 @@ pub(crate) fn assoc_def( // If there is no such item in that impl, this function will fail with a // cycle error if the specialization graph is currently being built. if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_def_id) { - let &item = tcx.associated_item(impl_item_id); + let item = tcx.associated_item(impl_item_id); let impl_node = Node::Impl(impl_def_id); return Ok(LeafDef { item, diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index f398fb06c..e38ae9381 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -78,7 +78,7 @@ impl<'tcx> Search<'tcx> { } } -impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> { type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -101,7 +101,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { ty::Closure(..) => { return ControlFlow::Break(ty); } - ty::Generator(..) | ty::GeneratorWitness(..) => { + ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => { return ControlFlow::Break(ty); } ty::FnDef(..) => { @@ -110,7 +110,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { return ControlFlow::Continue(()); } ty::Array(_, n) - if { n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } => + if { n.try_eval_target_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } => { // rust-lang/rust#62336: ignore type of contents // for empty array. diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index b5df583e3..bcf63d5a6 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -4,7 +4,7 @@ use smallvec::SmallVec; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, SubstsRef}; use super::NormalizeExt; @@ -239,7 +239,7 @@ pub fn predicate_for_trait_def<'tcx>( cause: ObligationCause<'tcx>, trait_def_id: DefId, recursion_depth: usize, - params: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>, + params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, ) -> PredicateObligation<'tcx> { let trait_ref = tcx.mk_trait_ref(trait_def_id, params); predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth) @@ -292,7 +292,7 @@ pub fn closure_trait_ref_and_return_type<'tcx>( assert!(!self_ty.has_escaping_bound_vars()); let arguments_tuple = match tuple_arguments { TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], - TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()), + TupleArgumentsFlag::Yes => tcx.mk_tup(sig.skip_binder().inputs()), }; let trait_ref = tcx.mk_trait_ref(fn_trait_def_id, [self_ty, arguments_tuple]); sig.map_bound(|sig| (trait_ref, sig.output())) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 64daca714..a4e9928f8 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::traits::util::PredicateSet; use rustc_infer::traits::ImplSource; -use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; use rustc_span::{sym, Span}; @@ -197,12 +197,12 @@ fn own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &[Def .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Fn); // Now list each method's DefId (for within its trait). - let own_entries = trait_methods.filter_map(move |trait_method| { + let own_entries = trait_methods.filter_map(move |&trait_method| { debug!("own_existential_vtable_entry: trait_method={:?}", trait_method); let def_id = trait_method.def_id; // Some methods cannot be called on an object; skip those. - if !is_vtable_safe_method(tcx, trait_def_id, &trait_method) { + if !is_vtable_safe_method(tcx, trait_def_id, trait_method) { debug!("own_existential_vtable_entry: not vtable safe"); return None; } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 12d4cb4fc..d498af359 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1,11 +1,11 @@ use crate::infer::InferCtxt; use crate::traits; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; -use rustc_span::Span; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_span::{Span, DUMMY_SP}; use std::iter; /// Returns the set of obligations needed to make `arg` well-formed. @@ -17,7 +17,7 @@ use std::iter; pub fn obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, recursion_depth: usize, arg: GenericArg<'tcx>, span: Span, @@ -75,6 +75,34 @@ pub fn obligations<'tcx>( Some(result) } +/// Compute the predicates that are required for a type to be well-formed. +/// +/// This is only intended to be used in the new solver, since it does not +/// take into account recursion depth or proper error-reporting spans. +pub fn unnormalized_obligations<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + arg: GenericArg<'tcx>, +) -> Option<Vec<traits::PredicateObligation<'tcx>>> { + if let ty::GenericArgKind::Lifetime(..) = arg.unpack() { + return Some(vec![]); + } + + debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg)); + + let mut wf = WfPredicates { + tcx: infcx.tcx, + param_env, + body_id: CRATE_DEF_ID, + span: DUMMY_SP, + out: vec![], + recursion_depth: 0, + item: None, + }; + wf.compute(arg); + Some(wf.out) +} + /// Returns the obligations that make this trait reference /// well-formed. For example, if there is a trait `Set` defined like /// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF @@ -82,7 +110,7 @@ pub fn obligations<'tcx>( pub fn trait_obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, trait_pred: &ty::TraitPredicate<'tcx>, span: Span, item: &'tcx hir::Item<'tcx>, @@ -105,7 +133,7 @@ pub fn trait_obligations<'tcx>( pub fn predicate_obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, predicate: ty::Predicate<'tcx>, span: Span, ) -> Vec<traits::PredicateObligation<'tcx>> { @@ -135,6 +163,10 @@ pub fn predicate_obligations<'tcx>( ty::TermKind::Const(c) => c.into(), }) } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + wf.compute(ct.into()); + wf.compute(ty.into()); + } ty::PredicateKind::WellFormed(arg) => { wf.compute(arg); } @@ -159,6 +191,9 @@ pub fn predicate_obligations<'tcx>( ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } + ty::PredicateKind::AliasEq(..) => { + bug!("We should only wf check where clauses and `AliasEq` is not a `Clause`") + } } wf.normalize(infcx) @@ -167,7 +202,7 @@ pub fn predicate_obligations<'tcx>( struct WfPredicates<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, span: Span, out: Vec<traits::PredicateObligation<'tcx>>, recursion_depth: usize, @@ -523,6 +558,7 @@ impl<'tcx> WfPredicates<'tcx> { | ty::Error(_) | ty::Str | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Param(_) | ty::Bound(..) @@ -847,7 +883,7 @@ pub fn object_region_bounds<'tcx>( // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically // a placeholder type. - let open_ty = tcx.mk_ty_infer(ty::FreshTy(0)); + let open_ty = tcx.mk_fresh_ty(0); let predicates = existential_predicates.iter().filter_map(|predicate| { if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() { @@ -890,6 +926,7 @@ pub(crate) fn required_region_bounds<'tcx>( match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::Trait(..)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::WellFormed(..) @@ -899,6 +936,7 @@ pub(crate) fn required_region_bounds<'tcx>( | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous + | ty::PredicateKind::AliasEq(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( ref t, |