@@ -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,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1258
1263
candidates. remove ( idx) ;
1259
1264
}
1260
1265
1266
+ let is_stable =
1267
+ is_stable && did. is_some ( ) && this. is_stable ( did. unwrap ( ) , path. span ) ;
1268
+ if is_stable
1269
+ && let Some ( idx) = candidates
1270
+ . iter ( )
1271
+ . position ( |v : & ImportSuggestion | v. did == did && !v. is_stable )
1272
+ {
1273
+ candidates. remove ( idx) ;
1274
+ }
1275
+
1261
1276
if candidates. iter ( ) . all ( |v : & ImportSuggestion | v. did != did) {
1262
1277
// See if we're recommending TryFrom, TryInto, or FromIterator and add
1263
1278
// a note about editions
@@ -1289,6 +1304,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1289
1304
doc_visible : child_doc_visible,
1290
1305
note,
1291
1306
via_import,
1307
+ is_stable,
1292
1308
} ) ;
1293
1309
}
1294
1310
}
@@ -1299,6 +1315,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1299
1315
let mut path_segments = path_segments. clone ( ) ;
1300
1316
path_segments. push ( ast:: PathSegment :: from_ident ( ident) ) ;
1301
1317
1318
+ let is_stable = is_stable && this. is_stable ( module. def_id ( ) , name_binding. span ) ;
1319
+
1302
1320
let alias_import = if let NameBindingKind :: Import { import, .. } =
1303
1321
name_binding. kind
1304
1322
&& let ImportKind :: ExternCrate { source : Some ( _) , .. } = import. kind
@@ -1315,8 +1333,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1315
1333
if !is_extern_crate_that_also_appears_in_prelude || alias_import {
1316
1334
// add the module to the lookup
1317
1335
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) ) ;
1336
+ if via_import { & mut worklist_via_import } else { & mut worklist } . push (
1337
+ (
1338
+ module,
1339
+ path_segments,
1340
+ child_accessible,
1341
+ child_doc_visible,
1342
+ is_stable,
1343
+ ) ,
1344
+ ) ;
1320
1345
}
1321
1346
}
1322
1347
}
@@ -1326,6 +1351,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1326
1351
candidates
1327
1352
}
1328
1353
1354
+ fn is_stable ( & self , did : DefId , span : Span ) -> bool {
1355
+ if did. is_local ( ) {
1356
+ return true ;
1357
+ }
1358
+
1359
+ match self . tcx . lookup_stability ( did) {
1360
+ Some ( Stability {
1361
+ level : attr:: StabilityLevel :: Unstable { implied_by, .. } ,
1362
+ feature,
1363
+ ..
1364
+ } ) => {
1365
+ if span. allows_unstable ( feature) {
1366
+ true
1367
+ } else if self . tcx . features ( ) . enabled ( feature) {
1368
+ true
1369
+ } else if let Some ( implied_by) = implied_by
1370
+ && self . tcx . features ( ) . enabled ( implied_by)
1371
+ {
1372
+ true
1373
+ } else {
1374
+ false
1375
+ }
1376
+ }
1377
+ Some ( _) => true ,
1378
+ None => false ,
1379
+ }
1380
+ }
1381
+
1329
1382
/// When name resolution fails, this method can be used to look up candidate
1330
1383
/// entities with the expected name. It allows filtering them using the
1331
1384
/// supplied predicate (which should be used to only accept the types of
0 commit comments