11
11
use self :: ImportDirectiveSubclass :: * ;
12
12
13
13
use { AmbiguityError , CrateLint , Module , ModuleOrUniformRoot , PerNS } ;
14
- use Namespace :: { self , TypeNS , MacroNS , ValueNS } ;
14
+ use Namespace :: { self , TypeNS , MacroNS } ;
15
15
use { NameBinding , NameBindingKind , ToNameBinding , PathResult , PrivacyError } ;
16
16
use Resolver ;
17
17
use { names_to_string, module_to_string} ;
@@ -34,6 +34,8 @@ use syntax::util::lev_distance::find_best_match_for_name;
34
34
use syntax_pos:: Span ;
35
35
36
36
use std:: cell:: { Cell , RefCell } ;
37
+ use std:: collections:: BTreeMap ;
38
+ use std:: fmt:: Write ;
37
39
use std:: { mem, ptr} ;
38
40
39
41
/// Contains data for specific types of import directives.
@@ -615,6 +617,17 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
615
617
self . finalize_resolutions_in ( module) ;
616
618
}
617
619
620
+ #[ derive( Default ) ]
621
+ struct UniformPathsCanaryResult {
622
+ module_scope : Option < Span > ,
623
+ block_scopes : Vec < Span > ,
624
+ }
625
+ // Collect all tripped `uniform_paths` canaries separately.
626
+ let mut uniform_paths_canaries: BTreeMap <
627
+ ( Span , NodeId ) ,
628
+ ( Name , PerNS < UniformPathsCanaryResult > ) ,
629
+ > = BTreeMap :: new ( ) ;
630
+
618
631
let mut errors = false ;
619
632
let mut seen_spans = FxHashSet ( ) ;
620
633
for i in 0 .. self . determined_imports . len ( ) {
@@ -624,49 +637,37 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
624
637
// For a `#![feature(uniform_paths)]` `use self::x as _` canary,
625
638
// failure is ignored, while success may cause an ambiguity error.
626
639
if import. is_uniform_paths_canary {
627
- let ( name, result) = match import. subclass {
628
- SingleImport { source, ref result, .. } => {
629
- let type_ns = result[ TypeNS ] . get ( ) . ok ( ) ;
630
- let value_ns = result[ ValueNS ] . get ( ) . ok ( ) ;
631
- ( source. name , type_ns. or ( value_ns) )
632
- }
633
- _ => bug ! ( ) ,
634
- } ;
635
-
636
640
if error. is_some ( ) {
637
641
continue ;
638
642
}
639
643
640
- let is_explicit_self =
644
+ let ( name, result) = match import. subclass {
645
+ SingleImport { source, ref result, .. } => ( source. name , result) ,
646
+ _ => bug ! ( ) ,
647
+ } ;
648
+
649
+ let has_explicit_self =
641
650
import. module_path . len ( ) > 0 &&
642
651
import. module_path [ 0 ] . name == keywords:: SelfValue . name ( ) ;
643
- let extern_crate_exists = self . extern_prelude . contains ( & name) ;
644
652
645
- // A successful `self::x` is ambiguous with an `x` external crate.
646
- if is_explicit_self && !extern_crate_exists {
647
- continue ;
648
- }
653
+ let ( prev_name, canary_results) =
654
+ uniform_paths_canaries. entry ( ( import. span , import. id ) )
655
+ . or_insert ( ( name, PerNS :: default ( ) ) ) ;
649
656
650
- errors = true ;
657
+ // All the canaries with the same `id` should have the same `name`.
658
+ assert_eq ! ( * prev_name, name) ;
651
659
652
- let msg = format ! ( "import from `{}` is ambiguous" , name) ;
653
- let mut err = self . session . struct_span_err ( import. span , & msg) ;
654
- if extern_crate_exists {
655
- err. span_label ( import. span ,
656
- format ! ( "could refer to external crate `::{}`" , name) ) ;
657
- }
658
- if let Some ( result) = result {
659
- if is_explicit_self {
660
- err. span_label ( result. span ,
661
- format ! ( "could also refer to `self::{}`" , name) ) ;
662
- } else {
663
- err. span_label ( result. span ,
664
- format ! ( "shadowed by block-scoped `{}`" , name) ) ;
660
+ self . per_ns ( |_, ns| {
661
+ if let Some ( result) = result[ ns] . get ( ) . ok ( ) {
662
+ if has_explicit_self {
663
+ // There should only be one `self::x` (module-scoped) canary.
664
+ assert_eq ! ( canary_results[ ns] . module_scope, None ) ;
665
+ canary_results[ ns] . module_scope = Some ( result. span ) ;
666
+ } else {
667
+ canary_results[ ns] . block_scopes . push ( result. span ) ;
668
+ }
665
669
}
666
- }
667
- err. help ( & format ! ( "write `::{0}` or `self::{0}` explicitly instead" , name) ) ;
668
- err. note ( "relative `use` paths enabled by `#![feature(uniform_paths)]`" ) ;
669
- err. emit ( ) ;
670
+ } ) ;
670
671
} else if let Some ( ( span, err) ) = error {
671
672
errors = true ;
672
673
@@ -694,6 +695,66 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
694
695
}
695
696
}
696
697
698
+ for ( ( span, _) , ( name, results) ) in uniform_paths_canaries {
699
+ self . per_ns ( |this, ns| {
700
+ let results = & results[ ns] ;
701
+
702
+ let has_external_crate =
703
+ ns == TypeNS && this. extern_prelude . contains ( & name) ;
704
+
705
+ // An ambiguity requires more than one possible resolution.
706
+ let possible_resultions =
707
+ ( has_external_crate as usize ) +
708
+ ( results. module_scope . is_some ( ) as usize ) +
709
+ ( !results. block_scopes . is_empty ( ) as usize ) ;
710
+ if possible_resultions <= 1 {
711
+ return ;
712
+ }
713
+
714
+ errors = true ;
715
+
716
+ // Special-case the error when `self::x` finds its own `use x;`.
717
+ if has_external_crate &&
718
+ results. module_scope == Some ( span) &&
719
+ results. block_scopes . is_empty ( ) {
720
+ let msg = format ! ( "`{}` import is redundant" , name) ;
721
+ this. session . struct_span_err ( span, & msg)
722
+ . span_label ( span,
723
+ format ! ( "refers to external crate `::{}`" , name) )
724
+ . span_label ( span,
725
+ format ! ( "defines `self::{}`, shadowing itself" , name) )
726
+ . help ( & format ! ( "remove or write `::{}` explicitly instead" , name) )
727
+ . note ( "relative `use` paths enabled by `#![feature(uniform_paths)]`" )
728
+ . emit ( ) ;
729
+ return ;
730
+ }
731
+
732
+ let msg = format ! ( "`{}` import is ambiguous" , name) ;
733
+ let mut err = this. session . struct_span_err ( span, & msg) ;
734
+ let mut suggestion_choices = String :: new ( ) ;
735
+ if has_external_crate {
736
+ write ! ( suggestion_choices, "`::{}`" , name) ;
737
+ err. span_label ( span,
738
+ format ! ( "can refer to external crate `::{}`" , name) ) ;
739
+ }
740
+ if let Some ( span) = results. module_scope {
741
+ if !suggestion_choices. is_empty ( ) {
742
+ suggestion_choices. push_str ( " or " ) ;
743
+ }
744
+ write ! ( suggestion_choices, "`self::{}`" , name) ;
745
+ err. span_label ( span,
746
+ format ! ( "can refer to `self::{}`" , name) ) ;
747
+ }
748
+ for & span in & results. block_scopes {
749
+ err. span_label ( span,
750
+ format ! ( "shadowed by block-scoped `{}`" , name) ) ;
751
+ }
752
+ err. help ( & format ! ( "write {} explicitly instead" , suggestion_choices) ) ;
753
+ err. note ( "relative `use` paths enabled by `#![feature(uniform_paths)]`" ) ;
754
+ err. emit ( ) ;
755
+ } ) ;
756
+ }
757
+
697
758
// Report unresolved imports only if no hard error was already reported
698
759
// to avoid generating multiple errors on the same import.
699
760
if !errors {
0 commit comments