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 c1cbc44953ad..29f29761b605 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 @@ -58,6 +58,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut user_written_bounds = Vec::new(); let mut potential_assoc_items = Vec::new(); for poly_trait_ref in hir_bounds.iter() { + // FIXME(mgca): We actually leak `trait_object_dummy_self` if the type of any assoc + // const mentions `Self` (in "Self projections" which we intentionally + // allow). That's because we query feed the instantiated type to `type_of`. + // That's really bad, dummy self should never escape lowering! It leads us + // to accept less code we'd like to support and can lead to ICEs later. let result = self.lower_poly_trait_ref( poly_trait_ref, dummy_self, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 429db832884b..3a1682614cbf 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -761,12 +761,12 @@ pub struct ImplSourceUserDefinedData<'tcx, N> { #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)] pub enum DynCompatibilityViolation { - /// `Self: Sized` declared on the trait. - SizedSelf(SmallVec<[Span; 1]>), - /// Trait is marked `#[rustc_dyn_incompatible_trait]`. ExplicitlyDynIncompatible(SmallVec<[Span; 1]>), + /// `Self: Sized` declared on the trait. + SizedSelf(SmallVec<[Span; 1]>), + /// Supertrait reference references `Self` an in illegal location /// (e.g., `trait Foo : Bar`). SupertraitSelf(SmallVec<[Span; 1]>), @@ -778,29 +778,24 @@ pub enum DynCompatibilityViolation { SupertraitConst(SmallVec<[Span; 1]>), /// Method has something illegal. - Method(Symbol, MethodViolationCode, Span), + Method(Symbol, MethodViolation, Span), - /// Associated constant. - AssocConst(Symbol, Span), + /// Associated constant is faulty. + AssocConst(Symbol, AssocConstViolation, Span), - /// Generic associated constant. - GenericAssocConst(Symbol, Span), - - /// Associated constant that wasn't marked `#[type_const]`. - NonTypeAssocConst(Symbol, Span), - - /// Generic associated type. + /// Generic associated type (GAT). GenericAssocTy(Symbol, Span), } impl DynCompatibilityViolation { pub fn error_msg(&self) -> Cow<'static, str> { + // FIXME(mgca): For method violations we just say "method ..." but for assoc const ones we + // say "it contains ... associated constant ...". Make it consistent. + match self { - DynCompatibilityViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), - DynCompatibilityViolation::ExplicitlyDynIncompatible(_) => { - "it opted out of dyn-compatibility".into() - } - DynCompatibilityViolation::SupertraitSelf(spans) => { + Self::ExplicitlyDynIncompatible(_) => "it opted out of dyn-compatibility".into(), + Self::SizedSelf(_) => "it requires `Self: Sized`".into(), + Self::SupertraitSelf(spans) => { if spans.iter().any(|sp| *sp != DUMMY_SP) { "it uses `Self` as a type parameter".into() } else { @@ -808,67 +803,55 @@ impl DynCompatibilityViolation { .into() } } - DynCompatibilityViolation::SupertraitNonLifetimeBinder(_) => { + Self::SupertraitNonLifetimeBinder(_) => { "where clause cannot reference non-lifetime `for<...>` variables".into() } - DynCompatibilityViolation::SupertraitConst(_) => { - "it cannot have a `const` supertrait".into() - } - DynCompatibilityViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { + Self::SupertraitConst(_) => "it cannot have a `const` supertrait".into(), + Self::Method(name, MethodViolation::StaticMethod(_), _) => { format!("associated function `{name}` has no `self` parameter").into() } - DynCompatibilityViolation::Method( - name, - MethodViolationCode::ReferencesSelfInput(_), - DUMMY_SP, - ) => format!("method `{name}` references the `Self` type in its parameters").into(), - DynCompatibilityViolation::Method( - name, - MethodViolationCode::ReferencesSelfInput(_), - _, - ) => format!("method `{name}` references the `Self` type in this parameter").into(), - DynCompatibilityViolation::Method( - name, - MethodViolationCode::ReferencesSelfOutput, - _, - ) => format!("method `{name}` references the `Self` type in its return type").into(), - DynCompatibilityViolation::Method( - name, - MethodViolationCode::ReferencesImplTraitInTrait(_), - _, - ) => { + Self::Method(name, MethodViolation::ReferencesSelfInput(_), DUMMY_SP) => { + format!("method `{name}` references the `Self` type in its parameters").into() + } + Self::Method(name, MethodViolation::ReferencesSelfInput(_), _) => { + format!("method `{name}` references the `Self` type in this parameter").into() + } + Self::Method(name, MethodViolation::ReferencesSelfOutput, _) => { + format!("method `{name}` references the `Self` type in its return type").into() + } + Self::Method(name, MethodViolation::ReferencesImplTraitInTrait(_), _) => { format!("method `{name}` references an `impl Trait` type in its return type").into() } - DynCompatibilityViolation::Method(name, MethodViolationCode::AsyncFn, _) => { + Self::Method(name, MethodViolation::AsyncFn, _) => { format!("method `{name}` is `async`").into() } - DynCompatibilityViolation::Method(name, MethodViolationCode::CVariadic, _) => { + Self::Method(name, MethodViolation::CVariadic, _) => { format!("method `{name}` is C-variadic").into() } - DynCompatibilityViolation::Method( - name, - MethodViolationCode::WhereClauseReferencesSelf, - _, - ) => format!("method `{name}` references the `Self` type in its `where` clause").into(), - DynCompatibilityViolation::Method(name, MethodViolationCode::Generic, _) => { + Self::Method(name, MethodViolation::WhereClauseReferencesSelf, _) => { + format!("method `{name}` references the `Self` type in its `where` clause").into() + } + Self::Method(name, MethodViolation::Generic, _) => { format!("method `{name}` has generic type parameters").into() } - DynCompatibilityViolation::Method( - name, - MethodViolationCode::UndispatchableReceiver(_), - _, - ) => format!("method `{name}`'s `self` parameter cannot be dispatched on").into(), - DynCompatibilityViolation::AssocConst(name, _) => { + Self::Method(name, MethodViolation::UndispatchableReceiver(_), _) => { + format!("method `{name}`'s `self` parameter cannot be dispatched on").into() + } + Self::AssocConst(name, AssocConstViolation::FeatureNotEnabled, _) => { format!("it contains associated const `{name}`").into() } - DynCompatibilityViolation::GenericAssocConst(name, _) => { + Self::AssocConst(name, AssocConstViolation::Generic, _) => { format!("it contains generic associated const `{name}`").into() } - DynCompatibilityViolation::NonTypeAssocConst(name, _) => { + Self::AssocConst(name, AssocConstViolation::NonType, _) => { format!("it contains associated const `{name}` that's not marked `#[type_const]`") .into() } - DynCompatibilityViolation::GenericAssocTy(name, _) => { + Self::AssocConst(name, AssocConstViolation::TypeReferencesSelf, _) => format!( + "it contains associated const `{name}` whose type references the `Self` type" + ) + .into(), + Self::GenericAssocTy(name, _) => { format!("it contains generic associated type `{name}`").into() } } @@ -876,32 +859,24 @@ impl DynCompatibilityViolation { pub fn solution(&self) -> DynCompatibilityViolationSolution { match self { - DynCompatibilityViolation::SizedSelf(_) - | DynCompatibilityViolation::ExplicitlyDynIncompatible(_) - | DynCompatibilityViolation::SupertraitSelf(_) - | DynCompatibilityViolation::SupertraitNonLifetimeBinder(..) - | DynCompatibilityViolation::SupertraitConst(_) => { - DynCompatibilityViolationSolution::None - } - DynCompatibilityViolation::Method( + Self::ExplicitlyDynIncompatible(_) + | Self::SizedSelf(_) + | Self::SupertraitSelf(_) + | Self::SupertraitNonLifetimeBinder(..) + | Self::SupertraitConst(_) => DynCompatibilityViolationSolution::None, + Self::Method( name, - MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))), + MethodViolation::StaticMethod(Some((add_self_sugg, make_sized_sugg))), _, ) => DynCompatibilityViolationSolution::AddSelfOrMakeSized { name: *name, add_self_sugg: add_self_sugg.clone(), make_sized_sugg: make_sized_sugg.clone(), }, - DynCompatibilityViolation::Method( - name, - MethodViolationCode::UndispatchableReceiver(Some(span)), - _, - ) => DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span), - DynCompatibilityViolation::AssocConst(name, _) - | DynCompatibilityViolation::GenericAssocConst(name, _) - | DynCompatibilityViolation::NonTypeAssocConst(name, _) - | DynCompatibilityViolation::GenericAssocTy(name, _) - | DynCompatibilityViolation::Method(name, ..) => { + Self::Method(name, MethodViolation::UndispatchableReceiver(Some(span)), _) => { + DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span) + } + Self::Method(name, ..) | Self::AssocConst(name, ..) | Self::GenericAssocTy(name, _) => { DynCompatibilityViolationSolution::MoveToAnotherTrait(*name) } } @@ -911,16 +886,14 @@ impl DynCompatibilityViolation { // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so // diagnostics use a `note` instead of a `span_label`. match self { - DynCompatibilityViolation::SupertraitSelf(spans) - | DynCompatibilityViolation::SizedSelf(spans) - | DynCompatibilityViolation::ExplicitlyDynIncompatible(spans) - | DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans) - | DynCompatibilityViolation::SupertraitConst(spans) => spans.clone(), - DynCompatibilityViolation::AssocConst(_, span) - | DynCompatibilityViolation::GenericAssocConst(_, span) - | DynCompatibilityViolation::NonTypeAssocConst(_, span) - | DynCompatibilityViolation::GenericAssocTy(_, span) - | DynCompatibilityViolation::Method(_, _, span) => { + Self::ExplicitlyDynIncompatible(spans) + | Self::SizedSelf(spans) + | Self::SupertraitSelf(spans) + | Self::SupertraitNonLifetimeBinder(spans) + | Self::SupertraitConst(spans) => spans.clone(), + Self::Method(_, _, span) + | Self::AssocConst(_, _, span) + | Self::GenericAssocTy(_, span) => { if *span != DUMMY_SP { smallvec![*span] } else { @@ -987,7 +960,7 @@ impl DynCompatibilityViolationSolution { /// Reasons a method might not be dyn-compatible. #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)] -pub enum MethodViolationCode { +pub enum MethodViolation { /// e.g., `fn foo()` StaticMethod(Option<(/* add &self */ (String, Span), /* add Self: Sized */ (String, Span))>), @@ -1016,6 +989,22 @@ pub enum MethodViolationCode { UndispatchableReceiver(Option), } +/// Reasons an associated const might not be dyn compatible. +#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)] +pub enum AssocConstViolation { + /// Unstable feature `min_generic_const_args` wasn't enabled. + FeatureNotEnabled, + + /// Has own generic parameters (GAC). + Generic, + + /// Isn't marked `#[type_const]`. + NonType, + + /// Its type mentions the `Self` type parameter. + TypeReferencesSelf, +} + /// These are the error cases for `codegen_select_candidate`. #[derive(Copy, Clone, Debug, Hash, HashStable, Encodable, Decodable)] pub enum CodegenObligationError { diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index e8f0dd57353c..be70612653ce 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -25,7 +25,8 @@ use crate::infer::TyCtxtInferExt; pub use crate::traits::DynCompatibilityViolation; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{ - MethodViolationCode, Obligation, ObligationCause, normalize_param_env_or_error, util, + AssocConstViolation, MethodViolation, Obligation, ObligationCause, + normalize_param_env_or_error, util, }; /// Returns the dyn-compatibility violations that affect HIR ty lowering. @@ -230,7 +231,7 @@ fn predicate_references_self<'tcx>( // types for trait objects. // // Note that we *do* allow projection *outputs* to contain - // `self` (i.e., `trait Foo: Bar { type Result; }`), + // `Self` (i.e., `trait Foo: Bar { type Result; }`), // we just require the user to specify *both* outputs // in the object type (i.e., `dyn Foo`). // @@ -322,20 +323,36 @@ pub fn dyn_compatibility_violations_for_assoc_item( match item.kind { ty::AssocKind::Const { name } => { + // 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. + + let mut errors = Vec::new(); + if tcx.features().min_generic_const_args() { if !tcx.generics_of(item.def_id).is_own_empty() { - vec![DynCompatibilityViolation::GenericAssocConst(name, span())] + errors.push(AssocConstViolation::Generic); } 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() + errors.push(AssocConstViolation::NonType); + } + + let ty = ty::Binder::dummy(tcx.type_of(item.def_id).instantiate_identity()); + if contains_illegal_self_type_reference( + tcx, + trait_def_id, + ty, + AllowSelfProjections::Yes, + ) { + errors.push(AssocConstViolation::TypeReferencesSelf); } } else { - vec![DynCompatibilityViolation::AssocConst(name, span())] + errors.push(AssocConstViolation::FeatureNotEnabled); } + + errors + .into_iter() + .map(|error| DynCompatibilityViolation::AssocConst(name, error, span())) + .collect() } ty::AssocKind::Fn { name, .. } => { virtual_call_violations_for_method(tcx, trait_def_id, item) @@ -344,10 +361,10 @@ pub fn dyn_compatibility_violations_for_assoc_item( let node = tcx.hir_get_if_local(item.def_id); // Get an accurate span depending on the violation. let span = match (&v, node) { - (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, - (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, - (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span, - (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { + (MethodViolation::ReferencesSelfInput(Some(span)), _) => *span, + (MethodViolation::UndispatchableReceiver(Some(span)), _) => *span, + (MethodViolation::ReferencesImplTraitInTrait(span), _) => *span, + (MethodViolation::ReferencesSelfOutput, Some(node)) => { node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) } _ => span(), @@ -380,7 +397,7 @@ fn virtual_call_violations_for_method<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: ty::AssocItem, -) -> Vec { +) -> Vec { let sig = tcx.fn_sig(method.def_id).instantiate_identity(); // The method's first parameter must be named `self` @@ -408,7 +425,7 @@ fn virtual_call_violations_for_method<'tcx>( // Not having `self` parameter messes up the later checks, // so we need to return instead of pushing - return vec![MethodViolationCode::StaticMethod(sugg)]; + return vec![MethodViolation::StaticMethod(sugg)]; } let mut errors = Vec::new(); @@ -429,7 +446,7 @@ fn virtual_call_violations_for_method<'tcx>( } else { None }; - errors.push(MethodViolationCode::ReferencesSelfInput(span)); + errors.push(MethodViolation::ReferencesSelfInput(span)); } } if contains_illegal_self_type_reference( @@ -438,19 +455,19 @@ fn virtual_call_violations_for_method<'tcx>( sig.output(), AllowSelfProjections::Yes, ) { - errors.push(MethodViolationCode::ReferencesSelfOutput); + errors.push(MethodViolation::ReferencesSelfOutput); } - if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) { - errors.push(code); + if let Some(error) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) { + errors.push(error); } if sig.skip_binder().c_variadic { - errors.push(MethodViolationCode::CVariadic); + errors.push(MethodViolation::CVariadic); } // We can't monomorphize things like `fn foo(...)`. let own_counts = tcx.generics_of(method.def_id).own_counts(); if own_counts.types > 0 || own_counts.consts > 0 { - errors.push(MethodViolationCode::Generic); + errors.push(MethodViolation::Generic); } let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0)); @@ -470,7 +487,7 @@ fn virtual_call_violations_for_method<'tcx>( } else { None }; - errors.push(MethodViolationCode::UndispatchableReceiver(span)); + errors.push(MethodViolation::UndispatchableReceiver(span)); } else { // We confirm that the `receiver_is_dispatchable` is accurate later, // see `check_receiver_correct`. It should be kept in sync with this code. @@ -528,7 +545,7 @@ fn virtual_call_violations_for_method<'tcx>( contains_illegal_self_type_reference(tcx, trait_def_id, pred, AllowSelfProjections::Yes) }) { - errors.push(MethodViolationCode::WhereClauseReferencesSelf); + errors.push(MethodViolation::WhereClauseReferencesSelf); } errors @@ -870,12 +887,12 @@ fn contains_illegal_impl_trait_in_trait<'tcx>( tcx: TyCtxt<'tcx>, fn_def_id: DefId, ty: ty::Binder<'tcx, Ty<'tcx>>, -) -> Option { +) -> Option { let ty = tcx.liberate_late_bound_regions(fn_def_id, ty); if tcx.asyncness(fn_def_id).is_async() { // Rendering the error as a separate `async-specific` message is better. - Some(MethodViolationCode::AsyncFn) + Some(MethodViolation::AsyncFn) } else { ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value() } @@ -887,14 +904,14 @@ struct IllegalRpititVisitor<'tcx> { } impl<'tcx> TypeVisitor> for IllegalRpititVisitor<'tcx> { - type Result = ControlFlow; + type Result = ControlFlow; fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { if let ty::Alias(ty::Projection, proj) = *ty.kind() && Some(proj) != self.allowed && self.tcx.is_impl_trait_in_trait(proj.def_id) { - ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait( + ControlFlow::Break(MethodViolation::ReferencesImplTraitInTrait( self.tcx.def_span(proj.def_id), )) } else { diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs new file mode 100644 index 000000000000..d19e7acbaff0 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.rs @@ -0,0 +1,38 @@ +// Ensure that we consider traits dyn *in*compatible if the type of any (type) assoc const +// mentions `Self` (barring "`Self` projections") + +//@ dont-require-annotations: NOTE + +#![feature(generic_const_items)] +#![feature(generic_const_parameter_types)] +#![feature(min_generic_const_args)] +#![feature(unsized_const_params)] +#![expect(incomplete_features)] + +trait Trait { + // NOTE: The `ConstParamTy_` bound is intentionally on the assoc const and not on the trait as + // doing the latter would already render the trait dyn incompatible due to it being + // bounded by `PartialEq` and supertrait bounds cannot mention `Self` like this. + #[type_const] + const K: Self where Self: std::marker::ConstParamTy_; + //~^ NOTE it contains associated const `K` whose type references the `Self` type + + // This is not a "`Self` projection" in our sense (which would be allowed) + // since the trait is not the principal trait or a supertrait thereof. + #[type_const] + const Q: ::Output; + //~^ NOTE it contains associated const `Q` whose type references the `Self` type +} + +trait SomeOtherTrait { + type Output: std::marker::ConstParamTy_; +} + +// You could imagine this impl being more interesting and mention `T` somewhere in `Output`... +impl SomeOtherTrait for T { + type Output = (); +} + +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-assoc-const-ty-mentions-self.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.stderr new file mode 100644 index 000000000000..dba1643d2c5c --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-assoc-const-ty-mentions-self.stderr @@ -0,0 +1,24 @@ +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/dyn-compat-assoc-const-ty-mentions-self.rs:37: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-assoc-const-ty-mentions-self.rs:17:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +... +LL | const K: Self where Self: std::marker::ConstParamTy_; + | ^ ...because it contains associated const `K` whose type references the `Self` type +... +LL | const Q: ::Output; + | ^ ...because it contains associated const `Q` whose type references the `Self` type + = help: consider moving `K` to another trait + = help: consider moving `Q` 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-self-bound-on-assoc-const-allowed-and-enforced.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs new file mode 100644 index 000000000000..07ce629ab7be --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs @@ -0,0 +1,24 @@ +// Ensure that the where-clause of assoc consts in dyn-compatible traits are allowed to freely +// reference the `Self` type parameter (contrary to methods) and that such where clauses are +// actually enforced. + +#![feature(min_generic_const_args, generic_const_items)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const N: i32 where Self: Bound; +} + +impl Trait for () { + #[type_const] + const N: i32 = 0; +} + +trait Bound {} + +fn main() { + let _: dyn Trait; // OK + + let _: &dyn Trait = &(); //~ ERROR the trait bound `(): Bound` is not satisfied +} diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.stderr new file mode 100644 index 000000000000..8eeb60d55c38 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `(): Bound` is not satisfied + --> $DIR/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs:23:32 + | +LL | let _: &dyn Trait = &(); + | ^^^ the trait `Bound` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs:18:1 + | +LL | trait Bound {} + | ^^^^^^^^^^^ +note: required by a bound in `Trait::N` + --> $DIR/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs:10:30 + | +LL | const N: i32 where Self: Bound; + | ^^^^^ required by this bound in `Trait::N` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs new file mode 100644 index 000000000000..936556e957ca --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.rs @@ -0,0 +1,30 @@ +// FIXME(mgca): Ideally this would compile -- at least if the user annotated the instantiated type +// of the assoc const (but we don't have the syntax for this (yet)). In any case, we +// should not leak `trait_object_dummy_self` (defined as `FreshTy(0)` under the hood) +// to the rest of the compiler and by extension the user via diagnostics. +//@ known-bug: unknown + +#![feature(min_generic_const_args, unsized_const_params, generic_const_parameter_types)] +#![expect(incomplete_features)] + +trait A { + type Ty: std::marker::ConstParamTy_; + #[type_const] const CT: Self::Ty; +} + +impl A for () { + type Ty = i32; + #[type_const] const CT: i32 = 0; +} + +fn main() { + // NOTE: As alluded to above, if we can't get the examples below to compile as written, + // we might want to allow the user to manually specify the instantiated type somehow. + // The hypothetical syntax for that *might* look sth. like + // * `dyn A i32 { 0 }>` + // * `dyn A` + + let _: dyn A; + + let _: &dyn A = &(); +} diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr new file mode 100644 index 000000000000..8ee231ec070f --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `FreshTy(0): A` is not satisfied + --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:27:33 + | +LL | let _: dyn A; + | ^ the trait `A` is not implemented for `FreshTy(0)` + | +help: the trait `A` is implemented for `()` + --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:15:1 + | +LL | impl A for () { + | ^^^^^^^^^^^^^ + +error[E0277]: the trait bound `FreshTy(0): A` is not satisfied + --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:29:34 + | +LL | let _: &dyn A = &(); + | ^ the trait `A` is not implemented for `FreshTy(0)` + | +help: the trait `A` is implemented for `()` + --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:15:1 + | +LL | impl A for () { + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.