Rework var resolution in InferCtxtLike, uplift EagerResolver

This commit is contained in:
Michael Goulet 2024-05-19 13:04:44 -04:00
parent 569fb43aa0
commit b0f1afd1fc
12 changed files with 204 additions and 165 deletions

View File

@ -369,34 +369,44 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
}
}
fn root_ty_var(&self, vid: TyVid) -> TyVid {
self.root_var(vid)
}
fn probe_ty_var(&self, vid: TyVid) -> Option<Ty<'tcx>> {
self.probe_ty_var(vid).ok()
}
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
let re = self
.inner
.borrow_mut()
.unwrap_region_constraints()
.opportunistic_resolve_var(self.tcx, vid);
if *re == ty::ReVar(vid) { None } else { Some(re) }
}
fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
self.root_const_var(vid)
}
fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> {
self.probe_const_var(vid).ok()
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
}
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
self.defining_opaque_types
}
fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> {
match self.probe_ty_var(vid) {
Ok(ty) => ty,
Err(_) => Ty::new_var(self.tcx, self.root_var(vid)),
}
}
fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx> {
self.opportunistic_resolve_int_var(vid)
}
fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx> {
self.opportunistic_resolve_float_var(vid)
}
fn opportunistic_resolve_ct_var(&self, vid: ConstVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
match self.probe_const_var(vid) {
Ok(ct) => ct,
Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid), ty),
}
}
fn opportunistic_resolve_effect_var(&self, vid: EffectVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
match self.probe_effect_var(vid) {
Some(ct) => ct,
None => {
ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)), ty)
}
}
}
}
/// See the `error_reporting` module for more details.

View File

@ -173,84 +173,3 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
}
}
}
///////////////////////////////////////////////////////////////////////////
// EAGER RESOLUTION
/// Resolves ty, region, and const vars to their inferred values or their root vars.
pub struct EagerResolver<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> EagerResolver<'a, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
EagerResolver { infcx }
}
}
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
Ok(t) => t.fold_with(self),
Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
},
ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
_ => {
if t.has_infer() {
t.super_fold_with(self)
} else {
t
}
}
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReVar(vid) => self
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.opportunistic_resolve_var(self.infcx.tcx, vid),
_ => r,
}
}
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
match c.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
// FIXME: we need to fold the ty too, I think.
match self.infcx.probe_const_var(vid) {
Ok(c) => c.fold_with(self),
Err(_) => {
ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
}
}
}
ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool);
self.infcx.probe_effect_var(vid).unwrap_or_else(|| {
ty::Const::new_infer(
self.infcx.tcx,
ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)),
self.infcx.tcx.types.bool,
)
})
}
_ => {
if c.has_infer() {
c.super_fold_with(self)
} else {
c
}
}
}
}
}

View File

@ -175,6 +175,14 @@ impl<'tcx> Const<'tcx> {
}
impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Self {
Const::new_infer(tcx, infer, ty)
}
fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid, ty: Ty<'tcx>) -> Self {
Const::new_var(tcx, vid, ty)
}
fn new_anon_bound(
tcx: TyCtxt<'tcx>,
debruijn: ty::DebruijnIndex,

View File

@ -1611,6 +1611,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
tcx.types.bool
}
fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Self {
Ty::new_infer(tcx, infer)
}
fn new_var(tcx: TyCtxt<'tcx>, vid: ty::TyVid) -> Self {
Ty::new_var(tcx, vid)
}
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
}

View File

