@@ -81,6 +81,8 @@ use rustc_front::hir::{ItemFn, ItemForeignMod, ItemImpl, ItemMod, ItemStatic, It
8181use  rustc_front:: hir:: { ItemStruct ,  ItemTrait ,  ItemTy ,  ItemUse } ; 
8282use  rustc_front:: hir:: Local ; 
8383use  rustc_front:: hir:: { Pat ,  PatKind ,  Path ,  PrimTy } ; 
84+ use  rustc_front:: hir:: { PathSegment ,  PathParameters } ; 
85+ use  rustc_front:: hir:: HirVec ; 
8486use  rustc_front:: hir:: { TraitRef ,  Ty ,  TyBool ,  TyChar ,  TyFloat ,  TyInt } ; 
8587use  rustc_front:: hir:: { TyRptr ,  TyStr ,  TyUint ,  TyPath ,  TyPtr } ; 
8688use  rustc_front:: util:: walk_pat; 
@@ -117,6 +119,12 @@ enum SuggestionType {
117119    NotFound , 
118120} 
119121
122+ /// Candidates for a name resolution failure 
123+ pub  struct  SuggestedCandidates  { 
124+     name :  String , 
125+     candidates :  Vec < Path > , 
126+ } 
127+ 
120128pub  enum  ResolutionError < ' a >  { 
121129    /// error E0401: can't use type parameters from outer function 
122130TypeParametersFromOuterFunction , 
@@ -127,7 +135,7 @@ pub enum ResolutionError<'a> {
127135    /// error E0404: is not a trait 
128136IsNotATrait ( & ' a  str ) , 
129137    /// error E0405: use of undeclared trait name 
130- UndeclaredTraitName ( & ' a  str ) , 
138+ UndeclaredTraitName ( & ' a  str ,   SuggestedCandidates ) , 
131139    /// error E0406: undeclared associated type 
132140UndeclaredAssociatedType , 
133141    /// error E0407: method is not a member of trait 
@@ -145,7 +153,7 @@ pub enum ResolutionError<'a> {
145153    /// error E0411: use of `Self` outside of an impl or trait 
146154SelfUsedOutsideImplOrTrait , 
147155    /// error E0412: use of undeclared 
148- UseOfUndeclared ( & ' a  str ,  & ' a  str ) , 
156+ UseOfUndeclared ( & ' a  str ,  & ' a  str ,   SuggestedCandidates ) , 
149157    /// error E0413: declaration shadows an enum variant or unit-like struct in scope 
150158DeclarationShadowsEnumVariantOrUnitLikeStruct ( Name ) , 
151159    /// error E0414: only irrefutable patterns allowed here 
@@ -248,12 +256,14 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
248256        ResolutionError :: IsNotATrait ( name)  => { 
249257            struct_span_err ! ( resolver. session,  span,  E0404 ,  "`{}` is not a trait" ,  name) 
250258        } 
251-         ResolutionError :: UndeclaredTraitName ( name)  => { 
252-             struct_span_err ! ( resolver. session, 
253-                              span, 
254-                              E0405 , 
255-                              "use of undeclared trait name `{}`" , 
256-                              name) 
259+         ResolutionError :: UndeclaredTraitName ( name,  candidates)  => { 
260+             let  mut  err = struct_span_err ! ( resolver. session, 
261+                                            span, 
262+                                            E0405 , 
263+                                            "trait `{}` is not in scope" , 
264+                                            name) ; 
265+             show_candidates ( & mut  err,  span,  & candidates) ; 
266+             err
257267        } 
258268        ResolutionError :: UndeclaredAssociatedType  => { 
259269            struct_span_err ! ( resolver. session,  span,  E0406 ,  "undeclared associated type" ) 
@@ -313,13 +323,15 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
313323                             E0411 , 
314324                             "use of `Self` outside of an impl or trait" ) 
315325        } 
316-         ResolutionError :: UseOfUndeclared ( kind,  name)  => { 
317-             struct_span_err ! ( resolver. session, 
318-                              span, 
319-                              E0412 , 
320-                              "use of undeclared {} `{}`" , 
321-                              kind, 
322-                              name) 
326+         ResolutionError :: UseOfUndeclared ( kind,  name,  candidates)  => { 
327+             let  mut  err = struct_span_err ! ( resolver. session, 
328+                                            span, 
329+                                            E0412 , 
330+                                            "{} `{}` is undefined or not in scope" , 
331+                                            kind, 
332+                                            name) ; 
333+             show_candidates ( & mut  err,  span,  & candidates) ; 
334+             err
323335        } 
324336        ResolutionError :: DeclarationShadowsEnumVariantOrUnitLikeStruct ( name)  => { 
325337            struct_span_err ! ( resolver. session, 
@@ -839,6 +851,7 @@ pub struct ModuleS<'a> {
839851pub  type  Module < ' a >  = & ' a  ModuleS < ' a > ; 
840852
841853impl < ' a >  ModuleS < ' a >  { 
854+ 
842855    fn  new ( parent_link :  ParentLink < ' a > ,  def :  Option < Def > ,  external :  bool ,  is_public :  bool )  -> Self  { 
843856        ModuleS  { 
844857            parent_link :  parent_link, 
@@ -1970,10 +1983,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
19701983                Err ( ( ) ) 
19711984            } 
19721985        }  else  { 
1973-             resolve_error ( self , 
1974-                           trait_path. span , 
1975-                           ResolutionError :: UndeclaredTraitName ( & path_names_to_string ( trait_path, 
1976-                                                                                       path_depth) ) ) ; 
1986+ 
1987+             // find possible candidates 
1988+             let  trait_name = trait_path. segments . last ( ) . unwrap ( ) . identifier . name ; 
1989+             let  candidates =
1990+                 self . lookup_candidates ( 
1991+                     trait_name, 
1992+                     TypeNS , 
1993+                     |def| match  def { 
1994+                         Def :: Trait ( _)  => true , 
1995+                         _             => false , 
1996+                     } , 
1997+                 ) ; 
1998+ 
1999+             // create error object 
2000+             let  name = & path_names_to_string ( trait_path,  path_depth) ; 
2001+             let  error =
2002+                 ResolutionError :: UndeclaredTraitName ( 
2003+                     name, 
2004+                     candidates, 
2005+                 ) ; 
2006+ 
2007+             resolve_error ( self ,  trait_path. span ,  error) ; 
19772008            Err ( ( ) ) 
19782009        } 
19792010    } 
@@ -2297,13 +2328,33 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
22972328                                          ty. span , 
22982329                                          ResolutionError :: SelfUsedOutsideImplOrTrait ) ; 
22992330                        }  else  { 
2300-                             resolve_error ( self , 
2301-                                           ty. span , 
2302-                                           ResolutionError :: UseOfUndeclared ( 
2303-                                                                     kind, 
2304-                                                                     & path_names_to_string ( path, 
2305-                                                                                            0 ) ) 
2306-                                          ) ; 
2331+                             let  segment = path. segments . last ( ) ; 
2332+                             let  segment = segment. expect ( "missing name in path" ) ; 
2333+                             let  type_name = segment. identifier . name ; 
2334+ 
2335+                             let  candidates =
2336+                                 self . lookup_candidates ( 
2337+                                     type_name, 
2338+                                     TypeNS , 
2339+                                     |def| match  def { 
2340+                                         Def :: Trait ( _)  |
2341+                                         Def :: Enum ( _)  |
2342+                                         Def :: Struct ( _)  |
2343+                                         Def :: TyAlias ( _)  => true , 
2344+                                         _               => false , 
2345+                                     } , 
2346+                                 ) ; 
2347+ 
2348+                             // create error object 
2349+                             let  name = & path_names_to_string ( path,  0 ) ; 
2350+                             let  error =
2351+                                 ResolutionError :: UseOfUndeclared ( 
2352+                                     kind, 
2353+                                     name, 
2354+                                     candidates, 
2355+                                 ) ; 
2356+ 
2357+                             resolve_error ( self ,  ty. span ,  error) ; 
23072358                        } 
23082359                    } 
23092360                } 
@@ -3458,6 +3509,99 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
34583509        found_traits
34593510    } 
34603511
3512+     /// When name resolution fails, this method can be used to look up candidate 
3513+ /// entities with the expected name. It allows filtering them using the 
3514+ /// supplied predicate (which should be used to only accept the types of 
3515+ /// definitions expected e.g. traits). The lookup spans across all crates. 
3516+ /// 
3517+ /// NOTE: The method does not look into imports, but this is not a problem, 
3518+ /// since we report the definitions (thus, the de-aliased imports). 
3519+ fn  lookup_candidates < FilterFn > ( & mut  self , 
3520+                                    lookup_name :  Name , 
3521+                                    namespace :  Namespace , 
3522+                                    filter_fn :  FilterFn )  -> SuggestedCandidates 
3523+         where  FilterFn :  Fn ( Def )  -> bool  { 
3524+ 
3525+         let  mut  lookup_results = Vec :: new ( ) ; 
3526+         let  mut  worklist = Vec :: new ( ) ; 
3527+         worklist. push ( ( self . graph_root ,  Vec :: new ( ) ,  false ) ) ; 
3528+ 
3529+         while  let  Some ( ( in_module, 
3530+                         path_segments, 
3531+                         in_module_is_extern) )  = worklist. pop ( )  { 
3532+             build_reduced_graph:: populate_module_if_necessary ( self ,  & in_module) ; 
3533+ 
3534+             in_module. for_each_child ( |name,  ns,  name_binding| { 
3535+ 
3536+                 // avoid imports entirely 
3537+                 if  name_binding. is_import ( )  {  return ;  } 
3538+ 
3539+                 // collect results based on the filter function 
3540+                 if  let  Some ( def)  = name_binding. def ( )  { 
3541+                     if  name == lookup_name && ns == namespace && filter_fn ( def)  { 
3542+                         // create the path 
3543+                         let  ident = hir:: Ident :: from_name ( name) ; 
3544+                         let  params = PathParameters :: none ( ) ; 
3545+                         let  segment = PathSegment  { 
3546+                             identifier :  ident, 
3547+                             parameters :  params, 
3548+                         } ; 
3549+                         let  span = name_binding. span . unwrap_or ( syntax:: codemap:: DUMMY_SP ) ; 
3550+                         let  mut  segms = path_segments. clone ( ) ; 
3551+                         segms. push ( segment) ; 
3552+                         let  segms = HirVec :: from_vec ( segms) ; 
3553+                         let  path = Path  { 
3554+                             span :  span, 
3555+                             global :  true , 
3556+                             segments :  segms, 
3557+                         } ; 
3558+                         // the entity is accessible in the following cases: 
3559+                         // 1. if it's defined in the same crate, it's always 
3560+                         // accessible (since private entities can be made public) 
3561+                         // 2. if it's defined in another crate, it's accessible 
3562+                         // only if both the module is public and the entity is 
3563+                         // declared as public (due to pruning, we don't explore 
3564+                         // outside crate private modules => no need to check this) 
3565+                         if  !in_module_is_extern || name_binding. is_public ( )  { 
3566+                             lookup_results. push ( path) ; 
3567+                         } 
3568+                     } 
3569+                 } 
3570+ 
3571+                 // collect submodules to explore 
3572+                 if  let  Some ( module)  = name_binding. module ( )  { 
3573+                     // form the path 
3574+                     let  path_segments = match  module. parent_link  { 
3575+                         NoParentLink  => path_segments. clone ( ) , 
3576+                         ModuleParentLink ( _,  name)  => { 
3577+                             let  mut  paths = path_segments. clone ( ) ; 
3578+                             let  ident = hir:: Ident :: from_name ( name) ; 
3579+                             let  params = PathParameters :: none ( ) ; 
3580+                             let  segm = PathSegment  { 
3581+                                 identifier :  ident, 
3582+                                 parameters :  params, 
3583+                             } ; 
3584+                             paths. push ( segm) ; 
3585+                             paths
3586+                         } 
3587+                         _ => unreachable ! ( ) , 
3588+                     } ; 
3589+ 
3590+                     if  !in_module_is_extern || name_binding. is_public ( )  { 
3591+                         // add the module to the lookup 
3592+                         let  is_extern = in_module_is_extern || module. is_extern_crate ; 
3593+                         worklist. push ( ( module,  path_segments,  is_extern) ) ; 
3594+                     } 
3595+                 } 
3596+             } ) 
3597+         } 
3598+ 
3599+         SuggestedCandidates  { 
3600+             name :  lookup_name. as_str ( ) . to_string ( ) , 
3601+             candidates :  lookup_results, 
3602+         } 
3603+     } 
3604+ 
34613605    fn  record_def ( & mut  self ,  node_id :  NodeId ,  resolution :  PathResolution )  { 
34623606        debug ! ( "(recording def) recording {:?} for {}" ,  resolution,  node_id) ; 
34633607        assert ! ( match  resolution. last_private { 
@@ -3513,6 +3657,67 @@ fn path_names_to_string(path: &Path, depth: usize) -> String {
35133657    names_to_string ( & names[ ..] ) 
35143658} 
35153659
3660+ /// When an entity with a given name is not available in scope, we search for 
3661+ /// entities with that name in all crates. This method allows outputting the 
3662+ /// results of this search in a programmer-friendly way 
3663+ fn  show_candidates ( session :  & mut  DiagnosticBuilder , 
3664+                    span :  syntax:: codemap:: Span , 
3665+                    candidates :  & SuggestedCandidates )  { 
3666+ 
3667+     let  paths = & candidates. candidates ; 
3668+ 
3669+     if  paths. len ( )  > 0  { 
3670+         // don't show more than MAX_CANDIDATES results, so 
3671+         // we're consistent with the trait suggestions 
3672+         const  MAX_CANDIDATES :  usize  = 5 ; 
3673+ 
3674+         // we want consistent results across executions, but candidates are produced 
3675+         // by iterating through a hash map, so make sure they are ordered: 
3676+         let  mut  path_strings:  Vec < _ >  = paths. into_iter ( ) 
3677+                                             . map ( |p| path_names_to_string ( & p,  0 ) ) 
3678+                                             . collect ( ) ; 
3679+         path_strings. sort ( ) ; 
3680+ 
3681+         // behave differently based on how many candidates we have: 
3682+         if  !paths. is_empty ( )  { 
3683+             if  paths. len ( )  == 1  { 
3684+                 session. fileline_help ( 
3685+                     span, 
3686+                     & format ! ( "you can to import it into scope: `use {};`." , 
3687+                         & path_strings[ 0 ] ) , 
3688+                 ) ; 
3689+             }  else  { 
3690+                 session. fileline_help ( span,  "you can import several candidates \  
3691+ ) ; 
3692+                 let  count = path_strings. len ( )  as  isize  - MAX_CANDIDATES  as  isize  + 1 ; 
3693+ 
3694+                 for  ( idx,  path_string)  in  path_strings. iter ( ) . enumerate ( )  { 
3695+                     if  idx == MAX_CANDIDATES  - 1  && count > 1  { 
3696+                         session. fileline_help ( 
3697+                             span, 
3698+                             & format ! ( "  and {} other candidates" ,  count) . to_string ( ) , 
3699+                         ) ; 
3700+                         break ; 
3701+                     }  else  { 
3702+                         session. fileline_help ( 
3703+                             span, 
3704+                             & format ! ( "  `{}`" ,  path_string) . to_string ( ) , 
3705+                         ) ; 
3706+                     } 
3707+                 } 
3708+             } 
3709+         } 
3710+     }  else  { 
3711+         // nothing found: 
3712+         session. fileline_help ( 
3713+             span, 
3714+             & format ! ( "no candidates by the name of `{}` found in your \  
3715+ \ 
3716+ ,  candidates. name. to_string( ) ) , 
3717+         ) ; 
3718+     } ; 
3719+ } 
3720+ 
35163721/// A somewhat inefficient routine to obtain the name of a module. 
35173722fn  module_to_string ( module :  Module )  -> String  { 
35183723    let  mut  names = Vec :: new ( ) ; 
0 commit comments