mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Auto merge of #77087 - estebank:issue-45817, r=matthewjasper
Provide structured suggestions when finding structs when expecting a trait When finding an ADT in a trait object definition provide some solutions. Fix #45817. Given `<Param as Trait>::Assoc: Ty` suggest `Param: Trait<Assoc = Ty>`. Fix #75829.
This commit is contained in:
commit
08764ad163
@ -1884,6 +1884,16 @@ impl Clone for Ty {
|
||||
}
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
pub fn peel_refs(&self) -> &Self {
|
||||
let mut final_ty = self;
|
||||
while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
|
||||
final_ty = &ty;
|
||||
}
|
||||
final_ty
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct BareFnTy {
|
||||
pub unsafety: Unsafe,
|
||||
|
@ -384,6 +384,13 @@ struct DiagnosticMetadata<'ast> {
|
||||
|
||||
/// Used to detect possible `if let` written without `let` and to provide structured suggestion.
|
||||
in_if_condition: Option<&'ast Expr>,
|
||||
|
||||
/// If we are currently in a trait object definition. Used to point at the bounds when
|
||||
/// encountering a struct or enum.
|
||||
current_trait_object: Option<&'ast [ast::GenericBound]>,
|
||||
|
||||
/// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
|
||||
current_where_predicate: Option<&'ast WherePredicate>,
|
||||
}
|
||||
|
||||
struct LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
@ -453,6 +460,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
self.diagnostic_metadata.current_let_binding = original;
|
||||
}
|
||||
fn visit_ty(&mut self, ty: &'ast Ty) {
|
||||
let prev = self.diagnostic_metadata.current_trait_object;
|
||||
match ty.kind {
|
||||
TyKind::Path(ref qself, ref path) => {
|
||||
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
|
||||
@ -464,9 +472,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
.map_or(Res::Err, |d| d.res());
|
||||
self.r.record_partial_res(ty.id, PartialRes::new(res));
|
||||
}
|
||||
TyKind::TraitObject(ref bounds, ..) => {
|
||||
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
visit::walk_ty(self, ty);
|
||||
self.diagnostic_metadata.current_trait_object = prev;
|
||||
}
|
||||
fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
|
||||
self.smart_resolve_path(
|
||||
@ -660,6 +672,14 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
}
|
||||
self.diagnostic_metadata.currently_processing_generics = prev;
|
||||
}
|
||||
|
||||
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
|
||||
debug!("visit_where_predicate {:?}", p);
|
||||
let previous_value =
|
||||
replace(&mut self.diagnostic_metadata.current_where_predicate, Some(p));
|
||||
visit::walk_where_predicate(self, p);
|
||||
self.diagnostic_metadata.current_where_predicate = previous_value;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
|
||||
use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
|
||||
use crate::late::{LateResolutionVisitor, RibKind};
|
||||
use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
|
||||
use crate::path_names_to_string;
|
||||
use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
|
||||
use crate::{PathResult, PathSource, Segment};
|
||||
@ -8,6 +8,7 @@ use crate::{PathResult, PathSource, Segment};
|
||||
use rustc_ast::util::lev_distance::find_best_match_for_name;
|
||||
use rustc_ast::visit::FnKind;
|
||||
use rustc_ast::{self as ast, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
|
||||
use rustc_ast_pretty::pprust::path_segment_to_string;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
@ -19,7 +20,7 @@ use rustc_session::config::nightly_options;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
|
||||
|
||||
use tracing::debug;
|
||||
|
||||
@ -439,27 +440,213 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
if !self.type_ascription_suggestion(&mut err, base_span)
|
||||
&& !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span)
|
||||
{
|
||||
// Fallback label.
|
||||
err.span_label(base_span, fallback_label);
|
||||
if !self.type_ascription_suggestion(&mut err, base_span) {
|
||||
let mut fallback = false;
|
||||
if let (
|
||||
PathSource::Trait(AliasPossibility::Maybe),
|
||||
Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
|
||||
) = (source, res)
|
||||
{
|
||||
if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
|
||||
fallback = true;
|
||||
let spans: Vec<Span> = bounds
|
||||
.iter()
|
||||
.map(|bound| bound.span())
|
||||
.filter(|&sp| sp != base_span)
|
||||
.collect();
|
||||
|
||||
match self.diagnostic_metadata.current_let_binding {
|
||||
Some((pat_sp, Some(ty_sp), None)) if ty_sp.contains(base_span) && could_be_expr => {
|
||||
err.span_suggestion_short(
|
||||
pat_sp.between(ty_sp),
|
||||
"use `=` if you meant to assign",
|
||||
" = ".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
let start_span = bounds.iter().map(|bound| bound.span()).next().unwrap();
|
||||
// `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
|
||||
let end_span = bounds.iter().map(|bound| bound.span()).last().unwrap();
|
||||
// `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
|
||||
let last_bound_span = spans.last().cloned().unwrap();
|
||||
let mut multi_span: MultiSpan = spans.clone().into();
|
||||
for sp in spans {
|
||||
let msg = if sp == last_bound_span {
|
||||
format!(
|
||||
"...because of {} bound{}",
|
||||
if bounds.len() <= 2 { "this" } else { "these" },
|
||||
if bounds.len() <= 2 { "" } else { "s" },
|
||||
)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
multi_span.push_span_label(sp, msg);
|
||||
}
|
||||
multi_span.push_span_label(
|
||||
base_span,
|
||||
"expected this type to be a trait...".to_string(),
|
||||
);
|
||||
err.span_help(
|
||||
multi_span,
|
||||
"`+` is used to constrain a \"trait object\" type with lifetimes or \
|
||||
auto-traits; structs and enums can't be bound in that way",
|
||||
);
|
||||
if bounds.iter().all(|bound| match bound {
|
||||
ast::GenericBound::Outlives(_) => true,
|
||||
ast::GenericBound::Trait(tr, _) => tr.span == base_span,
|
||||
}) {
|
||||
let mut sugg = vec![];
|
||||
if base_span != start_span {
|
||||
sugg.push((start_span.until(base_span), String::new()));
|
||||
}
|
||||
if base_span != end_span {
|
||||
sugg.push((base_span.shrink_to_hi().to(end_span), String::new()));
|
||||
}
|
||||
|
||||
err.multipart_suggestion(
|
||||
"if you meant to use a type and not a trait here, remove the bounds",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
fallback |= self.restrict_assoc_type_in_where_clause(span, &mut err);
|
||||
|
||||
if !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) {
|
||||
fallback = true;
|
||||
match self.diagnostic_metadata.current_let_binding {
|
||||
Some((pat_sp, Some(ty_sp), None))
|
||||
if ty_sp.contains(base_span) && could_be_expr =>
|
||||
{
|
||||
err.span_suggestion_short(
|
||||
pat_sp.between(ty_sp),
|
||||
"use `=` if you meant to assign",
|
||||
" = ".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if fallback {
|
||||
// Fallback label.
|
||||
err.span_label(base_span, fallback_label);
|
||||
}
|
||||
}
|
||||
(err, candidates)
|
||||
}
|
||||
|
||||
/// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
|
||||
fn restrict_assoc_type_in_where_clause(
|
||||
&mut self,
|
||||
span: Span,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
) -> bool {
|
||||
// Detect that we are actually in a `where` predicate.
|
||||
let (bounded_ty, bounds, where_span) =
|
||||
if let Some(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
||||
bounded_ty,
|
||||
bound_generic_params,
|
||||
bounds,
|
||||
span,
|
||||
})) = self.diagnostic_metadata.current_where_predicate
|
||||
{
|
||||
if !bound_generic_params.is_empty() {
|
||||
return false;
|
||||
}
|
||||
(bounded_ty, bounds, span)
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Confirm that the target is an associated type.
|
||||
let (ty, position, path) = if let ast::TyKind::Path(
|
||||
Some(ast::QSelf { ty, position, .. }),
|
||||
path,
|
||||
) = &bounded_ty.kind
|
||||
{
|
||||
// use this to verify that ident is a type param.
|
||||
let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
|
||||
bounded_ty.id,
|
||||
None,
|
||||
&Segment::from_path(path),
|
||||
Namespace::TypeNS,
|
||||
span,
|
||||
true,
|
||||
CrateLint::No,
|
||||
) {
|
||||
partial_res
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
if !(matches!(
|
||||
partial_res.base_res(),
|
||||
hir::def::Res::Def(hir::def::DefKind::AssocTy, _)
|
||||
) && partial_res.unresolved_segments() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
(ty, position, path)
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if let ast::TyKind::Path(None, type_param_path) = &ty.peel_refs().kind {
|
||||
// Confirm that the `SelfTy` is a type parameter.
|
||||
let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
|
||||
bounded_ty.id,
|
||||
None,
|
||||
&Segment::from_path(type_param_path),
|
||||
Namespace::TypeNS,
|
||||
span,
|
||||
true,
|
||||
CrateLint::No,
|
||||
) {
|
||||
partial_res
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
if !(matches!(
|
||||
partial_res.base_res(),
|
||||
hir::def::Res::Def(hir::def::DefKind::TyParam, _)
|
||||
) && partial_res.unresolved_segments() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let (
|
||||
[ast::PathSegment { ident: constrain_ident, args: None, .. }],
|
||||
[ast::GenericBound::Trait(poly_trait_ref, ast::TraitBoundModifier::None)],
|
||||
) = (&type_param_path.segments[..], &bounds[..])
|
||||
{
|
||||
if let [ast::PathSegment { ident, args: None, .. }] =
|
||||
&poly_trait_ref.trait_ref.path.segments[..]
|
||||
{
|
||||
if ident.span == span {
|
||||
err.span_suggestion_verbose(
|
||||
*where_span,
|
||||
&format!("constrain the associated type to `{}`", ident),
|
||||
format!(
|
||||
"{}: {}<{} = {}>",
|
||||
self.r
|
||||
.session
|
||||
.source_map()
|
||||
.span_to_snippet(ty.span) // Account for `<&'a T as Foo>::Bar`.
|
||||
.unwrap_or_else(|_| constrain_ident.to_string()),
|
||||
path.segments[..*position]
|
||||
.iter()
|
||||
.map(|segment| path_segment_to_string(segment))
|
||||
.collect::<Vec<_>>()
|
||||
.join("::"),
|
||||
path.segments[*position..]
|
||||
.iter()
|
||||
.map(|segment| path_segment_to_string(segment))
|
||||
.collect::<Vec<_>>()
|
||||
.join("::"),
|
||||
ident,
|
||||
),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Check if the source is call expression and the first argument is `self`. If true,
|
||||
/// return the span of whole call and the span for all arguments expect the first one (`self`).
|
||||
fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
|
||||
|
19
src/test/ui/traits/assoc_type_bound_with_struct.rs
Normal file
19
src/test/ui/traits/assoc_type_bound_with_struct.rs
Normal file
@ -0,0 +1,19 @@
|
||||
trait Bar {
|
||||
type Baz;
|
||||
}
|
||||
|
||||
struct Foo<T> where T: Bar, <T as Bar>::Baz: String { //~ ERROR expected trait, found struct
|
||||
t: T,
|
||||
}
|
||||
|
||||
struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String { //~ ERROR expected trait, found struct
|
||||
t: &'a T,
|
||||
}
|
||||
|
||||
fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String { //~ ERROR expected trait, found struct
|
||||
}
|
||||
|
||||
fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { //~ ERROR expected trait, found
|
||||
}
|
||||
|
||||
fn main() {}
|
83
src/test/ui/traits/assoc_type_bound_with_struct.stderr
Normal file
83
src/test/ui/traits/assoc_type_bound_with_struct.stderr
Normal file
@ -0,0 +1,83 @@
|
||||
error[E0404]: expected trait, found struct `String`
|
||||
--> $DIR/assoc_type_bound_with_struct.rs:5:46
|
||||
|
|
||||
LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: String {
|
||||
| ^^^^^^ not a trait
|
||||
|
|
||||
::: $SRC_DIR/alloc/src/string.rs:LL:COL
|
||||
|
|
||||
LL | pub trait ToString {
|
||||
| ------------------ similarly named trait `ToString` defined here
|
||||
|
|
||||
help: constrain the associated type to `String`
|
||||
|
|
||||
LL | struct Foo<T> where T: Bar, T: Bar<Baz = String> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
help: a trait with a similar name exists
|
||||
|
|
||||
LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: ToString {
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0404]: expected trait, found struct `String`
|
||||
--> $DIR/assoc_type_bound_with_struct.rs:9:54
|
||||
|
|
||||
LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String {
|
||||
| ^^^^^^ not a trait
|
||||
|
|
||||
::: $SRC_DIR/alloc/src/string.rs:LL:COL
|
||||
|
|
||||
LL | pub trait ToString {
|
||||
| ------------------ similarly named trait `ToString` defined here
|
||||
|
|
||||
help: constrain the associated type to `String`
|
||||
|
|
||||
LL | struct Qux<'a, T> where T: Bar, &'a T: Bar<Baz = String> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: a trait with a similar name exists
|
||||
|
|
||||
LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: ToString {
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0404]: expected trait, found struct `String`
|
||||
--> $DIR/assoc_type_bound_with_struct.rs:13:45
|
||||
|
|
||||
LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String {
|
||||
| ^^^^^^ not a trait
|
||||
|
|
||||
::: $SRC_DIR/alloc/src/string.rs:LL:COL
|
||||
|
|
||||
LL | pub trait ToString {
|
||||
| ------------------ similarly named trait `ToString` defined here
|
||||
|
|
||||
help: constrain the associated type to `String`
|
||||
|
|
||||
LL | fn foo<T: Bar>(_: T) where T: Bar<Baz = String> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
help: a trait with a similar name exists
|
||||
|
|
||||
LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: ToString {
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0404]: expected trait, found struct `String`
|
||||
--> $DIR/assoc_type_bound_with_struct.rs:16:57
|
||||
|
|
||||
LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String {
|
||||
| ^^^^^^ not a trait
|
||||
|
|
||||
::: $SRC_DIR/alloc/src/string.rs:LL:COL
|
||||
|
|
||||
LL | pub trait ToString {
|
||||
| ------------------ similarly named trait `ToString` defined here
|
||||
|
|
||||
help: constrain the associated type to `String`
|
||||
|
|
||||
LL | fn qux<'a, T: Bar>(_: &'a T) where &'a T: Bar<Baz = String> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: a trait with a similar name exists
|
||||
|
|
||||
LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: ToString {
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0404`.
|
@ -1,9 +1,38 @@
|
||||
// We don't need those errors. Ideally we would silence them, but to do so we need to move the
|
||||
// lint from being an early-lint during parsing to a late-lint, because it needs to be aware of
|
||||
// the types involved.
|
||||
#![allow(bare_trait_objects)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
fn foo(_x: Box<Foo + Send>) { } //~ ERROR expected trait, found struct `Foo`
|
||||
|
||||
type A<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
|
||||
type TypeAlias<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
|
||||
|
||||
fn main() { }
|
||||
struct A;
|
||||
fn a() -> A + 'static { //~ ERROR expected trait, found
|
||||
A
|
||||
}
|
||||
fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) { //~ ERROR expected trait, found
|
||||
panic!()
|
||||
}
|
||||
fn c() -> 'static + A { //~ ERROR expected trait, found
|
||||
A
|
||||
}
|
||||
fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) { //~ ERROR expected trait, found
|
||||
panic!()
|
||||
}
|
||||
fn e() -> 'static + A + 'static { //~ ERROR expected trait, found
|
||||
//~^ ERROR only a single explicit lifetime bound is permitted
|
||||
A
|
||||
}
|
||||
fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) { //~ ERROR expected trait, found
|
||||
//~^ ERROR only a single explicit lifetime bound is permitted
|
||||
panic!()
|
||||
}
|
||||
struct Traitor;
|
||||
trait Trait {}
|
||||
fn g() -> Traitor + 'static { //~ ERROR expected trait, found struct `Traitor`
|
||||
A
|
||||
}
|
||||
fn main() {}
|
||||
|
@ -1,15 +1,168 @@
|
||||
error[E0226]: only a single explicit lifetime bound is permitted
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:25:25
|
||||
|
|
||||
LL | fn e() -> 'static + A + 'static {
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0226]: only a single explicit lifetime bound is permitted
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:29:53
|
||||
|
|
||||
LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
|
||||
| ^^
|
||||
|
||||
error[E0404]: expected trait, found struct `Foo`
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:5:16
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:8:16
|
||||
|
|
||||
LL | fn foo(_x: Box<Foo + Send>) { }
|
||||
| ^^^ not a trait
|
||||
|
|
||||
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:8:22
|
||||
|
|
||||
LL | fn foo(_x: Box<Foo + Send>) { }
|
||||
| --- ^^^^ ...because of this bound
|
||||
| |
|
||||
| expected this type to be a trait...
|
||||
|
||||
error[E0404]: expected trait, found struct `Vec`
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:7:21
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:10:29
|
||||
|
|
||||
LL | type A<T> = Box<dyn Vec<T>>;
|
||||
| ^^^^^^ not a trait
|
||||
LL | type TypeAlias<T> = Box<dyn Vec<T>>;
|
||||
| ^^^^^^ not a trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0404]: expected trait, found struct `A`
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:13:11
|
||||
|
|
||||
LL | fn a() -> A + 'static {
|
||||
| ^ not a trait
|
||||
|
|
||||
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:13:15
|
||||
|
|
||||
LL | fn a() -> A + 'static {
|
||||
| - ^^^^^^^ ...because of this bound
|
||||
| |
|
||||
| expected this type to be a trait...
|
||||
help: if you meant to use a type and not a trait here, remove the bounds
|
||||
|
|
||||
LL | fn a() -> A {
|
||||
| --
|
||||
|
||||
For more information about this error, try `rustc --explain E0404`.
|
||||
error[E0404]: expected trait, found enum `Result`
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:16:34
|
||||
|
|
||||
LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) {
|
||||
| ^^^^^^^^^^^ not a trait
|
||||
|
|
||||
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:16:48
|
||||
|
|
||||
LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) {
|
||||
| ----------- ^^ ...because of this bound
|
||||
| |
|
||||
| expected this type to be a trait...
|
||||
help: if you meant to use a type and not a trait here, remove the bounds
|
||||
|
|
||||
LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
|
||||
| --
|
||||
|
||||
error[E0404]: expected trait, found struct `A`
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:19:21
|
||||
|
|
||||
LL | fn c() -> 'static + A {
|
||||
| ^ not a trait
|
||||
|
|
||||
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:19:11
|
||||
|
|
||||
LL | fn c() -> 'static + A {
|
||||
| ^^^^^^^ - expected this type to be a trait...
|
||||
| |
|
||||
| ...because of this bound
|
||||
help: if you meant to use a type and not a trait here, remove the bounds
|
||||
|
|
||||
LL | fn c() -> A {
|
||||
| --
|
||||
|
||||
error[E0404]: expected trait, found enum `Result`
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:22:39
|
||||
|
|
||||
LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) {
|
||||
| ^^^^^^^^^^^ not a trait
|
||||
|
|
||||
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:22:34
|
||||
|
|
||||
LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) {
|
||||
| ^^ ----------- expected this type to be a trait...
|
||||
| |
|
||||
| ...because of this bound
|
||||
help: if you meant to use a type and not a trait here, remove the bounds
|
||||
|
|
||||
LL | fn d<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
|
||||
| --
|
||||
|
||||
error[E0404]: expected trait, found struct `A`
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:25:21
|
||||
|
|
||||
LL | fn e() -> 'static + A + 'static {
|
||||
| ^ not a trait
|
||||
|
|
||||
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:25:11
|
||||
|
|
||||
LL | fn e() -> 'static + A + 'static {
|
||||
| ^^^^^^^ - ^^^^^^^ ...because of these bounds
|
||||
| |
|
||||
| expected this type to be a trait...
|
||||
help: if you meant to use a type and not a trait here, remove the bounds
|
||||
|
|
||||
LL | fn e() -> A {
|
||||
| ---
|
||||
|
||||
error[E0404]: expected trait, found enum `Result`
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:29:39
|
||||
|
|
||||
LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
|
||||
| ^^^^^^^^^^^ not a trait
|
||||
|
|
||||
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:29:34
|
||||
|
|
||||
LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
|
||||
| ^^ ----------- ^^ ...because of these bounds
|
||||
| |
|
||||
| expected this type to be a trait...
|
||||
help: if you meant to use a type and not a trait here, remove the bounds
|
||||
|
|
||||
LL | fn f<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
|
||||
| -- --
|
||||
|
||||
error[E0404]: expected trait, found struct `Traitor`
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:35:11
|
||||
|
|
||||
LL | trait Trait {}
|
||||
| ----------- similarly named trait `Trait` defined here
|
||||
LL | fn g() -> Traitor + 'static {
|
||||
| ^^^^^^^ not a trait
|
||||
|
|
||||
help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
|
||||
--> $DIR/trait-bounds-not-on-struct.rs:35:21
|
||||
|
|
||||
LL | fn g() -> Traitor + 'static {
|
||||
| ------- ^^^^^^^ ...because of this bound
|
||||
| |
|
||||
| expected this type to be a trait...
|
||||
help: if you meant to use a type and not a trait here, remove the bounds
|
||||
|
|
||||
LL | fn g() -> Traitor {
|
||||
| --
|
||||
help: a trait with a similar name exists
|
||||
|
|
||||
LL | fn g() -> Trait + 'static {
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0226, E0404.
|
||||
For more information about an error, try `rustc --explain E0226`.
|
||||
|
Loading…
Reference in New Issue
Block a user