diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 2aed66d27e96..695a0793ccd1 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -56,7 +56,7 @@ pub(super) fn lower_trait_object_ty( } let mut user_written_bounds = Vec::new(); - let mut potential_assoc_types = Vec::new(); + let mut potential_assoc_items = Vec::new(); for poly_trait_ref in hir_bounds.iter() { let result = self.lower_poly_trait_ref( poly_trait_ref, @@ -66,7 +66,7 @@ pub(super) fn lower_trait_object_ty( OverlappingAsssocItemConstraints::Forbidden, ); if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct { - potential_assoc_types.extend(invalid_args); + potential_assoc_items.extend(invalid_args); } } @@ -138,7 +138,7 @@ pub(super) fn lower_trait_object_ty( } // Map the projection bounds onto a key that makes it easy to remove redundant - // bounds that are constrained by supertraits of the principal def id. + // bounds that are constrained by supertraits of the principal trait. // // Also make sure we detect conflicting bounds from expanding a trait alias and // also specifying it manually, like: @@ -191,13 +191,12 @@ pub(super) fn lower_trait_object_ty( let principal_trait = regular_traits.into_iter().next(); - // A stable ordering of associated types from the principal trait and all its - // supertraits. We use this to ensure that different substitutions of a trait - // don't result in `dyn Trait` types with different projections lists, which - // can be unsound: . - // We achieve a stable ordering by walking over the unsubstituted principal - // trait ref. - let mut ordered_associated_types = vec![]; + // A stable ordering of associated types & consts from the principal trait and all its + // supertraits. We use this to ensure that different substitutions of a trait don't + // result in `dyn Trait` types with different projections lists, which can be unsound: + // . + // We achieve a stable ordering by walking over the unsubstituted principal trait ref. + let mut ordered_associated_items = vec![]; if let Some((principal_trait, ref spans)) = principal_trait { let principal_trait = principal_trait.map_bound(|trait_pred| { @@ -223,12 +222,12 @@ pub(super) fn lower_trait_object_ty( // FIXME(negative_bounds): Handle this correctly... let trait_ref = tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref)); - ordered_associated_types.extend( + ordered_associated_items.extend( tcx.associated_items(pred.trait_ref.def_id) .in_definition_order() - // We only care about associated types. - .filter(|item| item.is_type()) - // No RPITITs -- they're not dyn-compatible for now. + // Only associated types & consts can possibly be constrained via a binding. + .filter(|item| item.is_type() || item.is_const()) + // Traits with RPITITs are simply not dyn compatible (for now). .filter(|item| !item.is_impl_trait_in_trait()) .map(|item| (item.def_id, trait_ref)), ); @@ -283,15 +282,13 @@ pub(super) fn lower_trait_object_ty( } } - // `dyn Trait` desugars to (not Rust syntax) `dyn Trait where - // ::Assoc = Foo`. So every `Projection` clause is an - // `Assoc = Foo` bound. `needed_associated_types` contains all associated - // types that we expect to be provided by the user, so the following loop - // removes all the associated types that have a corresponding `Projection` - // clause, either from expanding trait aliases or written by the user. + // Flag assoc item bindings that didn't really need to be specified. for &(projection_bound, span) in projection_bounds.values() { let def_id = projection_bound.item_def_id(); if tcx.generics_require_sized_self(def_id) { + // FIXME(mgca): Ideally we would generalize the name of this lint to sth. like + // `unused_associated_item_bindings` since this can now also trigger on *const* + // projections / assoc *const* bindings. tcx.emit_node_span_lint( UNUSED_ASSOCIATED_TYPE_BOUNDS, hir_id, @@ -301,35 +298,36 @@ pub(super) fn lower_trait_object_ty( } } - // We compute the list of projection bounds taking the ordered associated types, - // and check if there was an entry in the collected `projection_bounds`. Those - // are computed by first taking the user-written associated types, then elaborating - // the principal trait ref, and only using those if there was no user-written. - // See note below about how we handle missing associated types with `Self: Sized`, - // which are not required to be provided, but are still used if they are provided. - let mut missing_assoc_types = FxIndexSet::default(); - let projection_bounds: Vec<_> = ordered_associated_types + // The user has to constrain all associated types & consts via bindings unless the + // corresponding associated item has a `where Self: Sized` clause. This can be done + // in the `dyn Trait` directly, in the supertrait bounds or behind trait aliases. + // + // Collect all associated items that weren't specified and compute the list of + // projection bounds which we'll later turn into existential ones. + // + // We intentionally keep around projections whose associated item has a `Self: Sized` + // bound in order to be able to wfcheck the RHS, allow the RHS to constrain generic + // parameters and to imply bounds. + // See also . + let mut missing_assoc_items = FxIndexSet::default(); + let projection_bounds: Vec<_> = ordered_associated_items .into_iter() - .filter_map(|key| { - if let Some(assoc) = projection_bounds.get(&key) { - Some(*assoc) - } else { - // If the associated type has a `where Self: Sized` bound, then - // we do not need to provide the associated type. This results in - // a `dyn Trait` type that has a different number of projection - // bounds, which may lead to type mismatches. - if !tcx.generics_require_sized_self(key.0) { - missing_assoc_types.insert(key); - } - None + .filter_map(|key @ (def_id, _)| { + if let Some(&assoc) = projection_bounds.get(&key) { + return Some(assoc); } + if !tcx.generics_require_sized_self(def_id) { + missing_assoc_items.insert(key); + } + None }) .collect(); + // If there are any associated items whose value wasn't provided, bail out with an error. if let Err(guar) = self.check_for_required_assoc_tys( principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()), - missing_assoc_types, - potential_assoc_types, + missing_assoc_items, + potential_assoc_items, hir_bounds, ) { return Ty::new_error(tcx, guar); diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index d71df36684f5..429db832884b 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -759,7 +759,7 @@ pub struct ImplSourceUserDefinedData<'tcx, N> { pub nested: ThinVec, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)] pub enum DynCompatibilityViolation { /// `Self: Sized` declared on the trait. SizedSelf(SmallVec<[Span; 1]>), @@ -780,11 +780,17 @@ pub enum DynCompatibilityViolation { /// Method has something illegal. Method(Symbol, MethodViolationCode, Span), - /// Associated const. + /// Associated constant. AssocConst(Symbol, Span), - /// GAT - GAT(Symbol, Span), + /// Generic associated constant. + GenericAssocConst(Symbol, Span), + + /// Associated constant that wasn't marked `#[type_const]`. + NonTypeAssocConst(Symbol, Span), + + /// Generic associated type. + GenericAssocTy(Symbol, Span), } impl DynCompatibilityViolation { @@ -852,14 +858,18 @@ pub fn error_msg(&self) -> Cow<'static, str> { MethodViolationCode::UndispatchableReceiver(_), _, ) => format!("method `{name}`'s `self` parameter cannot be dispatched on").into(), - DynCompatibilityViolation::AssocConst(name, DUMMY_SP) => { - format!("it contains associated `const` `{name}`").into() + DynCompatibilityViolation::AssocConst(name, _) => { + format!("it contains associated const `{name}`").into() } - DynCompatibilityViolation::AssocConst(..) => { - "it contains this associated `const`".into() + DynCompatibilityViolation::GenericAssocConst(name, _) => { + format!("it contains generic associated const `{name}`").into() } - DynCompatibilityViolation::GAT(name, _) => { - format!("it contains the generic associated type `{name}`").into() + DynCompatibilityViolation::NonTypeAssocConst(name, _) => { + format!("it contains associated const `{name}` that's not marked `#[type_const]`") + .into() + } + DynCompatibilityViolation::GenericAssocTy(name, _) => { + format!("it contains generic associated type `{name}`").into() } } } @@ -888,7 +898,9 @@ pub fn solution(&self) -> DynCompatibilityViolationSolution { _, ) => DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span), DynCompatibilityViolation::AssocConst(name, _) - | DynCompatibilityViolation::GAT(name, _) + | DynCompatibilityViolation::GenericAssocConst(name, _) + | DynCompatibilityViolation::NonTypeAssocConst(name, _) + | DynCompatibilityViolation::GenericAssocTy(name, _) | DynCompatibilityViolation::Method(name, ..) => { DynCompatibilityViolationSolution::MoveToAnotherTrait(*name) } @@ -905,7 +917,9 @@ pub fn solution(&self) -> DynCompatibilityViolationSolution { | DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans) | DynCompatibilityViolation::SupertraitConst(spans) => spans.clone(), DynCompatibilityViolation::AssocConst(_, span) - | DynCompatibilityViolation::GAT(_, span) + | DynCompatibilityViolation::GenericAssocConst(_, span) + | DynCompatibilityViolation::NonTypeAssocConst(_, span) + | DynCompatibilityViolation::GenericAssocTy(_, span) | DynCompatibilityViolation::Method(_, _, span) => { if *span != DUMMY_SP { smallvec![*span] @@ -972,7 +986,7 @@ trait objects" } /// Reasons a method might not be dyn-compatible. -#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)] pub enum MethodViolationCode { /// e.g., `fn foo()` StaticMethod(Option<(/* add &self */ (String, Span), /* add Self: Sized */ (String, Span))>), diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 5e20bc142ffe..0957d103d997 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -148,8 +148,9 @@ pub fn as_def_kind(&self) -> DefKind { AssocKind::Type { .. } => DefKind::AssocTy, } } - pub fn is_type(&self) -> bool { - matches!(self.kind, ty::AssocKind::Type { .. }) + + pub fn is_const(&self) -> bool { + matches!(self.kind, ty::AssocKind::Const { .. }) } pub fn is_fn(&self) -> bool { @@ -160,6 +161,10 @@ pub fn is_method(&self) -> bool { matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. }) } + pub fn is_type(&self) -> bool { + matches!(self.kind, ty::AssocKind::Type { .. }) + } + pub fn as_tag(&self) -> AssocTag { match self.kind { AssocKind::Const { .. } => AssocTag::Const, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 34aca8adb4a0..b0b5a783b00e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -762,8 +762,7 @@ pub fn new_dynamic( .principal_def_id() .into_iter() .flat_map(|principal_def_id| { - // NOTE: This should agree with `needed_associated_types` in - // dyn trait lowering, or else we'll have ICEs. + // IMPORTANT: This has to agree with HIR ty lowering of dyn trait! elaborate::supertraits( tcx, ty::Binder::dummy(ty::TraitRef::identity(tcx, principal_def_id)), @@ -771,7 +770,7 @@ pub fn new_dynamic( .map(|principal| { tcx.associated_items(principal.def_id()) .in_definition_order() - .filter(|item| item.is_type()) + .filter(|item| item.is_type() || item.is_const()) .filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .count() diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 13acdad8aad7..4ec435009997 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -7,8 +7,9 @@ use std::ops::ControlFlow; use rustc_errors::FatalError; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, LangItem}; +use rustc_hir::{self as hir, LangItem, find_attr}; use rustc_middle::query::Providers; use rustc_middle::ty::{ self, EarlyBinder, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, @@ -288,7 +289,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { return false; /* No Sized trait, can't require it! */ }; - // Search for a predicate like `Self : Sized` amongst the trait bounds. + // Search for a predicate like `Self: Sized` amongst the trait bounds. let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; elaborate(tcx, predicates).any(|pred| match pred.kind().skip_binder() { @@ -306,24 +307,35 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { }) } -/// Returns `Some(_)` if this item makes the containing trait dyn-incompatible. #[instrument(level = "debug", skip(tcx), ret)] pub fn dyn_compatibility_violations_for_assoc_item( tcx: TyCtxt<'_>, trait_def_id: DefId, item: ty::AssocItem, ) -> Vec { - // Any item that has a `Self : Sized` requisite is otherwise - // exempt from the regulations. + // Any item that has a `Self: Sized` requisite is otherwise exempt from the regulations. if tcx.generics_require_sized_self(item.def_id) { return Vec::new(); } + let span = || item.ident(tcx).span; + match item.kind { - // Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all, - // and associated const bounds in trait objects aren't a thing yet either. ty::AssocKind::Const { name } => { - vec![DynCompatibilityViolation::AssocConst(name, item.ident(tcx).span)] + if tcx.features().min_generic_const_args() { + if !tcx.generics_of(item.def_id).is_own_empty() { + vec![DynCompatibilityViolation::GenericAssocConst(name, span())] + } else if !find_attr!(tcx.get_all_attrs(item.def_id), AttributeKind::TypeConst(_)) { + vec![DynCompatibilityViolation::NonTypeAssocConst(name, span())] + } else { + // We will permit type associated consts if they are explicitly mentioned in the + // trait object type. We can't check this here, as here we only check if it is + // guaranteed to not be possible. + Vec::new() + } + } else { + vec![DynCompatibilityViolation::AssocConst(name, span())] + } } ty::AssocKind::Fn { name, .. } => { virtual_call_violations_for_method(tcx, trait_def_id, item) @@ -338,20 +350,22 @@ pub fn dyn_compatibility_violations_for_assoc_item( (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) } - _ => item.ident(tcx).span, + _ => span(), }; DynCompatibilityViolation::Method(name, v, span) }) .collect() } - // Associated types can only be dyn-compatible if they have `Self: Sized` bounds. - ty::AssocKind::Type { .. } => { - if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() { - vec![DynCompatibilityViolation::GAT(item.name(), item.ident(tcx).span)] + ty::AssocKind::Type { data } => { + if !tcx.generics_of(item.def_id).is_own_empty() + && let ty::AssocTypeData::Normal(name) = data + { + vec![DynCompatibilityViolation::GenericAssocTy(name, span())] } else { - // We will permit associated types if they are explicitly mentioned in the trait object. - // We can't check this here, as here we only check if it is guaranteed to not be possible. + // We will permit associated types if they are explicitly mentioned in the trait + // object type. We can't check this here, as here we only check if it is + // guaranteed to not be possible. Vec::new() } } diff --git a/tests/ui/associated-consts/associated-const-in-trait.rs b/tests/ui/associated-consts/associated-const-in-trait.rs index 4d88f4ff5316..6b0b43feb109 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.rs +++ b/tests/ui/associated-consts/associated-const-in-trait.rs @@ -7,8 +7,6 @@ trait Trait { impl dyn Trait { //~^ ERROR the trait `Trait` is not dyn compatible [E0038] const fn n() -> usize { Self::N } - //~^ ERROR the trait `Trait` is not dyn compatible [E0038] - //~| ERROR the trait `Trait` is not dyn compatible } fn main() {} diff --git a/tests/ui/associated-consts/associated-const-in-trait.stderr b/tests/ui/associated-consts/associated-const-in-trait.stderr index fba7f53c097f..fb4a55110b4e 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.stderr +++ b/tests/ui/associated-consts/associated-const-in-trait.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` is not dyn compatible - --> $DIR/associated-const-in-trait.rs:7:6 + --> $DIR/associated-const-in-trait.rs:7:10 | LL | impl dyn Trait { - | ^^^^^^^^^ `Trait` is not dyn compatible + | ^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -11,41 +11,9 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait Trait { | ----- this trait is not dyn compatible... LL | const N: usize; - | ^ ...because it contains this associated `const` + | ^ ...because it contains associated const `N` = help: consider moving `N` to another trait -error[E0038]: the trait `Trait` is not dyn compatible - --> $DIR/associated-const-in-trait.rs:9:29 - | -LL | const fn n() -> usize { Self::N } - | ^^^^ `Trait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/associated-const-in-trait.rs:4:11 - | -LL | trait Trait { - | ----- this trait is not dyn compatible... -LL | const N: usize; - | ^ ...because it contains this associated `const` - = help: consider moving `N` to another trait - -error[E0038]: the trait `Trait` is not dyn compatible - --> $DIR/associated-const-in-trait.rs:9:29 - | -LL | const fn n() -> usize { Self::N } - | ^^^^^^^ `Trait` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/associated-const-in-trait.rs:4:11 - | -LL | trait Trait { - | ----- this trait is not dyn compatible... -LL | const N: usize; - | ^ ...because it contains this associated `const` - = help: consider moving `N` to another trait - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/associated-item/issue-48027.stderr b/tests/ui/associated-item/issue-48027.stderr index e5c1ced93413..7abcabc1c79d 100644 --- a/tests/ui/associated-item/issue-48027.stderr +++ b/tests/ui/associated-item/issue-48027.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/issue-48027.rs:6:6 + --> $DIR/issue-48027.rs:6:10 | LL | impl dyn Bar {} - | ^^^^^^^ `Bar` is not dyn compatible + | ^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -11,7 +11,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait Bar { | --- this trait is not dyn compatible... LL | const X: usize; - | ^ ...because it contains this associated `const` + | ^ ...because it contains associated const `X` = help: consider moving `X` to another trait error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type diff --git a/tests/ui/async-await/async-fn/dyn-pos.stderr b/tests/ui/async-await/async-fn/dyn-pos.stderr index 7d5b37bdbe73..efd3357ca679 100644 --- a/tests/ui/async-await/async-fn/dyn-pos.stderr +++ b/tests/ui/async-await/async-fn/dyn-pos.stderr @@ -8,7 +8,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | - = note: the trait is not dyn compatible because it contains the generic associated type `CallRefFuture` + = note: the trait is not dyn compatible because it contains generic associated type `CallRefFuture` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-basic.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-basic.rs new file mode 100644 index 000000000000..6e35d56dc6e7 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-basic.rs @@ -0,0 +1,38 @@ +// Traits with type associated consts are dyn compatible. +// Check that we allow the corresp. trait object types if all assoc consts are specified. + +//@ check-pass + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait: SuperTrait { + #[type_const] + const K: usize; +} + +trait SuperTrait { + #[type_const] + const Q: usize; + #[type_const] + const C: usize; +} + +trait Bound { + #[type_const] + const N: usize; +} + +impl Bound for () { + #[type_const] + const N: usize = 10; +} + +fn main() { + let _: dyn Trait; + + let obj: &dyn Bound = &(); + _ = identity(obj); + + fn identity(x: &(impl ?Sized + Bound)) -> &(impl ?Sized + Bound) { x } +} diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-mismatch.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-mismatch.rs new file mode 100644 index 000000000000..be41906a4f2f --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-mismatch.rs @@ -0,0 +1,18 @@ +// Ensure that we actually enforce equality constraints found in trait object types. + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const N: usize; +} + +impl Trait for () { + #[type_const] + const N: usize = 1; +} + +fn main() { + let _: &dyn Trait = &(); //~ ERROR type mismatch resolving `<() as Trait>::N == 0` +} diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-mismatch.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-mismatch.stderr new file mode 100644 index 000000000000..2ab02068eb34 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-mismatch.stderr @@ -0,0 +1,13 @@ +error[E0271]: type mismatch resolving `<() as Trait>::N == 0` + --> $DIR/dyn-compat-const-mismatch.rs:17:32 + | +LL | let _: &dyn Trait = &(); + | ^^^ expected `0`, found `1` + | + = note: expected constant `0` + found constant `1` + = note: required for the cast from `&()` to `&dyn Trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-generic-assoc-const.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-generic-assoc-const.rs new file mode 100644 index 000000000000..05e8aeea5ed5 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-generic-assoc-const.rs @@ -0,0 +1,16 @@ +// Ensure that traits with generic associated consts (GACs) are dyn *in*compatible. +// It would be very hard to make dyn Trait with GACs sound just like with GATs. + +//@ dont-require-annotations: NOTE + +#![feature(min_generic_const_args, generic_const_items)] +#![expect(incomplete_features)] + +trait Trait { + const POLY: T; + //~^ NOTE it contains generic associated const `POLY` +} + +fn main() { + let _: dyn Trait; //~ ERROR the trait `Trait` is not dyn compatible +} diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-generic-assoc-const.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-generic-assoc-const.stderr new file mode 100644 index 000000000000..ed187e0287e9 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-generic-assoc-const.stderr @@ -0,0 +1,19 @@ +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/dyn-compat-generic-assoc-const.rs:15:16 + | +LL | let _: dyn Trait; + | ^^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/dyn-compat-generic-assoc-const.rs:10:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | const POLY: T; + | ^^^^ ...because it contains generic associated const `POLY` + = help: consider moving `POLY` to another trait + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-non-type-assoc-const.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-non-type-assoc-const.rs new file mode 100644 index 000000000000..67650bce8c89 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-non-type-assoc-const.rs @@ -0,0 +1,20 @@ +// Ensure that traits with non-type associated consts are dyn *in*compatible. + +//@ dont-require-annotations: NOTE + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { + const K: usize; + //~^ NOTE it contains associated const `K` that's not marked `#[type_const]` +} + +fn main() { + let _: dyn Trait; //~ ERROR the trait `Trait` is not dyn compatible + + // Check that specifying the non-type assoc const doesn't "magically make it work". + let _: dyn Trait; + //~^ ERROR the trait `Trait` is not dyn compatible + //~| ERROR use of trait associated const without `#[type_const]` +} diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-non-type-assoc-const.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-non-type-assoc-const.stderr new file mode 100644 index 000000000000..c579cd312f1f --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-non-type-assoc-const.stderr @@ -0,0 +1,43 @@ +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/dyn-compat-non-type-assoc-const.rs:14:16 + | +LL | let _: dyn Trait; + | ^^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/dyn-compat-non-type-assoc-const.rs:9:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | const K: usize; + | ^ ...because it contains associated const `K` that's not marked `#[type_const]` + = help: consider moving `K` to another trait + +error: use of trait associated const without `#[type_const]` + --> $DIR/dyn-compat-non-type-assoc-const.rs:17:22 + | +LL | let _: dyn Trait; + | ^^^^^ + | + = note: the declaration in the trait must be marked with `#[type_const]` + +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/dyn-compat-non-type-assoc-const.rs:17:16 + | +LL | let _: dyn Trait; + | ^^^^^^^^^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/dyn-compat-non-type-assoc-const.rs:9:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | const K: usize; + | ^ ...because it contains associated const `K` that's not marked `#[type_const]` + = help: consider moving `K` to another trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-unspecified-assoc-consts.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-unspecified-assoc-consts.rs new file mode 100644 index 000000000000..532c853c32b8 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-unspecified-assoc-consts.rs @@ -0,0 +1,25 @@ +// Traits with type associated consts are dyn compatible. However, all associated consts must +// be specified in the corresp. trait object type (barring exceptions) similiar to associated +// types. Check that we reject code that doesn't provide the necessary bindings. + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const K: usize; +} + +// fn ctxt / body +fn main() { + let _: dyn Trait; + //~^ ERROR the value of the associated type `K` in `Trait` must be specified +} + +// item ctxt / signature / non-body +struct Store(dyn Trait); +//~^ ERROR the value of the associated type `K` in `Trait` must be specified + +// item ctxt & no wfcking (eager ty alias) +type DynTrait = dyn Trait; +//~^ ERROR the value of the associated type `K` in `Trait` must be specified diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-unspecified-assoc-consts.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-unspecified-assoc-consts.stderr new file mode 100644 index 000000000000..37a4fdd38d3b --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-unspecified-assoc-consts.stderr @@ -0,0 +1,30 @@ +error[E0191]: the value of the associated type `K` in `Trait` must be specified + --> $DIR/dyn-compat-unspecified-assoc-consts.rs:20:18 + | +LL | const K: usize; + | -------------- `K` defined here +... +LL | struct Store(dyn Trait); + | ^^^^^ help: specify the associated type: `Trait` + +error[E0191]: the value of the associated type `K` in `Trait` must be specified + --> $DIR/dyn-compat-unspecified-assoc-consts.rs:24:21 + | +LL | const K: usize; + | -------------- `K` defined here +... +LL | type DynTrait = dyn Trait; + | ^^^^^ help: specify the associated type: `Trait` + +error[E0191]: the value of the associated type `K` in `Trait` must be specified + --> $DIR/dyn-compat-unspecified-assoc-consts.rs:15:16 + | +LL | const K: usize; + | -------------- `K` defined here +... +LL | let _: dyn Trait; + | ^^^^^ help: specify the associated type: `Trait` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0191`. diff --git a/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.stderr b/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.stderr index 7d563e3b6054..87ec5973fa28 100644 --- a/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.stderr +++ b/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.stderr @@ -11,7 +11,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait X { | - this trait is not dyn compatible... LL | type Y; - | ^ ...because it contains the generic associated type `Y` + | ^ ...because it contains generic associated type `Y` = help: consider moving `Y` to another trait error: aborting due to 1 previous error diff --git a/tests/ui/dyn-compatibility/associated-consts.stderr b/tests/ui/dyn-compatibility/associated-consts.stderr index dc64c93a577e..a92557ea7b8b 100644 --- a/tests/ui/dyn-compatibility/associated-consts.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/associated-consts.rs:8:31 + --> $DIR/associated-consts.rs:8:35 | LL | fn make_bar(t: &T) -> &dyn Bar { - | ^^^^^^^ `Bar` is not dyn compatible + | ^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -11,7 +11,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait Bar { | --- this trait is not dyn compatible... LL | const X: usize; - | ^ ...because it contains this associated `const` + | ^ ...because it contains associated const `X` = help: consider moving `X` to another trait error: aborting due to 1 previous error diff --git a/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr index cfebd5d69470..1189c8dc2a6a 100644 --- a/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr +++ b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr @@ -11,7 +11,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait Super { | ----- this trait is not dyn compatible... LL | type Assoc<'a>; - | ^^^^^ ...because it contains the generic associated type `Assoc` + | ^^^^^ ...because it contains generic associated type `Assoc` = help: consider moving `Assoc` to another trait error: aborting due to 1 previous error diff --git a/tests/ui/dyn-compatibility/missing-assoc-type.stderr b/tests/ui/dyn-compatibility/missing-assoc-type.stderr index 5a7560682f2e..5a5dc20590d0 100644 --- a/tests/ui/dyn-compatibility/missing-assoc-type.stderr +++ b/tests/ui/dyn-compatibility/missing-assoc-type.stderr @@ -11,7 +11,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait Foo { | --- this trait is not dyn compatible... LL | type Bar; - | ^^^ ...because it contains the generic associated type `Bar` + | ^^^ ...because it contains generic associated type `Bar` = help: consider moving `Bar` to another trait error: aborting due to 1 previous error diff --git a/tests/ui/dyn-compatibility/no-duplicate-e0038.stderr b/tests/ui/dyn-compatibility/no-duplicate-e0038.stderr index 94037387c3e1..bef580bcedb5 100644 --- a/tests/ui/dyn-compatibility/no-duplicate-e0038.stderr +++ b/tests/ui/dyn-compatibility/no-duplicate-e0038.stderr @@ -11,7 +11,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait Tr { | -- this trait is not dyn compatible... LL | const N: usize; - | ^ ...because it contains this associated `const` + | ^ ...because it contains associated const `N` = help: consider moving `N` to another trait = help: only type `u8` implements `Tr`; consider using it directly instead. diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr index ba4ce4753995..a8c2f512a9ad 100644 --- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr +++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr @@ -18,7 +18,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable --> $DIR/supertrait-mentions-GAT.rs:4:10 | LL | type Gat<'a> - | ^^^ ...because it contains the generic associated type `Gat` + | ^^^ ...because it contains generic associated type `Gat` ... LL | trait SuperTrait: for<'a> GatTrait = T> { | ---------- this trait is not dyn compatible... diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.stderr index d4ccd80f1465..8dec88f6d932 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path.stderr @@ -11,7 +11,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait Foo { | --- this trait is not dyn compatible... LL | type A<'a> where Self: 'a; - | ^ ...because it contains the generic associated type `A` + | ^ ...because it contains generic associated type `A` = help: consider moving `A` to another trait error[E0038]: the trait `Foo` is not dyn compatible @@ -27,7 +27,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait Foo { | --- this trait is not dyn compatible... LL | type A<'a> where Self: 'a; - | ^ ...because it contains the generic associated type `A` + | ^ ...because it contains generic associated type `A` = help: consider moving `A` to another trait error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/issue-67510-pass.stderr b/tests/ui/generic-associated-types/issue-67510-pass.stderr index 4b56c4ef35f4..8f47407089c7 100644 --- a/tests/ui/generic-associated-types/issue-67510-pass.stderr +++ b/tests/ui/generic-associated-types/issue-67510-pass.stderr @@ -11,7 +11,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait X { | - this trait is not dyn compatible... LL | type Y<'a>; - | ^ ...because it contains the generic associated type `Y` + | ^ ...because it contains generic associated type `Y` = help: consider moving `Y` to another trait error: aborting due to 1 previous error diff --git a/tests/ui/generic-associated-types/issue-76535.stderr b/tests/ui/generic-associated-types/issue-76535.stderr index 2daf9d817bb3..324f35e88293 100644 --- a/tests/ui/generic-associated-types/issue-76535.stderr +++ b/tests/ui/generic-associated-types/issue-76535.stderr @@ -27,7 +27,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | pub trait SuperTrait { | ---------- this trait is not dyn compatible... LL | type SubType<'a>: SubTrait where Self: 'a; - | ^^^^^^^ ...because it contains the generic associated type `SubType` + | ^^^^^^^ ...because it contains generic associated type `SubType` = help: consider moving `SubType` to another trait = help: only type `SuperStruct` implements `SuperTrait` within this crate; consider using it directly instead. = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type diff --git a/tests/ui/generic-associated-types/issue-78671.stderr b/tests/ui/generic-associated-types/issue-78671.stderr index fff061a8ada7..8b744622fc81 100644 --- a/tests/ui/generic-associated-types/issue-78671.stderr +++ b/tests/ui/generic-associated-types/issue-78671.stderr @@ -27,7 +27,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait CollectionFamily { | ---------------- this trait is not dyn compatible... LL | type Member; - | ^^^^^^ ...because it contains the generic associated type `Member` + | ^^^^^^ ...because it contains generic associated type `Member` = help: consider moving `Member` to another trait error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/issue-79422.stderr b/tests/ui/generic-associated-types/issue-79422.stderr index dcf3a9008de5..d22cc48e5290 100644 --- a/tests/ui/generic-associated-types/issue-79422.stderr +++ b/tests/ui/generic-associated-types/issue-79422.stderr @@ -27,7 +27,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait MapLike { | ------- this trait is not dyn compatible... LL | type VRefCont<'a>: RefCont<'a, V> - | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` + | ^^^^^^^^ ...because it contains generic associated type `VRefCont` = help: consider moving `VRefCont` to another trait error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/trait-objects.stderr b/tests/ui/generic-associated-types/trait-objects.stderr index 8c3af6b654ab..03a7eb76d91b 100644 --- a/tests/ui/generic-associated-types/trait-objects.stderr +++ b/tests/ui/generic-associated-types/trait-objects.stderr @@ -11,7 +11,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait StreamingIterator { | ----------------- this trait is not dyn compatible... LL | type Item<'a> where Self: 'a; - | ^^^^ ...because it contains the generic associated type `Item` + | ^^^^ ...because it contains generic associated type `Item` = help: consider moving `Item` to another trait error: aborting due to 1 previous error diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index eb72b307ed0f..acb67af53f18 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -141,15 +141,15 @@ note: for a trait to be dyn compatible it needs to allow building a vtable --> $DIR/item-privacy.rs:26:15 | LL | const A: u8 = 0; - | ^ ...because it contains this associated `const` + | ^ ...because it contains associated const `A` ... LL | const B: u8 = 0; - | ^ ...because it contains this associated `const` + | ^ ...because it contains associated const `B` ... LL | pub trait C: A + B { | - this trait is not dyn compatible... LL | const C: u8 = 0; - | ^ ...because it contains this associated `const` + | ^ ...because it contains associated const `C` = help: consider moving `C` to another trait = help: consider moving `A` to another trait = help: consider moving `B` to another trait @@ -166,15 +166,15 @@ note: for a trait to be dyn compatible it needs to allow building a vtable --> $DIR/item-privacy.rs:26:15 | LL | const A: u8 = 0; - | ^ ...because it contains this associated `const` + | ^ ...because it contains associated const `A` ... LL | const B: u8 = 0; - | ^ ...because it contains this associated `const` + | ^ ...because it contains associated const `B` ... LL | pub trait C: A + B { | - this trait is not dyn compatible... LL | const C: u8 = 0; - | ^ ...because it contains this associated `const` + | ^ ...because it contains associated const `C` = help: consider moving `C` to another trait = help: consider moving `A` to another trait = help: consider moving `B` to another trait diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr index bf79535df116..49651e8d6c05 100644 --- a/tests/ui/wf/issue-87495.stderr +++ b/tests/ui/wf/issue-87495.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `T` is not dyn compatible - --> $DIR/issue-87495.rs:4:25 + --> $DIR/issue-87495.rs:4:29 | LL | const CONST: (bool, dyn T); - | ^^^^^ `T` is not dyn compatible + | ^ `T` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -11,13 +11,8 @@ note: for a trait to be dyn compatible it needs to allow building a vtable LL | trait T { | - this trait is not dyn compatible... LL | const CONST: (bool, dyn T); - | ^^^^^ ...because it contains this associated `const` + | ^^^^^ ...because it contains associated const `CONST` = help: consider moving `CONST` to another trait -help: you might have meant to use `Self` to refer to the implementing type - | -LL - const CONST: (bool, dyn T); -LL + const CONST: (bool, Self); - | error: aborting due to 1 previous error