diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8207057fd0aa..502dcd1b7e85 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2599,6 +2599,21 @@ impl<'a> Resolver<'a> { } _ => {} }, + (Def::Enum(..), PathSource::TupleStruct) => { + if let Some(variants) = this.collect_enum_variants(def) { + err.note(&format!("did you mean to use one \ + of the following variants?\n{}", + variants.iter() + .map(|suggestion| format!("- `{}`", + path_names_to_string(suggestion))) + .collect::>() + .join("\n"))); + + } else { + err.note("did you mean to use one of the enum's variants?"); + } + return (err, candidates); + }, _ if ns == ValueNS && is_struct_like(def) => { if let Def::Struct(def_id) = def { if let Some((ctor_def, ctor_vis)) @@ -3495,6 +3510,70 @@ impl<'a> Resolver<'a> { candidates } + fn find_module(&mut self, + module_def: Def) + -> Option<(Module<'a>, ImportSuggestion)> + { + let mut result = None; + let mut worklist = Vec::new(); + let mut seen_modules = FxHashSet(); + worklist.push((self.graph_root, Vec::new())); + + while let Some((in_module, path_segments)) = worklist.pop() { + // abort if the module is already found + if let Some(_) = result { break; } + + self.populate_module_if_necessary(in_module); + + in_module.for_each_child(|ident, _, name_binding| { + // abort if the module is already found + if let Some(_) = result { + return (); + } + if let Some(module) = name_binding.module() { + // form the path + let mut path_segments = path_segments.clone(); + path_segments.push(ast::PathSegment::from_ident(ident, name_binding.span)); + if module.def() == Some(module_def) { + let path = Path { + span: name_binding.span, + segments: path_segments, + }; + result = Some((module, ImportSuggestion { path: path })); + } else { + // add the module to the lookup + if seen_modules.insert(module.def_id().unwrap()) { + worklist.push((module, path_segments)); + } + } + } + }); + } + + result + } + + fn collect_enum_variants(&mut self, enum_def: Def) -> Option> { + if let Def::Enum(..) = enum_def {} else { + panic!("Non-enum def passed to collect_enum_variants: {:?}", enum_def) + } + + self.find_module(enum_def).map(|(enum_module, enum_import_suggestion)| { + let mut variants = Vec::new(); + enum_module.for_each_child_stable(|ident, _, name_binding| { + if let Def::Variant(..) = name_binding.def() { + let mut segms = enum_import_suggestion.path.segments.clone(); + segms.push(ast::PathSegment::from_ident(ident, name_binding.span)); + variants.push(Path { + span: name_binding.span, + segments: segms, + }); + } + }); + variants + }) + } + fn record_def(&mut self, node_id: NodeId, resolution: PathResolution) { debug!("(recording def) recording {:?} for {}", resolution, node_id); if let Some(prev_res) = self.def_map.insert(node_id, resolution) {