Skip to content

Commit 65c043f

Browse files
committed
Auto merge of #38154 - petrochenkov:altname, r=jseyfried
More systematic error reporting in path resolution Path resolution for types, expressions and patterns used various heuristics to give more helpful messages on unresolved or incorrectly resolved paths. This PR combines these heuristics and applies them to all non-import paths. First a path is resolved in all namespaces, starting from its primary namespace (to give messages like "expected function, found macro, you probably forgot `!`"). If this resolution doesn't give a desired result we create a base error - either "path is not resolved" or "path is resolved, but the resolution is not acceptable in this context". Other helps and notes are applied to this base error using heuristics. Here's the list of heuristics for a path with a last segment `name` in order. First we issue special messages for unresolved `Self` and `self`. Second we try to find free items named `name` in other modules and suggest to import them. Then we try to find fields and associated items named `name` and suggest `self.name` or `Self::name`. After that we try several deterministic context dependent heuristics like "expected value, found struct, you probably forgot `{}`". If nothing of the above works we try to find candidates with other names using Levenshtein distance. --- Some alternatives/notes/unresolved questions: - ~~I had a strong desire to migrate all affected tests to `test/ui`, diagnostics comparison becomes much more meaningful, but I did this only for few tests so far.~~ (Done) - ~~Labels for "unresolved path" errors are mostly useless now, it may make sense to move some help/notes to these labels, help becomes closer to the error this way.~~ (Done) - ~~Currently only the first successful heuristic results in additional message shown to the user, it may make sense to print them all, they are rarely compatible, so the diagnostics bloat is unlikely.~~ (Done) - Now when #38014 landed `resolve_path` can potentially be replaced with `smart_resolve_path` in couple more places - e.g. ~~visibilities~~ (done), ~~import prefixes~~ (done), HIR paths. --- Some additional fixes: - Associated suggestions and typo suggestions are filtered with a context specific predicate to avoid inapplicable suggestions. - `adjust_local_def` works properly in speculative resolution. - I also fixed a recently introduced ICE in partially resolved UFCS paths (see test `ufcs-partially-resolved.rs`). Minimal reproduction: ``` enum E {} fn main() { <u8 as E>::A; } ``` Fixes #38409, fixes #38504 (duplicates). - Some bugs in resolution of visibilities are fixed - `pub(Enum)`, `pub(Trait)`, `pub(non::local::path)`. - Fixes #38012. --- r? @jseyfried for technical details + @jonathandturner for diagnostics changes How to read the patch: `smart_resolve_path(_fragment)/resolve_qpath_anywhere` are written anew and replace `resolve_trait_reference`/`resolve_type`/`resolve_pattern_path`/`resolve_struct_path`/`resolve_expr` for `ExprKind::Path`, everything else can be read as a diff.
2 parents 8493dbe + 09aba18 commit 65c043f

File tree

164 files changed

+2291
-1335
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

164 files changed

+2291
-1335
lines changed

src/librustc/middle/cstore.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,7 @@ pub trait CrateStore<'tcx> {
298298

299299
// trait/impl-item info
300300
fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
301-
fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
302-
-> Option<ty::AssociatedItem>;
301+
fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>;
303302

304303
// flags
305304
fn is_const_fn(&self, did: DefId) -> bool;
@@ -456,8 +455,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
456455

457456
// trait/impl-item info
458457
fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
459-
fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
460-
-> Option<ty::AssociatedItem> { bug!("associated_item") }
458+
fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem> { bug!("associated_item") }
461459

462460
// flags
463461
fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }

