@@ -5,6 +5,7 @@ use rustc_ast::{
5
5
self as ast, CRATE_NODE_ID , Crate , ItemKind , MetaItemInner , MetaItemKind , ModKind , NodeId , Path ,
6
6
} ;
7
7
use rustc_ast_pretty:: pprust;
8
+ use rustc_attr_data_structures:: { self as attr, Stability } ;
8
9
use rustc_data_structures:: fx:: FxHashSet ;
9
10
use rustc_data_structures:: unord:: UnordSet ;
10
11
use rustc_errors:: codes:: * ;
@@ -110,6 +111,7 @@ pub(crate) struct ImportSuggestion {
110
111
pub via_import : bool ,
111
112
/// An extra note that should be issued if this item is suggested
112
113
pub note : Option < String > ,
114
+ pub is_stable : bool ,
113
115
}
114
116
115
117
/// Adjust the impl span so that just the `impl` keyword is taken by removing
@@ -1172,13 +1174,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1172
1174
ThinVec :: <ast:: PathSegment >:: new( ) ,
1173
1175
true ,
1174
1176
start_did. is_local( ) || !self . tcx. is_doc_hidden( start_did) ,
1177
+ true ,
1175
1178
) ] ;
1176
1179
let mut worklist_via_import = vec ! [ ] ;
1177
1180
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
+ {
1182
1187
let in_module_is_extern = !in_module. def_id ( ) . is_local ( ) ;
1183
1188
in_module. for_each_child ( self , |this, ident, ns, name_binding| {
1184
1189
// Avoid non-importable candidates.
@@ -1258,6 +1263,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1258
1263
candidates. remove ( idx) ;
1259
1264
}
1260
1265
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
+
1261
1287
if candidates. iter ( ) . all ( |v : & ImportSuggestion | v. did != did) {
1262
1288
// See if we're recommending TryFrom, TryInto, or FromIterator and add
1263
1289
// a note about editions
@@ -1289,6 +1315,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1289
1315
doc_visible : child_doc_visible,
1290
1316
note,
1291
1317
via_import,
1318
+ is_stable,
1292
1319
} ) ;
1293
1320
}
1294
1321
}
@@ -1315,8 +1342,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1315
1342
if !is_extern_crate_that_also_appears_in_prelude || alias_import {
1316
1343
// add the module to the lookup
1317
1344
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
+ ) ;
1320
1354
}
1321
1355
}
1322
1356
}
@@ -1326,6 +1360,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1326
1360
candidates
1327
1361
}
1328
1362
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
+
1329
1391
/// When name resolution fails, this method can be used to look up candidate
1330
1392
/// entities with the expected name. It allows filtering them using the
1331
1393
/// supplied predicate (which should be used to only accept the types of
0 commit comments