Skip to content

Commit e2f781c

Browse files
committed
Example usage of multiple suggestions
1 parent 67d762d commit e2f781c

15 files changed

+113
-91
lines changed

src/librustc_errors/emitter.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ impl Emitter for EmitterWriter {
8181

8282
/// maximum number of lines we will print for each error; arbitrary.
8383
pub const MAX_HIGHLIGHT_LINES: usize = 6;
84+
/// maximum number of suggestions to be shown
85+
///
86+
/// Arbitrary, but taken from trait import suggestion limit
87+
pub const MAX_SUGGESTIONS: usize = 4;
8488

8589
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8690
pub enum ColorConfig {
@@ -1077,20 +1081,22 @@ impl EmitterWriter {
10771081

10781082
assert!(!lines.lines.is_empty());
10791083

1080-
for complete in suggestion.splice_lines(cm.borrow()) {
1081-
buffer.append(0, &level.to_string(), Style::Level(level.clone()));
1082-
buffer.append(0, ": ", Style::HeaderMsg);
1083-
self.msg_to_buffer(&mut buffer,
1084-
&[(suggestion.msg.to_owned(), Style::NoStyle)],
1085-
max_line_num_len,
1086-
"suggestion",
1087-
Some(Style::HeaderMsg));
1084+
buffer.append(0, &level.to_string(), Style::Level(level.clone()));
1085+
buffer.append(0, ": ", Style::HeaderMsg);
1086+
self.msg_to_buffer(&mut buffer,
1087+
&[(suggestion.msg.to_owned(), Style::NoStyle)],
1088+
max_line_num_len,
1089+
"suggestion",
1090+
Some(Style::HeaderMsg));
1091+
1092+
let suggestions = suggestion.splice_lines(cm.borrow());
1093+
let mut row_num = 1;
1094+
for complete in suggestions.iter().take(MAX_SUGGESTIONS) {
10881095

10891096
// print the suggestion without any line numbers, but leave
10901097
// space for them. This helps with lining up with previous
10911098
// snippets from the actual error being reported.
10921099
let mut lines = complete.lines();
1093-
let mut row_num = 1;
10941100
for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
10951101
draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
10961102
buffer.append(row_num, line, Style::NoStyle);
@@ -1102,6 +1108,10 @@ impl EmitterWriter {
11021108
buffer.append(row_num, "...", Style::NoStyle);
11031109
}
11041110
}
1111+
if suggestions.len() > MAX_SUGGESTIONS {
1112+
let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
1113+
buffer.append(row_num, &msg, Style::NoStyle);
1114+
}
11051115
emit_to_destination(&buffer.render(), level, &mut self.dst)?;
11061116
}
11071117
Ok(())

src/librustc_errors/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,10 @@ impl CodeSuggestion {
183183
prev_line = fm.get_line(prev_hi.line - 1);
184184
}
185185
for buf in &mut bufs {
186-
push_trailing(buf, prev_line, &prev_hi, None);
186+
// if the replacement already ends with a newline, don't print the next line
187+
if !buf.ends_with('\n') {
188+
push_trailing(buf, prev_line, &prev_hi, None);
189+
}
187190
// remove trailing newline
188191
buf.pop();
189192
}

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ impl<'a> Resolver<'a> {
150150
view_path.span,
151151
ResolutionError::SelfImportsOnlyAllowedWithin);
152152
} else if source_name == "$crate" && full_path.segments.len() == 1 {
153-
let crate_root = self.resolve_crate_var(source.ctxt);
153+
let crate_root = self.resolve_crate_var(source.ctxt, item.span);
154154
let crate_name = match crate_root.kind {
155155
ModuleKind::Def(_, name) => name,
156156
ModuleKind::Block(..) => unreachable!(),
@@ -247,7 +247,7 @@ impl<'a> Resolver<'a> {
247247

248248
// n.b. we don't need to look at the path option here, because cstore already did
249249
let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap();
250-
let module = self.get_extern_crate_root(crate_id);
250+
let module = self.get_extern_crate_root(crate_id, item.span);
251251
self.populate_module_if_necessary(module);
252252
let used = self.process_legacy_macro_imports(item, module, expansion);
253253
let binding =
@@ -279,7 +279,7 @@ impl<'a> Resolver<'a> {
279279
no_implicit_prelude: parent.no_implicit_prelude || {
280280
attr::contains_name(&item.attrs, "no_implicit_prelude")
281281
},
282-
..ModuleData::new(Some(parent), module_kind, def_id)
282+
..ModuleData::new(Some(parent), module_kind, def_id, item.span)
283283
});
284284
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
285285
self.module_map.insert(def_id, module);
@@ -314,7 +314,10 @@ impl<'a> Resolver<'a> {
314314
ItemKind::Enum(ref enum_definition, _) => {
315315
let def = Def::Enum(self.definitions.local_def_id(item.id));
316316
let module_kind = ModuleKind::Def(def, ident.name);
317-
let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
317+
let module = self.new_module(parent,
318+
module_kind,
319+
parent.normal_ancestor_id,
320+
item.span);
318321
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
319322

320323
for variant in &(*enum_definition).variants {
@@ -370,7 +373,10 @@ impl<'a> Resolver<'a> {
370373

371374
// Add all the items within to a new module.
372375
let module_kind = ModuleKind::Def(Def::Trait(def_id), ident.name);
373-
let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
376+
let module = self.new_module(parent,
377+
module_kind,
378+
parent.normal_ancestor_id,
379+
item.span);
374380
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
375381
self.current_module = module;
376382
}
@@ -419,7 +425,7 @@ impl<'a> Resolver<'a> {
419425
let parent = self.current_module;
420426
if self.block_needs_anonymous_module(block) {
421427
let module =
422-
self.new_module(parent, ModuleKind::Block(block.id), parent.normal_ancestor_id);
428+
self.new_module(parent, ModuleKind::Block(block.id), parent.normal_ancestor_id, block.span);
423429
self.block_map.insert(block.id, module);
424430
self.current_module = module; // Descend into the block.
425431
}
@@ -431,10 +437,14 @@ impl<'a> Resolver<'a> {
431437
let def = child.def;
432438
let def_id = def.def_id();
433439
let vis = self.session.cstore.visibility(def_id);
440+
let span = child.span;
434441

435442
match def {
436443
Def::Mod(..) | Def::Enum(..) => {
437-
let module = self.new_module(parent, ModuleKind::Def(def, ident.name), def_id);
444+
let module = self.new_module(parent,
445+
ModuleKind::Def(def, ident.name),
446+
def_id,
447+
span);
438448
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
439449
}
440450
Def::Variant(..) | Def::TyAlias(..) => {
@@ -454,7 +464,10 @@ impl<'a> Resolver<'a> {
454464
}
455465
Def::Trait(..) => {
456466
let module_kind = ModuleKind::Def(def, ident.name);
457-
let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
467+
let module = self.new_module(parent,
468+
module_kind,
469+
parent.normal_ancestor_id,
470+
span);
458471
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
459472

460473
for child in self.session.cstore.item_children(def_id) {
@@ -483,18 +496,18 @@ impl<'a> Resolver<'a> {
483496
}
484497
}
485498

486-
fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'a> {
499+
fn get_extern_crate_root(&mut self, cnum: CrateNum, span: Span) -> Module<'a> {
487500
let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
488501
let name = self.session.cstore.crate_name(cnum);
489502
let macros_only = self.session.cstore.dep_kind(cnum).macros_only();
490503
let module_kind = ModuleKind::Def(Def::Mod(def_id), name);
491504
let arenas = self.arenas;
492505
*self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| {
493-
arenas.alloc_module(ModuleData::new(None, module_kind, def_id))
506+
arenas.alloc_module(ModuleData::new(None, module_kind, def_id, span))
494507
})
495508
}
496509

497-
pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> {
510+
pub fn macro_def_scope(&mut self, expansion: Mark, span: Span) -> Module<'a> {
498511
let def_id = self.macro_defs[&expansion];
499512
if let Some(id) = self.definitions.as_local_node_id(def_id) {
500513
self.local_macro_def_scopes[&id]
@@ -503,7 +516,7 @@ impl<'a> Resolver<'a> {
503516
self.graph_root
504517
} else {
505518
let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap();
506-
self.get_extern_crate_root(module_def_id.krate)
519+
self.get_extern_crate_root(module_def_id.krate, span)
507520
}
508521
}
509522

src/librustc_resolve/lib.rs

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -865,12 +865,15 @@ pub struct ModuleData<'a> {
865865
// access the children must be preceded with a
866866
// `populate_module_if_necessary` call.
867867
populated: Cell<bool>,
868+
869+
/// Span of the module itself. Used for error reporting.
870+
span: Span,
868871
}
869872

870873
pub type Module<'a> = &'a ModuleData<'a>;
871874

872875
impl<'a> ModuleData<'a> {
873-
fn new(parent: Option<Module<'a>>, kind: ModuleKind, normal_ancestor_id: DefId) -> Self {
876+
fn new(parent: Option<Module<'a>>, kind: ModuleKind, normal_ancestor_id: DefId, span: Span) -> Self {
874877
ModuleData {
875878
parent: parent,
876879
kind: kind,
@@ -884,6 +887,7 @@ impl<'a> ModuleData<'a> {
884887
globs: RefCell::new((Vec::new())),
885888
traits: RefCell::new(None),
886889
populated: Cell::new(normal_ancestor_id.is_local()),
890+
span: span,
887891
}
888892
}
889893

@@ -1298,7 +1302,7 @@ impl<'a> Resolver<'a> {
12981302
let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name());
12991303
let graph_root = arenas.alloc_module(ModuleData {
13001304
no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"),
1301-
..ModuleData::new(None, root_module_kind, root_def_id)
1305+
..ModuleData::new(None, root_module_kind, root_def_id, krate.span)
13021306
});
13031307
let mut module_map = FxHashMap();
13041308
module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
@@ -1430,9 +1434,9 @@ impl<'a> Resolver<'a> {
14301434
self.crate_loader.postprocess(krate);
14311435
}
14321436

1433-
fn new_module(&self, parent: Module<'a>, kind: ModuleKind, normal_ancestor_id: DefId)
1437+
fn new_module(&self, parent: Module<'a>, kind: ModuleKind, normal_ancestor_id: DefId, span: Span)
14341438
-> Module<'a> {
1435-
self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id))
1439+
self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id, span))
14361440
}
14371441

14381442
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
@@ -1535,12 +1539,12 @@ impl<'a> Resolver<'a> {
15351539
None
15361540
}
15371541

1538-
fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext) -> Module<'a> {
1542+
fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext, span: Span) -> Module<'a> {
15391543
let mut ctxt_data = crate_var_ctxt.data();
15401544
while ctxt_data.prev_ctxt != SyntaxContext::empty() {
15411545
ctxt_data = ctxt_data.prev_ctxt.data();
15421546
}
1543-
let module = self.macro_def_scope(ctxt_data.outer_mark);
1547+
let module = self.macro_def_scope(ctxt_data.outer_mark, span);
15441548
if module.is_local() { self.graph_root } else { module }
15451549
}
15461550

@@ -2271,8 +2275,10 @@ impl<'a> Resolver<'a> {
22712275
let name = path.last().unwrap().name;
22722276
let candidates = this.lookup_import_candidates(name, ns, is_expected);
22732277
if !candidates.is_empty() {
2278+
let mut module_span = this.current_module.span;
2279+
module_span.hi = module_span.lo;
22742280
// Report import candidates as help and proceed searching for labels.
2275-
show_candidates(&mut err, &candidates, def.is_some());
2281+
show_candidates(&mut err, module_span, &candidates, def.is_some());
22762282
} else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
22772283
let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant);
22782284
let mut enum_candidates = enum_candidates.iter()
@@ -2584,7 +2590,7 @@ impl<'a> Resolver<'a> {
25842590
module = Some(self.graph_root);
25852591
continue
25862592
} else if i == 0 && ns == TypeNS && ident.name == "$crate" {
2587-
module = Some(self.resolve_crate_var(ident.ctxt));
2593+
module = Some(self.resolve_crate_var(ident.ctxt, DUMMY_SP));
25882594
continue
25892595
}
25902596

@@ -3463,12 +3469,10 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, St
34633469
/// When an entity with a given name is not available in scope, we search for
34643470
/// entities with that name in all crates. This method allows outputting the
34653471
/// results of this search in a programmer-friendly way
3466-
fn show_candidates(session: &mut DiagnosticBuilder,
3472+
fn show_candidates(err: &mut DiagnosticBuilder,
3473+
span: Span,
34673474
candidates: &[ImportSuggestion],
34683475
better: bool) {
3469-
// don't show more than MAX_CANDIDATES results, so
3470-
// we're consistent with the trait suggestions
3471-
const MAX_CANDIDATES: usize = 4;
34723476

34733477
// we want consistent results across executions, but candidates are produced
34743478
// by iterating through a hash map, so make sure they are ordered:
@@ -3481,21 +3485,13 @@ fn show_candidates(session: &mut DiagnosticBuilder,
34813485
1 => " is found in another module, you can import it",
34823486
_ => "s are found in other modules, you can import them",
34833487
};
3488+
let msg = format!("possible {}candidate{} into scope", better, msg_diff);
3489+
3490+
for candidate in &mut path_strings {
3491+
*candidate = format!("use {};\n", candidate);
3492+
}
34843493

3485-
let end = cmp::min(MAX_CANDIDATES, path_strings.len());
3486-
session.help(&format!("possible {}candidate{} into scope:{}{}",
3487-
better,
3488-
msg_diff,
3489-
&path_strings[0..end].iter().map(|candidate| {
3490-
format!("\n `use {};`", candidate)
3491-
}).collect::<String>(),
3492-
if path_strings.len() > MAX_CANDIDATES {
3493-
format!("\nand {} other candidates",
3494-
path_strings.len() - MAX_CANDIDATES)
3495-
} else {
3496-
"".to_owned()
3497-
}
3498-
));
3494+
err.span_suggestions(span, &msg, path_strings);
34993495
}
35003496

35013497
/// A somewhat inefficient routine to obtain the name of a module.

src/librustc_resolve/macros.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,14 @@ impl<'a> base::Resolver for Resolver<'a> {
123123
}
124124

125125
fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> {
126-
struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>);
126+
struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>, Span);
127127

128128
impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> {
129129
fn fold_path(&mut self, mut path: ast::Path) -> ast::Path {
130130
let ident = path.segments[0].identifier;
131131
if ident.name == "$crate" {
132132
path.segments[0].identifier.name = keywords::CrateRoot.name();
133-
let module = self.0.resolve_crate_var(ident.ctxt);
133+
let module = self.0.resolve_crate_var(ident.ctxt, self.1);
134134
if !module.is_local() {
135135
let span = path.segments[0].span;
136136
path.segments.insert(1, match module.kind {
@@ -149,7 +149,7 @@ impl<'a> base::Resolver for Resolver<'a> {
149149
}
150150
}
151151

152-
EliminateCrateVar(self).fold_item(item).expect_one("")
152+
EliminateCrateVar(self, item.span).fold_item(item).expect_one("")
153153
}
154154

155155
fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool {

src/test/ui/resolve/enums-are-namespaced-xc.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,26 @@ error[E0425]: cannot find value `A` in module `namespaced_enums`
44
15 | let _ = namespaced_enums::A;
55
| ^ not found in `namespaced_enums`
66
|
7-
= help: possible candidate is found in another module, you can import it into scope:
8-
`use namespaced_enums::Foo::A;`
7+
help: possible candidate is found in another module, you can import it into scope
8+
| use namespaced_enums::Foo::A;
99

1010
error[E0425]: cannot find function `B` in module `namespaced_enums`
1111
--> $DIR/enums-are-namespaced-xc.rs:18:31
1212
|
1313
18 | let _ = namespaced_enums::B(10);
1414
| ^ not found in `namespaced_enums`
1515
|
16-
= help: possible candidate is found in another module, you can import it into scope:
17-
`use namespaced_enums::Foo::B;`
16+
help: possible candidate is found in another module, you can import it into scope
17+
| use namespaced_enums::Foo::B;
1818

1919
error[E0422]: cannot find struct, variant or union type `C` in module `namespaced_enums`
2020
--> $DIR/enums-are-namespaced-xc.rs:21:31
2121
|
2222
21 | let _ = namespaced_enums::C { a: 10 };
2323
| ^ not found in `namespaced_enums`
2424
|
25-
= help: possible candidate is found in another module, you can import it into scope:
26-
`use namespaced_enums::Foo::C;`
25+
help: possible candidate is found in another module, you can import it into scope
26+
| use namespaced_enums::Foo::C;
2727

2828
error: aborting due to 3 previous errors
2929

src/test/ui/resolve/issue-16058.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ error[E0574]: expected struct, variant or union type, found enum `Result`
44
19 | Result {
55
| ^^^^^^ not a struct, variant or union type
66
|
7-
= help: possible better candidates are found in other modules, you can import them into scope:
8-
`use std::fmt::Result;`
9-
`use std::io::Result;`
10-
`use std::thread::Result;`
7+
help: possible better candidates are found in other modules, you can import them into scope
8+
| use std::fmt::Result;
9+
| use std::io::Result;
10+
| use std::thread::Result;
1111

1212
error: aborting due to previous error
1313

src/test/ui/resolve/issue-17518.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ error[E0422]: cannot find struct, variant or union type `E` in this scope
44
16 | E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E`
55
| ^ not found in this scope
66
|
7-
= help: possible candidate is found in another module, you can import it into scope:
8-
`use SomeEnum::E;`
7+
help: possible candidate is found in another module, you can import it into scope
8+
| use SomeEnum::E;
99

1010
error: aborting due to previous error
1111

0 commit comments

Comments
 (0)