src/librustc/ty/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -2071,7 +2071,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
20712071
pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
20722072
self.associated_items.memoize(def_id, || {
20732073
if !def_id.is_local() {
2074-
return self.sess.cstore.associated_item(self.global_tcx(), def_id)
2074+
return self.sess.cstore.associated_item(def_id)
20752075
.expect("missing AssociatedItem in metadata");
20762076
}
20772077

@@ -2526,8 +2526,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
25262526
/// ID of the impl that the method belongs to. Otherwise, return `None`.
25272527
pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
25282528
if def_id.krate != LOCAL_CRATE {
2529-
return self.sess.cstore.associated_item(self.global_tcx(), def_id)
2530-
.and_then(|item| {
2529+
return self.sess.cstore.associated_item(def_id).and_then(|item| {
25312530
match item.container {
25322531
TraitContainer(_) => None,
25332532
ImplContainer(def_id) => Some(def_id),

src/librustc_metadata/cstore_impl.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
188188
self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index)
189189
}
190190

191-
fn associated_item<'a>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
192-
-> Option<ty::AssociatedItem>
191+
fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>
193192
{
194193
self.dep_graph.read(DepNode::MetaData(def));
195194
self.get_crate_data(def.krate).get_associated_item(def.index)

src/librustc_resolve/build_reduced_graph.rs

+22-53
Original file line numberDiff line numberDiff line change
@@ -417,58 +417,38 @@ impl<'a> Resolver<'a> {
417417
let ident = Ident::with_empty_ctxt(child.name);
418418
let def = child.def;
419419
let def_id = def.def_id();
420-
let vis = match def {
421-
Def::Macro(..) => ty::Visibility::Public,
422-
_ if parent.is_trait() => ty::Visibility::Public,
423-
_ => self.session.cstore.visibility(def_id),
424-
};
420+
let vis = self.session.cstore.visibility(def_id);
425421

426422
match def {
427423
Def::Mod(..) | Def::Enum(..) => {
428424
let module = self.new_module(parent, ModuleKind::Def(def, ident.name), def_id);
429425
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
430426
}
431-
Def::Variant(..) => {
427+
Def::Variant(..) | Def::TyAlias(..) => {
432428
self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
433429
}
434-
Def::VariantCtor(..) => {
435-
self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
436-
}
437-
Def::Fn(..) |
438-
Def::Static(..) |
439-
Def::Const(..) |
440-
Def::AssociatedConst(..) |
441-
Def::Method(..) => {
430+
Def::Fn(..) | Def::Static(..) | Def::Const(..) |
431+
Def::VariantCtor(..) | Def::StructCtor(..) => {
442432
self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
443433
}
444434
Def::Trait(..) => {
445435
let module_kind = ModuleKind::Def(def, ident.name);
446436
let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
447437
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
448438

449-
// If this is a trait, add all the trait item names to the trait info.
450-
let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id);
451-
for trait_item_def_id in trait_item_def_ids {
452-
let trait_item_name = self.session.cstore.def_key(trait_item_def_id)
453-
.disambiguated_data.data.get_opt_name()
454-
.expect("opt_item_name returned None for trait");
455-
self.trait_item_map.insert((trait_item_name, def_id), false);
456-
}
457-
}
458-
Def::TyAlias(..) | Def::AssociatedTy(..) => {
459-
self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
460-
}
461-
Def::Struct(..) => {
462-
self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
439+
for child in self.session.cstore.item_children(def_id) {
440+
let ns = if let Def::AssociatedTy(..) = child.def { TypeNS } else { ValueNS };
441+
let ident = Ident::with_empty_ctxt(child.name);
442+
self.define(module, ident, ns, (child.def, ty::Visibility::Public,
443+
DUMMY_SP, Mark::root()));
463444

464-
// Record field names for error reporting.
465-
let field_names = self.session.cstore.struct_field_names(def_id);
466-
self.insert_field_names(def_id, field_names);
467-
}
468-
Def::StructCtor(..) => {
469-
self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
445+
let has_self = self.session.cstore.associated_item(child.def.def_id())
446+
.map_or(false, |item| item.method_has_self_argument);
447+
self.trait_item_map.insert((def_id, child.name, ns), (child.def, has_self));
448+
}
449+
module.populated.set(true);
470450
}
471-
Def::Union(..) => {
451+
Def::Struct(..) | Def::Union(..) => {
472452
self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
473453

474454
// Record field names for error reporting.
@@ -478,15 +458,7 @@ impl<'a> Resolver<'a> {
478458
Def::Macro(..) => {
479459
self.define(parent, ident, MacroNS, (def, vis, DUMMY_SP, Mark::root()));
480460
}
481-
Def::Local(..) |
482-
Def::PrimTy(..) |
483-
Def::TyParam(..) |
484-
Def::Upvar(..) |
485-
Def::Label(..) |
486-
Def::SelfTy(..) |
487-
Def::Err => {
488-
bug!("unexpected definition: {:?}", def);
489-
}
461+
_ => bug!("unexpected definition: {:?}", def)
490462
}
491463
}
492464

@@ -751,18 +723,15 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
751723

752724
// Add the item to the trait info.
753725
let item_def_id = self.resolver.definitions.local_def_id(item.id);
754-
let mut is_static_method = false;
755-
let (def, ns) = match item.node {
756-
TraitItemKind::Const(..) => (Def::AssociatedConst(item_def_id), ValueNS),
757-
TraitItemKind::Method(ref sig, _) => {
758-
is_static_method = !sig.decl.has_self();
759-
(Def::Method(item_def_id), ValueNS)
760-
}
761-
TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS),
726+
let (def, ns, has_self) = match item.node {
727+
TraitItemKind::Const(..) => (Def::AssociatedConst(item_def_id), ValueNS, false),
728+
TraitItemKind::Method(ref sig, _) =>
729+
(Def::Method(item_def_id), ValueNS, sig.decl.has_self()),
730+
TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS, false),
762731
TraitItemKind::Macro(_) => bug!(), // handled above
763732
};
764733

765-
self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method);
734+
self.resolver.trait_item_map.insert((def_id, item.ident.name, ns), (def, has_self));
766735

767736
let vis = ty::Visibility::Public;
768737
self.resolver.define(parent, item.ident, ns, (def, vis, item.span, self.expansion));

src/librustc_resolve/diagnostics.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,26 @@ match (A, B, C) {
860860
```
861861
"##,
862862

863+
E0422: r##"
864+
You are trying to use an identifier that is either undefined or not a struct.
865+
Erroneous code example:
866+
``` compile_fail,E0422
867+
fn main () {
868+
let x = Foo { x: 1, y: 2 };
869+
}
870+
```
871+
In this case, `Foo` is undefined, so it inherently isn't anything, and
872+
definitely not a struct.
873+
```compile_fail
874+
fn main () {
875+
let foo = 1;
876+
let x = foo { x: 1, y: 2 };
877+
}
878+
```
879+
In this case, `foo` is defined, but is not a struct, so Rust can't use it as
880+
one.
881+
"##,
882+
863883
E0423: r##"
864884
A `struct` variant name was used like a function name.
865885
@@ -1519,7 +1539,12 @@ register_diagnostics! {
15191539
// E0419, merged into 531
15201540
// E0420, merged into 532
15211541
// E0421, merged into 531
1522-
// E0422, merged into 531/532
15231542
E0531, // unresolved pattern path kind `name`
15241543
// E0427, merged into 530
1544+
E0573,
1545+
E0574,
1546+
E0575,
1547+
E0576,
1548+
E0577,
1549+
E0578,
15251550
}

0 commit comments

Comments
 (0)