@@ -81,6 +81,8 @@ use rustc_front::hir::{ItemFn, ItemForeignMod, ItemImpl, ItemMod, ItemStatic, It
81
81
use rustc_front:: hir:: { ItemStruct , ItemTrait , ItemTy , ItemUse } ;
82
82
use rustc_front:: hir:: Local ;
83
83
use rustc_front:: hir:: { Pat , PatKind , Path , PrimTy } ;
84
+ use rustc_front:: hir:: { PathSegment , PathParameters } ;
85
+ use rustc_front:: hir:: HirVec ;
84
86
use rustc_front:: hir:: { TraitRef , Ty , TyBool , TyChar , TyFloat , TyInt } ;
85
87
use rustc_front:: hir:: { TyRptr , TyStr , TyUint , TyPath , TyPtr } ;
86
88
use rustc_front:: util:: walk_pat;
@@ -117,6 +119,12 @@ enum SuggestionType {
117
119
NotFound ,
118
120
}
119
121
122
+ /// Candidates for a name resolution failure
123
+ pub struct SuggestedCandidates {
124
+ name : String ,
125
+ candidates : Vec < Path > ,
126
+ }
127
+
120
128
pub enum ResolutionError < ' a > {
121
129
/// error E0401: can't use type parameters from outer function
122
130
TypeParametersFromOuterFunction ,
@@ -127,7 +135,7 @@ pub enum ResolutionError<'a> {
127
135
/// error E0404: is not a trait
128
136
IsNotATrait ( & ' a str ) ,
129
137
/// error E0405: use of undeclared trait name
130
- UndeclaredTraitName ( & ' a str ) ,
138
+ UndeclaredTraitName ( & ' a str , SuggestedCandidates ) ,
131
139
/// error E0406: undeclared associated type
132
140
UndeclaredAssociatedType ,
133
141
/// error E0407: method is not a member of trait
@@ -145,7 +153,7 @@ pub enum ResolutionError<'a> {
145
153
/// error E0411: use of `Self` outside of an impl or trait
146
154
SelfUsedOutsideImplOrTrait ,
147
155
/// error E0412: use of undeclared
148
- UseOfUndeclared ( & ' a str , & ' a str ) ,
156
+ UseOfUndeclared ( & ' a str , & ' a str , SuggestedCandidates ) ,
149
157
/// error E0413: declaration shadows an enum variant or unit-like struct in scope
150
158
DeclarationShadowsEnumVariantOrUnitLikeStruct ( Name ) ,
151
159
/// 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>,
248
256
ResolutionError :: IsNotATrait ( name) => {
249
257
struct_span_err ! ( resolver. session, span, E0404 , "`{}` is not a trait" , name)
250
258
}
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
257
267
}
258
268
ResolutionError :: UndeclaredAssociatedType => {
259
269
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>,
313
323
E0411 ,
314
324
"use of `Self` outside of an impl or trait" )
315
325
}
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
323
335
}
324
336
ResolutionError :: DeclarationShadowsEnumVariantOrUnitLikeStruct ( name) => {
325
337
struct_span_err ! ( resolver. session,
@@ -839,6 +851,7 @@ pub struct ModuleS<'a> {
839
851
pub type Module < ' a > = & ' a ModuleS < ' a > ;
840
852
841
853
impl < ' a > ModuleS < ' a > {
854
+
842
855
fn new ( parent_link : ParentLink < ' a > , def : Option < Def > , external : bool , is_public : bool ) -> Self {
843
856
ModuleS {
844
857
parent_link : parent_link,
@@ -1970,10 +1983,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
1970
1983
Err ( ( ) )
1971
1984
}
1972
1985
} 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) ;
1977
2008
Err ( ( ) )
1978
2009
}
1979
2010
}
@@ -2297,13 +2328,33 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
2297
2328
ty. span ,
2298
2329
ResolutionError :: SelfUsedOutsideImplOrTrait ) ;
2299
2330
} 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) ;
2307
2358
}
2308
2359
}
2309
2360
}
@@ -3458,6 +3509,99 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
3458
3509
found_traits
3459
3510
}
3460
3511
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
+
3461
3605
fn record_def ( & mut self , node_id : NodeId , resolution : PathResolution ) {
3462
3606
debug ! ( "(recording def) recording {:?} for {}" , resolution, node_id) ;
3463
3607
assert ! ( match resolution. last_private {
@@ -3513,6 +3657,67 @@ fn path_names_to_string(path: &Path, depth: usize) -> String {
3513
3657
names_to_string ( & names[ ..] )
3514
3658
}
3515
3659
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
+ into scope (`use ...;`):") ;
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
+ project; maybe you misspelled the name or forgot to import \
3716
+ an external crate?", candidates. name. to_string( ) ) ,
3717
+ ) ;
3718
+ } ;
3719
+ }
3720
+
3516
3721
/// A somewhat inefficient routine to obtain the name of a module.
3517
3722
fn module_to_string ( module : Module ) -> String {
3518
3723
let mut names = Vec :: new ( ) ;
0 commit comments