Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
reviews + rebase
  • Loading branch information
BoxyUwU committed Feb 8, 2024
commit f867742be8a19ca253b0d7d1c9a4ab54b7ff02c5
2 changes: 0 additions & 2 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,6 @@ impl<'tcx> InferCtxt<'tcx> {
_ => {}
}

// FIXME(tree_universes): leaking placeholders
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))
})
Expand All @@ -1043,7 +1042,6 @@ impl<'tcx> InferCtxt<'tcx> {
cause: &traits::ObligationCause<'tcx>,
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
) {
// FIXME(tree_universes): leaking placeholders
self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| {
let origin = SubregionOrigin::from_obligation_cause(cause, || {
RelateRegionParamBound(cause.span)
Expand Down
15 changes: 9 additions & 6 deletions compiler/rustc_infer/src/infer/relate/higher_ranked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
debug!("b_prime={:?}", sup_prime);

// Compare types now that bound regions have been replaced.
// FIXME(tree_universes): leaked universes
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime);
if result.is_ok() {
debug!("OK result={result:?}");
Expand All @@ -70,7 +69,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// This is the first step of checking subtyping when higher-ranked things are involved.
/// For more details visit the relevant sections of the [rustc dev guide].
///
/// `enter_forall` should be preferred over this method.
/// `fn enter_forall` should be preferred over this method.
///
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
#[instrument(level = "debug", skip(self), ret)]
Expand Down Expand Up @@ -111,21 +110,25 @@ impl<'tcx> InferCtxt<'tcx> {
}

/// Replaces all bound variables (lifetimes, types, and constants) bound by
/// `binder` with placeholder variables in a new universe. This means that the
/// new placeholders can only be named by inference variables created after
/// this method has been called.
/// `binder` with placeholder variables in a new universe and then calls the
/// closure `f` with the instantiated value. The new placeholders can only be
/// named by inference variables created inside of the closure `f` or afterwards.
///
/// This is the first step of checking subtyping when higher-ranked things are involved.
/// For more details visit the relevant sections of the [rustc dev guide].
///
/// This method should be preferred over `enter_forall_and_leak_universe`.
/// This method should be preferred over `fn enter_forall_and_leak_universe`.
///
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
#[instrument(level = "debug", skip(self, f))]
pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U
where
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
{
// FIXME: currently we do nothing to prevent placeholders with the new universe being
// used after exiting `f`. For example region subtyping can result in outlives constraints
// that name placeholders created in this function. Nested goals from type relations can
// also contain placeholders created by this function.
let value = self.enter_forall_and_leak_universe(forall);
debug!("?value");
f(value)
Expand Down
89 changes: 40 additions & 49 deletions compiler/rustc_infer/src/infer/relate/nll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,54 +261,6 @@ where
Ok(a)
}

#[instrument(skip(self), level = "debug")]
fn enter_forall_and_leak_universe<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
where
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
{
if let Some(inner) = binder.no_bound_vars() {
return inner;
}

let mut next_region = {
let nll_delegate = &mut self.delegate;
let mut lazy_universe = None;

move |br: ty::BoundRegion| {
// The first time this closure is called, create a
// new universe for the placeholders we will make
// from here out.
let universe = lazy_universe.unwrap_or_else(|| {
let universe = nll_delegate.create_next_universe();
lazy_universe = Some(universe);
universe
});

let placeholder = ty::PlaceholderRegion { universe, bound: br };
debug!(?placeholder);
let placeholder_reg = nll_delegate.next_placeholder_region(placeholder);
debug!(?placeholder_reg);

placeholder_reg
}
};

let delegate = FnMutDelegate {
regions: &mut next_region,
types: &mut |_bound_ty: ty::BoundTy| {
unreachable!("we only replace regions in nll_relate, not types")
},
consts: &mut |_bound_var: ty::BoundVar, _ty| {
unreachable!("we only replace regions in nll_relate, not consts")
},
};

let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
debug!(?replaced);

replaced
}

fn enter_forall<T, U>(
&mut self,
binder: ty::Binder<'tcx, T>,
Expand All @@ -317,7 +269,46 @@ where
where
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
{
let value = self.enter_forall_and_leak_universe(binder);
let value = if let Some(inner) = binder.no_bound_vars() {
inner
} else {
let mut next_region = {
let nll_delegate = &mut self.delegate;
let mut lazy_universe = None;

move |br: ty::BoundRegion| {
// The first time this closure is called, create a
// new universe for the placeholders we will make
// from here out.
let universe = lazy_universe.unwrap_or_else(|| {
let universe = nll_delegate.create_next_universe();
lazy_universe = Some(universe);
universe
});

let placeholder = ty::PlaceholderRegion { universe, bound: br };
debug!(?placeholder);
let placeholder_reg = nll_delegate.next_placeholder_region(placeholder);
debug!(?placeholder_reg);

placeholder_reg
}
};

let delegate = FnMutDelegate {
regions: &mut next_region,
types: &mut |_bound_ty: ty::BoundTy| {
unreachable!("we only replace regions in nll_relate, not types")
},
consts: &mut |_bound_var: ty::BoundVar, _ty| {
unreachable!("we only replace regions in nll_relate, not consts")
},
};

self.infcx.tcx.replace_bound_vars_uncached(binder, delegate)
};

debug!(?value);
f(self, value)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(

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![ty::Binder::dummy(args.as_coroutine_closure().tupled_upvars_ty())])
}

ty::Coroutine(_, args) => {
let coroutine_args = args.as_coroutine();
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
self.infcx.enter_forall(kind, |kind| {
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
self.add_goal(GoalSource::Misc, goal);
// FIXME(tree_universes): leaking universes
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
) -> SelectionResult<'tcx, Selection<'tcx>> {
assert!(self.next_trait_solver());

// FIXME(tree_universes): leaking universes?
self.enter_forall(obligation.predicate, |pred| {
let trait_goal = Goal::new(self.tcx, obligation.param_env, pred);

Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_trait_selection/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
constituent_tys(ecx, goal.predicate.self_ty())?
.into_iter()
.map(|ty| {
// FIXME(tree_universes): leaking universes
ecx.enter_forall(ty, |ty| {
goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty))
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4621,7 +4621,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let ocx = ObligationCtxt::new(self);
self.enter_forall(pred, |pred| {
let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred);
// FIXME(tree_universes): universe leakage
ocx.register_obligation(Obligation::new(
self.tcx,
ObligationCause::dummy(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2049,7 +2049,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
for (obligation_arg, impl_arg) in
std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
{
// FIXME(tree_universes): universe leakage
if let Err(terr) =
ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -728,64 +728,63 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

self.infcx.probe(|_snapshot| {
let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
let placeholder_trait_predicate =
self.infcx.enter_forall_and_leak_universe(poly_trait_predicate);

let self_ty = placeholder_trait_predicate.self_ty();
let principal_trait_ref = match self_ty.kind() {
ty::Dynamic(data, ..) => {
if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
debug!(
"assemble_candidates_from_object_ty: matched builtin bound, \
self.infcx.enter_forall(poly_trait_predicate, |placeholder_trait_predicate| {
let self_ty = placeholder_trait_predicate.self_ty();
let principal_trait_ref = match self_ty.kind() {
ty::Dynamic(data, ..) => {
if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
debug!(
"assemble_candidates_from_object_ty: matched builtin bound, \
pushing candidate"
);
candidates.vec.push(BuiltinObjectCandidate);
return;
}
);
candidates.vec.push(BuiltinObjectCandidate);
return;
}

if let Some(principal) = data.principal() {
if !self.infcx.tcx.features().object_safe_for_dispatch {
principal.with_self_ty(self.tcx(), self_ty)
} else if self.tcx().check_is_object_safe(principal.def_id()) {
principal.with_self_ty(self.tcx(), self_ty)
if let Some(principal) = data.principal() {
if !self.infcx.tcx.features().object_safe_for_dispatch {
principal.with_self_ty(self.tcx(), self_ty)
} else if self.tcx().check_is_object_safe(principal.def_id()) {
principal.with_self_ty(self.tcx(), self_ty)
} else {
return;
}
} else {
// Only auto trait bounds exist.
return;
}
} else {
// Only auto trait bounds exist.
}
ty::Infer(ty::TyVar(_)) => {
debug!("assemble_candidates_from_object_ty: ambiguous");
candidates.ambiguous = true; // could wind up being an object type
return;
}
}
ty::Infer(ty::TyVar(_)) => {
debug!("assemble_candidates_from_object_ty: ambiguous");
candidates.ambiguous = true; // could wind up being an object type
return;
}
_ => return,
};

debug!(?principal_trait_ref, "assemble_candidates_from_object_ty");

// Count only those upcast versions that match the trait-ref
// we are looking for. Specifically, do not only check for the
// correct trait, but also the correct type parameters.
// For example, we may be trying to upcast `Foo` to `Bar<i32>`,
// but `Foo` is declared as `trait Foo: Bar<u32>`.
let candidate_supertraits = util::supertraits(self.tcx(), principal_trait_ref)
.enumerate()
.filter(|&(_, upcast_trait_ref)| {
self.infcx.probe(|_| {
self.match_normalize_trait_ref(
obligation,
upcast_trait_ref,
placeholder_trait_predicate.trait_ref,
)
.is_ok()
_ => return,
};

debug!(?principal_trait_ref, "assemble_candidates_from_object_ty");

// Count only those upcast versions that match the trait-ref
// we are looking for. Specifically, do not only check for the
// correct trait, but also the correct type parameters.
// For example, we may be trying to upcast `Foo` to `Bar<i32>`,
// but `Foo` is declared as `trait Foo: Bar<u32>`.
let candidate_supertraits = util::supertraits(self.tcx(), principal_trait_ref)
.enumerate()
.filter(|&(_, upcast_trait_ref)| {
self.infcx.probe(|_| {
self.match_normalize_trait_ref(
obligation,
upcast_trait_ref,
placeholder_trait_predicate.trait_ref,
)
.is_ok()
})
})
})
.map(|(idx, _)| ObjectCandidate(idx));
.map(|(idx, _)| ObjectCandidate(idx));

candidates.vec.extend(candidate_supertraits);
candidates.vec.extend(candidate_supertraits);
})
})
}

Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_type_ir/src/region_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,7 @@ pub enum RegionKind<I: Interner> {
/// A placeholder region -- the higher-ranked version of `ReLateParam`.
/// Should not exist outside of type inference.
///
/// Used when instantiating a `forall` binder via
/// `infcx.enter_forall` and `infcx.enter_forall_and_leak_universe`.
/// Used when instantiating a `forall` binder via `infcx.enter_forall`.
RePlaceholder(I::PlaceholderRegion),

/// Erased region, used by trait selection, in MIR and during codegen.
Expand Down