resolve/expand: resolve_macro_invocation no longer returns determinate errors

It either returns the indeterminacy error, or valid (but perhaps dummy) `SyntaxExtension`.

With this change enum `Determinacy` is no longer used in libsyntax and can be moved to resolve.

The regressions in diagnosics are fixed in the next commits.
This commit is contained in:
Vadim Petrochenkov
2019-07-03 11:44:57 +03:00
parent cd0fd630e8
commit f16993d4ac
10 changed files with 109 additions and 124 deletions

View File

@@ -9,7 +9,7 @@ use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleIm
use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding}; use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
use crate::{ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry}; use crate::{ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
use crate::Namespace::{self, TypeNS, ValueNS, MacroNS}; use crate::Namespace::{self, TypeNS, ValueNS, MacroNS};
use crate::{resolve_error, resolve_struct_error, ResolutionError}; use crate::{resolve_error, resolve_struct_error, ResolutionError, Determinacy};
use rustc::bug; use rustc::bug;
use rustc::hir::def::{self, *}; use rustc::hir::def::{self, *};
@@ -30,7 +30,6 @@ use syntax::attr;
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant}; use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant};
use syntax::ext::base::SyntaxExtension; use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::Determinacy::Undetermined;
use syntax::ext::hygiene::Mark; use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules; use syntax::ext::tt::macro_rules;
use syntax::feature_gate::is_builtin_attr; use syntax::feature_gate::is_builtin_attr;
@@ -231,9 +230,9 @@ impl<'a> Resolver<'a> {
source: source.ident, source: source.ident,
target: ident, target: ident,
source_bindings: PerNS { source_bindings: PerNS {
type_ns: Cell::new(Err(Undetermined)), type_ns: Cell::new(Err(Determinacy::Undetermined)),
value_ns: Cell::new(Err(Undetermined)), value_ns: Cell::new(Err(Determinacy::Undetermined)),
macro_ns: Cell::new(Err(Undetermined)), macro_ns: Cell::new(Err(Determinacy::Undetermined)),
}, },
target_bindings: PerNS { target_bindings: PerNS {
type_ns: Cell::new(None), type_ns: Cell::new(None),

View File

@@ -15,6 +15,7 @@
pub use rustc::hir::def::{Namespace, PerNS}; pub use rustc::hir::def::{Namespace, PerNS};
use Determinacy::*;
use GenericParameters::*; use GenericParameters::*;
use RibKind::*; use RibKind::*;
use smallvec::smallvec; use smallvec::smallvec;
@@ -41,7 +42,6 @@ use syntax::source_map::SourceMap;
use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext}; use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext};
use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
use syntax::ext::base::SyntaxExtension; use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::base::MacroKind; use syntax::ext::base::MacroKind;
use syntax::symbol::{Symbol, kw, sym}; use syntax::symbol::{Symbol, kw, sym};
use syntax::util::lev_distance::find_best_match_for_name; use syntax::util::lev_distance::find_best_match_for_name;
@@ -93,6 +93,18 @@ enum Weak {
No, No,
} }
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Determinacy {
Determined,
Undetermined,
}
impl Determinacy {
fn determined(determined: bool) -> Determinacy {
if determined { Determinacy::Determined } else { Determinacy::Undetermined }
}
}
enum ScopeSet { enum ScopeSet {
Import(Namespace), Import(Namespace),
AbsolutePath(Namespace), AbsolutePath(Namespace),

View File

@@ -1,4 +1,4 @@
use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc}; use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
use crate::{CrateLint, Resolver, ResolutionError, ScopeSet, Weak}; use crate::{CrateLint, Resolver, ResolutionError, ScopeSet, Weak};
use crate::{Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding}; use crate::{Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
use crate::{is_known_tool, resolve_error}; use crate::{is_known_tool, resolve_error};
@@ -14,7 +14,7 @@ use rustc::{ty, lint, span_bug};
use syntax::ast::{self, Ident, ItemKind}; use syntax::ast::{self, Ident, ItemKind};
use syntax::attr::{self, StabilityLevel}; use syntax::attr::{self, StabilityLevel};
use syntax::errors::DiagnosticBuilder; use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, Determinacy}; use syntax::ext::base::{self, Indeterminate};
use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
use syntax::ext::hygiene::{self, Mark}; use syntax::ext::hygiene::{self, Mark};
@@ -216,7 +216,7 @@ impl<'a> base::Resolver for Resolver<'a> {
} }
fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy> { -> Result<Option<Lrc<SyntaxExtension>>, Indeterminate> {
let (path, kind, derives_in_scope, after_derive) = match invoc.kind { let (path, kind, derives_in_scope, after_derive) = match invoc.kind {
InvocationKind::Attr { attr: None, .. } => InvocationKind::Attr { attr: None, .. } =>
return Ok(None), return Ok(None),
@@ -229,12 +229,7 @@ impl<'a> base::Resolver for Resolver<'a> {
}; };
let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
let (res, ext) = match self.resolve_macro_to_res(path, kind, &parent_scope, true, force) { let (res, ext) = self.resolve_macro_to_res(path, kind, &parent_scope, true, force)?;
Ok((res, ext)) => (res, ext),
// Return dummy syntax extensions for unresolved macros for better recovery.
Err(Determinacy::Determined) => (Res::Err, self.dummy_ext(kind)),
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
};
let span = invoc.span(); let span = invoc.span();
let descr = fast_print_path(path); let descr = fast_print_path(path);
@@ -287,7 +282,7 @@ impl<'a> Resolver<'a> {
parent_scope: &ParentScope<'a>, parent_scope: &ParentScope<'a>,
trace: bool, trace: bool,
force: bool, force: bool,
) -> Result<(Res, Lrc<SyntaxExtension>), Determinacy> { ) -> Result<(Res, Lrc<SyntaxExtension>), Indeterminate> {
let res = self.resolve_macro_to_res_inner(path, kind, parent_scope, trace, force); let res = self.resolve_macro_to_res_inner(path, kind, parent_scope, trace, force);
// Report errors and enforce feature gates for the resolved macro. // Report errors and enforce feature gates for the resolved macro.
@@ -313,7 +308,14 @@ impl<'a> Resolver<'a> {
} }
} }
let res = res?; let res = match res {
Err(Determinacy::Undetermined) => return Err(Indeterminate),
Ok(Res::Err) | Err(Determinacy::Determined) => {
// Return dummy syntax extensions for unresolved macros for better recovery.
return Ok((Res::Err, self.dummy_ext(kind)));
}
Ok(res) => res,
};
match res { match res {
Res::Def(DefKind::Macro(_), def_id) => { Res::Def(DefKind::Macro(_), def_id) => {
@@ -328,35 +330,23 @@ impl<'a> Resolver<'a> {
} }
} }
Res::NonMacroAttr(attr_kind) => { Res::NonMacroAttr(attr_kind) => {
if kind == MacroKind::Attr { if attr_kind == NonMacroAttrKind::Custom {
if attr_kind == NonMacroAttrKind::Custom { assert!(path.segments.len() == 1);
assert!(path.segments.len() == 1); if !features.custom_attribute {
if !features.custom_attribute { let msg = format!("The attribute `{}` is currently unknown to the \
let msg = format!("The attribute `{}` is currently unknown to the \ compiler and may have meaning added to it in the \
compiler and may have meaning added to it in the \ future", path);
future", path); self.report_unknown_attribute(
self.report_unknown_attribute( path.span,
path.span, &path.segments[0].ident.as_str(),
&path.segments[0].ident.as_str(), &msg,
&msg, sym::custom_attribute,
sym::custom_attribute, );
);
}
} }
} else {
// Not only attributes, but anything in macro namespace can result in
// `Res::NonMacroAttr` definition (e.g., `inline!()`), so we must report
// an error for those cases.
let msg = format!("expected a macro, found {}", res.descr());
self.session.span_err(path.span, &msg);
return Err(Determinacy::Determined);
} }
} }
Res::Err => {
return Err(Determinacy::Determined);
}
_ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"),
} };
Ok((res, self.get_macro(res))) Ok((res, self.get_macro(res)))
} }
@@ -608,9 +598,7 @@ impl<'a> Resolver<'a> {
result = Ok((binding, Flags::empty())); result = Ok((binding, Flags::empty()));
break; break;
} }
Err(Determinacy::Determined) => {} Err(Indeterminate) => result = Err(Determinacy::Undetermined),
Err(Determinacy::Undetermined) =>
result = Err(Determinacy::Undetermined),
} }
} }
result result

