Skip to content

Commit 320ada6

Browse files
committed
Auto merge of #68447 - estebank:sugg-type-param, r=petrochenkov
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.
2 parents c3681d6 + 697fdc5 commit 320ada6

File tree

12 files changed

+178
-66
lines changed

12 files changed

+178
-66
lines changed

src/librustc_resolve/diagnostics.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1415,11 +1415,15 @@ crate fn show_candidates(
14151415
better: bool,
14161416
found_use: bool,
14171417
) {
1418+
if candidates.is_empty() {
1419+
return;
1420+
}
14181421
// we want consistent results across executions, but candidates are produced
14191422
// by iterating through a hash map, so make sure they are ordered:
14201423
let mut path_strings: Vec<_> =
14211424
candidates.into_iter().map(|c| path_names_to_string(&c.path)).collect();
14221425
path_strings.sort();
1426+
path_strings.dedup();
14231427

14241428
let better = if better { "better " } else { "" };
14251429
let msg_diff = match path_strings.len() {
@@ -1444,6 +1448,7 @@ crate fn show_candidates(
14441448
msg.push('\n');
14451449
msg.push_str(&candidate);
14461450
}
1451+
err.note(&msg);
14471452
}
14481453
}
14491454

src/librustc_resolve/late.rs

+61-49
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ impl<'a> PathSource<'a> {
323323
}
324324

