@@ -5,6 +5,7 @@ use rustc_ast::{
55 self as ast, CRATE_NODE_ID , Crate , ItemKind , MetaItemInner , MetaItemKind , ModKind , NodeId , Path ,
66} ;
77use rustc_ast_pretty:: pprust;
8+ use rustc_attr_data_structures:: { self as attr, Stability } ;
89use rustc_data_structures:: fx:: FxHashSet ;
910use rustc_data_structures:: unord:: UnordSet ;
1011use 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
0 commit comments