about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2020-09-22 17:35:03 -0700
committerEsteban Küber <esteban@kuber.com.ar>2020-10-09 14:44:24 -0700
commit711760c8ec9dc431de43a0a72593abcdd74e0b3e (patch)
treee4a24a34202f8be633420344d75ca63eb5707016
parent5ddef544fa26c5535376fa424baf30cb985f7cb1 (diff)
Point out why a trait is expected on `Struct + 'lt`
-rw-r--r--compiler/rustc_resolve/src/late.rs7
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs11
-rw-r--r--src/test/ui/traits/trait-bounds-not-on-struct.stderr6
3 files changed, 23 insertions, 1 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 2c01934b490..cfaf59e8feb 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -384,6 +384,8 @@ struct DiagnosticMetadata<'ast> {
 
     /// Used to detect possible `if let` written without `let` and to provide structured suggestion.
     in_if_condition: Option<&'ast Expr>,
+
+    current_trait_object: Option<&'ast [ast::GenericBound]>,
 }
 
 struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -453,6 +455,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 +467,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(
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 15e72228870..a3948cc00d6 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -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};
@@ -445,6 +445,15 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             // Fallback label.
             err.span_label(base_span, fallback_label);
 
+            if let PathSource::Trait(AliasPossibility::Maybe) = source {
+                if let Some([start, .., end]) = self.diagnostic_metadata.current_trait_object {
+                    err.span_help(
+                        start.span().to(end.span()),
+                        "`+` can be used to constrain a \"trait object\" type with lifetimes or \
+                         auto-traits, structs and enums can't be bound in that way",
+                    );
+                }
+            }
             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(
diff --git a/src/test/ui/traits/trait-bounds-not-on-struct.stderr b/src/test/ui/traits/trait-bounds-not-on-struct.stderr
index a649a4eee55..3d338ef3736 100644
--- a/src/test/ui/traits/trait-bounds-not-on-struct.stderr
+++ b/src/test/ui/traits/trait-bounds-not-on-struct.stderr
@@ -3,6 +3,12 @@ error[E0404]: expected trait, found struct `Foo`
    |
 LL | fn foo(_x: Box<Foo + Send>) { }
    |                ^^^ not a trait
+   |
+help: `+` can be 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:5:16
+   |
+LL | fn foo(_x: Box<Foo + Send>) { }
+   |                ^^^^^^^^^^
 
 error[E0404]: expected trait, found struct `Vec`
   --> $DIR/trait-bounds-not-on-struct.rs:7:21