Skip to content

Commit 7c253ac

Browse files
committed
Suggest stable candidates rather than unstable ones
1 parent 7e552b4 commit 7c253ac

File tree

6 files changed

+94
-6
lines changed

6 files changed

+94
-6
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4330,6 +4330,7 @@ dependencies = [
43304330
"rustc_arena",
43314331
"rustc_ast",
43324332
"rustc_ast_pretty",
4333+
"rustc_attr_data_structures",
43334334
"rustc_attr_parsing",
43344335
"rustc_data_structures",
43354336
"rustc_errors",

compiler/rustc_resolve/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pulldown-cmark = { version = "0.11", features = ["html"], default-features = fal
1111
rustc_arena = { path = "../rustc_arena" }
1212
rustc_ast = { path = "../rustc_ast" }
1313
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
14+
rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
1415
rustc_attr_parsing = { path = "../rustc_attr_parsing" }
1516
rustc_data_structures = { path = "../rustc_data_structures" }
1617
rustc_errors = { path = "../rustc_errors" }

compiler/rustc_resolve/src/diagnostics.rs

+68-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_ast::{
55
self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path,
66
};
77
use rustc_ast_pretty::pprust;
8+
use rustc_attr_data_structures::{self as attr, Stability};
89
use rustc_data_structures::fx::FxHashSet;
910
use rustc_data_structures::unord::UnordSet;
1011
use rustc_errors::codes::*;
@@ -110,6 +111,7 @@ pub(crate) struct ImportSuggestion {
110111
pub via_import: bool,
111112
/// An extra note that should be issued if this item is suggested
112113
pub note: Option<String>,
114+
pub is_stable: bool,
113115
}
114116

115117
/// Adjust the impl span so that just the `impl` keyword is taken by removing
@@ -1172,13 +1174,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
11721174
ThinVec::<ast::PathSegment>::new(),
11731175
true,
11741176
start_did.is_local() || !self.tcx.is_doc_hidden(start_did),
1177+
true,
11751178
)];
11761179
let mut worklist_via_import = vec![];
11771180

1178-
while let Some((in_module, path_segments, accessible, doc_visible)) = match worklist.pop() {
1179-
None => worklist_via_import.pop(),
1180-
Some(x) => Some(x),
1181-
} {
1181+
while let Some((in_module, path_segments, accessible, doc_visible, is_stable)) =
1182+
match worklist.pop() {
1183+
None => worklist_via_import.pop(),
1184+
Some(x) => Some(x),
1185+
}
1186+
{
11821187
let in_module_is_extern = !in_module.def_id().is_local();
11831188
in_module.for_each_child(self, |this, ident, ns, name_binding| {
11841189
// Avoid non-importable candidates.
@@ -1258,6 +1263,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
12581263
candidates.remove(idx);
12591264
}
12601265

1266+
let is_stable = if is_stable
1267+
&& let Some(did) = did
1268+
&& this.is_stable(did, path.span)
1269+
{
1270+
true
1271+
} else {
1272+
false
1273+
};
1274+
1275+
// Rreplace unstable suggestions if we meet a new stable one,
1276+
// and do nothing if any other situation. For example, if we
1277+
// meet `std::ops::Range` after `std::range::legacy::Range`,
1278+
// we will remove the latter and then insert the former.
1279+
if is_stable
1280+
&& let Some(idx) = candidates
1281+
.iter()
1282+
.position(|v: &ImportSuggestion| v.did == did && !v.is_stable)
1283+
{
1284+
candidates.remove(idx);
1285+
}
1286+
12611287
if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
12621288
// See if we're recommending TryFrom, TryInto, or FromIterator and add
12631289
// a note about editions
@@ -1289,6 +1315,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
12891315
doc_visible: child_doc_visible,
12901316
note,
12911317
via_import,
1318+
is_stable,
12921319
});
12931320
}
12941321
}
@@ -1315,8 +1342,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
13151342
if !is_extern_crate_that_also_appears_in_prelude || alias_import {
13161343
// add the module to the lookup
13171344
if seen_modules.insert(module.def_id()) {
1318-
if via_import { &mut worklist_via_import } else { &mut worklist }
1319-
.push((module, path_segments, child_accessible, child_doc_visible));
1345+
if via_import { &mut worklist_via_import } else { &mut worklist }.push(
1346+
(
1347+
module,
1348+
path_segments,
1349+
child_accessible,
1350+
child_doc_visible,
1351+
is_stable && this.is_stable(module.def_id(), name_binding.span),
1352+
),
1353+
);
13201354
}
13211355
}
13221356
}
@@ -1326,6 +1360,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
13261360
candidates
13271361
}
13281362

1363+
fn is_stable(&self, did: DefId, span: Span) -> bool {
1364+
if did.is_local() {
1365+
return true;
1366+
}
1367+
1368+
match self.tcx.lookup_stability(did) {
1369+
Some(Stability {
1370+
level: attr::StabilityLevel::Unstable { implied_by, .. },
1371+
feature,
1372+
..
1373+
}) => {
1374+
if span.allows_unstable(feature) {
1375+
true
1376+
} else if self.tcx.features().enabled(feature) {
1377+
true
1378+
} else if let Some(implied_by) = implied_by
1379+
&& self.tcx.features().enabled(implied_by)
1380+
{
1381+
true
1382+
} else {
1383+
false
1384+
}
1385+
}
1386+
Some(_) => true,
1387+
None => false,
1388+
}
1389+
}
1390+
13291391
/// When name resolution fails, this method can be used to look up candidate
13301392
/// entities with the expected name. It allows filtering them using the
13311393
/// supplied predicate (which should be used to only accept the types of

compiler/rustc_resolve/src/late/diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2501,6 +2501,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
25012501
doc_visible,
25022502
note: None,
25032503
via_import: false,
2504+
is_stable: true,
25042505
},
25052506
));
25062507
} else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
const _: Range = 0..1; //~ ERROR cannot find type `Range` in this scope
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0412]: cannot find type `Range` in this scope
2+
--> $DIR/sugg-stable-import-first-issue-140240.rs:2:14
3+
|
4+
LL | const _: Range = 0..1;
5+
| ^^^^^ not found in this scope
6+
|
7+
help: consider importing one of these structs
8+
|
9+
LL + use std::collections::btree_map::Range;
10+
|
11+
LL + use std::collections::btree_set::Range;
12+
|
13+
LL + use std::ops::Range;
14+
|
15+
LL + use std::range::Range;
16+
|
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0412`.

0 commit comments

Comments
 (0)