@ -268,7 +268,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
ty::ReVar(vid) => {
assert_eq!(
self.infcx.opportunistic_resolve_lt_var(vid),
None,
r,
"region vid should have been resolved fully before canonicalization"
);
match self.canonicalize_mode {
@ -302,13 +302,8 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
ty::Infer(i) => match i {
ty::TyVar(vid) => {
assert_eq!(
self.infcx.root_ty_var(vid),
vid,
"ty vid should have been resolved fully before canonicalization"
);
assert_eq!(
self.infcx.probe_ty_var(vid),
None,
self.infcx.opportunistic_resolve_ty_var(vid),
t,
"ty vid should have been resolved fully before canonicalization"
);
@ -318,10 +313,24 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
.unwrap_or_else(|| panic!("ty var should have been resolved: {t:?}")),
))
}
ty::IntVar(_) => CanonicalVarKind::Ty(CanonicalTyVarKind::Int),
ty::FloatVar(_) => CanonicalVarKind::Ty(CanonicalTyVarKind::Float),
ty::IntVar(vid) => {
assert_eq!(
self.infcx.opportunistic_resolve_int_var(vid),
t,
"ty vid should have been resolved fully before canonicalization"
);
CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
}
ty::FloatVar(vid) => {
assert_eq!(
self.infcx.opportunistic_resolve_float_var(vid),
t,
"ty vid should have been resolved fully before canonicalization"
);
CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
}
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
todo!()
panic!("fresh vars not expected in canonicalization")
}
},
ty::Placeholder(placeholder) => match self.canonicalize_mode {
@ -387,14 +396,11 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
let kind = match c.kind() {
ty::ConstKind::Infer(i) => match i {
ty::InferConst::Var(vid) => {
// We compare `kind`s here because we've folded the `ty` with `RegionsToStatic`
// so we'll get a mismatch in types if it actually changed any regions.
assert_eq!(
self.infcx.root_ct_var(vid),
vid,
"region vid should have been resolved fully before canonicalization"
);
assert_eq!(
self.infcx.probe_ct_var(vid),
None,
self.infcx.opportunistic_resolve_ct_var(vid, ty).kind(),
c.kind(),
"region vid should have been resolved fully before canonicalization"
);
CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty)

View File

@ -1,2 +1,3 @@
pub mod canonicalizer;
pub mod resolve;
pub mod solve;

View File

@ -0,0 +1,83 @@
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_type_ir::inherent::*;
use rustc_type_ir::visit::TypeVisitableExt;
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
///////////////////////////////////////////////////////////////////////////
// EAGER RESOLUTION
/// Resolves ty, region, and const vars to their inferred values or their root vars.
pub struct EagerResolver<
'a,
Infcx: InferCtxtLike<Interner = I>,
I: Interner = <Infcx as InferCtxtLike>::Interner,
> {
infcx: &'a Infcx,
}
impl<'a, Infcx: InferCtxtLike> EagerResolver<'a, Infcx> {
pub fn new(infcx: &'a Infcx) -> Self {
EagerResolver { infcx }
}
}
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> for EagerResolver<'_, Infcx> {
fn interner(&self) -> I {
self.infcx.interner()
}
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
match t.kind() {
ty::Infer(ty::TyVar(vid)) => {
let resolved = self.infcx.opportunistic_resolve_ty_var(vid);
if t != resolved && resolved.has_infer() {
resolved.fold_with(self)
} else {
resolved
}
}
ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
_ => {
if t.has_infer() {
t.super_fold_with(self)
} else {
t
}
}
}
}
fn fold_region(&mut self, r: I::Region) -> I::Region {
match r.kind() {
ty::ReVar(vid) => self.infcx.opportunistic_resolve_lt_var(vid),
_ => r,
}
}
fn fold_const(&mut self, c: I::Const) -> I::Const {
match c.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
let ty = c.ty().fold_with(self);
let resolved = self.infcx.opportunistic_resolve_ct_var(vid, ty);
if c != resolved && resolved.has_infer() {
resolved.fold_with(self)
} else {
resolved
}
}
ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
let bool = Ty::new_bool(self.infcx.interner());
debug_assert_eq!(c.ty(), bool);
self.infcx.opportunistic_resolve_effect_var(vid, bool)
}
_ => {
if c.has_infer() {
c.super_fold_with(self)
} else {
c
}
}
}
}
}

View File

@ -18,7 +18,6 @@ use rustc_index::IndexVec;
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
use rustc_infer::infer::resolve::EagerResolver;
use rustc_infer::infer::RegionVariableOrigin;
use rustc_infer::infer::{InferCtxt, InferOk};
use rustc_infer::traits::solve::NestedNormalizationGoals;
@ -31,6 +30,7 @@ use rustc_middle::traits::solve::{
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer};
use rustc_next_trait_solver::resolve::EagerResolver;
use rustc_span::{Span, DUMMY_SP};
use std::assert_matches::assert_matches;
use std::iter;

View File

@ -11,7 +11,6 @@
use rustc_ast_ir::try_visit;
use rustc_ast_ir::visit::VisitorResult;
use rustc_infer::infer::resolve::EagerResolver;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
use rustc_macros::extension;
use rustc_middle::traits::query::NoSolution;
@ -20,6 +19,7 @@ use rustc_middle::traits::solve::{Certainty, Goal};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{TyCtxt, TypeFoldable};
use rustc_middle::{bug, ty};
use rustc_next_trait_solver::resolve::EagerResolver;
use rustc_span::{Span, DUMMY_SP};
use crate::solve::eval_ctxt::canonical;

View File

