summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_traits
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_traits')
-rw-r--r--compiler/rustc_traits/Cargo.toml1
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs19
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs31
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs2
-rw-r--r--compiler/rustc_traits/src/codegen.rs4
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs268
-rw-r--r--compiler/rustc_traits/src/evaluate_obligation.rs6
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs173
-rw-r--r--compiler/rustc_traits/src/lib.rs5
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs4
-rw-r--r--compiler/rustc_traits/src/normalize_projection_ty.rs31
-rw-r--r--compiler/rustc_traits/src/type_op.rs124
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>,
{