1 //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
4 use std
::{mem, sync::Arc}
;
10 name
::{name, AsName, Name}
,
11 AstId
, ExpandError
, HirFileId
, InFile
,
14 use once_cell
::unsync
::OnceCell
;
16 use rustc_hash
::FxHashMap
;
19 self, ArrayExprKind
, AstChildren
, HasArgList
, HasLoopBody
, HasName
, LiteralKind
,
22 AstNode
, AstPtr
, SyntaxNodePtr
,
27 body
::{Body, BodySourceMap, Expander, ExprPtr, LabelPtr, LabelSource, PatPtr}
,
28 body
::{BodyDiagnostic, ExprSource, PatSource}
,
29 builtin_type
::{BuiltinFloat, BuiltinInt, BuiltinUint}
,
32 dummy_expr_id
, Array
, BindingAnnotation
, ClosureKind
, Expr
, ExprId
, FloatTypeWrapper
,
33 Label
, LabelId
, Literal
, MatchArm
, Movability
, Pat
, PatId
, RecordFieldPat
, RecordLitField
,
37 item_scope
::BuiltinShadowMode
,
38 path
::{GenericArgs, Path}
,
39 type_ref
::{Mutability, Rawness, TypeRef}
,
40 AdtId
, BlockLoc
, ModuleDefId
, UnresolvedMacro
,
43 pub struct LowerCtx
<'a
> {
44 pub db
: &'a
dyn DefDatabase
,
46 ast_id_map
: Option
<(HirFileId
, OnceCell
<Arc
<AstIdMap
>>)>,
49 impl<'a
> LowerCtx
<'a
> {
50 pub fn new(db
: &'a
dyn DefDatabase
, file_id
: HirFileId
) -> Self {
53 hygiene
: Hygiene
::new(db
.upcast(), file_id
),
54 ast_id_map
: Some((file_id
, OnceCell
::new())),
58 pub fn with_hygiene(db
: &'a
dyn DefDatabase
, hygiene
: &Hygiene
) -> Self {
59 LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: None }
62 pub(crate) fn hygiene(&self) -> &Hygiene
{
66 pub(crate) fn lower_path(&self, ast
: ast
::Path
) -> Option
<Path
> {
67 Path
::from_src(ast
, self)
70 pub(crate) fn ast_id
<N
: AstNode
>(&self, db
: &dyn DefDatabase
, item
: &N
) -> Option
<AstId
<N
>> {
71 let &(file_id
, ref ast_id_map
) = self.ast_id_map
.as_ref()?
;
72 let ast_id_map
= ast_id_map
.get_or_init(|| db
.ast_id_map(file_id
));
73 Some(InFile
::new(file_id
, ast_id_map
.ast_id(item
)))
80 params
: Option
<(ast
::ParamList
, impl Iterator
<Item
= bool
>)>,
81 body
: Option
<ast
::Expr
>,
82 ) -> (Body
, BodySourceMap
) {
85 source_map
: BodySourceMap
::default(),
86 ast_id_map
: db
.ast_id_map(expander
.current_file_id
),
88 exprs
: Arena
::default(),
89 pats
: Arena
::default(),
90 labels
: Arena
::default(),
92 body_expr
: dummy_expr_id(),
93 block_scopes
: Vec
::new(),
95 or_pats
: Default
::default(),
98 name_to_pat_grouping
: Default
::default(),
99 is_lowering_inside_or_pat
: false,
100 is_lowering_assignee_expr
: false,
101 is_lowering_generator
: false,
103 .collect(params
, body
)
106 struct ExprCollector
<'a
> {
107 db
: &'a
dyn DefDatabase
,
109 ast_id_map
: Arc
<AstIdMap
>,
111 source_map
: BodySourceMap
,
112 // a poor-mans union-find?
113 name_to_pat_grouping
: FxHashMap
<Name
, Vec
<PatId
>>,
114 is_lowering_inside_or_pat
: bool
,
115 is_lowering_assignee_expr
: bool
,
116 is_lowering_generator
: bool
,
119 impl ExprCollector
<'_
> {
122 param_list
: Option
<(ast
::ParamList
, impl Iterator
<Item
= bool
>)>,
123 body
: Option
<ast
::Expr
>,
124 ) -> (Body
, BodySourceMap
) {
125 if let Some((param_list
, mut attr_enabled
)) = param_list
{
126 if let Some(self_param
) =
127 param_list
.self_param().filter(|_
| attr_enabled
.next().unwrap_or(false))
129 let ptr
= AstPtr
::new(&self_param
);
130 let param_pat
= self.alloc_pat(
133 mode
: BindingAnnotation
::new(
134 self_param
.mut_token().is_some() && self_param
.amp_token().is_none(),
141 self.body
.params
.push(param_pat
);
144 for pat
in param_list
147 .filter_map(|(param
, enabled
)| param
.pat().filter(|_
| enabled
))
149 let param_pat
= self.collect_pat(pat
);
150 self.body
.params
.push(param_pat
);
154 self.body
.body_expr
= self.collect_expr_opt(body
);
155 (self.body
, self.source_map
)
158 fn ctx(&self) -> LowerCtx
<'_
> {
159 LowerCtx
::new(self.db
, self.expander
.current_file_id
)
162 fn alloc_expr(&mut self, expr
: Expr
, ptr
: ExprPtr
) -> ExprId
{
163 let src
= self.expander
.to_source(ptr
);
164 let id
= self.make_expr(expr
, src
.clone());
165 self.source_map
.expr_map
.insert(src
, id
);
168 // desugared exprs don't have ptr, that's wrong and should be fixed
170 fn alloc_expr_desugared(&mut self, expr
: Expr
) -> ExprId
{
171 self.body
.exprs
.alloc(expr
)
173 fn missing_expr(&mut self) -> ExprId
{
174 self.alloc_expr_desugared(Expr
::Missing
)
176 fn make_expr(&mut self, expr
: Expr
, src
: ExprSource
) -> ExprId
{
177 let id
= self.body
.exprs
.alloc(expr
);
178 self.source_map
.expr_map_back
.insert(id
, src
);
182 fn alloc_pat(&mut self, pat
: Pat
, ptr
: PatPtr
) -> PatId
{
183 let src
= self.expander
.to_source(ptr
);
184 let id
= self.make_pat(pat
, src
.clone());
185 self.source_map
.pat_map
.insert(src
, id
);
188 fn missing_pat(&mut self) -> PatId
{
189 self.body
.pats
.alloc(Pat
::Missing
)
191 fn make_pat(&mut self, pat
: Pat
, src
: PatSource
) -> PatId
{
192 let id
= self.body
.pats
.alloc(pat
);
193 self.source_map
.pat_map_back
.insert(id
, src
);
197 fn alloc_label(&mut self, label
: Label
, ptr
: LabelPtr
) -> LabelId
{
198 let src
= self.expander
.to_source(ptr
);
199 let id
= self.make_label(label
, src
.clone());
200 self.source_map
.label_map
.insert(src
, id
);
203 fn make_label(&mut self, label
: Label
, src
: LabelSource
) -> LabelId
{
204 let id
= self.body
.labels
.alloc(label
);
205 self.source_map
.label_map_back
.insert(id
, src
);
209 fn collect_expr(&mut self, expr
: ast
::Expr
) -> ExprId
{
210 self.maybe_collect_expr(expr
).unwrap_or_else(|| self.missing_expr())
213 /// Returns `None` if and only if the expression is `#[cfg]`d out.
214 fn maybe_collect_expr(&mut self, expr
: ast
::Expr
) -> Option
<ExprId
> {
215 let syntax_ptr
= AstPtr
::new(&expr
);
216 self.check_cfg(&expr
)?
;
219 ast
::Expr
::IfExpr(e
) => {
220 let then_branch
= self.collect_block_opt(e
.then_branch());
222 let else_branch
= e
.else_branch().map(|b
| match b
{
223 ast
::ElseBranch
::Block(it
) => self.collect_block(it
),
224 ast
::ElseBranch
::IfExpr(elif
) => {
225 let expr
: ast
::Expr
= ast
::Expr
::cast(elif
.syntax().clone()).unwrap();
226 self.collect_expr(expr
)
230 let condition
= self.collect_expr_opt(e
.condition());
232 self.alloc_expr(Expr
::If { condition, then_branch, else_branch }
, syntax_ptr
)
234 ast
::Expr
::LetExpr(e
) => {
235 let pat
= self.collect_pat_opt(e
.pat());
236 let expr
= self.collect_expr_opt(e
.expr());
237 self.alloc_expr(Expr
::Let { pat, expr }
, syntax_ptr
)
239 ast
::Expr
::BlockExpr(e
) => match e
.modifier() {
240 Some(ast
::BlockModifier
::Try(_
)) => {
241 let body
= self.collect_block(e
);
242 self.alloc_expr(Expr
::TryBlock { body }
, syntax_ptr
)
244 Some(ast
::BlockModifier
::Unsafe(_
)) => {
245 let body
= self.collect_block(e
);
246 self.alloc_expr(Expr
::Unsafe { body }
, syntax_ptr
)
248 // FIXME: we need to record these effects somewhere...
249 Some(ast
::BlockModifier
::Label(label
)) => {
250 let label
= self.collect_label(label
);
251 let res
= self.collect_block(e
);
252 match &mut self.body
.exprs
[res
] {
253 Expr
::Block { label: block_label, .. }
=> {
254 *block_label
= Some(label
);
260 Some(ast
::BlockModifier
::Async(_
)) => {
261 let body
= self.collect_block(e
);
262 self.alloc_expr(Expr
::Async { body }
, syntax_ptr
)
264 Some(ast
::BlockModifier
::Const(_
)) => {
265 let body
= self.collect_block(e
);
266 self.alloc_expr(Expr
::Const { body }
, syntax_ptr
)
268 None
=> self.collect_block(e
),
270 ast
::Expr
::LoopExpr(e
) => {
271 let label
= e
.label().map(|label
| self.collect_label(label
));
272 let body
= self.collect_block_opt(e
.loop_body());
273 self.alloc_expr(Expr
::Loop { body, label }
, syntax_ptr
)
275 ast
::Expr
::WhileExpr(e
) => {
276 let label
= e
.label().map(|label
| self.collect_label(label
));
277 let body
= self.collect_block_opt(e
.loop_body());
279 let condition
= self.collect_expr_opt(e
.condition());
281 self.alloc_expr(Expr
::While { condition, body, label }
, syntax_ptr
)
283 ast
::Expr
::ForExpr(e
) => {
284 let label
= e
.label().map(|label
| self.collect_label(label
));
285 let iterable
= self.collect_expr_opt(e
.iterable());
286 let pat
= self.collect_pat_opt(e
.pat());
287 let body
= self.collect_block_opt(e
.loop_body());
288 self.alloc_expr(Expr
::For { iterable, pat, body, label }
, syntax_ptr
)
290 ast
::Expr
::CallExpr(e
) => {
291 let callee
= self.collect_expr_opt(e
.expr());
292 let args
= if let Some(arg_list
) = e
.arg_list() {
293 arg_list
.args().filter_map(|e
| self.maybe_collect_expr(e
)).collect()
298 Expr
::Call { callee, args, is_assignee_expr: self.is_lowering_assignee_expr }
,
302 ast
::Expr
::MethodCallExpr(e
) => {
303 let receiver
= self.collect_expr_opt(e
.receiver());
304 let args
= if let Some(arg_list
) = e
.arg_list() {
305 arg_list
.args().filter_map(|e
| self.maybe_collect_expr(e
)).collect()
309 let method_name
= e
.name_ref().map(|nr
| nr
.as_name()).unwrap_or_else(Name
::missing
);
312 .and_then(|it
| GenericArgs
::from_ast(&self.ctx(), it
))
315 Expr
::MethodCall { receiver, method_name, args, generic_args }
,
319 ast
::Expr
::MatchExpr(e
) => {
320 let expr
= self.collect_expr_opt(e
.expr());
321 let arms
= if let Some(match_arm_list
) = e
.match_arm_list() {
325 self.check_cfg(&arm
).map(|()| MatchArm
{
326 pat
: self.collect_pat_opt(arm
.pat()),
327 expr
: self.collect_expr_opt(arm
.expr()),
330 .map(|guard
| self.collect_expr_opt(guard
.condition())),
337 self.alloc_expr(Expr
::Match { expr, arms }
, syntax_ptr
)
339 ast
::Expr
::PathExpr(e
) => {
342 .and_then(|path
| self.expander
.parse_path(self.db
, path
))
344 .unwrap_or(Expr
::Missing
);
345 self.alloc_expr(path
, syntax_ptr
)
347 ast
::Expr
::ContinueExpr(e
) => self.alloc_expr(
348 Expr
::Continue { label: e.lifetime().map(|l| Name::new_lifetime(&l)) }
,
351 ast
::Expr
::BreakExpr(e
) => {
352 let expr
= e
.expr().map(|e
| self.collect_expr(e
));
354 Expr
::Break { expr, label: e.lifetime().map(|l| Name::new_lifetime(&l)) }
,
358 ast
::Expr
::ParenExpr(e
) => {
359 let inner
= self.collect_expr_opt(e
.expr());
360 // make the paren expr point to the inner expression as well
361 let src
= self.expander
.to_source(syntax_ptr
);
362 self.source_map
.expr_map
.insert(src
, inner
);
365 ast
::Expr
::ReturnExpr(e
) => {
366 let expr
= e
.expr().map(|e
| self.collect_expr(e
));
367 self.alloc_expr(Expr
::Return { expr }
, syntax_ptr
)
369 ast
::Expr
::YieldExpr(e
) => {
370 self.is_lowering_generator
= true;
371 let expr
= e
.expr().map(|e
| self.collect_expr(e
));
372 self.alloc_expr(Expr
::Yield { expr }
, syntax_ptr
)
374 ast
::Expr
::YeetExpr(e
) => {
375 let expr
= e
.expr().map(|e
| self.collect_expr(e
));
376 self.alloc_expr(Expr
::Yeet { expr }
, syntax_ptr
)
378 ast
::Expr
::RecordExpr(e
) => {
380 e
.path().and_then(|path
| self.expander
.parse_path(self.db
, path
)).map(Box
::new
);
381 let is_assignee_expr
= self.is_lowering_assignee_expr
;
382 let record_lit
= if let Some(nfl
) = e
.record_expr_field_list() {
385 .filter_map(|field
| {
386 self.check_cfg(&field
)?
;
388 let name
= field
.field_name()?
.as_name();
390 let expr
= match field
.expr() {
391 Some(e
) => self.collect_expr(e
),
392 None
=> self.missing_expr(),
394 let src
= self.expander
.to_source(AstPtr
::new(&field
));
395 self.source_map
.field_map
.insert(src
.clone(), expr
);
396 self.source_map
.field_map_back
.insert(expr
, src
);
397 Some(RecordLitField { name, expr }
)
400 let spread
= nfl
.spread().map(|s
| self.collect_expr(s
));
401 let ellipsis
= nfl
.dotdot_token().is_some();
402 Expr
::RecordLit { path, fields, spread, ellipsis, is_assignee_expr }
406 fields
: Box
::default(),
413 self.alloc_expr(record_lit
, syntax_ptr
)
415 ast
::Expr
::FieldExpr(e
) => {
416 let expr
= self.collect_expr_opt(e
.expr());
417 let name
= match e
.field_access() {
418 Some(kind
) => kind
.as_name(),
419 _
=> Name
::missing(),
421 self.alloc_expr(Expr
::Field { expr, name }
, syntax_ptr
)
423 ast
::Expr
::AwaitExpr(e
) => {
424 let expr
= self.collect_expr_opt(e
.expr());
425 self.alloc_expr(Expr
::Await { expr }
, syntax_ptr
)
427 ast
::Expr
::TryExpr(e
) => {
428 let expr
= self.collect_expr_opt(e
.expr());
429 self.alloc_expr(Expr
::Try { expr }
, syntax_ptr
)
431 ast
::Expr
::CastExpr(e
) => {
432 let expr
= self.collect_expr_opt(e
.expr());
433 let type_ref
= Interned
::new(TypeRef
::from_ast_opt(&self.ctx(), e
.ty()));
434 self.alloc_expr(Expr
::Cast { expr, type_ref }
, syntax_ptr
)
436 ast
::Expr
::RefExpr(e
) => {
437 let expr
= self.collect_expr_opt(e
.expr());
438 let raw_tok
= e
.raw_token().is_some();
439 let mutability
= if raw_tok
{
440 if e
.mut_token().is_some() {
442 } else if e
.const_token().is_some() {
445 unreachable
!("parser only remaps to raw_token() if matching mutability token follows")
448 Mutability
::from_mutable(e
.mut_token().is_some())
450 let rawness
= Rawness
::from_raw(raw_tok
);
451 self.alloc_expr(Expr
::Ref { expr, rawness, mutability }
, syntax_ptr
)
453 ast
::Expr
::PrefixExpr(e
) => {
454 let expr
= self.collect_expr_opt(e
.expr());
456 Some(op
) => self.alloc_expr(Expr
::UnaryOp { expr, op }
, syntax_ptr
),
457 None
=> self.alloc_expr(Expr
::Missing
, syntax_ptr
),
460 ast
::Expr
::ClosureExpr(e
) => {
461 let mut args
= Vec
::new();
462 let mut arg_types
= Vec
::new();
463 if let Some(pl
) = e
.param_list() {
464 for param
in pl
.params() {
465 let pat
= self.collect_pat_opt(param
.pat());
467 param
.ty().map(|it
| Interned
::new(TypeRef
::from_ast(&self.ctx(), it
)));
469 arg_types
.push(type_ref
);
474 .and_then(|r
| r
.ty())
475 .map(|it
| Interned
::new(TypeRef
::from_ast(&self.ctx(), it
)));
477 let prev_is_lowering_generator
= self.is_lowering_generator
;
478 self.is_lowering_generator
= false;
480 let body
= self.collect_expr_opt(e
.body());
482 let closure_kind
= if self.is_lowering_generator
{
483 let movability
= if e
.static_token().is_some() {
488 ClosureKind
::Generator(movability
)
492 self.is_lowering_generator
= prev_is_lowering_generator
;
497 arg_types
: arg_types
.into(),
505 ast
::Expr
::BinExpr(e
) => {
506 let op
= e
.op_kind();
507 if let Some(ast
::BinaryOp
::Assignment { op: None }
) = op
{
508 self.is_lowering_assignee_expr
= true;
510 let lhs
= self.collect_expr_opt(e
.lhs());
511 self.is_lowering_assignee_expr
= false;
512 let rhs
= self.collect_expr_opt(e
.rhs());
513 self.alloc_expr(Expr
::BinaryOp { lhs, rhs, op }
, syntax_ptr
)
515 ast
::Expr
::TupleExpr(e
) => {
516 let exprs
= e
.fields().map(|expr
| self.collect_expr(expr
)).collect();
518 Expr
::Tuple { exprs, is_assignee_expr: self.is_lowering_assignee_expr }
,
522 ast
::Expr
::BoxExpr(e
) => {
523 let expr
= self.collect_expr_opt(e
.expr());
524 self.alloc_expr(Expr
::Box { expr }
, syntax_ptr
)
527 ast
::Expr
::ArrayExpr(e
) => {
531 ArrayExprKind
::ElementList(e
) => {
532 let elements
= e
.map(|expr
| self.collect_expr(expr
)).collect();
534 Expr
::Array(Array
::ElementList
{
536 is_assignee_expr
: self.is_lowering_assignee_expr
,
541 ArrayExprKind
::Repeat { initializer, repeat }
=> {
542 let initializer
= self.collect_expr_opt(initializer
);
543 let repeat
= self.collect_expr_opt(repeat
);
545 Expr
::Array(Array
::Repeat { initializer, repeat }
),
552 ast
::Expr
::Literal(e
) => self.alloc_expr(Expr
::Literal(e
.kind().into()), syntax_ptr
),
553 ast
::Expr
::IndexExpr(e
) => {
554 let base
= self.collect_expr_opt(e
.base());
555 let index
= self.collect_expr_opt(e
.index());
556 self.alloc_expr(Expr
::Index { base, index }
, syntax_ptr
)
558 ast
::Expr
::RangeExpr(e
) => {
559 let lhs
= e
.start().map(|lhs
| self.collect_expr(lhs
));
560 let rhs
= e
.end().map(|rhs
| self.collect_expr(rhs
));
562 Some(range_type
) => {
563 self.alloc_expr(Expr
::Range { lhs, rhs, range_type }
, syntax_ptr
)
565 None
=> self.alloc_expr(Expr
::Missing
, syntax_ptr
),
568 ast
::Expr
::MacroExpr(e
) => {
569 let e
= e
.macro_call()?
;
570 let macro_ptr
= AstPtr
::new(&e
);
571 let id
= self.collect_macro_call(e
, macro_ptr
, true, |this
, expansion
| {
572 expansion
.map(|it
| this
.collect_expr(it
))
576 // Make the macro-call point to its expanded expression so we can query
577 // semantics on syntax pointers to the macro
578 let src
= self.expander
.to_source(syntax_ptr
);
579 self.source_map
.expr_map
.insert(src
, id
);
582 None
=> self.alloc_expr(Expr
::Missing
, syntax_ptr
),
585 ast
::Expr
::UnderscoreExpr(_
) => self.alloc_expr(Expr
::Underscore
, syntax_ptr
),
589 fn collect_macro_call
<F
, T
, U
>(
591 mcall
: ast
::MacroCall
,
592 syntax_ptr
: AstPtr
<ast
::MacroCall
>,
593 record_diagnostics
: bool
,
597 F
: FnOnce(&mut Self, Option
<T
>) -> U
,
600 // File containing the macro call. Expansion errors will be attached here.
601 let outer_file
= self.expander
.current_file_id
;
603 let macro_call_ptr
= self.expander
.to_source(AstPtr
::new(&mcall
));
604 let res
= self.expander
.enter_expand(self.db
, mcall
);
606 let res
= match res
{
608 Err(UnresolvedMacro { path }
) => {
609 if record_diagnostics
{
610 self.source_map
.diagnostics
.push(BodyDiagnostic
::UnresolvedMacroCall
{
611 node
: InFile
::new(outer_file
, syntax_ptr
),
615 return collector(self, None
);
619 if record_diagnostics
{
621 Some(ExpandError
::UnresolvedProcMacro(krate
)) => {
622 self.source_map
.diagnostics
.push(BodyDiagnostic
::UnresolvedProcMacro
{
623 node
: InFile
::new(outer_file
, syntax_ptr
),
628 self.source_map
.diagnostics
.push(BodyDiagnostic
::MacroError
{
629 node
: InFile
::new(outer_file
, syntax_ptr
),
630 message
: err
.to_string(),
638 Some((mark
, expansion
)) => {
639 self.source_map
.expansions
.insert(macro_call_ptr
, self.expander
.current_file_id
);
640 let prev_ast_id_map
= mem
::replace(
641 &mut self.ast_id_map
,
642 self.db
.ast_id_map(self.expander
.current_file_id
),
645 let id
= collector(self, Some(expansion
));
646 self.ast_id_map
= prev_ast_id_map
;
647 self.expander
.exit(self.db
, mark
);
650 None
=> collector(self, None
),
654 fn collect_expr_opt(&mut self, expr
: Option
<ast
::Expr
>) -> ExprId
{
656 Some(expr
) => self.collect_expr(expr
),
657 None
=> self.missing_expr(),
661 fn collect_macro_as_stmt(
663 statements
: &mut Vec
<Statement
>,
665 ) -> Option
<ExprId
> {
666 let mac_call
= mac
.macro_call()?
;
667 let syntax_ptr
= AstPtr
::new(&ast
::Expr
::from(mac
));
668 let macro_ptr
= AstPtr
::new(&mac_call
);
669 let expansion
= self.collect_macro_call(
673 |this
, expansion
: Option
<ast
::MacroStmts
>| match expansion
{
675 expansion
.statements().for_each(|stmt
| this
.collect_stmt(statements
, stmt
));
676 expansion
.expr().and_then(|expr
| match expr
{
677 ast
::Expr
::MacroExpr(mac
) => this
.collect_macro_as_stmt(statements
, mac
),
678 expr
=> Some(this
.collect_expr(expr
)),
686 // Make the macro-call point to its expanded expression so we can query
687 // semantics on syntax pointers to the macro
688 let src
= self.expander
.to_source(syntax_ptr
);
689 self.source_map
.expr_map
.insert(src
, tail
);
696 fn collect_stmt(&mut self, statements
: &mut Vec
<Statement
>, s
: ast
::Stmt
) {
698 ast
::Stmt
::LetStmt(stmt
) => {
699 if self.check_cfg(&stmt
).is_none() {
702 let pat
= self.collect_pat_opt(stmt
.pat());
704 stmt
.ty().map(|it
| Interned
::new(TypeRef
::from_ast(&self.ctx(), it
)));
705 let initializer
= stmt
.initializer().map(|e
| self.collect_expr(e
));
706 let else_branch
= stmt
708 .and_then(|let_else
| let_else
.block_expr())
709 .map(|block
| self.collect_block(block
));
710 statements
.push(Statement
::Let { pat, type_ref, initializer, else_branch }
);
712 ast
::Stmt
::ExprStmt(stmt
) => {
713 let expr
= stmt
.expr();
715 Some(expr
) if self.check_cfg(expr
).is_none() => return,
718 let has_semi
= stmt
.semicolon_token().is_some();
719 // Note that macro could be expanded to multiple statements
720 if let Some(ast
::Expr
::MacroExpr(mac
)) = expr
{
721 if let Some(expr
) = self.collect_macro_as_stmt(statements
, mac
) {
722 statements
.push(Statement
::Expr { expr, has_semi }
)
725 let expr
= self.collect_expr_opt(expr
);
726 statements
.push(Statement
::Expr { expr, has_semi }
);
729 ast
::Stmt
::Item(_item
) => (),
733 fn collect_block(&mut self, block
: ast
::BlockExpr
) -> ExprId
{
734 let file_local_id
= self.ast_id_map
.ast_id(&block
);
735 let ast_id
= AstId
::new(self.expander
.current_file_id
, file_local_id
);
737 BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) }
;
738 let block_id
= self.db
.intern_block(block_loc
);
740 let (module
, def_map
) = match self.db
.block_def_map(block_id
) {
742 self.body
.block_scopes
.push(block_id
);
743 (def_map
.root(), def_map
)
745 None
=> (self.expander
.module
, self.expander
.def_map
.clone()),
747 let prev_def_map
= mem
::replace(&mut self.expander
.def_map
, def_map
);
748 let prev_local_module
= mem
::replace(&mut self.expander
.module
, module
);
750 let mut statements
= Vec
::new();
751 block
.statements().for_each(|s
| self.collect_stmt(&mut statements
, s
));
752 let tail
= block
.tail_expr().and_then(|e
| match e
{
753 ast
::Expr
::MacroExpr(mac
) => self.collect_macro_as_stmt(&mut statements
, mac
),
754 expr
=> self.maybe_collect_expr(expr
),
756 let tail
= tail
.or_else(|| {
757 let stmt
= statements
.pop()?
;
758 if let Statement
::Expr { expr, has_semi: false }
= stmt
{
761 statements
.push(stmt
);
765 let syntax_node_ptr
= AstPtr
::new(&block
.into());
766 let expr_id
= self.alloc_expr(
769 statements
: statements
.into_boxed_slice(),
776 self.expander
.def_map
= prev_def_map
;
777 self.expander
.module
= prev_local_module
;
781 fn collect_block_opt(&mut self, expr
: Option
<ast
::BlockExpr
>) -> ExprId
{
783 Some(block
) => self.collect_block(block
),
784 None
=> self.missing_expr(),
788 fn collect_label(&mut self, ast_label
: ast
::Label
) -> LabelId
{
790 name
: ast_label
.lifetime().as_ref().map_or_else(Name
::missing
, Name
::new_lifetime
),
792 self.alloc_label(label
, AstPtr
::new(&ast_label
))
795 fn collect_pat(&mut self, pat
: ast
::Pat
) -> PatId
{
796 let pat_id
= self.collect_pat_(pat
);
797 for (_
, pats
) in self.name_to_pat_grouping
.drain() {
798 let pats
= Arc
::<[_
]>::from(pats
);
799 self.body
.or_pats
.extend(pats
.iter().map(|&pat
| (pat
, pats
.clone())));
801 self.is_lowering_inside_or_pat
= false;
805 fn collect_pat_opt(&mut self, pat
: Option
<ast
::Pat
>) -> PatId
{
807 Some(pat
) => self.collect_pat(pat
),
808 None
=> self.missing_pat(),
812 fn collect_pat_(&mut self, pat
: ast
::Pat
) -> PatId
{
813 let pattern
= match &pat
{
814 ast
::Pat
::IdentPat(bp
) => {
815 let name
= bp
.name().map(|nr
| nr
.as_name()).unwrap_or_else(Name
::missing
);
817 let key
= self.is_lowering_inside_or_pat
.then(|| name
.clone());
819 BindingAnnotation
::new(bp
.mut_token().is_some(), bp
.ref_token().is_some());
820 let subpat
= bp
.pat().map(|subpat
| self.collect_pat_(subpat
));
821 let pattern
= if annotation
== BindingAnnotation
::Unannotated
&& subpat
.is_none() {
822 // This could also be a single-segment path pattern. To
823 // decide that, we need to try resolving the name.
824 let (resolved
, _
) = self.expander
.def_map
.resolve_path(
826 self.expander
.module
,
827 &name
.clone().into(),
828 BuiltinShadowMode
::Other
,
830 match resolved
.take_values() {
831 Some(ModuleDefId
::ConstId(_
)) => Pat
::Path(name
.into()),
832 Some(ModuleDefId
::EnumVariantId(_
)) => {
833 // this is only really valid for unit variants, but
834 // shadowing other enum variants with a pattern is
836 Pat
::Path(name
.into())
838 Some(ModuleDefId
::AdtId(AdtId
::StructId(s
)))
839 if self.db
.struct_data(s
).variant_data
.kind() != StructKind
::Record
=>
841 // Funnily enough, record structs *can* be shadowed
842 // by pattern bindings (but unit or tuple structs
844 Pat
::Path(name
.into())
846 // shadowing statics is an error as well, so we just ignore that case here
847 _
=> Pat
::Bind { name, mode: annotation, subpat }
,
850 Pat
::Bind { name, mode: annotation, subpat }
853 let ptr
= AstPtr
::new(&pat
);
854 let pat
= self.alloc_pat(pattern
, Either
::Left(ptr
));
855 if let Some(key
) = key
{
856 self.name_to_pat_grouping
.entry(key
).or_default().push(pat
);
860 ast
::Pat
::TupleStructPat(p
) => {
862 p
.path().and_then(|path
| self.expander
.parse_path(self.db
, path
)).map(Box
::new
);
863 let (args
, ellipsis
) = self.collect_tuple_pat(p
.fields());
864 Pat
::TupleStruct { path, args, ellipsis }
866 ast
::Pat
::RefPat(p
) => {
867 let pat
= self.collect_pat_opt(p
.pat());
868 let mutability
= Mutability
::from_mutable(p
.mut_token().is_some());
869 Pat
::Ref { pat, mutability }
871 ast
::Pat
::PathPat(p
) => {
873 p
.path().and_then(|path
| self.expander
.parse_path(self.db
, path
)).map(Box
::new
);
874 path
.map(Pat
::Path
).unwrap_or(Pat
::Missing
)
876 ast
::Pat
::OrPat(p
) => {
877 self.is_lowering_inside_or_pat
= true;
878 let pats
= p
.pats().map(|p
| self.collect_pat_(p
)).collect();
881 ast
::Pat
::ParenPat(p
) => return self.collect_pat_opt_(p
.pat()),
882 ast
::Pat
::TuplePat(p
) => {
883 let (args
, ellipsis
) = self.collect_tuple_pat(p
.fields());
884 Pat
::Tuple { args, ellipsis }
886 ast
::Pat
::WildcardPat(_
) => Pat
::Wild
,
887 ast
::Pat
::RecordPat(p
) => {
889 p
.path().and_then(|path
| self.expander
.parse_path(self.db
, path
)).map(Box
::new
);
891 .record_pat_field_list()
892 .expect("every struct should have a field list")
895 let ast_pat
= f
.pat()?
;
896 let pat
= self.collect_pat_(ast_pat
);
897 let name
= f
.field_name()?
.as_name();
898 Some(RecordFieldPat { name, pat }
)
903 .record_pat_field_list()
904 .expect("every struct should have a field list")
908 Pat
::Record { path, args, ellipsis }
910 ast
::Pat
::SlicePat(p
) => {
911 let SlicePatComponents { prefix, slice, suffix }
= p
.components();
913 // FIXME properly handle `RestPat`
915 prefix
: prefix
.into_iter().map(|p
| self.collect_pat_(p
)).collect(),
916 slice
: slice
.map(|p
| self.collect_pat_(p
)),
917 suffix
: suffix
.into_iter().map(|p
| self.collect_pat_(p
)).collect(),
920 ast
::Pat
::LiteralPat(lit
) => {
921 if let Some(ast_lit
) = lit
.literal() {
922 let expr
= Expr
::Literal(ast_lit
.kind().into());
923 let expr_ptr
= AstPtr
::new(&ast
::Expr
::Literal(ast_lit
));
924 let expr_id
= self.alloc_expr(expr
, expr_ptr
);
930 ast
::Pat
::RestPat(_
) => {
931 // `RestPat` requires special handling and should not be mapped
932 // to a Pat. Here we are using `Pat::Missing` as a fallback for
933 // when `RestPat` is mapped to `Pat`, which can easily happen
934 // when the source code being analyzed has a malformed pattern
935 // which includes `..` in a place where it isn't valid.
939 ast
::Pat
::BoxPat(boxpat
) => {
940 let inner
= self.collect_pat_opt_(boxpat
.pat());
943 ast
::Pat
::ConstBlockPat(const_block_pat
) => {
944 if let Some(expr
) = const_block_pat
.block_expr() {
945 let expr_id
= self.collect_block(expr
);
946 Pat
::ConstBlock(expr_id
)
951 ast
::Pat
::MacroPat(mac
) => match mac
.macro_call() {
953 let macro_ptr
= AstPtr
::new(&call
);
954 let src
= self.expander
.to_source(Either
::Left(AstPtr
::new(&pat
)));
956 self.collect_macro_call(call
, macro_ptr
, true, |this
, expanded_pat
| {
957 this
.collect_pat_opt_(expanded_pat
)
959 self.source_map
.pat_map
.insert(src
, pat
);
962 None
=> Pat
::Missing
,
965 ast
::Pat
::RangePat(_
) => Pat
::Missing
,
967 let ptr
= AstPtr
::new(&pat
);
968 self.alloc_pat(pattern
, Either
::Left(ptr
))
971 fn collect_pat_opt_(&mut self, pat
: Option
<ast
::Pat
>) -> PatId
{
973 Some(pat
) => self.collect_pat_(pat
),
974 None
=> self.missing_pat(),
978 fn collect_tuple_pat(&mut self, args
: AstChildren
<ast
::Pat
>) -> (Box
<[PatId
]>, Option
<usize>) {
979 // Find the location of the `..`, if there is one. Note that we do not
980 // consider the possibility of there being multiple `..` here.
981 let ellipsis
= args
.clone().position(|p
| matches
!(p
, ast
::Pat
::RestPat(_
)));
982 // We want to skip the `..` pattern here, since we account for it above.
984 .filter(|p
| !matches
!(p
, ast
::Pat
::RestPat(_
)))
985 .map(|p
| self.collect_pat_(p
))
991 /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
993 fn check_cfg(&mut self, owner
: &dyn ast
::HasAttrs
) -> Option
<()> {
994 match self.expander
.parse_attrs(self.db
, owner
).cfg() {
996 if self.expander
.cfg_options().check(&cfg
) != Some(false) {
1000 self.source_map
.diagnostics
.push(BodyDiagnostic
::InactiveCode
{
1002 self.expander
.current_file_id
,
1003 SyntaxNodePtr
::new(owner
.syntax()),
1006 opts
: self.expander
.cfg_options().clone(),
1016 impl From
<ast
::LiteralKind
> for Literal
{
1017 fn from(ast_lit_kind
: ast
::LiteralKind
) -> Self {
1018 match ast_lit_kind
{
1019 // FIXME: these should have actual values filled in, but unsure on perf impact
1020 LiteralKind
::IntNumber(lit
) => {
1021 if let builtin @
Some(_
) = lit
.suffix().and_then(BuiltinFloat
::from_suffix
) {
1023 FloatTypeWrapper
::new(lit
.float_value().unwrap_or(Default
::default())),
1026 } else if let builtin @
Some(_
) = lit
.suffix().and_then(BuiltinInt
::from_suffix
) {
1027 Literal
::Int(lit
.value().unwrap_or(0) as i128
, builtin
)
1029 let builtin
= lit
.suffix().and_then(BuiltinUint
::from_suffix
);
1030 Literal
::Uint(lit
.value().unwrap_or(0), builtin
)
1033 LiteralKind
::FloatNumber(lit
) => {
1034 let ty
= lit
.suffix().and_then(BuiltinFloat
::from_suffix
);
1035 Literal
::Float(FloatTypeWrapper
::new(lit
.value().unwrap_or(Default
::default())), ty
)
1037 LiteralKind
::ByteString(bs
) => {
1038 let text
= bs
.value().map(Box
::from
).unwrap_or_else(Default
::default);
1039 Literal
::ByteString(text
)
1041 LiteralKind
::String(s
) => {
1042 let text
= s
.value().map(Box
::from
).unwrap_or_else(Default
::default);
1043 Literal
::String(text
)
1045 LiteralKind
::Byte(b
) => {
1046 Literal
::Uint(b
.value().unwrap_or_default() as u128
, Some(BuiltinUint
::U8
))
1048 LiteralKind
::Char(c
) => Literal
::Char(c
.value().unwrap_or_default()),
1049 LiteralKind
::Bool(val
) => Literal
::Bool(val
),