mGCA: Render traits dyn incompatible if the ty of an assoc const refs Self (barring Self projections)
This commit is contained in:
parent
618c15eb6c
commit
7f5819317b
9 changed files with 292 additions and 118 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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> = &();
|
||||
}
|
||||
|
|
@ -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`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue