@@ -113,16 +113,24 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
113
113
}
114
114
}
115
115
116
- fn build_reduced_graph_for_use_tree ( & mut self ,
117
- root_use_tree : & ast:: UseTree ,
118
- root_id : NodeId ,
119
- use_tree : & ast:: UseTree ,
120
- id : NodeId ,
121
- vis : ty:: Visibility ,
122
- prefix : & ast:: Path ,
123
- nested : bool ,
124
- item : & Item ,
125
- expansion : Mark ) {
116
+ fn build_reduced_graph_for_use_tree (
117
+ & mut self ,
118
+ root_use_tree : & ast:: UseTree ,
119
+ root_id : NodeId ,
120
+ use_tree : & ast:: UseTree ,
121
+ id : NodeId ,
122
+ vis : ty:: Visibility ,
123
+ prefix : & ast:: Path ,
124
+ mut uniform_paths_canary_emitted : bool ,
125
+ nested : bool ,
126
+ item : & Item ,
127
+ expansion : Mark ,
128
+ ) {
129
+ debug ! ( "build_reduced_graph_for_use_tree(prefix={:?}, \
130
+ uniform_paths_canary_emitted={}, \
131
+ use_tree={:?}, nested={})",
132
+ prefix, uniform_paths_canary_emitted, use_tree, nested) ;
133
+
126
134
let is_prelude = attr:: contains_name ( & item. attrs , "prelude_import" ) ;
127
135
let path = & use_tree. prefix ;
128
136
@@ -131,6 +139,71 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
131
139
. map ( |seg| seg. ident )
132
140
. collect ( ) ;
133
141
142
+ debug ! ( "build_reduced_graph_for_use_tree: module_path={:?}" , module_path) ;
143
+
144
+ // `#[feature(uniform_paths)]` allows an unqualified import path,
145
+ // e.g. `use x::...;` to resolve not just globally (`use ::x::...;`)
146
+ // but also relatively (`use self::x::...;`). To catch ambiguities
147
+ // that might arise from both of these being available and resolution
148
+ // silently picking one of them, an artificial `use self::x as _;`
149
+ // import is injected as a "canary", and an error is emitted if it
150
+ // successfully resolves while an `x` external crate exists.
151
+ //
152
+ // Additionally, the canary might be able to catch limitations of the
153
+ // current implementation, where `::x` may be chosen due to `self::x`
154
+ // not existing, but `self::x` could appear later, from macro expansion.
155
+ //
156
+ // NB. The canary currently only errors if the `x::...` path *could*
157
+ // resolve as a relative path through the extern crate, i.e. `x` is
158
+ // in `extern_prelude`, *even though* `::x` might still forcefully
159
+ // load a non-`extern_prelude` crate.
160
+ // While always producing an ambiguity errors if `self::x` exists and
161
+ // a crate *could* be loaded, would be more conservative, imports for
162
+ // local modules named `test` (or less commonly, `syntax` or `log`),
163
+ // would need to be qualified (e.g. `self::test`), which is considered
164
+ // ergonomically unacceptable.
165
+ let emit_uniform_paths_canary =
166
+ !uniform_paths_canary_emitted &&
167
+ module_path. get ( 0 ) . map_or ( false , |ident| {
168
+ !ident. is_path_segment_keyword ( )
169
+ } ) ;
170
+ if emit_uniform_paths_canary {
171
+ // Relative paths should only get here if the feature-gate is on.
172
+ assert ! ( self . session. rust_2018( ) &&
173
+ self . session. features_untracked( ) . uniform_paths) ;
174
+
175
+ let source = module_path[ 0 ] ;
176
+ let subclass = SingleImport {
177
+ target : Ident {
178
+ name : keywords:: Underscore . name ( ) . gensymed ( ) ,
179
+ span : source. span ,
180
+ } ,
181
+ source,
182
+ result : PerNS {
183
+ type_ns : Cell :: new ( Err ( Undetermined ) ) ,
184
+ value_ns : Cell :: new ( Err ( Undetermined ) ) ,
185
+ macro_ns : Cell :: new ( Err ( Undetermined ) ) ,
186
+ } ,
187
+ type_ns_only : false ,
188
+ } ;
189
+ self . add_import_directive (
190
+ vec ! [ Ident {
191
+ name: keywords:: SelfValue . name( ) ,
192
+ span: source. span,
193
+ } ] ,
194
+ subclass,
195
+ source. span ,
196
+ id,
197
+ root_use_tree. span ,
198
+ root_id,
199
+ ty:: Visibility :: Invisible ,
200
+ expansion,
201
+ true , // is_uniform_paths_canary
202
+ ) ;
203
+
204
+ uniform_paths_canary_emitted = true ;
205
+ }
206
+
134
207
match use_tree. kind {
135
208
ast:: UseTreeKind :: Simple ( rename, ..) => {
136
209
let mut ident = use_tree. ident ( ) ;
@@ -223,6 +296,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
223
296
root_id,
224
297
vis,
225
298
expansion,
299
+ false , // is_uniform_paths_canary
226
300
) ;
227
301
}
228
302
ast:: UseTreeKind :: Glob => {
@@ -239,6 +313,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
239
313
root_id,
240
314
vis,
241
315
expansion,
316
+ false , // is_uniform_paths_canary
242
317
) ;
243
318
}
244
319
ast:: UseTreeKind :: Nested ( ref items) => {
@@ -273,7 +348,16 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
273
348
274
349
for & ( ref tree, id) in items {
275
350
self . build_reduced_graph_for_use_tree (
276
- root_use_tree, root_id, tree, id, vis, & prefix, true , item, expansion
351
+ root_use_tree,
352
+ root_id,
353
+ tree,
354
+ id,
355
+ vis,
356
+ & prefix,
357
+ uniform_paths_canary_emitted,
358
+ true ,
359
+ item,
360
+ expansion,
277
361
) ;
278
362
}
279
363
}
@@ -305,7 +389,16 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
305
389
} ;
306
390
307
391
self . build_reduced_graph_for_use_tree (
308
- use_tree, item. id , use_tree, item. id , vis, & prefix, false , item, expansion,
392
+ use_tree,
393
+ item. id ,
394
+ use_tree,
395
+ item. id ,
396
+ vis,
397
+ & prefix,
398
+ false , // uniform_paths_canary_emitted
399
+ false ,
400
+ item,
401
+ expansion,
309
402
) ;
310
403
}
311
404
@@ -333,6 +426,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
333
426
vis : Cell :: new ( vis) ,
334
427
expansion,
335
428
used : Cell :: new ( used) ,
429
+ is_uniform_paths_canary : false ,
336
430
} ) ;
337
431
self . potentially_unused_imports . push ( directive) ;
338
432
let imported_binding = self . import ( binding, directive) ;
@@ -735,6 +829,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
735
829
vis : Cell :: new ( ty:: Visibility :: Restricted ( DefId :: local ( CRATE_DEF_INDEX ) ) ) ,
736
830
expansion,
737
831
used : Cell :: new ( false ) ,
832
+ is_uniform_paths_canary : false ,
738
833
} ) ;
739
834
740
835
if let Some ( span) = legacy_imports. import_all {
0 commit comments