@@ -24,6 +24,7 @@ use syntax::attr;
24
24
use syntax:: errors:: DiagnosticBuilder ;
25
25
use syntax:: ext:: base:: { self , Determinacy , MultiModifier , MultiDecorator } ;
26
26
use syntax:: ext:: base:: { NormalTT , Resolver as SyntaxResolver , SyntaxExtension } ;
27
+ use syntax:: ext:: base:: MacroKind ;
27
28
use syntax:: ext:: expand:: { Expansion , mark_tts} ;
28
29
use syntax:: ext:: hygiene:: Mark ;
29
30
use syntax:: ext:: tt:: macro_rules;
@@ -236,8 +237,8 @@ impl<'a> base::Resolver for Resolver<'a> {
236
237
None
237
238
}
238
239
239
- fn resolve_macro ( & mut self , scope : Mark , path : & ast:: Path , force : bool )
240
- -> Result < Rc < SyntaxExtension > , Determinacy > {
240
+ fn resolve_macro ( & mut self , scope : Mark , path : & ast:: Path , kind : MacroKind ,
241
+ force : bool ) -> Result < Rc < SyntaxExtension > , Determinacy > {
241
242
let ast:: Path { ref segments, span } = * path;
242
243
if segments. iter ( ) . any ( |segment| segment. parameters . is_some ( ) ) {
243
244
let kind =
@@ -256,6 +257,7 @@ impl<'a> base::Resolver for Resolver<'a> {
256
257
let msg = "non-ident macro paths are experimental" ;
257
258
let feature = "use_extern_macros" ;
258
259
emit_feature_err ( & self . session . parse_sess , feature, span, GateIssue :: Language , msg) ;
260
+ self . found_unresolved_macro = true ;
259
261
return Err ( Determinacy :: Determined ) ;
260
262
}
261
263
@@ -266,7 +268,10 @@ impl<'a> base::Resolver for Resolver<'a> {
266
268
} ,
267
269
PathResult :: Module ( ..) => unreachable ! ( ) ,
268
270
PathResult :: Indeterminate if !force => return Err ( Determinacy :: Undetermined ) ,
269
- _ => Err ( Determinacy :: Determined ) ,
271
+ _ => {
272
+ self . found_unresolved_macro = true ;
273
+ Err ( Determinacy :: Determined )
274
+ } ,
270
275
} ;
271
276
self . current_module . macro_resolutions . borrow_mut ( )
272
277
. push ( ( path. into_boxed_slice ( ) , span) ) ;
@@ -279,40 +284,19 @@ impl<'a> base::Resolver for Resolver<'a> {
279
284
Some ( MacroBinding :: Modern ( binding) ) => Ok ( binding. get_macro ( self ) ) ,
280
285
None => match self . resolve_lexical_macro_path_segment ( path[ 0 ] , MacroNS , None ) {
281
286
Ok ( binding) => Ok ( binding. get_macro ( self ) ) ,
282
- Err ( Determinacy :: Undetermined ) if !force => return Err ( Determinacy :: Undetermined ) ,
283
- _ => {
284
- let msg = format ! ( "macro undefined: `{}`" , name) ;
285
- let mut err = self . session . struct_span_err ( span, & msg) ;
286
- self . suggest_macro_name ( & name. as_str ( ) , & mut err) ;
287
- err. emit ( ) ;
288
- return Err ( Determinacy :: Determined ) ;
289
- } ,
287
+ Err ( Determinacy :: Undetermined ) if !force =>
288
+ return Err ( Determinacy :: Undetermined ) ,
289
+ Err ( _) => {
290
+ self . found_unresolved_macro = true ;
291
+ Err ( Determinacy :: Determined )
292
+ }
290
293
} ,
291
294
} ;
292
295
293
- if self . use_extern_macros {
294
- self . current_module . legacy_macro_resolutions . borrow_mut ( ) . push ( ( scope, path[ 0 ] , span) ) ;
295
- }
296
- result
297
- }
296
+ self . current_module . legacy_macro_resolutions . borrow_mut ( )
297
+ . push ( ( scope, path[ 0 ] , span, kind) ) ;
298
298
299
- fn resolve_derive_macro ( & mut self , scope : Mark , path : & ast:: Path , force : bool )
300
- -> Result < Rc < SyntaxExtension > , Determinacy > {
301
- let ast:: Path { span, .. } = * path;
302
- match self . resolve_macro ( scope, path, false ) {
303
- Ok ( ext) => match * ext {
304
- SyntaxExtension :: BuiltinDerive ( ..) |
305
- SyntaxExtension :: ProcMacroDerive ( ..) => Ok ( ext) ,
306
- _ => Err ( Determinacy :: Determined ) ,
307
- } ,
308
- Err ( Determinacy :: Undetermined ) if force => {
309
- let msg = format ! ( "cannot find derive macro `{}` in this scope" , path) ;
310
- let mut err = self . session . struct_span_err ( span, & msg) ;
311
- err. emit ( ) ;
312
- Err ( Determinacy :: Determined )
313
- } ,
314
- Err ( err) => Err ( err) ,
315
- }
299
+ result
316
300
}
317
301
}
318
302
@@ -438,37 +422,74 @@ impl<'a> Resolver<'a> {
438
422
}
439
423
}
440
424
441
- for & ( mark, ident, span) in module. legacy_macro_resolutions . borrow ( ) . iter ( ) {
425
+ for & ( mark, ident, span, kind ) in module. legacy_macro_resolutions . borrow ( ) . iter ( ) {
442
426
let legacy_scope = & self . invocations [ & mark] . legacy_scope ;
443
427
let legacy_resolution = self . resolve_legacy_scope ( legacy_scope, ident. name , true ) ;
444
428
let resolution = self . resolve_lexical_macro_path_segment ( ident, MacroNS , Some ( span) ) ;
445
- let ( legacy_resolution, resolution) = match ( legacy_resolution, resolution) {
446
- ( Some ( legacy_resolution) , Ok ( resolution) ) => ( legacy_resolution, resolution) ,
429
+ match ( legacy_resolution, resolution) {
430
+ ( Some ( legacy_resolution) , Ok ( resolution) ) => {
431
+ let ( legacy_span, participle) = match legacy_resolution {
432
+ MacroBinding :: Modern ( binding)
433
+ if binding. def ( ) == resolution. def ( ) => continue ,
434
+ MacroBinding :: Modern ( binding) => ( binding. span , "imported" ) ,
435
+ MacroBinding :: Legacy ( binding) => ( binding. span , "defined" ) ,
436
+ } ;
437
+ let msg1 = format ! ( "`{}` could refer to the macro {} here" , ident, participle) ;
438
+ let msg2 = format ! ( "`{}` could also refer to the macro imported here" , ident) ;
439
+ self . session . struct_span_err ( span, & format ! ( "`{}` is ambiguous" , ident) )
440
+ . span_note ( legacy_span, & msg1)
441
+ . span_note ( resolution. span , & msg2)
442
+ . emit ( ) ;
443
+ } ,
447
444
( Some ( MacroBinding :: Modern ( binding) ) , Err ( _) ) => {
448
445
self . record_use ( ident, MacroNS , binding, span) ;
449
446
self . err_if_macro_use_proc_macro ( ident. name , span, binding) ;
450
- continue
451
447
} ,
452
- _ => continue ,
453
- } ;
454
- let ( legacy_span, participle) = match legacy_resolution {
455
- MacroBinding :: Modern ( binding) if binding. def ( ) == resolution. def ( ) => continue ,
456
- MacroBinding :: Modern ( binding) => ( binding. span , "imported" ) ,
457
- MacroBinding :: Legacy ( binding) => ( binding. span , "defined" ) ,
448
+ ( None , Err ( _) ) => {
449
+ let msg = match kind {
450
+ MacroKind :: Bang =>
451
+ format ! ( "cannot find macro `{}!` in this scope" , ident) ,
452
+ MacroKind :: Attr =>
453
+ format ! ( "cannot find attribute macro `{}` in this scope" , ident) ,
454
+ MacroKind :: Derive =>
455
+ format ! ( "cannot find derive macro `{}` in this scope" , ident) ,
456
+ } ;
457
+ let mut err = self . session . struct_span_err ( span, & msg) ;
458
+ self . suggest_macro_name ( & ident. name . as_str ( ) , kind, & mut err) ;
459
+ err. emit ( ) ;
460
+ } ,
461
+ _ => { } ,
458
462
} ;
459
- let msg1 = format ! ( "`{}` could refer to the macro {} here" , ident, participle) ;
460
- let msg2 = format ! ( "`{}` could also refer to the macro imported here" , ident) ;
461
- self . session . struct_span_err ( span, & format ! ( "`{}` is ambiguous" , ident) )
462
- . span_note ( legacy_span, & msg1)
463
- . span_note ( resolution. span , & msg2)
464
- . emit ( ) ;
465
463
}
466
464
}
467
465
468
- fn suggest_macro_name ( & mut self , name : & str , err : & mut DiagnosticBuilder < ' a > ) {
469
- if let Some ( suggestion) = find_best_match_for_name ( self . macro_names . iter ( ) , name, None ) {
466
+ fn suggest_macro_name ( & mut self , name : & str , kind : MacroKind ,
467
+ err : & mut DiagnosticBuilder < ' a > ) {
468
+ let suggestion = match kind {
469
+ MacroKind :: Bang =>
470
+ find_best_match_for_name ( self . macro_names . iter ( ) , name, None ) ,
471
+ MacroKind :: Attr |
472
+ MacroKind :: Derive => {
473
+ // Find a suggestion from the legacy namespace.
474
+ // FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
475
+ let builtin_macros = self . builtin_macros . clone ( ) ;
476
+ let names = builtin_macros. iter ( ) . filter_map ( |( name, binding) | {
477
+ if binding. get_macro ( self ) . kind ( ) == kind {
478
+ Some ( name)
479
+ } else {
480
+ None
481
+ }
482
+ } ) ;
483
+ find_best_match_for_name ( names, name, None )
484
+ }
485
+ } ;
486
+ if let Some ( suggestion) = suggestion {
470
487
if suggestion != name {
471
- err. help ( & format ! ( "did you mean `{}!`?" , suggestion) ) ;
488
+ if let MacroKind :: Bang = kind {
489
+ err. help ( & format ! ( "did you mean `{}!`?" , suggestion) ) ;
490
+ } else {
491
+ err. help ( & format ! ( "did you mean `{}`?" , suggestion) ) ;
492
+ }
472
493
} else {
473
494
err. help ( & format ! ( "have you added the `#[macro_use]` on the module/import?" ) ) ;
474
495
}
0 commit comments