@@ -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,24 @@ 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
+ if is_stable
1276
+ // Remove unstable match if exists
1277
+ && let Some ( idx) = candidates
1278
+ . iter ( )
1279
+ . position ( |v : & ImportSuggestion | v. did == did && !v. is_stable )
1280
+ {
1281
+ candidates. remove ( idx) ;
1282
+ }
1283
+
1261
1284
if candidates. iter ( ) . all ( |v : & ImportSuggestion | v. did != did) {
1262
1285
// See if we're recommending TryFrom, TryInto, or FromIterator and add
1263
1286
// a note about editions
@@ -1289,6 +1312,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1289
1312
doc_visible : child_doc_visible,
1290
1313
note,
1291
1314
via_import,
1315
+ is_stable,
1292
1316
} ) ;
1293
1317
}
1294
1318
}
@@ -1315,8 +1339,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1315
1339
if !is_extern_crate_that_also_appears_in_prelude || alias_import {
1316
1340
// add the module to the lookup
1317
1341
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) ) ;
1342
+ if via_import { & mut worklist_via_import } else { & mut worklist } . push (
1343
+ (
1344
+ module,
1345
+ path_segments,
1346
+ child_accessible,
1347
+ child_doc_visible,
1348
+ is_stable && this. is_stable ( module. def_id ( ) , name_binding. span ) ,
1349
+ ) ,
1350
+ ) ;
1320
1351
}
1321
1352
}
1322
1353
}
@@ -1326,6 +1357,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1326
1357
candidates
1327
1358
}
1328
1359
1360
+ fn is_stable ( & self , did : DefId , span : Span ) -> bool {
1361
+ if did. is_local ( ) {
1362
+ return true ;
1363
+ }
1364
+
1365
+ match self . tcx . lookup_stability ( did) {
1366
+ Some ( Stability {
1367
+ level : attr:: StabilityLevel :: Unstable { implied_by, .. } ,
1368
+ feature,
1369
+ ..
1370
+ } ) => {
1371
+ if span. allows_unstable ( feature) {
1372
+ true
1373
+ } else if self . tcx . features ( ) . enabled ( feature) {
1374
+ true
1375
+ } else if let Some ( implied_by) = implied_by
1376
+ && self . tcx . features ( ) . enabled ( implied_by)
1377
+ {
1378
+ true
1379
+ } else {
1380
+ false
1381
+ }
1382
+ }
1383
+ Some ( _) => true ,
1384
+ None => false ,
1385
+ }
1386
+ }
1387
+
1329
1388
/// When name resolution fails, this method can be used to look up candidate
1330
1389
/// entities with the expected name. It allows filtering them using the
1331
1390
/// supplied predicate (which should be used to only accept the types of
0 commit comments