1
Fork 0

introduce enter_forall

This commit is contained in:
Boxy 2024-01-30 01:27:06 +00:00
parent af88f7db51
commit ac559af98f
15 changed files with 524 additions and 446 deletions

View file

@ -1032,10 +1032,10 @@ impl<'tcx> InferCtxt<'tcx> {
_ => {} _ => {}
} }
let ty::SubtypePredicate { a_is_expected, a, b } = // FIXME(tree_universes): leaking universes
self.instantiate_binder_with_placeholders(predicate); self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)) Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
})
} }
pub fn region_outlives_predicate( pub fn region_outlives_predicate(
@ -1043,10 +1043,13 @@ impl<'tcx> InferCtxt<'tcx> {
cause: &traits::ObligationCause<'tcx>, cause: &traits::ObligationCause<'tcx>,
predicate: ty::PolyRegionOutlivesPredicate<'tcx>, predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
) { ) {
let ty::OutlivesPredicate(r_a, r_b) = self.instantiate_binder_with_placeholders(predicate); // FIXME(tree_universes): leaking universes
let origin = self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| {
SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span)); let origin = SubregionOrigin::from_obligation_cause(cause, || {
RelateRegionParamBound(cause.span)
});
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
})
} }
/// Number of type variables created so far. /// Number of type variables created so far.
@ -1455,7 +1458,7 @@ impl<'tcx> InferCtxt<'tcx> {
// Use this method if you'd like to find some substitution of the binder's // Use this method if you'd like to find some substitution of the binder's
// variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`] // variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`]
// that corresponds to your use case, consider whether or not you should // that corresponds to your use case, consider whether or not you should
// use [`InferCtxt::instantiate_binder_with_placeholders`] instead. // use [`InferCtxt::enter_forall`] instead.
pub fn instantiate_binder_with_fresh_vars<T>( pub fn instantiate_binder_with_fresh_vars<T>(
&self, &self,
span: Span, span: Span,

View file

@ -38,24 +38,24 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
// First, we instantiate each bound region in the supertype with a // First, we instantiate each bound region in the supertype with a
// fresh placeholder region. Note that this automatically creates // fresh placeholder region. Note that this automatically creates
// a new universe if needed. // a new universe if needed.
let sup_prime = self.infcx.instantiate_binder_with_placeholders(sup); self.infcx.enter_forall(sup, |sup_prime| {
// Next, we instantiate each bound region in the subtype // Next, we instantiate each bound region in the subtype
// with a fresh region variable. These region variables -- // with a fresh region variable. These region variables --
// but no other preexisting region variables -- can name // but no other preexisting region variables -- can name
// the placeholders. // the placeholders.
let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub); let sub_prime =
self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub);
debug!("a_prime={:?}", sub_prime); debug!("a_prime={:?}", sub_prime);
debug!("b_prime={:?}", sup_prime); debug!("b_prime={:?}", sup_prime);
// Compare types now that bound regions have been replaced. // Compare types now that bound regions have been replaced.
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?; // FIXME(tree_universes): leaked dead universes
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime);
if result.is_ok() {
debug!("OK result={result:?}"); debug!("OK result={result:?}");
// NOTE: returning the result here would be dangerous as it contains }
// placeholders which **must not** be named afterwards. result.map(|_| ())
Ok(()) })
} }
} }
@ -106,6 +106,14 @@ impl<'tcx> InferCtxt<'tcx> {
self.tcx.replace_bound_vars_uncached(binder, delegate) self.tcx.replace_bound_vars_uncached(binder, delegate)
} }
pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U
where
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
{
let value = self.instantiate_binder_with_placeholders(forall);
f(value)
}
/// See [RegionConstraintCollector::leak_check][1]. We only check placeholder /// See [RegionConstraintCollector::leak_check][1]. We only check placeholder
/// leaking into `outer_universe`, i.e. placeholders which cannot be named by that /// leaking into `outer_universe`, i.e. placeholders which cannot be named by that
/// universe. /// universe.

View file

