@@ -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,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
12581263 candidates. remove ( idx) ;
12591264 }
12601265
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+
12611276 if candidates. iter ( ) . all ( |v : & ImportSuggestion | v. did != did) {
12621277 // See if we're recommending TryFrom, TryInto, or FromIterator and add
12631278 // a note about editions
@@ -1289,6 +1304,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
12891304 doc_visible : child_doc_visible,
12901305 note,
12911306 via_import,
1307+ is_stable,
12921308 } ) ;
12931309 }
12941310 }
@@ -1299,6 +1315,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
12991315 let mut path_segments = path_segments. clone ( ) ;
13001316 path_segments. push ( ast:: PathSegment :: from_ident ( ident) ) ;
13011317
1318+ let is_stable = is_stable && this. is_stable ( module. def_id ( ) , name_binding. span ) ;
1319+
13021320 let alias_import = if let NameBindingKind :: Import { import, .. } =
13031321 name_binding. kind
13041322 && let ImportKind :: ExternCrate { source : Some ( _) , .. } = import. kind
@@ -1315,8 +1333,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
13151333 if !is_extern_crate_that_also_appears_in_prelude || alias_import {
13161334 // add the module to the lookup
13171335 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+ ) ;
13201345 }
13211346 }
13221347 }
@@ -1326,6 +1351,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
13261351 candidates
13271352 }
13281353
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+
13291382 /// When name resolution fails, this method can be used to look up candidate
13301383 /// entities with the expected name. It allows filtering them using the
13311384 /// supplied predicate (which should be used to only accept the types of
0 commit comments