Auto merge of #150843 - fmease:dyn-ace, r=BoxyUwU

mGCA: Make trait object types with type-level associated consts dyn compatible

Under feature `min_generic_const_args` (mGCA) (rust-lang/rust#132980), render traits with non-parametrized type-level associated constants (i.e., `#[type_const]` ones) dyn compatible but force the user to specify all type-level associated consts in the trait object type via bindings (either directly, via supertrait bounds and/or behind trait aliases) just like associated types, their sibling.

Fixes rust-lang/rust#130300 (feature request).
Fixes rust-lang/rust#136063 (bug).
Fixes rust-lang/rust#137260 (bug).
Fixes rust-lang/rust#137514 (bug).

While I'm accounting for most illegal `Self` references via const projections & params, I'm intentionally ignoring RUST-123140 (and duplicates) in this PR which is to be tackled some other time.

Additional context: Crate `rustc-demangle` had to be updated to fix v0 demangling. I've patched it in PR https://github.com/rust-lang/rustc-demangle/pull/87 which was was released in version 0.1.27 via PR https://github.com/rust-lang/rustc-demangle/pull/88.
This commit is contained in:
bors
2026-01-22 01:56:41 +00:00
108 changed files with 1442 additions and 702 deletions
+2 -2
View File
@@ -3356,9 +3356,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.26"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
[[package]]
name = "rustc-hash"
@@ -242,7 +242,7 @@ pub(crate) fn define_function<'tcx>(
let generics = tcx.generics_of(enclosing_fn_def_id);
let args = instance.args.truncate_to(tcx, generics);
type_names::push_generic_params(
type_names::push_generic_args(
tcx,
tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), args),
&mut name,
@@ -456,7 +456,7 @@ fn dbg_scope_fn(
let generics = tcx.generics_of(enclosing_fn_def_id);
let args = instance.args.truncate_to(tcx, generics);
type_names::push_generic_params(
type_names::push_generic_args(
tcx,
tcx.normalize_erasing_regions(self.typing_env(), args),
&mut name,
@@ -109,14 +109,14 @@ fn push_debuginfo_type_name<'tcx>(
ty_and_layout,
&|output, visited| {
push_item_name(tcx, def.did(), true, output);
push_generic_params_internal(tcx, args, output, visited);
push_generic_args_internal(tcx, args, output, visited);
},
output,
visited,
);
} else {
push_item_name(tcx, def.did(), qualified, output);
push_generic_params_internal(tcx, args, output, visited);
push_generic_args_internal(tcx, args, output, visited);
}
}
ty::Tuple(component_types) => {
@@ -253,19 +253,18 @@ fn push_debuginfo_type_name<'tcx>(
);
push_item_name(tcx, principal.def_id, qualified, output);
let principal_has_generic_params =
push_generic_params_internal(tcx, principal.args, output, visited);
push_generic_args_internal(tcx, principal.args, output, visited);
let projection_bounds: SmallVec<[_; 4]> = trait_data
.projection_bounds()
.map(|bound| {
let ExistentialProjection { def_id: item_def_id, term, .. } =
tcx.instantiate_bound_regions_with_erased(bound);
// FIXME(mgca): allow for consts here
(item_def_id, term.expect_type())
(item_def_id, term)
})
.collect();
if projection_bounds.len() != 0 {
if !projection_bounds.is_empty() {
if principal_has_generic_params {
// push_generic_params_internal() above added a `>` but we actually
// want to add more items to that list, so remove that again...
@@ -279,17 +278,17 @@ fn push_debuginfo_type_name<'tcx>(
output.push('<');
}
for (item_def_id, ty) in projection_bounds {
for (item_def_id, term) in projection_bounds {
if cpp_like_debuginfo {
output.push_str("assoc$<");
push_item_name(tcx, item_def_id, false, output);
push_arg_separator(cpp_like_debuginfo, output);
push_debuginfo_type_name(tcx, ty, true, output, visited);
push_debuginfo_term_name(tcx, term, true, output, visited);
push_close_angle_bracket(cpp_like_debuginfo, output);
} else {
push_item_name(tcx, item_def_id, false, output);
output.push('=');
push_debuginfo_type_name(tcx, ty, true, output, visited);
push_debuginfo_term_name(tcx, term, true, output, visited);
}
push_arg_separator(cpp_like_debuginfo, output);
}
@@ -533,7 +532,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref);
push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
visited.clear();
push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
push_generic_args_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
} else {
vtable_name.push('_');
}
@@ -631,7 +630,13 @@ fn push_unqualified_item_name(
};
}
fn push_generic_params_internal<'tcx>(
pub fn push_generic_args<'tcx>(tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, output: &mut String) {
let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
let mut visited = FxHashSet::default();
push_generic_args_internal(tcx, args, output, &mut visited);
}
fn push_generic_args_internal<'tcx>(
tcx: TyCtxt<'tcx>,
args: GenericArgsRef<'tcx>,
output: &mut String,
@@ -646,14 +651,10 @@ fn push_generic_params_internal<'tcx>(
output.push('<');
for type_parameter in args {
match type_parameter {
GenericArgKind::Type(type_parameter) => {
push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
}
GenericArgKind::Const(ct) => {
push_const_param(tcx, ct, output);
}
for arg in args {
match arg {
GenericArgKind::Type(ty) => push_debuginfo_type_name(tcx, ty, true, output, visited),
GenericArgKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output),
other => bug!("Unexpected non-erasable generic: {:?}", other),
}
@@ -665,7 +666,20 @@ fn push_generic_params_internal<'tcx>(
true
}
fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
fn push_debuginfo_term_name<'tcx>(
tcx: TyCtxt<'tcx>,
term: ty::Term<'tcx>,
qualified: bool,
output: &mut String,
visited: &mut FxHashSet<Ty<'tcx>>,
) {
match term.kind() {
ty::TermKind::Ty(ty) => push_debuginfo_type_name(tcx, ty, qualified, output, visited),
ty::TermKind::Const(ct) => push_debuginfo_const_name(tcx, ct, output),
}
}
fn push_debuginfo_const_name<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
match ct.kind() {
ty::ConstKind::Param(param) => {
write!(output, "{}", param.name)
@@ -715,16 +729,6 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
.unwrap();
}
pub fn push_generic_params<'tcx>(
tcx: TyCtxt<'tcx>,
args: GenericArgsRef<'tcx>,
output: &mut String,
) {
let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
let mut visited = FxHashSet::default();
push_generic_params_internal(tcx, args, output, &mut visited);
}
fn push_closure_or_coroutine_name<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
@@ -767,7 +771,7 @@ fn push_closure_or_coroutine_name<'tcx>(
// FIXME(async_closures): This is probably not going to be correct w.r.t.
// multiple coroutine flavors. Maybe truncate to (parent + 1)?
let args = args.truncate_to(tcx, generics);
push_generic_params_internal(tcx, args, output, visited);
push_generic_args_internal(tcx, args, output, visited);
}
fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
+30 -31
View File
@@ -165,6 +165,11 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
.label = parameter captured again here
hir_analysis_dyn_trait_assoc_item_binding_mentions_self =
{$kind} binding in trait object type mentions `Self`
.label = contains a mention of `Self`
.binding_label = this binding mentions `Self`
hir_analysis_eii_with_generics =
`{$impl_name}` cannot have generic parameters other than lifetimes
.label = required by this attribute
@@ -330,6 +335,31 @@ hir_analysis_manual_implementation =
hir_analysis_method_should_return_future = method should be `async` or return a future, but it is synchronous
.note = this method is `async` so it expects a future to be returned
hir_analysis_missing_generic_params =
the {$descr} {$parameterCount ->
[one] parameter
*[other] parameters
} {$parameters} must be explicitly specified
.label = {$descr} {$parameterCount ->
[one] parameter
*[other] parameters
} {$parameters} must be specified for this
.suggestion = explicitly specify the {$descr} {$parameterCount ->
[one] parameter
*[other] parameters
}
.no_suggestion_label = missing {$parameterCount ->
[one] reference
*[other] references
} to {$parameters}
.note = because the parameter {$parameterCount ->
[one] default references
*[other] defaults reference
} `Self`, the {$parameterCount ->
[one] parameter
*[other] parameters
} must be specified on the trait object type
hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}`
.label = missing one of `{$missing_items_msg}` in implementation
.note = required because of this annotation
@@ -346,34 +376,6 @@ hir_analysis_missing_trait_item_unstable = not all trait items implemented, miss
.some_note = use of unstable library feature `{$feature}`: {$reason}
.none_note = use of unstable library feature `{$feature}`
hir_analysis_missing_type_params =
the type {$parameterCount ->
[one] parameter
*[other] parameters
} {$parameters} must be explicitly specified
.label = type {$parameterCount ->
[one] parameter
*[other] parameters
} {$parameters} must be specified for this
.suggestion = set the type {$parameterCount ->
[one] parameter
*[other] parameters
} to the desired {$parameterCount ->
[one] type
*[other] types
}
.no_suggestion_label = missing {$parameterCount ->
[one] reference
*[other] references
} to {$parameters}
.note = because the parameter {$parameterCount ->
[one] default references
*[other] defaults reference
} `Self`, the {$parameterCount ->
[one] parameter
*[other] parameters
} must be specified on the object type
hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}`
hir_analysis_not_supported_delegation = {$descr}
@@ -481,9 +483,6 @@ hir_analysis_self_in_impl_self =
`Self` is not valid in the self type of an impl block
.note = replace `Self` with a different type
hir_analysis_self_in_type_alias = `Self` is not allowed in type aliases
.label = `Self` is only available in impls, traits, and concrete type definitions
hir_analysis_self_ty_not_captured = `impl Trait` must mention the `Self` type of the trait in `use<...>`
.label = `Self` type parameter is implicitly captured by this `impl Trait`
.note = currently, all type parameters are required to be mentioned in the precise captures list
@@ -1960,7 +1960,7 @@ fn compare_generic_param_kinds<'tcx>(
trait_item: ty::AssocItem,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
assert_eq!(impl_item.as_tag(), trait_item.as_tag());
assert_eq!(impl_item.tag(), trait_item.tag());
let ty_const_params_of = |def_id| {
tcx.generics_of(def_id).own_params.iter().filter(|param| {
+50 -24
View File
@@ -4,11 +4,11 @@
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
MultiSpan,
MultiSpan, listify,
};
use rustc_hir::limit::Limit;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_middle::ty::{self, Ty};
use rustc_span::{Ident, Span, Symbol};
use crate::fluent_generated as fluent;
@@ -400,35 +400,58 @@ pub(crate) struct UnconstrainedOpaqueType {
pub what: &'static str,
}
pub(crate) struct MissingTypeParams {
pub(crate) struct MissingGenericParams {
pub span: Span,
pub def_span: Span,
pub span_snippet: Option<String>,
pub missing_type_params: Vec<Symbol>,
pub missing_generic_params: Vec<(Symbol, ty::GenericParamDefKind)>,
pub empty_generic_args: bool,
}
// Manual implementation of `Diagnostic` to be able to call `span_to_snippet`.
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams {
// FIXME: This doesn't need to be a manual impl!
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams {
#[track_caller]
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_type_params);
let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_generic_params);
err.span(self.span);
err.code(E0393);
err.arg("parameterCount", self.missing_type_params.len());
err.arg(
"parameters",
self.missing_type_params
.iter()
.map(|n| format!("`{n}`"))
.collect::<Vec<_>>()
.join(", "),
);
err.span_label(self.def_span, fluent::hir_analysis_label);
enum Descr {
Generic,
Type,
Const,
}
let mut descr = None;
for (_, kind) in &self.missing_generic_params {
descr = match (&descr, kind) {
(None, ty::GenericParamDefKind::Type { .. }) => Some(Descr::Type),
(None, ty::GenericParamDefKind::Const { .. }) => Some(Descr::Const),
(Some(Descr::Type), ty::GenericParamDefKind::Const { .. })
| (Some(Descr::Const), ty::GenericParamDefKind::Type { .. }) => {
Some(Descr::Generic)
}
_ => continue,
}
}
err.arg(
"descr",
match descr.unwrap() {
Descr::Generic => "generic",
Descr::Type => "type",
Descr::Const => "const",
},
);
err.arg("parameterCount", self.missing_generic_params.len());
err.arg(
"parameters",
listify(&self.missing_generic_params, |(n, _)| format!("`{n}`")).unwrap(),
);
let mut suggested = false;
// Don't suggest setting the type params if there are some already: the order is
// Don't suggest setting the generic params if there are some already: The order is
// tricky to get right and the user will already know what the syntax is.
if let Some(snippet) = self.span_snippet
&& self.empty_generic_args
@@ -438,16 +461,16 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
// we would have to preserve the right order. For now, as clearly the user is
// aware of the syntax, we do nothing.
} else {
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
// least we can clue them to the correct syntax `Iterator<Type>`.
// The user wrote `Trait`, so we don't have a type we can suggest, but at
// least we can clue them to the correct syntax `Trait</* Term */>`.
err.span_suggestion_verbose(
self.span.shrink_to_hi(),
fluent::hir_analysis_suggestion,
format!(
"<{}>",
self.missing_type_params
self.missing_generic_params
.iter()
.map(|n| n.to_string())
.map(|(n, _)| format!("/* {n} */"))
.collect::<Vec<_>>()
.join(", ")
),
@@ -1609,11 +1632,14 @@ pub(crate) enum SupertraitItemShadowee {
}
#[derive(Diagnostic)]
#[diag(hir_analysis_self_in_type_alias, code = E0411)]
pub(crate) struct SelfInTypeAlias {
#[diag(hir_analysis_dyn_trait_assoc_item_binding_mentions_self)]
pub(crate) struct DynTraitAssocItemBindingMentionsSelf {
#[primary_span]
#[label]
pub span: Span,
pub kind: &'static str,
#[label(hir_analysis_binding_label)]
pub binding: Span,
}
#[derive(Diagnostic)]
@@ -22,7 +22,7 @@
use tracing::{debug, instrument};
use super::HirTyLowerer;
use crate::errors::SelfInTypeAlias;
use crate::errors::DynTraitAssocItemBindingMentionsSelf;
use crate::hir_ty_lowering::{
GenericArgCountMismatch, ImpliedBoundsContext, OverlappingAsssocItemConstraints,
PredicateFilter, RegionInferReason,
@@ -56,8 +56,13 @@ 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() {
// 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,
@@ -66,7 +71,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,31 +143,33 @@ 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:
// ```
// type Alias = Trait<Assoc = i32>;
// let _: &dyn Alias<Assoc = u32> = /* ... */;
// ```
// Also make sure we detect conflicting bounds from expanding trait aliases.
//
// FIXME(#150936): Since the elaborated projection bounds also include the user-written ones
// and we're separately rejecting duplicate+conflicting bindings for trait
// object types when lowering assoc item bindings, there are basic cases
// where we're emitting two distinct but very similar diagnostics.
let mut projection_bounds = FxIndexMap::default();
for (proj, proj_span) in elaborated_projection_bounds {
let proj = proj.map_bound(|mut b| {
if let Some(term_ty) = &b.term.as_type() {
let references_self = term_ty.walk().any(|arg| arg == dummy_self.into());
if references_self {
// With trait alias and type alias combined, type resolver
// may not be able to catch all illegal `Self` usages (issue 139082)
let guar = self.dcx().emit_err(SelfInTypeAlias { span });
b.term = replace_dummy_self_with_error(tcx, b.term, guar);
}
let item_def_id = proj.item_def_id();
let proj = proj.map_bound(|mut proj| {
let references_self = proj.term.walk().any(|arg| arg == dummy_self.into());
if references_self {
let guar = self.dcx().emit_err(DynTraitAssocItemBindingMentionsSelf {
span,
kind: tcx.def_descr(item_def_id),
binding: proj_span,
});
proj.term = replace_dummy_self_with_error(tcx, proj.term, guar);
}
b
proj
});
let key = (
proj.skip_binder().projection_term.def_id,
item_def_id,
tcx.anonymize_bound_vars(
proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
),
@@ -171,19 +178,17 @@ pub(super) fn lower_trait_object_ty(
projection_bounds.insert(key, (proj, proj_span))
&& tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
{
let item = tcx.item_name(proj.item_def_id());
let kind = tcx.def_descr(item_def_id);
let name = tcx.item_name(item_def_id);
self.dcx()
.struct_span_err(
span,
format!("conflicting associated type bounds for `{item}`"),
)
.struct_span_err(span, format!("conflicting {kind} bindings for `{name}`"))
.with_span_label(
old_proj_span,
format!("`{item}` is specified to be `{}` here", old_proj.term()),
format!("`{name}` is specified to be `{}` here", old_proj.term()),
)
.with_span_label(
proj_span,
format!("`{item}` is specified to be `{}` here", proj.term()),
format!("`{name}` is specified to be `{}` here", proj.term()),
)
.emit();
}
@@ -191,13 +196,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: <https://github.com/rust-lang/rust/pull/136458>.
// 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:
// <https://github.com/rust-lang/rust/pull/136458>.
// 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 +227,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)),
);
@@ -237,11 +241,8 @@ pub(super) fn lower_trait_object_ty(
let pred = bound_predicate.rebind(pred);
// A `Self` within the original bound will be instantiated with a
// `trait_object_dummy_self`, so check for that.
let references_self = match pred.skip_binder().term.kind() {
ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
// FIXME(mgca): We should walk the const instead of not doing anything
ty::TermKind::Const(_) => false,
};
let references_self =
pred.skip_binder().term.walk().any(|arg| arg == dummy_self.into());
// If the projection output contains `Self`, force the user to
// elaborate it explicitly to avoid a lot of complexity.
@@ -262,7 +263,7 @@ pub(super) fn lower_trait_object_ty(
// the discussion in #56288 for alternatives.
if !references_self {
let key = (
pred.skip_binder().projection_term.def_id,
pred.item_def_id(),
tcx.anonymize_bound_vars(
pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
),
@@ -283,15 +284,13 @@ pub(super) fn lower_trait_object_ty(
}
}
// `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where
// <Self as Trait>::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 +300,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 <https://github.com/rust-lang/rust/pull/140684>.
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 let Err(guar) = self.check_for_required_assoc_tys(
// 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_items(
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);
@@ -354,9 +354,9 @@ pub(super) fn lower_trait_object_ty(
let span = *spans.first().unwrap();
// Verify that `dummy_self` did not leak inside default type parameters. This
// Verify that `dummy_self` did not leak inside generic parameter defaults. This
// could not be done at path creation, since we need to see through trait aliases.
let mut missing_type_params = vec![];
let mut missing_generic_params = Vec::new();
let generics = tcx.generics_of(trait_ref.def_id);
let args: Vec<_> = trait_ref
.args
@@ -367,8 +367,8 @@ pub(super) fn lower_trait_object_ty(
.map(|(index, arg)| {
if arg.walk().any(|arg| arg == dummy_self.into()) {
let param = &generics.own_params[index];
missing_type_params.push(param.name);
Ty::new_misc_error(tcx).into()
missing_generic_params.push((param.name, param.kind.clone()));
param.to_error(tcx)
} else {
arg
}
@@ -379,8 +379,8 @@ pub(super) fn lower_trait_object_ty(
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
&& hir_bound.span.contains(span)
});
self.report_missing_type_params(
missing_type_params,
self.report_missing_generic_params(
missing_generic_params,
trait_ref.def_id,
span,
empty_generic_args,
@@ -28,31 +28,29 @@
use super::InherentAssocCandidate;
use crate::errors::{
self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
self, AssocItemConstraintsNotAllowedHere, ManualImplementation, ParenthesizedFnTraitExpansion,
TraitObjectDeclaredWithNoTraits,
};
use crate::fluent_generated as fluent;
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
/// the type parameter's name as a placeholder.
pub(crate) fn report_missing_type_params(
pub(crate) fn report_missing_generic_params(
&self,
missing_type_params: Vec<Symbol>,
missing_generic_params: Vec<(Symbol, ty::GenericParamDefKind)>,
def_id: DefId,
span: Span,
empty_generic_args: bool,
) {
if missing_type_params.is_empty() {
if missing_generic_params.is_empty() {
return;
}
self.dcx().emit_err(MissingTypeParams {
self.dcx().emit_err(errors::MissingGenericParams {
span,
def_span: self.tcx().def_span(def_id),
span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
missing_type_params,
missing_generic_params,
empty_generic_args,
});
}
@@ -171,7 +169,7 @@ pub(super) fn report_unresolved_assoc_item<I>(
let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
.filter_map(|item| {
if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag {
if !item.is_impl_trait_in_trait() && item.tag() == assoc_tag {
item.opt_name()
} else {
None
@@ -207,7 +205,7 @@ pub(super) fn report_unresolved_assoc_item<I>(
.iter()
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
.filter_map(|item| {
(!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then(|| item.name())
(!item.is_impl_trait_in_trait() && item.tag() == assoc_tag).then(|| item.name())
})
.collect();
@@ -220,7 +218,7 @@ pub(super) fn report_unresolved_assoc_item<I>(
.filter(|trait_def_id| {
tcx.associated_items(trait_def_id)
.filter_by_name_unhygienic(suggested_name)
.any(|item| item.as_tag() == assoc_tag)
.any(|item| item.tag() == assoc_tag)
})
.collect::<Vec<_>>()[..]
{
@@ -383,9 +381,9 @@ fn report_assoc_kind_mismatch(
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(ct) => ct.span,
};
(span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
(span, Some(ident.span), assoc_item.tag(), assoc_tag)
} else {
(ident.span, None, assoc_tag, assoc_item.as_tag())
(ident.span, None, assoc_tag, assoc_item.tag())
};
self.dcx().emit_err(errors::AssocKindMismatch {
@@ -393,7 +391,7 @@ fn report_assoc_kind_mismatch(
expected: assoc_tag_str(expected),
got: assoc_tag_str(got),
expected_because_label,
assoc_kind: assoc_tag_str(assoc_item.as_tag()),
assoc_kind: assoc_tag_str(assoc_item.tag()),
def_span: tcx.def_span(assoc_item.def_id),
bound_on_assoc_const_label,
wrap_in_braces_sugg,
@@ -909,43 +907,49 @@ pub(crate) fn report_unresolved_inherent_assoc_item(
err.emit()
}
/// When there are any missing associated types, emit an E0191 error and attempt to supply a
/// reasonable suggestion on how to write it. For the case of multiple associated types in the
/// same trait bound have the same name (as they come from different supertraits), we instead
/// emit a generic note suggesting using a `where` clause to constraint instead.
pub(crate) fn check_for_required_assoc_tys(
/// If there are any missing associated items, emit an error instructing the user to provide
/// them unless that's impossible due to shadowing. Moreover, if any corresponding trait refs
/// are dyn incompatible due to associated items we emit an dyn incompatibility error instead.
pub(crate) fn check_for_required_assoc_items(
&self,
spans: SmallVec<[Span; 1]>,
missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
potential_assoc_types: Vec<usize>,
missing_assoc_items: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
potential_assoc_items: Vec<usize>,
trait_bounds: &[hir::PolyTraitRef<'_>],
) -> Result<(), ErrorGuaranteed> {
if missing_assoc_types.is_empty() {
if missing_assoc_items.is_empty() {
return Ok(());
}
let tcx = self.tcx();
let principal_span = *spans.first().unwrap();
let tcx = self.tcx();
// FIXME: This logic needs some more care w.r.t handling of conflicts
let missing_assoc_types: Vec<_> = missing_assoc_types
let missing_assoc_items: Vec<_> = missing_assoc_items
.into_iter()
.map(|(def_id, trait_ref)| (tcx.associated_item(def_id), trait_ref))
.collect();
let mut names: FxIndexMap<_, Vec<Symbol>> = Default::default();
let mut names: FxIndexMap<_, Vec<_>> = Default::default();
let mut names_len = 0;
let mut descr = None;
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
// `issue-22560.rs`.
let mut dyn_compatibility_violations = Ok(());
for (assoc_item, trait_ref) in &missing_assoc_types {
names.entry(trait_ref).or_default().push(assoc_item.name());
names_len += 1;
enum Descr {
Item,
Tag(ty::AssocTag),
}
for &(assoc_item, trait_ref) in &missing_assoc_items {
// We don't want to suggest specifying associated items if there's something wrong with
// any of them that renders the trait dyn incompatible; providing them certainly won't
// fix the issue and we could also risk suggesting invalid code.
//
// Note that this check is only truly necessary in item ctxts where we merely perform
// *minimal* dyn compatibility checks. In fn ctxts we would've already bailed out with
// an error by this point if the trait was dyn incompatible.
let violations =
dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), *assoc_item);
dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), assoc_item);
if !violations.is_empty() {
dyn_compatibility_violations = Err(report_dyn_incompatibility(
return Err(report_dyn_incompatibility(
tcx,
principal_span,
None,
@@ -954,15 +958,20 @@ pub(crate) fn check_for_required_assoc_tys(
)
.emit());
}
}
if let Err(guar) = dyn_compatibility_violations {
return Err(guar);
names.entry(trait_ref).or_default().push(assoc_item.name());
names_len += 1;
descr = match descr {
None => Some(Descr::Tag(assoc_item.tag())),
Some(Descr::Tag(tag)) if tag != assoc_item.tag() => Some(Descr::Item),
_ => continue,
};
}
// related to issue #91997, turbofishes added only when in an expr or pat
let mut in_expr_or_pat = false;
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
if let ([], [bound]) = (&potential_assoc_items[..], &trait_bounds) {
let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
in_expr_or_pat = match grandparent {
hir::Node::Expr(_) | hir::Node::Pat(_) => true,
@@ -970,37 +979,41 @@ pub(crate) fn check_for_required_assoc_tys(
};
}
// We get all the associated items that _are_ set,
// so that we can check if any of their names match one of the ones we are missing.
// This would mean that they are shadowing the associated type we are missing,
// and we can then use their span to indicate this to the user.
let bound_names = trait_bounds
.iter()
.filter_map(|poly_trait_ref| {
let path = poly_trait_ref.trait_ref.path.segments.last()?;
let args = path.args?;
// We get all the associated items that *are* set, so that we can check if any of
// their names match one of the ones we are missing.
// This would mean that they are shadowing the associated item we are missing, and
// we can then use their span to indicate this to the user.
//
// FIXME: This does not account for trait aliases. I think we should just make
// `lower_trait_object_ty` compute the list of all specified items or give us the
// necessary ingredients if it's too expensive to compute in the happy path.
let bound_names: UnordMap<_, _> =
trait_bounds
.iter()
.filter_map(|poly_trait_ref| {
let path = poly_trait_ref.trait_ref.path.segments.last()?;
let args = path.args?;
let Res::Def(DefKind::Trait, trait_def_id) = path.res else { return None };
Some(args.constraints.iter().filter_map(|constraint| {
let ident = constraint.ident;
Some(args.constraints.iter().filter_map(move |constraint| {
let hir::AssocItemConstraintKind::Equality { term } = constraint.kind
else {
return None;
};
let tag = match term {
hir::Term::Ty(_) => ty::AssocTag::Type,
hir::Term::Const(_) => ty::AssocTag::Const,
};
let assoc_item = tcx
.associated_items(trait_def_id)
.find_by_ident_and_kind(tcx, constraint.ident, tag, trait_def_id)?;
Some(((constraint.ident.name, tag), assoc_item.def_id))
}))
})
.flatten()
.collect();
let Res::Def(DefKind::Trait, trait_def) = path.res else {
return None;
};
let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
tcx,
ident,
ty::AssocTag::Type,
trait_def,
);
Some((ident.name, assoc_item?))
}))
})
.flatten()
.collect::<UnordMap<Symbol, &ty::AssocItem>>();
let mut names = names
let mut names: Vec<_> = names
.into_iter()
.map(|(trait_, mut assocs)| {
assocs.sort();
@@ -1010,66 +1023,69 @@ pub(crate) fn check_for_required_assoc_tys(
listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default()
)
})
.collect::<Vec<String>>();
.collect();
names.sort();
let names = names.join(", ");
let descr = match descr.unwrap() {
Descr::Item => "associated item",
Descr::Tag(tag) => tag.descr(),
};
let mut err = struct_span_code_err!(
self.dcx(),
principal_span,
E0191,
"the value of the associated type{} {} must be specified",
pluralize!(names_len),
names,
"the value of the {descr}{s} {names} must be specified",
s = pluralize!(names_len),
);
let mut suggestions = vec![];
let mut types_count = 0;
let mut items_count = 0;
let mut where_constraints = vec![];
let mut already_has_generics_args_suggestion = false;
let mut names: UnordMap<_, usize> = Default::default();
for (item, _) in &missing_assoc_types {
types_count += 1;
*names.entry(item.name()).or_insert(0) += 1;
for (item, _) in &missing_assoc_items {
items_count += 1;
*names.entry((item.name(), item.tag())).or_insert(0) += 1;
}
let mut dupes = false;
let mut shadows = false;
for (item, trait_ref) in &missing_assoc_types {
for (item, trait_ref) in &missing_assoc_items {
let name = item.name();
let prefix = if names[&name] > 1 {
let trait_def_id = trait_ref.def_id();
let key = (name, item.tag());
if names[&key] > 1 {
dupes = true;
format!("{}::", tcx.def_path_str(trait_def_id))
} else if bound_names.get(&name).is_some_and(|x| *x != item) {
let trait_def_id = trait_ref.def_id();
} else if bound_names.get(&key).is_some_and(|&def_id| def_id != item.def_id) {
shadows = true;
format!("{}::", tcx.def_path_str(trait_def_id))
}
let prefix = if dupes || shadows {
format!("{}::", tcx.def_path_str(trait_ref.def_id()))
} else {
String::new()
};
let mut is_shadowed = false;
if let Some(assoc_item) = bound_names.get(&name)
&& *assoc_item != item
if let Some(&def_id) = bound_names.get(&key)
&& def_id != item.def_id
{
is_shadowed = true;
let rename_message =
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
let rename_message = if def_id.is_local() { ", consider renaming it" } else { "" };
err.span_label(
tcx.def_span(assoc_item.def_id),
format!("`{}{}` shadowed here{}", prefix, name, rename_message),
tcx.def_span(def_id),
format!("`{prefix}{name}` shadowed here{rename_message}"),
);
}
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message));
err.span_label(sp, format!("`{prefix}{name}` defined here{rename_message}"));
}
}
if potential_assoc_types.len() == missing_assoc_types.len() {
if potential_assoc_items.len() == missing_assoc_items.len() {
// When the amount of missing associated types equals the number of
// extra type arguments present. A suggesting to replace the generic args with
// associated types is already emitted.
@@ -1077,30 +1093,48 @@ pub(crate) fn check_for_required_assoc_tys(
} else if let (Ok(snippet), false, false) =
(tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
{
let types: Vec<_> = missing_assoc_types
let bindings: Vec<_> = missing_assoc_items
.iter()
.map(|(item, _)| format!("{} = Type", item.name()))
.map(|(item, _)| {
format!(
"{} = /* {} */",
item.name(),
match item.kind {
ty::AssocKind::Const { .. } => "CONST",
ty::AssocKind::Type { .. } => "Type",
ty::AssocKind::Fn { .. } => unreachable!(),
}
)
})
.collect();
// FIXME(fmease): Does not account for `dyn Trait<>` (suggs `dyn Trait<, X = Y>`).
let code = if let Some(snippet) = snippet.strip_suffix('>') {
// The user wrote `Trait<'a>` or similar and we don't have a type we can
// suggest, but at least we can clue them to the correct syntax
// `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
// suggestion.
format!("{}, {}>", snippet, types.join(", "))
// The user wrote `Trait<'a>` or similar and we don't have a term we can suggest,
// but at least we can clue them to the correct syntax `Trait<'a, Item = /* ... */>`
// while accounting for the `<'a>` in the suggestion.
format!("{}, {}>", snippet, bindings.join(", "))
} else if in_expr_or_pat {
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
// least we can clue them to the correct syntax `Iterator::<Item = Type>`.
format!("{}::<{}>", snippet, types.join(", "))
// The user wrote `Trait`, so we don't have a term we can suggest, but at least we
// can clue them to the correct syntax `Trait::<Item = /* ... */>`.
format!("{}::<{}>", snippet, bindings.join(", "))
} else {
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
// least we can clue them to the correct syntax `Iterator<Item = Type>`.
format!("{}<{}>", snippet, types.join(", "))
// The user wrote `Trait`, so we don't have a term we can suggest, but at least we
// can clue them to the correct syntax `Trait<Item = /* ... */>`.
format!("{}<{}>", snippet, bindings.join(", "))
};
suggestions.push((principal_span, code));
} else if dupes {
where_constraints.push(principal_span);
}
// FIXME: This note doesn't make sense, get rid of this outright.
// I don't see how adding a type param (to the trait?) would help.
// If the user can modify the trait, they should just rename one of the assoc tys.
// What does it mean with the rest of the message?
// Does it suggest adding equality predicates (unimplemented) to the trait object
// type? (pseudo) "dyn B + <Self as B>::X = T + <Self as A>::X = U"?
// Instead, maybe mention shadowing if applicable (yes, even when no "relevant"
// bindings were provided).
let where_msg = "consider introducing a new type parameter, adding `where` constraints \
using the fully-qualified path to the associated types";
if !where_constraints.is_empty() && suggestions.is_empty() {
@@ -1112,12 +1146,12 @@ pub(crate) fn check_for_required_assoc_tys(
if suggestions.len() != 1 || already_has_generics_args_suggestion {
// We don't need this label if there's an inline suggestion, show otherwise.
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
for (item, _) in &missing_assoc_types {
types_count += 1;
for (item, _) in &missing_assoc_items {
items_count += 1;
*names.entry(item.name()).or_insert(0) += 1;
}
let mut label = vec![];
for (item, trait_ref) in &missing_assoc_types {
for (item, trait_ref) in &missing_assoc_items {
let name = item.name();
let postfix = if names[&name] > 1 {
format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
@@ -1130,9 +1164,9 @@ pub(crate) fn check_for_required_assoc_tys(
err.span_label(
principal_span,
format!(
"associated type{} {} must be specified",
pluralize!(label.len()),
label.join(", "),
"{descr}{s} {names} must be specified",
s = pluralize!(label.len()),
names = label.join(", "),
),
);
}
@@ -1153,7 +1187,7 @@ pub(crate) fn check_for_required_assoc_tys(
let overlaps = suggestions.windows(2).any(|pair| pair[0].0.overlaps(pair[1].0));
if !suggestions.is_empty() && !overlaps {
err.multipart_suggestion(
format!("specify the associated type{}", pluralize!(types_count)),
format!("specify the {descr}{s}", s = pluralize!(items_count)),
suggestions,
Applicability::HasPlaceholders,
);
@@ -1768,7 +1768,7 @@ fn probe_assoc_item_unchecked(
let item = tcx
.associated_items(scope)
.filter_by_name_unhygienic(ident.name)
.find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
.find(|i| i.tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
Some((*item, def_scope))
}
+88 -85
View File
@@ -759,14 +759,14 @@ pub struct ImplSourceUserDefinedData<'tcx, N> {
pub nested: ThinVec<N>,
}
#[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]>),
/// 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,23 +778,24 @@ pub enum DynCompatibilityViolation {
SupertraitConst(SmallVec<[Span; 1]>),
/// Method has something illegal.
Method(Symbol, MethodViolationCode, Span),
Method(Symbol, MethodViolation, Span),
/// Associated const.
AssocConst(Symbol, Span),
/// Associated constant is faulty.
AssocConst(Symbol, AssocConstViolation, Span),
/// GAT
GAT(Symbol, Span),
/// 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 {
@@ -802,94 +803,80 @@ pub fn error_msg(&self) -> Cow<'static, str> {
.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, DUMMY_SP) => {
format!("it contains associated `const` `{name}`").into()
Self::Method(name, MethodViolation::UndispatchableReceiver(_), _) => {
format!("method `{name}`'s `self` parameter cannot be dispatched on").into()
}
DynCompatibilityViolation::AssocConst(..) => {
"it contains this associated `const`".into()
Self::AssocConst(name, AssocConstViolation::FeatureNotEnabled, _) => {
format!("it contains associated const `{name}`").into()
}
DynCompatibilityViolation::GAT(name, _) => {
format!("it contains the generic associated type `{name}`").into()
Self::AssocConst(name, AssocConstViolation::Generic, _) => {
format!("it contains generic associated const `{name}`").into()
}
Self::AssocConst(name, AssocConstViolation::NonType, _) => {
format!("it contains associated const `{name}` that's not marked `#[type_const]`")
.into()
}
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()
}
}
}
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::GAT(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)
}
}
@@ -899,14 +886,14 @@ pub fn solution(&self) -> DynCompatibilityViolationSolution {
// 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::GAT(_, 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 {
@@ -972,8 +959,8 @@ trait objects"
}
/// Reasons a method might not be dyn-compatible.
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
pub enum MethodViolationCode {
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)]
pub enum MethodViolation {
/// e.g., `fn foo()`
StaticMethod(Option<(/* add &self */ (String, Span), /* add Self: Sized */ (String, Span))>),
@@ -1002,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 {
+49 -39
View File
@@ -126,30 +126,19 @@ pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
}
pub fn descr(&self) -> &'static str {
match self.kind {
ty::AssocKind::Const { .. } => "associated const",
ty::AssocKind::Fn { has_self: true, .. } => "method",
ty::AssocKind::Fn { has_self: false, .. } => "associated function",
ty::AssocKind::Type { .. } => "associated type",
}
self.kind.descr()
}
pub fn namespace(&self) -> Namespace {
match self.kind {
ty::AssocKind::Type { .. } => Namespace::TypeNS,
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
}
self.kind.namespace()
}
pub fn as_def_kind(&self) -> DefKind {
match self.kind {
AssocKind::Const { .. } => DefKind::AssocConst,
AssocKind::Fn { .. } => DefKind::AssocFn,
AssocKind::Type { .. } => DefKind::AssocTy,
}
self.kind.as_def_kind()
}
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,12 +149,12 @@ pub fn is_method(&self) -> bool {
matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. })
}
pub fn as_tag(&self) -> AssocTag {
match self.kind {
AssocKind::Const { .. } => AssocTag::Const,
AssocKind::Fn { .. } => AssocTag::Fn,
AssocKind::Type { .. } => AssocTag::Type,
}
pub fn is_type(&self) -> bool {
matches!(self.kind, ty::AssocKind::Type { .. })
}
pub fn tag(&self) -> AssocTag {
self.kind.tag()
}
pub fn is_impl_trait_in_trait(&self) -> bool {
@@ -191,40 +180,61 @@ pub enum AssocKind {
impl AssocKind {
pub fn namespace(&self) -> Namespace {
match *self {
ty::AssocKind::Type { .. } => Namespace::TypeNS,
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
match self {
Self::Type { .. } => Namespace::TypeNS,
Self::Const { .. } | Self::Fn { .. } => Namespace::ValueNS,
}
}
pub fn tag(&self) -> AssocTag {
match self {
Self::Const { .. } => AssocTag::Const,
Self::Fn { .. } => AssocTag::Fn,
Self::Type { .. } => AssocTag::Type,
}
}
pub fn as_def_kind(&self) -> DefKind {
match self {
AssocKind::Const { .. } => DefKind::AssocConst,
AssocKind::Fn { .. } => DefKind::AssocFn,
AssocKind::Type { .. } => DefKind::AssocTy,
Self::Const { .. } => DefKind::AssocConst,
Self::Fn { .. } => DefKind::AssocFn,
Self::Type { .. } => DefKind::AssocTy,
}
}
pub fn descr(&self) -> &'static str {
match self {
Self::Fn { has_self: true, .. } => "method",
_ => self.tag().descr(),
}
}
}
impl std::fmt::Display for AssocKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
AssocKind::Const { .. } => write!(f, "associated const"),
AssocKind::Type { .. } => write!(f, "associated type"),
}
f.write_str(self.descr())
}
}
// Like `AssocKind`, but just the tag, no fields. Used in various kinds of matching.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// Like [`AssocKind`], but just the tag, no fields. Used in various kinds of matching.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum AssocTag {
Const,
Fn,
Type,
}
impl AssocTag {
pub fn descr(self) -> &'static str {
// This should match `DefKind::descr`.
match self {
Self::Const => "associated constant",
Self::Fn => "associated function",
Self::Type => "associated type",
}
}
}
/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
///
/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
@@ -272,7 +282,7 @@ pub fn filter_by_name_unhygienic_and_kind(
name: Symbol,
assoc_tag: AssocTag,
) -> impl '_ + Iterator<Item = &ty::AssocItem> {
self.filter_by_name_unhygienic(name).filter(move |item| item.as_tag() == assoc_tag)
self.filter_by_name_unhygienic(name).filter(move |item| item.tag() == assoc_tag)
}
/// Returns the associated item with the given identifier and `AssocKind`, if one exists.
@@ -285,7 +295,7 @@ pub fn find_by_ident_and_kind(
parent_def_id: DefId,
) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name)
.filter(|item| item.as_tag() == assoc_tag)
.filter(|item| item.tag() == assoc_tag)
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
}
+2 -3
View File
@@ -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()
+1 -1
View File
@@ -6,7 +6,7 @@ edition = "2024"
[dependencies]
# tidy-alphabetical-start
punycode = "0.4.0"
rustc-demangle = "0.1.21"
rustc-demangle = "0.1.27"
rustc_abi = { path = "../rustc_abi" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
+4 -1
View File
@@ -648,7 +648,10 @@ fn print_dyn_existential(
p.push_ident(name.as_str());
match projection.term.kind() {
ty::TermKind::Ty(ty) => ty.print(p),
ty::TermKind::Const(c) => c.print(p),
ty::TermKind::Const(c) => {
p.push("K");
c.print(p)
}
}?;
}
ty::ExistentialPredicate::AutoTrait(def_id) => {
@@ -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,
@@ -24,7 +25,8 @@
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.
@@ -229,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=()>`).
//
@@ -288,7 +290,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 +308,51 @@ 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<DynCompatibilityViolation> {
// 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)]
// 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() {
errors.push(AssocConstViolation::Generic);
} else if !find_attr!(tcx.get_all_attrs(item.def_id), AttributeKind::TypeConst(_)) {
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 {
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)
@@ -332,26 +361,28 @@ 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())
}
_ => 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()
}
}
@@ -366,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`
@@ -394,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();
@@ -415,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(
@@ -424,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));
@@ -456,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.
@@ -514,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
@@ -672,13 +703,16 @@ enum AllowSelfProjections {
No,
}
/// This is somewhat subtle. In general, we want to forbid
/// references to `Self` in the argument and return types,
/// since the value of `Self` is erased. However, there is one
/// exception: it is ok to reference `Self` in order to access
/// an associated type of the current trait, since we retain
/// the value of those associated types in the object type
/// itself.
/// Check if the given value contains illegal `Self` references.
///
/// This is somewhat subtle. In general, we want to forbid references to `Self` in the
/// argument and return types, since the value of `Self` is erased.
///
/// However, there is one exception: It is ok to reference `Self` in order to access an
/// associated type of the current trait, since we retain the value of those associated
/// types in the trait object type itself.
///
/// The same thing holds for associated consts under feature `min_generic_const_args`.
///
/// ```rust,ignore (example)
/// trait SuperTrait {
@@ -733,82 +767,88 @@ struct IllegalSelfTypeVisitor<'tcx> {
allow_self_projections: AllowSelfProjections,
}
impl<'tcx> IllegalSelfTypeVisitor<'tcx> {
fn is_supertrait_of_current_trait(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
// Compute supertraits of current trait lazily.
let supertraits = self.supertraits.get_or_insert_with(|| {
util::supertraits(
self.tcx,
ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id)),
)
.map(|trait_ref| {
self.tcx.erase_and_anonymize_regions(
self.tcx.instantiate_bound_regions_with_erased(trait_ref),
)
})
.collect()
});
// Determine whether the given trait ref is in fact a supertrait of the current trait.
// In that case, any derived projections are legal, because the term will be specified
// in the trait object type.
// Note that we can just use direct equality here because all of these types are part of
// the formal parameter listing, and hence there should be no inference variables.
let trait_ref = trait_ref
.fold_with(&mut EraseEscapingBoundRegions { tcx: self.tcx, binder: ty::INNERMOST });
supertraits.contains(&trait_ref)
}
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
type Result = ControlFlow<()>;
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
match t.kind() {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
match ty.kind() {
ty::Param(_) => {
if t == self.tcx.types.self_param {
if ty == self.tcx.types.self_param {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
}
ty::Alias(ty::Projection, data) if self.tcx.is_impl_trait_in_trait(data.def_id) => {
ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => {
// We'll deny these later in their own pass
ControlFlow::Continue(())
}
ty::Alias(ty::Projection, data) => {
ty::Alias(ty::Projection, proj) => {
match self.allow_self_projections {
AllowSelfProjections::Yes => {
// This is a projected type `<Foo as SomeTrait>::X`.
// Compute supertraits of current trait lazily.
if self.supertraits.is_none() {
self.supertraits = Some(
util::supertraits(
self.tcx,
ty::Binder::dummy(ty::TraitRef::identity(
self.tcx,
self.trait_def_id,
)),
)
.map(|trait_ref| {
self.tcx.erase_and_anonymize_regions(
self.tcx.instantiate_bound_regions_with_erased(trait_ref),
)
})
.collect(),
);
}
// Determine whether the trait reference `Foo as
// SomeTrait` is in fact a supertrait of the
// current trait. In that case, this type is
// legal, because the type `X` will be specified
// in the object type. Note that we can just use
// direct equality here because all of these types
// are part of the formal parameter listing, and
// hence there should be no inference variables.
let is_supertrait_of_current_trait =
self.supertraits.as_ref().unwrap().contains(
&data.trait_ref(self.tcx).fold_with(
&mut EraseEscapingBoundRegions {
tcx: self.tcx,
binder: ty::INNERMOST,
},
),
);
// only walk contained types if it's not a super trait
if is_supertrait_of_current_trait {
// Only walk contained types if the parent trait is not a supertrait.
if self.is_supertrait_of_current_trait(proj.trait_ref(self.tcx)) {
ControlFlow::Continue(())
} else {
t.super_visit_with(self) // POSSIBLY reporting an error
ty.super_visit_with(self)
}
}
AllowSelfProjections::No => t.super_visit_with(self),
AllowSelfProjections::No => ty.super_visit_with(self),
}
}
_ => t.super_visit_with(self),
_ => ty.super_visit_with(self),
}
}
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
// Constants can only influence dyn-compatibility if they are generic and reference `Self`.
// This is only possible for unevaluated constants, so we walk these here.
self.tcx.expand_abstract_consts(ct).super_visit_with(self)
let ct = self.tcx.expand_abstract_consts(ct);
match ct.kind() {
ty::ConstKind::Unevaluated(proj) if self.tcx.features().min_generic_const_args() => {
match self.allow_self_projections {
AllowSelfProjections::Yes => {
let trait_def_id = self.tcx.parent(proj.def);
let trait_ref = ty::TraitRef::from_assoc(self.tcx, trait_def_id, proj.args);
// Only walk contained consts if the parent trait is not a supertrait.
if self.is_supertrait_of_current_trait(trait_ref) {
ControlFlow::Continue(())
} else {
ct.super_visit_with(self)
}
}
AllowSelfProjections::No => ct.super_visit_with(self),
}
}
_ => ct.super_visit_with(self),
}
}
}
@@ -847,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()
}
@@ -864,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 {
+7 -2
View File
@@ -857,7 +857,11 @@ Remaining primitives are encoded as a crate production, e.g. `C4f128`.
>
> <span id="dyn-trait">dyn-trait</span> → *[path]* {*[dyn-trait-assoc-binding]*}
>
> <span id="dyn-trait-assoc-binding">dyn-trait-assoc-binding</span> → `p` *[undisambiguated-identifier]* *[type]*
> <span id="dyn-trait-assoc-binding">dyn-trait-assoc-binding</span> → `p` *[undisambiguated-identifier]* *[type-or-const]*
>
> <span id="type-or-const">type-or-const</span> → \
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[type]* \
> &nbsp;&nbsp; | `K` *[const]*
The tag `D` is followed by a *[dyn-bounds]* which encodes the trait bounds,
followed by a *[lifetime]* of the trait object lifetime bound.
@@ -867,11 +871,12 @@ Remaining primitives are encoded as a crate production, e.g. `C4f128`.
Each *[dyn-trait]* represents a trait bound, which consists of a *[path]* to the trait followed by zero or more *[dyn-trait-assoc-binding]* which list the associated types.
Each *[dyn-trait-assoc-binding]* consists of a character `p` followed a *[undisambiguated-identifier]* representing the associated binding name, and finally a *[type]*.
Each *[dyn-trait-assoc-binding]* consists of a character `p` followed a *[undisambiguated-identifier]* representing the associated binding name, and finally a *[type-or-const]*.
[dyn-bounds]: #dyn-bounds
[dyn-trait]: #dyn-trait
[dyn-trait-assoc-binding]: #dyn-trait-assoc-binding
[type-or-const]: #type-or-const
* A *[path]* to a named type.
+1 -1
View File
@@ -561,7 +561,7 @@ pub(crate) fn build_impl(
.find_by_ident_and_kind(
tcx,
item.ident(tcx),
item.as_tag(),
item.tag(),
associated_trait.def_id,
)
.unwrap(); // corresponding associated item has to exist
+1 -1
View File
@@ -1226,7 +1226,7 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n
.associated_items(did)
.filter_by_name_unhygienic(method_name)
.next()
.filter(|item| item.as_tag() == AssocTag::Fn)
.filter(|item| item.tag() == AssocTag::Fn)
})
} else {
None
-6
View File
@@ -1,6 +0,0 @@
//@ known-bug: #136063
#![feature(generic_const_exprs)]
trait A<const B: u8 = X> {}
impl A<1> for bool {}
fn bar(arg : &dyn A<x>) { bar(true) }
pub fn main() {}
-11
View File
@@ -1,11 +0,0 @@
//@ known-bug: #137260
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
trait Iter<const N: usize = { 1 + true }> {}
fn needs_iter<const N: usize, T: Iter<N>>() {}
fn test() {
needs_iter::<1, dyn Iter<()>>();
}
-9
View File
@@ -1,9 +0,0 @@
//@ known-bug: #137514
//@ needs-rustc-debug-assertions
#![feature(generic_const_exprs)]
trait Bar<const N: usize> {}
trait BB = Bar<{ 1i32 + 1 }>;
fn foo(x: &dyn BB) {}
@@ -0,0 +1,34 @@
//@ compile-flags: -g
//@ disable-gdb-pretty-printers
//@ ignore-backends: gcc
//@ gdb-command:run
//@ gdb-command:whatis local
//@ gdb-check:type = &dyn associated_const_bindings::Trait<N=101>
//@ cdb-command: g
//@ cdb-command:dv /t /n local
//@ cdb-check:struct ref$<dyn$<associated_const_bindings::Trait<assoc$<N,101> > > > local = [...]
#![feature(min_generic_const_args)]
#![expect(unused_variables, incomplete_features)]
trait Trait {
#[type_const]
const N: usize;
}
impl Trait for () {
#[type_const]
const N: usize = 101;
}
fn main() {
let local = &() as &dyn Trait<N = 101>;
zzz(); // #break
}
#[inline(never)]
fn zzz() {
()
}
@@ -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() {}
@@ -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 <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
@@ -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 <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $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 <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $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`.
+3 -3
View File
@@ -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 <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
@@ -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
@@ -86,7 +86,7 @@ fn uncallable_rtn(
type MustFail = dyn Iterator<Item = i32, Item = u32>;
//~^ ERROR [E0719]
//~| ERROR conflicting associated type bounds
//~| ERROR conflicting associated type bindings
trait Trait2 {
#[type_const]
@@ -95,7 +95,7 @@ trait Trait2 {
type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
//~^ ERROR [E0719]
//~| ERROR conflicting associated type bounds
//~| ERROR conflicting associated constant bindings
type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
//~^ ERROR [E0719]
@@ -116,7 +116,7 @@ LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
| |
| `Item` bound here first
error: conflicting associated type bounds for `Item`
error: conflicting associated type bindings for `Item`
--> $DIR/duplicate-bound-err.rs:87:17
|
LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
@@ -133,7 +133,7 @@ LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
| |
| `ASSOC` bound here first
error: conflicting associated type bounds for `ASSOC`
error: conflicting associated constant bindings for `ASSOC`
--> $DIR/duplicate-bound-err.rs:96:18
|
LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
@@ -2,7 +2,7 @@ error[E0191]: the value of the associated types `Item` and `IntoIter` in `IntoIt
--> $DIR/overlaping-bound-suggestion.rs:7:13
|
LL | inner: <IntoIterator<Item: IntoIterator<Item: >>::IntoIterator as Item>::Core,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated types: `IntoIterator<Item: IntoIterator<Item: >, Item = Type, IntoIter = Type>`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated types: `IntoIterator<Item: IntoIterator<Item: >, Item = /* Type */, IntoIter = /* Type */>`
error: aborting due to 1 previous error
@@ -5,7 +5,7 @@ LL | type B;
| ------ `B` defined here
...
LL | let b = &42isize as &dyn Foo<A=usize>;
| ^^^^^^^^^^^^ help: specify the associated type: `Foo<A=usize, B = Type>`
| ^^^^^^^^^^^^ help: specify the associated type: `Foo<A=usize, B = /* Type */>`
error[E0191]: the value of the associated type `A` in `Foo` must be specified
--> $DIR/associated-types-incomplete-object.rs:26:30
@@ -14,7 +14,7 @@ LL | type A;
| ------ `A` defined here
...
LL | let c = &42isize as &dyn Foo<B=char>;
| ^^^^^^^^^^^ help: specify the associated type: `Foo<B=char, A = Type>`
| ^^^^^^^^^^^ help: specify the associated type: `Foo<B=char, A = /* Type */>`
error[E0191]: the value of the associated types `A` and `B` in `Foo` must be specified
--> $DIR/associated-types-incomplete-object.rs:29:30
@@ -25,7 +25,7 @@ LL | type B;
| ------ `B` defined here
...
LL | let d = &42isize as &dyn Foo;
| ^^^ help: specify the associated types: `Foo<A = Type, B = Type>`
| ^^^ help: specify the associated types: `Foo<A = /* Type */, B = /* Type */>`
error: aborting due to 3 previous errors
@@ -4,5 +4,5 @@
fn main() {
let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
//~^ ERROR conflicting associated type bounds
//~^ ERROR conflicting associated type bindings
}
@@ -1,4 +1,4 @@
error: conflicting associated type bounds for `Item`
error: conflicting associated type bindings for `Item`
--> $DIR/associated-types-overridden-binding-2.rs:6:13
|
LL | trait I32Iterator = Iterator<Item = i32>;
@@ -8,5 +8,5 @@ trait Bar: Foo<Item = u32> {} //~ ERROR type annotations needed
fn main() {
let _: &dyn I32Iterator<Item = u32>;
//~^ ERROR conflicting associated type bounds
//~^ ERROR conflicting associated type bindings
}
@@ -22,7 +22,7 @@ note: required by a bound in `I32Iterator`
LL | trait I32Iterator = Iterator<Item = i32>;
| ^^^^^^^^^^ required by this bound in `I32Iterator`
error: conflicting associated type bounds for `Item`
error: conflicting associated type bindings for `Item`
--> $DIR/associated-types-overridden-binding.rs:10:13
|
LL | trait I32Iterator = Iterator<Item = i32>;
@@ -6,7 +6,7 @@ LL | type Value;
LL | type ChildKey;
| ------------- `ChildKey` defined here
LL | type Children = dyn Index<Self::ChildKey, Output = dyn Hierarchy>;
| ------------- `Children` defined here ^^^^^^^^^ help: specify the associated types: `Hierarchy<Value = Type, ChildKey = Type, Children = Type>`
| ------------- `Children` defined here ^^^^^^^^^ help: specify the associated types: `Hierarchy<Value = /* Type */, ChildKey = /* Type */, Children = /* Type */>`
error: aborting due to 1 previous error
+1 -1
View File
@@ -8,7 +8,7 @@ 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>
--> $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
@@ -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,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<C = 3> {
#[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<K = 1, Q = 2>;
let obj: &dyn Bound<N = 10> = &();
_ = identity(obj);
fn identity(x: &(impl ?Sized + Bound<N = 10>)) -> &(impl ?Sized + Bound<N = 10>) { x }
}
@@ -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<N = 0> = &(); //~ ERROR type mismatch resolving `<() as Trait>::N == 0`
}
@@ -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<N = 0> = &();
| ^^^ expected `0`, found `1`
|
= note: expected constant `0`
found constant `1`
= note: required for the cast from `&()` to `&dyn Trait<N = 0>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0271`.
@@ -0,0 +1,21 @@
// Test that we force users to explicitly specify const arguments for const parameters that
// have defaults if the default mentions the `Self` type parameter.
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
trait X<const N: usize = { <Self as Y>::N }> {}
trait Y {
#[type_const]
const N: usize;
}
impl<T: ?Sized> Y for T {
#[type_const]
const N: usize = 1;
}
fn main() {
let _: dyn X; //~ ERROR the const parameter `N` must be explicitly specified
}
@@ -0,0 +1,18 @@
error[E0393]: the const parameter `N` must be explicitly specified
--> $DIR/dyn-compat-const-param-default-mentions-self.rs:20:16
|
LL | trait X<const N: usize = { <Self as Y>::N }> {}
| -------------------------------------------- const parameter `N` must be specified for this
...
LL | let _: dyn X;
| ^
|
= note: because the parameter default references `Self`, the parameter must be specified on the trait object type
help: explicitly specify the const parameter
|
LL | let _: dyn X</* N */>;
| +++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0393`.
@@ -0,0 +1,22 @@
// Check that we reject const projections behind trait aliases that mention `Self`.
// The code below is pretty artifical and contains a type mismatch anyway but we still need to
// reject it & lower the `Self` ty param to a `{type error}` to avoid ICEs down the line.
//
// The author of the trait object type can't fix this unlike the supertrait bound
// equivalent where they just need to explicitly specify the assoc const.
#![feature(min_generic_const_args, trait_alias)]
#![expect(incomplete_features)]
trait Trait {
#[type_const]
const Y: i32;
}
struct Hold<T: ?Sized>(T);
trait Bound = Trait<Y = { Hold::<Self> }>;
fn main() {
let _: dyn Bound; //~ ERROR associated constant binding in trait object type mentions `Self`
}
@@ -0,0 +1,11 @@
error: associated constant binding in trait object type mentions `Self`
--> $DIR/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs:21:12
|
LL | trait Bound = Trait<Y = { Hold::<Self> }>;
| -------------------- this binding mentions `Self`
...
LL | let _: dyn Bound;
| ^^^^^^^^^ contains a mention of `Self`
error: aborting due to 1 previous error
@@ -0,0 +1,20 @@
// Test that we force users to explicitly specify associated constants (via bindings)
// which reference the `Self` type parameter.
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
trait X: Y<K = { Self::Q }> {
#[type_const]
const Q: usize;
}
trait Y {
#[type_const]
const K: usize;
}
fn main() {
let _: dyn X<Q = 10>;
//~^ ERROR the value of the associated constant `K` in `Y` must be specified
}
@@ -0,0 +1,12 @@
error[E0191]: the value of the associated constant `K` in `Y` must be specified
--> $DIR/dyn-compat-const-projection-from-supertrait-mentions-self.rs:18:16
|
LL | const K: usize;
| -------------- `K` defined here
...
LL | let _: dyn X<Q = 10>;
| ^^^^^^^^^ help: specify the associated constant: `X<Q = 10, K = /* CONST */>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0191`.
@@ -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>: T;
//~^ NOTE it contains generic associated const `POLY`
}
fn main() {
let _: dyn Trait; //~ ERROR the trait `Trait` is not dyn compatible
}
@@ -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 <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/dyn-compat-generic-assoc-const.rs:10:11
|
LL | trait Trait {
| ----- this trait is not dyn compatible...
LL | const POLY<T>: 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`.
@@ -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<K = 0>;
//~^ ERROR the trait `Trait` is not dyn compatible
//~| ERROR use of trait associated const without `#[type_const]`
}
@@ -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 <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $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<K = 0>;
| ^^^^^
|
= 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<K = 0>;
| ^^^^^^^^^^^^ `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-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`.
@@ -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`.
@@ -0,0 +1,56 @@
// While mentioning `Self` in the method signature of dyn compatible traits is generally forbidden
// due to type erasure, we can make an exception for const projections from `Self` where the trait
// is the principal trait or a supertrait thereof. That's sound because we force users to specify
// all associated consts in the trait object type, so the projections are all normalizable.
//
// Check that we can define & use dyn compatible traits that reference `Self` const projections.
// This is a run-pass test to ensure that codegen can actually deal with such method instances
// (e.g., const projections normalize flawlessly to something concrete, symbols get mangled
// properly, the vtable is fine) and simply to ensure that the generated code "received" the
// correct values from the type assoc consts).
//@ run-pass
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
trait Trait {
#[type_const]
const N: usize;
fn process(&self, _: [u8; Self::N]) -> [u8; Self::N];
}
impl Trait for u8 {
#[type_const]
const N: usize = 2;
fn process(&self, [x, y]: [u8; Self::N]) -> [u8; Self::N] {
[self * x, self + y]
}
}
impl<const N: usize> Trait for [u8; N] {
#[type_const]
const N: usize = N;
fn process(&self, other: [u8; Self::N]) -> [u8; Self::N] {
let mut result = [0; _];
for i in 0..Self::N {
result[i] = self[i] + other[i];
}
result
}
}
fn main() {
let ops: [Box<dyn Trait<N = 2>>; _] = [Box::new(3), Box::new([1, 1])];
let mut data = [16, 32];
for op in ops {
data = op.process(data);
}
assert_eq!(data, [49, 36]);
}
@@ -0,0 +1,20 @@
// Ensure that we reject the `Self` type parameter in supertrait bounds of dyn-compatible traits
// even if they're part of a "`Self` projection" (contrary to method signatures and the type of
// assoc consts).
//@ dont-require-annotations: NOTE
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
trait Trait: SuperTrait<{ Self::N }> {
//~^ NOTE it uses `Self` as a type parameter
#[type_const]
const N: usize;
}
trait SuperTrait<const N: usize> {}
fn main() {
let _: dyn Trait; //~ ERROR the trait `Trait` is not dyn compatible
}
@@ -0,0 +1,18 @@
error[E0038]: the trait `Trait` is not dyn compatible
--> $DIR/dyn-compat-self-const-projections-in-supertrait-bounds.rs:19: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-self-const-projections-in-supertrait-bounds.rs:10:14
|
LL | trait Trait: SuperTrait<{ Self::N }> {
| ----- ^^^^^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
| |
| this trait is not dyn compatible...
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0038`.
@@ -0,0 +1,28 @@
// Ensure that we can successfully mangle & demangle trait object types w/ assoc const bindings.
// FIXME(mgca): Legacy mangling still crashes:
// "finding type for [impl], encountered [crate root] with no parent"
//@ build-fail
//@ revisions: v0
//\@[legacy] compile-flags: -C symbol-mangling-version=legacy -Z unstable-options
//@ [v0] compile-flags: -C symbol-mangling-version=v0
//\@[legacy] normalize-stderr: "h[[:xdigit:]]{16}" -> "h[HASH]"
//@ [v0] normalize-stderr: "sym\[.*?\]" -> "sym[HASH]"
#![feature(min_generic_const_args, rustc_attrs)]
#![expect(incomplete_features)]
#![crate_name = "sym"]
trait Trait {
#[type_const]
const N: usize;
}
#[rustc_symbol_name]
//~^ ERROR symbol-name(_RMCs
//~| ERROR demangling(<dyn sym[
//~| ERROR demangling-alt(<dyn sym::Trait<N = 0>>)
impl dyn Trait<N = 0> {}
fn main() {}
@@ -0,0 +1,20 @@
error: symbol-name(_RMCsCRATE_HASH_3symDNtB<REF>_5Traitp1NKj0_EL_)
--> $DIR/dyn-compat-symbol-mangling.rs:22:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling(<dyn sym[HASH]::Trait<N = 0usize>>)
--> $DIR/dyn-compat-symbol-mangling.rs:22:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<dyn sym::Trait<N = 0>>)
--> $DIR/dyn-compat-symbol-mangling.rs:22:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
@@ -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 constant `K` in `Trait` must be specified
}
// item ctxt / signature / non-body
struct Store(dyn Trait);
//~^ ERROR the value of the associated constant `K` in `Trait` must be specified
// item ctxt & no wfcking (eager ty alias)
type DynTrait = dyn Trait;
//~^ ERROR the value of the associated constant `K` in `Trait` must be specified
@@ -0,0 +1,30 @@
error[E0191]: the value of the associated constant `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 constant: `Trait<K = /* CONST */>`
error[E0191]: the value of the associated constant `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 constant: `Trait<K = /* CONST */>`
error[E0191]: the value of the associated constant `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 constant: `Trait<K = /* CONST */>`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0191`.
@@ -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<const N: i16>;
| ^ ...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
@@ -16,7 +16,7 @@ impl Bar for Foo<'_> {
const STATIC: &str = "";
//~^ ERROR `&` without an explicit lifetime name cannot be used here
//~| WARN this was previously accepted by the compiler but is being phased out
//~| ERROR lifetime parameters or bounds on associated const `STATIC` do not match the trait declaration
//~| ERROR lifetime parameters or bounds on associated constant `STATIC` do not match the trait declaration
}
fn main() {}
@@ -39,14 +39,14 @@ help: use the `'static` lifetime
LL | const STATIC: &'static str = "";
| +++++++
error[E0195]: lifetime parameters or bounds on associated const `STATIC` do not match the trait declaration
error[E0195]: lifetime parameters or bounds on associated constant `STATIC` do not match the trait declaration
--> $DIR/elided-lifetime.rs:16:17
|
LL | const STATIC: &str;
| - lifetimes in impl do not match this associated const in trait
| - lifetimes in impl do not match this associated constant in trait
...
LL | const STATIC: &str = "";
| ^ lifetimes do not match associated const in trait
| ^ lifetimes do not match associated constant in trait
error: aborting due to 3 previous errors
@@ -9,7 +9,7 @@ impl Bar<'_> for A {
const STATIC: &str = "";
//~^ ERROR `&` without an explicit lifetime name cannot be used here
//~| WARN this was previously accepted by the compiler but is being phased out
//~| ERROR lifetime parameters or bounds on associated const `STATIC` do not match the trait declaration
//~| ERROR lifetime parameters or bounds on associated constant `STATIC` do not match the trait declaration
}
struct B;
@@ -21,14 +21,14 @@ help: use the `'static` lifetime
LL | const STATIC: &'static str = "";
| +++++++
error[E0195]: lifetime parameters or bounds on associated const `STATIC` do not match the trait declaration
error[E0195]: lifetime parameters or bounds on associated constant `STATIC` do not match the trait declaration
--> $DIR/static-trait-impl.rs:9:17
|
LL | const STATIC: &'a str;
| - lifetimes in impl do not match this associated const in trait
| - lifetimes in impl do not match this associated constant in trait
...
LL | const STATIC: &str = "";
| ^ lifetimes do not match associated const in trait
| ^ lifetimes do not match associated constant in trait
error: aborting due to 2 previous errors
@@ -5,7 +5,7 @@ LL | type Bar
| -------- `Bar` defined here
...
LL | fn foo(_: &dyn Foo<()>) {}
| ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>`
| ^^^^^^^ help: specify the associated type: `Foo<(), Bar = /* Type */>`
error[E0191]: the value of the associated type `Bar` in `Foo<i32>` must be specified
--> $DIR/assoc_type_bounds.rs:11:16
@@ -14,7 +14,7 @@ LL | type Bar
| -------- `Bar` defined here
...
LL | fn bar(_: &dyn Foo<i32>) {}
| ^^^^^^^^ help: specify the associated type: `Foo<i32, Bar = Type>`
| ^^^^^^^^ help: specify the associated type: `Foo<i32, Bar = /* Type */>`
error: aborting due to 2 previous errors
@@ -5,7 +5,7 @@ LL | type Bar
| -------- `Bar` defined here
...
LL | fn foo(_: &dyn Foo<()>) {}
| ^^^^^^^ help: specify the associated type: `Foo<(), Bar = Type>`
| ^^^^^^^ help: specify the associated type: `Foo<(), Bar = /* Type */>`
error[E0191]: the value of the associated type `Bar` in `Foo<i32>` must be specified
--> $DIR/assoc_type_bounds2.rs:11:16
@@ -14,7 +14,7 @@ LL | type Bar
| -------- `Bar` defined here
...
LL | fn bar(_: &dyn Foo<i32>) {}
| ^^^^^^^^ help: specify the associated type: `Foo<i32, Bar = Type>`
| ^^^^^^^^ help: specify the associated type: `Foo<i32, Bar = /* Type */>`
error: aborting due to 2 previous errors
@@ -5,7 +5,7 @@ LL | type Bop;
| -------- `Bop` defined here
...
LL | fn foo(_: &dyn Foo) {}
| ^^^ help: specify the associated type: `Foo<Bop = Type>`
| ^^^ help: specify the associated type: `Foo<Bop = /* Type */>`
error[E0191]: the value of the associated type `Bop` in `Bar` must be specified
--> $DIR/assoc_type_bounds_sized_others.rs:22:16
@@ -14,7 +14,7 @@ LL | type Bop;
| -------- `Bop` defined here
...
LL | fn bar(_: &dyn Bar) {}
| ^^^ help: specify the associated type: `Bar<Bop = Type>`
| ^^^ help: specify the associated type: `Bar<Bop = /* Type */>`
error: aborting due to 2 previous errors
@@ -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: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 <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
@@ -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
@@ -7,11 +7,11 @@ LL | trait A<C = <Self as D>::E> {}
LL | let B: &dyn A = &();
| ^
|
= note: because the parameter default references `Self`, the parameter must be specified on the object type
help: set the type parameter to the desired type
= note: because the parameter default references `Self`, the parameter must be specified on the trait object type
help: explicitly specify the type parameter
|
LL | let B: &dyn A<C> = &();
| +++
LL | let B: &dyn A</* C */> = &();
| +++++++++
error: aborting due to 1 previous error
@@ -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
@@ -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<T>;
| ^^^ ...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
@@ -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.
@@ -5,7 +5,7 @@ LL | type Assoc: Default;
| ------------------- `Assoc` defined here
...
LL | let q: <dyn Dyn<i32, u32> as Sup<u32>>::Assoc = Default::default();
| ^^^^^^^^^^^^^ help: specify the associated type: `Dyn<i32, u32, Assoc = Type>`
| ^^^^^^^^^^^^^ help: specify the associated type: `Dyn<i32, u32, Assoc = /* Type */>`
error: aborting due to 1 previous error
@@ -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<T>: for<'a> GatTrait<Gat<'a> = T> {
| ---------- this trait is not dyn compatible...
@@ -1,12 +0,0 @@
#![feature(trait_alias)]
trait B = Fn() -> Self;
type D = &'static dyn B;
//~^ ERROR E0411
fn a() -> D {
unreachable!();
}
fn main() {
_ = a();
}
@@ -1,9 +0,0 @@
error[E0411]: `Self` is not allowed in type aliases
--> $DIR/trait-alias-self-projection.rs:3:19
|
LL | type D = &'static dyn B;
| ^^^^^ `Self` is only available in impls, traits, and concrete type definitions
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0411`.
@@ -0,0 +1,18 @@
// Check that we reject type projections behind trait aliases that mention `Self`.
//
// The author of the trait object type can't fix this unlike the supertrait bound
// equivalent where they just need to explicitly specify the assoc type.
// issue: <https://github.com/rust-lang/rust/issues/139082>
#![feature(trait_alias)]
trait F = Fn() -> Self;
trait G = H<T = Self>;
trait H { type T: ?Sized; }
fn main() {
let _: dyn F; //~ ERROR associated type binding in trait object type mentions `Self`
let _: dyn G; //~ ERROR associated type binding in trait object type mentions `Self`
}
@@ -0,0 +1,20 @@
error: associated type binding in trait object type mentions `Self`
--> $DIR/type-projection-behind-trait-alias-mentions-self.rs:16:12
|
LL | trait F = Fn() -> Self;
| ---- this binding mentions `Self`
...
LL | let _: dyn F;
| ^^^^^ contains a mention of `Self`
error: associated type binding in trait object type mentions `Self`
--> $DIR/type-projection-behind-trait-alias-mentions-self.rs:17:12
|
LL | trait G = H<T = Self>;
| -------- this binding mentions `Self`
...
LL | let _: dyn G;
| ^^^^^ contains a mention of `Self`
error: aborting due to 2 previous errors
+1 -1
View File
@@ -5,7 +5,7 @@ LL | type Bar;
| -------- `Bar` defined here
...
LL | type Foo = dyn Trait;
| ^^^^^ help: specify the associated type: `Trait<Bar = Type>`
| ^^^^^ help: specify the associated type: `Trait<Bar = /* Type */>`
error: aborting due to 1 previous error
+1 -1
View File
@@ -11,7 +11,7 @@ LL | type Bar;
| -------- `Bar` defined here
...
LL | type Foo = dyn Trait<F=i32>;
| ^^^^^^^^^^^^ help: specify the associated type: `Trait<F=i32, Bar = Type>`
| ^^^^^^^^^^^^ help: specify the associated type: `Trait<F=i32, Bar = /* Type */>`
error: aborting due to 2 previous errors
+4 -4
View File
@@ -7,11 +7,11 @@ LL |
LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {}
| ^
|
= note: because the parameter default references `Self`, the parameter must be specified on the object type
help: set the type parameter to the desired type
= note: because the parameter default references `Self`, the parameter must be specified on the trait object type
help: explicitly specify the type parameter
|
LL | fn together_we_will_rule_the_galaxy(son: &dyn A<T>) {}
| +++
LL | fn together_we_will_rule_the_galaxy(son: &dyn A</* T */>) {}
| +++++++++
error: aborting due to 1 previous error
@@ -16,7 +16,7 @@ error[E0191]: the value of the associated type `Item` in `Iterator` must be spec
--> $DIR/dynless-turbofish-e0191-issue-91997.rs:5:13
|
LL | let _ = MyIterator::next;
| ^^^^^^^^^^ help: specify the associated type: `MyIterator::<Item = Type>`
| ^^^^^^^^^^ help: specify the associated type: `MyIterator::<Item = /* Type */>`
error: aborting due to 1 previous error; 1 warning emitted
@@ -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
@@ -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
@@ -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
@@ -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<T>;
| ^^^^^^ ...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
@@ -27,7 +27,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable
LL | trait MapLike<K, V> {
| ------- 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
@@ -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
@@ -14,7 +14,7 @@ impl Trait for () {
//~| ERROR mismatched types
const Q = "";
//~^ ERROR missing type for `const` item
//~| ERROR lifetime parameters or bounds on associated const `Q` do not match the trait declaration
//~| ERROR lifetime parameters or bounds on associated constant `Q` do not match the trait declaration
}
fn main() {}
@@ -15,14 +15,14 @@ error: missing type for `const` item
LL | const K<T> = ();
| ^ help: provide a type for the associated constant: `()`
error[E0195]: lifetime parameters or bounds on associated const `Q` do not match the trait declaration
error[E0195]: lifetime parameters or bounds on associated constant `Q` do not match the trait declaration
--> $DIR/assoc-const-missing-type.rs:15:12
|
LL | const Q<'a>: &'a str;
| ---- lifetimes in impl do not match this associated const in trait
| ---- lifetimes in impl do not match this associated constant in trait
...
LL | const Q = "";
| ^ lifetimes do not match associated const in trait
| ^ lifetimes do not match associated constant in trait
error: missing type for `const` item
--> $DIR/assoc-const-missing-type.rs:15:12
@@ -14,15 +14,15 @@ trait Trait<P> {
impl<P> Trait<P> for () {
const A<T>: () = ();
//~^ ERROR const `A` has 1 type parameter but its trait declaration has 0 type parameters
//~^ ERROR constant `A` has 1 type parameter but its trait declaration has 0 type parameters
const B<const K: u64>: u64 = 0;
//~^ ERROR const `B` has 1 const parameter but its trait declaration has 2 const parameters
//~^ ERROR constant `B` has 1 const parameter but its trait declaration has 2 const parameters
const C<'a>: &'a str = "";
//~^ ERROR const `C` has 0 type parameters but its trait declaration has 1 type parameter
//~^ ERROR constant `C` has 0 type parameters but its trait declaration has 1 type parameter
const D<const N: u16>: u16 = N;
//~^ ERROR const `D` has an incompatible generic parameter for trait `Trait`
//~^ ERROR constant `D` has an incompatible generic parameter for trait `Trait`
const E: &'static () = &();
//~^ ERROR lifetime parameters or bounds on associated const `E` do not match the trait declaration
//~^ ERROR lifetime parameters or bounds on associated constant `E` do not match the trait declaration
const F: usize = 1024
where
@@ -1,4 +1,4 @@
error[E0049]: associated const `A` has 1 type parameter but its trait declaration has 0 type parameters
error[E0049]: associated constant `A` has 1 type parameter but its trait declaration has 0 type parameters
--> $DIR/compare-impl-item.rs:16:13
|
LL | const A: ();
@@ -7,7 +7,7 @@ LL | const A: ();
LL | const A<T>: () = ();
| ^ found 1 type parameter
error[E0049]: associated const `B` has 1 const parameter but its trait declaration has 2 const parameters
error[E0049]: associated constant `B` has 1 const parameter but its trait declaration has 2 const parameters
--> $DIR/compare-impl-item.rs:18:13
|
LL | const B<const K: u64, const Q: u64>: u64;
@@ -18,7 +18,7 @@ LL | const B<const K: u64, const Q: u64>: u64;
LL | const B<const K: u64>: u64 = 0;
| ^^^^^^^^^^^^ found 1 const parameter
error[E0049]: associated const `C` has 0 type parameters but its trait declaration has 1 type parameter
error[E0049]: associated constant `C` has 0 type parameters but its trait declaration has 1 type parameter
--> $DIR/compare-impl-item.rs:20:13
|
LL | const C<T>: T;
@@ -27,7 +27,7 @@ LL | const C<T>: T;
LL | const C<'a>: &'a str = "";
| ^^ found 0 type parameters
error[E0053]: associated const `D` has an incompatible generic parameter for trait `Trait`
error[E0053]: associated constant `D` has an incompatible generic parameter for trait `Trait`
--> $DIR/compare-impl-item.rs:22:13
|
LL | trait Trait<P> {
@@ -42,14 +42,14 @@ LL | impl<P> Trait<P> for () {
LL | const D<const N: u16>: u16 = N;
| ^^^^^^^^^^^^ found const parameter of type `u16`
error[E0195]: lifetime parameters or bounds on associated const `E` do not match the trait declaration
error[E0195]: lifetime parameters or bounds on associated constant `E` do not match the trait declaration
--> $DIR/compare-impl-item.rs:24:12
|
LL | const E<'a>: &'a ();
| ---- lifetimes in impl do not match this associated const in trait
| ---- lifetimes in impl do not match this associated constant in trait
...
LL | const E: &'static () = &();
| ^ lifetimes do not match associated const in trait
| ^ lifetimes do not match associated constant in trait
error[E0276]: impl has stricter requirements than trait
--> $DIR/compare-impl-item.rs:29:12
@@ -5,7 +5,7 @@ LL | type Bar;
| -------- `Bar` defined here
...
LL | impl Foo for Box<dyn Foo> {
| ^^^ help: specify the associated type: `Foo<Bar = Type>`
| ^^^ help: specify the associated type: `Foo<Bar = /* Type */>`
error: aborting due to 1 previous error
+1 -1
View File
@@ -5,7 +5,7 @@ LL | type A;
| ------ `A` defined here
...
LL | fn bar(x: &dyn Foo) {}
| ^^^ help: specify the associated type: `Foo<A = Type>`
| ^^^ help: specify the associated type: `Foo<A = /* Type */>`
error: aborting due to 1 previous error
+4 -4
View File
@@ -7,11 +7,11 @@ LL |
LL | fn f(a: &dyn A) {}
| ^
|
= note: because the parameter default references `Self`, the parameter must be specified on the object type
help: set the type parameter to the desired type
= note: because the parameter default references `Self`, the parameter must be specified on the trait object type
help: explicitly specify the type parameter
|
LL | fn f(a: &dyn A<T>) {}
| +++
LL | fn f(a: &dyn A</* T */>) {}
| +++++++++
error: aborting due to 1 previous error
+2 -2
View File
@@ -16,7 +16,7 @@ error[E0191]: the value of the associated type `Output` in `BitXor<_>` must be s
--> $DIR/issue-28344.rs:5:17
|
LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
| ^^^^^^ help: specify the associated type: `BitXor::<Output = Type>`
| ^^^^^^ help: specify the associated type: `BitXor::<Output = /* Type */>`
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/issue-28344.rs:10:13
@@ -35,7 +35,7 @@ error[E0191]: the value of the associated type `Output` in `BitXor<_>` must be s
--> $DIR/issue-28344.rs:10:13
|
LL | let g = BitXor::bitor;
| ^^^^^^ help: specify the associated type: `BitXor::<Output = Type>`
| ^^^^^^ help: specify the associated type: `BitXor::<Output = /* Type */>`
error: aborting due to 2 previous errors; 2 warnings emitted
@@ -2,7 +2,7 @@ error[E0191]: the value of the associated type `Item` in `Iterator` must be spec
--> $DIR/trait-hidden-method.rs:4:33
|
LL | Box::new(1..=10) as Box<dyn Iterator>
| ^^^^^^^^ help: specify the associated type: `Iterator<Item = Type>`
| ^^^^^^^^ help: specify the associated type: `Iterator<Item = /* Type */>`
error: aborting due to 1 previous error

Some files were not shown because too many files have changed in this diff Show More