@ -309,6 +309,18 @@ where
replaced replaced
} }
fn enter_forall<T, U>(
&mut self,
binder: ty::Binder<'tcx, T>,
f: impl FnOnce(&mut Self, T) -> U,
) -> U
where
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
{
let value = self.instantiate_binder_with_placeholders(binder);
f(self, value)
}
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
where where
@ -630,10 +642,10 @@ where
// Note: the order here is important. Create the placeholders first, otherwise // Note: the order here is important. Create the placeholders first, otherwise
// we assign the wrong universe to the existential! // we assign the wrong universe to the existential!
let b_replaced = self.instantiate_binder_with_placeholders(b); self.enter_forall(b, |this, b| {
let a_replaced = self.instantiate_binder_with_existentials(a); let a = this.instantiate_binder_with_existentials(a);
this.relate(a, b)
self.relate(a_replaced, b_replaced)?; })?;
self.ambient_variance = variance; self.ambient_variance = variance;
} }
@ -650,10 +662,10 @@ where
let variance = let variance =
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
let a_replaced = self.instantiate_binder_with_placeholders(a); self.enter_forall(a, |this, a| {
let b_replaced = self.instantiate_binder_with_existentials(b); let b = this.instantiate_binder_with_existentials(b);
this.relate(a, b)
self.relate(a_replaced, b_replaced)?; })?;
self.ambient_variance = variance; self.ambient_variance = variance;
} }

View file

@ -77,13 +77,13 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
for (pred, pred_span) in for (pred, pred_span) in
cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied()
{ {
let predicate = infcx.instantiate_binder_with_placeholders(pred.kind()); infcx.enter_forall(pred.kind(), |predicate| {
let ty::ClauseKind::Projection(proj) = predicate else { let ty::ClauseKind::Projection(proj) = predicate else {
continue; return;
}; };
// Only check types, since those are the only things that may // Only check types, since those are the only things that may
// have opaques in them anyways. // have opaques in them anyways.
let Some(proj_term) = proj.term.ty() else { continue }; let Some(proj_term) = proj.term.ty() else { return };
// HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"... // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"...
if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind() if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind()
@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_)
) )
{ {
continue; return;
} }
// HACK: `async fn() -> Self` in traits is "ok"... // HACK: `async fn() -> Self` in traits is "ok"...
@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
&& matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_)) && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_))
&& opaque.in_trait && opaque.in_trait
{ {
continue; return;
} }
let proj_ty = let proj_ty =
@ -135,6 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
) else { ) else {
continue; continue;
}; };
// If that predicate doesn't hold modulo regions (but passed during type-check), // If that predicate doesn't hold modulo regions (but passed during type-check),
// then we must've taken advantage of the hack in `project_and_unify_types` where // then we must've taken advantage of the hack in `project_and_unify_types` where
// we replace opaques with inference vars. Emit a warning! // we replace opaques with inference vars. Emit a warning!
@ -156,6 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
}), }),
_ => None, _ => None,
}; };
cx.emit_span_lint( cx.emit_span_lint(
OPAQUE_HIDDEN_INFERRED_BOUND, OPAQUE_HIDDEN_INFERRED_BOUND,
pred_span, pred_span,
@ -172,6 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
); );
} }
} }
});
} }
} }
} }

View file

