use profile::Count;
use syntax::{
ast::{
- self, ArgListOwner, ArrayExprKind, AstChildren, LiteralKind, LoopBodyOwner, NameOwner,
+ self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
SlicePatComponents,
},
AstNode, AstPtr, SyntaxNodePtr,
db::DefDatabase,
expr::{
dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, Label, LabelId, Literal, MatchArm,
- MatchGuard, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
+ Pat, PatId, RecordFieldPat, RecordLitField, Statement,
},
intern::Interned,
item_scope::BuiltinShadowMode,
self.body.params.push(param_pat);
}
- for param in param_list.params() {
- let pat = match param.pat() {
- None => continue,
- Some(pat) => pat,
- };
+ for pat in param_list.params().filter_map(|param| param.pat()) {
let param_pat = self.collect_pat(pat);
self.body.params.push(param_pat);
}
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
self.make_expr(expr, Err(SyntheticSyntax))
}
- fn unit(&mut self) -> ExprId {
- self.alloc_expr_desugared(Expr::Tuple { exprs: Vec::new() })
- }
fn missing_expr(&mut self) -> ExprId {
self.alloc_expr_desugared(Expr::Missing)
}
}
});
- let condition = match e.condition() {
- None => self.missing_expr(),
- Some(condition) => match condition.pat() {
- None => self.collect_expr_opt(condition.expr()),
- // if let -- desugar to match
- Some(pat) => {
- let pat = self.collect_pat(pat);
- let match_expr = self.collect_expr_opt(condition.expr());
- let placeholder_pat = self.missing_pat();
- let arms = vec![
- MatchArm { pat, expr: then_branch, guard: None },
- MatchArm {
- pat: placeholder_pat,
- expr: else_branch.unwrap_or_else(|| self.unit()),
- guard: None,
- },
- ];
- return Some(
- self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr),
- );
- }
- },
- };
+ let condition = self.collect_expr_opt(e.condition());
self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
}
- ast::Expr::EffectExpr(e) => match e.effect() {
- ast::Effect::Try(_) => {
- let body = self.collect_block_opt(e.block_expr());
+ ast::Expr::LetExpr(e) => {
+ let pat = self.collect_pat_opt(e.pat());
+ let expr = self.collect_expr_opt(e.expr());
+ self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
+ }
+ ast::Expr::BlockExpr(e) => match e.modifier() {
+ Some(ast::BlockModifier::Try(_)) => {
+ let body = self.collect_block(e);
self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
}
- ast::Effect::Unsafe(_) => {
- let body = self.collect_block_opt(e.block_expr());
+ Some(ast::BlockModifier::Unsafe(_)) => {
+ let body = self.collect_block(e);
self.alloc_expr(Expr::Unsafe { body }, syntax_ptr)
}
// FIXME: we need to record these effects somewhere...
- ast::Effect::Label(label) => {
+ Some(ast::BlockModifier::Label(label)) => {
let label = self.collect_label(label);
- match e.block_expr() {
- Some(block) => {
- let res = self.collect_block(block);
- match &mut self.body.exprs[res] {
- Expr::Block { label: block_label, .. } => {
- *block_label = Some(label);
- }
- _ => unreachable!(),
- }
- res
+ let res = self.collect_block(e);
+ match &mut self.body.exprs[res] {
+ Expr::Block { label: block_label, .. } => {
+ *block_label = Some(label);
}
- None => self.missing_expr(),
+ _ => unreachable!(),
}
+ res
}
- // FIXME: we need to record these effects somewhere...
- ast::Effect::Async(_) => {
- let body = self.collect_block_opt(e.block_expr());
+ Some(ast::BlockModifier::Async(_)) => {
+ let body = self.collect_block(e);
self.alloc_expr(Expr::Async { body }, syntax_ptr)
}
- ast::Effect::Const(_) => {
- let body = self.collect_block_opt(e.block_expr());
+ Some(ast::BlockModifier::Const(_)) => {
+ let body = self.collect_block(e);
self.alloc_expr(Expr::Const { body }, syntax_ptr)
}
+ None => self.collect_block(e),
},
- ast::Expr::BlockExpr(e) => self.collect_block(e),
ast::Expr::LoopExpr(e) => {
let label = e.label().map(|label| self.collect_label(label));
let body = self.collect_block_opt(e.loop_body());
let label = e.label().map(|label| self.collect_label(label));
let body = self.collect_block_opt(e.loop_body());
- let condition = match e.condition() {
- None => self.missing_expr(),
- Some(condition) => match condition.pat() {
- None => self.collect_expr_opt(condition.expr()),
- // if let -- desugar to match
- Some(pat) => {
- cov_mark::hit!(infer_resolve_while_let);
- let pat = self.collect_pat(pat);
- let match_expr = self.collect_expr_opt(condition.expr());
- let placeholder_pat = self.missing_pat();
- let break_ =
- self.alloc_expr_desugared(Expr::Break { expr: None, label: None });
- let arms = vec![
- MatchArm { pat, expr: body, guard: None },
- MatchArm { pat: placeholder_pat, expr: break_, guard: None },
- ];
- let match_expr =
- self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
- return Some(
- self.alloc_expr(Expr::Loop { body: match_expr, label }, syntax_ptr),
- );
- }
- },
- };
+ let condition = self.collect_expr_opt(e.condition());
self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
}
let args = if let Some(arg_list) = e.arg_list() {
arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
} else {
- Vec::new()
+ Box::default()
};
self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
}
let args = if let Some(arg_list) = e.arg_list() {
arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
} else {
- Vec::new()
+ Box::default()
};
let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
let generic_args = e
self.check_cfg(&arm).map(|()| MatchArm {
pat: self.collect_pat_opt(arm.pat()),
expr: self.collect_expr_opt(arm.expr()),
- guard: arm.guard().map(|guard| match guard.pat() {
- Some(pat) => MatchGuard::IfLet {
- pat: self.collect_pat(pat),
- expr: self.collect_expr_opt(guard.expr()),
- },
- None => {
- MatchGuard::If { expr: self.collect_expr_opt(guard.expr()) }
- }
- }),
+ guard: arm
+ .guard()
+ .map(|guard| self.collect_expr_opt(guard.condition())),
})
})
.collect()
} else {
- Vec::new()
+ Box::default()
};
self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
}
let spread = nfl.spread().map(|s| self.collect_expr(s));
Expr::RecordLit { path, fields, spread }
} else {
- Expr::RecordLit { path, fields: Vec::new(), spread: None }
+ Expr::RecordLit { path, fields: Box::default(), spread: None }
};
self.alloc_expr(record_lit, syntax_ptr)
}
ast::Expr::PrefixExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
- if let Some(op) = e.op_kind() {
- self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
- } else {
- self.alloc_expr(Expr::Missing, syntax_ptr)
+ match e.op_kind() {
+ Some(op) => self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),
+ None => self.alloc_expr(Expr::Missing, syntax_ptr),
}
}
ast::Expr::ClosureExpr(e) => {
.and_then(|r| r.ty())
.map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
let body = self.collect_expr_opt(e.body());
- self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
+ self.alloc_expr(
+ Expr::Lambda { args: args.into(), arg_types: arg_types.into(), ret_type, body },
+ syntax_ptr,
+ )
}
ast::Expr::BinExpr(e) => {
let lhs = self.collect_expr_opt(e.lhs());
ast::Expr::MacroCall(e) => {
let macro_ptr = AstPtr::new(&e);
let mut ids = vec![];
- self.collect_macro_call(e, macro_ptr, |this, expansion| {
+ self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
ids.push(match expansion {
Some(it) => this.collect_expr(it),
None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
&mut self,
e: ast::MacroCall,
syntax_ptr: AstPtr<ast::MacroCall>,
+ record_diagnostics: bool,
mut collector: F,
) {
// File containing the macro call. Expansion errors will be attached here.
let res = match res {
Ok(res) => res,
Err(UnresolvedMacro { path }) => {
- self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall {
- node: InFile::new(outer_file, syntax_ptr),
- path,
- });
+ if record_diagnostics {
+ self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall {
+ node: InFile::new(outer_file, syntax_ptr),
+ path,
+ });
+ }
collector(self, None);
return;
}
};
- match &res.err {
- Some(ExpandError::UnresolvedProcMacro) => {
- self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro {
- node: InFile::new(outer_file, syntax_ptr),
- });
- }
- Some(err) => {
- self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
- node: InFile::new(outer_file, syntax_ptr),
- message: err.to_string(),
- });
+ if record_diagnostics {
+ match &res.err {
+ Some(ExpandError::UnresolvedProcMacro) => {
+ self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro {
+ node: InFile::new(outer_file, syntax_ptr),
+ });
+ }
+ Some(err) => {
+ self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
+ node: InFile::new(outer_file, syntax_ptr),
+ message: err.to_string(),
+ });
+ }
+ None => {}
}
- None => {}
}
match res.value {
}
fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
- if let Some(expr) = expr {
- self.collect_expr(expr)
- } else {
- self.missing_expr()
+ match expr {
+ Some(expr) => self.collect_expr(expr),
+ None => self.missing_expr(),
}
}
let type_ref =
stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
let initializer = stmt.initializer().map(|e| self.collect_expr(e));
- self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
+ let else_branch = stmt
+ .let_else()
+ .and_then(|let_else| let_else.block_expr())
+ .map(|block| self.collect_block(block));
+ self.statements_in_scope.push(Statement::Let {
+ pat,
+ type_ref,
+ initializer,
+ else_branch,
+ });
}
ast::Stmt::ExprStmt(stmt) => {
- if self.check_cfg(&stmt).is_none() {
- return;
+ if let Some(expr) = stmt.expr() {
+ if self.check_cfg(&expr).is_none() {
+ return;
+ }
}
let has_semi = stmt.semicolon_token().is_some();
// Note that macro could be expended to multiple statements
let macro_ptr = AstPtr::new(&m);
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
- self.collect_macro_call(m, macro_ptr, |this, expansion| match expansion {
- Some(expansion) => {
- let statements: ast::MacroStmts = expansion;
-
- statements.statements().for_each(|stmt| this.collect_stmt(stmt));
- if let Some(expr) = statements.expr() {
- let expr = this.collect_expr(expr);
+ self.collect_macro_call(
+ m,
+ macro_ptr,
+ false,
+ |this, expansion| match expansion {
+ Some(expansion) => {
+ let statements: ast::MacroStmts = expansion;
+
+ statements.statements().for_each(|stmt| this.collect_stmt(stmt));
+ if let Some(expr) = statements.expr() {
+ let expr = this.collect_expr(expr);
+ this.statements_in_scope
+ .push(Statement::Expr { expr, has_semi });
+ }
+ }
+ None => {
+ let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
this.statements_in_scope.push(Statement::Expr { expr, has_semi });
}
- }
- None => {
- let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
- this.statements_in_scope.push(Statement::Expr { expr, has_semi });
- }
- });
+ },
+ );
} else {
let expr = self.collect_expr_opt(stmt.expr());
self.statements_in_scope.push(Statement::Expr { expr, has_semi });
}
}
- ast::Stmt::Item(item) => {
- self.check_cfg(&item);
- }
+ ast::Stmt::Item(_item) => {}
}
}
self.statements_in_scope.pop();
}
let tail = tail;
- let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements);
+ let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements).into();
let syntax_node_ptr = AstPtr::new(&block.into());
let expr_id = self.alloc_expr(
Expr::Block { id: block_id, statements, tail, label: None },
}
fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
- if let Some(block) = expr {
- self.collect_block(block)
- } else {
- self.missing_expr()
+ match expr {
+ Some(block) => self.collect_block(block),
+ None => self.missing_expr(),
}
}
ast::Pat::RecordPat(p) => {
let path =
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
- let args: Vec<_> = p
+ let args = p
.record_pat_field_list()
.expect("every struct should have a field list")
.fields()
let ellipsis = p
.record_pat_field_list()
.expect("every struct should have a field list")
- .dotdot_token()
+ .rest_pat()
.is_some();
Pat::Record { path, args, ellipsis }
Some(call) => {
let macro_ptr = AstPtr::new(&call);
let mut pat = None;
- self.collect_macro_call(call, macro_ptr, |this, expanded_pat| {
+ self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
pat = Some(this.collect_pat_opt(expanded_pat));
});
}
fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
- if let Some(pat) = pat {
- self.collect_pat(pat)
- } else {
- self.missing_pat()
+ match pat {
+ Some(pat) => self.collect_pat(pat),
+ None => self.missing_pat(),
}
}
- fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) {
+ fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Box<[PatId]>, Option<usize>) {
// Find the location of the `..`, if there is one. Note that we do not
// consider the possibility of there being multiple `..` here.
let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_)));
/// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
/// not.
- fn check_cfg(&mut self, owner: &dyn ast::AttrsOwner) -> Option<()> {
+ fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> Option<()> {
match self.expander.parse_attrs(self.db, owner).cfg() {
Some(cfg) => {
if self.expander.cfg_options().check(&cfg) != Some(false) {
Literal::Float(Default::default(), ty)
}
LiteralKind::ByteString(bs) => {
- let text = bs.value().map(Vec::from).unwrap_or_else(Default::default);
+ let text = bs.value().map(Box::from).unwrap_or_else(Default::default);
Literal::ByteString(text)
}
LiteralKind::String(_) => Literal::String(Default::default()),