Skip to content

Commit d37da1e

Browse files
committed
Adjusted diagnostic output so that if there is no use in a item sequence,
then we just suggest the first legal position where you could inject a use. To do this, I added `inject_use_span` field to `ModSpans`, and populate it in parser (it is the span of the first token found after inner attributes, if any). Then I rewrote the use-suggestion code to utilize it, and threw out some stuff that is now unnecessary with this in place. (I think the result is easier to understand.) Then I added a test of issue 87613.
1 parent b827952 commit d37da1e

File tree

13 files changed

+168
-66
lines changed

13 files changed

+168
-66
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2322,16 +2322,17 @@ pub enum ModKind {
23222322
Unloaded,
23232323
}
23242324

2325-
#[derive(Clone, Encodable, Decodable, Debug)]
2325+
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
23262326
pub struct ModSpans {
23272327
/// `inner_span` covers the body of the module; for a file module, its the whole file.
23282328
/// For an inline module, its the span inside the `{ ... }`, not including the curly braces.
23292329
pub inner_span: Span,
2330+
pub inject_use_span: Span,
23302331
}
23312332

23322333
impl Default for ModSpans {
23332334
fn default() -> ModSpans {
2334-
ModSpans { inner_span: Default::default() }
2335+
ModSpans { inner_span: Default::default(), inject_use_span: Default::default() }
23352336
}
23362337
}
23372338

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,8 +1009,9 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
10091009
ItemKind::Mod(unsafety, mod_kind) => {
10101010
visit_unsafety(unsafety, vis);
10111011
match mod_kind {
1012-
ModKind::Loaded(items, _inline, ModSpans { inner_span }) => {
1012+
ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => {
10131013
vis.visit_span(inner_span);
1014+
vis.visit_span(inject_use_span);
10141015
items.flat_map_in_place(|item| vis.flat_map_item(item));
10151016
}
10161017
ModKind::Unloaded => {}
@@ -1112,8 +1113,9 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
11121113
vis.visit_id(id);
11131114
visit_attrs(attrs, vis);
11141115
items.flat_map_in_place(|item| vis.flat_map_item(item));
1115-
let ModSpans { inner_span } = spans;
1116+
let ModSpans { inner_span, inject_use_span } = spans;
11161117
vis.visit_span(inner_span);
1118+
vis.visit_span(inject_use_span);
11171119
}
11181120

11191121
// Mutates one item into possibly many items.

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
263263
})
264264
}
265265
ItemKind::Mod(_, ref mod_kind) => match mod_kind {
266-
ModKind::Loaded(items, _, ModSpans { inner_span }) => {
266+
ModKind::Loaded(items, _, ModSpans { inner_span, inject_use_span: _ }) => {
267267
hir::ItemKind::Mod(self.lower_mod(items, *inner_span))
268268
}
269269
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),

compiler/rustc_builtin_macros/src/test_harness.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,8 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
129129

130130
// We don't want to recurse into anything other than mods, since
131131
// mods or tests inside of functions will break things
132-
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span })) =
133-
item.kind
134-
{
132+
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ref spans)) = item.kind {
133+
let ast::ModSpans { inner_span: span, inject_use_span: _ } = *spans;
135134
let prev_tests = mem::take(&mut self.tests);
136135
noop_visit_item_kind(&mut item.kind, self);
137136
self.add_test_cases(item.id, span, prev_tests);

compiler/rustc_parse/src/parser/item.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ impl<'a> Parser<'a> {
5555
let lo = self.token.span;
5656
let attrs = self.parse_inner_attributes()?;
5757

58+
let post_attr_lo = self.token.span;
5859
let mut items = vec![];
5960
while let Some(item) = self.parse_item(ForceCollect::No)? {
6061
items.push(item);
@@ -71,7 +72,9 @@ impl<'a> Parser<'a> {
7172
}
7273
}
7374

74-
Ok((attrs, items, ModSpans { inner_span: lo.to(self.prev_token.span) }))
75+
let inject_use_span = post_attr_lo.data().with_hi(post_attr_lo.lo());
76+
let mod_spans = ModSpans { inner_span: lo.to(self.prev_token.span), inject_use_span };
77+
Ok((attrs, items, mod_spans))
7578
}
7679
}
7780

compiler/rustc_resolve/src/lib.rs

Lines changed: 48 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ use rustc_span::{Span, DUMMY_SP};
7171
use smallvec::{smallvec, SmallVec};
7272
use std::cell::{Cell, RefCell};
7373
use std::collections::BTreeSet;
74-
use std::ops::ControlFlow;
7574
use std::{cmp, fmt, iter, mem, ptr};
7675
use tracing::debug;
7776

@@ -315,74 +314,70 @@ impl<'a> From<&'a ast::PathSegment> for Segment {
315314
}
316315
}
317316

317+
#[derive(Debug)]
318318
struct UsePlacementFinder {
319319
target_module: NodeId,
320-
span: Option<Span>,
321-
found_use: bool,
320+
first_legal_span: Option<Span>,
321+
first_use_span: Option<Span>,
322322
}
323323

