mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Rollup merge of #115727 - fee1-dead-contrib:effect-fallback, r=oli-obk
Implement fallback for effect param r? `@oli-obk` or `@lcnr` tracking issue for this ongoing work: https://github.com/rust-lang/rust/issues/110395
This commit is contained in:
commit
e7a347baf8
@ -523,7 +523,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
Ty::new_misc_error(tcx).into()
|
Ty::new_misc_error(tcx).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GenericParamDefKind::Const { has_default } => {
|
GenericParamDefKind::Const { has_default, .. } => {
|
||||||
let ty = tcx
|
let ty = tcx
|
||||||
.at(self.span)
|
.at(self.span)
|
||||||
.type_of(param.def_id)
|
.type_of(param.def_id)
|
||||||
|
@ -1255,7 +1255,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||||||
|
|
||||||
let is_our_default = |def: &ty::GenericParamDef| match def.kind {
|
let is_our_default = |def: &ty::GenericParamDef| match def.kind {
|
||||||
GenericParamDefKind::Type { has_default, .. }
|
GenericParamDefKind::Type { has_default, .. }
|
||||||
| GenericParamDefKind::Const { has_default } => {
|
| GenericParamDefKind::Const { has_default, .. } => {
|
||||||
has_default && def.index >= generics.parent_count as u32
|
has_default && def.index >= generics.parent_count as u32
|
||||||
}
|
}
|
||||||
GenericParamDefKind::Lifetime => unreachable!(),
|
GenericParamDefKind::Lifetime => unreachable!(),
|
||||||
|
@ -328,7 +328,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||||||
name: param.name.ident().name,
|
name: param.name.ident().name,
|
||||||
def_id: param.def_id.to_def_id(),
|
def_id: param.def_id.to_def_id(),
|
||||||
pure_wrt_drop: param.pure_wrt_drop,
|
pure_wrt_drop: param.pure_wrt_drop,
|
||||||
kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
|
kind: ty::GenericParamDefKind::Const {
|
||||||
|
has_default: default.is_some(),
|
||||||
|
is_host_effect: is_host_param,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -4,6 +4,7 @@ use rustc_data_structures::{
|
|||||||
graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
|
graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
|
||||||
unord::{UnordBag, UnordMap, UnordSet},
|
unord::{UnordBag, UnordMap, UnordSet},
|
||||||
};
|
};
|
||||||
|
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
|
|
||||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||||
@ -23,22 +24,12 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||||||
self.fulfillment_cx.borrow_mut().pending_obligations()
|
self.fulfillment_cx.borrow_mut().pending_obligations()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check if we have any unsolved variables. If not, no need for fallback.
|
let fallback_occured = self.fallback_types() || self.fallback_effects();
|
||||||
let unsolved_variables = self.unsolved_variables();
|
|
||||||
if unsolved_variables.is_empty() {
|
if !fallback_occured {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
|
|
||||||
|
|
||||||
// We do fallback in two passes, to try to generate
|
|
||||||
// better error messages.
|
|
||||||
// The first time, we do *not* replace opaque types.
|
|
||||||
for ty in unsolved_variables {
|
|
||||||
debug!("unsolved_variable = {:?}", ty);
|
|
||||||
self.fallback_if_possible(ty, &diverging_fallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We now see if we can make progress. This might cause us to
|
// We now see if we can make progress. This might cause us to
|
||||||
// unify inference variables for opaque types, since we may
|
// unify inference variables for opaque types, since we may
|
||||||
// have unified some other type variables during the first
|
// have unified some other type variables during the first
|
||||||
@ -65,6 +56,53 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||||||
self.select_obligations_where_possible(|_| {});
|
self.select_obligations_where_possible(|_| {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fallback_types(&self) -> bool {
|
||||||
|
// Check if we have any unsolved variables. If not, no need for fallback.
|
||||||
|
let unsolved_variables = self.unsolved_variables();
|
||||||
|
|
||||||
|
if unsolved_variables.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
|
||||||
|
|
||||||
|
// We do fallback in two passes, to try to generate
|
||||||
|
// better error messages.
|
||||||
|
// The first time, we do *not* replace opaque types.
|
||||||
|
for ty in unsolved_variables {
|
||||||
|
debug!("unsolved_variable = {:?}", ty);
|
||||||
|
self.fallback_if_possible(ty, &diverging_fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fallback_effects(&self) -> bool {
|
||||||
|
let unsolved_effects = self.unsolved_effects();
|
||||||
|
|
||||||
|
if unsolved_effects.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not setting `fallback_has_occured` here because that field is only used for type fallback
|
||||||
|
// diagnostics.
|
||||||
|
|
||||||
|
for effect in unsolved_effects {
|
||||||
|
let expected = self.tcx.consts.true_;
|
||||||
|
let cause = self.misc(rustc_span::DUMMY_SP);
|
||||||
|
match self.at(&cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, effect) {
|
||||||
|
Ok(InferOk { obligations, value: () }) => {
|
||||||
|
self.register_predicates(obligations);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
bug!("cannot eq unsolved effect: {e:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
// Tries to apply a fallback to `ty` if it is an unsolved variable.
|
// Tries to apply a fallback to `ty` if it is an unsolved variable.
|
||||||
//
|
//
|
||||||
// - Unconstrained ints are replaced with `i32`.
|
// - Unconstrained ints are replaced with `i32`.
|
||||||
|
@ -1295,17 +1295,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
|
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
|
||||||
self.fcx.ty_infer(Some(param), inf.span).into()
|
self.fcx.ty_infer(Some(param), inf.span).into()
|
||||||
}
|
}
|
||||||
(GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
|
(
|
||||||
|
&GenericParamDefKind::Const { has_default, is_host_effect },
|
||||||
|
GenericArg::Infer(inf),
|
||||||
|
) => {
|
||||||
let tcx = self.fcx.tcx();
|
let tcx = self.fcx.tcx();
|
||||||
self.fcx
|
|
||||||
.ct_infer(
|
if has_default && is_host_effect {
|
||||||
tcx.type_of(param.def_id)
|
self.fcx.var_for_effect(param)
|
||||||
.no_bound_vars()
|
} else {
|
||||||
.expect("const parameter types cannot be generic"),
|
self.fcx
|
||||||
Some(param),
|
.ct_infer(
|
||||||
inf.span,
|
tcx.type_of(param.def_id)
|
||||||
)
|
.no_bound_vars()
|
||||||
.into()
|
.expect("const parameter types cannot be generic"),
|
||||||
|
Some(param),
|
||||||
|
inf.span,
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@ -1324,7 +1332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
GenericParamDefKind::Type { has_default, .. } => {
|
GenericParamDefKind::Type { has_default, .. } => {
|
||||||
if !infer_args && has_default {
|
if !infer_args && has_default {
|
||||||
// If we have a default, then we it doesn't matter that we're not
|
// If we have a default, then it doesn't matter that we're not
|
||||||
// inferring the type arguments: we provide the default where any
|
// inferring the type arguments: we provide the default where any
|
||||||
// is missing.
|
// is missing.
|
||||||
tcx.type_of(param.def_id).instantiate(tcx, args.unwrap()).into()
|
tcx.type_of(param.def_id).instantiate(tcx, args.unwrap()).into()
|
||||||
@ -1336,17 +1344,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.fcx.var_for_def(self.span, param)
|
self.fcx.var_for_def(self.span, param)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GenericParamDefKind::Const { has_default } => {
|
GenericParamDefKind::Const { has_default, is_host_effect } => {
|
||||||
if !infer_args
|
if has_default {
|
||||||
&& has_default
|
// N.B. this is a bit of a hack. `infer_args` is passed depending on
|
||||||
&& !tcx.has_attr(param.def_id, sym::rustc_host)
|
// whether the user has provided generic args. E.g. for `Vec::new`
|
||||||
{
|
// we would have to infer the generic types. However, for `Vec::<T>::new`
|
||||||
tcx.const_param_default(param.def_id)
|
// where the allocator param `A` has a default we will *not* infer. But
|
||||||
.instantiate(tcx, args.unwrap())
|
// for effect params this is a different story: if the user has not written
|
||||||
.into()
|
// anything explicit for the effect param, we always need to try to infer
|
||||||
} else {
|
// it before falling back to default, such that a `const fn` such as
|
||||||
self.fcx.var_for_def(self.span, param)
|
// `needs_drop::<()>` can still be called in const contexts. (if we defaulted
|
||||||
|
// instead of inferred, typeck would error)
|
||||||
|
if is_host_effect {
|
||||||
|
return self.fcx.var_for_effect(param);
|
||||||
|
} else if !infer_args {
|
||||||
|
return tcx
|
||||||
|
.const_param_default(param.def_id)
|
||||||
|
.instantiate(tcx, args.unwrap())
|
||||||
|
.into();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.fcx.var_for_def(self.span, param)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,14 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
|||||||
param: Option<&ty::GenericParamDef>,
|
param: Option<&ty::GenericParamDef>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Const<'tcx> {
|
) -> Const<'tcx> {
|
||||||
|
// FIXME ideally this shouldn't use unwrap
|
||||||
match param {
|
match param {
|
||||||
|
Some(
|
||||||
|
param @ ty::GenericParamDef {
|
||||||
|
kind: ty::GenericParamDefKind::Const { is_host_effect: true, .. },
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => self.var_for_effect(param).as_const().unwrap(),
|
||||||
Some(param) => self.var_for_def(span, param).as_const().unwrap(),
|
Some(param) => self.var_for_def(span, param).as_const().unwrap(),
|
||||||
None => self.next_const_var(
|
None => self.next_const_var(
|
||||||
ty,
|
ty,
|
||||||
|
@ -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(_)) => {
|
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
|
||||||
bug!("encountered a fresh const during canonicalization")
|
bug!("encountered a fresh const during canonicalization")
|
||||||
}
|
}
|
||||||
@ -690,7 +701,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|v| CanonicalVarInfo {
|
.map(|v| CanonicalVarInfo {
|
||||||
kind: match v.kind {
|
kind: match v.kind {
|
||||||
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
|
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
|
||||||
|
| CanonicalVarKind::Effect => {
|
||||||
return *v;
|
return *v;
|
||||||
}
|
}
|
||||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
|
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
|
||||||
|
@ -151,7 +151,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
universe_map(ui),
|
universe_map(ui),
|
||||||
)
|
)
|
||||||
.into(),
|
.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) => {
|
CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => {
|
||||||
let universe_mapped = universe_map(universe);
|
let universe_mapped = universe_map(universe);
|
||||||
let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound };
|
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::infer::generalize::{self, CombineDelegate, Generalization};
|
||||||
use crate::traits::{Obligation, PredicateObligations};
|
use crate::traits::{Obligation, PredicateObligations};
|
||||||
use rustc_middle::infer::canonical::OriginalQueryValues;
|
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::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||||
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
|
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
|
||||||
@ -91,7 +91,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.float_unification_table()
|
.float_unification_table()
|
||||||
.unify_var_var(a_id, b_id)
|
.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)
|
Ok(a)
|
||||||
}
|
}
|
||||||
(&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
|
(&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
|
||||||
@ -210,10 +210,30 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
return Ok(a);
|
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.
|
// 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(_))) => {
|
ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
|
||||||
bug!("tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var)")
|
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)), _) => {
|
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
|
||||||
@ -223,6 +243,23 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
||||||
return self.unify_const_variable(vid, a, relation.param_env());
|
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(..))
|
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
|
||||||
if self.tcx.features().generic_const_exprs || self.next_trait_solver() =>
|
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))?;
|
.map_err(|e| float_unification_error(vid_is_expected, e))?;
|
||||||
Ok(Ty::new_float(self.tcx, val))
|
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> {
|
impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||||
@ -493,3 +544,11 @@ fn float_unification_error<'tcx>(
|
|||||||
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
|
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
|
||||||
TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b))
|
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> {
|
||||||
|
bug!("unexpected effect unification error")
|
||||||
|
}
|
||||||
|
@ -156,6 +156,21 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
|
|||||||
.known();
|
.known();
|
||||||
self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
|
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)) => {
|
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
|
||||||
if i >= self.const_freshen_count {
|
if i >= self.const_freshen_count {
|
||||||
bug!(
|
bug!(
|
||||||
|
@ -403,6 +403,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ty::ConstKind::Infer(InferConst::EffectVar(_)) => Ok(c),
|
||||||
// FIXME: remove this branch once `structurally_relate_consts` is fully
|
// FIXME: remove this branch once `structurally_relate_consts` is fully
|
||||||
// structural.
|
// structural.
|
||||||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
|
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_errors::{DiagnosticBuilder, ErrorGuaranteed};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
|
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::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
||||||
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
|
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
|
||||||
use rustc_middle::mir::ConstraintCategory;
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
@ -33,13 +33,14 @@ use rustc_middle::ty::relate::RelateResult;
|
|||||||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
||||||
pub use rustc_middle::ty::IntVarValue;
|
pub use rustc_middle::ty::IntVarValue;
|
||||||
use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtxt};
|
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_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use self::combine::CombineFields;
|
use self::combine::CombineFields;
|
||||||
use self::error_reporting::TypeErrCtxt;
|
use self::error_reporting::TypeErrCtxt;
|
||||||
@ -115,6 +116,9 @@ pub struct InferCtxtInner<'tcx> {
|
|||||||
/// Map from floating variable to the kind of float it represents.
|
/// Map from floating variable to the kind of float it represents.
|
||||||
float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
|
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.
|
/// Tracks the set of region variables and the constraints between them.
|
||||||
///
|
///
|
||||||
/// This is initially `Some(_)` but when
|
/// This is initially `Some(_)` but when
|
||||||
@ -172,6 +176,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
|
|||||||
const_unification_storage: ut::UnificationTableStorage::new(),
|
const_unification_storage: ut::UnificationTableStorage::new(),
|
||||||
int_unification_storage: ut::UnificationTableStorage::new(),
|
int_unification_storage: ut::UnificationTableStorage::new(),
|
||||||
float_unification_storage: ut::UnificationTableStorage::new(),
|
float_unification_storage: ut::UnificationTableStorage::new(),
|
||||||
|
effect_unification_storage: ut::UnificationTableStorage::new(),
|
||||||
region_constraint_storage: Some(RegionConstraintStorage::new()),
|
region_constraint_storage: Some(RegionConstraintStorage::new()),
|
||||||
region_obligations: vec![],
|
region_obligations: vec![],
|
||||||
opaque_type_storage: Default::default(),
|
opaque_type_storage: Default::default(),
|
||||||
@ -223,6 +228,10 @@ impl<'tcx> InferCtxtInner<'tcx> {
|
|||||||
self.const_unification_storage.with_log(&mut self.undo_log)
|
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]
|
#[inline]
|
||||||
pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> {
|
pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> {
|
||||||
self.region_constraint_storage
|
self.region_constraint_storage
|
||||||
@ -356,6 +365,7 @@ impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
|
|||||||
Err(universe) => Some(universe),
|
Err(universe) => Some(universe),
|
||||||
Ok(_) => None,
|
Ok(_) => None,
|
||||||
},
|
},
|
||||||
|
EffectVar(_) => None,
|
||||||
Fresh(_) => None,
|
Fresh(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -777,6 +787,19 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
vars
|
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>(
|
fn combine_fields<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
trace: TypeTrace<'tcx>,
|
trace: TypeTrace<'tcx>,
|
||||||
@ -1158,7 +1181,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
|
|
||||||
Ty::new_var(self.tcx, ty_var_id).into()
|
Ty::new_var(self.tcx, ty_var_id).into()
|
||||||
}
|
}
|
||||||
GenericParamDefKind::Const { .. } => {
|
GenericParamDefKind::Const { is_host_effect, .. } => {
|
||||||
|
if is_host_effect {
|
||||||
|
return self.var_for_effect(param);
|
||||||
|
}
|
||||||
let origin = ConstVariableOrigin {
|
let origin = ConstVariableOrigin {
|
||||||
kind: ConstVariableOriginKind::ConstParameterDefinition(
|
kind: ConstVariableOriginKind::ConstParameterDefinition(
|
||||||
param.name,
|
param.name,
|
||||||
@ -1184,6 +1210,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
|
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
|
||||||
/// type/region parameter to a fresh inference variable.
|
/// type/region parameter to a fresh inference variable.
|
||||||
pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
|
pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
|
||||||
@ -1369,6 +1406,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
|
/// Attempts to resolve all type/region/const variables in
|
||||||
/// `value`. Region inference must have been run already (e.g.,
|
/// `value`. Region inference must have been run already (e.g.,
|
||||||
/// by calling `resolve_regions_and_report_errors`). If some
|
/// by calling `resolve_regions_and_report_errors`). If some
|
||||||
@ -1649,6 +1690,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
ConstVariableValue::Known { .. } => true,
|
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 +1769,8 @@ pub enum TyOrConstInferVar<'tcx> {
|
|||||||
|
|
||||||
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
|
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
|
||||||
Const(ConstVid<'tcx>),
|
Const(ConstVid<'tcx>),
|
||||||
|
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`.
|
||||||
|
Effect(EffectVid<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TyOrConstInferVar<'tcx> {
|
impl<'tcx> TyOrConstInferVar<'tcx> {
|
||||||
@ -1750,6 +1801,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> {
|
|||||||
fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
|
fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
|
||||||
match ct.kind() {
|
match ct.kind() {
|
||||||
ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
|
ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
|
||||||
|
ty::ConstKind::Infer(InferConst::EffectVar(v)) => Some(TyOrConstInferVar::Effect(v)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1793,17 +1845,24 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||||
if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
|
match ct.kind() {
|
||||||
self.infcx
|
ty::ConstKind::Infer(InferConst::Var(vid)) => self
|
||||||
|
.infcx
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.const_unification_table()
|
.const_unification_table()
|
||||||
.probe_value(vid)
|
.probe_value(vid)
|
||||||
.val
|
.val
|
||||||
.known()
|
.known()
|
||||||
.unwrap_or(ct)
|
.unwrap_or(ct),
|
||||||
} else {
|
ty::ConstKind::Infer(InferConst::EffectVar(vid)) => self
|
||||||
ct
|
.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>>>),
|
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
|
||||||
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
||||||
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
||||||
|
EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
|
||||||
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
|
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
|
||||||
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
|
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
|
||||||
ProjectionCache(traits::UndoLog<'tcx>),
|
ProjectionCache(traits::UndoLog<'tcx>),
|
||||||
@ -55,6 +56,7 @@ impl_from! {
|
|||||||
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
||||||
|
|
||||||
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
||||||
|
EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>),
|
||||||
|
|
||||||
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'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::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
|
||||||
UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
|
UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
|
||||||
UndoLog::FloatUnificationTable(undo) => self.float_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) => {
|
UndoLog::RegionConstraintCollector(undo) => {
|
||||||
self.region_constraint_storage.as_mut().unwrap().reverse(undo)
|
self.region_constraint_storage.as_mut().unwrap().reverse(undo)
|
||||||
}
|
}
|
||||||
|
@ -184,6 +184,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
|
|||||||
CanonicalVarKind::PlaceholderRegion(..) => false,
|
CanonicalVarKind::PlaceholderRegion(..) => false,
|
||||||
CanonicalVarKind::Const(..) => true,
|
CanonicalVarKind::Const(..) => true,
|
||||||
CanonicalVarKind::PlaceholderConst(_, _) => false,
|
CanonicalVarKind::PlaceholderConst(_, _) => false,
|
||||||
|
CanonicalVarKind::Effect => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +194,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
|
|||||||
CanonicalVarKind::Ty(_)
|
CanonicalVarKind::Ty(_)
|
||||||
| CanonicalVarKind::PlaceholderTy(_)
|
| CanonicalVarKind::PlaceholderTy(_)
|
||||||
| CanonicalVarKind::Const(_, _)
|
| CanonicalVarKind::Const(_, _)
|
||||||
| CanonicalVarKind::PlaceholderConst(_, _) => false,
|
| CanonicalVarKind::PlaceholderConst(_, _)
|
||||||
|
| CanonicalVarKind::Effect => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +203,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
|
|||||||
match self.kind {
|
match self.kind {
|
||||||
CanonicalVarKind::Ty(_)
|
CanonicalVarKind::Ty(_)
|
||||||
| CanonicalVarKind::Region(_)
|
| CanonicalVarKind::Region(_)
|
||||||
| CanonicalVarKind::Const(_, _) => bug!("expected placeholder: {self:?}"),
|
| CanonicalVarKind::Const(_, _)
|
||||||
|
| CanonicalVarKind::Effect => bug!("expected placeholder: {self:?}"),
|
||||||
|
|
||||||
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.bound.var.as_usize(),
|
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.bound.var.as_usize(),
|
||||||
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.bound.var.as_usize(),
|
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.bound.var.as_usize(),
|
||||||
@ -233,6 +236,9 @@ pub enum CanonicalVarKind<'tcx> {
|
|||||||
/// Some kind of const inference variable.
|
/// Some kind of const inference variable.
|
||||||
Const(ty::UniverseIndex, Ty<'tcx>),
|
Const(ty::UniverseIndex, Ty<'tcx>),
|
||||||
|
|
||||||
|
/// Effect variable `'?E`.
|
||||||
|
Effect,
|
||||||
|
|
||||||
/// A "placeholder" that represents "any const".
|
/// A "placeholder" that represents "any const".
|
||||||
PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
|
PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
|
||||||
}
|
}
|
||||||
@ -240,11 +246,11 @@ pub enum CanonicalVarKind<'tcx> {
|
|||||||
impl<'tcx> CanonicalVarKind<'tcx> {
|
impl<'tcx> CanonicalVarKind<'tcx> {
|
||||||
pub fn universe(self) -> ty::UniverseIndex {
|
pub fn universe(self) -> ty::UniverseIndex {
|
||||||
match self {
|
match self {
|
||||||
CanonicalVarKind::Ty(kind) => match kind {
|
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
|
||||||
CanonicalTyVarKind::General(ui) => ui,
|
CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
|
||||||
CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT,
|
ty::UniverseIndex::ROOT
|
||||||
},
|
}
|
||||||
|
CanonicalVarKind::Effect => ty::UniverseIndex::ROOT,
|
||||||
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
|
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
|
||||||
CanonicalVarKind::Region(ui) => ui,
|
CanonicalVarKind::Region(ui) => ui,
|
||||||
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
|
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
|
||||||
@ -259,15 +265,14 @@ impl<'tcx> CanonicalVarKind<'tcx> {
|
|||||||
/// the updated universe is not the root.
|
/// the updated universe is not the root.
|
||||||
pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarKind<'tcx> {
|
pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarKind<'tcx> {
|
||||||
match self {
|
match self {
|
||||||
CanonicalVarKind::Ty(kind) => match kind {
|
CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => {
|
||||||
CanonicalTyVarKind::General(_) => {
|
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
|
||||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
|
}
|
||||||
}
|
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
|
||||||
CanonicalTyVarKind::Int | CanonicalTyVarKind::Float => {
|
| CanonicalVarKind::Effect => {
|
||||||
assert_eq!(ui, ty::UniverseIndex::ROOT);
|
assert_eq!(ui, ty::UniverseIndex::ROOT);
|
||||||
CanonicalVarKind::Ty(kind)
|
self
|
||||||
}
|
}
|
||||||
},
|
|
||||||
CanonicalVarKind::PlaceholderTy(placeholder) => {
|
CanonicalVarKind::PlaceholderTy(placeholder) => {
|
||||||
CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ui, ..placeholder })
|
CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ui, ..placeholder })
|
||||||
}
|
}
|
||||||
@ -454,6 +459,13 @@ impl<'tcx> CanonicalVarValues<'tcx> {
|
|||||||
};
|
};
|
||||||
ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into()
|
ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into()
|
||||||
}
|
}
|
||||||
|
CanonicalVarKind::Effect => ty::Const::new_bound(
|
||||||
|
tcx,
|
||||||
|
ty::INNERMOST,
|
||||||
|
ty::BoundVar::from_usize(i),
|
||||||
|
tcx.types.bool,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
CanonicalVarKind::Const(_, ty)
|
CanonicalVarKind::Const(_, ty)
|
||||||
| CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound(
|
| CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound(
|
||||||
tcx,
|
tcx,
|
||||||
|
@ -188,3 +188,53 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// values for the effect inference variable
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum EffectVarValue<'tcx> {
|
||||||
|
/// The host effect is on, enabling access to syscalls, filesystem access, etc.
|
||||||
|
Host,
|
||||||
|
/// The host effect is off. Execution is restricted to const operations only.
|
||||||
|
NoHost,
|
||||||
|
Const(ty::Const<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> EffectVarValue<'tcx> {
|
||||||
|
pub fn as_const(self, tcx: TyCtxt<'tcx>) -> ty::Const<'tcx> {
|
||||||
|
match self {
|
||||||
|
EffectVarValue::Host => tcx.consts.true_,
|
||||||
|
EffectVarValue::NoHost => tcx.consts.false_,
|
||||||
|
EffectVarValue::Const(c) => c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
|
||||||
|
type Error = (EffectVarValue<'tcx>, EffectVarValue<'tcx>);
|
||||||
|
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
|
||||||
|
match (value1, value2) {
|
||||||
|
(EffectVarValue::Host, EffectVarValue::Host) => Ok(EffectVarValue::Host),
|
||||||
|
(EffectVarValue::NoHost, EffectVarValue::NoHost) => Ok(EffectVarValue::NoHost),
|
||||||
|
(EffectVarValue::NoHost | EffectVarValue::Host, _)
|
||||||
|
| (_, EffectVarValue::NoHost | EffectVarValue::Host) => Err((*value1, *value2)),
|
||||||
|
(EffectVarValue::Const(_), EffectVarValue::Const(_)) => {
|
||||||
|
bug!("equating two const variables, both of which have known values")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> UnifyKey for ty::EffectVid<'tcx> {
|
||||||
|
type Value = Option<EffectVarValue<'tcx>>;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self) -> u32 {
|
||||||
|
self.index
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn from_index(i: u32) -> Self {
|
||||||
|
ty::EffectVid { index: i, phantom: PhantomData }
|
||||||
|
}
|
||||||
|
fn tag() -> &'static str {
|
||||||
|
"EffectVid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -55,6 +55,11 @@ static_assert_size!(super::ConstKind<'_>, 32);
|
|||||||
pub enum InferConst<'tcx> {
|
pub enum InferConst<'tcx> {
|
||||||
/// Infer the value of the const.
|
/// Infer the value of the const.
|
||||||
Var(ty::ConstVid<'tcx>),
|
Var(ty::ConstVid<'tcx>),
|
||||||
|
/// Infer the value of the effect.
|
||||||
|
///
|
||||||
|
/// For why this is separate from the `Var` variant above, see the
|
||||||
|
/// documentation on `EffectVid`.
|
||||||
|
EffectVar(ty::EffectVid<'tcx>),
|
||||||
/// A fresh const variable. See `infer::freshen` for more details.
|
/// A fresh const variable. See `infer::freshen` for more details.
|
||||||
Fresh(u32),
|
Fresh(u32),
|
||||||
}
|
}
|
||||||
@ -62,7 +67,9 @@ pub enum InferConst<'tcx> {
|
|||||||
impl<CTX> HashStable<CTX> for InferConst<'_> {
|
impl<CTX> HashStable<CTX> for InferConst<'_> {
|
||||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||||
match self {
|
match self {
|
||||||
InferConst::Var(_) => panic!("const variables should not be hashed: {self:?}"),
|
InferConst::Var(_) | InferConst::EffectVar(_) => {
|
||||||
|
panic!("const variables should not be hashed: {self:?}")
|
||||||
|
}
|
||||||
InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
|
InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,7 +324,9 @@ impl FlagComputation {
|
|||||||
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
|
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
|
||||||
match infer {
|
match infer {
|
||||||
InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
|
InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
|
||||||
InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
|
InferConst::Var(_) | InferConst::EffectVar(_) => {
|
||||||
|
self.add_flags(TypeFlags::HAS_CT_INFER)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::ConstKind::Bound(debruijn, _) => {
|
ty::ConstKind::Bound(debruijn, _) => {
|
||||||
|
@ -12,7 +12,7 @@ use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamT
|
|||||||
pub enum GenericParamDefKind {
|
pub enum GenericParamDefKind {
|
||||||
Lifetime,
|
Lifetime,
|
||||||
Type { has_default: bool, synthetic: bool },
|
Type { has_default: bool, synthetic: bool },
|
||||||
Const { has_default: bool },
|
Const { has_default: bool, is_host_effect: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenericParamDefKind {
|
impl GenericParamDefKind {
|
||||||
@ -87,7 +87,7 @@ impl GenericParamDef {
|
|||||||
GenericParamDefKind::Type { has_default, .. } if has_default => {
|
GenericParamDefKind::Type { has_default, .. } if has_default => {
|
||||||
Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
|
Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
|
||||||
}
|
}
|
||||||
GenericParamDefKind::Const { has_default } if has_default => {
|
GenericParamDefKind::Const { has_default, .. } if has_default => {
|
||||||
Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
|
Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -187,7 +187,7 @@ impl<'tcx> Generics {
|
|||||||
GenericParamDefKind::Type { has_default, .. } => {
|
GenericParamDefKind::Type { has_default, .. } => {
|
||||||
own_defaults.types += has_default as usize;
|
own_defaults.types += has_default as usize;
|
||||||
}
|
}
|
||||||
GenericParamDefKind::Const { has_default } => {
|
GenericParamDefKind::Const { has_default, .. } => {
|
||||||
own_defaults.consts += has_default as usize;
|
own_defaults.consts += has_default as usize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,9 +98,9 @@ pub use self::sty::BoundRegionKind::*;
|
|||||||
pub use self::sty::{
|
pub use self::sty::{
|
||||||
AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
|
AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
|
||||||
BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, ConstKind, ConstVid,
|
BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, ConstKind, ConstVid,
|
||||||
EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
|
EarlyBoundRegion, EffectVid, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef,
|
||||||
FreeRegion, GenSig, GeneratorArgs, GeneratorArgsParts, InlineConstArgs, InlineConstArgsParts,
|
FnSig, FreeRegion, GenSig, GeneratorArgs, GeneratorArgsParts, InlineConstArgs,
|
||||||
ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
|
InlineConstArgsParts, ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
|
||||||
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, Region, RegionKind, RegionVid,
|
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, Region, RegionKind, RegionVid,
|
||||||
TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
|
TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
|
||||||
};
|
};
|
||||||
|
@ -138,6 +138,12 @@ impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for ty::EffectVid<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "?{}e", self.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
|
impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
with_no_trimmed_paths!(fmt::Display::fmt(self, f))
|
with_no_trimmed_paths!(fmt::Display::fmt(self, f))
|
||||||
@ -253,6 +259,7 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
InferConst::Var(var) => write!(f, "{var:?}"),
|
InferConst::Var(var) => write!(f, "{var:?}"),
|
||||||
|
InferConst::EffectVar(var) => write!(f, "{var:?}"),
|
||||||
InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
|
InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,6 +274,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
|
|||||||
None => write!(f, "{:?}", this.data),
|
None => write!(f, "{:?}", this.data),
|
||||||
Some(universe) => match *this.data {
|
Some(universe) => match *this.data {
|
||||||
Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()),
|
Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()),
|
||||||
|
EffectVar(vid) => write!(f, "?{}_{}e", vid.index, universe.index()),
|
||||||
Fresh(_) => {
|
Fresh(_) => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -1577,6 +1577,20 @@ pub struct ConstVid<'tcx> {
|
|||||||
pub phantom: PhantomData<&'tcx ()>,
|
pub phantom: PhantomData<&'tcx ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An **effect** **v**ariable **ID**.
|
||||||
|
///
|
||||||
|
/// Handling effect infer variables happens separately from const infer variables
|
||||||
|
/// because we do not want to reuse any of the const infer machinery. If we try to
|
||||||
|
/// relate an effect variable with a normal one, we would ICE, which can catch bugs
|
||||||
|
/// where we are not correctly using the effect var for an effect param. Fallback
|
||||||
|
/// is also implemented on top of having separate effect and normal const variables.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[derive(TyEncodable, TyDecodable)]
|
||||||
|
pub struct EffectVid<'tcx> {
|
||||||
|
pub index: u32,
|
||||||
|
pub phantom: PhantomData<&'tcx ()>,
|
||||||
|
}
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
/// A **region** (lifetime) **v**ariable **ID**.
|
/// A **region** (lifetime) **v**ariable **ID**.
|
||||||
#[derive(HashStable)]
|
#[derive(HashStable)]
|
||||||
|
@ -836,7 +836,7 @@ impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
|
|||||||
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
|
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GenericParamDefKind::Const { has_default } => {
|
GenericParamDefKind::Const { has_default, .. } => {
|
||||||
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
|
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
|
||||||
if has_default {
|
if has_default {
|
||||||
self.visit(
|
self.visit(
|
||||||
|
@ -1297,7 +1297,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind {
|
|||||||
ty::GenericParamDefKind::Type { has_default, synthetic } => {
|
ty::GenericParamDefKind::Type { has_default, synthetic } => {
|
||||||
GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic }
|
GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic }
|
||||||
}
|
}
|
||||||
ty::GenericParamDefKind::Const { has_default } => {
|
ty::GenericParamDefKind::Const { has_default, is_host_effect: _ } => {
|
||||||
GenericParamDefKind::Const { has_default: *has_default }
|
GenericParamDefKind::Const { has_default: *has_default }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,6 +365,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
|
|||||||
// FIXME: we should fold this ty eventually
|
// FIXME: we should fold this ty eventually
|
||||||
CanonicalVarKind::Const(ui, c.ty())
|
CanonicalVarKind::Const(ui, c.ty())
|
||||||
}
|
}
|
||||||
|
ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => {
|
||||||
|
bug!("effect var has no universe")
|
||||||
|
}
|
||||||
ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
|
ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
|
||||||
bug!("fresh var during canonicalization: {c:?}")
|
bug!("fresh var during canonicalization: {c:?}")
|
||||||
}
|
}
|
||||||
|
@ -542,7 +542,7 @@ fn clean_generic_param_def<'tcx>(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ty::GenericParamDefKind::Const { has_default } => (
|
ty::GenericParamDefKind::Const { has_default, .. } => (
|
||||||
def.name,
|
def.name,
|
||||||
GenericParamDefKind::Const {
|
GenericParamDefKind::Const {
|
||||||
ty: Box::new(clean_middle_ty(
|
ty: Box::new(clean_middle_ty(
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(const_trait_impl, effects)]
|
||||||
|
|
||||||
|
pub const fn owo() {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = owo;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user