Skip to content

Commit ed9a09d

Browse files
committed
Support paths in macro invocations.
1 parent 29791ad commit ed9a09d

File tree

4 files changed

+116
-53
lines changed

4 files changed

+116
-53
lines changed

src/librustc_resolve/lib.rs

+20-7
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,7 @@ pub struct ModuleS<'a> {
783783

784784
resolutions: RefCell<FxHashMap<(Name, Namespace), &'a RefCell<NameResolution<'a>>>>,
785785
legacy_macro_resolutions: RefCell<Vec<(Mark, Name, Span)>>,
786+
macro_resolutions: RefCell<Vec<(Box<[Ident]>, PathScope, Span)>>,
786787

787788
// Macro invocations that can expand into items in this module.
788789
unresolved_invocations: RefCell<FxHashSet<Mark>>,
@@ -811,6 +812,7 @@ impl<'a> ModuleS<'a> {
811812
normal_ancestor_id: None,
812813
resolutions: RefCell::new(FxHashMap()),
813814
legacy_macro_resolutions: RefCell::new(Vec::new()),
815+
macro_resolutions: RefCell::new(Vec::new()),
814816
unresolved_invocations: RefCell::new(FxHashSet()),
815817
no_implicit_prelude: false,
816818
glob_importers: RefCell::new(Vec::new()),
@@ -1316,6 +1318,7 @@ impl<'a> Resolver<'a> {
13161318
pub fn resolve_crate(&mut self, krate: &Crate) {
13171319
ImportResolver { resolver: self }.finalize_imports();
13181320
self.current_module = self.graph_root;
1321+
self.finalize_current_module_macro_resolutions();
13191322
visit::walk_crate(self, krate);
13201323

13211324
check_unused::check_crate(self, krate);
@@ -2359,10 +2362,13 @@ impl<'a> Resolver<'a> {
23592362

23602363
let binding = if let Some(module) = module {
23612364
self.resolve_name_in_module(module, ident.name, ns, false, record_used)
2365+
} else if opt_ns == Some(MacroNS) {
2366+
self.resolve_lexical_macro_path_segment(ident.name, ns, record_used)
23622367
} else {
23632368
match self.resolve_ident_in_lexical_scope(ident, ns, record_used) {
23642369
Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
2365-
Some(LexicalScopeBinding::Def(def)) if opt_ns.is_some() => {
2370+
Some(LexicalScopeBinding::Def(def))
2371+
if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => {
23662372
return PathResult::NonModule(PathResolution {
23672373
base_def: def,
23682374
depth: path.len() - 1,
@@ -2378,7 +2384,7 @@ impl<'a> Resolver<'a> {
23782384
module = Some(next_module);
23792385
} else if binding.def() == Def::Err {
23802386
return PathResult::NonModule(err_path_resolution());
2381-
} else if opt_ns.is_some() {
2387+
} else if opt_ns.is_some() && !(opt_ns == Some(MacroNS) && !is_last) {
23822388
return PathResult::NonModule(PathResolution {
23832389
base_def: binding.def(),
23842390
depth: path.len() - i - 1,
@@ -3059,15 +3065,22 @@ impl<'a> Resolver<'a> {
30593065

30603066
for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors {
30613067
if !reported_spans.insert(span) { continue }
3062-
let msg1 = format!("`{}` could resolve to the name imported here", name);
3063-
let msg2 = format!("`{}` could also resolve to the name imported here", name);
3068+
let participle = |binding: &NameBinding| {
3069+
if binding.is_import() { "imported" } else { "defined" }
3070+
};
3071+
let msg1 = format!("`{}` could resolve to the name {} here", name, participle(b1));
3072+
let msg2 = format!("`{}` could also resolve to the name {} here", name, participle(b2));
30643073
self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
30653074
.span_note(b1.span, &msg1)
30663075
.span_note(b2.span, &msg2)
3067-
.note(&if lexical || !b1.is_glob_import() {
3068-
"macro-expanded macro imports do not shadow".to_owned()
3069-
} else {
3076+
.note(&if !lexical && b1.is_glob_import() {
30703077
format!("consider adding an explicit import of `{}` to disambiguate", name)
3078+
} else if let Def::Macro(..) = b1.def() {
3079+
format!("macro-expanded {} do not shadow",
3080+
if b1.is_import() { "macro imports" } else { "macros" })
3081+
} else {
3082+
format!("macro-expanded {} do not shadow when used in a macro invocation path",
3083+
if b1.is_import() { "imports" } else { "items" })
30713084
})
30723085
.emit();
30733086
}

src/librustc_resolve/macros.rs

+79-39
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use {Module, ModuleKind, NameBinding, NameBindingKind, Resolver, AmbiguityError};
11+
use {AmbiguityError, Resolver, ResolutionError, resolve_error};
12+
use {Module, ModuleKind, NameBinding, NameBindingKind, PathScope, PathResult};
1213
use Namespace::{self, MacroNS};
1314
use build_reduced_graph::BuildReducedGraphVisitor;
1415
use resolve_imports::ImportResolver;
@@ -25,6 +26,7 @@ use syntax::ext::base::{NormalTT, SyntaxExtension};
2526
use syntax::ext::expand::Expansion;
2627
use syntax::ext::hygiene::Mark;
2728
use syntax::ext::tt::macro_rules;
29+
use syntax::feature_gate::{emit_feature_err, GateIssue};
2830
use syntax::fold::Folder;
2931
use syntax::ptr::P;
3032
use syntax::util::lev_distance::find_best_match_for_name;
@@ -207,75 +209,103 @@ impl<'a> base::Resolver for Resolver<'a> {
207209

208210
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
209211
-> Result<Rc<SyntaxExtension>, Determinacy> {
210-
if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
211-
self.session.span_err(path.span, "expected macro name without module separators");
212+
let ast::Path { ref segments, global, span } = *path;
213+
if segments.iter().any(|segment| !segment.parameters.is_empty()) {
214+
let kind =
215+
if segments.last().unwrap().parameters.is_empty() { "module" } else { "macro" };
216+
let msg = format!("type parameters are not allowed on {}s", kind);
217+
self.session.span_err(path.span, &msg);
212218
return Err(Determinacy::Determined);
213219
}
214-
let name = path.segments[0].identifier.name;
215220

221+
let path_scope = if global { PathScope::Global } else { PathScope::Lexical };
222+
let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
216223
let invocation = self.invocations[&scope];
217224
self.current_module = invocation.module.get();
218-
let ext = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) {
219-
Some(MacroBinding::Legacy(binding)) => binding.ext.clone(),
220-
Some(MacroBinding::Modern(binding)) => binding.get_macro(self),
221-
None => match self.resolve_in_item_lexical_scope(name, MacroNS, None) {
222-
Some(binding) => binding.get_macro(self),
223-
None => return Err(if force {
225+
226+
if path.len() > 1 || global {
227+
if !self.use_extern_macros {
228+
let msg = "non-ident macro paths are experimental";
229+
let feature = "use_extern_macros";
230+
emit_feature_err(&self.session.parse_sess, feature, span, GateIssue::Language, msg);
231+
return Err(Determinacy::Determined);
232+
}
233+
234+
let ext = match self.resolve_path(&path, path_scope, Some(MacroNS), None) {
235+
PathResult::NonModule(path_res) => Ok(self.get_macro(path_res.base_def)),
236+
PathResult::Module(..) => unreachable!(),
237+
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
238+
_ => Err(Determinacy::Determined),
239+
};
240+
self.current_module.macro_resolutions.borrow_mut()
241+
.push((path.into_boxed_slice(), path_scope, span));
242+
return ext;
243+
}
244+
245+
let name = path[0].name;
246+
let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) {
247+
Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()),
248+
Some(MacroBinding::Modern(binding)) => Ok(binding.get_macro(self)),
249+
None => match self.resolve_lexical_macro_path_segment(name, MacroNS, None) {
250+
Ok(binding) => Ok(binding.get_macro(self)),
251+
Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined),
252+
_ => {
224253
let msg = format!("macro undefined: '{}!'", name);
225-
let mut err = self.session.struct_span_err(path.span, &msg);
254+
let mut err = self.session.struct_span_err(span, &msg);
226255
self.suggest_macro_name(&name.as_str(), &mut err);
227256
err.emit();
228-
Determinacy::Determined
229-
} else {
230-
Determinacy::Undetermined
231-
}),
257+
return Err(Determinacy::Determined);
258+
},
232259
},
233260
};
234261

235262
if self.use_extern_macros {
236-
self.current_module.legacy_macro_resolutions.borrow_mut()
237-
.push((scope, name, path.span));
263+
self.current_module.legacy_macro_resolutions.borrow_mut().push((scope, name, span));
238264
}
239-
Ok(ext)
265+
result
240266
}
241267
}
242268

243269
impl<'a> Resolver<'a> {
244-
// Resolve the name in the module's lexical scope, excluding non-items.
245-
fn resolve_in_item_lexical_scope(&mut self,
246-
name: Name,
247-
ns: Namespace,
248-
record_used: Option<Span>)
249-
-> Option<&'a NameBinding<'a>> {
270+
// Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`)
271+
pub fn resolve_lexical_macro_path_segment(&mut self,
272+
name: Name,
273+
ns: Namespace,
274+
record_used: Option<Span>)
275+
-> Result<&'a NameBinding<'a>, Determinacy> {
250276
let mut module = self.current_module;
251-
let mut potential_expanded_shadower = None;
277+
let mut potential_expanded_shadower: Option<&NameBinding> = None;
252278
loop {
253279
// Since expanded macros may not shadow the lexical scope (enforced below),
254280
// we can ignore unresolved invocations (indicated by the penultimate argument).
255281
match self.resolve_name_in_module(module, name, ns, true, record_used) {
256282
Ok(binding) => {
257283
let span = match record_used {
258284
Some(span) => span,
259-
None => return Some(binding),
285+
None => return Ok(binding),
260286
};
261-
if let Some(shadower) = potential_expanded_shadower {
262-
self.ambiguity_errors.push(AmbiguityError {
263-
span: span, name: name, b1: shadower, b2: binding, lexical: true,
264-
});
265-
return Some(shadower);
266-
} else if binding.expansion == Mark::root() {
267-
return Some(binding);
268-
} else {
269-
potential_expanded_shadower = Some(binding);
287+
match potential_expanded_shadower {
288+
Some(shadower) if shadower.def() != binding.def() => {
289+
self.ambiguity_errors.push(AmbiguityError {
290+
span: span, name: name, b1: shadower, b2: binding, lexical: true,
291+
});
292+
return Ok(shadower);
293+
}
294+
_ if binding.expansion == Mark::root() => return Ok(binding),
295+
_ => potential_expanded_shadower = Some(binding),
270296
}
271297
},
272-
Err(Determinacy::Undetermined) => return None,
298+
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
273299
Err(Determinacy::Determined) => {}
274300
}
275301

276302
match module.kind {
277303
ModuleKind::Block(..) => module = module.parent.unwrap(),
278-
ModuleKind::Def(..) => return potential_expanded_shadower,
304+
ModuleKind::Def(..) => return match potential_expanded_shadower {
305+
Some(binding) => Ok(binding),
306+
None if record_used.is_some() => Err(Determinacy::Determined),
307+
None => Err(Determinacy::Undetermined),
308+
},
279309
}
280310
}
281311
}
@@ -343,12 +373,22 @@ impl<'a> Resolver<'a> {
343373

344374
pub fn finalize_current_module_macro_resolutions(&mut self) {
345375
let module = self.current_module;
376+
for &(ref path, scope, span) in module.macro_resolutions.borrow().iter() {
377+
match self.resolve_path(path, scope, Some(MacroNS), Some(span)) {
378+
PathResult::NonModule(_) => {},
379+
PathResult::Failed(msg, _) => {
380+
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
381+
}
382+
_ => unreachable!(),
383+
}
384+
}
385+
346386
for &(mark, name, span) in module.legacy_macro_resolutions.borrow().iter() {
347387
let legacy_scope = &self.invocations[&mark].legacy_scope;
348388
let legacy_resolution = self.resolve_legacy_scope(legacy_scope, name, true);
349-
let resolution = self.resolve_in_item_lexical_scope(name, MacroNS, Some(span));
389+
let resolution = self.resolve_lexical_macro_path_segment(name, MacroNS, Some(span));
350390
let (legacy_resolution, resolution) = match (legacy_resolution, resolution) {
351-
(Some(legacy_resolution), Some(resolution)) => (legacy_resolution, resolution),
391+
(Some(legacy_resolution), Ok(resolution)) => (legacy_resolution, resolution),
352392
_ => continue,
353393
};
354394
let (legacy_span, participle) = match legacy_resolution {

src/librustc_resolve/resolve_imports.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use self::ImportDirectiveSubclass::*;
1212

13-
use {Module, PerNS};
13+
use {AmbiguityError, Module, PerNS};
1414
use Namespace::{self, TypeNS, MacroNS};
1515
use {NameBinding, NameBindingKind, PathResult, PathScope, PrivacyError, ToNameBinding};
1616
use Resolver;
@@ -73,6 +73,7 @@ pub struct NameResolution<'a> {
7373
single_imports: SingleImports<'a>,
7474
/// The least shadowable known binding for this name, or None if there are no known bindings.
7575
pub binding: Option<&'a NameBinding<'a>>,
76+
shadows_glob: Option<&'a NameBinding<'a>>,
7677
}
7778

7879
#[derive(Clone, Debug)]
@@ -151,6 +152,18 @@ impl<'a> Resolver<'a> {
151152

152153
if let Some(span) = record_used {
153154
if let Some(binding) = resolution.binding {
155+
if let Some(shadowed_glob) = resolution.shadows_glob {
156+
// If we ignore unresolved invocations, we must forbid
157+
// expanded shadowing to avoid time travel.
158+
if ignore_unresolved_invocations &&
159+
binding.expansion != Mark::root() &&
160+
ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing
161+
binding.def() != shadowed_glob.def() {
162+
self.ambiguity_errors.push(AmbiguityError {
163+
span: span, name: name, lexical: false, b1: binding, b2: shadowed_glob,
164+
});
165+
}
166+
}
154167
if self.record_use(name, ns, binding, span) {
155168
return Ok(self.dummy_binding);
156169
}
@@ -298,6 +311,7 @@ impl<'a> Resolver<'a> {
298311
if binding.is_glob_import() {
299312
if !old_binding.is_glob_import() &&
300313
!(ns == MacroNS && old_binding.expansion != Mark::root()) {
314+
resolution.shadows_glob = Some(binding);
301315
} else if binding.def() != old_binding.def() {
302316
resolution.binding = Some(this.ambiguity(old_binding, binding));
303317
} else if !old_binding.vis.is_at_least(binding.vis, this) {
@@ -310,6 +324,7 @@ impl<'a> Resolver<'a> {
310324
resolution.binding = Some(this.ambiguity(binding, old_binding));
311325
} else {
312326
resolution.binding = Some(binding);
327+
resolution.shadows_glob = Some(old_binding);
313328
}
314329
} else {
315330
return Err(old_binding);

src/libsyntax/ext/expand.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -400,12 +400,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
400400
&self.cx.ecfg.features.unwrap());
401401
}
402402

403-
if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
404-
self.cx.span_err(path.span, "expected macro name without module separators");
405-
return kind.dummy(span);
406-
}
407-
408-
let extname = path.segments[0].identifier.name;
403+
let extname = path.segments.last().unwrap().identifier.name;
409404
let ident = ident.unwrap_or(keywords::Invalid.ident());
410405
let marked_tts = mark_tts(&tts, mark);
411406
let opt_expanded = match *ext {

0 commit comments

Comments
 (0)