View File

@@ -2,6 +2,7 @@ use ImportDirectiveSubclass::*;
use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc}; use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, Weak}; use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, Weak};
use crate::Determinacy::{self, *};
use crate::Namespace::{self, TypeNS, MacroNS}; use crate::Namespace::{self, TypeNS, MacroNS};
use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
use crate::{Resolver, Segment}; use crate::{Resolver, Segment};
@@ -27,7 +28,6 @@ use rustc::util::nodemap::FxHashSet;
use rustc::{bug, span_bug}; use rustc::{bug, span_bug};
use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID}; use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID};
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::hygiene::Mark; use syntax::ext::hygiene::Mark;
use syntax::symbol::kw; use syntax::symbol::kw;
use syntax::util::lev_distance::find_best_match_for_name; use syntax::util::lev_distance::find_best_match_for_name;

View File

@@ -676,6 +676,9 @@ impl SyntaxExtension {
pub type NamedSyntaxExtension = (Name, SyntaxExtension); pub type NamedSyntaxExtension = (Name, SyntaxExtension);
/// Error type that denotes indeterminacy.
pub struct Indeterminate;
pub trait Resolver { pub trait Resolver {
fn next_node_id(&mut self) -> ast::NodeId; fn next_node_id(&mut self) -> ast::NodeId;
@@ -689,23 +692,11 @@ pub trait Resolver {
fn resolve_imports(&mut self); fn resolve_imports(&mut self);
fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy>; -> Result<Option<Lrc<SyntaxExtension>>, Indeterminate>;
fn check_unused_macros(&self); fn check_unused_macros(&self);
} }
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Determinacy {
Determined,
Undetermined,
}
impl Determinacy {
pub fn determined(determined: bool) -> Determinacy {
if determined { Determinacy::Determined } else { Determinacy::Undetermined }
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct ModuleData { pub struct ModuleData {
pub mod_path: Vec<ast::Ident>, pub mod_path: Vec<ast::Ident>,

View File

@@ -313,9 +313,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let scope = let scope =
if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
let ext = match self.cx.resolver.resolve_macro_invocation(&invoc, scope, force) { let ext = match self.cx.resolver.resolve_macro_invocation(&invoc, scope, force) {
Ok(ext) => Some(ext), Ok(ext) => ext,
Err(Determinacy::Determined) => None, Err(Indeterminate) => {
Err(Determinacy::Undetermined) => {
undetermined_invocations.push(invoc); undetermined_invocations.push(invoc);
continue continue
} }
@@ -328,65 +327,61 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
self.cx.current_expansion.mark = scope; self.cx.current_expansion.mark = scope;
// FIXME(jseyfried): Refactor out the following logic // FIXME(jseyfried): Refactor out the following logic
let (expanded_fragment, new_invocations) = if let Some(ext) = ext { let (expanded_fragment, new_invocations) = if let Some(ext) = ext {
if let Some(ext) = ext { let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span());
let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span()); let fragment = self.expand_invoc(invoc, &*ext).unwrap_or_else(|| {
let fragment = self.expand_invoc(invoc, &*ext).unwrap_or_else(|| { invoc_fragment_kind.dummy(invoc_span).unwrap()
invoc_fragment_kind.dummy(invoc_span).unwrap() });
}); self.collect_invocations(fragment, &[])
self.collect_invocations(fragment, &[]) } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind {
} else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { if !item.derive_allowed() {
if !item.derive_allowed() { let attr = attr::find_by_name(item.attrs(), sym::derive)
let attr = attr::find_by_name(item.attrs(), sym::derive) .expect("`derive` attribute should exist");
.expect("`derive` attribute should exist"); let span = attr.span;
let span = attr.span; let mut err = self.cx.mut_span_err(span,
let mut err = self.cx.mut_span_err(span, "`derive` may only be applied to \
"`derive` may only be applied to \ structs, enums and unions");
structs, enums and unions"); if let ast::AttrStyle::Inner = attr.style {
if let ast::AttrStyle::Inner = attr.style { let trait_list = traits.iter()
let trait_list = traits.iter() .map(|t| t.to_string()).collect::<Vec<_>>();
.map(|t| t.to_string()).collect::<Vec<_>>(); let suggestion = format!("#[derive({})]", trait_list.join(", "));
let suggestion = format!("#[derive({})]", trait_list.join(", ")); err.span_suggestion(
err.span_suggestion( span, "try an outer attribute", suggestion,
span, "try an outer attribute", suggestion, // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
// We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT Applicability::MaybeIncorrect
Applicability::MaybeIncorrect );
);
}
err.emit();
} }
err.emit();
let mut item = self.fully_configure(item);
item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive));
let mut item_with_markers = item.clone();
add_derived_markers(&mut self.cx, item.span(), &traits, &mut item_with_markers);
let derives = derives.entry(invoc.expansion_data.mark).or_default();
derives.reserve(traits.len());
invocations.reserve(traits.len());
for path in traits {
let mark = Mark::fresh(self.cx.current_expansion.mark);
derives.push(mark);
invocations.push(Invocation {
kind: InvocationKind::Derive {
path,
item: item.clone(),
item_with_markers: item_with_markers.clone(),
},
fragment_kind: invoc.fragment_kind,
expansion_data: ExpansionData {
mark,
..invoc.expansion_data.clone()
},
});
}
let fragment = invoc.fragment_kind
.expect_from_annotatables(::std::iter::once(item_with_markers));
self.collect_invocations(fragment, derives)
} else {
unreachable!()
} }
let mut item = self.fully_configure(item);
item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive));
let mut item_with_markers = item.clone();
add_derived_markers(&mut self.cx, item.span(), &traits, &mut item_with_markers);
let derives = derives.entry(invoc.expansion_data.mark).or_default();
derives.reserve(traits.len());
invocations.reserve(traits.len());
for path in traits {
let mark = Mark::fresh(self.cx.current_expansion.mark);
derives.push(mark);
invocations.push(Invocation {
kind: InvocationKind::Derive {
path,
item: item.clone(),
item_with_markers: item_with_markers.clone(),
},
fragment_kind: invoc.fragment_kind,
expansion_data: ExpansionData {
mark,
..invoc.expansion_data.clone()
},
});
}
let fragment = invoc.fragment_kind
.expect_from_annotatables(::std::iter::once(item_with_markers));
self.collect_invocations(fragment, derives)
} else { } else {
self.collect_invocations(invoc.fragment_kind.dummy(invoc.span()).unwrap(), &[]) unreachable!()
}; };
if expanded_fragments.len() < depth { if expanded_fragments.len() < depth {

View File

@@ -1,4 +1,4 @@
#[derive(inline)] //~ ERROR expected a macro, found built-in attribute #[derive(inline)] //~ ERROR macro `inline` may not be used for derive attributes
struct S; struct S;
fn main() {} fn main() {}

View File

@@ -1,4 +1,4 @@
error: expected a macro, found built-in attribute error: macro `inline` may not be used for derive attributes
--> $DIR/macro-path-prelude-fail-4.rs:1:10 --> $DIR/macro-path-prelude-fail-4.rs:1:10
| |
LL | #[derive(inline)] LL | #[derive(inline)]

View File

@@ -1,6 +1,6 @@
#[derive(rustfmt::skip)] //~ ERROR expected a macro, found tool attribute #[derive(rustfmt::skip)] //~ ERROR macro `rustfmt::skip` may not be used for derive attributes
struct S; struct S;
fn main() { fn main() {
rustfmt::skip!(); //~ ERROR expected a macro, found tool attribute rustfmt::skip!(); //~ ERROR `rustfmt::skip` can only be used in attributes
} }

View File

@@ -1,10 +1,10 @@
error: expected a macro, found tool attribute error: macro `rustfmt::skip` may not be used for derive attributes
--> $DIR/tool-attributes-misplaced-2.rs:1:10 --> $DIR/tool-attributes-misplaced-2.rs:1:10
| |
LL | #[derive(rustfmt::skip)] LL | #[derive(rustfmt::skip)]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: expected a macro, found tool attribute error: `rustfmt::skip` can only be used in attributes
--> $DIR/tool-attributes-misplaced-2.rs:5:5 --> $DIR/tool-attributes-misplaced-2.rs:5:5
| |
LL | rustfmt::skip!(); LL | rustfmt::skip!();