Generalize diag for missing assoc types to account for assoc consts

This commit is contained in:
León Orell Valerian Liehr 2026-01-05 09:50:38 +01:00
parent 7777958231
commit 9b861ace46
No known key found for this signature in database
GPG key ID: D17A07215F68E713
23 changed files with 170 additions and 132 deletions

View file

@ -324,7 +324,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.collect();
// If there are any associated items whose value wasn't provided, bail out with an error.
if let Err(guar) = self.check_for_required_assoc_tys(
if let Err(guar) = self.check_for_required_assoc_items(
principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
missing_assoc_items,
potential_assoc_items,

View file

@ -909,43 +909,49 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
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 +960,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
.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.as_tag())),
Some(Descr::Tag(tag)) if tag != assoc_item.as_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 +981,41 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
}
// 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 +1025,71 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default()
)
})
.collect::<Vec<String>>();
.collect();
names.sort();
let names = names.join(", ");
let descr = match descr.unwrap() {
// FIXME(fmease): Create `ty::AssocTag::descr`.
Descr::Tag(ty::AssocTag::Type) => "associated type",
Descr::Tag(ty::AssocTag::Const) => "associated constant",
_ => "associated item",
};
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.as_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.as_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 +1097,48 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} 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 +1150,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
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 +1168,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
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 +1191,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
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,
);

View file

@ -223,7 +223,7 @@ impl std::fmt::Display for AssocKind {
}
// Like `AssocKind`, but just the tag, no fields. Used in various kinds of matching.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum AssocTag {
Const,
Fn,

View file

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

View file

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

View file

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

View file

@ -13,13 +13,13 @@ trait Trait {
// fn ctxt / body
fn main() {
let _: dyn Trait;
//~^ ERROR the value of the associated type `K` in `Trait` must be specified
//~^ 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 type `K` in `Trait` must be specified
//~^ 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 type `K` in `Trait` must be specified
//~^ ERROR the value of the associated constant `K` in `Trait` must be specified

View file

@ -1,29 +1,29 @@
error[E0191]: the value of the associated type `K` in `Trait` must be specified
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 type: `Trait<K = Type>`
| ^^^^^ help: specify the associated constant: `Trait<K = /* CONST */>`
error[E0191]: the value of the associated type `K` in `Trait` must be specified
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 type: `Trait<K = Type>`
| ^^^^^ help: specify the associated constant: `Trait<K = /* CONST */>`
error[E0191]: the value of the associated type `K` in `Trait` must be specified
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 type: `Trait<K = Type>`
| ^^^^^ help: specify the associated constant: `Trait<K = /* CONST */>`
error: aborting due to 3 previous errors

View file

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

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

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

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

View file

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

View file

@ -19,7 +19,7 @@ error[E0191]: the value of the associated type `Item` in `Iterator` must be spec
--> $DIR/object-fail.rs:9:17
|
LL | let _: &dyn IteratorAlias = &vec![123].into_iter();
| ^^^^^^^^^^^^^ help: specify the associated type: `IteratorAlias<Item = Type>`
| ^^^^^^^^^^^^^ help: specify the associated type: `IteratorAlias<Item = /* Type */>`
error: aborting due to 2 previous errors

View file

@ -5,7 +5,7 @@ LL | type Output;
| ----------- `Output` defined here
...
LL | let x = &10 as &dyn Add;
| ^^^ help: specify the associated type: `Add<Output = Type>`
| ^^^ help: specify the associated type: `Add<Output = /* Type */>`
error: aborting due to 1 previous error

View file

@ -5,7 +5,7 @@ LL | type Output;
| ----------- `Output` defined here
...
LL | let _x: Box<dyn Helper<Target=i32>> = Box::new(2u32);
| ^^^^^^^^^^^^^^^^^^ help: specify the associated type: `Helper<Target=i32, Output = Type>`
| ^^^^^^^^^^^^^^^^^^ help: specify the associated type: `Helper<Target=i32, Output = /* Type */>`
error[E0191]: the value of the associated type `Output` in `Base` must be specified
--> $DIR/with-self-in-projection-output-bad.rs:48:21
@ -14,7 +14,7 @@ LL | type Output;
| ----------- `Output` defined here
...
LL | let _y: Box<dyn NormalizableHelper<Target=i32>> = Box::new(2u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `NormalizableHelper<Target=i32, Output = Type>`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `NormalizableHelper<Target=i32, Output = /* Type */>`
error: aborting due to 2 previous errors

View file

@ -5,7 +5,7 @@ LL | type A;
| ------ `A` defined here
...
LL | type I<'a> = &'a (dyn Foo + 'a);
| ^^^ help: specify the associated type: `Foo<A = Type>`
| ^^^ help: specify the associated type: `Foo<A = /* Type */>`
error: aborting due to 1 previous error