325325
#[derive(Default)]
326-
struct DiagnosticMetadata {
326+
struct DiagnosticMetadata<'ast> {
327327
/// The current trait's associated types' ident, used for diagnostic suggestions.
328328
current_trait_assoc_types: Vec<Ident>,
329329

@@ -333,6 +333,13 @@ struct DiagnosticMetadata {
333333
/// The current self item if inside an ADT (used for better errors).
334334
current_self_item: Option<NodeId>,
335335

336+
/// The current trait (used to suggest).
337+
current_item: Option<&'ast Item>,
338+
339+
/// When processing generics and encountering a type not found, suggest introducing a type
340+
/// param.
341+
currently_processing_generics: bool,
342+
336343
/// The current enclosing function (used for better errors).
337344
current_function: Option<Span>,
338345

@@ -347,7 +354,7 @@ struct DiagnosticMetadata {
347354
current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
348355
}
349356

350-
struct LateResolutionVisitor<'a, 'b> {
357+
struct LateResolutionVisitor<'a, 'b, 'ast> {
351358
r: &'b mut Resolver<'a>,
352359

353360
/// The module that represents the current item scope.
@@ -364,30 +371,32 @@ struct LateResolutionVisitor<'a, 'b> {
364371
current_trait_ref: Option<(Module<'a>, TraitRef)>,
365372

366373
/// Fields used to add information to diagnostic errors.
367-
diagnostic_metadata: DiagnosticMetadata,
374+
diagnostic_metadata: DiagnosticMetadata<'ast>,
368375
}
369376

370377
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
371-
impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
372-
fn visit_item(&mut self, item: &'tcx Item) {
378+
impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
379+
fn visit_item(&mut self, item: &'ast Item) {
380+
let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
373381
self.resolve_item(item);
382+
self.diagnostic_metadata.current_item = prev;
374383
}
375-
fn visit_arm(&mut self, arm: &'tcx Arm) {
384+
fn visit_arm(&mut self, arm: &'ast Arm) {
376385
self.resolve_arm(arm);
377386
}
378-
fn visit_block(&mut self, block: &'tcx Block) {
387+
fn visit_block(&mut self, block: &'ast Block) {
379388
self.resolve_block(block);
380389
}
381-
fn visit_anon_const(&mut self, constant: &'tcx AnonConst) {
390+
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
382391
debug!("visit_anon_const {:?}", constant);
383392
self.with_constant_rib(|this| {
384393
visit::walk_anon_const(this, constant);
385394
});
386395
}
387-
fn visit_expr(&mut self, expr: &'tcx Expr) {
396+
fn visit_expr(&mut self, expr: &'ast Expr) {
388397
self.resolve_expr(expr, None);
389398
}
390-
fn visit_local(&mut self, local: &'tcx Local) {
399+
fn visit_local(&mut self, local: &'ast Local) {
391400
let local_spans = match local.pat.kind {
392401
// We check for this to avoid tuple struct fields.
393402
PatKind::Wild => None,
@@ -401,7 +410,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
401410
self.resolve_local(local);
402411
self.diagnostic_metadata.current_let_binding = original;
403412
}
404-
fn visit_ty(&mut self, ty: &'tcx Ty) {
413+
fn visit_ty(&mut self, ty: &'ast Ty) {
405414
match ty.kind {
406415
TyKind::Path(ref qself, ref path) => {
407416
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
@@ -417,7 +426,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
417426
}
418427
visit::walk_ty(self, ty);
419428
}
420-
fn visit_poly_trait_ref(&mut self, tref: &'tcx PolyTraitRef, m: &'tcx TraitBoundModifier) {
429+
fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
421430
self.smart_resolve_path(
422431
tref.trait_ref.ref_id,
423432
None,
@@ -426,7 +435,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
426435
);
427436
visit::walk_poly_trait_ref(self, tref, m);
428437
}
429-
fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) {
438+
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
430439
match foreign_item.kind {
431440
ForeignItemKind::Fn(_, ref generics) => {
432441
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
@@ -443,7 +452,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
443452
}
444453
}
445454
}
446-
fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, sp: Span, _: NodeId) {
455+
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, declaration: &'ast FnDecl, sp: Span, _: NodeId) {
447456
let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp));
448457
debug!("(resolving function) entering function");
449458
let rib_kind = match fn_kind {
@@ -472,7 +481,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
472481
self.diagnostic_metadata.current_function = previous_value;
473482
}
474483

475-
fn visit_generics(&mut self, generics: &'tcx Generics) {
484+
fn visit_generics(&mut self, generics: &'ast Generics) {
476485
// For type parameter defaults, we have to ban access
477486
// to following type parameters, as the InternalSubsts can only
478487
// provide previous type parameters as they're built. We
@@ -534,11 +543,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
534543
}
535544
}
536545

537-
fn visit_generic_arg(&mut self, arg: &'tcx GenericArg) {
546+
fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
538547
debug!("visit_generic_arg({:?})", arg);
548+
let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true);
539549
match arg {
540550
GenericArg::Type(ref ty) => {
541-
// We parse const arguments as path types as we cannot distiguish them durring
551+
// We parse const arguments as path types as we cannot distiguish them during
542552
// parsing. We try to resolve that ambiguity by attempting resolution the type
543553
// namespace first, and if that fails we try again in the value namespace. If
544554
// 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, '_> {
556566
)
557567
.is_some()
558568
};
559-
560569
if !check_ns(TypeNS) && check_ns(ValueNS) {
561570
// This must be equivalent to `visit_anon_const`, but we cannot call it
562571
// 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, '_> {
574583
this.visit_path(path, ty.id);
575584
});
576585

586+
self.diagnostic_metadata.currently_processing_generics = prev;
577587
return;
578588
}
579589
}
@@ -584,11 +594,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
584594
GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
585595
GenericArg::Const(ct) => self.visit_anon_const(ct),
586596
}
597+
self.diagnostic_metadata.currently_processing_generics = prev;
587598
}
588599
}
589600

590-
impl<'a, 'b> LateResolutionVisitor<'a, '_> {
591-
fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b> {
601+
impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
602+
fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> {
592603
// During late resolution we only track the module component of the parent scope,
593604
// although it may be useful to track other components as well for diagnostics.
594605
let graph_root = resolver.graph_root;
@@ -724,7 +735,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
724735
None
725736
}
726737

727-
fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
738+
fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
728739
debug!("resolve_adt");
729740
self.with_current_self_item(item, |this| {
730741
this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
@@ -778,7 +789,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
778789
}
779790
}
780791

781-
fn resolve_item(&mut self, item: &Item) {
792+
fn resolve_item(&mut self, item: &'ast Item) {
782793
let name = item.ident.name;
783794
debug!("(resolving item) resolving {} ({:?})", name, item.kind);
784795

@@ -1024,16 +1035,15 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
10241035
let mut new_id = None;
10251036
if let Some(trait_ref) = opt_trait_ref {
10261037
let path: Vec<_> = Segment::from_path(&trait_ref.path);
1027-
let res = self
1028-
.smart_resolve_path_fragment(
1029-
trait_ref.ref_id,
1030-
None,
1031-
&path,
1032-
trait_ref.path.span,
1033-
PathSource::Trait(AliasPossibility::No),
1034-
CrateLint::SimplePath(trait_ref.ref_id),
1035-
)
1036-
.base_res();
1038+
let res = self.smart_resolve_path_fragment(
1039+
trait_ref.ref_id,
1040+
None,
1041+
&path,
1042+
trait_ref.path.span,
1043+
PathSource::Trait(AliasPossibility::No),
1044+
CrateLint::SimplePath(trait_ref.ref_id),
1045+
);
1046+
let res = res.base_res();
10371047
if res != Res::Err {
10381048
new_id = Some(res.def_id());
10391049
let span = trait_ref.path.span;
@@ -1070,11 +1080,11 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
10701080

10711081
fn resolve_implementation(
10721082
&mut self,
1073-
generics: &Generics,
1074-
opt_trait_reference: &Option<TraitRef>,
1075-
self_type: &Ty,
1083+
generics: &'ast Generics,
1084+
opt_trait_reference: &'ast Option<TraitRef>,
1085+
self_type: &'ast Ty,
10761086
item_id: NodeId,
1077-
impl_items: &[AssocItem],
1087+
impl_items: &'ast [AssocItem],
10781088
) {
10791089
debug!("resolve_implementation");
10801090
// If applicable, create a rib for the type parameters.
@@ -1179,7 +1189,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
11791189
}
11801190
}
11811191

1182-
fn resolve_params(&mut self, params: &[Param]) {
1192+
fn resolve_params(&mut self, params: &'ast [Param]) {
11831193
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
11841194
for Param { pat, ty, .. } in params {
11851195
self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
@@ -1188,7 +1198,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
11881198
}
11891199
}
11901200

1191-
fn resolve_local(&mut self, local: &Local) {
1201+
fn resolve_local(&mut self, local: &'ast Local) {
11921202
// Resolve the type.
11931203
walk_list!(self, visit_ty, &local.ty);
11941204

@@ -1307,7 +1317,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
13071317
}
13081318

13091319
/// Check the consistency of the outermost or-patterns.
1310-
fn check_consistent_bindings_top(&mut self, pat: &Pat) {
1320+
fn check_consistent_bindings_top(&mut self, pat: &'ast Pat) {
13111321
pat.walk(&mut |pat| match pat.kind {
13121322
PatKind::Or(ref ps) => {
13131323
self.check_consistent_bindings(ps);
@@ -1317,7 +1327,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
13171327
})
13181328
}
13191329

1320-
fn resolve_arm(&mut self, arm: &Arm) {
1330+
fn resolve_arm(&mut self, arm: &'ast Arm) {
13211331
self.with_rib(ValueNS, NormalRibKind, |this| {
13221332
this.resolve_pattern_top(&arm.pat, PatternSource::Match);
13231333
walk_list!(this, visit_expr, &arm.guard);
@@ -1326,14 +1336,14 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
13261336
}
13271337

13281338
/// Arising from `source`, resolve a top level pattern.
1329-
fn resolve_pattern_top(&mut self, pat: &Pat, pat_src: PatternSource) {
1339+
fn resolve_pattern_top(&mut self, pat: &'ast Pat, pat_src: PatternSource) {
13301340
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
13311341
self.resolve_pattern(pat, pat_src, &mut bindings);
13321342
}
13331343

13341344
fn resolve_pattern(
13351345
&mut self,
1336-
pat: &Pat,
1346+
pat: &'ast Pat,
13371347
pat_src: PatternSource,
13381348
bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>,
13391349
) {
@@ -1544,7 +1554,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
15441554
id: NodeId,
15451555
qself: Option<&QSelf>,
15461556
path: &Path,
1547-
source: PathSource<'_>,
1557+
source: PathSource<'ast>,
15481558
) {
15491559
self.smart_resolve_path_fragment(
15501560
id,
@@ -1562,7 +1572,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
15621572
qself: Option<&QSelf>,
15631573
path: &[Segment],
15641574
span: Span,
1565-
source: PathSource<'_>,
1575+
source: PathSource<'ast>,
15661576
crate_lint: CrateLint,
15671577
) -> PartialRes {
15681578
let ns = source.namespace();
@@ -1573,7 +1583,9 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
15731583
let def_id = this.parent_scope.module.normal_ancestor_id;
15741584
let node_id = this.r.definitions.as_local_node_id(def_id).unwrap();
15751585
let better = res.is_some();
1576-
this.r.use_injections.push(UseError { err, candidates, node_id, better });
1586+
let suggestion =
1587+
if res.is_none() { this.report_missing_type_error(path) } else { None };
1588+
this.r.use_injections.push(UseError { err, candidates, node_id, better, suggestion });
15771589
PartialRes::new(Res::Err)
15781590
};
15791591

@@ -1838,11 +1850,11 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
18381850
}
18391851
}
18401852

1841-
fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &Block) {
1853+
fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &'ast Block) {
18421854
self.with_resolved_label(label, id, |this| this.visit_block(block));
18431855
}
18441856

1845-
fn resolve_block(&mut self, block: &Block) {
1857+
fn resolve_block(&mut self, block: &'ast Block) {
18461858
debug!("(resolving block) entering block");
18471859
// Move down in the graph, if there's an anonymous module rooted here.
18481860
let orig_module = self.parent_scope.module;
@@ -1885,7 +1897,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
18851897
debug!("(resolving block) leaving block");
18861898
}
18871899

1888-
fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
1900+
fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
18891901
// First, record candidate traits for this expression if it could
18901902
// result in the invocation of a method call.
18911903

@@ -2023,7 +2035,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
20232035
}
20242036
}
20252037

2026-
fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
2038+
fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &'ast Expr) {
20272039
match expr.kind {
20282040
ExprKind::Field(_, ident) => {
20292041
// FIXME(#6890): Even though you can't treat a method like a

0 commit comments

Comments
 (0)