mGCA: Render traits dyn incompatible if the ty of an assoc const refs Self (barring Self projections)

This commit is contained in:
León Orell Valerian Liehr 2026-01-19 20:13:48 +01:00
parent 618c15eb6c
commit 7f5819317b
No known key found for this signature in database
GPG key ID: D17A07215F68E713
9 changed files with 292 additions and 118 deletions

View file

@ -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,

View file

@ -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<Self>`).
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<Span>),
}
/// 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 {

View file

@ -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<Output=Self::Result> { type Result; }`),
// `Self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
// we just require the user to specify *both* outputs
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
//
@ -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<MethodViolationCode> {
) -> Vec<MethodViolation> {
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<A>(...)`.
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<MethodViolationCode> {
) -> Option<MethodViolation> {
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<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
type Result = ControlFlow<MethodViolationCode>;
type Result = ControlFlow<MethodViolation>;
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 {

View file

@ -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<Self>` 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: <Self as SomeOtherTrait>::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<T: ?Sized> SomeOtherTrait for T {
type Output = ();
}
fn main() {
let _: dyn Trait; //~ ERROR the trait `Trait` is not dyn compatible
}

View file

@ -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 <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $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: <Self as SomeOtherTrait>::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`.

View file

@ -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<N = 0>; // OK
let _: &dyn Trait<N = 0> = &(); //~ ERROR the trait bound `(): Bound` is not satisfied
}

View file

@ -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<N = 0> = &();
| ^^^ 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`.

View file

@ -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<Ty = i32, CT = const -> i32 { 0 }>`
// * `dyn A<Ty = i32, CT: i32 = 0>`
let _: dyn A<Ty = i32, CT = 0>;
let _: &dyn A<Ty = i32, CT = 0> = &();
}

View file

@ -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<Ty = i32, CT = 0>;
| ^ 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<Ty = i32, CT = 0> = &();
| ^ 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`.