diff options
Diffstat (limited to 'compiler/rustc_traits')
-rw-r--r-- | compiler/rustc_traits/Cargo.toml | 1 | ||||
-rw-r--r-- | compiler/rustc_traits/src/chalk/db.rs | 19 | ||||
-rw-r--r-- | compiler/rustc_traits/src/chalk/lowering.rs | 31 | ||||
-rw-r--r-- | compiler/rustc_traits/src/chalk/mod.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_traits/src/codegen.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_traits/src/dropck_outlives.rs | 268 | ||||
-rw-r--r-- | compiler/rustc_traits/src/evaluate_obligation.rs | 6 | ||||
-rw-r--r-- | compiler/rustc_traits/src/implied_outlives_bounds.rs | 173 | ||||
-rw-r--r-- | compiler/rustc_traits/src/lib.rs | 5 | ||||
-rw-r--r-- | compiler/rustc_traits/src/normalize_erasing_regions.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_traits/src/normalize_projection_ty.rs | 31 | ||||
-rw-r--r-- | compiler/rustc_traits/src/type_op.rs | 124 |
12 files changed, 90 insertions, 578 deletions
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index eff6fb26d..dfd6fbff7 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -8,7 +8,6 @@ tracing = "0.1" rustc_middle = { path = "../rustc_middle" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } -rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 9683e4847..c319b2e31 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -50,12 +50,11 @@ impl<'tcx> RustIrDatabase<'tcx> { where ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option<T>>, { - let bounds = self.interner.tcx.bound_explicit_item_bounds(def_id); - bounds - .0 - .iter() - .map(|(bound, _)| bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars)) - .filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, self.interner)) + self.interner + .tcx + .explicit_item_bounds(def_id) + .subst_iter_copied(self.interner.tcx, &bound_vars) + .filter_map(|(bound, _)| LowerInto::<Option<_>>::lower_into(bound, self.interner)) .collect() } } @@ -506,15 +505,11 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0); - let explicit_item_bounds = self.interner.tcx.bound_explicit_item_bounds(opaque_ty_id.0); + let explicit_item_bounds = self.interner.tcx.explicit_item_bounds(opaque_ty_id.0); let bounds = explicit_item_bounds - .0 - .iter() + .subst_iter_copied(self.interner.tcx, &bound_vars) .map(|(bound, _)| { - explicit_item_bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars) - }) - .map(|bound| { bound.fold_with(&mut ReplaceOpaqueTyFolder { tcx: self.interner.tcx, opaque_ty_id, diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 2be72879b..e447ab94f 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -60,6 +60,20 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution<RustInterner<'tcx>>> for Subst } } +impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution<RustInterner<'tcx>>> + for &'tcx ty::List<Ty<'tcx>> +{ + fn lower_into( + self, + interner: RustInterner<'tcx>, + ) -> chalk_ir::Substitution<RustInterner<'tcx>> { + chalk_ir::Substitution::from_iter( + interner, + self.iter().map(|ty| GenericArg::from(ty).lower_into(interner)), + ) + } +} + impl<'tcx> LowerInto<'tcx, SubstsRef<'tcx>> for &chalk_ir::Substitution<RustInterner<'tcx>> { fn lower_into(self, interner: RustInterner<'tcx>) -> SubstsRef<'tcx> { interner @@ -351,15 +365,14 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> { ty::GeneratorWitness(_) => unimplemented!(), ty::GeneratorWitnessMIR(..) => unimplemented!(), ty::Never => chalk_ir::TyKind::Never, - ty::Tuple(types) => { - chalk_ir::TyKind::Tuple(types.len(), types.as_substs().lower_into(interner)) - } + ty::Tuple(types) => chalk_ir::TyKind::Tuple(types.len(), types.lower_into(interner)), ty::Alias(ty::Projection, ty::AliasTy { def_id, substs, .. }) => { chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { associated_ty_id: chalk_ir::AssocTypeId(def_id), substitution: substs.lower_into(interner), })) } + ty::Alias(ty::Inherent, _) => unimplemented!(), ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { opaque_ty_id: chalk_ir::OpaqueTyId(def_id), @@ -435,7 +448,7 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> { TyKind::GeneratorWitness(..) => unimplemented!(), TyKind::Never => ty::Never, TyKind::Tuple(_len, substitution) => { - ty::Tuple(substitution.lower_into(interner).try_as_type_list().unwrap()) + ty::Tuple(substitution.lower_into(interner).into_type_list(interner.tcx)) } TyKind::Slice(ty) => ty::Slice(ty.lower_into(interner)), TyKind::Raw(mutbl, ty) => ty::RawPtr(ty::TypeAndMut { @@ -666,7 +679,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => { - bug!("unexpected predicate {}", &self) + bug!("unexpected predicate {self}") } }; value.map(|value| chalk_ir::Binders::new(binders, value)) @@ -998,7 +1011,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for BoundVarsCollector<'tcx> { _ => (), }; - r.super_visit_with(self) + ControlFlow::Continue(()) } } @@ -1048,7 +1061,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for NamedBoundVarSubstitutor<'a, 'tcx> { _ => (), }; - r.super_fold_with(self) + r } } @@ -1142,7 +1155,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamsSubstitutor<'tcx> { } }, - _ => r.super_fold_with(self), + _ => r, } } } @@ -1223,6 +1236,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for PlaceholdersCollector { _ => (), }; - r.super_visit_with(self) + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index a5ebc26a8..8834449c9 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -7,8 +7,8 @@ pub(crate) mod db; pub(crate) mod lowering; use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; +use rustc_middle::query::Providers; use rustc_middle::traits::ChalkRustInterner; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_infer::infer::canonical::{ diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 6f81d343e..ddba03b0b 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -3,9 +3,9 @@ // seems likely that they should eventually be merged into more // general routines. -use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _}; -use rustc_middle::traits::CodegenObligationError; +use rustc_middle::traits::{CodegenObligationError, DefiningAnchor}; use rustc_middle::ty::{self, TyCtxt}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::{ diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 58117c46f..f35c14eea 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -2,18 +2,15 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; +use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::InternalSubsts; -use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; -use rustc_span::source_map::{Span, DUMMY_SP}; +use rustc_middle::ty::TyCtxt; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives; use rustc_trait_selection::traits::query::dropck_outlives::{ - DropckConstraint, DropckOutlivesResult, + compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner, }; -use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; -use rustc_trait_selection::traits::{Normalized, ObligationCause}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p }; @@ -26,263 +23,10 @@ fn dropck_outlives<'tcx>( debug!("dropck_outlives(goal={:#?})", canonical_goal); tcx.infer_ctxt().enter_canonical_trait_query(&canonical_goal, |ocx, goal| { - let tcx = ocx.infcx.tcx; - let ParamEnvAnd { param_env, value: for_ty } = goal; - - let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] }; - - // A stack of types left to process. Each round, we pop - // something from the stack and invoke - // `dtorck_constraint_for_ty`. This may produce new types that - // have to be pushed on the stack. This continues until we have explored - // all the reachable types from the type `for_ty`. - // - // Example: Imagine that we have the following code: - // - // ```rust - // struct A { - // value: B, - // children: Vec<A>, - // } - // - // struct B { - // value: u32 - // } - // - // fn f() { - // let a: A = ...; - // .. - // } // here, `a` is dropped - // ``` - // - // at the point where `a` is dropped, we need to figure out - // which types inside of `a` contain region data that may be - // accessed by any destructors in `a`. We begin by pushing `A` - // onto the stack, as that is the type of `a`. We will then - // invoke `dtorck_constraint_for_ty` which will expand `A` - // into the types of its fields `(B, Vec<A>)`. These will get - // pushed onto the stack. Eventually, expanding `Vec<A>` will - // lead to us trying to push `A` a second time -- to prevent - // infinite recursion, we notice that `A` was already pushed - // once and stop. - let mut ty_stack = vec![(for_ty, 0)]; - - // Set used to detect infinite recursion. - let mut ty_set = FxHashSet::default(); - - let cause = ObligationCause::dummy(); - let mut constraints = DropckConstraint::empty(); - while let Some((ty, depth)) = ty_stack.pop() { - debug!( - "{} kinds, {} overflows, {} ty_stack", - result.kinds.len(), - result.overflows.len(), - ty_stack.len() - ); - dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; - - // "outlives" represent types/regions that may be touched - // by a destructor. - result.kinds.append(&mut constraints.outlives); - result.overflows.append(&mut constraints.overflows); - - // If we have even one overflow, we should stop trying to evaluate further -- - // chances are, the subsequent overflows for this evaluation won't provide useful - // information and will just decrease the speed at which we can emit these errors - // (since we'll be printing for just that much longer for the often enormous types - // that result here). - if !result.overflows.is_empty() { - break; - } - - // dtorck types are "types that will get dropped but which - // do not themselves define a destructor", more or less. We have - // to push them onto the stack to be expanded. - for ty in constraints.dtorck_types.drain(..) { - let Normalized { value: ty, obligations } = - ocx.infcx.at(&cause, param_env).query_normalize(ty)?; - ocx.register_obligations(obligations); - - debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); - - match ty.kind() { - // All parameters live for the duration of the - // function. - ty::Param(..) => {} - - // A projection that we couldn't resolve - it - // might have a destructor. - ty::Alias(..) => { - result.kinds.push(ty.into()); - } - - _ => { - if ty_set.insert(ty) { - ty_stack.push((ty, depth + 1)); - } - } - } - } - } - - debug!("dropck_outlives: result = {:#?}", result); - Ok(result) + compute_dropck_outlives_inner(ocx, goal) }) } -/// Returns a set of constraints that needs to be satisfied in -/// order for `ty` to be valid for destruction. -fn dtorck_constraint_for_ty<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - for_ty: Ty<'tcx>, - depth: usize, - ty: Ty<'tcx>, - constraints: &mut DropckConstraint<'tcx>, -) -> Result<(), NoSolution> { - debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty); - - if !tcx.recursion_limit().value_within_limit(depth) { - constraints.overflows.push(ty); - return Ok(()); - } - - if trivial_dropck_outlives(tcx, ty) { - return Ok(()); - } - - match ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Never - | ty::Foreign(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::GeneratorWitness(..) - | ty::GeneratorWitnessMIR(..) => { - // these types never have a destructor - } - - ty::Array(ety, _) | ty::Slice(ety) => { - // single-element containers, behave like their element - rustc_data_structures::stack::ensure_sufficient_stack(|| { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, *ety, constraints) - })?; - } - - ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in tys.iter() { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; - } - Ok::<_, NoSolution>(()) - })?, - - ty::Closure(_, substs) => { - if !substs.as_closure().is_valid() { - // By the time this code runs, all type variables ought to - // be fully resolved. - - tcx.sess.delay_span_bug( - span, - &format!("upvar_tys for closure not found. Expected capture information for closure {ty}",), - ); - return Err(NoSolution); - } - - rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in substs.as_closure().upvar_tys() { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; - } - Ok::<_, NoSolution>(()) - })? - } - - ty::Generator(_, substs, _movability) => { - // rust-lang/rust#49918: types can be constructed, stored - // in the interior, and sit idle when generator yields - // (and is subsequently dropped). - // - // It would be nice to descend into interior of a - // generator to determine what effects dropping it might - // have (by looking at any drop effects associated with - // its interior). - // - // However, the interior's representation uses things like - // GeneratorWitness that explicitly assume they are not - // traversed in such a manner. So instead, we will - // simplify things for now by treating all generators as - // if they were like trait objects, where its upvars must - // all be alive for the generator's (potential) - // destructor. - // - // In particular, skipping over `_interior` is safe - // because any side-effects from dropping `_interior` can - // only take place through references with lifetimes - // derived from lifetimes attached to the upvars and resume - // argument, and we *do* incorporate those here. - - if !substs.as_generator().is_valid() { - // By the time this code runs, all type variables ought to - // be fully resolved. - tcx.sess.delay_span_bug( - span, - &format!("upvar_tys for generator not found. Expected capture information for generator {ty}",), - ); - return Err(NoSolution); - } - - constraints.outlives.extend( - substs - .as_generator() - .upvar_tys() - .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }), - ); - constraints.outlives.push(substs.as_generator().resume_ty().into()); - } - - ty::Adt(def, substs) => { - let DropckConstraint { dtorck_types, outlives, overflows } = - tcx.at(span).adt_dtorck_constraint(def.did())?; - // FIXME: we can try to recursively `dtorck_constraint_on_ty` - // there, but that needs some way to handle cycles. - constraints - .dtorck_types - .extend(dtorck_types.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); - constraints - .outlives - .extend(outlives.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); - constraints - .overflows - .extend(overflows.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); - } - - // Objects must be alive in order for their destructor - // to be called. - ty::Dynamic(..) => { - constraints.outlives.push(ty.into()); - } - - // Types that can't be resolved. Pass them forward. - ty::Alias(..) | ty::Param(..) => { - constraints.dtorck_types.push(ty); - } - - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => { - // By the time this code runs, all type variables ought to - // be fully resolved. - return Err(NoSolution); - } - } - - Ok(()) -} - /// Calculates the dtorck constraint for a type. pub(crate) fn adt_dtorck_constraint( tcx: TyCtxt<'_>, @@ -311,7 +55,7 @@ pub(crate) fn adt_dtorck_constraint( let mut result = DropckConstraint::empty(); for field in def.all_fields() { let fty = tcx.type_of(field.did).subst_identity(); - dtorck_constraint_for_ty(tcx, span, fty, 0, fty, &mut result)?; + dtorck_constraint_for_ty_inner(tcx, span, fty, 0, fty, &mut result)?; } result.outlives.extend(tcx.destructor_constraints(def)); dedup_dtorck_constraint(&mut result); diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index e94c8efe6..f5b2753b7 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -1,5 +1,6 @@ -use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; -use rustc_middle::ty::query::Providers; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::query::Providers; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; @@ -15,6 +16,7 @@ fn evaluate_obligation<'tcx>( tcx: TyCtxt<'tcx>, canonical_goal: CanonicalPredicateGoal<'tcx>, ) -> Result<EvaluationResult, OverflowError> { + assert!(!tcx.trait_solver_next()); debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); // HACK This bubble is required for this tests to pass: // impl-trait/issue99642.rs diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index f5bba14d2..959838ab3 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -3,18 +3,13 @@ //! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`]. use rustc_infer::infer::canonical::{self, Canonical}; -use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::query::OutlivesBound; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::source_map::DUMMY_SP; +use rustc_middle::query::Providers; +use rustc_middle::ty::TyCtxt; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; -use rustc_trait_selection::traits::wf; -use rustc_trait_selection::traits::ObligationCtxt; -use smallvec::{smallvec, SmallVec}; +use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner; +use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { implied_outlives_bounds, ..*p }; @@ -29,164 +24,6 @@ fn implied_outlives_bounds<'tcx>( > { tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { let (param_env, ty) = key.into_parts(); - compute_implied_outlives_bounds(ocx, param_env, ty) + compute_implied_outlives_bounds_inner(ocx, param_env, ty) }) } - -fn compute_implied_outlives_bounds<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, -) -> Fallible<Vec<OutlivesBound<'tcx>>> { - let tcx = ocx.infcx.tcx; - - // Sometimes when we ask what it takes for T: WF, we get back that - // U: WF is required; in that case, we push U onto this stack and - // process it next. Because the resulting predicates aren't always - // guaranteed to be a subset of the original type, so we need to store the - // WF args we've computed in a set. - let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); - let mut wf_args = vec![ty.into()]; - - let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> = - vec![]; - - while let Some(arg) = wf_args.pop() { - if !checked_wf_args.insert(arg) { - continue; - } - - // Compute the obligations for `arg` to be well-formed. If `arg` is - // an unresolved inference variable, just substituted an empty set - // -- because the return type here is going to be things we *add* - // to the environment, it's always ok for this set to be smaller - // than the ultimate set. (Note: normally there won't be - // unresolved inference variables here anyway, but there might be - // during typeck under some circumstances.) - // - // FIXME(@lcnr): It's not really "always fine", having fewer implied - // bounds can be backward incompatible, e.g. #101951 was caused by - // us not dealing with inference vars in `TypeOutlives` predicates. - let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP) - .unwrap_or_default(); - - for obligation in obligations { - debug!(?obligation); - assert!(!obligation.has_escaping_bound_vars()); - - // While these predicates should all be implied by other parts of - // the program, they are still relevant as they may constrain - // inference variables, which is necessary to add the correct - // implied bounds in some cases, mostly when dealing with projections. - // - // Another important point here: we only register `Projection` - // predicates, since otherwise we might register outlives - // predicates containing inference variables, and we don't - // learn anything new from those. - if obligation.predicate.has_non_region_infer() { - match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::AliasRelate(..) => { - ocx.register_obligation(obligation.clone()); - } - _ => {} - } - } - - let pred = match obligation.predicate.kind().no_bound_vars() { - None => continue, - Some(pred) => pred, - }; - match pred { - ty::PredicateKind::Clause(ty::Clause::Trait(..)) - // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound - // if we ever support that - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} - - // We need to search through *all* WellFormed predicates - ty::PredicateKind::WellFormed(arg) => { - wf_args.push(arg); - } - - // We need to register region relationships - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( - r_a, - r_b, - ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)), - - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - ty_a, - r_b, - ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)), - } - } - } - - // This call to `select_all_or_error` is necessary to constrain inference variables, which we - // use further down when computing the implied bounds. - match ocx.select_all_or_error().as_slice() { - [] => (), - _ => return Err(NoSolution), - } - - // We lazily compute the outlives components as - // `select_all_or_error` constrains inference variables. - let implied_bounds = outlives_bounds - .into_iter() - .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { - ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], - ty::GenericArgKind::Type(ty_a) => { - let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); - let mut components = smallvec![]; - push_outlives_components(tcx, ty_a, &mut components); - implied_bounds_from_components(r_b, components) - } - ty::GenericArgKind::Const(_) => unreachable!(), - }) - .collect(); - - Ok(implied_bounds) -} - -/// When we have an implied bound that `T: 'a`, we can further break -/// this down to determine what relationships would have to hold for -/// `T: 'a` to hold. We get to assume that the caller has validated -/// those relationships. -fn implied_bounds_from_components<'tcx>( - sub_region: ty::Region<'tcx>, - sup_components: SmallVec<[Component<'tcx>; 4]>, -) -> Vec<OutlivesBound<'tcx>> { - sup_components - .into_iter() - .filter_map(|component| { - match component { - Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), - Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), - Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)), - Component::EscapingAlias(_) => - // If the projection has escaping regions, don't - // try to infer any implied bounds even for its - // free components. This is conservative, because - // the caller will still have to prove that those - // free components outlive `sub_region`. But the - // idea is that the WAY that the caller proves - // that may change in the future and we want to - // give ourselves room to get smarter here. - { - None - } - Component::UnresolvedInferenceVariable(..) => None, - } - }) - .collect() -} diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 8bea5588a..907e2d39c 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -21,9 +21,10 @@ mod normalize_erasing_regions; mod normalize_projection_ty; mod type_op; -pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; +pub use rustc_trait_selection::traits::query::type_op::ascribe_user_type::type_op_ascribe_user_type_with_span; +pub use type_op::type_op_prove_predicate_with_cause; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; pub fn provide(p: &mut Providers) { dropck_outlives::provide(p); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 126a494f3..94c33efae 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; @@ -47,7 +47,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par // us a test case. debug_assert_eq!(normalized_value, resolved_value); let erased = infcx.tcx.erase_regions(resolved_value); - debug_assert!(!erased.needs_infer(), "{erased:?}"); + debug_assert!(!erased.has_infer(), "{erased:?}"); Ok(erased) } Err(NoSolution) => Err(NoSolution), diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index e805eb428..b552ba41a 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::{ @@ -10,7 +10,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext}; use std::sync::atomic::Ordering; pub(crate) fn provide(p: &mut Providers) { - *p = Providers { normalize_projection_ty, ..*p }; + *p = Providers { normalize_projection_ty, normalize_inherent_projection_ty, ..*p }; } fn normalize_projection_ty<'tcx>( @@ -42,3 +42,30 @@ fn normalize_projection_ty<'tcx>( }, ) } + +fn normalize_inherent_projection_ty<'tcx>( + tcx: TyCtxt<'tcx>, + goal: CanonicalProjectionGoal<'tcx>, +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { + debug!("normalize_provider(goal={:#?})", goal); + + tcx.infer_ctxt().enter_canonical_trait_query( + &goal, + |ocx, ParamEnvAnd { param_env, value: goal }| { + let selcx = &mut SelectionContext::new(ocx.infcx); + let cause = ObligationCause::dummy(); + let mut obligations = vec![]; + let answer = traits::normalize_inherent_projection( + selcx, + param_env, + goal, + cause, + 0, + &mut obligations, + ); + ocx.register_obligations(obligations); + + Ok(NormalizationResult { normalized_ty: answer }) + }, + ) +} diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index e0fd487b3..9904acb1c 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -1,21 +1,19 @@ -use rustc_hir as hir; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; -use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; -use rustc_infer::traits::ObligationCauseCode; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::query::Providers; +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::DefiningAnchor; +use rustc_middle::ty::{FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{ParamEnvAnd, Predicate}; -use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType}; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; -use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType; +use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{ + type_op_ascribe_user_type_with_span, AscribeUserType, +}; use rustc_trait_selection::traits::query::type_op::eq::Eq; use rustc_trait_selection::traits::query::type_op::normalize::Normalize; use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate; use rustc_trait_selection::traits::query::type_op::subtype::Subtype; -use rustc_trait_selection::traits::query::{Fallible, NoSolution}; use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt}; use std::fmt; @@ -42,110 +40,6 @@ fn type_op_ascribe_user_type<'tcx>( }) } -/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors, -/// this query can be re-run to better track the span of the obligation cause, and improve the error -/// message. Do not call directly unless you're in that very specific context. -pub fn type_op_ascribe_user_type_with_span<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, - span: Option<Span>, -) -> Result<(), NoSolution> { - let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts(); - debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty); - let span = span.unwrap_or(DUMMY_SP); - match user_ty { - UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?, - UserType::TypeOf(def_id, user_substs) => { - relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)? - } - }; - Ok(()) -} - -#[instrument(level = "debug", skip(ocx, param_env, span))] -fn relate_mir_and_user_ty<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span, - mir_ty: Ty<'tcx>, - user_ty: Ty<'tcx>, -) -> Result<(), NoSolution> { - let cause = ObligationCause::dummy_with_span(span); - let user_ty = ocx.normalize(&cause, param_env, user_ty); - ocx.eq(&cause, param_env, mir_ty, user_ty)?; - - // FIXME(#104764): We should check well-formedness before normalization. - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into())); - ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); - Ok(()) -} - -#[instrument(level = "debug", skip(ocx, param_env, span))] -fn relate_mir_and_user_substs<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span, - mir_ty: Ty<'tcx>, - def_id: hir::def_id::DefId, - user_substs: UserSubsts<'tcx>, -) -> Result<(), NoSolution> { - let UserSubsts { user_self_ty, substs } = user_substs; - let tcx = ocx.infcx.tcx; - let cause = ObligationCause::dummy_with_span(span); - - let ty = tcx.type_of(def_id).subst(tcx, substs); - let ty = ocx.normalize(&cause, param_env, ty); - debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); - - ocx.eq(&cause, param_env, mir_ty, ty)?; - - // Prove the predicates coming along with `def_id`. - // - // Also, normalize the `instantiated_predicates` - // because otherwise we wind up with duplicate "type - // outlives" error messages. - let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); - - debug!(?instantiated_predicates); - for (instantiated_predicate, predicate_span) in instantiated_predicates { - let span = if span == DUMMY_SP { predicate_span } else { span }; - let cause = ObligationCause::new( - span, - CRATE_DEF_ID, - ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), - ); - let instantiated_predicate = - ocx.normalize(&cause.clone(), param_env, instantiated_predicate); - - ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); - } - - if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { - let self_ty = ocx.normalize(&cause, param_env, self_ty); - let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs); - let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); - - ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())); - ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); - } - - // In addition to proving the predicates, we have to - // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the substs being - // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `substs` directly because they - // haven't been normalized. - // - // FIXME(nmatsakis): Well, perhaps we should normalize - // them? This would only be relevant if some input - // type were ill-formed but did not appear in `ty`, - // which...could happen with normalization... - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())); - ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate)); - Ok(()) -} - fn type_op_eq<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, @@ -159,7 +53,7 @@ fn type_op_eq<'tcx>( fn type_op_normalize<'tcx, T>( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Normalize<T>>, -) -> Fallible<T> +) -> Result<T, NoSolution> where T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<'tcx>, { |