yeet GeneralizerDelegate

This commit is contained in:
lcnr 2024-02-17 02:32:53 +01:00
parent 5c540044d6
commit 54b3c8759a

View File

@ -1,6 +1,5 @@
use std::mem;
use crate::infer::nll_relate::TypeRelatingDelegate;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind, TypeVariableValue};
use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin};
use rustc_data_structures::sso::SsoHashMap;
@ -43,13 +42,7 @@ pub(super) fn instantiate_ty_var<R: ObligationEmittingRelation<'tcx>>(
//
// We then relate `generalized_ty <: source_ty`,adding constraints like `'x: '?2` and `?1 <: ?3`.
let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } =
generalize(
self,
&mut CombineDelegate { infcx: self, span: relation.span() },
source_ty,
target_vid,
ambient_variance,
)?;
self.generalize(relation.span(), target_vid, ambient_variance, source_ty)?;
// Constrain `b_vid` to the generalized type `generalized_ty`.
if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
@ -180,13 +173,7 @@ pub(super) fn instantiate_const_var(
// FIXME(generic_const_exprs): Occurs check failures for unevaluated
// constants and generic expressions are not yet handled correctly.
let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } =
generalize(
self,
&mut CombineDelegate { infcx: self, span },
source_ct,
target_vid,
ty::Variance::Invariant,
)?;
self.generalize(span, target_vid, ty::Variance::Invariant, source_ct)?;
debug_assert!(!generalized_ct.is_ct_infer());
if has_unconstrained_ty_var {
@ -199,96 +186,48 @@ pub(super) fn instantiate_const_var(
.union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
// FIXME(generic_const_exprs): We have to make sure we actually equate
// `generalized_ct` and `source_ct` here.`
// `generalized_ct` and `source_ct` here.
Ok(generalized_ct)
}
}
/// Attempts to generalize `term` for the type variable `for_vid`.
/// This checks for cycles -- that is, whether the type `term`
/// references `for_vid`.
pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Relate<'tcx>>(
infcx: &InferCtxt<'tcx>,
delegate: &mut D,
term: T,
for_vid: impl Into<ty::TermVid>,
/// Attempts to generalize `source_term` for the type variable `target_vid`.
/// This checks for cycles -- that is, whether `source_term` references `target_vid`.
fn generalize<T: Into<Term<'tcx>> + Relate<'tcx>>(
&self,
span: Span,
target_vid: impl Into<ty::TermVid>,
ambient_variance: ty::Variance,
) -> RelateResult<'tcx, Generalization<T>> {
let (for_universe, root_vid) = match for_vid.into() {
source_term: T,
) -> RelateResult<'tcx, Generalization<T>> {
assert!(!source_term.has_escaping_bound_vars());
let (for_universe, root_vid) = match target_vid.into() {
ty::TermVid::Ty(ty_vid) => (
infcx.probe_ty_var(ty_vid).unwrap_err(),
ty::TermVid::Ty(infcx.inner.borrow_mut().type_variables().sub_root_var(ty_vid)),
self.probe_ty_var(ty_vid).unwrap_err(),
ty::TermVid::Ty(self.inner.borrow_mut().type_variables().sub_root_var(ty_vid)),
),
ty::TermVid::Const(ct_vid) => (
infcx.probe_const_var(ct_vid).unwrap_err(),
ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid).vid),
self.probe_const_var(ct_vid).unwrap_err(),
ty::TermVid::Const(
self.inner.borrow_mut().const_unification_table().find(ct_vid).vid,
),
),
};
let mut generalizer = Generalizer {
infcx,
delegate,
ambient_variance,
infcx: self,
span,
root_vid,
for_universe,
root_term: term.into(),
ambient_variance,
root_term: source_term.into(),
in_alias: false,
has_unconstrained_ty_var: false,
cache: Default::default(),
};
assert!(!term.has_escaping_bound_vars());
let value_may_be_infer = generalizer.relate(term, term)?;
let value_may_be_infer = generalizer.relate(source_term, source_term)?;
let has_unconstrained_ty_var = generalizer.has_unconstrained_ty_var;
Ok(Generalization { value_may_be_infer, has_unconstrained_ty_var })
}
/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking
/// in the generalizer code.
pub trait GeneralizerDelegate<'tcx> {
fn forbid_inference_vars() -> bool;
fn span(&self) -> Span;
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
}
pub struct CombineDelegate<'cx, 'tcx> {
pub infcx: &'cx InferCtxt<'tcx>,
pub span: Span,
}
impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> {
fn forbid_inference_vars() -> bool {
false
}
fn span(&self) -> Span {
self.span
}
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
// FIXME: This is non-ideal because we don't give a
// very descriptive origin for this region variable.
self.infcx
.next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe)
}
}
impl<'tcx, T> GeneralizerDelegate<'tcx> for T
where
T: TypeRelatingDelegate<'tcx>,
{
fn forbid_inference_vars() -> bool {
<Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars()
}
fn span(&self) -> Span {
<Self as TypeRelatingDelegate<'tcx>>::span(&self)
}
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
<Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe)
}
}
@ -305,18 +244,10 @@ fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>
/// establishes `'0: 'x` as a constraint.
///
/// [blog post]: https://is.gd/0hKvIr
struct Generalizer<'me, 'tcx, D> {
struct Generalizer<'me, 'tcx> {
infcx: &'me InferCtxt<'tcx>,
/// This is used to abstract the behaviors of the three previous
/// generalizer-like implementations (`Generalizer`, `TypeGeneralizer`,
/// and `ConstInferUnifier`). See [`GeneralizerDelegate`] for more
/// information.
delegate: &'me mut D,
/// After we generalize this type, we are going to relate it to
/// some other type. What will be the variance at this point?
ambient_variance: ty::Variance,
span: Span,
/// The vid of the type variable that is in the process of being
/// instantiated. If we find this within the value we are folding,
@ -328,6 +259,10 @@ struct Generalizer<'me, 'tcx, D> {
/// we reject the relation.
for_universe: ty::UniverseIndex,
/// After we generalize this type, we are going to relate it to
/// some other type. What will be the variance at this point?
ambient_variance: ty::Variance,
/// The root term (const or type) we're generalizing. Used for cycle errors.
root_term: Term<'tcx>,
@ -344,7 +279,7 @@ struct Generalizer<'me, 'tcx, D> {
has_unconstrained_ty_var: bool,
}
impl<'tcx, D> Generalizer<'_, 'tcx, D> {
impl<'tcx> Generalizer<'_, 'tcx> {
/// Create an error that corresponds to the term kind in `root_term`
fn cyclic_term_error(&self) -> TypeError<'tcx> {
match self.root_term.unpack() {
@ -354,10 +289,7 @@ fn cyclic_term_error(&self) -> TypeError<'tcx> {
}
}
impl<'tcx, D> TypeRelation<'tcx> for Generalizer<'_, 'tcx, D>
where
D: GeneralizerDelegate<'tcx>,
{
impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
@ -426,12 +358,6 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
// subtyping. This is basically our "occurs check", preventing
// us from creating infinitely sized types.
let g = match *t.kind() {
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_))
if D::forbid_inference_vars() =>
{
bug!("unexpected inference variable encountered in NLL generalization: {t}");
}
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("unexpected infer type: {t}")
}
@ -534,7 +460,7 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
Ok(self.infcx.next_ty_var_in_universe(
TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: self.delegate.span(),
span: self.span,
},
self.for_universe,
))
@ -592,7 +518,10 @@ fn regions(
}
}
Ok(self.delegate.generalize_region(self.for_universe))
Ok(self.infcx.next_region_var_in_universe(
RegionVariableOrigin::MiscVariable(self.span),
self.for_universe,
))
}
#[instrument(level = "debug", skip(self, c2), ret)]
@ -604,9 +533,6 @@ fn consts(
assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
match c.kind() {
ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
bug!("unexpected inference variable encountered in NLL generalization: {:?}", c);
}
ty::ConstKind::Infer(InferConst::Var(vid)) => {
// If root const vids are equal, then `root_vid` and
// `vid` are related and we'd be inferring an infinitely