Skip to content

Commit

Permalink
resolve: Cleanup two main macro resolution functions, tweak some comm…
Browse files Browse the repository at this point in the history
…ents
  • Loading branch information
petrochenkov committed Sep 8, 2018
1 parent f34ac26 commit 9a539ad
Showing 1 changed file with 50 additions and 64 deletions.
114 changes: 50 additions & 64 deletions src/librustc_resolve/macros.rs
Expand Up @@ -45,6 +45,7 @@ use std::mem;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::small_vec::ExpectOne;

#[derive(Clone, Copy)]
crate struct FromPrelude(bool);

#[derive(Clone)]
Expand Down Expand Up @@ -578,15 +579,18 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
assert!(force || !record_used); // `record_used` implies `force`
ident = ident.modern();

// Names from inner scope that can't shadow names from outer scopes, e.g.
// mod m { ... }
// This is *the* result, resolution from the scope closest to the resolved identifier.
// However, sometimes this result is "weak" because it comes from a glob import or
// a macro expansion, and in this case it cannot shadow names from outer scopes, e.g.
// mod m { ... } // solution in outer scope
// {
// use prefix::*; // if this imports another `m`, then it can't shadow the outer `m`
// // and we have and ambiguity error
// use prefix::*; // imports another `m` - innermost solution
// // weak, cannot shadow the outer `m`, need to report ambiguity error
// m::mac!();
// }
// This includes names from globs and from macro expansions.
let mut potentially_ambiguous_result: Option<(&NameBinding, FromPrelude)> = None;
// So we have to save the innermost solution and continue searching in outer scopes
// to detect potential ambiguities.
let mut innermost_result: Option<(&NameBinding, FromPrelude)> = None;

enum WhereToResolve<'a> {
Module(Module<'a>),
Expand Down Expand Up @@ -729,32 +733,25 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
return Ok(result);
}

// Found a solution that is ambiguous with a previously found solution.
// Push an ambiguity error for later reporting and
// return something for better recovery.
if let Some(previous_result) = potentially_ambiguous_result {
if result.0.def() != previous_result.0.def() {
if let Some(innermost_result) = innermost_result {
// Found another solution, if the first one was "weak", report an error.
if result.0.def() != innermost_result.0.def() &&
(innermost_result.0.is_glob_import() ||
innermost_result.0.expansion != Mark::root()) {
self.ambiguity_errors.push(AmbiguityError {
span: path_span,
name: ident.name,
b1: previous_result.0,
b1: innermost_result.0,
b2: result.0,
});
return Ok(previous_result);
return Ok(innermost_result);
}
} else {
// Found the first solution.
innermost_result = Some(result);
}

// Found a solution that's not an ambiguity yet, but is "suspicious" and
// can participate in ambiguities later on.
// Remember it and go search for other solutions in outer scopes.
if result.0.is_glob_import() || result.0.expansion != Mark::root() {
potentially_ambiguous_result = Some(result);

continue_search!();
}

// Found a solution that can't be ambiguous, great success.
return Ok(result);
continue_search!();
},
Err(Determinacy::Determined) => {
continue_search!();
Expand All @@ -763,9 +760,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
}

// Previously found potentially ambiguous result turned out to not be ambiguous after all.
if let Some(previous_result) = potentially_ambiguous_result {
return Ok(previous_result);
// The first found solution was the only one, return it.
if let Some(innermost_result) = innermost_result {
return Ok(innermost_result);
}

let determinacy = Determinacy::determined(force);
Expand All @@ -784,30 +781,31 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}

fn resolve_legacy_scope(&mut self,
scope: &'a Cell<LegacyScope<'a>>,
invocation_legacy_scope: &'a Cell<LegacyScope<'a>>,
ident: Ident,
record_used: bool)
-> Option<&'a NameBinding<'a>> {
let ident = ident.modern();

// Names from inner scope that can't shadow names from outer scopes, e.g.
// macro_rules! mac { ... }
// This is *the* result, resolution from the scope closest to the resolved identifier.
// However, sometimes this result is "weak" because it comes from a macro expansion,
// and in this case it cannot shadow names from outer scopes, e.g.
// macro_rules! m { ... } // solution in outer scope
// {
// define_mac!(); // if this generates another `macro_rules! mac`, then it can't shadow
// // the outer `mac` and we have and ambiguity error
// mac!();
// define_m!(); // generates another `macro_rules! m` - innermost solution
// // weak, cannot shadow the outer `m`, need to report ambiguity error
// m!();
// }
let mut potentially_ambiguous_result: Option<&NameBinding> = None;
// So we have to save the innermost solution and continue searching in outer scopes
// to detect potential ambiguities.
let mut innermost_result: Option<&NameBinding> = None;

// Go through all the scopes and try to resolve the name.
let mut where_to_resolve = scope;
let mut where_to_resolve = invocation_legacy_scope;
loop {
let result = match where_to_resolve.get() {
LegacyScope::Binding(legacy_binding) => if ident == legacy_binding.ident {
Some(legacy_binding.binding)
} else {
None
}
LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
Some(legacy_binding.binding),
_ => None,
};

Expand Down Expand Up @@ -836,45 +834,33 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
return Some(result);
}

// Found a solution that is ambiguous with a previously found solution.
// Push an ambiguity error for later reporting and
// return something for better recovery.
if let Some(previous_result) = potentially_ambiguous_result {
if result.def() != previous_result.def() {
if let Some(innermost_result) = innermost_result {
// Found another solution, if the first one was "weak", report an error.
if result.def() != innermost_result.def() &&
innermost_result.expansion != Mark::root() {
self.ambiguity_errors.push(AmbiguityError {
span: ident.span,
name: ident.name,
b1: previous_result,
b1: innermost_result,
b2: result,
});
return Some(previous_result);
return Some(innermost_result);
}
} else {
// Found the first solution.
innermost_result = Some(result);
}

// Found a solution that's not an ambiguity yet, but is "suspicious" and
// can participate in ambiguities later on.
// Remember it and go search for other solutions in outer scopes.
if result.expansion != Mark::root() {
potentially_ambiguous_result = Some(result);

continue_search!();
}

// Found a solution that can't be ambiguous.
return Some(result);
continue_search!();
}
None => {
continue_search!();
}
}
}

// Previously found potentially ambiguous result turned out to not be ambiguous after all.
if let Some(previous_result) = potentially_ambiguous_result {
return Some(previous_result);
}

None
// The first found solution was the only one (or there was no solution at all), return it.
innermost_result
}

pub fn finalize_current_module_macro_resolutions(&mut self) {
Expand Down

0 comments on commit 9a539ad

Please sign in to comment.