@ -1,4 +1,6 @@
use crate::{ConstVid, InferCtxtLike, Interner, RegionVid, TyVid, UniverseIndex};
use crate::{
ConstVid, EffectVid, FloatVid, InferCtxtLike, IntVid, Interner, RegionVid, TyVid, UniverseIndex,
};
use core::fmt;
use std::marker::PhantomData;
@ -24,27 +26,31 @@ impl<I: Interner> InferCtxtLike for NoInfcx<I> {
None
}
fn root_ty_var(&self, vid: TyVid) -> TyVid {
vid
fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> I::Ty {
panic!("cannot resolve {vid:?}")
}
fn probe_ty_var(&self, _vid: TyVid) -> Option<I::Ty> {
None
fn opportunistic_resolve_int_var(&self, vid: IntVid) -> I::Ty {
panic!("cannot resolve {vid:?}")
}
fn opportunistic_resolve_lt_var(&self, _vid: RegionVid) -> Option<I::Region> {
None
fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> I::Ty {
panic!("cannot resolve {vid:?}")
}
fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
vid
fn opportunistic_resolve_ct_var(&self, vid: ConstVid, _: I::Ty) -> I::Const {
panic!("cannot resolve {vid:?}")
}
fn probe_ct_var(&self, _vid: ConstVid) -> Option<I::Const> {
None
fn opportunistic_resolve_effect_var(&self, vid: EffectVid, _: I::Ty) -> I::Const {
panic!("cannot resolve {vid:?}")
}
fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes {
fn opportunistic_resolve_lt_var(&self, vid: crate::RegionVid) -> I::Region {
panic!("cannot resolve {vid:?}")
}
fn defining_opaque_types(&self) -> I::DefiningOpaqueTypes {
Default::default()
}
}

View File

@ -1,4 +1,4 @@
use crate::{ConstVid, Interner, RegionVid, TyVid, UniverseIndex};
use crate::{ConstVid, EffectVid, FloatVid, IntVid, Interner, RegionVid, TyVid, UniverseIndex};
pub trait InferCtxtLike {
type Interner: Interner;
@ -6,34 +6,23 @@ pub trait InferCtxtLike {
fn interner(&self) -> Self::Interner;
fn universe_of_ty(&self, ty: TyVid) -> Option<UniverseIndex>;
/// Resolve `TyVid` to its root `TyVid`.
fn root_ty_var(&self, vid: TyVid) -> TyVid;
/// Resolve `TyVid` to its inferred type, if it has been equated with a non-infer type.
fn probe_ty_var(&self, vid: TyVid) -> Option<<Self::Interner as Interner>::Ty>;
fn universe_of_lt(&self, lt: RegionVid) -> Option<UniverseIndex>;
/// Resolve `InferRegion` to its inferred region, if it has been equated with
/// a non-infer region.
///
/// FIXME: This has slightly different semantics than `{probe,resolve}_{ty,ct}_var`,
/// that has to do with the fact unlike `Ty` or `Const` vars, in rustc, we may
/// not always be able to *name* the root region var from the universe of the
/// var we're trying to resolve. That's why it's called *opportunistic*.
fn opportunistic_resolve_lt_var(
&self,
vid: RegionVid,
) -> Option<<Self::Interner as Interner>::Region>;
fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>;
/// Resolve `ConstVid` to its root `ConstVid`.
fn root_ct_var(&self, vid: ConstVid) -> ConstVid;
/// Resolve `ConstVid` to its inferred type, if it has been equated with a non-infer type.
fn probe_ct_var(&self, vid: ConstVid) -> Option<<Self::Interner as Interner>::Const>;
fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> <Self::Interner as Interner>::Ty;
fn opportunistic_resolve_int_var(&self, vid: IntVid) -> <Self::Interner as Interner>::Ty;
fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> <Self::Interner as Interner>::Ty;
fn opportunistic_resolve_ct_var(
&self,
vid: ConstVid,
ty: <Self::Interner as Interner>::Ty,
) -> <Self::Interner as Interner>::Const;
fn opportunistic_resolve_effect_var(
&self,
vid: EffectVid,
ty: <Self::Interner as Interner>::Ty,
) -> <Self::Interner as Interner>::Const;
fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> <Self::Interner as Interner>::Region;
fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
}

View File

@ -7,11 +7,11 @@ use std::fmt::Debug;
use std::hash::Hash;
use std::ops::Deref;
use crate::fold::TypeSuperFoldable;
use crate::fold::{TypeFoldable, TypeSuperFoldable};
use crate::visit::{Flags, TypeSuperVisitable};
use crate::{
AliasTy, AliasTyKind, BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind,
TyKind, UnevaluatedConst, UniverseIndex,
AliasTy, AliasTyKind, BoundVar, ConstKind, ConstVid, DebruijnIndex, DebugWithInfcx, InferConst,
InferTy, Interner, RegionKind, TyKind, TyVid, UnevaluatedConst, UniverseIndex,
};
pub trait Ty<I: Interner<Ty = Self>>:
@ -28,6 +28,10 @@ pub trait Ty<I: Interner<Ty = Self>>:
{
fn new_bool(interner: I) -> Self;
fn new_infer(interner: I, var: InferTy) -> Self;
fn new_var(interner: I, var: TyVid) -> Self;
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self;
@ -68,6 +72,10 @@ pub trait Const<I: Interner<Const = Self>>:
+ TypeSuperFoldable<I>
+ Flags
{
fn new_infer(interner: I, var: InferConst, ty: I::Ty) -> Self;
fn new_var(interner: I, var: ConstVid, ty: I::Ty) -> Self;
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self;
fn new_unevaluated(interner: I, uv: UnevaluatedConst<I>, ty: I::Ty) -> Self;
@ -87,6 +95,7 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
+ IntoIterator<Item = I::GenericArg>
+ Deref<Target: Deref<Target = [I::GenericArg]>>
+ Default
+ TypeFoldable<I>
{
fn type_at(self, i: usize) -> I::Ty;