mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Suggest assoc type on type not found in trait method definition
This commit is contained in:
parent
69656fa4cb
commit
6b9580b651
@ -52,7 +52,7 @@ use syntax::ast::{CRATE_NODE_ID, Arm, IsAsync, BindingMode, Block, Crate, Expr,
|
|||||||
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
|
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
|
||||||
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
|
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
|
||||||
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
|
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
|
||||||
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
|
use syntax::ast::{QSelf, TraitItem, TraitItemKind, TraitRef, Ty, TyKind};
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
use syntax::{span_err, struct_span_err, unwrap_or, walk_list};
|
use syntax::{span_err, struct_span_err, unwrap_or, walk_list};
|
||||||
|
|
||||||
@ -1053,6 +1053,7 @@ impl<'a, R> Rib<'a, R> {
|
|||||||
/// This refers to the thing referred by a name. The difference between `Res` and `Item` is that
|
/// This refers to the thing referred by a name. The difference between `Res` and `Item` is that
|
||||||
/// items are visible in their whole block, while `Res`es only from the place they are defined
|
/// items are visible in their whole block, while `Res`es only from the place they are defined
|
||||||
/// forward.
|
/// forward.
|
||||||
|
#[derive(Debug)]
|
||||||
enum LexicalScopeBinding<'a> {
|
enum LexicalScopeBinding<'a> {
|
||||||
Item(&'a NameBinding<'a>),
|
Item(&'a NameBinding<'a>),
|
||||||
Res(Res),
|
Res(Res),
|
||||||
@ -1601,6 +1602,9 @@ pub struct Resolver<'a> {
|
|||||||
/// The trait that the current context can refer to.
|
/// The trait that the current context can refer to.
|
||||||
current_trait_ref: Option<(Module<'a>, TraitRef)>,
|
current_trait_ref: Option<(Module<'a>, TraitRef)>,
|
||||||
|
|
||||||
|
/// The current trait's associated types' ident, used for diagnostic suggestions.
|
||||||
|
current_trait_assoc_types: Vec<Ident>,
|
||||||
|
|
||||||
/// The current self type if inside an impl (used for better errors).
|
/// The current self type if inside an impl (used for better errors).
|
||||||
current_self_type: Option<Ty>,
|
current_self_type: Option<Ty>,
|
||||||
|
|
||||||
@ -1971,6 +1975,7 @@ impl<'a> Resolver<'a> {
|
|||||||
label_ribs: Vec::new(),
|
label_ribs: Vec::new(),
|
||||||
|
|
||||||
current_trait_ref: None,
|
current_trait_ref: None,
|
||||||
|
current_trait_assoc_types: Vec::new(),
|
||||||
current_self_type: None,
|
current_self_type: None,
|
||||||
current_self_item: None,
|
current_self_item: None,
|
||||||
last_import_segment: false,
|
last_import_segment: false,
|
||||||
@ -2579,32 +2584,36 @@ impl<'a> Resolver<'a> {
|
|||||||
walk_list!(this, visit_param_bound, bounds);
|
walk_list!(this, visit_param_bound, bounds);
|
||||||
|
|
||||||
for trait_item in trait_items {
|
for trait_item in trait_items {
|
||||||
let generic_params = HasGenericParams(&trait_item.generics,
|
this.with_trait_items(trait_items, |this| {
|
||||||
AssocItemRibKind);
|
let generic_params = HasGenericParams(
|
||||||
this.with_generic_param_rib(generic_params, |this| {
|
&trait_item.generics,
|
||||||
match trait_item.node {
|
AssocItemRibKind,
|
||||||
TraitItemKind::Const(ref ty, ref default) => {
|
);
|
||||||
this.visit_ty(ty);
|
this.with_generic_param_rib(generic_params, |this| {
|
||||||
|
match trait_item.node {
|
||||||
|
TraitItemKind::Const(ref ty, ref default) => {
|
||||||
|
this.visit_ty(ty);
|
||||||
|
|
||||||
// Only impose the restrictions of
|
// Only impose the restrictions of
|
||||||
// ConstRibKind for an actual constant
|
// ConstRibKind for an actual constant
|
||||||
// expression in a provided default.
|
// expression in a provided default.
|
||||||
if let Some(ref expr) = *default{
|
if let Some(ref expr) = *default{
|
||||||
this.with_constant_rib(|this| {
|
this.with_constant_rib(|this| {
|
||||||
this.visit_expr(expr);
|
this.visit_expr(expr);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
TraitItemKind::Method(_, _) => {
|
||||||
TraitItemKind::Method(_, _) => {
|
visit::walk_trait_item(this, trait_item)
|
||||||
visit::walk_trait_item(this, trait_item)
|
}
|
||||||
}
|
TraitItemKind::Type(..) => {
|
||||||
TraitItemKind::Type(..) => {
|
visit::walk_trait_item(this, trait_item)
|
||||||
visit::walk_trait_item(this, trait_item)
|
}
|
||||||
}
|
TraitItemKind::Macro(_) => {
|
||||||
TraitItemKind::Macro(_) => {
|
panic!("unexpanded macro in resolve!")
|
||||||
panic!("unexpanded macro in resolve!")
|
}
|
||||||
}
|
};
|
||||||
};
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -2774,6 +2783,22 @@ impl<'a> Resolver<'a> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412.
|
||||||
|
fn with_trait_items<T, F>(&mut self, trait_items: &Vec<TraitItem>, f: F) -> T
|
||||||
|
where F: FnOnce(&mut Resolver<'_>) -> T
|
||||||
|
{
|
||||||
|
let trait_assoc_types = replace(
|
||||||
|
&mut self.current_trait_assoc_types,
|
||||||
|
trait_items.iter().filter_map(|item| match &item.node {
|
||||||
|
TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident),
|
||||||
|
_ => None,
|
||||||
|
}).collect(),
|
||||||
|
);
|
||||||
|
let result = f(self);
|
||||||
|
self.current_trait_assoc_types = trait_assoc_types;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
/// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`).
|
/// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`).
|
||||||
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
|
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
|
||||||
where F: FnOnce(&mut Resolver<'_>, Option<DefId>) -> T
|
where F: FnOnce(&mut Resolver<'_>, Option<DefId>) -> T
|
||||||
@ -3464,8 +3489,12 @@ impl<'a> Resolver<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn self_type_is_available(&mut self, span: Span) -> bool {
|
fn self_type_is_available(&mut self, span: Span) -> bool {
|
||||||
let binding = self.resolve_ident_in_lexical_scope(Ident::with_empty_ctxt(kw::SelfUpper),
|
let binding = self.resolve_ident_in_lexical_scope(
|
||||||
TypeNS, None, span);
|
Ident::with_empty_ctxt(kw::SelfUpper),
|
||||||
|
TypeNS,
|
||||||
|
None,
|
||||||
|
span,
|
||||||
|
);
|
||||||
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
|
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4095,13 +4124,12 @@ impl<'a> Resolver<'a> {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_assoc_candidate<FilterFn>(&mut self,
|
fn lookup_assoc_candidate<FilterFn: Fn(Res) -> bool>(
|
||||||
ident: Ident,
|
&mut self,
|
||||||
ns: Namespace,
|
ident: Ident,
|
||||||
filter_fn: FilterFn)
|
ns: Namespace,
|
||||||
-> Option<AssocSuggestion>
|
filter_fn: FilterFn,
|
||||||
where FilterFn: Fn(Res) -> bool
|
) -> Option<AssocSuggestion> {
|
||||||
{
|
|
||||||
fn extract_node_id(t: &Ty) -> Option<NodeId> {
|
fn extract_node_id(t: &Ty) -> Option<NodeId> {
|
||||||
match t.node {
|
match t.node {
|
||||||
TyKind::Path(None, _) => Some(t.id),
|
TyKind::Path(None, _) => Some(t.id),
|
||||||
@ -4133,6 +4161,12 @@ impl<'a> Resolver<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for assoc_type_ident in &self.current_trait_assoc_types {
|
||||||
|
if *assoc_type_ident == ident {
|
||||||
|
return Some(AssocSuggestion::AssocItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Look for associated items in the current trait.
|
// Look for associated items in the current trait.
|
||||||
if let Some((module, _)) = self.current_trait_ref {
|
if let Some((module, _)) = self.current_trait_ref {
|
||||||
if let Ok(binding) = self.resolve_ident_in_module(
|
if let Ok(binding) = self.resolve_ident_in_module(
|
||||||
@ -4145,6 +4179,7 @@ impl<'a> Resolver<'a> {
|
|||||||
) {
|
) {
|
||||||
let res = binding.res();
|
let res = binding.res();
|
||||||
if filter_fn(res) {
|
if filter_fn(res) {
|
||||||
|
debug!("extract_node_id res not filtered");
|
||||||
return Some(if self.has_self.contains(&res.def_id()) {
|
return Some(if self.has_self.contains(&res.def_id()) {
|
||||||
AssocSuggestion::MethodWithSelf
|
AssocSuggestion::MethodWithSelf
|
||||||
} else {
|
} else {
|
||||||
|
7
src/test/ui/suggestions/assoc-type-in-method-return.rs
Normal file
7
src/test/ui/suggestions/assoc-type-in-method-return.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
trait A {
|
||||||
|
type Bla;
|
||||||
|
fn to_bla(&self) -> Bla;
|
||||||
|
//~^ ERROR cannot find type `Bla` in this scope
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,9 @@
|
|||||||
|
error[E0412]: cannot find type `Bla` in this scope
|
||||||
|
--> $DIR/assoc-type-in-method-return.rs:3:25
|
||||||
|
|
|
||||||
|
LL | fn to_bla(&self) -> Bla;
|
||||||
|
| ^^^ help: try: `Self::Bla`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0412`.
|
Loading…
Reference in New Issue
Block a user