From 08c7ff22645cbb661edd67a8a30cf3dd67a07c23 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 28 Mar 2024 12:10:44 -0400 Subject: [PATCH] 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 867faf63261..b92800a1728 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 16d8453ea24..a7148c88864 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -382,43 +382,47 @@ fn fold_const(&mut self, c: I::Const) -> I::Const 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 @@ fn fold_const(&mut self, c: I::Const) -> I::Const }), ); - 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 ae1e1902f14..d941195eecc 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -2,13 +2,14 @@ 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 e7e695e5908..1572a641d06 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 00000000000..6c2a11e0135 --- /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 00000000000..dc8c926f182 --- /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 +