@ -1052,6 +1052,7 @@ impl<'tcx, T> Binder<'tcx, T> {
where where
T: TypeVisitable<TyCtxt<'tcx>>, T: TypeVisitable<TyCtxt<'tcx>>,
{ {
// `self.value` is equivalent to `self.skip_binder()`
if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
} }

View file

@ -20,7 +20,7 @@ use crate::solve::EvalCtxt;
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
ecx: &EvalCtxt<'_, 'tcx>, ecx: &EvalCtxt<'_, 'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Result<Vec<Ty<'tcx>>, NoSolution> { ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
let tcx = ecx.tcx(); let tcx = ecx.tcx();
match *ty.kind() { match *ty.kind() {
ty::Uint(_) ty::Uint(_)
@ -34,7 +34,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
| ty::Char => Ok(vec![]), | ty::Char => Ok(vec![]),
// Treat `str` like it's defined as `struct str([u8]);` // Treat `str` like it's defined as `struct str([u8]);`
ty::Str => Ok(vec![Ty::new_slice(tcx, tcx.types.u8)]), ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, tcx.types.u8))]),
ty::Dynamic(..) ty::Dynamic(..)
| ty::Param(..) | ty::Param(..)
@ -47,46 +47,46 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
} }
ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
Ok(vec![element_ty]) Ok(vec![ty::Binder::dummy(element_ty)])
} }
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![ty::Binder::dummy(element_ty)]),
ty::Tuple(tys) => { ty::Tuple(tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
Ok(tys.iter().collect()) Ok(tys.iter().map(ty::Binder::dummy).collect())
} }
ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]), ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
ty::CoroutineClosure(_, args) => Ok(vec![args.as_coroutine_closure().tupled_upvars_ty()]), ty::CoroutineClosure(_, args) => Ok(vec![args.as_coroutine_closure().tupled_upvars_ty()]),
ty::Coroutine(_, args) => { ty::Coroutine(_, args) => {
let coroutine_args = args.as_coroutine(); let coroutine_args = args.as_coroutine();
Ok(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()]) Ok(vec![
ty::Binder::dummy(coroutine_args.tupled_upvars_ty()),
ty::Binder::dummy(coroutine_args.witness()),
])
} }
ty::CoroutineWitness(def_id, args) => Ok(ecx ty::CoroutineWitness(def_id, args) => Ok(ecx
.tcx() .tcx()
.coroutine_hidden_types(def_id) .coroutine_hidden_types(def_id)
.map(|bty| { .map(|bty| replace_erased_lifetimes_with_bound_vars(tcx, bty.instantiate(tcx, args)))
ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars(
tcx,
bty.instantiate(tcx, args),
))
})
.collect()), .collect()),
// For `PhantomData<T>`, we pass `T`. // For `PhantomData<T>`, we pass `T`.
ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![args.type_at(0)]), ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]),
ty::Adt(def, args) => Ok(def.all_fields().map(|f| f.ty(tcx, args)).collect()), ty::Adt(def, args) => {
Ok(def.all_fields().map(|f| ty::Binder::dummy(f.ty(tcx, args))).collect())
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
// We can resolve the `impl Trait` to its concrete type, // We can resolve the `impl Trait` to its concrete type,
// which enforces a DAG between the functions requiring // which enforces a DAG between the functions requiring
// the auto trait bounds in question. // the auto trait bounds in question.
Ok(vec![tcx.type_of(def_id).instantiate(tcx, args)]) Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, args))])
} }
} }
} }
@ -116,7 +116,7 @@ pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>(
pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
ecx: &EvalCtxt<'_, 'tcx>, ecx: &EvalCtxt<'_, 'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Result<Vec<Ty<'tcx>>, NoSolution> { ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
match *ty.kind() { match *ty.kind() {
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Uint(_) | ty::Uint(_)
@ -150,11 +150,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
bug!("unexpected type `{ty}`") bug!("unexpected type `{ty}`")
} }
ty::Tuple(tys) => Ok(tys.to_vec()), ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()),
ty::Adt(def, args) => { ty::Adt(def, args) => {
let sized_crit = def.sized_constraint(ecx.tcx()); let sized_crit = def.sized_constraint(ecx.tcx());
Ok(sized_crit.iter_instantiated(ecx.tcx(), args).collect()) Ok(sized_crit.iter_instantiated(ecx.tcx(), args).map(ty::Binder::dummy).collect())
} }
} }
} }
@ -163,7 +163,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
ecx: &EvalCtxt<'_, 'tcx>, ecx: &EvalCtxt<'_, 'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Result<Vec<Ty<'tcx>>, NoSolution> { ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
match *ty.kind() { match *ty.kind() {
ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]), ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]),
@ -194,9 +194,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
bug!("unexpected type `{ty}`") bug!("unexpected type `{ty}`")
} }
ty::Tuple(tys) => Ok(tys.to_vec()), ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()),
ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]), ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
ty::CoroutineClosure(..) => Err(NoSolution), ty::CoroutineClosure(..) => Err(NoSolution),
@ -205,7 +205,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
Movability::Movable => { Movability::Movable => {
if ecx.tcx().features().coroutine_clone { if ecx.tcx().features().coroutine_clone {
let coroutine = args.as_coroutine(); let coroutine = args.as_coroutine();
Ok(vec![coroutine.tupled_upvars_ty(), coroutine.witness()]) Ok(vec![
ty::Binder::dummy(coroutine.tupled_upvars_ty()),
ty::Binder::dummy(coroutine.witness()),
])
} else { } else {
Err(NoSolution) Err(NoSolution)
} }
@ -216,10 +219,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
.tcx() .tcx()
.coroutine_hidden_types(def_id) .coroutine_hidden_types(def_id)
.map(|bty| { .map(|bty| {
ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars( replace_erased_lifetimes_with_bound_vars(
ecx.tcx(), ecx.tcx(),
bty.instantiate(ecx.tcx(), args), bty.instantiate(ecx.tcx(), args),
)) )
}) })
.collect()), .collect()),
} }

