@@ -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,
@@ -1969,10 +1982,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
1969
1982
Err ( ( ) )
1970
1983
}
1971
1984
} else {
1972
- resolve_error ( self ,
1973
- trait_path. span ,
1974
- ResolutionError :: UndeclaredTraitName ( & path_names_to_string ( trait_path,
1975
- path_depth) ) ) ;
1985
+
1986
+ // find possible candidates
1987
+ let trait_name = trait_path. segments . last ( ) . unwrap ( ) . identifier . name ;
1988
+ let candidates =
1989
+ self . lookup_candidates (
1990
+ trait_name,
1991
+ TypeNS ,
1992
+ |def| match def {
1993
+ Def :: Trait ( _) => true ,
1994
+ _ => false ,
1995
+ } ,
1996
+ ) ;
1997
+
1998
+ // create error object
1999
+ let name = & path_names_to_string ( trait_path, path_depth) ;
2000
+ let error =
2001
+ ResolutionError :: UndeclaredTraitName (
2002
+ name,
2003
+ candidates,
2004
+ ) ;
2005
+
2006
+ resolve_error ( self , trait_path. span , error) ;
1976
2007
Err ( ( ) )
1977
2008
}
1978
2009
}
@@ -2296,13 +2327,33 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
2296
2327
ty. span ,
2297
2328
ResolutionError :: SelfUsedOutsideImplOrTrait ) ;
2298
2329
} else {
2299
- resolve_error ( self ,
2300
- ty. span ,
2301
- ResolutionError :: UseOfUndeclared (
2302
- kind,
2303
- & path_names_to_string ( path,
2304
- 0 ) )
2305
- ) ;
2330
+ let segment = path. segments . last ( ) ;
2331
+ let segment = segment. expect ( "missing name in path" ) ;
2332
+ let type_name = segment. identifier . name ;
2333
+
2334
+ let candidates =
2335
+ self . lookup_candidates (
2336
+ type_name,
2337
+ TypeNS ,
2338
+ |def| match def {
2339
+ Def :: Trait ( _) |
2340
+ Def :: Enum ( _) |
2341
+ Def :: Struct ( _) |
2342
+ Def :: TyAlias ( _) => true ,
2343
+ _ => false ,
2344
+ } ,
2345
+ ) ;
2346
+
2347
+ // create error object
2348
+ let name = & path_names_to_string ( path, 0 ) ;
2349
+ let error =
2350
+ ResolutionError :: UseOfUndeclared (
2351
+ kind,
2352
+ name,
2353
+ candidates,
2354
+ ) ;
2355
+
2356
+ resolve_error ( self , ty. span , error) ;
2306
2357
}
2307
2358
}
2308
2359
}
@@ -3457,6 +3508,99 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
3457
3508
found_traits
3458
3509
}
3459
3510
3511
+ /// When name resolution fails, this method can be used to look up candidate
3512
+ /// entities with the expected name. It allows filtering them using the
3513
+ /// supplied predicate (which should be used to only accept the types of
3514
+ /// definitions expected e.g. traits). The lookup spans across all crates.
3515
+ ///
3516
+ /// NOTE: The method does not look into imports, but this is not a problem,
3517
+ /// since we report the definitions (thus, the de-aliased imports).
3518
+ fn lookup_candidates < FilterFn > ( & mut self ,
3519
+ lookup_name : Name ,
3520
+ namespace : Namespace ,
3521
+ filter_fn : FilterFn ) -> SuggestedCandidates
3522
+ where FilterFn : Fn ( Def ) -> bool {
3523
+
3524
+ let mut lookup_results = Vec :: new ( ) ;
3525
+ let mut worklist = Vec :: new ( ) ;
3526
+ worklist. push ( ( self . graph_root , Vec :: new ( ) , false ) ) ;
3527
+
3528
+ while let Some ( ( in_module,
3529
+ path_segments,
3530
+ in_module_is_extern) ) = worklist. pop ( ) {
3531
+ build_reduced_graph:: populate_module_if_necessary ( self , & in_module) ;
3532
+
3533
+ in_module. for_each_child ( |name, ns, name_binding| {
3534
+
3535
+ // avoid imports entirely
3536
+ if name_binding. is_import ( ) { return ; }
3537
+
3538
+ // collect results based on the filter function
3539
+ if let Some ( def) = name_binding. def ( ) {
3540
+ if name == lookup_name && ns == namespace && filter_fn ( def) {
3541
+ // create the path
3542
+ let ident = hir:: Ident :: from_name ( name) ;
3543
+ let params = PathParameters :: none ( ) ;
3544
+ let segment = PathSegment {
3545
+ identifier : ident,
3546
+ parameters : params,
3547
+ } ;
3548
+ let span = name_binding. span . unwrap_or ( syntax:: codemap:: DUMMY_SP ) ;
3549
+ let mut segms = path_segments. clone ( ) ;
3550
+ segms. push ( segment) ;
3551
+ let segms = HirVec :: from_vec ( segms) ;
3552
+ let path = Path {
3553
+ span : span,
3554
+ global : true ,
3555
+ segments : segms,
3556
+ } ;
3557
+ // the entity is accessible in the following cases:
3558
+ // 1. if it's defined in the same crate, it's always
3559
+ // accessible (since private entities can be made public)
3560
+ // 2. if it's defined in another crate, it's accessible
3561
+ // only if both the module is public and the entity is
3562
+ // declared as public (due to pruning, we don't explore
3563
+ // outside crate private modules => no need to check this)
3564
+ if !in_module_is_extern || name_binding. is_public ( ) {
3565
+ lookup_results. push ( path) ;
3566
+ }
3567
+ }
3568
+ }
3569
+
3570
+ // collect submodules to explore
3571
+ if let Some ( module) = name_binding. module ( ) {
3572
+ // form the path
3573
+ let path_segments = match module. parent_link {
3574
+ NoParentLink => path_segments. clone ( ) ,
3575
+ ModuleParentLink ( _, name) => {
3576
+ let mut paths = path_segments. clone ( ) ;
3577
+ let ident = hir:: Ident :: from_name ( name) ;
3578
+ let params = PathParameters :: none ( ) ;
3579
+ let segm = PathSegment {
3580
+ identifier : ident,
3581
+ parameters : params,
3582
+ } ;
3583
+ paths. push ( segm) ;
3584
+ paths
3585
+ }
3586
+ _ => unreachable ! ( ) ,
3587
+ } ;
3588
+
3589
+ if !in_module_is_extern || name_binding. is_public ( ) {
3590
+ // add the module to the lookup
3591
+ let is_extern = in_module_is_extern || module. is_extern_crate ;
3592
+ worklist. push ( ( module, path_segments, is_extern) ) ;
3593
+ }
3594
+ }
3595
+ } )
3596
+ }
3597
+
3598
+ SuggestedCandidates {
3599
+ name : lookup_name. as_str ( ) . to_string ( ) ,
3600
+ candidates : lookup_results,
3601
+ }
3602
+ }
3603
+
3460
3604
fn record_def ( & mut self , node_id : NodeId , resolution : PathResolution ) {
3461
3605
debug ! ( "(recording def) recording {:?} for {}" , resolution, node_id) ;
3462
3606
assert ! ( match resolution. last_private {
@@ -3512,6 +3656,67 @@ fn path_names_to_string(path: &Path, depth: usize) -> String {
3512
3656
names_to_string ( & names[ ..] )
3513
3657
}
3514
3658
3659
+ /// When an entity with a given name is not available in scope, we search for
3660
+ /// entities with that name in all crates. This method allows outputting the
3661
+ /// results of this search in a programmer-friendly way
3662
+ fn show_candidates ( session : & mut DiagnosticBuilder ,
3663
+ span : syntax:: codemap:: Span ,
3664
+ candidates : & SuggestedCandidates ) {
3665
+
3666
+ let paths = & candidates. candidates ;
3667
+
3668
+ if paths. len ( ) > 0 {
3669
+ // don't show more than MAX_CANDIDATES results, so
3670
+ // we're consistent with the trait suggestions
3671
+ const MAX_CANDIDATES : usize = 5 ;
3672
+
3673
+ // we want consistent results across executions, but candidates are produced
3674
+ // by iterating through a hash map, so make sure they are ordered:
3675
+ let mut path_strings: Vec < _ > = paths. into_iter ( )
3676
+ . map ( |p| path_names_to_string ( & p, 0 ) )
3677
+ . collect ( ) ;
3678
+ path_strings. sort ( ) ;
3679
+
3680
+ // behave differently based on how many candidates we have:
3681
+ if !paths. is_empty ( ) {
3682
+ if paths. len ( ) == 1 {
3683
+ session. fileline_help (
3684
+ span,
3685
+ & format ! ( "you can to import it into scope: `use {};`." ,
3686
+ & path_strings[ 0 ] ) ,
3687
+ ) ;
3688
+ } else {
3689
+ session. fileline_help ( span, "you can import several candidates \
3690
+ into scope (`use ...;`):") ;
3691
+ let count = path_strings. len ( ) as isize - MAX_CANDIDATES as isize + 1 ;
3692
+
3693
+ for ( idx, path_string) in path_strings. iter ( ) . enumerate ( ) {
3694
+ if idx == MAX_CANDIDATES - 1 && count > 1 {
3695
+ session. fileline_help (
3696
+ span,
3697
+ & format ! ( " and {} other candidates" , count) . to_string ( ) ,
3698
+ ) ;
3699
+ break ;
3700
+ } else {
3701
+ session. fileline_help (
3702
+ span,
3703
+ & format ! ( " `{}`" , path_string) . to_string ( ) ,
3704
+ ) ;
3705
+ }
3706
+ }
3707
+ }
3708
+ }
3709
+ } else {
3710
+ // nothing found:
3711
+ session. fileline_help (
3712
+ span,
3713
+ & format ! ( "no candidates by the name of `{}` found in your \
3714
+ project; maybe you misspelled the name or forgot to import \
3715
+ an external crate?", candidates. name. to_string( ) ) ,
3716
+ ) ;
3717
+ } ;
3718
+ }
3719
+
3515
3720
/// A somewhat inefficient routine to obtain the name of a module.
3516
3721
fn module_to_string < ' a > ( module : Module < ' a > ) -> String {
3517
3722
let mut names = Vec :: new ( ) ;
0 commit comments