diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2019-12-17 18:15:06 -0800 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2019-12-24 22:23:02 -0800 |
| commit | 80adfd8de380d3055683e4a042ce845e663b7309 (patch) | |
| tree | 5fefcb11b8abd707d88fb80ef3598b8ea9b76895 | |
| parent | 83c5b4ec40ceadfbcf3c558f06e04c48f01c1e52 (diff) | |
| download | rust-80adfd8de380d3055683e4a042ce845e663b7309.tar.gz rust-80adfd8de380d3055683e4a042ce845e663b7309.zip | |
Account for multiple trait bounds with missing associated types
6 files changed, 367 insertions, 146 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 07b2f2c47a2..96295e7a326 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1444,59 +1444,68 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Use a `BTreeSet` to keep output in a more consistent order. - let mut associated_types = BTreeSet::default(); + let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default(); - let regular_traits_refs = bounds + let regular_traits_refs_spans = bounds .trait_bounds .into_iter() - .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())) - .map(|(trait_ref, _)| trait_ref); - for trait_ref in traits::elaborate_trait_refs(tcx, regular_traits_refs) { - debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", trait_ref); - match trait_ref { - ty::Predicate::Trait(pred) => { - associated_types.extend( - tcx.associated_items(pred.def_id()) - .filter(|item| item.kind == ty::AssocKind::Type) - .map(|item| item.def_id), - ); - } - ty::Predicate::Projection(pred) => { - // A `Self` within the original bound will be substituted with a - // `trait_object_dummy_self`, so check for that. - let references_self = pred.skip_binder().ty.walk().any(|t| t == dummy_self); - - // If the projection output contains `Self`, force the user to - // elaborate it explicitly to avoid a lot of complexity. - // - // The "classicaly useful" case is the following: - // ``` - // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput { - // type MyOutput; - // } - // ``` - // - // Here, the user could theoretically write `dyn MyTrait<Output = X>`, - // but actually supporting that would "expand" to an infinitely-long type - // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`. - // - // Instead, we force the user to write `dyn MyTrait<MyOutput = X, Output = X>`, - // which is uglier but works. See the discussion in #56288 for alternatives. - if !references_self { - // Include projections defined on supertraits. - bounds.projection_bounds.push((pred, DUMMY_SP)) + .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); + + for (base_trait_ref, span) in regular_traits_refs_spans { + debug!("conv_object_ty_poly_trait_ref regular_trait_ref `{:?}`", base_trait_ref); + let mut new_bounds = vec![]; + for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) { + debug!( + "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", + trait_ref + ); + match trait_ref { + ty::Predicate::Trait(pred) => { + associated_types.entry(span).or_default().extend( + tcx.associated_items(pred.def_id()) + .filter(|item| item.kind == ty::AssocKind::Type) + .map(|item| item.def_id), + ); } + ty::Predicate::Projection(pred) => { + // A `Self` within the original bound will be substituted with a + // `trait_object_dummy_self`, so check for that. + let references_self = pred.skip_binder().ty.walk().any(|t| t == dummy_self); + + // If the projection output contains `Self`, force the user to + // elaborate it explicitly to avoid a lot of complexity. + // + // The "classicaly useful" case is the following: + // ``` + // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput { + // type MyOutput; + // } + // ``` + // + // Here, the user could theoretically write `dyn MyTrait<Output = X>`, + // but actually supporting that would "expand" to an infinitely-long type + // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`. + // + // Instead, we force the user to write `dyn MyTrait<MyOutput = X, Output = X>`, + // which is uglier but works. See the discussion in #56288 for alternatives. + if !references_self { + // Include projections defined on supertraits. + new_bounds.push((pred, span)); + } + } + _ => (), } - _ => (), } + bounds.projection_bounds.extend(new_bounds); } for (projection_bound, _) in &bounds.projection_bounds { - associated_types.remove(&projection_bound.projection_def_id()); + for (_, def_ids) in &mut associated_types { + def_ids.remove(&projection_bound.projection_def_id()); + } } self.complain_about_missing_associated_types( - span, associated_types, potential_assoc_types, trait_bounds, @@ -1591,134 +1600,183 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn complain_about_missing_associated_types( &self, - span: Span, - associated_types: BTreeSet<DefId>, + mut associated_types: FxHashMap<Span, BTreeSet<DefId>>, potential_assoc_types: Vec<Span>, trait_bounds: &[hir::PolyTraitRef], ) { - if associated_types.is_empty() { + if !associated_types.values().any(|v| v.len() > 0) { return; } - // Account for things like `dyn Foo + 'a` by pointing at the `TraitRef.path` - // `Span` instead of the `PolyTraitRef` `Span`. That way the suggestion will - // be valid, otherwise we would suggest `dyn Foo + 'a<A = Type>`. See tests - // `issue-22434.rs` and `issue-22560.rs` for examples. - let sugg_span = match (&potential_assoc_types[..], &trait_bounds) { + let tcx = self.tcx(); + let mut names = vec![]; + + // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and + // `issue-22560.rs`. + let mut trait_bound_spans: Vec<Span> = vec![]; + for (span, item_def_ids) in &associated_types { + if !item_def_ids.is_empty() { + trait_bound_spans.push(*span); + } + for item_def_id in item_def_ids { + let assoc_item = tcx.associated_item(*item_def_id); + let trait_def_id = assoc_item.container.id(); + names.push(format!( + "`{}` (from trait `{}`)", + assoc_item.ident, + tcx.def_path_str(trait_def_id), + )); + } + } + + match (&potential_assoc_types[..], &trait_bounds) { ([], [bound]) => match &bound.trait_ref.path.segments[..] { // FIXME: `trait_ref.path.span` can point to a full path with multiple // segments, even though `trait_ref.path.segments` is of length `1`. Work // around that bug here, even though it should be fixed elsewhere. // This would otherwise cause an invalid suggestion. For an example, look at - // `src/test/ui/issues/issue-28344.rs`. - [segment] if segment.args.is_none() => segment.ident.span, - _ => bound.trait_ref.path.span, + // `src/test/ui/issues/issue-28344.rs` where instead of the following: + // + // error[E0191]: the value of the associated type `Output` + // (from trait `std::ops::BitXor`) must be specified + // --> $DIR/issue-28344.rs:4:17 + // | + // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); + // | ^^^^^^ help: specify the associated type: + // | `BitXor<Output = Type>` + // + // we would output: + // + // error[E0191]: the value of the associated type `Output` + // (from trait `std::ops::BitXor`) must be specified + // --> $DIR/issue-28344.rs:4:17 + // | + // LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); + // | ^^^^^^^^^^^^^ help: specify the associated type: + // | `BitXor::bitor<Output = Type>` + [segment] if segment.args.is_none() => { + trait_bound_spans = vec![segment.ident.span]; + associated_types = associated_types + .into_iter() + .map(|(_, defs)| (segment.ident.span, defs)) + .collect(); + } + _ => {} }, - _ => span, - }; - let tcx = self.tcx(); - let names = associated_types - .iter() - .map(|item_def_id| { - let assoc_item = tcx.associated_item(*item_def_id); - let trait_def_id = assoc_item.container.id(); - format!("`{}` (from trait `{}`)", assoc_item.ident, tcx.def_path_str(trait_def_id)) - }) - .collect::<Vec<_>>() - .join(", "); + _ => {} + } let mut err = struct_span_err!( tcx.sess, - sugg_span, + trait_bound_spans, E0191, "the value of the associated type{} {} must be specified", - pluralize!(associated_types.len()), - names, + pluralize!(names.len()), + names.join(", "), ); - let mut suggestions = Vec::new(); - let mut applicability = Applicability::MaybeIncorrect; - for (i, item_def_id) in associated_types.iter().enumerate() { - let assoc_item = tcx.associated_item(*item_def_id); - if let Some(sp) = tcx.hir().span_if_local(*item_def_id) { - err.span_label(sp, format!("`{}` defined here", assoc_item.ident)); - } - if potential_assoc_types.len() == associated_types.len() { + let mut suggestions = vec![]; + let mut types_count = 0; + let mut where_constraints = vec![]; + for (span, def_ids) in &associated_types { + let assoc_items: Vec<_> = + def_ids.iter().map(|def_id| tcx.associated_item(*def_id)).collect(); + let mut names: FxHashMap<_, usize> = FxHashMap::default(); + for item in &assoc_items { + types_count += 1; + *names.entry(item.ident.name).or_insert(0) += 1; + } + let mut dupes = false; + for item in &assoc_items { + let prefix = if names[&item.ident.name] > 1 { + let trait_def_id = item.container.id(); + dupes = true; + format!("{}::", tcx.def_path_str(trait_def_id)) + } else { + String::new() + }; + if let Some(sp) = tcx.hir().span_if_local(item.def_id) { + err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident)); + } + } + if potential_assoc_types.len() == assoc_items.len() { // Only suggest when the amount of missing associated types equals the number of // extra type arguments present, as that gives us a relatively high confidence // that the user forgot to give the associtated type's name. The canonical // example would be trying to use `Iterator<isize>` instead of // `Iterator<Item = isize>`. - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(potential_assoc_types[i]) - { - suggestions.push(( - potential_assoc_types[i], - format!("{} = {}", assoc_item.ident, snippet), - )); + for (potential, item) in potential_assoc_types.iter().zip(assoc_items.iter()) { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) { + suggestions.push((*potential, format!("{} = {}", item.ident, snippet))); + } } - } - } - let mut suggestions_len = suggestions.len(); - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sugg_span) { - let assoc_types: Vec<String> = associated_types - .iter() - .map(|item_def_id| { - let assoc_item = tcx.associated_item(*item_def_id); - format!("{} = Type", assoc_item.ident) - }) - .collect(); - let dedup = assoc_types.clone().drain(..).collect::<FxHashSet<_>>(); - - if dedup.len() != assoc_types.len() && trait_bounds.len() == 1 { - // If there are duplicates associated type names and a single trait bound do not - // use structured suggestion, it means that there are multiple super-traits with - // the same associated type name. - err.help( - "consider introducing a new type parameter, adding `where` constraints \ - using the fully-qualified path to the associated type", - ); - } else if dedup.len() == assoc_types.len() && - potential_assoc_types.is_empty() && - trait_bounds.len() == 1 && - // Do not attempt to suggest when we don't know which path segment needs the - // type parameter set. - trait_bounds[0].trait_ref.path.segments.len() == 1 + } else if let (Ok(snippet), false) = + (tcx.sess.source_map().span_to_snippet(*span), dupes) { - applicability = Applicability::HasPlaceholders; - let sugg = assoc_types.join(", "); - if snippet.ends_with('>') { + let types: Vec<_> = + assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect(); + let code = if snippet.ends_with(">") { // 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. - suggestions.push(( - sugg_span, - format!("{}, {}>", &snippet[..snippet.len() - 1], sugg,), - )); + format!("{}, {}>", &snippet[..snippet.len() - 1], types.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>`. - suggestions.push((sugg_span, format!("{}<{}>", snippet, sugg))); - } - suggestions_len = assoc_types.len(); + format!("{}<{}>", snippet, types.join(", ")) + }; + suggestions.push((*span, code)); + } else if dupes { + where_constraints.push(*span); } } + 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() { + // If there are duplicates associated type names and a single trait bound do not + // use structured suggestion, it means that there are multiple super-traits with + // the same associated type name. + err.help(where_msg); + } if suggestions.len() != 1 { // We don't need this label if there's an inline suggestion, show otherwise. - let names = associated_types - .iter() - .map(|t| format!("`{}`", tcx.associated_item(*t).ident)) - .collect::<Vec<_>>() - .join(", "); - err.span_label( - sugg_span, - format!( - "associated type{} {} must be specified", - pluralize!(associated_types.len()), - names, - ), - ); + for (span, def_ids) in &associated_types { + let assoc_items: Vec<_> = + def_ids.iter().map(|def_id| tcx.associated_item(*def_id)).collect(); + let mut names: FxHashMap<_, usize> = FxHashMap::default(); + for item in &assoc_items { + types_count += 1; + *names.entry(item.ident.name).or_insert(0) += 1; + } + let mut label = vec![]; + for item in &assoc_items { + let postfix = if names[&item.ident.name] > 1 { + let trait_def_id = item.container.id(); + format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id)) + } else { + String::new() + }; + label.push(format!("`{}`{}", item.ident, postfix)); + } + if !label.is_empty() { + err.span_label( + *span, + format!( + "associated type{} {} must be specified", + pluralize!(label.len()), + label.join(", "), + ), + ); + } + } } if !suggestions.is_empty() { - let msg = format!("specify the associated type{}", pluralize!(suggestions_len)); - err.multipart_suggestion(&msg, suggestions, applicability); + err.multipart_suggestion( + &format!("specify the associated type{}", pluralize!(types_count)), + suggestions, + Applicability::HasPlaceholders, + ); + if !where_constraints.is_empty() { + err.span_help(where_constraints, where_msg); + } } err.emit(); } diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr index aa46e5d077f..8eb296d4998 100644 --- a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr +++ b/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr @@ -49,15 +49,15 @@ error[E0191]: the value of the associated types `Color` (from trait `Vehicle`), --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:30 | LL | type Color; - | ----------- `Color` defined here + | ----------- `Vehicle::Color` defined here ... LL | type Color; - | ----------- `Color` defined here + | ----------- `Box::Color` defined here ... LL | fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) { - | ^^^^^^^^^^^^^^^^^^^ associated types `Color`, `Color` must be specified + | ^^^^^^^^^^^^^^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified | - = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated type + = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-from-multiple-supertraits.rs:28:29 @@ -84,15 +84,15 @@ error[E0191]: the value of the associated types `Color` (from trait `Vehicle`), --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:32 | LL | type Color; - | ----------- `Color` defined here + | ----------- `Vehicle::Color` defined here ... LL | type Color; - | ----------- `Color` defined here + | ----------- `Box::Color` defined here ... LL | fn dent_object_2<COLOR>(c: dyn BoxCar) where <dyn BoxCar as Vehicle>::Color = COLOR { - | ^^^^^^ associated types `Color`, `Color` must be specified + | ^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified | - = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated type + = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types error: aborting due to 6 previous errors diff --git a/src/test/ui/associated-types/missing-associated-types.rs b/src/test/ui/associated-types/missing-associated-types.rs new file mode 100644 index 00000000000..3c8410e39bd --- /dev/null +++ b/src/test/ui/associated-types/missing-associated-types.rs @@ -0,0 +1,27 @@ +use std::ops::{Add, Sub, Mul, Div}; +trait X<Rhs>: Mul<Rhs> + Div<Rhs> {} +trait Y<Rhs>: Div<Rhs, Output = Rhs> { + type A; +} +trait Z<Rhs>: Div<Rhs> { + type A; + type B; +} +trait Fine<Rhs>: Div<Rhs, Output = Rhs> {} + +type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>; +//~^ ERROR only auto traits can be used as additional traits in a trait object +//~| ERROR the value of the associated types +type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>; +//~^ ERROR only auto traits can be used as additional traits in a trait object +//~| ERROR the value of the associated types +type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>; +//~^ ERROR only auto traits can be used as additional traits in a trait object +//~| ERROR the value of the associated types +type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>; +//~^ ERROR only auto traits can be used as additional traits in a trait object +//~| ERROR the value of the associated types +type Bal<Rhs> = dyn X<Rhs>; +//~^ ERROR the value of the associated types + +fn main() {} diff --git a/src/test/ui/associated-types/missing-associated-types.stderr b/src/test/ui/associated-types/missing-associated-types.stderr new file mode 100644 index 00000000000..7be26638817 --- /dev/null +++ b/src/test/ui/associated-types/missing-associated-types.stderr @@ -0,0 +1,129 @@ +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/missing-associated-types.rs:12:32 + | +LL | type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>; + | -------- ^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`) must be specified + --> $DIR/missing-associated-types.rs:12:52 + | +LL | type A; + | ------- `A` defined here +... +LL | type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>; + | ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated type `A` must be specified + | | | | + | | | associated type `Output` must be specified + | | associated type `Output` must be specified + | associated type `Output` must be specified + | +help: specify the associated types + | +LL | type Foo<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + X<Rhs, Output = Type> + Y<Rhs, A = Type>; + | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/missing-associated-types.rs:15:32 + | +LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>; + | -------- ^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0191]: the value of the associated types `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`), `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + --> $DIR/missing-associated-types.rs:15:21 + | +LL | type A; + | ------- `A` defined here +LL | type B; + | ------- `B` defined here +... +LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>; + | ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated types `A`, `B`, `Output` must be specified + | | | | + | | | associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + | | associated type `Output` must be specified + | associated type `Output` must be specified + | +help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types + --> $DIR/missing-associated-types.rs:15:43 + | +LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>; + | ^^^^^^ +help: specify the associated types + | +LL | type Bar<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + X<Rhs> + Z<Rhs, A = Type, B = Type, Output = Type>; + | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/missing-associated-types.rs:18:32 + | +LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>; + | -------- ^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0191]: the value of the associated types `Output` (from trait `std::ops::Sub`), `A` (from trait `Y`), `Output` (from trait `std::ops::Add`) must be specified + --> $DIR/missing-associated-types.rs:18:32 + | +LL | type A; + | ------- `A` defined here +... +LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>; + | ^^^^^^^^ ^^^^^^^^ ^^^^^^ associated type `A` must be specified + | | | + | | associated type `Output` must be specified + | associated type `Output` must be specified + | +help: specify the associated types + | +LL | type Baz<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + Y<Rhs, A = Type>; + | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/missing-associated-types.rs:21:32 + | +LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>; + | -------- ^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0191]: the value of the associated types `Output` (from trait `std::ops::Sub`), `Output` (from trait `std::ops::Add`) must be specified + --> $DIR/missing-associated-types.rs:21:32 + | +LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>; + | ^^^^^^^^ ^^^^^^^^ associated type `Output` must be specified + | | + | associated type `Output` must be specified + | +help: specify the associated types + | +LL | type Bat<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + Fine<Rhs>; + | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0191]: the value of the associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + --> $DIR/missing-associated-types.rs:24:21 + | +LL | type Bal<Rhs> = dyn X<Rhs>; + | ^^^^^^ associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + | + = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0191, E0225. +For more information about an error, try `rustc --explain E0191`. diff --git a/src/test/ui/issues/issue-22560.stderr b/src/test/ui/issues/issue-22560.stderr index 4466a40f0da..bf80b24fa56 100644 --- a/src/test/ui/issues/issue-22560.stderr +++ b/src/test/ui/issues/issue-22560.stderr @@ -35,8 +35,8 @@ LL | type Test = dyn Add + Sub; | first non-auto trait | trait alias used in trait object type (first use) -error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified - --> $DIR/issue-22560.rs:9:13 +error[E0191]: the value of the associated types `Output` (from trait `Sub`), `Output` (from trait `Add`) must be specified + --> $DIR/issue-22560.rs:9:23 | LL | type Output; | ------------ `Output` defined here @@ -45,7 +45,14 @@ LL | type Output; | ------------ `Output` defined here ... LL | type Test = dyn Add + Sub; - | ^^^^^^^^^^^^^ associated types `Output`, `Output` must be specified + | ^^^ ^^^ associated type `Output` must be specified + | | + | associated type `Output` must be specified + | +help: specify the associated types + | +LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>; + | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr index 321196d14b7..58a73187fb1 100644 --- a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr +++ b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr @@ -7,7 +7,7 @@ LL | i: Box<dyn T<usize, usize, usize, usize, B=usize>>, | unexpected type argument error[E0191]: the value of the associated types `A` (from trait `T`), `C` (from trait `T`) must be specified - --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:12 + --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16 | LL | type A; | ------- `A` defined here @@ -16,7 +16,7 @@ LL | type C; | ------- `C` defined here ... LL | i: Box<dyn T<usize, usize, usize, usize, B=usize>>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified | help: specify the associated types | |