View file

@ -477,10 +477,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
} }
} }
} else { } else {
let kind = self.infcx.instantiate_binder_with_placeholders(kind); self.infcx.enter_forall(kind, |kind| {
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
self.add_goal(GoalSource::Misc, goal); self.add_goal(GoalSource::Misc, goal);
// FIXME(tree_universes): leaking universes
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
} }
} }
@ -801,13 +803,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) )
} }
pub(super) fn instantiate_binder_with_placeholders<T: TypeFoldable<TyCtxt<'tcx>> + Copy>( pub(super) fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
&self, &self,
value: ty::Binder<'tcx, T>, value: ty::Binder<'tcx, T>,
) -> T { f: impl FnOnce(T) -> U,
self.infcx.instantiate_binder_with_placeholders(value) ) -> U {
self.infcx.enter_forall(value, f)
} }
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
where where
T: TypeFoldable<TyCtxt<'tcx>>, T: TypeFoldable<TyCtxt<'tcx>>,

View file

@ -31,11 +31,9 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
) -> SelectionResult<'tcx, Selection<'tcx>> { ) -> SelectionResult<'tcx, Selection<'tcx>> {
assert!(self.next_trait_solver()); assert!(self.next_trait_solver());
let trait_goal = Goal::new( // FIXME(tree_universes): leaking universes?
self.tcx, self.enter_forall(obligation.predicate, |pred| {
obligation.param_env, let trait_goal = Goal::new(self.tcx, obligation.param_env, pred);
self.instantiate_binder_with_placeholders(obligation.predicate),
);
let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::Never, |ecx| { let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::Never, |ecx| {
let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate); let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate);
@ -79,7 +77,9 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
}); });
let (candidate, certainty, nested_goals) = match result { let (candidate, certainty, nested_goals) = match result {
Ok(Some((candidate, certainty, nested_goals))) => (candidate, certainty, nested_goals), Ok(Some((candidate, certainty, nested_goals))) => {
(candidate, certainty, nested_goals)
}
Ok(None) => return Ok(None), Ok(None) => return Ok(None),
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
@ -87,7 +87,12 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
let nested_obligations: Vec<_> = nested_goals let nested_obligations: Vec<_> = nested_goals
.into_iter() .into_iter()
.map(|goal| { .map(|goal| {
Obligation::new(self.tcx, ObligationCause::dummy(), goal.param_env, goal.predicate) Obligation::new(
self.tcx,
ObligationCause::dummy(),
goal.param_env,
goal.predicate,
)
}) })
.collect(); .collect();
@ -128,6 +133,7 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
(Certainty::Maybe(_), _) => Ok(None), (Certainty::Maybe(_), _) => Ok(None),
} }
})
} }
} }

View file

