Implement fallback for effect param
This commit is contained in:
parent
b14b0745ad
commit
84a490712a
20 changed files with 390 additions and 72 deletions
|
@ -522,6 +522,17 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Infer(InferConst::EffectVar(vid)) => {
|
||||
match self.infcx.probe_effect_var(vid) {
|
||||
Some(value) => return self.fold_const(value.as_const(self.infcx.tcx)),
|
||||
None => {
|
||||
return self.canonicalize_const_var(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Effect },
|
||||
ct,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
|
||||
bug!("encountered a fresh const during canonicalization")
|
||||
}
|
||||
|
@ -690,7 +701,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
.iter()
|
||||
.map(|v| CanonicalVarInfo {
|
||||
kind: match v.kind {
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
|
||||
| CanonicalVarKind::Effect => {
|
||||
return *v;
|
||||
}
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
|
||||
|
|
|
@ -151,7 +151,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
universe_map(ui),
|
||||
)
|
||||
.into(),
|
||||
|
||||
CanonicalVarKind::Effect => {
|
||||
let vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool)
|
||||
.into()
|
||||
}
|
||||
CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => {
|
||||
let universe_mapped = universe_map(universe);
|
||||
let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound };
|
||||
|
|
|
@ -30,7 +30,7 @@ use super::{DefineOpaqueTypes, InferCtxt, TypeTrace};
|
|||
use crate::infer::generalize::{self, CombineDelegate, Generalization};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
use rustc_middle::infer::canonical::OriginalQueryValues;
|
||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
|
||||
|
@ -91,7 +91,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.borrow_mut()
|
||||
.float_unification_table()
|
||||
.unify_var_var(a_id, b_id)
|
||||
.map_err(|e| float_unification_error(relation.a_is_expected(), e))?;
|
||||
.map_err(|e| float_unification_error(a_is_expected, e))?;
|
||||
Ok(a)
|
||||
}
|
||||
(&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
|
||||
|
@ -210,10 +210,30 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
return Ok(a);
|
||||
}
|
||||
|
||||
(
|
||||
ty::ConstKind::Infer(InferConst::EffectVar(a_vid)),
|
||||
ty::ConstKind::Infer(InferConst::EffectVar(b_vid)),
|
||||
) => {
|
||||
self.inner
|
||||
.borrow_mut()
|
||||
.effect_unification_table()
|
||||
.unify_var_var(a_vid, b_vid)
|
||||
.map_err(|a| effect_unification_error(self.tcx, relation.a_is_expected(), a))?;
|
||||
return Ok(a);
|
||||
}
|
||||
|
||||
// All other cases of inference with other variables are errors.
|
||||
(ty::ConstKind::Infer(InferConst::Var(_)), ty::ConstKind::Infer(_))
|
||||
| (ty::ConstKind::Infer(_), ty::ConstKind::Infer(InferConst::Var(_))) => {
|
||||
bug!("tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var)")
|
||||
(
|
||||
ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
|
||||
ty::ConstKind::Infer(_),
|
||||
)
|
||||
| (
|
||||
ty::ConstKind::Infer(_),
|
||||
ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
|
||||
) => {
|
||||
bug!(
|
||||
"tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
|
||||
)
|
||||
}
|
||||
|
||||
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
|
||||
|
@ -223,6 +243,23 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
||||
return self.unify_const_variable(vid, a, relation.param_env());
|
||||
}
|
||||
|
||||
(ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => {
|
||||
return self.unify_effect_variable(
|
||||
relation.a_is_expected(),
|
||||
vid,
|
||||
EffectVarValue::Const(b),
|
||||
);
|
||||
}
|
||||
|
||||
(_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => {
|
||||
return self.unify_effect_variable(
|
||||
!relation.a_is_expected(),
|
||||
vid,
|
||||
EffectVarValue::Const(a),
|
||||
);
|
||||
}
|
||||
|
||||
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
|
||||
if self.tcx.features().generic_const_exprs || self.next_trait_solver() =>
|
||||
{
|
||||
|
@ -340,6 +377,20 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.map_err(|e| float_unification_error(vid_is_expected, e))?;
|
||||
Ok(Ty::new_float(self.tcx, val))
|
||||
}
|
||||
|
||||
fn unify_effect_variable(
|
||||
&self,
|
||||
vid_is_expected: bool,
|
||||
vid: ty::EffectVid<'tcx>,
|
||||
val: EffectVarValue<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>> {
|
||||
self.inner
|
||||
.borrow_mut()
|
||||
.effect_unification_table()
|
||||
.unify_var_value(vid, Some(val))
|
||||
.map_err(|e| effect_unification_error(self.tcx, vid_is_expected, e))?;
|
||||
Ok(val.as_const(self.tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||
|
@ -493,3 +544,11 @@ fn float_unification_error<'tcx>(
|
|||
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
|
||||
TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b))
|
||||
}
|
||||
|
||||
fn effect_unification_error<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
a_is_expected: bool,
|
||||
(a, b): (EffectVarValue<'tcx>, EffectVarValue<'tcx>),
|
||||
) -> TypeError<'tcx> {
|
||||
TypeError::ConstMismatch(ExpectedFound::new(a_is_expected, a.as_const(tcx), b.as_const(tcx)))
|
||||
}
|
||||
|
|
|
@ -156,6 +156,21 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
|
|||
.known();
|
||||
self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
|
||||
}
|
||||
ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
|
||||
let opt_ct = self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.effect_unification_table()
|
||||
.probe_value(v)
|
||||
.map(|effect| effect.as_const(self.infcx.tcx));
|
||||
self.freshen_const(
|
||||
opt_ct,
|
||||
ty::InferConst::EffectVar(v),
|
||||
ty::InferConst::Fresh,
|
||||
ct.ty(),
|
||||
)
|
||||
}
|
||||
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
|
||||
if i >= self.const_freshen_count {
|
||||
bug!(
|
||||
|
|
|
@ -403,6 +403,7 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Infer(InferConst::EffectVar(_)) => Ok(c),
|
||||
// FIXME: remove this branch once `structurally_relate_consts` is fully
|
||||
// structural.
|
||||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
|
||||
|
|
|
@ -21,7 +21,7 @@ use rustc_data_structures::unify as ut;
|
|||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
|
@ -33,13 +33,14 @@ use rustc_middle::ty::relate::RelateResult;
|
|||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
||||
pub use rustc_middle::ty::IntVarValue;
|
||||
use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
|
||||
use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use self::combine::CombineFields;
|
||||
use self::error_reporting::TypeErrCtxt;
|
||||
|
@ -115,6 +116,9 @@ pub struct InferCtxtInner<'tcx> {
|
|||
/// Map from floating variable to the kind of float it represents.
|
||||
float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
|
||||
|
||||
/// Map from effect variable to the effect param it represents.
|
||||
effect_unification_storage: ut::UnificationTableStorage<ty::EffectVid<'tcx>>,
|
||||
|
||||
/// Tracks the set of region variables and the constraints between them.
|
||||
///
|
||||
/// This is initially `Some(_)` but when
|
||||
|
@ -172,6 +176,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
|
|||
const_unification_storage: ut::UnificationTableStorage::new(),
|
||||
int_unification_storage: ut::UnificationTableStorage::new(),
|
||||
float_unification_storage: ut::UnificationTableStorage::new(),
|
||||
effect_unification_storage: ut::UnificationTableStorage::new(),
|
||||
region_constraint_storage: Some(RegionConstraintStorage::new()),
|
||||
region_obligations: vec![],
|
||||
opaque_type_storage: Default::default(),
|
||||
|
@ -223,6 +228,10 @@ impl<'tcx> InferCtxtInner<'tcx> {
|
|||
self.const_unification_storage.with_log(&mut self.undo_log)
|
||||
}
|
||||
|
||||
fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::EffectVid<'tcx>> {
|
||||
self.effect_unification_storage.with_log(&mut self.undo_log)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> {
|
||||
self.region_constraint_storage
|
||||
|
@ -356,6 +365,7 @@ impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
|
|||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
},
|
||||
EffectVar(_) => None,
|
||||
Fresh(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -777,6 +787,19 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
vars
|
||||
}
|
||||
|
||||
pub fn unsolved_effects(&self) -> Vec<ty::Const<'tcx>> {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let mut table = inner.effect_unification_table();
|
||||
|
||||
(0..table.len())
|
||||
.map(|i| ty::EffectVid { index: i as u32, phantom: PhantomData })
|
||||
.filter(|&vid| table.probe_value(vid).is_none())
|
||||
.map(|v| {
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn combine_fields<'a>(
|
||||
&'a self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
|
@ -1159,6 +1182,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
Ty::new_var(self.tcx, ty_var_id).into()
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
// todo what about using effect var here
|
||||
if self.tcx.has_attr(param.def_id, sym::rustc_host) {
|
||||
return self.var_for_effect(param);
|
||||
}
|
||||
let origin = ConstVariableOrigin {
|
||||
kind: ConstVariableOriginKind::ConstParameterDefinition(
|
||||
param.name,
|
||||
|
@ -1184,6 +1211,17 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
|
||||
let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None);
|
||||
let ty = self
|
||||
.tcx
|
||||
.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
debug_assert_eq!(self.tcx.types.bool, ty);
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into()
|
||||
}
|
||||
|
||||
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
|
||||
/// type/region parameter to a fresh inference variable.
|
||||
pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
|
||||
|
@ -1369,6 +1407,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn probe_effect_var(&self, vid: EffectVid<'tcx>) -> Option<EffectVarValue<'tcx>> {
|
||||
self.inner.borrow_mut().effect_unification_table().probe_value(vid)
|
||||
}
|
||||
|
||||
/// Attempts to resolve all type/region/const variables in
|
||||
/// `value`. Region inference must have been run already (e.g.,
|
||||
/// by calling `resolve_regions_and_report_errors`). If some
|
||||
|
@ -1649,6 +1691,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
ConstVariableValue::Known { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
TyOrConstInferVar::Effect(v) => {
|
||||
// If `probe_value` returns `Some`, it never equals
|
||||
// `ty::ConstKind::Infer(ty::InferConst::Effect(v))`.
|
||||
//
|
||||
// Not `inlined_probe_value(v)` because this call site is colder.
|
||||
self.probe_effect_var(v).is_some()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1720,6 +1770,8 @@ pub enum TyOrConstInferVar<'tcx> {
|
|||
|
||||
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
|
||||
Const(ConstVid<'tcx>),
|
||||
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`.
|
||||
Effect(EffectVid<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> TyOrConstInferVar<'tcx> {
|
||||
|
@ -1750,6 +1802,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> {
|
|||
fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
|
||||
ty::ConstKind::Infer(InferConst::EffectVar(v)) => Some(TyOrConstInferVar::Effect(v)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -1793,17 +1846,24 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
|
||||
self.infcx
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Infer(InferConst::Var(vid)) => self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.const_unification_table()
|
||||
.probe_value(vid)
|
||||
.val
|
||||
.known()
|
||||
.unwrap_or(ct)
|
||||
} else {
|
||||
ct
|
||||
.unwrap_or(ct),
|
||||
ty::ConstKind::Infer(InferConst::EffectVar(vid)) => self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.effect_unification_table()
|
||||
.probe_value(vid)
|
||||
.map_or(ct, |val| val.as_const(self.infcx.tcx)),
|
||||
_ => ct,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ pub(crate) enum UndoLog<'tcx> {
|
|||
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
|
||||
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
||||
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
||||
EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
|
||||
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
|
||||
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
|
||||
ProjectionCache(traits::UndoLog<'tcx>),
|
||||
|
@ -55,6 +56,7 @@ impl_from! {
|
|||
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
||||
|
||||
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
||||
EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
|
||||
|
||||
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
|
||||
|
||||
|
@ -71,6 +73,7 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
|
|||
UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
|
||||
UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
|
||||
UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo),
|
||||
UndoLog::EffectUnificationTable(undo) => self.effect_unification_storage.reverse(undo),
|
||||
UndoLog::RegionConstraintCollector(undo) => {
|
||||
self.region_constraint_storage.as_mut().unwrap().reverse(undo)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue