Rollup merge of #123170 - compiler-errors:const-statics, r=lcnr
Replace regions in const canonical vars' types with `'static` in next-solver canonicalizer We shouldn't ever have non-static regions in consts on stable (or really any regions at all, lol). The test I committed is less minimal than, e.g., https://github.com/rust-lang/rust/issues/123155?notification_referrer_id=NT_kwDOADgQyrMxMDAzNDU4MDI0OTozNjc0MzE0#issuecomment-2025472029 -- however, I believe that it actually portrays the underlying issue here a bit better than that one. In the linked issue, we end up emitting a normalizes-to predicate for a const placeholder because we don't actually unify `false` and `""`. In the test I committed, we emit a normalizes-to predicate as a part of actually solving a negative coherence goal. Fixes #123155 Fixes #118783 r? lcnr
This commit is contained in:
commit
93f1443280
7 changed files with 120 additions and 73 deletions
|
@ -140,6 +140,10 @@ impl<'tcx> rustc_type_ir::new::Region<TyCtxt<'tcx>> for Region<'tcx> {
|
||||||
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
|
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
|
||||||
Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon })
|
Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_static(tcx: TyCtxt<'tcx>) -> Self {
|
||||||
|
tcx.lifetimes.re_static
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Region utilities
|
/// Region utilities
|
||||||
|
|
|
@ -296,10 +296,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
||||||
Region::new_anon_bound(self.interner(), self.binder_index, var)
|
Region::new_anon_bound(self.interner(), self.binder_index, var)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_ty(&mut self, t: I::Ty) -> I::Ty
|
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
|
||||||
where
|
|
||||||
I::Ty: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
let kind = match t.kind() {
|
let kind = match t.kind() {
|
||||||
ty::Infer(i) => match i {
|
ty::Infer(i) => match i {
|
||||||
ty::TyVar(vid) => {
|
ty::TyVar(vid) => {
|
||||||
|
@ -378,47 +375,48 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
||||||
Ty::new_anon_bound(self.interner(), self.binder_index, var)
|
Ty::new_anon_bound(self.interner(), self.binder_index, var)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_const(&mut self, c: I::Const) -> I::Const
|
fn fold_const(&mut self, c: I::Const) -> I::Const {
|
||||||
where
|
// We could canonicalize all consts with static types, but the only ones we
|
||||||
I::Const: TypeSuperFoldable<I>,
|
// *really* need to worry about are the ones that we end up putting into `CanonicalVarKind`
|
||||||
{
|
// since canonical vars can't reference other canonical vars.
|
||||||
|
let ty = c
|
||||||
|
.ty()
|
||||||
|
.fold_with(&mut RegionsToStatic { interner: self.interner(), binder: ty::INNERMOST });
|
||||||
let kind = match c.kind() {
|
let kind = match c.kind() {
|
||||||
ty::ConstKind::Infer(i) => {
|
ty::ConstKind::Infer(i) => match i {
|
||||||
// FIXME: we should fold the ty too eventually
|
ty::InferConst::Var(vid) => {
|
||||||
match i {
|
assert_eq!(
|
||||||
ty::InferConst::Var(vid) => {
|
self.infcx.root_ct_var(vid),
|
||||||
assert_eq!(
|
vid,
|
||||||
self.infcx.root_ct_var(vid),
|
"region vid should have been resolved fully before canonicalization"
|
||||||
vid,
|
);
|
||||||
"region vid should have been resolved fully before canonicalization"
|
assert_eq!(
|
||||||
);
|
self.infcx.probe_ct_var(vid),
|
||||||
assert_eq!(
|
None,
|
||||||
self.infcx.probe_ct_var(vid),
|
"region vid should have been resolved fully before canonicalization"
|
||||||
None,
|
);
|
||||||
"region vid should have been resolved fully before canonicalization"
|
CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty)
|
||||||
);
|
|
||||||
CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), c.ty())
|
|
||||||
}
|
|
||||||
ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
|
|
||||||
ty::InferConst::Fresh(_) => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
|
||||||
|
ty::InferConst::Fresh(_) => todo!(),
|
||||||
|
},
|
||||||
ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
|
ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
|
||||||
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
|
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
|
||||||
PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
|
PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
|
||||||
c.ty(),
|
ty,
|
||||||
),
|
),
|
||||||
CanonicalizeMode::Response { .. } => {
|
CanonicalizeMode::Response { .. } => {
|
||||||
CanonicalVarKind::PlaceholderConst(placeholder, c.ty())
|
CanonicalVarKind::PlaceholderConst(placeholder, ty)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ty::ConstKind::Param(_) => match self.canonicalize_mode {
|
ty::ConstKind::Param(_) => match self.canonicalize_mode {
|
||||||
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
|
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
|
||||||
PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
|
PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
|
||||||
c.ty(),
|
ty,
|
||||||
),
|
),
|
||||||
CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"),
|
CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"),
|
||||||
},
|
},
|
||||||
|
// FIXME: See comment above -- we could fold the region separately or something.
|
||||||
ty::ConstKind::Bound(_, _)
|
ty::ConstKind::Bound(_, _)
|
||||||
| ty::ConstKind::Unevaluated(_)
|
| ty::ConstKind::Unevaluated(_)
|
||||||
| ty::ConstKind::Value(_)
|
| ty::ConstKind::Value(_)
|
||||||
|
@ -435,6 +433,35 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
Const::new_anon_bound(self.interner(), self.binder_index, var, c.ty())
|
Const::new_anon_bound(self.interner(), self.binder_index, var, ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RegionsToStatic<I> {
|
||||||
|
interner: I,
|
||||||
|
binder: ty::DebruijnIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> TypeFolder<I> for RegionsToStatic<I> {
|
||||||
|
fn interner(&self) -> I {
|
||||||
|
self.interner
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
|
||||||
|
where
|
||||||
|
T: TypeFoldable<I>,
|
||||||
|
I::Binder<T>: TypeSuperFoldable<I>,
|
||||||
|
{
|
||||||
|
self.binder.shift_in(1);
|
||||||
|
let t = t.fold_with(self);
|
||||||
|
self.binder.shift_out(1);
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_region(&mut self, r: I::Region) -> I::Region {
|
||||||
|
match r.kind() {
|
||||||
|
ty::ReBound(db, _) if self.binder > db => r,
|
||||||
|
_ => Region::new_static(self.interner()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,31 +136,21 @@ pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> {
|
||||||
t.super_fold_with(self)
|
t.super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_ty(&mut self, t: I::Ty) -> I::Ty
|
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
|
||||||
where
|
|
||||||
I::Ty: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
t.super_fold_with(self)
|
t.super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default region folder is a no-op because `Region` is non-recursive
|
// The default region folder is a no-op because `Region` is non-recursive
|
||||||
// and has no `super_fold_with` method to call. That also explains the
|
// and has no `super_fold_with` method to call.
|
||||||
// lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
|
|
||||||
fn fold_region(&mut self, r: I::Region) -> I::Region {
|
fn fold_region(&mut self, r: I::Region) -> I::Region {
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_const(&mut self, c: I::Const) -> I::Const
|
fn fold_const(&mut self, c: I::Const) -> I::Const {
|
||||||
where
|
|
||||||
I::Const: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
c.super_fold_with(self)
|
c.super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate
|
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
|
||||||
where
|
|
||||||
I::Predicate: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
p.super_fold_with(self)
|
p.super_fold_with(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,31 +175,21 @@ pub trait FallibleTypeFolder<I: Interner>: Sized {
|
||||||
t.try_super_fold_with(self)
|
t.try_super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error>
|
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error> {
|
||||||
where
|
|
||||||
I::Ty: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
t.try_super_fold_with(self)
|
t.try_super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default region folder is a no-op because `Region` is non-recursive
|
// The default region folder is a no-op because `Region` is non-recursive
|
||||||
// and has no `super_fold_with` method to call. That also explains the
|
// and has no `super_fold_with` method to call.
|
||||||
// lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
|
|
||||||
fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> {
|
fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> {
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error>
|
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error> {
|
||||||
where
|
|
||||||
I::Const: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
c.try_super_fold_with(self)
|
c.try_super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error>
|
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error> {
|
||||||
where
|
|
||||||
I::Predicate: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
p.try_super_fold_with(self)
|
p.try_super_fold_with(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,10 +214,7 @@ where
|
||||||
Ok(self.fold_binder(t))
|
Ok(self.fold_binder(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never>
|
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never> {
|
||||||
where
|
|
||||||
I::Ty: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
Ok(self.fold_ty(t))
|
Ok(self.fold_ty(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,17 +222,11 @@ where
|
||||||
Ok(self.fold_region(r))
|
Ok(self.fold_region(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never>
|
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never> {
|
||||||
where
|
|
||||||
I::Const: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
Ok(self.fold_const(c))
|
Ok(self.fold_const(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never>
|
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never> {
|
||||||
where
|
|
||||||
I::Predicate: TypeSuperFoldable<I>,
|
|
||||||
{
|
|
||||||
Ok(self.fold_predicate(p))
|
Ok(self.fold_predicate(p))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,14 @@ use smallvec::SmallVec;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
use crate::fold::TypeSuperFoldable;
|
||||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||||
use crate::{
|
use crate::{
|
||||||
new, BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebugWithInfcx, RegionKind, TyKind,
|
new, BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebugWithInfcx, RegionKind, TyKind,
|
||||||
UniverseIndex,
|
UniverseIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Interner: Sized {
|
pub trait Interner: Sized + Copy {
|
||||||
type DefId: Copy + Debug + Hash + Eq;
|
type DefId: Copy + Debug + Hash + Eq;
|
||||||
type AdtDef: Copy + Debug + Hash + Eq;
|
type AdtDef: Copy + Debug + Hash + Eq;
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ pub trait Interner: Sized {
|
||||||
+ Into<Self::GenericArg>
|
+ Into<Self::GenericArg>
|
||||||
+ IntoKind<Kind = TyKind<Self>>
|
+ IntoKind<Kind = TyKind<Self>>
|
||||||
+ TypeSuperVisitable<Self>
|
+ TypeSuperVisitable<Self>
|
||||||
|
+ TypeSuperFoldable<Self>
|
||||||
+ Flags
|
+ Flags
|
||||||
+ new::Ty<Self>;
|
+ new::Ty<Self>;
|
||||||
type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
|
type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
|
||||||
|
@ -57,6 +59,7 @@ pub trait Interner: Sized {
|
||||||
+ IntoKind<Kind = ConstKind<Self>>
|
+ IntoKind<Kind = ConstKind<Self>>
|
||||||
+ ConstTy<Self>
|
+ ConstTy<Self>
|
||||||
+ TypeSuperVisitable<Self>
|
+ TypeSuperVisitable<Self>
|
||||||
|
+ TypeSuperFoldable<Self>
|
||||||
+ Flags
|
+ Flags
|
||||||
+ new::Const<Self>;
|
+ new::Const<Self>;
|
||||||
type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
|
type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
|
||||||
|
@ -82,7 +85,13 @@ pub trait Interner: Sized {
|
||||||
type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike;
|
type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike;
|
||||||
|
|
||||||
// Predicates
|
// Predicates
|
||||||
type Predicate: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
|
type Predicate: Copy
|
||||||
|
+ Debug
|
||||||
|
+ Hash
|
||||||
|
+ Eq
|
||||||
|
+ TypeSuperVisitable<Self>
|
||||||
|
+ TypeSuperFoldable<Self>
|
||||||
|
+ Flags;
|
||||||
type TraitPredicate: Copy + Debug + Hash + Eq;
|
type TraitPredicate: Copy + Debug + Hash + Eq;
|
||||||
type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
|
type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
|
||||||
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
|
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
|
||||||
|
|
|
@ -6,6 +6,8 @@ pub trait Ty<I: Interner<Ty = Self>> {
|
||||||
|
|
||||||
pub trait Region<I: Interner<Region = Self>> {
|
pub trait Region<I: Interner<Region = Self>> {
|
||||||
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
|
fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
|
||||||
|
|
||||||
|
fn new_static(interner: I) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Const<I: Interner<Const = Self>> {
|
pub trait Const<I: Interner<Const = Self>> {
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![feature(adt_const_params)]
|
||||||
|
//~^ WARN the feature `adt_const_params` is incomplete
|
||||||
|
#![feature(with_negative_coherence, negative_impls)]
|
||||||
|
|
||||||
|
pub trait A<const K: &'static str> {}
|
||||||
|
pub trait C {}
|
||||||
|
|
||||||
|
|
||||||
|
struct W<T>(T);
|
||||||
|
|
||||||
|
// Negative coherence:
|
||||||
|
// Proving `W<!T>: !A<"">` requires proving `CONST alias-eq ""`, which requires proving
|
||||||
|
// `CONST normalizes-to (?1c: &str)`. The type's region is uniquified, so it ends up being
|
||||||
|
// put in to the canonical vars list with an infer region => ICE.
|
||||||
|
impl<T> C for T where T: A<""> {}
|
||||||
|
impl<T> C for W<T> {}
|
||||||
|
|
||||||
|
impl<T> !A<CONST> for W<T> {}
|
||||||
|
const CONST: &str = "";
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/regions-in-canonical.rs:3:12
|
||||||
|
|
|
||||||
|
LL | #![feature(adt_const_params)]
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue