From 08c7ff22645cbb661edd67a8a30cf3dd67a07c23 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 28 Mar 2024 12:10:44 -0400 Subject: [PATCH 1/2] Restrict const ty's regions to static when putting them in canonical var list --- compiler/rustc_middle/src/ty/region.rs | 4 + .../src/canonicalizer.rs | 79 +++++++++++++------ compiler/rustc_type_ir/src/interner.rs | 5 +- compiler/rustc_type_ir/src/new.rs | 2 + .../regions-in-canonical.rs | 23 ++++++ .../regions-in-canonical.stderr | 11 +++ 6 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 tests/ui/coherence/negative-coherence/regions-in-canonical.rs create mode 100644 tests/ui/coherence/negative-coherence/regions-in-canonical.stderr diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 867faf6326199..b92800a172880 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -140,6 +140,10 @@ impl<'tcx> rustc_type_ir::new::Region> for Region<'tcx> { 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 }) } + + fn new_static(tcx: TyCtxt<'tcx>) -> Self { + tcx.lifetimes.re_static + } } /// Region utilities diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 16d8453ea24ef..a7148c8886487 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -382,43 +382,47 @@ impl, I: Interner> TypeFolder where I::Const: TypeSuperFoldable, { + // We could canonicalize all consts with static types, but the only ones we + // *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() { - ty::ConstKind::Infer(i) => { - // FIXME: we should fold the ty too eventually - match i { - ty::InferConst::Var(vid) => { - assert_eq!( - self.infcx.root_ct_var(vid), - vid, - "region vid should have been resolved fully before canonicalization" - ); - assert_eq!( - self.infcx.probe_ct_var(vid), - None, - "region vid should have been resolved fully before canonicalization" - ); - CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), c.ty()) - } - ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect, - ty::InferConst::Fresh(_) => todo!(), + ty::ConstKind::Infer(i) => match i { + ty::InferConst::Var(vid) => { + assert_eq!( + self.infcx.root_ct_var(vid), + vid, + "region vid should have been resolved fully before canonicalization" + ); + assert_eq!( + self.infcx.probe_ct_var(vid), + None, + "region vid should have been resolved fully before canonicalization" + ); + CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty) } - } + ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect, + ty::InferConst::Fresh(_) => todo!(), + }, ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( PlaceholderLike::new(placeholder.universe(), self.variables.len().into()), - c.ty(), + ty, ), CanonicalizeMode::Response { .. } => { - CanonicalVarKind::PlaceholderConst(placeholder, c.ty()) + CanonicalVarKind::PlaceholderConst(placeholder, ty) } }, ty::ConstKind::Param(_) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()), - c.ty(), + ty, ), 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::Unevaluated(_) | ty::ConstKind::Value(_) @@ -435,6 +439,35 @@ impl, I: Interner> TypeFolder }), ); - 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 { + interner: I, + binder: ty::DebruijnIndex, +} + +impl TypeFolder for RegionsToStatic { + fn interner(&self) -> I { + self.interner + } + + fn fold_binder(&mut self, t: I::Binder) -> I::Binder + where + T: TypeFoldable, + I::Binder: TypeSuperFoldable, + { + 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()), + } } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index ae1e1902f14cd..d941195eecc69 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -2,13 +2,14 @@ use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; +use crate::fold::TypeSuperFoldable; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{ new, BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebugWithInfcx, RegionKind, TyKind, UniverseIndex, }; -pub trait Interner: Sized { +pub trait Interner: Sized + Copy { type DefId: Copy + Debug + Hash + Eq; type AdtDef: Copy + Debug + Hash + Eq; @@ -34,6 +35,7 @@ pub trait Interner: Sized { + Into + IntoKind> + TypeSuperVisitable + + TypeSuperFoldable + Flags + new::Ty; type Tys: Copy + Debug + Hash + Eq + IntoIterator; @@ -57,6 +59,7 @@ pub trait Interner: Sized { + IntoKind> + ConstTy + TypeSuperVisitable + + TypeSuperFoldable + Flags + new::Const; type AliasConst: Copy + DebugWithInfcx + Hash + Eq; diff --git a/compiler/rustc_type_ir/src/new.rs b/compiler/rustc_type_ir/src/new.rs index e7e695e59085a..1572a641d06f0 100644 --- a/compiler/rustc_type_ir/src/new.rs +++ b/compiler/rustc_type_ir/src/new.rs @@ -6,6 +6,8 @@ pub trait Ty> { pub trait Region> { fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; + + fn new_static(interner: I) -> Self; } pub trait Const> { diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs new file mode 100644 index 0000000000000..6c2a11e013583 --- /dev/null +++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs @@ -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 {} +pub trait C {} + + +struct W(T); + +// Negative coherence: +// Proving `W: !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 C for T where T: A<""> {} +impl C for W {} + +impl !A for W {} +const CONST: &str = ""; + +fn main() {} diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr new file mode 100644 index 0000000000000..dc8c926f182b4 --- /dev/null +++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr @@ -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 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + From 6439c7fe238d14f10b9b4cfae328ec408e8dfde4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 28 Mar 2024 12:17:17 -0400 Subject: [PATCH 2/2] Require foldability part of interner item bounds, remove redundant where clauses --- .../src/canonicalizer.rs | 10 +--- compiler/rustc_type_ir/src/fold.rs | 51 ++++--------------- compiler/rustc_type_ir/src/interner.rs | 8 ++- 3 files changed, 20 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index a7148c8886487..1899517c0e248 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -296,10 +296,7 @@ impl, I: Interner> TypeFolder Region::new_anon_bound(self.interner(), self.binder_index, var) } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty - where - I::Ty: TypeSuperFoldable, - { + fn fold_ty(&mut self, t: I::Ty) -> I::Ty { let kind = match t.kind() { ty::Infer(i) => match i { ty::TyVar(vid) => { @@ -378,10 +375,7 @@ impl, I: Interner> TypeFolder Ty::new_anon_bound(self.interner(), self.binder_index, var) } - fn fold_const(&mut self, c: I::Const) -> I::Const - where - I::Const: TypeSuperFoldable, - { + fn fold_const(&mut self, c: I::Const) -> I::Const { // We could canonicalize all consts with static types, but the only ones we // *really* need to worry about are the ones that we end up putting into `CanonicalVarKind` // since canonical vars can't reference other canonical vars. diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 8d402588398e4..01bb3d73dbdf3 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -136,31 +136,21 @@ pub trait TypeFolder: FallibleTypeFolder { t.super_fold_with(self) } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty - where - I::Ty: TypeSuperFoldable, - { + fn fold_ty(&mut self, t: I::Ty) -> I::Ty { t.super_fold_with(self) } // 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 - // lack of `I::Region: TypeSuperFoldable` bound on this method. + // and has no `super_fold_with` method to call. fn fold_region(&mut self, r: I::Region) -> I::Region { r } - fn fold_const(&mut self, c: I::Const) -> I::Const - where - I::Const: TypeSuperFoldable, - { + fn fold_const(&mut self, c: I::Const) -> I::Const { c.super_fold_with(self) } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate - where - I::Predicate: TypeSuperFoldable, - { + fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { p.super_fold_with(self) } } @@ -185,31 +175,21 @@ pub trait FallibleTypeFolder: Sized { t.try_super_fold_with(self) } - fn try_fold_ty(&mut self, t: I::Ty) -> Result - where - I::Ty: TypeSuperFoldable, - { + fn try_fold_ty(&mut self, t: I::Ty) -> Result { t.try_super_fold_with(self) } // 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 - // lack of `I::Region: TypeSuperFoldable` bound on this method. + // and has no `super_fold_with` method to call. fn try_fold_region(&mut self, r: I::Region) -> Result { Ok(r) } - fn try_fold_const(&mut self, c: I::Const) -> Result - where - I::Const: TypeSuperFoldable, - { + fn try_fold_const(&mut self, c: I::Const) -> Result { c.try_super_fold_with(self) } - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result - where - I::Predicate: TypeSuperFoldable, - { + fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { p.try_super_fold_with(self) } } @@ -234,10 +214,7 @@ where Ok(self.fold_binder(t)) } - fn try_fold_ty(&mut self, t: I::Ty) -> Result - where - I::Ty: TypeSuperFoldable, - { + fn try_fold_ty(&mut self, t: I::Ty) -> Result { Ok(self.fold_ty(t)) } @@ -245,17 +222,11 @@ where Ok(self.fold_region(r)) } - fn try_fold_const(&mut self, c: I::Const) -> Result - where - I::Const: TypeSuperFoldable, - { + fn try_fold_const(&mut self, c: I::Const) -> Result { Ok(self.fold_const(c)) } - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result - where - I::Predicate: TypeSuperFoldable, - { + fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { Ok(self.fold_predicate(p)) } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index d941195eecc69..7a2885dd3bb6b 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -85,7 +85,13 @@ pub trait Interner: Sized + Copy { type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike; // Predicates - type Predicate: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; + type Predicate: Copy + + Debug + + Hash + + Eq + + TypeSuperVisitable + + TypeSuperFoldable + + Flags; type TraitPredicate: Copy + Debug + Hash + Eq; type RegionOutlivesPredicate: Copy + Debug + Hash + Eq; type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;