324324
impl UsePlacementFinder {
325325
fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
326-
let mut finder = UsePlacementFinder { target_module, span: None, found_use: false };
327-
if let ControlFlow::Continue(..) = finder.check_mod(&krate.items, CRATE_NODE_ID) {
328-
visit::walk_crate(&mut finder, krate);
329-
}
330-
(finder.span, finder.found_use)
331-
}
332-
333-
fn check_mod(&mut self, items: &[P<ast::Item>], node_id: NodeId) -> ControlFlow<()> {
334-
if self.span.is_some() {
335-
return ControlFlow::Break(());
336-
}
337-
if node_id != self.target_module {
338-
return ControlFlow::Continue(());
339-
}
340-
// find a use statement
341-
for item in items {
342-
match item.kind {
343-
ItemKind::Use(..) => {
344-
// don't suggest placing a use before the prelude
345-
// import or other generated ones
346-
if !item.span.from_expansion() {
347-
self.span = Some(item.span.shrink_to_lo());
348-
self.found_use = true;
349-
return ControlFlow::Break(());
350-
}
351-
}
352-
// don't place use before extern crate
353-
ItemKind::ExternCrate(_) => {}
354-
// but place them before the first other item
355-
_ => {
356-
if self.span.map_or(true, |span| item.span < span)
357-
&& !item.span.from_expansion()
358-
{
359-
self.span = Some(item.span.shrink_to_lo());
360-
// don't insert between attributes and an item
361-
// find the first attribute on the item
362-
// FIXME: This is broken for active attributes.
363-
for attr in &item.attrs {
364-
if !attr.span.is_dummy()
365-
&& self.span.map_or(true, |span| attr.span < span)
366-
{
367-
self.span = Some(attr.span.shrink_to_lo());
368-
}
369-
}
370-
}
371-
}
326+
let mut finder =
327+
UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None };
328+
finder.visit_crate(krate);
329+
if let Some(use_span) = finder.first_use_span {
330+
(Some(use_span), true)
331+
} else {
332+
(finder.first_legal_span, false)
333+
}
334+
}
335+
}
336+
337+
fn is_span_suitable_for_use_injection(s: Span) -> bool {
338+
// don't suggest placing a use before the prelude
339+
// import or other generated ones
340+
!s.from_expansion()
341+
}
342+
343+
fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
344+
for item in items {
345+
if let ItemKind::Use(..) = item.kind {
346+
if is_span_suitable_for_use_injection(item.span) {
347+
return Some(item.span.shrink_to_lo());
372348
}
373349
}
374-
ControlFlow::Continue(())
375350
}
351+
return None;
376352
}
377353

378354
impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
355+
fn visit_crate(&mut self, c: &Crate) {
356+
if self.target_module == CRATE_NODE_ID {
357+
let inject = c.spans.inject_use_span;
358+
if is_span_suitable_for_use_injection(inject) {
359+
self.first_legal_span = Some(inject);
360+
}
361+
self.first_use_span = search_for_any_use_in_items(&c.items);
362+
return;
363+
} else {
364+
visit::walk_crate(self, c);
365+
}
366+
}
367+
379368
fn visit_item(&mut self, item: &'tcx ast::Item) {
380-
if let ItemKind::Mod(_, ModKind::Loaded(items, ..)) = &item.kind {
381-
if let ControlFlow::Break(..) = self.check_mod(items, item.id) {
369+
if self.target_module == item.id {
370+
if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind {
371+
let inject = mod_spans.inject_use_span;
372+
if is_span_suitable_for_use_injection(inject) {
373+
self.first_legal_span = Some(inject);
374+
}
375+
self.first_use_span = search_for_any_use_in_items(items);
382376
return;
383377
}
378+
} else {
379+
visit::walk_item(self, item);
384380
}
385-
visit::walk_item(self, item);
386381
}
387382
}
388383

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
1+
{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
1+
{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// aux-build:amputate-span.rs
2+
// edition:2018
3+
// compile-flags: --extern amputate_span
4+
5+
// This test has been crafted to ensure the following things:
6+
//
7+
// 1. There's a resolution error that prompts the compiler to suggest
8+
// adding a `use` item.
9+
//
10+
// 2. There are no `use` or `extern crate` items in the source
11+
// code. In fact, there is only one item, the `fn main`
12+
// declaration.
13+
//
14+
// 3. The single `fn main` declaration has an attribute attached to it
15+
// that just deletes the first token from the given item.
16+
//
17+
// You need all of these conditions to hold in order to replicate the
18+
// scenario that yielded issue 87613, where the compiler's suggestion
19+
// looks like:
20+
//
21+
// ```
22+
// help: consider importing this struct
23+
// |
24+
// 47 | hey */ async use std::process::Command;
25+
// | ++++++++++++++++++++++++++
26+
// ```
27+
//
28+
// The first condition is necessary to force the compiler issue a
29+
// suggestion. The second condition is necessary to force the
30+
// suggestion to be issued at a span associated with the sole
31+
// `fn`-item of this crate. The third condition is necessary in order
32+
// to yield the weird state where the associated span of the `fn`-item
33+
// does not actually cover all of the original source code of the
34+
// `fn`-item (which is why we are calling it an "amputated" span
35+
// here).
36+
//
37+
// Note that satisfying conditions 2 and 3 requires the use of the
38+
// `--extern` compile flag.
39+
//
40+
// You might ask yourself: What code would do such a thing? The
41+
// answer is: the #[tokio::main] attribute does *exactly* this (as
42+
// well as injecting some other code into the `fn main` that it
43+
// constructs).
44+
45+
#[amputate_span::drop_first_token]
46+
/* what the
47+
hey */ async fn main() {
48+
Command::new("git"); //~ ERROR [E0433]
49+
}
50+
51+
// (The /* ... */ comment in the above is not part of the original
52+
// bug. It is just meant to illustrate one particular facet of the
53+
// original non-ideal behavior, where we were transcribing the
54+
// trailing comment as part of the emitted suggestion, for better or
55+
// for worse.)
56+
57+
mod inner {
58+
#[amputate_span::drop_first_token]
59+
/* another interesting
60+
case */ async fn foo() {
61+
Command::new("git"); //~ ERROR [E0433]
62+
}
63+
}

0 commit comments

Comments
 (0)