@ -1049,14 +1049,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
fn probe_and_evaluate_goal_for_constituent_tys( fn probe_and_evaluate_goal_for_constituent_tys(
&mut self, &mut self,
goal: Goal<'tcx, TraitPredicate<'tcx>>, goal: Goal<'tcx, TraitPredicate<'tcx>>,
constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>, constituent_tys: impl Fn(
&EvalCtxt<'_, 'tcx>,
Ty<'tcx>,
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>,
) -> QueryResult<'tcx> { ) -> QueryResult<'tcx> {
self.probe_misc_candidate("constituent tys").enter(|ecx| { self.probe_misc_candidate("constituent tys").enter(|ecx| {
ecx.add_goals( ecx.add_goals(
GoalSource::ImplWhereBound, GoalSource::ImplWhereBound,
constituent_tys(ecx, goal.predicate.self_ty())? constituent_tys(ecx, goal.predicate.self_ty())?
.into_iter() .into_iter()
.map(|ty| goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty))) .map(|ty| {
// FIXME(tree_universes): leaking universes
ecx.enter_forall(ty, |ty| {
goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty))
})
})
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); );
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)

View file

@ -971,7 +971,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
let Goal { param_env, predicate } = goal.goal(); let Goal { param_env, predicate } = goal.goal();
// For bound predicates we simply call `infcx.instantiate_binder_with_placeholders` // For bound predicates we simply call `infcx.enter_forall`
// and then prove the resulting predicate as a nested goal. // and then prove the resulting predicate as a nested goal.
let trait_ref = match predicate.kind().no_bound_vars() { let trait_ref = match predicate.kind().no_bound_vars() {
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref, Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,

View file

@ -21,14 +21,18 @@ pub fn recompute_applicable_impls<'tcx>(
let impl_may_apply = |impl_def_id| { let impl_may_apply = |impl_def_id| {
let ocx = ObligationCtxt::new(infcx); let ocx = ObligationCtxt::new(infcx);
let placeholder_obligation = infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
infcx.instantiate_binder_with_placeholders(obligation.predicate); let obligation_trait_ref = ocx.normalize(
let obligation_trait_ref = &ObligationCause::dummy(),
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); param_env,
placeholder_obligation.trait_ref,
);
let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args); let impl_trait_ref =
let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref); tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args);
let impl_trait_ref =
ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
if let Err(_) = if let Err(_) =
ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref) ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
@ -42,14 +46,17 @@ pub fn recompute_applicable_impls<'tcx>(
})); }));
ocx.select_where_possible().is_empty() ocx.select_where_possible().is_empty()
})
}; };
let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| { let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
let ocx = ObligationCtxt::new(infcx); let ocx = ObligationCtxt::new(infcx);
let placeholder_obligation = infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
infcx.instantiate_binder_with_placeholders(obligation.predicate); let obligation_trait_ref = ocx.normalize(
let obligation_trait_ref = &ObligationCause::dummy(),
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); param_env,
placeholder_obligation.trait_ref,
);
let param_env_predicate = infcx.instantiate_binder_with_fresh_vars( let param_env_predicate = infcx.instantiate_binder_with_fresh_vars(
DUMMY_SP, DUMMY_SP,
@ -59,13 +66,17 @@ pub fn recompute_applicable_impls<'tcx>(
let param_env_trait_ref = let param_env_trait_ref =
ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref); ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref);
if let Err(_) = if let Err(_) = ocx.eq(
ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, param_env_trait_ref) &ObligationCause::dummy(),
{ param_env,
obligation_trait_ref,
param_env_trait_ref,
) {
return false; return false;
} }
ocx.select_where_possible().is_empty() ocx.select_where_possible().is_empty()
})
}; };
let mut ambiguities = Vec::new(); let mut ambiguities = Vec::new();

View file

@ -64,7 +64,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) -> Option<(DefId, GenericArgsRef<'tcx>)> { ) -> Option<(DefId, GenericArgsRef<'tcx>)> {
let tcx = self.tcx; let tcx = self.tcx;
let param_env = obligation.param_env; let param_env = obligation.param_env;
let trait_ref = self.instantiate_binder_with_placeholders(trait_ref); self.enter_forall(trait_ref, |trait_ref| {
let trait_self_ty = trait_ref.self_ty(); let trait_self_ty = trait_ref.self_ty();
let mut self_match_impls = vec![]; let mut self_match_impls = vec![];
@ -72,14 +72,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| { self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id); let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id);
let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args); let impl_trait_ref =
tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args);
let impl_self_ty = impl_trait_ref.self_ty(); let impl_self_ty = impl_trait_ref.self_ty();
if 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_args)); self_match_impls.push((def_id, impl_args));
if iter::zip(trait_ref.args.types().skip(1), impl_trait_ref.args.types().skip(1)) if iter::zip(
trait_ref.args.types().skip(1),
impl_trait_ref.args.types().skip(1),
)
.all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some()) .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
{ {
fuzzy_match_impls.push((def_id, impl_args)); fuzzy_match_impls.push((def_id, impl_args));
@ -97,6 +101,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
tcx.has_attr(impl_def_id_and_args.0, sym::rustc_on_unimplemented) tcx.has_attr(impl_def_id_and_args.0, sym::rustc_on_unimplemented)
.then_some(impl_def_id_and_args) .then_some(impl_def_id_and_args)
})
} }
/// Used to set on_unimplemented's `ItemContext` /// Used to set on_unimplemented's `ItemContext`

