mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Auto merge of #74040 - lcnr:const-occurs-check, r=nikomatsakis
fix unification of const variables
r? `@nikomatsakis` `@varkor` `@eddyb` let's just ping everyone here 😅
This commit is contained in:
commit
e0bf356f9e
@ -45,7 +45,7 @@ use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
|||||||
use rustc_middle::ty::subst::SubstsRef;
|
use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_middle::ty::{IntType, UintType};
|
use rustc_middle::ty::{IntType, UintType};
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
/// Small-storage-optimized implementation of a map
|
/// Small-storage-optimized implementation of a map
|
||||||
/// made specifically for caching results.
|
/// made specifically for caching results.
|
||||||
@ -219,11 +219,11 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
|
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
|
||||||
return self.unify_const_variable(a_is_expected, vid, b);
|
return self.unify_const_variable(relation.param_env(), vid, b, a_is_expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
||||||
return self.unify_const_variable(!a_is_expected, vid, a);
|
return self.unify_const_variable(relation.param_env(), vid, a, !a_is_expected);
|
||||||
}
|
}
|
||||||
(ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => {
|
(ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => {
|
||||||
// FIXME(#59490): Need to remove the leak check to accommodate
|
// FIXME(#59490): Need to remove the leak check to accommodate
|
||||||
@ -247,17 +247,66 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||||||
ty::relate::super_relate_consts(relation, a, b)
|
ty::relate::super_relate_consts(relation, a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unify_const_variable(
|
/// Unifies the const variable `target_vid` with the given constant.
|
||||||
|
///
|
||||||
|
/// This also tests if the given const `ct` contains an inference variable which was previously
|
||||||
|
/// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct`
|
||||||
|
/// would result in an infinite type as we continously replace an inference variable
|
||||||
|
/// in `ct` with `ct` itself.
|
||||||
|
///
|
||||||
|
/// This is especially important as unevaluated consts use their parents generics.
|
||||||
|
/// They therefore often contain unused substs, making these errors far more likely.
|
||||||
|
///
|
||||||
|
/// A good example of this is the following:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #![feature(const_generics)]
|
||||||
|
///
|
||||||
|
/// fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] {
|
||||||
|
/// todo!()
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut arr = Default::default();
|
||||||
|
/// arr = bind(arr);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics
|
||||||
|
/// of `fn bind` (meaning that its substs contain `N`).
|
||||||
|
///
|
||||||
|
/// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`.
|
||||||
|
/// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`.
|
||||||
|
///
|
||||||
|
/// As `3 + 4` contains `N` in its substs, this must not succeed.
|
||||||
|
///
|
||||||
|
/// See `src/test/ui/const-generics/occurs-check/` for more examples where this is relevant.
|
||||||
|
fn unify_const_variable(
|
||||||
&self,
|
&self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
target_vid: ty::ConstVid<'tcx>,
|
||||||
|
ct: &'tcx ty::Const<'tcx>,
|
||||||
vid_is_expected: bool,
|
vid_is_expected: bool,
|
||||||
vid: ty::ConstVid<'tcx>,
|
|
||||||
value: &'tcx ty::Const<'tcx>,
|
|
||||||
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
|
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
|
||||||
|
let (for_universe, span) = {
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
let variable_table = &mut inner.const_unification_table();
|
||||||
|
let var_value = variable_table.probe_value(target_vid);
|
||||||
|
match var_value.val {
|
||||||
|
ConstVariableValue::Known { value } => {
|
||||||
|
bug!("instantiating {:?} which has a known value {:?}", target_vid, value)
|
||||||
|
}
|
||||||
|
ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let value = ConstInferUnifier { infcx: self, span, param_env, for_universe, target_vid }
|
||||||
|
.relate(ct, ct)?;
|
||||||
|
|
||||||
self.inner
|
self.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.const_unification_table()
|
.const_unification_table()
|
||||||
.unify_var_value(
|
.unify_var_value(
|
||||||
vid,
|
target_vid,
|
||||||
ConstVarValue {
|
ConstVarValue {
|
||||||
origin: ConstVariableOrigin {
|
origin: ConstVariableOrigin {
|
||||||
kind: ConstVariableOriginKind::ConstInference,
|
kind: ConstVariableOriginKind::ConstInference,
|
||||||
@ -266,8 +315,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||||||
val: ConstVariableValue::Known { value },
|
val: ConstVariableValue::Known { value },
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.map_err(|e| const_unification_error(vid_is_expected, e))?;
|
.map(|()| value)
|
||||||
Ok(value)
|
.map_err(|e| const_unification_error(vid_is_expected, e))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify_integral_variable(
|
fn unify_integral_variable(
|
||||||
@ -422,7 +471,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||||||
|
|
||||||
let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
|
let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
|
||||||
v @ TypeVariableValue::Known { .. } => {
|
v @ TypeVariableValue::Known { .. } => {
|
||||||
panic!("instantiating {:?} which has a known value {:?}", for_vid, v,)
|
bug!("instantiating {:?} which has a known value {:?}", for_vid, v,)
|
||||||
}
|
}
|
||||||
TypeVariableValue::Unknown { universe } => universe,
|
TypeVariableValue::Unknown { universe } => universe,
|
||||||
};
|
};
|
||||||
@ -740,7 +789,6 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(c),
|
|
||||||
_ => relate::super_relate_consts(self, c, c),
|
_ => relate::super_relate_consts(self, c, c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -790,3 +838,175 @@ fn float_unification_error<'tcx>(
|
|||||||
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
|
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
|
||||||
TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, a, b))
|
TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ConstInferUnifier<'cx, 'tcx> {
|
||||||
|
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||||
|
|
||||||
|
span: Span,
|
||||||
|
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
|
||||||
|
for_universe: ty::UniverseIndex,
|
||||||
|
|
||||||
|
/// The vid of the const variable that is in the process of being
|
||||||
|
/// instantiated; if we find this within the const we are folding,
|
||||||
|
/// that means we would have created a cyclic const.
|
||||||
|
target_vid: ty::ConstVid<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use `TypeRelation` here to propagate `RelateResult` upwards.
|
||||||
|
//
|
||||||
|
// Both inputs are expected to be the same.
|
||||||
|
impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
|
||||||
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
|
self.infcx.tcx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||||
|
self.param_env
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tag(&self) -> &'static str {
|
||||||
|
"ConstInferUnifier"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a_is_expected(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn relate_with_variance<T: Relate<'tcx>>(
|
||||||
|
&mut self,
|
||||||
|
_variance: ty::Variance,
|
||||||
|
a: T,
|
||||||
|
b: T,
|
||||||
|
) -> RelateResult<'tcx, T> {
|
||||||
|
// We don't care about variance here.
|
||||||
|
self.relate(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binders<T>(
|
||||||
|
&mut self,
|
||||||
|
a: ty::Binder<T>,
|
||||||
|
b: ty::Binder<T>,
|
||||||
|
) -> RelateResult<'tcx, ty::Binder<T>>
|
||||||
|
where
|
||||||
|
T: Relate<'tcx>,
|
||||||
|
{
|
||||||
|
Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||||
|
debug_assert_eq!(t, _t);
|
||||||
|
debug!("ConstInferUnifier: t={:?}", t);
|
||||||
|
|
||||||
|
match t.kind() {
|
||||||
|
&ty::Infer(ty::TyVar(vid)) => {
|
||||||
|
let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid);
|
||||||
|
let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid);
|
||||||
|
match probe {
|
||||||
|
TypeVariableValue::Known { value: u } => {
|
||||||
|
debug!("ConstOccursChecker: known value {:?}", u);
|
||||||
|
self.tys(u, u)
|
||||||
|
}
|
||||||
|
TypeVariableValue::Unknown { universe } => {
|
||||||
|
if self.for_universe.can_name(universe) {
|
||||||
|
return Ok(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
let origin =
|
||||||
|
*self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
|
||||||
|
let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var(
|
||||||
|
self.for_universe,
|
||||||
|
false,
|
||||||
|
origin,
|
||||||
|
);
|
||||||
|
let u = self.tcx().mk_ty_var(new_var_id);
|
||||||
|
debug!(
|
||||||
|
"ConstInferUnifier: replacing original vid={:?} with new={:?}",
|
||||||
|
vid, u
|
||||||
|
);
|
||||||
|
Ok(u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => relate::super_relate_tys(self, t, t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn regions(
|
||||||
|
&mut self,
|
||||||
|
r: ty::Region<'tcx>,
|
||||||
|
_r: ty::Region<'tcx>,
|
||||||
|
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||||
|
debug_assert_eq!(r, _r);
|
||||||
|
debug!("ConstInferUnifier: r={:?}", r);
|
||||||
|
|
||||||
|
match r {
|
||||||
|
// Never make variables for regions bound within the type itself,
|
||||||
|
// nor for erased regions.
|
||||||
|
ty::ReLateBound(..) | ty::ReErased => {
|
||||||
|
return Ok(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::RePlaceholder(..)
|
||||||
|
| ty::ReVar(..)
|
||||||
|
| ty::ReEmpty(_)
|
||||||
|
| ty::ReStatic
|
||||||
|
| ty::ReEarlyBound(..)
|
||||||
|
| ty::ReFree(..) => {
|
||||||
|
// see common code below
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let r_universe = self.infcx.universe_of_region(r);
|
||||||
|
if self.for_universe.can_name(r_universe) {
|
||||||
|
return Ok(r);
|
||||||
|
} else {
|
||||||
|
// FIXME: This is non-ideal because we don't give a
|
||||||
|
// very descriptive origin for this region variable.
|
||||||
|
Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consts(
|
||||||
|
&mut self,
|
||||||
|
c: &'tcx ty::Const<'tcx>,
|
||||||
|
_c: &'tcx ty::Const<'tcx>,
|
||||||
|
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
|
||||||
|
debug_assert_eq!(c, _c);
|
||||||
|
debug!("ConstInferUnifier: c={:?}", c);
|
||||||
|
|
||||||
|
match c.val {
|
||||||
|
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
||||||
|
let mut inner = self.infcx.inner.borrow_mut();
|
||||||
|
let variable_table = &mut inner.const_unification_table();
|
||||||
|
|
||||||
|
// Check if the current unification would end up
|
||||||
|
// unifying `target_vid` with a const which contains
|
||||||
|
// an inference variable which is unioned with `target_vid`.
|
||||||
|
//
|
||||||
|
// Not doing so can easily result in stack overflows.
|
||||||
|
if variable_table.unioned(self.target_vid, vid) {
|
||||||
|
return Err(TypeError::CyclicConst(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
let var_value = variable_table.probe_value(vid);
|
||||||
|
match var_value.val {
|
||||||
|
ConstVariableValue::Known { value: u } => self.consts(u, u),
|
||||||
|
ConstVariableValue::Unknown { universe } => {
|
||||||
|
if self.for_universe.can_name(universe) {
|
||||||
|
Ok(c)
|
||||||
|
} else {
|
||||||
|
let new_var_id = variable_table.new_key(ConstVarValue {
|
||||||
|
origin: var_value.origin,
|
||||||
|
val: ConstVariableValue::Unknown { universe: self.for_universe },
|
||||||
|
});
|
||||||
|
Ok(self.tcx().mk_const_var(new_var_id, c.ty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => relate::super_relate_consts(self, c, c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -56,6 +56,7 @@ pub enum TypeError<'tcx> {
|
|||||||
/// created a cycle (because it appears somewhere within that
|
/// created a cycle (because it appears somewhere within that
|
||||||
/// type).
|
/// type).
|
||||||
CyclicTy(Ty<'tcx>),
|
CyclicTy(Ty<'tcx>),
|
||||||
|
CyclicConst(&'tcx ty::Const<'tcx>),
|
||||||
ProjectionMismatched(ExpectedFound<DefId>),
|
ProjectionMismatched(ExpectedFound<DefId>),
|
||||||
ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
|
ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
|
||||||
ObjectUnsafeCoercion(DefId),
|
ObjectUnsafeCoercion(DefId),
|
||||||
@ -100,6 +101,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
|||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
CyclicTy(_) => write!(f, "cyclic type of infinite size"),
|
CyclicTy(_) => write!(f, "cyclic type of infinite size"),
|
||||||
|
CyclicConst(_) => write!(f, "encountered a self-referencing constant"),
|
||||||
Mismatch => write!(f, "types differ"),
|
Mismatch => write!(f, "types differ"),
|
||||||
UnsafetyMismatch(values) => {
|
UnsafetyMismatch(values) => {
|
||||||
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
|
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
|
||||||
@ -195,9 +197,9 @@ impl<'tcx> TypeError<'tcx> {
|
|||||||
pub fn must_include_note(&self) -> bool {
|
pub fn must_include_note(&self) -> bool {
|
||||||
use self::TypeError::*;
|
use self::TypeError::*;
|
||||||
match self {
|
match self {
|
||||||
CyclicTy(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
|
CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_)
|
||||||
| Sorts(_) | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_)
|
| FixedArraySize(_) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
|
||||||
| TargetFeatureCast(_) => false,
|
| VariadicMismatch(_) | TargetFeatureCast(_) => false,
|
||||||
|
|
||||||
Mutability
|
Mutability
|
||||||
| TupleSize(_)
|
| TupleSize(_)
|
||||||
|
@ -689,6 +689,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
|
|||||||
Traits(x) => Traits(x),
|
Traits(x) => Traits(x),
|
||||||
VariadicMismatch(x) => VariadicMismatch(x),
|
VariadicMismatch(x) => VariadicMismatch(x),
|
||||||
CyclicTy(t) => return tcx.lift(&t).map(|t| CyclicTy(t)),
|
CyclicTy(t) => return tcx.lift(&t).map(|t| CyclicTy(t)),
|
||||||
|
CyclicConst(ct) => return tcx.lift(&ct).map(|ct| CyclicConst(ct)),
|
||||||
ProjectionMismatched(x) => ProjectionMismatched(x),
|
ProjectionMismatched(x) => ProjectionMismatched(x),
|
||||||
Sorts(ref x) => return tcx.lift(x).map(Sorts),
|
Sorts(ref x) => return tcx.lift(x).map(Sorts),
|
||||||
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
|
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
|
||||||
|
@ -482,13 +482,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
|
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
|
||||||
pub(super) fn resolve(
|
pub(super) fn resolve(
|
||||||
&self,
|
&self,
|
||||||
def_id: DefId,
|
def: ty::WithOptConstParam<DefId>,
|
||||||
substs: SubstsRef<'tcx>,
|
substs: SubstsRef<'tcx>,
|
||||||
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
|
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
|
||||||
trace!("resolve: {:?}, {:#?}", def_id, substs);
|
trace!("resolve: {:?}, {:#?}", def, substs);
|
||||||
trace!("param_env: {:#?}", self.param_env);
|
trace!("param_env: {:#?}", self.param_env);
|
||||||
trace!("substs: {:#?}", substs);
|
trace!("substs: {:#?}", substs);
|
||||||
match ty::Instance::resolve(*self.tcx, self.param_env, def_id, substs) {
|
match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) {
|
||||||
Ok(Some(instance)) => Ok(instance),
|
Ok(Some(instance)) => Ok(instance),
|
||||||
Ok(None) => throw_inval!(TooGeneric),
|
Ok(None) => throw_inval!(TooGeneric),
|
||||||
|
|
||||||
|
@ -552,7 +552,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
|
ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
|
||||||
ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)),
|
ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)),
|
||||||
ty::ConstKind::Unevaluated(def, substs, promoted) => {
|
ty::ConstKind::Unevaluated(def, substs, promoted) => {
|
||||||
let instance = self.resolve(def.did, substs)?;
|
let instance = self.resolve(def, substs)?;
|
||||||
return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into());
|
return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into());
|
||||||
}
|
}
|
||||||
ty::ConstKind::Infer(..)
|
ty::ConstKind::Infer(..)
|
||||||
|
@ -64,7 +64,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
}
|
}
|
||||||
ty::FnDef(def_id, substs) => {
|
ty::FnDef(def_id, substs) => {
|
||||||
let sig = func.layout.ty.fn_sig(*self.tcx);
|
let sig = func.layout.ty.fn_sig(*self.tcx);
|
||||||
(FnVal::Instance(self.resolve(def_id, substs)?), sig.abi())
|
(
|
||||||
|
FnVal::Instance(
|
||||||
|
self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?,
|
||||||
|
),
|
||||||
|
sig.abi(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ => span_bug!(
|
_ => span_bug!(
|
||||||
terminator.source_info.span,
|
terminator.source_info.span,
|
||||||
|
18
src/test/ui/const-generics/issues/issue-69654-run-pass.rs
Normal file
18
src/test/ui/const-generics/issues/issue-69654-run-pass.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// run-pass
|
||||||
|
#![feature(const_generics)]
|
||||||
|
#![allow(incomplete_features, unused_braces)]
|
||||||
|
|
||||||
|
trait Bar<T> {}
|
||||||
|
impl<T> Bar<T> for [u8; {7}] {}
|
||||||
|
|
||||||
|
struct Foo<const N: usize> {}
|
||||||
|
impl<const N: usize> Foo<N>
|
||||||
|
where
|
||||||
|
[u8; N]: Bar<[(); N]>,
|
||||||
|
{
|
||||||
|
fn foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Foo::foo();
|
||||||
|
}
|
18
src/test/ui/const-generics/issues/issue-69654.rs
Normal file
18
src/test/ui/const-generics/issues/issue-69654.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#![feature(const_generics)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
trait Bar<T> {}
|
||||||
|
impl<T> Bar<T> for [u8; T] {}
|
||||||
|
//~^ ERROR expected value, found type parameter `T`
|
||||||
|
|
||||||
|
struct Foo<const N: usize> {}
|
||||||
|
impl<const N: usize> Foo<N>
|
||||||
|
where
|
||||||
|
[u8; N]: Bar<[(); N]>,
|
||||||
|
{
|
||||||
|
fn foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Foo::foo();
|
||||||
|
}
|
9
src/test/ui/const-generics/issues/issue-69654.stderr
Normal file
9
src/test/ui/const-generics/issues/issue-69654.stderr
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
error[E0423]: expected value, found type parameter `T`
|
||||||
|
--> $DIR/issue-69654.rs:5:25
|
||||||
|
|
|
||||||
|
LL | impl<T> Bar<T> for [u8; T] {}
|
||||||
|
| ^ not a value
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0423`.
|
17
src/test/ui/const-generics/occurs-check/bind-param.rs
Normal file
17
src/test/ui/const-generics/occurs-check/bind-param.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// build-pass
|
||||||
|
#![feature(const_generics)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// This test does not use any "unevaluated" consts, so it should compile just fine.
|
||||||
|
|
||||||
|
fn bind<const N: usize>(value: [u8; N]) -> [u8; N] {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sink(_: [u8; 5]) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut arr = Default::default();
|
||||||
|
arr = bind(arr);
|
||||||
|
sink(arr);
|
||||||
|
}
|
18
src/test/ui/const-generics/occurs-check/unify-fixpoint.rs
Normal file
18
src/test/ui/const-generics/occurs-check/unify-fixpoint.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
|
||||||
|
|
||||||
|
// It depends on how we normalize constants and how const equate works if this
|
||||||
|
// compiles.
|
||||||
|
//
|
||||||
|
// Please ping @lcnr if the output if this test changes.
|
||||||
|
|
||||||
|
|
||||||
|
fn bind<const N: usize>(value: [u8; N + 2]) -> [u8; N * 2] {
|
||||||
|
//~^ ERROR constant expression depends on a generic parameter
|
||||||
|
//~| ERROR constant expression depends on a generic parameter
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut arr = Default::default();
|
||||||
|
arr = bind::<2>(arr);
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/unify-fixpoint.rs:1:12
|
||||||
|
|
|
||||||
|
LL | #![feature(const_generics)]
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
|
||||||
|
|
||||||
|
error: constant expression depends on a generic parameter
|
||||||
|
--> $DIR/unify-fixpoint.rs:9:32
|
||||||
|
|
|
||||||
|
LL | fn bind<const N: usize>(value: [u8; N + 2]) -> [u8; N * 2] {
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this may fail depending on what value the parameter takes
|
||||||
|
|
||||||
|
error: constant expression depends on a generic parameter
|
||||||
|
--> $DIR/unify-fixpoint.rs:9:48
|
||||||
|
|
|
||||||
|
LL | fn bind<const N: usize>(value: [u8; N + 2]) -> [u8; N * 2] {
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this may fail depending on what value the parameter takes
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors; 1 warning emitted
|
||||||
|
|
17
src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs
Normal file
17
src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#![feature(const_generics)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// This test would try to unify `N` with `N + 1` which must fail the occurs check.
|
||||||
|
|
||||||
|
fn bind<const N: usize>(value: [u8; N]) -> [u8; N + 1] {
|
||||||
|
//~^ ERROR constant expression depends on a generic parameter
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sink(_: [u8; 5]) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut arr = Default::default();
|
||||||
|
arr = bind(arr);
|
||||||
|
sink(arr);
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
error: constant expression depends on a generic parameter
|
||||||
|
--> $DIR/unify-n-nplusone.rs:6:44
|
||||||
|
|
|
||||||
|
LL | fn bind<const N: usize>(value: [u8; N]) -> [u8; N + 1] {
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this may fail depending on what value the parameter takes
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
14
src/test/ui/const-generics/occurs-check/unused-substs-1.rs
Normal file
14
src/test/ui/const-generics/occurs-check/unused-substs-1.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// build-pass
|
||||||
|
#![feature(const_generics)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
trait Bar<const M: usize> {}
|
||||||
|
impl<const N: usize> Bar<N> for A<{ 6 + 1 }> {}
|
||||||
|
|
||||||
|
struct A<const N: usize>
|
||||||
|
where
|
||||||
|
A<N>: Bar<N>;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = A;
|
||||||
|
}
|
27
src/test/ui/const-generics/occurs-check/unused-substs-2.rs
Normal file
27
src/test/ui/const-generics/occurs-check/unused-substs-2.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// check-pass
|
||||||
|
#![feature(const_generics)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// The goal is is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst.
|
||||||
|
//
|
||||||
|
// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty<ct>` we introduced an
|
||||||
|
// artificial inference cycle.
|
||||||
|
struct Foo<const N: usize>;
|
||||||
|
|
||||||
|
trait Bind<T> {
|
||||||
|
fn bind() -> (T, Self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `N` has to be `ConstKind::Unevaluated`.
|
||||||
|
impl<T> Bind<T> for Foo<{ 6 + 1 }> {
|
||||||
|
fn bind() -> (T, Self) {
|
||||||
|
(panic!(), Foo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (mut t, foo) = Foo::bind();
|
||||||
|
// `t` is `ty::Infer(TyVar(_#1t))`
|
||||||
|
// `foo` contains `ty::Infer(TyVar(_#1t))` in its substs
|
||||||
|
t = foo;
|
||||||
|
}
|
18
src/test/ui/const-generics/occurs-check/unused-substs-3.rs
Normal file
18
src/test/ui/const-generics/occurs-check/unused-substs-3.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// check-pass
|
||||||
|
#![feature(const_generics)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// The goal is is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst.
|
||||||
|
//
|
||||||
|
// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty<ct>` we introduced an
|
||||||
|
// artificial inference cycle.
|
||||||
|
fn bind<T>() -> (T, [u8; 6 + 1]) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (mut t, foo) = bind();
|
||||||
|
// `t` is `ty::Infer(TyVar(_#1t))`
|
||||||
|
// `foo` contains `ty::Infer(TyVar(_#1t))` in its substs
|
||||||
|
t = foo;
|
||||||
|
}
|
12
src/test/ui/const-generics/occurs-check/unused-substs-4.rs
Normal file
12
src/test/ui/const-generics/occurs-check/unused-substs-4.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// build-pass
|
||||||
|
#![feature(const_generics)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut arr = Default::default();
|
||||||
|
arr = bind(arr);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user