hygiene: Remove Options from functions returning ExpnInfo

The expansion info is not optional and should always exist
This commit is contained in:
Vadim Petrochenkov 2019-08-11 03:00:05 +03:00
parent 6cb28b6617
commit 73dee258c1
14 changed files with 98 additions and 155 deletions

View file

@ -9,7 +9,6 @@ use errors::Applicability;
use rustc_data_structures::fx::FxHashMap;
use syntax::ast::{Ident, Item, ItemKind};
use syntax::symbol::{sym, Symbol};
use syntax_pos::ExpnInfo;
declare_tool_lint! {
pub rustc::DEFAULT_HASH_TYPES,
@ -228,30 +227,20 @@ impl EarlyLintPass for LintPassImpl {
if let ItemKind::Impl(_, _, _, _, Some(lint_pass), _, _) = &item.node {
if let Some(last) = lint_pass.path.segments.last() {
if last.ident.name == sym::LintPass {
match &lint_pass.path.span.ctxt().outer_expn_info() {
Some(info) if is_lint_pass_expansion(info) => {}
_ => {
cx.struct_span_lint(
LINT_PASS_IMPL_WITHOUT_MACRO,
lint_pass.path.span,
"implementing `LintPass` by hand",
)
.help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
.emit();
}
let expn_info = lint_pass.path.span.ctxt().outer_expn_info();
let call_site = expn_info.call_site;
if expn_info.kind.descr() != sym::impl_lint_pass &&
call_site.ctxt().outer_expn_info().kind.descr() != sym::declare_lint_pass {
cx.struct_span_lint(
LINT_PASS_IMPL_WITHOUT_MACRO,
lint_pass.path.span,
"implementing `LintPass` by hand",
)
.help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
.emit();
}
}
}
}
}
}
fn is_lint_pass_expansion(expn_info: &ExpnInfo) -> bool {
if expn_info.kind.descr() == sym::impl_lint_pass {
true
} else if let Some(info) = expn_info.call_site.ctxt().outer_expn_info() {
info.kind.descr() == sym::declare_lint_pass
} else {
false
}
}

View file

@ -885,21 +885,16 @@ pub fn provide(providers: &mut Providers<'_>) {
/// This is used to test whether a lint should not even begin to figure out whether it should
/// be reported on the current node.
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
let info = match span.ctxt().outer_expn_info() {
Some(info) => info,
// no ExpnInfo means this span doesn't come from a macro
None => return false,
};
match info.kind {
let expn_info = span.ctxt().outer_expn_info();
match expn_info.kind {
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
ExpnKind::Desugaring(_) => true, // well, it's "external"
ExpnKind::Macro(MacroKind::Bang, _) => {
if info.def_site.is_dummy() {
if expn_info.def_site.is_dummy() {
// dummy span for the def_site means it's an external macro
return true;
}
match sess.source_map().span_to_snippet(info.def_site) {
match sess.source_map().span_to_snippet(expn_info.def_site) {
Ok(code) => !code.starts_with("macro_rules"),
// no snippet = external macro or compiler-builtin expansion
Err(_) => true,
@ -911,10 +906,8 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool {
/// Returns whether `span` originates in a derive macro's expansion
pub fn in_derive_expansion(span: Span) -> bool {
if let Some(info) = span.ctxt().outer_expn_info() {
if let ExpnKind::Macro(MacroKind::Derive, _) = info.kind {
return true;
}
if let ExpnKind::Macro(MacroKind::Derive, _) = span.ctxt().outer_expn_info().kind {
return true;
}
false
}

View file

@ -36,7 +36,7 @@ use errors::{Applicability, DiagnosticBuilder};
use std::fmt;
use syntax::ast;
use syntax::symbol::sym;
use syntax_pos::{DUMMY_SP, Span, ExpnInfo, ExpnKind};
use syntax_pos::{DUMMY_SP, Span, ExpnKind};
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn report_fulfillment_errors(&self,
@ -61,9 +61,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// We want to ignore desugarings here: spans are equivalent even
// if one is the result of a desugaring and the other is not.
let mut span = error.obligation.cause.span;
if let Some(ExpnInfo { kind: ExpnKind::Desugaring(_), def_site, .. })
= span.ctxt().outer_expn_info() {
span = def_site;
let expn_info = span.ctxt().outer_expn_info();
if let ExpnKind::Desugaring(_) = expn_info.kind {
span = expn_info.call_site;
}
error_map.entry(span).or_default().push(

View file

@ -820,18 +820,14 @@ where
TAG_NO_EXPANSION_INFO.encode(self)
} else {
let (expn_id, expn_info) = span_data.ctxt.outer_expn_with_info();
if let Some(expn_info) = expn_info {
if let Some(pos) = self.expn_info_shorthands.get(&expn_id).cloned() {
TAG_EXPANSION_INFO_SHORTHAND.encode(self)?;
pos.encode(self)
} else {
TAG_EXPANSION_INFO_INLINE.encode(self)?;
let pos = AbsoluteBytePos::new(self.position());
self.expn_info_shorthands.insert(expn_id, pos);
expn_info.encode(self)
}
if let Some(pos) = self.expn_info_shorthands.get(&expn_id).cloned() {
TAG_EXPANSION_INFO_SHORTHAND.encode(self)?;
pos.encode(self)
} else {
TAG_NO_EXPANSION_INFO.encode(self)
TAG_EXPANSION_INFO_INLINE.encode(self)?;
let pos = AbsoluteBytePos::new(self.position());
self.expn_info_shorthands.insert(expn_id, pos);
expn_info.encode(self)
}
}
}

View file

@ -1775,10 +1775,7 @@ impl SharedEmitterMain {
}
}
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg)) => {
match ExpnId::from_u32(cookie).expn_info() {
Some(ei) => sess.span_err(ei.call_site, &msg),
None => sess.err(&msg),
}
sess.span_err(ExpnId::from_u32(cookie).expn_info().call_site, &msg)
}
Ok(SharedEmitterMessage::AbortIfErrors) => {
sess.abort_if_errors();

View file

@ -517,9 +517,8 @@ impl EarlyLintPass for UnusedParens {
// trigger in situations that macro authors shouldn't have to care about, e.g.,
// when a parenthesized token tree matched in one macro expansion is matched as
// an expression in another and used as a fn/method argument (Issue #47775)
if e.span.ctxt().outer_expn_info()
.map_or(false, |info| info.call_site.from_expansion()) {
return;
if e.span.ctxt().outer_expn_info().call_site.from_expansion() {
return;
}
let msg = format!("{} argument", call_kind);
for arg in args_to_check {

View file

@ -346,8 +346,7 @@ impl<'a> Resolver<'a> {
// Possibly apply the macro helper hack
if kind == Some(MacroKind::Bang) && path.len() == 1 &&
path[0].ident.span.ctxt().outer_expn_info()
.map_or(false, |info| info.local_inner_macros) {
path[0].ident.span.ctxt().outer_expn_info().local_inner_macros {
let root = Ident::new(kw::DollarCrate, path[0].ident.span);
path.insert(0, Segment::from_ident(root));
}

View file

@ -756,10 +756,7 @@ impl<'a> ExtCtxt<'a> {
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config }
pub fn call_site(&self) -> Span {
match self.current_expansion.id.expn_info() {
Some(expn_info) => expn_info.call_site,
None => DUMMY_SP,
}
self.current_expansion.id.expn_info().call_site
}
pub fn backtrace(&self) -> SyntaxContext {
SyntaxContext::root().apply_mark(self.current_expansion.id)
@ -772,17 +769,13 @@ impl<'a> ExtCtxt<'a> {
let mut ctxt = self.backtrace();
let mut last_macro = None;
loop {
if ctxt.outer_expn_info().map_or(None, |info| {
if info.kind.descr() == sym::include {
// Stop going up the backtrace once include! is encountered
return None;
}
ctxt = info.call_site.ctxt();
last_macro = Some(info.call_site);
Some(())
}).is_none() {
break
let expn_info = ctxt.outer_expn_info();
// Stop going up the backtrace once include! is encountered
if expn_info.is_root() || expn_info.kind.descr() == sym::include {
break;
}
ctxt = expn_info.call_site.ctxt();
last_macro = Some(expn_info.call_site);
}
last_macro
}

View file

@ -475,7 +475,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
let info = self.cx.current_expansion.id.expn_info().unwrap();
let info = self.cx.current_expansion.id.expn_info();
let suggested_limit = self.cx.ecfg.recursion_limit * 2;
let mut err = self.cx.struct_span_err(info.call_site,
&format!("recursion limit reached while expanding the macro `{}`",

View file

@ -362,7 +362,7 @@ pub(crate) struct Rustc<'a> {
impl<'a> Rustc<'a> {
pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
// No way to determine def location for a proc macro right now, so use call location.
let location = cx.current_expansion.id.expn_info().unwrap().call_site;
let location = cx.current_expansion.id.expn_info().call_site;
let to_span = |transparency| {
location.with_ctxt(
SyntaxContext::root()
@ -677,7 +677,7 @@ impl server::Span for Rustc<'_> {
self.sess.source_map().lookup_char_pos(span.lo()).file
}
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
span.ctxt().outer_expn_info().map(|i| i.call_site)
span.parent()
}
fn source(&mut self, span: Self::Span) -> Self::Span {
span.source_callsite()

View file

@ -13,7 +13,6 @@ mod generics;
use crate::ast::{self, AttrStyle, Attribute, Arg, BindingMode, StrStyle, SelfKind};
use crate::ast::{FnDecl, Ident, IsAsync, MacDelimiter, Mutability, TyKind};
use crate::ast::{Visibility, VisibilityKind, Unsafety, CrateSugar};
use crate::ext::hygiene::SyntaxContext;
use crate::source_map::{self, respan};
use crate::parse::{SeqSep, literal, token};
use crate::parse::lexer::UnmatchedBrace;

View file

@ -31,12 +31,13 @@ mod tests;
/// otherwise return the call site span up to the `enclosing_sp` by
/// following the `expn_info` chain.
pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
let call_site1 = sp.ctxt().outer_expn_info().map(|ei| ei.call_site);
let call_site2 = enclosing_sp.ctxt().outer_expn_info().map(|ei| ei.call_site);
match (call_site1, call_site2) {
(None, _) => sp,
(Some(call_site1), Some(call_site2)) if call_site1 == call_site2 => sp,
(Some(call_site1), _) => original_sp(call_site1, enclosing_sp),
let expn_info1 = sp.ctxt().outer_expn_info();
let expn_info2 = enclosing_sp.ctxt().outer_expn_info();
if expn_info1.is_root() ||
!expn_info2.is_root() && expn_info1.call_site == expn_info2.call_site {
sp
} else {
original_sp(expn_info1.call_site, enclosing_sp)
}
}

View file

@ -112,8 +112,8 @@ impl ExpnId {
}
#[inline]
pub fn expn_info(self) -> Option<ExpnInfo> {
HygieneData::with(|data| data.expn_info(self).cloned())
pub fn expn_info(self) -> ExpnInfo {
HygieneData::with(|data| data.expn_info(self).clone())
}
#[inline]
@ -139,12 +139,9 @@ impl ExpnId {
#[inline]
pub fn looks_like_proc_macro_derive(self) -> bool {
HygieneData::with(|data| {
if data.default_transparency(self) == Transparency::Opaque {
if let Some(expn_info) = data.expn_info(self) {
if let ExpnKind::Macro(MacroKind::Derive, _) = expn_info.kind {
return true;
}
}
let expn_info = data.expn_info(self);
if let ExpnKind::Macro(MacroKind::Derive, _) = expn_info.kind {
return expn_info.default_transparency == Transparency::Opaque;
}
false
})
@ -190,16 +187,9 @@ impl HygieneData {
self.expn_data[expn_id.0 as usize].parent
}
fn expn_info(&self, expn_id: ExpnId) -> Option<&ExpnInfo> {
if expn_id != ExpnId::root() {
Some(self.expn_data[expn_id.0 as usize].expn_info.as_ref()
.expect("no expansion info for an expansion ID"))
} else {
// FIXME: Some code relies on `expn_info().is_none()` meaning "no expansion".
// Introduce a method for checking for "no expansion" instead and always return
// `ExpnInfo` from this function instead of the `Option`.
None
}
fn expn_info(&self, expn_id: ExpnId) -> &ExpnInfo {
self.expn_data[expn_id.0 as usize].expn_info.as_ref()
.expect("no expansion info for an expansion ID")
}
fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
@ -212,12 +202,6 @@ impl HygieneData {
true
}
fn default_transparency(&self, expn_id: ExpnId) -> Transparency {
self.expn_info(expn_id).map_or(
Transparency::SemiTransparent, |einfo| einfo.default_transparency
)
}
fn modern(&self, ctxt: SyntaxContext) -> SyntaxContext {
self.syntax_context_data[ctxt.0 as usize].opaque
}
@ -256,11 +240,7 @@ impl HygieneData {
fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
while span.from_expansion() && span.ctxt() != to {
if let Some(info) = self.expn_info(self.outer_expn(span.ctxt())) {
span = info.call_site;
} else {
break;
}
span = self.expn_info(self.outer_expn(span.ctxt())).call_site;
}
span
}
@ -275,7 +255,9 @@ impl HygieneData {
fn apply_mark(&mut self, ctxt: SyntaxContext, expn_id: ExpnId) -> SyntaxContext {
assert_ne!(expn_id, ExpnId::root());
self.apply_mark_with_transparency(ctxt, expn_id, self.default_transparency(expn_id))
self.apply_mark_with_transparency(
ctxt, expn_id, self.expn_info(expn_id).default_transparency
)
}
fn apply_mark_with_transparency(&mut self, ctxt: SyntaxContext, expn_id: ExpnId,
@ -285,8 +267,7 @@ impl HygieneData {
return self.apply_mark_internal(ctxt, expn_id, transparency);
}
let call_site_ctxt =
self.expn_info(expn_id).map_or(SyntaxContext::root(), |info| info.call_site.ctxt());
let call_site_ctxt = self.expn_info(expn_id).call_site.ctxt();
let mut call_site_ctxt = if transparency == Transparency::SemiTransparent {
self.modern(call_site_ctxt)
} else {
@ -581,17 +562,17 @@ impl SyntaxContext {
/// `ctxt.outer_expn_info()` is equivalent to but faster than
/// `ctxt.outer_expn().expn_info()`.
#[inline]
pub fn outer_expn_info(self) -> Option<ExpnInfo> {
HygieneData::with(|data| data.expn_info(data.outer_expn(self)).cloned())
pub fn outer_expn_info(self) -> ExpnInfo {
HygieneData::with(|data| data.expn_info(data.outer_expn(self)).clone())
}
/// `ctxt.outer_expn_with_info()` is equivalent to but faster than
/// `{ let outer = ctxt.outer_expn(); (outer, outer.expn_info()) }`.
#[inline]
pub fn outer_expn_with_info(self) -> (ExpnId, Option<ExpnInfo>) {
pub fn outer_expn_with_info(self) -> (ExpnId, ExpnInfo) {
HygieneData::with(|data| {
let outer = data.outer_expn(self);
(outer, data.expn_info(outer).cloned())
(outer, data.expn_info(outer).clone())
})
}
@ -681,6 +662,11 @@ impl ExpnInfo {
..ExpnInfo::default(kind, call_site, edition)
}
}
#[inline]
pub fn is_root(&self) -> bool {
if let ExpnKind::Root = self.kind { true } else { false }
}
}
/// Expansion kind.

View file

@ -355,20 +355,20 @@ impl Span {
/// Returns the source span -- this is either the supplied span, or the span for
/// the macro callsite that expanded to it.
pub fn source_callsite(self) -> Span {
self.ctxt().outer_expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self)
let expn_info = self.ctxt().outer_expn_info();
if !expn_info.is_root() { expn_info.call_site.source_callsite() } else { self }
}
/// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
/// if any.
pub fn parent(self) -> Option<Span> {
self.ctxt().outer_expn_info().map(|i| i.call_site)
let expn_info = self.ctxt().outer_expn_info();
if !expn_info.is_root() { Some(expn_info.call_site) } else { None }
}
/// Edition of the crate from which this span came.
pub fn edition(self) -> edition::Edition {
self.ctxt().outer_expn_info().map_or_else(|| {
Edition::from_session()
}, |einfo| einfo.edition)
self.ctxt().outer_expn_info().edition
}
#[inline]
@ -387,49 +387,39 @@ impl Span {
/// else returns the `ExpnInfo` for the macro definition
/// corresponding to the source callsite.
pub fn source_callee(self) -> Option<ExpnInfo> {
fn source_callee(info: ExpnInfo) -> ExpnInfo {
match info.call_site.ctxt().outer_expn_info() {
Some(info) => source_callee(info),
None => info,
}
fn source_callee(expn_info: ExpnInfo) -> ExpnInfo {
let next_expn_info = expn_info.call_site.ctxt().outer_expn_info();
if !next_expn_info.is_root() { source_callee(next_expn_info) } else { expn_info }
}
self.ctxt().outer_expn_info().map(source_callee)
let expn_info = self.ctxt().outer_expn_info();
if !expn_info.is_root() { Some(source_callee(expn_info)) } else { None }
}
/// Checks if a span is "internal" to a macro in which `#[unstable]`
/// items can be used (that is, a macro marked with
/// `#[allow_internal_unstable]`).
pub fn allows_unstable(&self, feature: Symbol) -> bool {
match self.ctxt().outer_expn_info() {
Some(info) => info
.allow_internal_unstable
.map_or(false, |features| features.iter().any(|&f|
f == feature || f == sym::allow_internal_unstable_backcompat_hack
)),
None => false,
}
self.ctxt().outer_expn_info().allow_internal_unstable.map_or(false, |features| {
features.iter().any(|&f| {
f == feature || f == sym::allow_internal_unstable_backcompat_hack
})
})
}
/// Checks if this span arises from a compiler desugaring of kind `kind`.
pub fn is_desugaring(&self, kind: DesugaringKind) -> bool {
match self.ctxt().outer_expn_info() {
Some(info) => match info.kind {
ExpnKind::Desugaring(k) => k == kind,
_ => false,
},
None => false,
match self.ctxt().outer_expn_info().kind {
ExpnKind::Desugaring(k) => k == kind,
_ => false,
}
}
/// Returns the compiler desugaring that created this span, or `None`
/// if this span is not from a desugaring.
pub fn desugaring_kind(&self) -> Option<DesugaringKind> {
match self.ctxt().outer_expn_info() {
Some(info) => match info.kind {
ExpnKind::Desugaring(k) => Some(k),
_ => None
},
None => None
match self.ctxt().outer_expn_info().kind {
ExpnKind::Desugaring(k) => Some(k),
_ => None
}
}
@ -437,16 +427,17 @@ impl Span {
/// can be used without triggering the `unsafe_code` lint
// (that is, a macro marked with `#[allow_internal_unsafe]`).
pub fn allows_unsafe(&self) -> bool {
match self.ctxt().outer_expn_info() {
Some(info) => info.allow_internal_unsafe,
None => false,
}
self.ctxt().outer_expn_info().allow_internal_unsafe
}
pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
let mut prev_span = DUMMY_SP;
let mut result = vec![];
while let Some(info) = self.ctxt().outer_expn_info() {
loop {
let info = self.ctxt().outer_expn_info();
if info.is_root() {
break;
}
// Don't print recursive invocations.
if !info.call_site.source_equal(&prev_span) {
let (pre, post) = match info.kind {