View file

@ -1248,7 +1248,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
trait_pred: ty::PolyTraitPredicate<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool { ) -> bool {
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
let ty = self.instantiate_binder_with_placeholders(self_ty); self.enter_forall(self_ty, |ty: Ty<'_>| {
let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else {
return false; return false;
}; };
@ -1260,7 +1260,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return false; return false;
}; };
let arg_node = self.tcx.hir_node(*arg_hir_id); let arg_node = self.tcx.hir_node(*arg_hir_id);
let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else { return false }; let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else {
return false;
};
let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None); let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None);
let has_clone = |ty| { let has_clone = |ty| {
@ -1288,12 +1290,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_suggestion_verbose( err.span_suggestion_verbose(
obligation.cause.span.shrink_to_hi(), obligation.cause.span.shrink_to_hi(),
"consider using clone here", "consider using clone here",
".clone()", ".clone()".to_string(),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
return true; return true;
} }
false false
})
} }
/// Extracts information about a callable type for diagnostics. This is a /// Extracts information about a callable type for diagnostics. This is a
@ -4038,26 +4041,27 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let Some(where_pred) = where_pred.as_trait_clause() if let Some(where_pred) = where_pred.as_trait_clause()
&& let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred() && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
{ {
let where_pred = self.instantiate_binder_with_placeholders(where_pred); self.enter_forall(where_pred, |where_pred| {
let failed_pred = self.instantiate_binder_with_fresh_vars( let failed_pred = self.instantiate_binder_with_fresh_vars(
expr.span, expr.span,
BoundRegionConversionTime::FnCall, BoundRegionConversionTime::FnCall,
failed_pred, failed_pred,
); );
let zipped = iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args); let zipped =
iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args);
for (expected, actual) in zipped { for (expected, actual) in zipped {
self.probe(|_| { self.probe(|_| {
match self.at(&ObligationCause::misc(expr.span, body_id), param_env).eq( match self
DefineOpaqueTypes::No, .at(&ObligationCause::misc(expr.span, body_id), param_env)
expected, .eq(DefineOpaqueTypes::No, expected, actual)
actual, {
) {
Ok(_) => (), // We ignore nested obligations here for now. Ok(_) => (), // We ignore nested obligations here for now.
Err(err) => type_diffs.push(err), Err(err) => type_diffs.push(err),
} }
}) })
} }
})
} else if let Some(where_pred) = where_pred.as_projection_clause() } else if let Some(where_pred) = where_pred.as_projection_clause()
&& let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred() && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
&& let Some(found) = failed_pred.skip_binder().term.ty() && let Some(found) = failed_pred.skip_binder().term.ty()
@ -4615,14 +4619,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{ {
self.probe(|_| { self.probe(|_| {
let ocx = ObligationCtxt::new(self); let ocx = ObligationCtxt::new(self);
let pred = self.instantiate_binder_with_placeholders(pred); self.enter_forall(pred, |pred| {
let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred); let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred);
// FIXME(tree_universes): universe leakage
ocx.register_obligation(Obligation::new( ocx.register_obligation(Obligation::new(
self.tcx, self.tcx,
ObligationCause::dummy(), ObligationCause::dummy(),
param_env, param_env,
pred, pred,
)); ));
});
if !ocx.select_where_possible().is_empty() { if !ocx.select_where_possible().is_empty() {
// encountered errors. // encountered errors.
return; return;
@ -4769,13 +4775,13 @@ fn hint_missing_borrow<'tcx>(
} }
let found_args = match found.kind() { let found_args = match found.kind() {
ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(), ty::FnPtr(f) => infcx.enter_forall(*f, |f| f.inputs().iter()),
kind => { kind => {
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind) span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
} }
}; };
let expected_args = match expected.kind() { let expected_args = match expected.kind() {
ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(), ty::FnPtr(f) => infcx.enter_forall(*f, |f| f.inputs().iter()),
kind => { kind => {
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
} }

View file

@ -1307,12 +1307,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut pred = obligation.predicate.to_opt_poly_trait_pred(); let mut pred = obligation.predicate.to_opt_poly_trait_pred();
while let Some((next_code, next_pred)) = code.parent() { while let Some((next_code, next_pred)) = code.parent() {
if let Some(pred) = pred { if let Some(pred) = pred {
let pred = self.instantiate_binder_with_placeholders(pred); self.enter_forall(pred, |pred| {
diag.note(format!( diag.note(format!(
"`{}` must implement `{}`, but it does not", "`{}` must implement `{}`, but it does not",
pred.self_ty(), pred.self_ty(),
pred.print_modifiers_and_trait_path() pred.print_modifiers_and_trait_path()
)); ));
})
} }
code = next_code; code = next_code;
pred = next_pred; pred = next_pred;
@ -2017,7 +2018,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let [single] = &impl_candidates { if let [single] = &impl_candidates {
if self.probe(|_| { if self.probe(|_| {
let ocx = ObligationCtxt::new(self); let ocx = ObligationCtxt::new(self);
let obligation_trait_ref = self.instantiate_binder_with_placeholders(trait_ref);
self.enter_forall(trait_ref, |obligation_trait_ref| {
let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id); let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id);
let impl_trait_ref = ocx.normalize( let impl_trait_ref = ocx.normalize(
&ObligationCause::dummy(), &ObligationCause::dummy(),
@ -2031,7 +2033,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.instantiate(self.tcx, impl_args) .instantiate(self.tcx, impl_args)
.into_iter() .into_iter()
.map(|(clause, _)| { .map(|(clause, _)| {
Obligation::new(self.tcx, ObligationCause::dummy(), param_env, clause) Obligation::new(
self.tcx,
ObligationCause::dummy(),
param_env,
clause,
)
}), }),
); );
if !ocx.select_where_possible().is_empty() { if !ocx.select_where_possible().is_empty() {
@ -2042,6 +2049,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
for (obligation_arg, impl_arg) in for (obligation_arg, impl_arg) in
std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args) std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
{ {
// FIXME(tree_universes): universe leakage
if let Err(terr) = if let Err(terr) =
ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg) ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg)
{ {
@ -2057,13 +2065,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return false; return false;
} }
let cand = let cand = self.resolve_vars_if_possible(impl_trait_ref).fold_with(
self.resolve_vars_if_possible(impl_trait_ref).fold_with(&mut BottomUpFolder { &mut BottomUpFolder {
tcx: self.tcx, tcx: self.tcx,
ty_op: |ty| ty, ty_op: |ty| ty,
lt_op: |lt| lt, lt_op: |lt| lt,
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
}); },
);
err.highlighted_help(vec![ err.highlighted_help(vec![
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())), StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
StringPart::highlighted("is"), StringPart::highlighted("is"),
@ -2081,6 +2090,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} }
true true
})
}) { }) {
return true; return true;
} }

View file

@ -164,7 +164,7 @@ pub enum RegionKind<I: Interner> {
/// Should not exist outside of type inference. /// Should not exist outside of type inference.
/// ///
/// Used when instantiating a `forall` binder via /// Used when instantiating a `forall` binder via
/// `infcx.instantiate_binder_with_placeholders`. /// `infcx.enter_forall` and `infcx.instantiate_binder_with_placeholders`.
RePlaceholder(I::PlaceholderRegion), RePlaceholder(I::PlaceholderRegion),
/// Erased region, used by trait selection, in MIR and during codegen. /// Erased region, used by trait selection, in MIR and during codegen.