Skip to content

Commit 31e0e12

Browse files
committed
Add support for undetermined macro invocations.
1 parent d5281ef commit 31e0e12

File tree

4 files changed

+44
-18
lines changed

4 files changed

+44
-18
lines changed

src/librustc_resolve/macros.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::cell::Cell;
1717
use std::rc::Rc;
1818
use syntax::ast;
1919
use syntax::errors::DiagnosticBuilder;
20-
use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
20+
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier};
2121
use syntax::ext::base::{NormalTT, SyntaxExtension};
2222
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
2323
use syntax::ext::hygiene::Mark;
@@ -173,15 +173,16 @@ impl<'a> base::Resolver for Resolver<'a> {
173173
None
174174
}
175175

176-
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
176+
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, _force: bool)
177+
-> Result<Rc<SyntaxExtension>, Determinacy> {
177178
let (name, span) = match invoc.kind {
178179
InvocationKind::Bang { ref mac, .. } => {
179180
let path = &mac.node.path;
180181
if path.segments.len() > 1 || path.global ||
181182
!path.segments[0].parameters.is_empty() {
182183
self.session.span_err(path.span,
183184
"expected macro name without module separators");
184-
return None;
185+
return Err(Determinacy::Determined);
185186
}
186187
(path.segments[0].identifier.name, path.span)
187188
}
@@ -192,12 +193,12 @@ impl<'a> base::Resolver for Resolver<'a> {
192193
if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
193194
invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
194195
}
195-
self.resolve_macro_name(invocation.legacy_scope.get(), name, true).or_else(|| {
196+
self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| {
196197
let mut err =
197198
self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
198199
self.suggest_macro_name(&name.as_str(), &mut err);
199200
err.emit();
200-
None
201+
Determinacy::Determined
201202
})
202203
}
203204

src/librustc_resolve/resolve_imports.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use self::Determinacy::*;
1211
use self::ImportDirectiveSubclass::*;
1312

1413
use Module;
@@ -26,6 +25,7 @@ use rustc::lint::builtin::PRIVATE_IN_PUBLIC;
2625
use rustc::hir::def::*;
2726

2827
use syntax::ast::{NodeId, Name};
28+
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
2929
use syntax::util::lev_distance::find_best_match_for_name;
3030
use syntax_pos::Span;
3131

@@ -37,12 +37,6 @@ impl<'a> Resolver<'a> {
3737
}
3838
}
3939

40-
#[derive(Copy, Clone, Debug)]
41-
pub enum Determinacy {
42-
Determined,
43-
Undetermined,
44-
}
45-
4640
/// Contains data for specific types of import directives.
4741
#[derive(Clone, Debug)]
4842
pub enum ImportDirectiveSubclass<'a> {

src/libsyntax/ext/base.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -522,10 +522,17 @@ pub trait Resolver {
522522
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
523523

524524
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
525-
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>>;
525+
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
526+
-> Result<Rc<SyntaxExtension>, Determinacy>;
526527
fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>>;
527528
}
528529

530+
#[derive(Copy, Clone, Debug)]
531+
pub enum Determinacy {
532+
Determined,
533+
Undetermined,
534+
}
535+
529536
pub struct DummyResolver;
530537

531538
impl Resolver for DummyResolver {
@@ -539,8 +546,9 @@ impl Resolver for DummyResolver {
539546

540547
fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
541548
fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option<Rc<MultiItemModifier>> { None }
542-
fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
543-
None
549+
fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation, _force: bool)
550+
-> Result<Rc<SyntaxExtension>, Determinacy> {
551+
Err(Determinacy::Determined)
544552
}
545553
}
546554

src/libsyntax/ext/expand.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
225225
invocations.reverse();
226226

227227
let mut expansions = Vec::new();
228-
while let Some(invoc) = invocations.pop() {
228+
let mut undetermined_invocations = Vec::new();
229+
let (mut progress, mut force) = (false, !self.monotonic);
230+
loop {
231+
let invoc = if let Some(invoc) = invocations.pop() {
232+
invoc
233+
} else if undetermined_invocations.is_empty() {
234+
break
235+
} else {
236+
invocations = mem::replace(&mut undetermined_invocations, Vec::new());
237+
force = !mem::replace(&mut progress, false);
238+
continue
239+
};
240+
241+
let scope =
242+
if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
243+
let ext = match self.cx.resolver.resolve_invoc(scope, &invoc, force) {
244+
Ok(ext) => Some(ext),
245+
Err(Determinacy::Determined) => None,
246+
Err(Determinacy::Undetermined) => {
247+
undetermined_invocations.push(invoc);
248+
continue
249+
}
250+
};
251+
252+
progress = true;
229253
let ExpansionData { depth, mark, .. } = invoc.expansion_data;
230254
self.cx.current_expansion = invoc.expansion_data.clone();
231255

232-
let scope = if self.monotonic { mark } else { orig_expansion_data.mark };
233256
self.cx.current_expansion.mark = scope;
234-
let expansion = match self.cx.resolver.resolve_invoc(scope, &invoc) {
257+
let expansion = match ext {
235258
Some(ext) => self.expand_invoc(invoc, ext),
236259
None => invoc.expansion_kind.dummy(invoc.span()),
237260
};

0 commit comments

Comments
 (0)