Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/body/lower.rs')
-rw-r--r--crates/hir-def/src/body/lower.rs693
1 files changed, 496 insertions, 197 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 9c547574ec..0b108b54e6 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -9,9 +9,10 @@ use base_db::CrateId;
use either::Either;
use hir_expand::{
name::{AsName, Name},
- InFile,
+ span_map::{ExpansionSpanMap, SpanMap},
+ InFile, MacroDefId,
};
-use intern::{sym, Interned, Symbol};
+use intern::{sym, Symbol};
use rustc_hash::FxHashMap;
use span::AstIdMap;
use stdx::never;
@@ -22,10 +23,11 @@ use syntax::{
},
AstNode, AstPtr, AstToken as _, SyntaxNodePtr,
};
+use text_size::TextSize;
use triomphe::Arc;
use crate::{
- body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
+ body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, HygieneId, LabelPtr, PatPtr},
builtin_type::BuiltinUint,
data::adt::StructKind,
db::DefDatabase,
@@ -37,8 +39,8 @@ use crate::{
FormatPlaceholder, FormatSign, FormatTrait,
},
Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
- Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, OffsetOf, Pat,
- PatId, RecordFieldPat, RecordLitField, Statement,
+ Expr, ExprId, Item, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
+ OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
},
item_scope::BuiltinShadowMode,
lang_item::LangItem,
@@ -46,7 +48,7 @@ use crate::{
nameres::{DefMap, MacroSubNs},
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
- AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro,
+ AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, MacroId, ModuleDefId, UnresolvedMacro,
};
type FxIndexSet<K> = indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
@@ -60,6 +62,17 @@ pub(super) fn lower(
krate: CrateId,
is_async_fn: bool,
) -> (Body, BodySourceMap) {
+ // We cannot leave the root span map empty and let any identifier from it be treated as root,
+ // because when inside nested macros `SyntaxContextId`s from the outer macro will be interleaved
+ // with the inner macro, and that will cause confusion because they won't be the same as `ROOT`
+ // even though they should be the same. Also, when the body comes from multiple expansions, their
+ // hygiene is different.
+ let span_map = expander.current_file_id().macro_file().map(|_| {
+ let SpanMap::ExpansionSpanMap(span_map) = expander.span_map(db) else {
+ panic!("in a macro file there should be `ExpansionSpanMap`");
+ };
+ Arc::clone(span_map)
+ });
ExprCollector {
db,
owner,
@@ -70,11 +83,12 @@ pub(super) fn lower(
body: Body::default(),
expander,
current_try_block_label: None,
- is_lowering_assignee_expr: false,
is_lowering_coroutine: false,
label_ribs: Vec::new(),
current_binding_owner: None,
awaitable_context: None,
+ current_span_map: span_map,
+ current_block_legacy_macro_defs_count: FxHashMap::default(),
}
.collect(params, body, is_async_fn)
}
@@ -89,9 +103,14 @@ struct ExprCollector<'a> {
body: Body,
source_map: BodySourceMap,
- is_lowering_assignee_expr: bool,
is_lowering_coroutine: bool,
+ /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other,
+ /// and we need to find the current definition. So we track the number of definitions we saw.
+ current_block_legacy_macro_defs_count: FxHashMap<Name, usize>,
+
+ current_span_map: Option<Arc<ExpansionSpanMap>>,
+
current_try_block_label: Option<LabelId>,
// points to the expression that a try expression will target (replaces current_try_block_label)
// catch_scope: Option<ExprId>,
@@ -110,31 +129,27 @@ struct ExprCollector<'a> {
#[derive(Clone, Debug)]
struct LabelRib {
kind: RibKind,
- // Once we handle macro hygiene this will need to be a map
- label: Option<(Name, LabelId)>,
}
impl LabelRib {
fn new(kind: RibKind) -> Self {
- LabelRib { kind, label: None }
- }
- fn new_normal(label: (Name, LabelId)) -> Self {
- LabelRib { kind: RibKind::Normal, label: Some(label) }
+ LabelRib { kind }
}
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
enum RibKind {
- Normal,
+ Normal(Name, LabelId, HygieneId),
Closure,
Constant,
+ MacroDef(Box<MacroDefId>),
}
impl RibKind {
/// This rib forbids referring to labels defined in upwards ribs.
- fn is_label_barrier(self) -> bool {
+ fn is_label_barrier(&self) -> bool {
match self {
- RibKind::Normal => false,
+ RibKind::Normal(..) | RibKind::MacroDef(_) => false,
RibKind::Closure | RibKind::Constant => true,
}
}
@@ -147,7 +162,7 @@ enum Awaitable {
#[derive(Debug, Default)]
struct BindingList {
- map: FxHashMap<Name, BindingId>,
+ map: FxHashMap<(Name, HygieneId), BindingId>,
is_used: FxHashMap<BindingId, bool>,
reject_new: bool,
}
@@ -157,9 +172,16 @@ impl BindingList {
&mut self,
ec: &mut ExprCollector<'_>,
name: Name,
+ hygiene: HygieneId,
mode: BindingAnnotation,
) -> BindingId {
- let id = *self.map.entry(name).or_insert_with_key(|n| ec.alloc_binding(n.clone(), mode));
+ let id = *self.map.entry((name, hygiene)).or_insert_with_key(|(name, _)| {
+ let id = ec.alloc_binding(name.clone(), mode);
+ if !hygiene.is_root() {
+ ec.body.binding_hygiene.insert(id, hygiene);
+ }
+ id
+ });
if ec.body.bindings[id].mode != mode {
ec.body.bindings[id].problems = Some(BindingProblems::BoundInconsistently);
}
@@ -213,6 +235,13 @@ impl ExprCollector<'_> {
Name::new_symbol_root(sym::self_.clone()),
BindingAnnotation::new(is_mutable, false),
);
+ let hygiene = self_param
+ .name()
+ .map(|name| self.hygiene_id_for(name.syntax().text_range().start()))
+ .unwrap_or(HygieneId::ROOT);
+ if !hygiene.is_root() {
+ self.body.binding_hygiene.insert(binding_id, hygiene);
+ }
self.body.self_param = Some(binding_id);
self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param)));
}
@@ -245,8 +274,8 @@ impl ExprCollector<'_> {
(self.body, self.source_map)
}
- fn ctx(&self) -> LowerCtx<'_> {
- self.expander.ctx(self.db)
+ fn ctx(&mut self) -> LowerCtx<'_> {
+ self.expander.ctx(self.db, &mut self.body.types, &mut self.source_map.types)
}
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
@@ -290,13 +319,14 @@ impl ExprCollector<'_> {
})
}
Some(ast::BlockModifier::Label(label)) => {
- let label = self.collect_label(label);
- self.with_labeled_rib(label, |this| {
+ let label_hygiene = self.hygiene_id_for(label.syntax().text_range().start());
+ let label_id = self.collect_label(label);
+ self.with_labeled_rib(label_id, label_hygiene, |this| {
this.collect_block_(e, |id, statements, tail| Expr::Block {
id,
statements,
tail,
- label: Some(label),
+ label: Some(label_id),
})
})
}
@@ -338,9 +368,14 @@ impl ExprCollector<'_> {
None => self.collect_block(e),
},
ast::Expr::LoopExpr(e) => {
- let label = e.label().map(|label| self.collect_label(label));
+ let label = e.label().map(|label| {
+ (
+ self.hygiene_id_for(label.syntax().text_range().start()),
+ self.collect_label(label),
+ )
+ });
let body = self.collect_labelled_block_opt(label, e.loop_body());
- self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
+ self.alloc_expr(Expr::Loop { body, label: label.map(|it| it.1) }, syntax_ptr)
}
ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e),
ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
@@ -359,14 +394,7 @@ impl ExprCollector<'_> {
} else {
Box::default()
};
- self.alloc_expr(
- Expr::Call {
- callee,
- args,
- is_assignee_expr: self.is_lowering_assignee_expr,
- },
- syntax_ptr,
- )
+ self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
}
}
ast::Expr::MethodCallExpr(e) => {
@@ -407,12 +435,15 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
}
ast::Expr::PathExpr(e) => {
- let path = e
- .path()
- .and_then(|path| self.expander.parse_path(self.db, path))
- .map(Expr::Path)
- .unwrap_or(Expr::Missing);
- self.alloc_expr(path, syntax_ptr)
+ let (path, hygiene) = self
+ .collect_expr_path(e)
+ .map(|(path, hygiene)| (Expr::Path(path), hygiene))
+ .unwrap_or((Expr::Missing, HygieneId::ROOT));
+ let expr_id = self.alloc_expr(path, syntax_ptr);
+ if !hygiene.is_root() {
+ self.body.expr_hygiene.insert(expr_id, hygiene);
+ }
+ expr_id
}
ast::Expr::ContinueExpr(e) => {
let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
@@ -433,7 +464,7 @@ impl ExprCollector<'_> {
let inner = self.collect_expr_opt(e.expr());
// make the paren expr point to the inner expression as well for IDE resolution
let src = self.expander.in_file(syntax_ptr);
- self.source_map.expr_map.insert(src, inner);
+ self.source_map.expr_map.insert(src, inner.into());
inner
}
ast::Expr::ReturnExpr(e) => {
@@ -455,9 +486,7 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
}
ast::Expr::RecordExpr(e) => {
- let path =
- e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
- let is_assignee_expr = self.is_lowering_assignee_expr;
+ let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
let record_lit = if let Some(nfl) = e.record_expr_field_list() {
let fields = nfl
.fields()
@@ -476,16 +505,9 @@ impl ExprCollector<'_> {
})
.collect();
let spread = nfl.spread().map(|s| self.collect_expr(s));
- let ellipsis = nfl.dotdot_token().is_some();
- Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr }
+ Expr::RecordLit { path, fields, spread }
} else {
- Expr::RecordLit {
- path,
- fields: Box::default(),
- spread: None,
- ellipsis: false,
- is_assignee_expr,
- }
+ Expr::RecordLit { path, fields: Box::default(), spread: None }
};
self.alloc_expr(record_lit, syntax_ptr)
@@ -511,7 +533,7 @@ impl ExprCollector<'_> {
ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
ast::Expr::CastExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
- let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+ let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty());
self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
}
ast::Expr::RefExpr(e) => {
@@ -550,16 +572,13 @@ impl ExprCollector<'_> {
arg_types.reserve_exact(num_params);
for param in pl.params() {
let pat = this.collect_pat_top(param.pat());
- let type_ref =
- param.ty().map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
+ let type_ref = param.ty().map(|it| TypeRef::from_ast(&this.ctx(), it));
args.push(pat);
arg_types.push(type_ref);
}
}
- let ret_type = e
- .ret_type()
- .and_then(|r| r.ty())
- .map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
+ let ret_type =
+ e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&this.ctx(), it));
let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
let prev_try_block_label = this.current_try_block_label.take();
@@ -602,12 +621,14 @@ impl ExprCollector<'_> {
ast::Expr::BinExpr(e) => {
let op = e.op_kind();
if let Some(ast::BinaryOp::Assignment { op: None }) = op {
- self.is_lowering_assignee_expr = true;
+ let target = self.collect_expr_as_pat_opt(e.lhs());
+ let value = self.collect_expr_opt(e.rhs());
+ self.alloc_expr(Expr::Assignment { target, value }, syntax_ptr)
+ } else {
+ let lhs = self.collect_expr_opt(e.lhs());
+ let rhs = self.collect_expr_opt(e.rhs());
+ self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
}
- let lhs = self.collect_expr_opt(e.lhs());
- self.is_lowering_assignee_expr = false;
- let rhs = self.collect_expr_opt(e.rhs());
- self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
}
ast::Expr::TupleExpr(e) => {
let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect();
@@ -617,13 +638,7 @@ impl ExprCollector<'_> {
exprs.insert(0, self.missing_expr());
}
- self.alloc_expr(
- Expr::Tuple {
- exprs: exprs.into_boxed_slice(),
- is_assignee_expr: self.is_lowering_assignee_expr,
- },
- syntax_ptr,
- )
+ self.alloc_expr(Expr::Tuple { exprs: exprs.into_boxed_slice() }, syntax_ptr)
}
ast::Expr::ArrayExpr(e) => {
let kind = e.kind();
@@ -631,13 +646,7 @@ impl ExprCollector<'_> {
match kind {
ArrayExprKind::ElementList(e) => {
let elements = e.map(|expr| self.collect_expr(expr)).collect();
- self.alloc_expr(
- Expr::Array(Array::ElementList {
- elements,
- is_assignee_expr: self.is_lowering_assignee_expr,
- }),
- syntax_ptr,
- )
+ self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr)
}
ArrayExprKind::Repeat { initializer, repeat } => {
let initializer = self.collect_expr_opt(initializer);
@@ -664,8 +673,7 @@ impl ExprCollector<'_> {
ast::Expr::IndexExpr(e) => {
let base = self.collect_expr_opt(e.base());
let index = self.collect_expr_opt(e.index());
- let is_assignee_expr = self.is_lowering_assignee_expr;
- self.alloc_expr(Expr::Index { base, index, is_assignee_expr }, syntax_ptr)
+ self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
}
ast::Expr::RangeExpr(e) => {
let lhs = e.start().map(|lhs| self.collect_expr(lhs));
@@ -688,7 +696,7 @@ impl ExprCollector<'_> {
// Make the macro-call point to its expanded expression so we can query
// semantics on syntax pointers to the macro
let src = self.expander.in_file(syntax_ptr);
- self.source_map.expr_map.insert(src, id);
+ self.source_map.expr_map.insert(src, id.into());
id
}
None => self.alloc_expr(Expr::Missing, syntax_ptr),
@@ -697,7 +705,7 @@ impl ExprCollector<'_> {
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),
ast::Expr::OffsetOfExpr(e) => {
- let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+ let container = TypeRef::from_ast_opt(&self.ctx(), e.ty());
let fields = e.fields().map(|it| it.as_name()).collect();
self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
}
@@ -705,6 +713,200 @@ impl ExprCollector<'_> {
})
}
+ fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
+ self.expander.parse_path(self.db, path, &mut self.body.types, &mut self.source_map.types)
+ }
+
+ fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> {
+ e.path().and_then(|path| {
+ let path = self.parse_path(path)?;
+ // Need to enable `mod_path.len() < 1` for `self`.
+ let may_be_variable = matches!(&path, Path::BarePath(mod_path) if mod_path.len() <= 1);
+ let hygiene = if may_be_variable {
+ self.hygiene_id_for(e.syntax().text_range().start())
+ } else {
+ HygieneId::ROOT
+ };
+ Some((path, hygiene))
+ })
+ }
+
+ fn collect_expr_as_pat_opt(&mut self, expr: Option<ast::Expr>) -> PatId {
+ match expr {
+ Some(expr) => self.collect_expr_as_pat(expr),
+ _ => self.missing_pat(),
+ }
+ }
+
+ fn collect_expr_as_pat(&mut self, expr: ast::Expr) -> PatId {
+ self.maybe_collect_expr_as_pat(&expr).unwrap_or_else(|| {
+ let src = self.expander.in_file(AstPtr::new(&expr).wrap_left());
+ let expr = self.collect_expr(expr);
+ // Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`.
+ let id = self.body.pats.alloc(Pat::Expr(expr));
+ self.source_map.pat_map_back.insert(id, src);
+ id
+ })
+ }
+
+ fn maybe_collect_expr_as_pat(&mut self, expr: &ast::Expr) -> Option<PatId> {
+ self.check_cfg(expr)?;
+ let syntax_ptr = AstPtr::new(expr);
+
+ let result = match expr {
+ ast::Expr::UnderscoreExpr(_) => self.alloc_pat_from_expr(Pat::Wild, syntax_ptr),
+ ast::Expr::ParenExpr(e) => {
+ // We special-case `(..)` for consistency with patterns.
+ if let Some(ast::Expr::RangeExpr(range)) = e.expr() {
+ if range.is_range_full() {
+ return Some(self.alloc_pat_from_expr(
+ Pat::Tuple { args: Box::default(), ellipsis: Some(0) },
+ syntax_ptr,
+ ));
+ }
+ }
+ return e.expr().and_then(|expr| self.maybe_collect_expr_as_pat(&expr));
+ }
+ ast::Expr::TupleExpr(e) => {
+ let (ellipsis, args) = collect_tuple(self, e.fields());
+ self.alloc_pat_from_expr(Pat::Tuple { args, ellipsis }, syntax_ptr)
+ }
+ ast::Expr::ArrayExpr(e) => {
+ if e.semicolon_token().is_some() {
+ return None;
+ }
+
+ let mut elements = e.exprs();
+ let prefix = elements
+ .by_ref()
+ .map_while(|elem| collect_possibly_rest(self, elem).left())
+ .collect();
+ let suffix = elements.map(|elem| self.collect_expr_as_pat(elem)).collect();
+ self.alloc_pat_from_expr(Pat::Slice { prefix, slice: None, suffix }, syntax_ptr)
+ }
+ ast::Expr::CallExpr(e) => {
+ let path = collect_path(self, e.expr()?)?;
+ let path = path.path().and_then(|path| self.parse_path(path)).map(Box::new);
+ let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args());
+ self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr)
+ }
+ ast::Expr::PathExpr(e) => {
+ let (path, hygiene) = self
+ .collect_expr_path(e.clone())
+ .map(|(path, hygiene)| (Pat::Path(path), hygiene))
+ .unwrap_or((Pat::Missing, HygieneId::ROOT));
+ let pat_id = self.alloc_pat_from_expr(path, syntax_ptr);
+ if !hygiene.is_root() {
+ self.body.pat_hygiene.insert(pat_id, hygiene);
+ }
+ pat_id
+ }
+ ast::Expr::MacroExpr(e) => {
+ let e = e.macro_call()?;
+ let macro_ptr = AstPtr::new(&e);
+ let src = self.expander.in_file(AstPtr::new(expr));
+ let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
+ this.collect_expr_as_pat_opt(expansion)
+ });
+ self.source_map.expr_map.insert(src, id.into());
+ id
+ }
+ ast::Expr::RecordExpr(e) => {
+ let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
+ let record_field_list = e.record_expr_field_list()?;
+ let ellipsis = record_field_list.dotdot_token().is_some();
+ // FIXME: Report an error here if `record_field_list.spread().is_some()`.
+ let args = record_field_list
+ .fields()
+ .filter_map(|f| {
+ self.check_cfg(&f)?;
+ let field_expr = f.expr()?;
+ let pat = self.collect_expr_as_pat(field_expr);
+ let name = f.field_name()?.as_name();
+ let src = self.expander.in_file(AstPtr::new(&f).wrap_left());
+ self.source_map.pat_field_map_back.insert(pat, src);
+ Some(RecordFieldPat { name, pat })
+ })
+ .collect();
+ self.alloc_pat_from_expr(Pat::Record { path, args, ellipsis }, syntax_ptr)
+ }
+ _ => return None,
+ };
+ return Some(result);
+
+ fn collect_path(this: &mut ExprCollector<'_>, expr: ast::Expr) -> Option<ast::PathExpr> {
+ match expr {
+ ast::Expr::PathExpr(e) => Some(e),
+ ast::Expr::MacroExpr(mac) => {
+ let call = mac.macro_call()?;
+ {
+ let macro_ptr = AstPtr::new(&call);
+ this.collect_macro_call(call, macro_ptr, true, |this, expanded_path| {
+ collect_path(this, expanded_path?)
+ })
+ }
+ }
+ _ => None,
+ }
+ }
+
+ fn collect_possibly_rest(
+ this: &mut ExprCollector<'_>,
+ expr: ast::Expr,
+ ) -> Either<PatId, ()> {
+ match &expr {
+ ast::Expr::RangeExpr(e) if e.is_range_full() => Either::Right(()),
+ ast::Expr::MacroExpr(mac) => match mac.macro_call() {
+ Some(call) => {
+ let macro_ptr = AstPtr::new(&call);
+ let pat = this.collect_macro_call(
+ call,
+ macro_ptr,
+ true,
+ |this, expanded_expr| match expanded_expr {
+ Some(expanded_pat) => collect_possibly_rest(this, expanded_pat),
+ None => Either::Left(this.missing_pat()),
+ },
+ );
+ if let Either::Left(pat) = pat {
+ let src = this.expander.in_file(AstPtr::new(&expr).wrap_left());
+ this.source_map.pat_map_back.insert(pat, src);
+ }
+ pat
+ }
+ None => {
+ let ptr = AstPtr::new(&expr);
+ Either::Left(this.alloc_pat_from_expr(Pat::Missing, ptr))
+ }
+ },
+ _ => Either::Left(this.collect_expr_as_pat(expr)),
+ }
+ }
+
+ fn collect_tuple(
+ this: &mut ExprCollector<'_>,
+ fields: ast::AstChildren<ast::Expr>,
+ ) -> (Option<u32>, Box<[la_arena::Idx<Pat>]>) {
+ let mut ellipsis = None;
+ let args = fields
+ .enumerate()
+ .filter_map(|(idx, elem)| {
+ match collect_possibly_rest(this, elem) {
+ Either::Left(pat) => Some(pat),
+ Either::Right(()) => {
+ if ellipsis.is_none() {
+ ellipsis = Some(idx as u32);
+ }
+ // FIXME: Report an error here otherwise.
+ None
+ }
+ }
+ })
+ .collect();
+ (ellipsis, args)
+ }
+ }
+
fn initialize_binding_owner(
&mut self,
syntax_ptr: AstPtr<ast::Expr>,
@@ -744,7 +946,7 @@ impl ExprCollector<'_> {
let old_label = self.current_try_block_label.replace(label);
let ptr = AstPtr::new(&e).upcast();
- let (btail, expr_id) = self.with_labeled_rib(label, |this| {
+ let (btail, expr_id) = self.with_labeled_rib(label, HygieneId::ROOT, |this| {
let mut btail = None;
let block = this.collect_block_(e, |id, statements, tail| {
btail = tail;
@@ -755,17 +957,13 @@ impl ExprCollector<'_> {
let callee = self.alloc_expr_desugared_with_ptr(Expr::Path(try_from_output), ptr);
let next_tail = match btail {
- Some(tail) => self.alloc_expr_desugared_with_ptr(
- Expr::Call { callee, args: Box::new([tail]), is_assignee_expr: false },
- ptr,
- ),
+ Some(tail) => self
+ .alloc_expr_desugared_with_ptr(Expr::Call { callee, args: Box::new([tail]) }, ptr),
None => {
- let unit = self.alloc_expr_desugared_with_ptr(
- Expr::Tuple { exprs: Box::new([]), is_assignee_expr: false },
- ptr,
- );
+ let unit =
+ self.alloc_expr_desugared_with_ptr(Expr::Tuple { exprs: Box::new([]) }, ptr);
self.alloc_expr_desugared_with_ptr(
- Expr::Call { callee, args: Box::new([unit]), is_assignee_expr: false },
+ Expr::Call { callee, args: Box::new([unit]) },
ptr,
)
}
@@ -792,7 +990,9 @@ impl ExprCollector<'_> {
/// FIXME: Rustc wraps the condition in a construct equivalent to `{ let _t = <cond>; _t }`
/// to preserve drop semantics. We should probably do the same in future.
fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId {
- let label = e.label().map(|label| self.collect_label(label));
+ let label = e.label().map(|label| {
+ (self.hygiene_id_for(label.syntax().text_range().start()), self.collect_label(label))
+ });
let body = self.collect_labelled_block_opt(label, e.loop_body());
// Labels can also be used in the condition expression, like this:
@@ -809,9 +1009,9 @@ impl ExprCollector<'_> {
// }
// ```
let condition = match label {
- Some(label) => {
- self.with_labeled_rib(label, |this| this.collect_expr_opt(e.condition()))
- }
+ Some((label_hygiene, label)) => self.with_labeled_rib(label, label_hygiene, |this| {
+ this.collect_expr_opt(e.condition())
+ }),
None => self.collect_expr_opt(e.condition()),
};
@@ -820,7 +1020,7 @@ impl ExprCollector<'_> {
Expr::If { condition, then_branch: body, else_branch: Some(break_expr) },
syntax_ptr,
);
- self.alloc_expr(Expr::Loop { body: if_expr, label }, syntax_ptr)
+ self.alloc_expr(Expr::Loop { body: if_expr, label: label.map(|it| it.1) }, syntax_ptr)
}
/// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:
@@ -851,15 +1051,11 @@ impl ExprCollector<'_> {
let head = self.collect_expr_opt(e.iterable());
let into_iter_fn_expr = self.alloc_expr(Expr::Path(into_iter_fn), syntax_ptr);
let iterator = self.alloc_expr(
- Expr::Call {
- callee: into_iter_fn_expr,
- args: Box::new([head]),
- is_assignee_expr: false,
- },
+ Expr::Call { callee: into_iter_fn_expr, args: Box::new([head]) },
syntax_ptr,
);
let none_arm = MatchArm {
- pat: self.alloc_pat_desugared(Pat::Path(Box::new(option_none))),
+ pat: self.alloc_pat_desugared(Pat::Path(option_none)),
guard: None,
expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr),
};
@@ -868,7 +1064,9 @@ impl ExprCollector<'_> {
args: Box::new([self.collect_pat_top(e.pat())]),
ellipsis: None,
};
- let label = e.label().map(|label| self.collect_label(label));
+ let label = e.label().map(|label| {
+ (self.hygiene_id_for(label.syntax().text_range().start()), self.collect_label(label))
+ });
let some_arm = MatchArm {
pat: self.alloc_pat_desugared(some_pat),
guard: None,
@@ -884,11 +1082,7 @@ impl ExprCollector<'_> {
);
let iter_next_fn_expr = self.alloc_expr(Expr::Path(iter_next_fn), syntax_ptr);
let iter_next_expr = self.alloc_expr(
- Expr::Call {
- callee: iter_next_fn_expr,
- args: Box::new([iter_expr_mut]),
- is_assignee_expr: false,
- },
+ Expr::Call { callee: iter_next_fn_expr, args: Box::new([iter_expr_mut]) },
syntax_ptr,
);
let loop_inner = self.alloc_expr(
@@ -904,7 +1098,8 @@ impl ExprCollector<'_> {
},
syntax_ptr,
);
- let loop_outer = self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr);
+ let loop_outer = self
+ .alloc_expr(Expr::Loop { body: loop_inner, label: label.map(|it| it.1) }, syntax_ptr);
let iter_binding = self.alloc_binding(iter_name, BindingAnnotation::Mutable);
let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None });
self.add_definition_to_binding(iter_binding, iter_pat);
@@ -942,10 +1137,8 @@ impl ExprCollector<'_> {
};
let operand = self.collect_expr_opt(e.expr());
let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr);
- let expr = self.alloc_expr(
- Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false },
- syntax_ptr,
- );
+ let expr = self
+ .alloc_expr(Expr::Call { callee: try_branch, args: Box::new([operand]) }, syntax_ptr);
let continue_name = Name::generate_new_name(self.body.bindings.len());
let continue_binding =
self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated);
@@ -975,10 +1168,8 @@ impl ExprCollector<'_> {
expr: {
let it = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr);
let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr);
- let result = self.alloc_expr(
- Expr::Call { callee, args: Box::new([it]), is_assignee_expr: false },
- syntax_ptr,
- );
+ let result =
+ self.alloc_expr(Expr::Call { callee, args: Box::new([it]) }, syntax_ptr);
self.alloc_expr(
match self.current_try_block_label {
Some(label) => Expr::Break { expr: Some(result), label: Some(label) },
@@ -1065,7 +1256,14 @@ impl ExprCollector<'_> {
// FIXME: Report parse errors here
}
+ let SpanMap::ExpansionSpanMap(new_span_map) = self.expander.span_map(self.db)
+ else {
+ panic!("just expanded a macro, ExpansionSpanMap should be available");
+ };
+ let old_span_map =
+ mem::replace(&mut self.current_span_map, Some(new_span_map.clone()));
let id = collector(self, Some(expansion.tree()));
+ self.current_span_map = old_span_map;
self.ast_id_map = prev_ast_id_map;
self.expander.exit(mark);
id
@@ -1108,7 +1306,7 @@ impl ExprCollector<'_> {
// Make the macro-call point to its expanded expression so we can query
// semantics on syntax pointers to the macro
let src = self.expander.in_file(syntax_ptr);
- self.source_map.expr_map.insert(src, tail);
+ self.source_map.expr_map.insert(src, tail.into());
})
}
@@ -1119,8 +1317,7 @@ impl ExprCollector<'_> {
return;
}
let pat = self.collect_pat_top(stmt.pat());
- let type_ref =
- stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
+ let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
let initializer = stmt.initializer().map(|e| self.collect_expr(e));
let else_branch = stmt
.let_else()
@@ -1145,10 +1342,46 @@ impl ExprCollector<'_> {
statements.push(Statement::Expr { expr, has_semi });
}
}
- ast::Stmt::Item(_item) => statements.push(Statement::Item),
+ ast::Stmt::Item(ast::Item::MacroDef(macro_)) => {
+ let Some(name) = macro_.name() else {
+ statements.push(Statement::Item(Item::Other));
+ return;
+ };
+ let name = name.as_name();
+ let macro_id = self.def_map.modules[DefMap::ROOT].scope.get(&name).take_macros();
+ self.collect_macro_def(statements, macro_id);
+ }
+ ast::Stmt::Item(ast::Item::MacroRules(macro_)) => {
+ let Some(name) = macro_.name() else {
+ statements.push(Statement::Item(Item::Other));
+ return;
+ };
+ let name = name.as_name();
+ let macro_defs_count =
+ self.current_block_legacy_macro_defs_count.entry(name.clone()).or_insert(0);
+ let macro_id = self.def_map.modules[DefMap::ROOT]
+ .scope
+ .get_legacy_macro(&name)
+ .and_then(|it| it.get(*macro_defs_count))
+ .copied();
+ *macro_defs_count += 1;
+ self.collect_macro_def(statements, macro_id);
+ }
+ ast::Stmt::Item(_item) => statements.push(Statement::Item(Item::Other)),
}
}
+ fn collect_macro_def(&mut self, statements: &mut Vec<Statement>, macro_id: Option<MacroId>) {
+ let Some(macro_id) = macro_id else {
+ never!("def map should have macro definition, but it doesn't");
+ statements.push(Statement::Item(Item::Other));
+ return;
+ };
+ let macro_id = self.db.macro_def(macro_id);
+ statements.push(Statement::Item(Item::MacroDef(Box::new(macro_id))));
+ self.label_ribs.push(LabelRib::new(RibKind::MacroDef(Box::new(macro_id))));
+ }
+
fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
self.collect_block_(block, |id, statements, tail| Expr::Block {
id,
@@ -1194,6 +1427,7 @@ impl ExprCollector<'_> {
};
let prev_def_map = mem::replace(&mut self.def_map, def_map);
let prev_local_module = mem::replace(&mut self.expander.module, module);
+ let prev_legacy_macros_count = mem::take(&mut self.current_block_legacy_macro_defs_count);
let mut statements = Vec::new();
block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
@@ -1216,6 +1450,7 @@ impl ExprCollector<'_> {
self.def_map = prev_def_map;
self.expander.module = prev_local_module;
+ self.current_block_legacy_macro_defs_count = prev_legacy_macros_count;
expr_id
}
@@ -1228,11 +1463,13 @@ impl ExprCollector<'_> {
fn collect_labelled_block_opt(
&mut self,
- label: Option<LabelId>,
+ label: Option<(HygieneId, LabelId)>,
expr: Option<ast::BlockExpr>,
) -> ExprId {
match label {
- Some(label) => self.with_labeled_rib(label, |this| this.collect_block_opt(expr)),
+ Some((hygiene, label)) => {
+ self.with_labeled_rib(label, hygiene, |this| this.collect_block_opt(expr))
+ }
None => self.collect_block_opt(expr),
}
}
@@ -1250,6 +1487,10 @@ impl ExprCollector<'_> {
let pattern = match &pat {
ast::Pat::IdentPat(bp) => {
let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
+ let hygiene = bp
+ .name()
+ .map(|name| self.hygiene_id_for(name.syntax().text_range().start()))
+ .unwrap_or(HygieneId::ROOT);
let annotation =
BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
@@ -1285,12 +1526,12 @@ impl ExprCollector<'_> {
}
// shadowing statics is an error as well, so we just ignore that case here
_ => {
- let id = binding_list.find(self, name, annotation);
+ let id = binding_list.find(self, name, hygiene, annotation);
(Some(id), Pat::Bind { id, subpat })
}
}
} else {
- let id = binding_list.find(self, name, annotation);
+ let id = binding_list.find(self, name, hygiene, annotation);
(Some(id), Pat::Bind { id, subpat })
};
@@ -1302,8 +1543,7 @@ impl ExprCollector<'_> {
return pat;
}
ast::Pat::TupleStructPat(p) => {
- let path =
- p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+ let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
let (args, ellipsis) = self.collect_tuple_pat(
p.fields(),
comma_follows_token(p.l_paren_token()),
@@ -1317,8 +1557,7 @@ impl ExprCollector<'_> {
Pat::Ref { pat, mutability }
}
ast::Pat::PathPat(p) => {
- let path =
- p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+ let path = p.path().and_then(|path| self.parse_path(path));
path.map(Pat::Path).unwrap_or(Pat::Missing)
}
ast::Pat::OrPat(p) => 'b: {
@@ -1348,6 +1587,10 @@ impl ExprCollector<'_> {
for (id, _) in current_is_used.into_iter() {
binding_list.check_is_used(self, id);
}
+ if let &[pat] = &*pats {
+ // Leading pipe without real OR pattern. Leaving an one-item OR pattern may confuse later stages.
+ return pat;
+ }
Pat::Or(pats.into())
}
ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat(), binding_list),
@@ -1361,8 +1604,7 @@ impl ExprCollector<'_> {
}
ast::Pat::WildcardPat(_) => Pat::Wild,
ast::Pat::RecordPat(p) => {
- let path =
- p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+ let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
let record_pat_field_list =
&p.record_pat_field_list().expect("every struct should have a field list");
let args = record_pat_field_list
@@ -1372,7 +1614,7 @@ impl ExprCollector<'_> {
let ast_pat = f.pat()?;
let pat = self.collect_pat(ast_pat, binding_list);
let name = f.field_name()?.as_name();
- let src = self.expander.in_file(AstPtr::new(&f));
+ let src = self.expander.in_file(AstPtr::new(&f).wrap_right());
self.source_map.pat_field_map_back.insert(pat, src);
Some(RecordFieldPat { name, pat })
})
@@ -1569,20 +1811,51 @@ impl ExprCollector<'_> {
lifetime: Option<ast::Lifetime>,
) -> Result<Option<LabelId>, BodyDiagnostic> {
let Some(lifetime) = lifetime else { return Ok(None) };
+ let (mut hygiene_id, mut hygiene_info) = match &self.current_span_map {
+ None => (HygieneId::ROOT, None),
+ Some(span_map) => {
+ let span = span_map.span_at(lifetime.syntax().text_range().start());
+ let ctx = self.db.lookup_intern_syntax_context(span.ctx);
+ let hygiene_id = HygieneId::new(ctx.opaque_and_semitransparent);
+ let hygiene_info = ctx.outer_expn.map(|expansion| {
+ let expansion = self.db.lookup_intern_macro_call(expansion);
+ (ctx.parent, expansion.def)
+ });
+ (hygiene_id, hygiene_info)
+ }
+ };
let name = Name::new_lifetime(&lifetime);
for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() {
- if let Some((label_name, id)) = &rib.label {
- if *label_name == name {
- return if self.is_label_valid_from_rib(rib_idx) {
- Ok(Some(*id))
- } else {
- Err(BodyDiagnostic::UnreachableLabel {
- name,
- node: self.expander.in_file(AstPtr::new(&lifetime)),
- })
- };
+ match &rib.kind {
+ RibKind::Normal(label_name, id, label_hygiene) => {
+ if *label_name == name && *label_hygiene == hygiene_id {
+ return if self.is_label_valid_from_rib(rib_idx) {
+ Ok(Some(*id))
+ } else {
+ Err(BodyDiagnostic::UnreachableLabel {
+ name,
+ node: self.expander.in_file(AstPtr::new(&lifetime)),
+ })
+ };
+ }
}
+ RibKind::MacroDef(macro_id) => {
+ if let Some((parent_ctx, label_macro_id)) = hygiene_info {
+ if label_macro_id == **macro_id {
+ // A macro is allowed to refer to labels from before its declaration.
+ // Therefore, if we got to the rib of its declaration, give up its hygiene
+ // and use its parent expansion.
+ let parent_ctx = self.db.lookup_intern_syntax_context(parent_ctx);
+ hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent);
+ hygiene_info = parent_ctx.outer_expn.map(|expansion| {
+ let expansion = self.db.lookup_intern_macro_call(expansion);
+ (parent_ctx.parent, expansion.def)
+ });
+ }
+ }
+ }
+ _ => {}
}
}
@@ -1596,28 +1869,44 @@ impl ExprCollector<'_> {
!self.label_ribs[rib_index + 1..].iter().any(|rib| rib.kind.is_label_barrier())
}
+ fn pop_label_rib(&mut self) {
+ // We need to pop all macro defs, plus one rib.
+ while let Some(LabelRib { kind: RibKind::MacroDef(_) }) = self.label_ribs.pop() {
+ // Do nothing.
+ }
+ }
+
fn with_label_rib<T>(&mut self, kind: RibKind, f: impl FnOnce(&mut Self) -> T) -> T {
self.label_ribs.push(LabelRib::new(kind));
let res = f(self);
- self.label_ribs.pop();
+ self.pop_label_rib();
res
}
- fn with_labeled_rib<T>(&mut self, label: LabelId, f: impl FnOnce(&mut Self) -> T) -> T {
- self.label_ribs.push(LabelRib::new_normal((self.body[label].name.clone(), label)));
+ fn with_labeled_rib<T>(
+ &mut self,
+ label: LabelId,
+ hygiene: HygieneId,
+ f: impl FnOnce(&mut Self) -> T,
+ ) -> T {
+ self.label_ribs.push(LabelRib::new(RibKind::Normal(
+ self.body[label].name.clone(),
+ label,
+ hygiene,
+ )));
let res = f(self);
- self.label_ribs.pop();
+ self.pop_label_rib();
res
}
fn with_opt_labeled_rib<T>(
&mut self,
- label: Option<LabelId>,
+ label: Option<(HygieneId, LabelId)>,
f: impl FnOnce(&mut Self) -> T,
) -> T {
match label {
None => f(self),
- Some(label) => self.with_labeled_rib(label, f),
+ Some((hygiene, label)) => self.with_labeled_rib(label, hygiene, f),
}
}
// endregion: labels
@@ -1666,28 +1955,39 @@ impl ExprCollector<'_> {
_ => None,
});
let mut mappings = vec![];
- let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) {
+ let (fmt, hygiene) = match template.and_then(|it| self.expand_macros_to_string(it)) {
Some((s, is_direct_literal)) => {
let call_ctx = self.expander.syntax_context();
- format_args::parse(
+ let hygiene = self.hygiene_id_for(s.syntax().text_range().start());
+ let fmt = format_args::parse(
&s,
fmt_snippet,
args,
is_direct_literal,
- |name| self.alloc_expr_desugared(Expr::Path(Path::from(name))),
+ |name| {
+ let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
+ if !hygiene.is_root() {
+ self.body.expr_hygiene.insert(expr_id, hygiene);
+ }
+ expr_id
+ },
|name, span| {
if let Some(span) = span {
mappings.push((span, name))
}
},
call_ctx,
- )
+ );
+ (fmt, hygiene)
}
- None => FormatArgs {
- template: Default::default(),
- arguments: args.finish(),
- orphans: Default::default(),
- },
+ None => (
+ FormatArgs {
+ template: Default::default(),
+ arguments: args.finish(),
+ orphans: Default::default(),
+ },
+ HygieneId::ROOT,
+ ),
};
// Create a list of all _unique_ (argument, format trait) combinations.
@@ -1723,10 +2023,8 @@ impl ExprCollector<'_> {
}
})
.collect();
- let lit_pieces = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
- elements: lit_pieces,
- is_assignee_expr: false,
- }));
+ let lit_pieces =
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces }));
let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
expr: lit_pieces,
rawness: Rawness::Ref,
@@ -1743,10 +2041,7 @@ impl ExprCollector<'_> {
Some(self.make_format_spec(placeholder, &mut argmap))
})
.collect();
- let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
- elements,
- is_assignee_expr: false,
- }));
+ let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements }));
self.alloc_expr_desugared(Expr::Ref {
expr: array,
rawness: Rawness::Ref,
@@ -1756,10 +2051,8 @@ impl ExprCollector<'_> {
let arguments = &*fmt.arguments.arguments;
let args = if arguments.is_empty() {
- let expr = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
- elements: Box::default(),
- is_assignee_expr: false,
- }));
+ let expr = self
+ .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() }));
self.alloc_expr_desugared(Expr::Ref {
expr,
rawness: Rawness::Ref,
@@ -1786,10 +2079,8 @@ impl ExprCollector<'_> {
self.make_argument(arg, ty)
})
.collect();
- let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
- elements: args,
- is_assignee_expr: false,
- }));
+ let array =
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
self.alloc_expr_desugared(Expr::Ref {
expr: array,
rawness: Rawness::Ref,
@@ -1822,11 +2113,8 @@ impl ExprCollector<'_> {
let new_v1_formatted = self.alloc_expr_desugared(Expr::Path(new_v1_formatted));
let unsafe_arg_new = self.alloc_expr_desugared(Expr::Path(unsafe_arg_new));
- let unsafe_arg_new = self.alloc_expr_desugared(Expr::Call {
- callee: unsafe_arg_new,
- args: Box::default(),
- is_assignee_expr: false,
- });
+ let unsafe_arg_new =
+ self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() });
let unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
id: None,
// We collect the unused expressions here so that we still infer them instead of
@@ -1843,11 +2131,14 @@ impl ExprCollector<'_> {
Expr::Call {
callee: new_v1_formatted,
args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
- is_assignee_expr: false,
},
syntax_ptr,
);
- self.source_map.template_map.get_or_insert_with(Default::default).0.insert(idx, mappings);
+ self.source_map
+ .template_map
+ .get_or_insert_with(Default::default)
+ .0
+ .insert(idx, (hygiene, mappings));
idx
}
@@ -1938,7 +2229,6 @@ impl ExprCollector<'_> {
self.alloc_expr_desugared(Expr::Call {
callee: format_placeholder_new,
args: Box::new([position, fill, align, flags, precision, width]),
- is_assignee_expr: false,
})
}
@@ -1980,11 +2270,7 @@ impl ExprCollector<'_> {
Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)),
None => self.missing_expr(),
};
- self.alloc_expr_desugared(Expr::Call {
- callee: count_is,
- args: Box::new([args]),
- is_assignee_expr: false,
- })
+ self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) })
}
Some(FormatCount::Argument(arg)) => {
if let Ok(arg_index) = arg.index {
@@ -2005,7 +2291,6 @@ impl ExprCollector<'_> {
self.alloc_expr_desugared(Expr::Call {
callee: count_param,
args: Box::new([args]),
- is_assignee_expr: false,
})
} else {
// FIXME: This drops arg causing it to potentially not be resolved/type checked
@@ -2054,11 +2339,7 @@ impl ExprCollector<'_> {
Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)),
None => self.missing_expr(),
};
- self.alloc_expr_desugared(Expr::Call {
- callee: new_fn,
- args: Box::new([arg]),
- is_assignee_expr: false,
- })
+ self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) })
}
// endregion: format
@@ -2082,7 +2363,7 @@ impl ExprCollector<'_> {
let src = self.expander.in_file(ptr);
let id = self.body.exprs.alloc(expr);
self.source_map.expr_map_back.insert(id, src);
- self.source_map.expr_map.insert(src, id);
+ self.source_map.expr_map.insert(src, id.into());
id
}
// FIXME: desugared exprs don't have ptr, that's wrong and should be fixed.
@@ -2110,10 +2391,17 @@ impl ExprCollector<'_> {
binding
}
+ fn alloc_pat_from_expr(&mut self, pat: Pat, ptr: ExprPtr) -> PatId {
+ let src = self.expander.in_file(ptr);
+ let id = self.body.pats.alloc(pat);
+ self.source_map.expr_map.insert(src, id.into());
+ self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
+ id
+ }
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
let src = self.expander.in_file(ptr);
let id = self.body.pats.alloc(pat);
- self.source_map.pat_map_back.insert(id, src);
+ self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
self.source_map.pat_map.insert(src, id);
id
}
@@ -2151,6 +2439,17 @@ impl ExprCollector<'_> {
self.awaitable_context = orig;
res
}
+
+ /// If this returns `HygieneId::ROOT`, do not allocate to save space.
+ fn hygiene_id_for(&self, span_start: TextSize) -> HygieneId {
+ match &self.current_span_map {
+ None => HygieneId::ROOT,
+ Some(span_map) => {
+ let ctx = span_map.span_at(span_start).ctx;
+ HygieneId(self.db.lookup_intern_syntax_context(ctx).opaque_and_semitransparent)
+ }
+ }
+ }
}
fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {