Rollup merge of #145627 - compiler-errors:const-supertrait-dyn-compat, r=fee1-dead
Unconditionally-const supertraits are considered not dyn compatible Let's save some space in the design of const traits by making `dyn Trait` where `trait Trait: const Super` not dyn compatible. Such a trait cannot satisfy `dyn Trait: Trait`; we could in the future make this dyn compatible but *NOT* implement `Trait`, but that's a bit weird and seems like it needs to be independently justified moving forward. Fixes https://github.com/rust-lang/rust/issues/145198 r? fee1-dead
This commit is contained in:
@@ -760,6 +760,9 @@ pub enum DynCompatibilityViolation {
|
||||
// Supertrait has a non-lifetime `for<T>` binder.
|
||||
SupertraitNonLifetimeBinder(SmallVec<[Span; 1]>),
|
||||
|
||||
// Trait has a `const Trait` supertrait.
|
||||
SupertraitConst(SmallVec<[Span; 1]>),
|
||||
|
||||
/// Method has something illegal.
|
||||
Method(Symbol, MethodViolationCode, Span),
|
||||
|
||||
@@ -785,6 +788,9 @@ impl DynCompatibilityViolation {
|
||||
DynCompatibilityViolation::SupertraitNonLifetimeBinder(_) => {
|
||||
"where clause cannot reference non-lifetime `for<...>` variables".into()
|
||||
}
|
||||
DynCompatibilityViolation::SupertraitConst(_) => {
|
||||
"it cannot have a `const` supertrait".into()
|
||||
}
|
||||
DynCompatibilityViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
|
||||
format!("associated function `{name}` has no `self` parameter").into()
|
||||
}
|
||||
@@ -842,7 +848,8 @@ impl DynCompatibilityViolation {
|
||||
match self {
|
||||
DynCompatibilityViolation::SizedSelf(_)
|
||||
| DynCompatibilityViolation::SupertraitSelf(_)
|
||||
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(..) => {
|
||||
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(..)
|
||||
| DynCompatibilityViolation::SupertraitConst(_) => {
|
||||
DynCompatibilityViolationSolution::None
|
||||
}
|
||||
DynCompatibilityViolation::Method(
|
||||
@@ -873,15 +880,17 @@ impl DynCompatibilityViolation {
|
||||
match self {
|
||||
DynCompatibilityViolation::SupertraitSelf(spans)
|
||||
| DynCompatibilityViolation::SizedSelf(spans)
|
||||
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(),
|
||||
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans)
|
||||
| DynCompatibilityViolation::SupertraitConst(spans) => spans.clone(),
|
||||
DynCompatibilityViolation::AssocConst(_, span)
|
||||
| DynCompatibilityViolation::GAT(_, span)
|
||||
| DynCompatibilityViolation::Method(_, _, span)
|
||||
if *span != DUMMY_SP =>
|
||||
{
|
||||
| DynCompatibilityViolation::Method(_, _, span) => {
|
||||
if *span != DUMMY_SP {
|
||||
smallvec![*span]
|
||||
} else {
|
||||
smallvec![]
|
||||
}
|
||||
}
|
||||
_ => smallvec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,10 @@ fn dyn_compatibility_violations_for_trait(
|
||||
if !spans.is_empty() {
|
||||
violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
|
||||
}
|
||||
let spans = super_predicates_are_unconditionally_const(tcx, trait_def_id);
|
||||
if !spans.is_empty() {
|
||||
violations.push(DynCompatibilityViolation::SupertraitConst(spans));
|
||||
}
|
||||
|
||||
violations
|
||||
}
|
||||
@@ -247,16 +251,31 @@ fn super_predicates_have_non_lifetime_binders(
|
||||
tcx: TyCtxt<'_>,
|
||||
trait_def_id: DefId,
|
||||
) -> SmallVec<[Span; 1]> {
|
||||
// If non_lifetime_binders is disabled, then exit early
|
||||
if !tcx.features().non_lifetime_binders() {
|
||||
return SmallVec::new();
|
||||
}
|
||||
tcx.explicit_super_predicates_of(trait_def_id)
|
||||
.iter_identity_copied()
|
||||
.filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(span))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Checks for `const Trait` supertraits. We're okay with `[const] Trait`,
|
||||
/// supertraits since for a non-const instantiation of that trait, the
|
||||
/// conditionally-const supertrait is also not required to be const.
|
||||
fn super_predicates_are_unconditionally_const(
|
||||
tcx: TyCtxt<'_>,
|
||||
trait_def_id: DefId,
|
||||
) -> SmallVec<[Span; 1]> {
|
||||
tcx.explicit_super_predicates_of(trait_def_id)
|
||||
.iter_identity_copied()
|
||||
.filter_map(|(pred, span)| {
|
||||
if let ty::ClauseKind::HostEffect(_) = pred.kind().skip_binder() {
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
|
||||
tcx.generics_require_sized_self(trait_def_id)
|
||||
}
|
||||
|
||||
18
tests/ui/traits/const-traits/const-supertraits-dyn-compat.rs
Normal file
18
tests/ui/traits/const-traits/const-supertraits-dyn-compat.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
#![feature(const_trait_impl)]
|
||||
|
||||
const trait Super {}
|
||||
|
||||
// Not ok
|
||||
const trait Unconditionally: const Super {}
|
||||
fn test() {
|
||||
let _: &dyn Unconditionally;
|
||||
//~^ ERROR the trait `Unconditionally` is not dyn compatible
|
||||
}
|
||||
|
||||
// Okay
|
||||
const trait Conditionally: [const] Super {}
|
||||
fn test2() {
|
||||
let _: &dyn Conditionally;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,18 @@
|
||||
error[E0038]: the trait `Unconditionally` is not dyn compatible
|
||||
--> $DIR/const-supertraits-dyn-compat.rs:8:17
|
||||
|
|
||||
LL | let _: &dyn Unconditionally;
|
||||
| ^^^^^^^^^^^^^^^ `Unconditionally` is not dyn compatible
|
||||
|
|
||||
note: for a trait to be dyn compatible it needs to allow building a vtable
|
||||
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
|
||||
--> $DIR/const-supertraits-dyn-compat.rs:6:30
|
||||
|
|
||||
LL | const trait Unconditionally: const Super {}
|
||||
| --------------- ^^^^^^^^^^^ ...because it cannot have a `const` supertrait
|
||||
| |
|
||||
| this trait is not dyn compatible...
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0038`.
|
||||
Reference in New Issue
Block a user