about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2020-01-21 23:01:21 -0800
committerEsteban Küber <esteban@kuber.com.ar>2020-01-26 10:57:18 -0800
commit697fdc568e28fbb376567eda4edb2c2a05db68de (patch)
tree2353388fac15725d1de0ef61d3c729dda69ba9ff /src
parent8ad83afe5bcfa983a24b6f720c9ef389350f414b (diff)
downloadrust-697fdc568e28fbb376567eda4edb2c2a05db68de.tar.gz
rust-697fdc568e28fbb376567eda4edb2c2a05db68de.zip
Suggest defining type parameter when appropriate
```
error[E0412]: cannot find type `T` in this scope
 --> file.rs:3:12
  |
3 | impl Trait<T> for Struct {}
  |     -      ^ not found in this scope
  |     |
  |     help: you might be missing a type parameter: `<T>`
```

Fix #64298.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_resolve/diagnostics.rs5
-rw-r--r--src/librustc_resolve/late.rs110
-rw-r--r--src/librustc_resolve/late/diagnostics.rs51
-rw-r--r--src/librustc_resolve/lib.rs9
-rw-r--r--src/libsyntax/ast.rs14
-rw-r--r--src/test/ui/dyn-trait-compatibility.stderr12
-rw-r--r--src/test/ui/hygiene/globs.stderr15
-rw-r--r--src/test/ui/issues/issue-58712.stderr4
-rw-r--r--src/test/ui/privacy/privacy-ns1.stderr4
-rw-r--r--src/test/ui/proc-macro/generate-mod.stderr12
-rw-r--r--src/test/ui/suggestions/no-extern-crate-in-type.stderr4
-rw-r--r--src/test/ui/type-alias/issue-62364-self-ty-arg.stderr4
12 files changed, 178 insertions, 66 deletions
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 77dfe3d9f1d..b762e0b08ac 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -1415,11 +1415,15 @@ crate fn show_candidates(
     better: bool,
     found_use: bool,
 ) {
+    if candidates.is_empty() {
+        return;
+    }
     // we want consistent results across executions, but candidates are produced
     // by iterating through a hash map, so make sure they are ordered:
     let mut path_strings: Vec<_> =
         candidates.into_iter().map(|c| path_names_to_string(&c.path)).collect();
     path_strings.sort();
+    path_strings.dedup();
 
     let better = if better { "better " } else { "" };
     let msg_diff = match path_strings.len() {
@@ -1444,6 +1448,7 @@ crate fn show_candidates(
             msg.push('\n');
             msg.push_str(&candidate);
         }
+        err.note(&msg);
     }
 }
 
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 5e08ac8e2c3..faa9eb3bc2f 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -323,7 +323,7 @@ impl<'a> PathSource<'a> {
 }
 
 #[derive(Default)]
