Skip to content

Unconditionally-const supertraits are considered not dyn compatible #145627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),

Expand All @@ -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()
}
Expand Down Expand Up @@ -842,7 +848,8 @@ impl DynCompatibilityViolation {
match self {
DynCompatibilityViolation::SizedSelf(_)
| DynCompatibilityViolation::SupertraitSelf(_)
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(..) => {
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(..)
| DynCompatibilityViolation::SupertraitConst(_) => {
DynCompatibilityViolationSolution::None
}
DynCompatibilityViolation::Method(
Expand Down Expand Up @@ -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 =>
{
smallvec![*span]
| DynCompatibilityViolation::Method(_, _, span) => {
if *span != DUMMY_SP {
smallvec![*span]
} else {
smallvec![]
}
}
_ => smallvec![],
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -257,6 +261,28 @@ fn super_predicates_have_non_lifetime_binders(
.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]> {
if !tcx.features().const_trait_impl() {
return SmallVec::new();
}
Comment on lines +271 to +273
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems wrong? If I am a downstream crate that attempts to use a trait upstream that has : const Tr, then I should see that the trait isn't dyn compatible no matter whether I enable const_trait_impl.

I checked the callers of this and it looks like it's not limited to just local items.

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)
}
Expand Down
18 changes: 18 additions & 0 deletions tests/ui/traits/const-traits/const-supertraits-dyn-compat.rs
Original file line number Diff line number Diff line change
@@ -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() {}
18 changes: 18 additions & 0 deletions tests/ui/traits/const-traits/const-supertraits-dyn-compat.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Loading