Skip to content

Commit 2c3b05d

Browse files
committed
Auto merge of #62669 - estebank:suggest-assoc-type, r=cramertj
Suggest assoc type on type not found in trait method definition Given ``` trait A { type Bla; fn to_bla(&self) -> Bla; } ``` suggest using `Self::Bla`: ``` error[E0412]: cannot find type `Bla` in this scope --> file.rs:3:25 | LL | fn to_bla(&self) -> Bla; | ^^^ help: try: `Self::Bla` ``` Fix #62650.
2 parents efb7457 + 6b9580b commit 2c3b05d

File tree

3 files changed

+86
-35
lines changed

3 files changed

+86
-35
lines changed

src/librustc_resolve/lib.rs

+70-35
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use syntax::ast::{CRATE_NODE_ID, Arm, IsAsync, BindingMode, Block, Crate, Expr,
5252
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
5353
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
5454
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
55-
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
55+
use syntax::ast::{QSelf, TraitItem, TraitItemKind, TraitRef, Ty, TyKind};
5656
use syntax::ptr::P;
5757
use syntax::{span_err, struct_span_err, unwrap_or, walk_list};
5858

@@ -1053,6 +1053,7 @@ impl<'a, R> Rib<'a, R> {
10531053
/// This refers to the thing referred by a name. The difference between `Res` and `Item` is that
10541054
/// items are visible in their whole block, while `Res`es only from the place they are defined
10551055
/// forward.
1056+
#[derive(Debug)]
10561057
enum LexicalScopeBinding<'a> {
10571058
Item(&'a NameBinding<'a>),
10581059
Res(Res),
@@ -1601,6 +1602,9 @@ pub struct Resolver<'a> {
16011602
/// The trait that the current context can refer to.
16021603
current_trait_ref: Option<(Module<'a>, TraitRef)>,
16031604

1605+
/// The current trait's associated types' ident, used for diagnostic suggestions.
1606+
current_trait_assoc_types: Vec<Ident>,
1607+
16041608
/// The current self type if inside an impl (used for better errors).
16051609
current_self_type: Option<Ty>,
16061610

@@ -1971,6 +1975,7 @@ impl<'a> Resolver<'a> {
19711975
label_ribs: Vec::new(),
19721976

19731977
current_trait_ref: None,
1978+
current_trait_assoc_types: Vec::new(),
19741979
current_self_type: None,
19751980
current_self_item: None,
19761981
last_import_segment: false,
@@ -2579,32 +2584,36 @@ impl<'a> Resolver<'a> {
25792584
walk_list!(this, visit_param_bound, bounds);
25802585

25812586
for trait_item in trait_items {
2582-
let generic_params = HasGenericParams(&trait_item.generics,
2583-
AssocItemRibKind);
2584-
this.with_generic_param_rib(generic_params, |this| {
2585-
match trait_item.node {
2586-
TraitItemKind::Const(ref ty, ref default) => {
2587-
this.visit_ty(ty);
2588-
2589-
// Only impose the restrictions of
2590-
// ConstRibKind for an actual constant
2591-
// expression in a provided default.
2592-
if let Some(ref expr) = *default{
2593-
this.with_constant_rib(|this| {
2594-
this.visit_expr(expr);
2595-
});
2587+
this.with_trait_items(trait_items, |this| {
2588+
let generic_params = HasGenericParams(
2589+
&trait_item.generics,
2590+
AssocItemRibKind,
2591+
);
2592+
this.with_generic_param_rib(generic_params, |this| {
2593+
match trait_item.node {
2594+
TraitItemKind::Const(ref ty, ref default) => {
2595+
this.visit_ty(ty);
2596+
2597+
// Only impose the restrictions of
2598+
// ConstRibKind for an actual constant
2599+
// expression in a provided default.
2600+
if let Some(ref expr) = *default{
2601+
this.with_constant_rib(|this| {
2602+
this.visit_expr(expr);
2603+
});
2604+
}
25962605
}
2597-
}
2598-
TraitItemKind::Method(_, _) => {
2599-
visit::walk_trait_item(this, trait_item)
2600-
}
2601-
TraitItemKind::Type(..) => {
2602-
visit::walk_trait_item(this, trait_item)
2603-
}
2604-
TraitItemKind::Macro(_) => {
2605-
panic!("unexpanded macro in resolve!")
2606-
}
2607-
};
2606+
TraitItemKind::Method(_, _) => {
2607+
visit::walk_trait_item(this, trait_item)
2608+
}
2609+
TraitItemKind::Type(..) => {
2610+
visit::walk_trait_item(this, trait_item)
2611+
}
2612+
TraitItemKind::Macro(_) => {
2613+
panic!("unexpanded macro in resolve!")
2614+
}
2615+
};
2616+
});
26082617
});
26092618
}
26102619
});
@@ -2774,6 +2783,22 @@ impl<'a> Resolver<'a> {
27742783
result
27752784
}
27762785

2786+
/// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412.
2787+
fn with_trait_items<T, F>(&mut self, trait_items: &Vec<TraitItem>, f: F) -> T
2788+
where F: FnOnce(&mut Resolver<'_>) -> T
2789+
{
2790+
let trait_assoc_types = replace(
2791+
&mut self.current_trait_assoc_types,
2792+
trait_items.iter().filter_map(|item| match &item.node {
2793+
TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident),
2794+
_ => None,
2795+
}).collect(),
2796+
);
2797+
let result = f(self);
2798+
self.current_trait_assoc_types = trait_assoc_types;
2799+
result
2800+
}
2801+
27772802
/// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`).
27782803
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
27792804
where F: FnOnce(&mut Resolver<'_>, Option<DefId>) -> T
@@ -3464,8 +3489,12 @@ impl<'a> Resolver<'a> {
34643489
}
34653490

34663491
fn self_type_is_available(&mut self, span: Span) -> bool {
3467-
let binding = self.resolve_ident_in_lexical_scope(Ident::with_empty_ctxt(kw::SelfUpper),
3468-
TypeNS, None, span);
3492+
let binding = self.resolve_ident_in_lexical_scope(
3493+
Ident::with_empty_ctxt(kw::SelfUpper),
3494+
TypeNS,
3495+
None,
3496+
span,
3497+
);
34693498
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
34703499
}
34713500

@@ -4095,13 +4124,12 @@ impl<'a> Resolver<'a> {
40954124
res
40964125
}
40974126

4098-
fn lookup_assoc_candidate<FilterFn>(&mut self,
4099-
ident: Ident,
4100-
ns: Namespace,
4101-
filter_fn: FilterFn)
4102-
-> Option<AssocSuggestion>
4103-
where FilterFn: Fn(Res) -> bool
4104-
{
4127+
fn lookup_assoc_candidate<FilterFn: Fn(Res) -> bool>(
4128+
&mut self,
4129+
ident: Ident,
4130+
ns: Namespace,
4131+
filter_fn: FilterFn,
4132+
) -> Option<AssocSuggestion> {
41054133
fn extract_node_id(t: &Ty) -> Option<NodeId> {
41064134
match t.node {
41074135
TyKind::Path(None, _) => Some(t.id),
@@ -4133,6 +4161,12 @@ impl<'a> Resolver<'a> {
41334161
}
41344162
}
41354163

4164+
for assoc_type_ident in &self.current_trait_assoc_types {
4165+
if *assoc_type_ident == ident {
4166+
return Some(AssocSuggestion::AssocItem);
4167+
}
4168+
}
4169+
41364170
// Look for associated items in the current trait.
41374171
if let Some((module, _)) = self.current_trait_ref {
41384172
if let Ok(binding) = self.resolve_ident_in_module(
@@ -4145,6 +4179,7 @@ impl<'a> Resolver<'a> {
41454179
) {
41464180
let res = binding.res();
41474181
if filter_fn(res) {
4182+
debug!("extract_node_id res not filtered");
41484183
return Some(if self.has_self.contains(&res.def_id()) {
41494184
AssocSuggestion::MethodWithSelf
41504185
} else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
trait A {
2+
type Bla;
3+
fn to_bla(&self) -> Bla;
4+
//~^ ERROR cannot find type `Bla` in this scope
5+
}
6+
7+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0412]: cannot find type `Bla` in this scope
2+
--> $DIR/assoc-type-in-method-return.rs:3:25
3+
|
4+
LL | fn to_bla(&self) -> Bla;
5+
| ^^^ help: try: `Self::Bla`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0412`.

0 commit comments

Comments
 (0)