1111use self :: ImportDirectiveSubclass :: * ;
1212
1313use { AmbiguityError , CrateLint , Module , ModuleOrUniformRoot , PerNS } ;
14- use Namespace :: { self , TypeNS , MacroNS , ValueNS } ;
14+ use Namespace :: { self , TypeNS , MacroNS } ;
1515use { NameBinding , NameBindingKind , ToNameBinding , PathResult , PrivacyError } ;
1616use Resolver ;
1717use { names_to_string, module_to_string} ;
@@ -34,6 +34,8 @@ use syntax::util::lev_distance::find_best_match_for_name;
3434use syntax_pos:: Span ;
3535
3636use std:: cell:: { Cell , RefCell } ;
37+ use std:: collections:: BTreeMap ;
38+ use std:: fmt:: Write ;
3739use std:: { mem, ptr} ;
3840
3941/// Contains data for specific types of import directives.
@@ -615,6 +617,17 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
615617 self . finalize_resolutions_in ( module) ;
616618 }
617619
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+
618631 let mut errors = false ;
619632 let mut seen_spans = FxHashSet ( ) ;
620633 for i in 0 .. self . determined_imports . len ( ) {
@@ -624,49 +637,37 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
624637 // For a `#![feature(uniform_paths)]` `use self::x as _` canary,
625638 // failure is ignored, while success may cause an ambiguity error.
626639 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-
636640 if error. is_some ( ) {
637641 continue ;
638642 }
639643
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 =
641650 import. module_path . len ( ) > 0 &&
642651 import. module_path [ 0 ] . name == keywords:: SelfValue . name ( ) ;
643- let extern_crate_exists = self . extern_prelude . contains ( & name) ;
644652
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 ( ) ) ) ;
649656
650- errors = true ;
657+ // All the canaries with the same `id` should have the same `name`.
658+ assert_eq ! ( * prev_name, name) ;
651659
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+ }
665669 }
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+ } ) ;
670671 } else if let Some ( ( span, err) ) = error {
671672 errors = true ;
672673
@@ -694,6 +695,66 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
694695 }
695696 }
696697
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+
697758 // Report unresolved imports only if no hard error was already reported
698759 // to avoid generating multiple errors on the same import.
699760 if !errors {
0 commit comments