-struct DiagnosticMetadata {
+struct DiagnosticMetadata<'ast> {
     /// The current trait's associated types' ident, used for diagnostic suggestions.
     current_trait_assoc_types: Vec<Ident>,
 
@@ -333,6 +333,13 @@ struct DiagnosticMetadata {
     /// The current self item if inside an ADT (used for better errors).
     current_self_item: Option<NodeId>,
 
+    /// The current trait (used to suggest).
+    current_item: Option<&'ast Item>,
+
+    /// When processing generics and encountering a type not found, suggest introducing a type
+    /// param.
+    currently_processing_generics: bool,
+
     /// The current enclosing function (used for better errors).
     current_function: Option<Span>,
 
@@ -347,7 +354,7 @@ struct DiagnosticMetadata {
     current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
 }
 
-struct LateResolutionVisitor<'a, 'b> {
+struct LateResolutionVisitor<'a, 'b, 'ast> {
     r: &'b mut Resolver<'a>,
 
     /// The module that represents the current item scope.
@@ -364,30 +371,32 @@ struct LateResolutionVisitor<'a, 'b> {
     current_trait_ref: Option<(Module<'a>, TraitRef)>,
 
     /// Fields used to add information to diagnostic errors.
-    diagnostic_metadata: DiagnosticMetadata,
+    diagnostic_metadata: DiagnosticMetadata<'ast>,
 }
 
 /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
-impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
-    fn visit_item(&mut self, item: &'tcx Item) {
+impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
+    fn visit_item(&mut self, item: &'ast Item) {
+        let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
         self.resolve_item(item);
+        self.diagnostic_metadata.current_item = prev;
     }
-    fn visit_arm(&mut self, arm: &'tcx Arm) {
+    fn visit_arm(&mut self, arm: &'ast Arm) {
         self.resolve_arm(arm);
     }
-    fn visit_block(&mut self, block: &'tcx Block) {
+    fn visit_block(&mut self, block: &'ast Block) {
         self.resolve_block(block);
     }
-    fn visit_anon_const(&mut self, constant: &'tcx AnonConst) {
+    fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
         debug!("visit_anon_const {:?}", constant);
         self.with_constant_rib(|this| {
             visit::walk_anon_const(this, constant);
         });
     }
-    fn visit_expr(&mut self, expr: &'tcx Expr) {
+    fn visit_expr(&mut self, expr: &'ast Expr) {
         self.resolve_expr(expr, None);
     }
-    fn visit_local(&mut self, local: &'tcx Local) {
+    fn visit_local(&mut self, local: &'ast Local) {
         let local_spans = match local.pat.kind {
             // We check for this to avoid tuple struct fields.
             PatKind::Wild => None,
@@ -401,7 +410,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
         self.resolve_local(local);
         self.diagnostic_metadata.current_let_binding = original;
     }
-    fn visit_ty(&mut self, ty: &'tcx Ty) {
+    fn visit_ty(&mut self, ty: &'ast Ty) {
         match ty.kind {
             TyKind::Path(ref qself, ref path) => {
                 self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
@@ -417,7 +426,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
         }
         visit::walk_ty(self, ty);
     }
-    fn visit_poly_trait_ref(&mut self, tref: &'tcx PolyTraitRef, m: &'tcx TraitBoundModifier) {
+    fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
         self.smart_resolve_path(
             tref.trait_ref.ref_id,
             None,
@@ -426,7 +435,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
         );
         visit::walk_poly_trait_ref(self, tref, m);
     }
-    fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) {
+    fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
         match foreign_item.kind {
             ForeignItemKind::Fn(_, ref generics) => {
                 self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
@@ -443,7 +452,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
             }
         }
     }
-    fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, sp: Span, _: NodeId) {
+    fn visit_fn(&mut self, fn_kind: FnKind<'ast>, declaration: &'ast FnDecl, sp: Span, _: NodeId) {
         let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp));
         debug!("(resolving function) entering function");
         let rib_kind = match fn_kind {
@@ -472,7 +481,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
         self.diagnostic_metadata.current_function = previous_value;
     }
 
-    fn visit_generics(&mut self, generics: &'tcx Generics) {
+    fn visit_generics(&mut self, generics: &'ast Generics) {
         // For type parameter defaults, we have to ban access
         // to following type parameters, as the InternalSubsts can only
         // provide previous type parameters as they're built. We
@@ -534,11 +543,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
         }
     }
 
-    fn visit_generic_arg(&mut self, arg: &'tcx GenericArg) {
+    fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
         debug!("visit_generic_arg({:?})", arg);
+        let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true);
         match arg {
             GenericArg::Type(ref ty) => {
-                // We parse const arguments as path types as we cannot distiguish them durring
+                // We parse const arguments as path types as we cannot distiguish them during
                 // parsing. We try to resolve that ambiguity by attempting resolution the type
                 // namespace first, and if that fails we try again in the value namespace. If
                 // resolution in the value namespace succeeds, we have an generic const argument on
@@ -556,7 +566,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
                             )
                             .is_some()
                         };
-
                         if !check_ns(TypeNS) && check_ns(ValueNS) {
                             // This must be equivalent to `visit_anon_const`, but we cannot call it
                             // directly due to visitor lifetimes so we have to copy-paste some code.
@@ -574,6 +583,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
                                 this.visit_path(path, ty.id);
                             });
 
+                            self.diagnostic_metadata.currently_processing_generics = prev;
                             return;
                         }
                     }
@@ -584,11 +594,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
             GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
             GenericArg::Const(ct) => self.visit_anon_const(ct),
         }
+        self.diagnostic_metadata.currently_processing_generics = prev;
     }
 }
 
-impl<'a, 'b> LateResolutionVisitor<'a, '_> {
-    fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b> {
+impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
+    fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> {
         // During late resolution we only track the module component of the parent scope,
         // although it may be useful to track other components as well for diagnostics.
         let graph_root = resolver.graph_root;
@@ -724,7 +735,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         None
     }
 
-    fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
+    fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
         debug!("resolve_adt");
         self.with_current_self_item(item, |this| {
             this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
@@ -778,7 +789,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         }
     }
 
-    fn resolve_item(&mut self, item: &Item) {
+    fn resolve_item(&mut self, item: &'ast Item) {
         let name = item.ident.name;
         debug!("(resolving item) resolving {} ({:?})", name, item.kind);
 
@@ -1024,16 +1035,15 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         let mut new_id = None;
         if let Some(trait_ref) = opt_trait_ref {
             let path: Vec<_> = Segment::from_path(&trait_ref.path);
-            let res = self
-                .smart_resolve_path_fragment(
-                    trait_ref.ref_id,
-                    None,
-                    &path,
-                    trait_ref.path.span,
-                    PathSource::Trait(AliasPossibility::No),
-                    CrateLint::SimplePath(trait_ref.ref_id),
-                )
-                .base_res();
+            let res = self.smart_resolve_path_fragment(
+                trait_ref.ref_id,
+                None,
+                &path,
+                trait_ref.path.span,
+                PathSource::Trait(AliasPossibility::No),
+                CrateLint::SimplePath(trait_ref.ref_id),
+            );
+            let res = res.base_res();
             if res != Res::Err {
                 new_id = Some(res.def_id());
                 let span = trait_ref.path.span;
@@ -1070,11 +1080,11 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
 
     fn resolve_implementation(
         &mut self,
-        generics: &Generics,
-        opt_trait_reference: &Option<TraitRef>,
-        self_type: &Ty,
+        generics: &'ast Generics,
+        opt_trait_reference: &'ast Option<TraitRef>,
+        self_type: &'ast Ty,
         item_id: NodeId,
-        impl_items: &[AssocItem],
+        impl_items: &'ast [AssocItem],
     ) {
         debug!("resolve_implementation");
         // If applicable, create a rib for the type parameters.
@@ -1179,7 +1189,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         }
     }
 
-    fn resolve_params(&mut self, params: &[Param]) {
+    fn resolve_params(&mut self, params: &'ast [Param]) {
         let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
         for Param { pat, ty, .. } in params {
             self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
@@ -1188,7 +1198,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         }
     }
 
-    fn resolve_local(&mut self, local: &Local) {
+    fn resolve_local(&mut self, local: &'ast Local) {
         // Resolve the type.
         walk_list!(self, visit_ty, &local.ty);
 
@@ -1307,7 +1317,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
     }
 
     /// Check the consistency of the outermost or-patterns.
-    fn check_consistent_bindings_top(&mut self, pat: &Pat) {
+    fn check_consistent_bindings_top(&mut self, pat: &'ast Pat) {
         pat.walk(&mut |pat| match pat.kind {
             PatKind::Or(ref ps) => {
                 self.check_consistent_bindings(ps);
@@ -1317,7 +1327,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         })
     }
 
-    fn resolve_arm(&mut self, arm: &Arm) {
+    fn resolve_arm(&mut self, arm: &'ast Arm) {
         self.with_rib(ValueNS, NormalRibKind, |this| {
             this.resolve_pattern_top(&arm.pat, PatternSource::Match);
             walk_list!(this, visit_expr, &arm.guard);
@@ -1326,14 +1336,14 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
     }
 
     /// Arising from `source`, resolve a top level pattern.
-    fn resolve_pattern_top(&mut self, pat: &Pat, pat_src: PatternSource) {
+    fn resolve_pattern_top(&mut self, pat: &'ast Pat, pat_src: PatternSource) {
         let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
         self.resolve_pattern(pat, pat_src, &mut bindings);
     }
 
     fn resolve_pattern(
         &mut self,
-        pat: &Pat,
+        pat: &'ast Pat,
         pat_src: PatternSource,
         bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>,
     ) {
@@ -1544,7 +1554,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         id: NodeId,
         qself: Option<&QSelf>,
         path: &Path,
-        source: PathSource<'_>,
+        source: PathSource<'ast>,
     ) {
         self.smart_resolve_path_fragment(
             id,
@@ -1562,7 +1572,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         qself: Option<&QSelf>,
         path: &[Segment],
         span: Span,
-        source: PathSource<'_>,
+        source: PathSource<'ast>,
         crate_lint: CrateLint,
     ) -> PartialRes {
         let ns = source.namespace();
@@ -1573,7 +1583,9 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
             let def_id = this.parent_scope.module.normal_ancestor_id;
             let node_id = this.r.definitions.as_local_node_id(def_id).unwrap();
             let better = res.is_some();
-            this.r.use_injections.push(UseError { err, candidates, node_id, better });
+            let suggestion =
+                if res.is_none() { this.report_missing_type_error(path) } else { None };
+            this.r.use_injections.push(UseError { err, candidates, node_id, better, suggestion });
             PartialRes::new(Res::Err)
         };
 
@@ -1838,11 +1850,11 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         }
     }
 
-    fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &Block) {
+    fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &'ast Block) {
         self.with_resolved_label(label, id, |this| this.visit_block(block));
     }
 
-    fn resolve_block(&mut self, block: &Block) {
+    fn resolve_block(&mut self, block: &'ast Block) {
         debug!("(resolving block) entering block");
         // Move down in the graph, if there's an anonymous module rooted here.
         let orig_module = self.parent_scope.module;
@@ -1885,7 +1897,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         debug!("(resolving block) leaving block");
     }
 
-    fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
+    fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
         // First, record candidate traits for this expression if it could
         // result in the invocation of a method call.
 
@@ -2023,7 +2035,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
         }
     }
 
-    fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
+    fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &'ast Expr) {
         match expr.kind {
             ExprKind::Field(_, ident) => {
                 // FIXME(#6890): Even though you can't treat a method like a
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs
index 6a98c9e59a9..6ec4a13500e 100644
--- a/src/librustc_resolve/late/diagnostics.rs
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -12,9 +12,9 @@ use rustc_hir::def::{self, CtorKind, DefKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_hir::PrimTy;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::symbol::kw;
+use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
-use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind};
+use syntax::ast::{self, Expr, ExprKind, Ident, Item, ItemKind, NodeId, Path, Ty, TyKind};
 use syntax::util::lev_distance::find_best_match_for_name;
 
 use log::debug;
@@ -51,7 +51,7 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str
     (variant_path_string, enum_path_string)
 }
 
-impl<'a> LateResolutionVisitor<'a, '_> {
+impl<'a> LateResolutionVisitor<'a, '_, '_> {
     /// Handles error reporting for `smart_resolve_path_fragment` function.
     /// Creates base error and amends it with one short label and possibly some longer helps/notes.
     pub(crate) fn smart_resolve_report_errors(
@@ -858,4 +858,49 @@ impl<'a> LateResolutionVisitor<'a, '_> {
             variants
         })
     }
+
+    crate fn report_missing_type_error(
+        &self,
+        path: &[Segment],
+    ) -> Option<(Span, &'static str, String, Applicability)> {
+        let ident = match path {
+            [segment] => segment.ident,
+            _ => return None,
+        };
+        match (
+            self.diagnostic_metadata.current_item,
+            self.diagnostic_metadata.currently_processing_generics,
+        ) {
+            (Some(Item { kind: ItemKind::Fn(..), ident, .. }), true) if ident.name == sym::main => {
+                // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
+            }
+            (Some(Item { kind, .. }), true) => {
+                // Likely missing type parameter.
+                if let Some(generics) = kind.generics() {
+                    let msg = "you might be missing a type parameter";
+                    let (span, sugg) = if let [.., param] = &generics.params[..] {
+                        let span = if let [.., bound] = &param.bounds[..] {
+                            bound.span()
+                        } else {
+                            param.ident.span
+                        };
+                        (span, format!(", {}", ident))
+                    } else {
+                        (generics.span, format!("<{}>", ident))
+                    };
+                    // Do not suggest if this is coming from macro expansion.
+                    if !span.from_expansion() {
+                        return Some((
+                            span.shrink_to_hi(),
+                            msg,
+                            sugg,
+                            Applicability::MaybeIncorrect,
+                        ));
+                    }
+                }
+            }
+            _ => {}
+        }
+        None
+    }
 }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 0e6f40fa846..0b1752419b8 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -614,6 +614,8 @@ struct UseError<'a> {
     node_id: NodeId,
     /// Whether the diagnostic should state that it's "better".
     better: bool,
+    /// Extra free form suggestion. Currently used to suggest new type parameter.
+    suggestion: Option<(Span, &'static str, String, Applicability)>,
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
@@ -2474,11 +2476,16 @@ impl<'a> Resolver<'a> {
     }
 
     fn report_with_use_injections(&mut self, krate: &Crate) {
-        for UseError { mut err, candidates, node_id, better } in self.use_injections.drain(..) {
+        for UseError { mut err, candidates, node_id, better, suggestion } in
+            self.use_injections.drain(..)
+        {
             let (span, found_use) = UsePlacementFinder::check(krate, node_id);
             if !candidates.is_empty() {
                 diagnostics::show_candidates(&mut err, span, &candidates, better, found_use);
             }
+            if let Some((span, msg, sugg, appl)) = suggestion {
+                err.span_suggestion(span, msg, sugg, appl);
+            }
             err.emit();
         }
     }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 5f38ac4cc0f..5c64cc440ce 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2655,6 +2655,20 @@ impl ItemKind {
             ItemKind::Mac(..) | ItemKind::MacroDef(..) | ItemKind::Impl { .. } => "item",
         }
     }
+
+    pub fn generics(&self) -> Option<&Generics> {
+        match self {
+            Self::Fn(_, generics, _)
+            | Self::TyAlias(_, generics)
+            | Self::Enum(_, generics)
+            | Self::Struct(_, generics)
+            | Self::Union(_, generics)
+            | Self::Trait(_, _, generics, ..)
+            | Self::TraitAlias(generics, _)
+            | Self::Impl { generics, .. } => Some(generics),
+            _ => None,
+        }
+    }
 }
 
 pub type ForeignItem = Item<ForeignItemKind>;
diff --git a/src/test/ui/dyn-trait-compatibility.stderr b/src/test/ui/dyn-trait-compatibility.stderr
index 7210a11f350..8fe8ceb4d0a 100644
--- a/src/test/ui/dyn-trait-compatibility.stderr
+++ b/src/test/ui/dyn-trait-compatibility.stderr
@@ -26,13 +26,17 @@ error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/dyn-trait-compatibility.rs:5:15
    |
 LL | type A2 = dyn<dyn, dyn>;
-   |               ^^^ not found in this scope
+   |        -      ^^^ not found in this scope
+   |        |
+   |        help: you might be missing a type parameter: `<dyn>`
 
 error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/dyn-trait-compatibility.rs:5:20
    |
 LL | type A2 = dyn<dyn, dyn>;
-   |                    ^^^ not found in this scope
+   |        -           ^^^ not found in this scope
+   |        |
+   |        help: you might be missing a type parameter: `<dyn>`
 
 error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/dyn-trait-compatibility.rs:9:11
@@ -44,7 +48,9 @@ error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/dyn-trait-compatibility.rs:9:16
    |
 LL | type A3 = dyn<<dyn as dyn>::dyn>;
-   |                ^^^ not found in this scope
+   |        -       ^^^ not found in this scope
+   |        |
+   |        help: you might be missing a type parameter: `<dyn>`
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr
index 4b382a2b209..f9fbf295aec 100644
--- a/src/test/ui/hygiene/globs.stderr
+++ b/src/test/ui/hygiene/globs.stderr
@@ -4,11 +4,7 @@ error[E0425]: cannot find function `f` in this scope
 LL |         f();
    |         ^ not found in this scope
    |
-help: possible candidates are found in other modules, you can import them into scope
-   |
-LL | use foo::f;
-   |
-LL | use foo::f;
+help: possible candidate is found in another module, you can import it into scope
    |
 LL | use foo::f;
    |
@@ -32,11 +28,8 @@ LL | use bar::g;
    |
 LL | use foo::test2::test::g;
    |
-LL | use foo::test2::test::g;
-   |
 LL | use foo::test::g;
    |
-     and 2 other candidates
 
 error[E0425]: cannot find function `f` in this scope
   --> $DIR/globs.rs:61:12
@@ -46,6 +39,9 @@ LL | n!(f);
 ...
 LL |         n!(f);
    |            ^ not found in this scope
+   |
+   = note: possible candidate is found in another module, you can import it into scope:
+           foo::f
 
 error[E0425]: cannot find function `f` in this scope
   --> $DIR/globs.rs:65:17
@@ -55,6 +51,9 @@ LL | n!(f);
 ...
 LL |                 f
    |                 ^ not found in this scope
+   |
+   = note: possible candidate is found in another module, you can import it into scope:
+           foo::f
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-58712.stderr b/src/test/ui/issues/issue-58712.stderr
index 6164ad7ee19..87c16aa993b 100644
--- a/src/test/ui/issues/issue-58712.stderr
+++ b/src/test/ui/issues/issue-58712.stderr
@@ -2,7 +2,9 @@ error[E0412]: cannot find type `DeviceId` in this scope
   --> $DIR/issue-58712.rs:6:20
    |
 LL | impl<H> AddrVec<H, DeviceId> {
-   |                    ^^^^^^^^ not found in this scope
+   |       -            ^^^^^^^^ not found in this scope
+   |       |
+   |       help: you might be missing a type parameter: `, DeviceId`
 
 error[E0412]: cannot find type `DeviceId` in this scope
   --> $DIR/issue-58712.rs:8:29
diff --git a/src/test/ui/privacy/privacy-ns1.stderr b/src/test/ui/privacy/privacy-ns1.stderr
index 45ca00f55ab..66e9b78f676 100644
--- a/src/test/ui/privacy/privacy-ns1.stderr
+++ b/src/test/ui/privacy/privacy-ns1.stderr
@@ -63,6 +63,10 @@ LL | use foo2::Bar;
    |
 LL | use foo3::Bar;
    |
+help: you might be missing a type parameter
+   |
+LL | fn test_glob3<Bar>() {
+   |              ^^^^^
 
 error[E0107]: wrong number of const arguments: expected 0, found 1
   --> $DIR/privacy-ns1.rs:35:17
diff --git a/src/test/ui/proc-macro/generate-mod.stderr b/src/test/ui/proc-macro/generate-mod.stderr
index 829d8bf4c81..fe53fb242f4 100644
--- a/src/test/ui/proc-macro/generate-mod.stderr
+++ b/src/test/ui/proc-macro/generate-mod.stderr
@@ -6,6 +6,9 @@ LL | generate_mod::check!();
    | |
    | not found in this scope
    | in this macro invocation
+   |
+   = note: possible candidate is found in another module, you can import it into scope:
+           FromOutside
 
 error[E0412]: cannot find type `Outer` in this scope
   --> $DIR/generate-mod.rs:9:1
@@ -15,18 +18,27 @@ LL | generate_mod::check!();
    | |
    | not found in this scope
    | in this macro invocation
+   |
+   = note: possible candidate is found in another module, you can import it into scope:
+           Outer
 
 error[E0412]: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:12:1
    |
 LL | #[generate_mod::check_attr]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+   |
+   = note: possible candidate is found in another module, you can import it into scope:
+           FromOutside
 
 error[E0412]: cannot find type `OuterAttr` in this scope
   --> $DIR/generate-mod.rs:12:1
    |
 LL | #[generate_mod::check_attr]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+   |
+   = note: possible candidate is found in another module, you can import it into scope:
+           OuterAttr
 
 warning: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:16:10
diff --git a/src/test/ui/suggestions/no-extern-crate-in-type.stderr b/src/test/ui/suggestions/no-extern-crate-in-type.stderr
index 22aad3b0a9f..0a73a269134 100644
--- a/src/test/ui/suggestions/no-extern-crate-in-type.stderr
+++ b/src/test/ui/suggestions/no-extern-crate-in-type.stderr
@@ -8,6 +8,10 @@ help: possible candidate is found in another module, you can import it into scop
    |
 LL | use foo::Foo;
    |
+help: you might be missing a type parameter
+   |
+LL | type Output<Foo> = Option<Foo>;
+   |            ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias/issue-62364-self-ty-arg.stderr b/src/test/ui/type-alias/issue-62364-self-ty-arg.stderr
index 5ed27760a82..cae41672ead 100644
--- a/src/test/ui/type-alias/issue-62364-self-ty-arg.stderr
+++ b/src/test/ui/type-alias/issue-62364-self-ty-arg.stderr
@@ -2,7 +2,9 @@ error[E0411]: cannot find type `Self` in this scope
   --> $DIR/issue-62364-self-ty-arg.rs:5:29
    |
 LL | type Alias<'a> = Struct<&'a Self>;
-   |                             ^^^^ `Self` is only available in impls, traits, and type definitions
+   |              -              ^^^^ `Self` is only available in impls, traits, and type definitions
+   |              |
+   |              help: you might be missing a type parameter: `, Self`
 
 error: aborting due to previous error