//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
//! representation.
-use std::{any::type_name, mem, sync::Arc};
+use std::{mem, sync::Arc};
use either::Either;
use hir_expand::{
+ ast_id_map::{AstIdMap, FileAstId},
hygiene::Hygiene,
name::{name, AsName, Name},
- ExpandError, HirFileId, MacroDefId, MacroDefKind,
+ ExpandError, HirFileId,
};
use la_arena::Arena;
use profile::Count;
-use rustc_hash::FxHashMap;
use syntax::{
ast::{
self, ArgListOwner, ArrayExprKind, AstChildren, LiteralKind, LoopBodyOwner, NameOwner,
},
AstNode, AstPtr, SyntaxNodePtr,
};
-use test_utils::mark;
use crate::{
adt::StructKind,
body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
db::DefDatabase,
- diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro},
+ diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro},
expr::{
dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
Statement,
},
+ intern::Interned,
item_scope::BuiltinShadowMode,
- item_tree::{ItemTree, ItemTreeId, ItemTreeNode},
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
- AdtId, BlockLoc, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern,
- ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
+ AdtId, BlockLoc, ModuleDefId, UnresolvedMacro,
};
use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
-pub(crate) struct LowerCtx {
+pub struct LowerCtx<'a> {
+ pub db: &'a dyn DefDatabase,
hygiene: Hygiene,
+ file_id: Option<HirFileId>,
+ source_ast_id_map: Option<Arc<AstIdMap>>,
}
-impl LowerCtx {
- pub(crate) fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self {
- LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) }
+impl<'a> LowerCtx<'a> {
+ pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
+ LowerCtx {
+ db,
+ hygiene: Hygiene::new(db.upcast(), file_id),
+ file_id: Some(file_id),
+ source_ast_id_map: Some(db.ast_id_map(file_id)),
+ }
+ }
+
+ pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
+ LowerCtx { db, hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
+ }
+
+ pub(crate) fn hygiene(&self) -> &Hygiene {
+ &self.hygiene
}
- pub(crate) fn with_hygiene(hygiene: &Hygiene) -> Self {
- LowerCtx { hygiene: hygiene.clone() }
+
+ pub(crate) fn file_id(&self) -> HirFileId {
+ self.file_id.unwrap()
}
pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
- Path::from_src(ast, &self.hygiene)
+ Path::from_src(ast, self)
+ }
+
+ pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<FileAstId<N>> {
+ self.source_ast_id_map.as_ref().map(|ast_id_map| ast_id_map.ast_id(item))
}
}
pub(super) fn lower(
db: &dyn DefDatabase,
- def: DefWithBodyId,
expander: Expander,
params: Option<ast::ParamList>,
body: Option<ast::Expr>,
) -> (Body, BodySourceMap) {
- let item_tree = db.item_tree(expander.current_file_id);
ExprCollector {
db,
- def,
source_map: BodySourceMap::default(),
body: Body {
exprs: Arena::default(),
labels: Arena::default(),
params: Vec::new(),
body_expr: dummy_expr_id(),
- item_scope: Default::default(),
+ block_scopes: Vec::new(),
_c: Count::new(),
},
- item_trees: {
- let mut map = FxHashMap::default();
- map.insert(expander.current_file_id, item_tree);
- map
- },
expander,
+ statements_in_scope: Vec::new(),
}
.collect(params, body)
}
struct ExprCollector<'a> {
db: &'a dyn DefDatabase,
- def: DefWithBodyId,
expander: Expander,
body: Body,
source_map: BodySourceMap,
-
- item_trees: FxHashMap<HirFileId, Arc<ItemTree>>,
+ statements_in_scope: Vec<Statement>,
}
impl ExprCollector<'_> {
(self.body, self.source_map)
}
- fn ctx(&self) -> LowerCtx {
+ fn ctx(&self) -> LowerCtx<'_> {
LowerCtx::new(self.db, self.expander.current_file_id)
}
}
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
+ self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
+ }
+
+ /// Returns `None` if and only if the expression is `#[cfg]`d out.
+ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
let syntax_ptr = AstPtr::new(&expr);
- if self.check_cfg(&expr).is_none() {
- return self.missing_expr();
- }
+ self.check_cfg(&expr)?;
- match expr {
+ Some(match expr {
ast::Expr::IfExpr(e) => {
let then_branch = self.collect_block_opt(e.then_branch());
guard: None,
},
];
- return self
- .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr);
+ return Some(
+ self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr),
+ );
}
},
};
None => self.collect_expr_opt(condition.expr()),
// if let -- desugar to match
Some(pat) => {
- mark::hit!(infer_resolve_while_let);
+ 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 match_expr =
self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
- return self
- .alloc_expr(Expr::Loop { body: match_expr, label }, syntax_ptr);
+ return Some(
+ self.alloc_expr(Expr::Loop { body: match_expr, label }, syntax_ptr),
+ );
}
},
};
ast::Expr::CallExpr(e) => {
let callee = self.collect_expr_opt(e.expr());
let args = if let Some(arg_list) = e.arg_list() {
- arg_list.args().map(|e| self.collect_expr(e)).collect()
+ arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
} else {
Vec::new()
};
ast::Expr::MethodCallExpr(e) => {
let receiver = self.collect_expr_opt(e.receiver());
let args = if let Some(arg_list) = e.arg_list() {
- arg_list.args().map(|e| self.collect_expr(e)).collect()
+ arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
} else {
Vec::new()
};
let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
- let generic_args =
- e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it));
+ let generic_args = e
+ .generic_arg_list()
+ .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
+ .map(Box::new);
self.alloc_expr(
Expr::MethodCall { receiver, method_name, args, generic_args },
syntax_ptr,
ast::Expr::PathExpr(e) => {
let path = e
.path()
- .and_then(|path| self.expander.parse_path(path))
+ .and_then(|path| self.expander.parse_path(self.db, path))
.map(Expr::Path)
.unwrap_or(Expr::Missing);
self.alloc_expr(path, syntax_ptr)
self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
}
ast::Expr::RecordExpr(e) => {
- let path = e.path().and_then(|path| self.expander.parse_path(path));
- let mut field_ptrs = Vec::new();
+ let path =
+ e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let record_lit = if let Some(nfl) = e.record_expr_field_list() {
let fields = nfl
.fields()
- .inspect(|field| field_ptrs.push(AstPtr::new(field)))
.filter_map(|field| {
self.check_cfg(&field)?;
let name = field.field_name()?.as_name();
- Some(RecordLitField {
- name,
- expr: match field.expr() {
- Some(e) => self.collect_expr(e),
- None => self.missing_expr(),
- },
- })
+ let expr = match field.expr() {
+ Some(e) => self.collect_expr(e),
+ None => self.missing_expr(),
+ };
+ let src = self.expander.to_source(AstPtr::new(&field));
+ self.source_map.field_map.insert(src.clone(), expr);
+ self.source_map.field_map_back.insert(expr, src);
+ Some(RecordLitField { name, expr })
})
.collect();
let spread = nfl.spread().map(|s| self.collect_expr(s));
Expr::RecordLit { path, fields: Vec::new(), spread: None }
};
- let res = self.alloc_expr(record_lit, syntax_ptr);
- for (i, ptr) in field_ptrs.into_iter().enumerate() {
- let src = self.expander.to_source(ptr);
- self.source_map.field_map.insert((res, i), src);
- }
- res
+ self.alloc_expr(record_lit, syntax_ptr)
}
ast::Expr::FieldExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
}
ast::Expr::CastExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
- let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty());
+ let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
}
ast::Expr::RefExpr(e) => {
if let Some(pl) = e.param_list() {
for param in pl.params() {
let pat = self.collect_pat_opt(param.pat());
- let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
+ let type_ref =
+ param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
args.push(pat);
arg_types.push(type_ref);
}
}
- let ret_type =
- e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it));
+ let ret_type = e
+ .ret_type()
+ .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)
}
}
}
ast::Expr::MacroCall(e) => {
+ let macro_ptr = AstPtr::new(&e);
let mut ids = vec![];
- self.collect_macro_call(e, syntax_ptr.clone(), |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()),
});
ids[0]
}
- }
+ ast::Expr::MacroStmts(e) => {
+ e.statements().for_each(|s| self.collect_stmt(s));
+ let tail = e
+ .expr()
+ .map(|e| self.collect_expr(e))
+ .unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone()));
+
+ self.alloc_expr(Expr::MacroStmts { tail }, syntax_ptr)
+ }
+ })
}
fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
&mut self,
e: ast::MacroCall,
- syntax_ptr: AstPtr<ast::Expr>,
+ syntax_ptr: AstPtr<ast::MacroCall>,
+ is_error_recoverable: bool,
mut collector: F,
) {
// File containing the macro call. Expansion errors will be attached here.
let macro_call = self.expander.to_source(AstPtr::new(&e));
let res = self.expander.enter_expand(self.db, e);
+ let res = match res {
+ Ok(res) => res,
+ Err(UnresolvedMacro { path }) => {
+ self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall(
+ UnresolvedMacroCall {
+ file: outer_file,
+ node: syntax_ptr.cast().unwrap(),
+ path,
+ },
+ ));
+ collector(self, None);
+ return;
+ }
+ };
+
match &res.err {
Some(ExpandError::UnresolvedProcMacro) => {
self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
Some((mark, expansion)) => {
// FIXME: Statements are too complicated to recover from error for now.
// It is because we don't have any hygiene for local variable expansion right now.
- if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
+ if !is_error_recoverable && res.err.is_some() {
self.expander.exit(self.db, mark);
collector(self, None);
} else {
self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
- let item_tree = self.db.item_tree(self.expander.current_file_id);
- self.item_trees.insert(self.expander.current_file_id, item_tree);
-
let id = collector(self, Some(expansion));
self.expander.exit(self.db, mark);
id
}
}
- fn find_inner_item<N: ItemTreeNode>(&self, ast: &N::Source) -> Option<ItemTreeId<N>> {
- let id = self.expander.ast_id(ast);
- let tree = &self.item_trees[&id.file_id];
-
- // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes
-
- // Root file (non-macro).
- let item_tree_id = tree
- .all_inner_items()
- .chain(tree.top_level_items().iter().copied())
- .filter_map(|mod_item| mod_item.downcast::<N>())
- .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value.upcast())
- .or_else(|| {
- log::debug!(
- "couldn't find inner {} item for {:?} (AST: `{}` - {:?})",
- type_name::<N>(),
- id,
- ast.syntax(),
- ast.syntax(),
- );
- None
- })?;
-
- Some(ItemTreeId::new(id.file_id, item_tree_id))
- }
-
fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
if let Some(expr) = expr {
self.collect_expr(expr)
}
}
- fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
- let stmt =
- match s {
- ast::Stmt::LetStmt(stmt) => {
- self.check_cfg(&stmt)?;
-
- let pat = self.collect_pat_opt(stmt.pat());
- let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
- let initializer = stmt.initializer().map(|e| self.collect_expr(e));
- vec![Statement::Let { pat, type_ref, initializer }]
+ fn collect_stmt(&mut self, s: ast::Stmt) {
+ match s {
+ ast::Stmt::LetStmt(stmt) => {
+ if self.check_cfg(&stmt).is_none() {
+ return;
}
- ast::Stmt::ExprStmt(stmt) => {
- self.check_cfg(&stmt)?;
-
- // Note that macro could be expended to multiple statements
- if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
- let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
- let mut stmts = vec![];
-
- self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| {
- match expansion {
- Some(expansion) => {
- let statements: ast::MacroStmts = expansion;
- this.collect_stmts_items(statements.statements());
-
- statements.statements().for_each(|stmt| {
- if let Some(mut r) = this.collect_stmt(stmt) {
- stmts.append(&mut r);
- }
- });
- if let Some(expr) = statements.expr() {
- stmts.push(Statement::Expr(this.collect_expr(expr)));
- }
- }
- None => {
- stmts.push(Statement::Expr(
- this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
- ));
+ let pat = self.collect_pat_opt(stmt.pat());
+ 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 });
+ }
+ ast::Stmt::ExprStmt(stmt) => {
+ if self.check_cfg(&stmt).is_none() {
+ return;
+ }
+ let has_semi = stmt.semicolon_token().is_some();
+ // Note that macro could be expended to multiple statements
+ if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
+ let macro_ptr = AstPtr::new(&m);
+ let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
+
+ 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 });
}
}
- });
- stmts
- } else {
- vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
- }
+ 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)?;
-
- return None;
+ }
+ ast::Stmt::Item(item) => {
+ if self.check_cfg(&item).is_none() {
+ return;
}
- };
-
- Some(stmt)
+ }
+ }
}
fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
let block_loc =
BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
let block_id = self.db.intern_block(block_loc);
- let opt_def_map = self.db.block_def_map(block_id);
- let has_def_map = opt_def_map.is_some();
- let def_map = opt_def_map.unwrap_or_else(|| self.expander.def_map.clone());
- let module = if has_def_map { def_map.root() } else { self.expander.module };
+
+ let (module, def_map) = match self.db.block_def_map(block_id) {
+ Some(def_map) => {
+ self.body.block_scopes.push(block_id);
+ (def_map.root(), def_map)
+ }
+ None => (self.expander.module, self.expander.def_map.clone()),
+ };
let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
let prev_local_module = mem::replace(&mut self.expander.module, module);
-
- self.collect_stmts_items(block.statements());
- let statements =
- block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
- let tail = block.tail_expr().map(|e| self.collect_expr(e));
+ let prev_statements = std::mem::take(&mut self.statements_in_scope);
+
+ block.statements().for_each(|s| self.collect_stmt(s));
+ block.tail_expr().and_then(|e| {
+ let expr = self.maybe_collect_expr(e)?;
+ Some(self.statements_in_scope.push(Statement::Expr { expr, has_semi: false }))
+ });
+
+ let mut tail = None;
+ if let Some(Statement::Expr { expr, has_semi: false }) = self.statements_in_scope.last() {
+ tail = Some(*expr);
+ self.statements_in_scope.pop();
+ }
+ let tail = tail;
+ let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements);
let syntax_node_ptr = AstPtr::new(&block.into());
let expr_id = self.alloc_expr(
Expr::Block { id: block_id, statements, tail, label: None },
expr_id
}
- fn collect_stmts_items(&mut self, stmts: ast::AstChildren<ast::Stmt>) {
- let container = ContainerId::DefWithBodyId(self.def);
-
- let items = stmts
- .filter_map(|stmt| match stmt {
- ast::Stmt::Item(it) => Some(it),
- ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None,
- })
- .filter_map(|item| {
- let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
- ast::Item::Fn(def) => {
- let id = self.find_inner_item(&def)?;
- (
- FunctionLoc { container: container.into(), id }.intern(self.db).into(),
- def.name(),
- )
- }
- ast::Item::TypeAlias(def) => {
- let id = self.find_inner_item(&def)?;
- (
- TypeAliasLoc { container: container.into(), id }.intern(self.db).into(),
- def.name(),
- )
- }
- ast::Item::Const(def) => {
- let id = self.find_inner_item(&def)?;
- (
- ConstLoc { container: container.into(), id }.intern(self.db).into(),
- def.name(),
- )
- }
- ast::Item::Static(def) => {
- let id = self.find_inner_item(&def)?;
- (StaticLoc { container, id }.intern(self.db).into(), def.name())
- }
- ast::Item::Struct(def) => {
- let id = self.find_inner_item(&def)?;
- (StructLoc { container, id }.intern(self.db).into(), def.name())
- }
- ast::Item::Enum(def) => {
- let id = self.find_inner_item(&def)?;
- (EnumLoc { container, id }.intern(self.db).into(), def.name())
- }
- ast::Item::Union(def) => {
- let id = self.find_inner_item(&def)?;
- (UnionLoc { container, id }.intern(self.db).into(), def.name())
- }
- ast::Item::Trait(def) => {
- let id = self.find_inner_item(&def)?;
- (TraitLoc { container, id }.intern(self.db).into(), def.name())
- }
- ast::Item::ExternBlock(_) => return None, // FIXME: collect from extern blocks
- ast::Item::Impl(_)
- | ast::Item::Use(_)
- | ast::Item::ExternCrate(_)
- | ast::Item::Module(_)
- | ast::Item::MacroCall(_) => return None,
- ast::Item::MacroRules(def) => {
- return Some(Either::Right(ast::Macro::from(def)));
- }
- ast::Item::MacroDef(def) => {
- return Some(Either::Right(ast::Macro::from(def)));
- }
- };
-
- Some(Either::Left((def, name)))
- })
- .collect::<Vec<_>>();
-
- for either in items {
- match either {
- Either::Left((def, name)) => {
- self.body.item_scope.define_def(def);
- if let Some(name) = name {
- let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
- let has_constructor = match def {
- ModuleDefId::AdtId(AdtId::StructId(s)) => {
- self.db.struct_data(s).variant_data.kind() != StructKind::Record
- }
- _ => true,
- };
- self.body.item_scope.push_res(
- name.as_name(),
- crate::per_ns::PerNs::from_def(def, vis, has_constructor),
- );
- }
- }
- Either::Right(e) => {
- let mac = MacroDefId {
- krate: self.expander.def_map.krate(),
- ast_id: Some(self.expander.ast_id(&e)),
- kind: MacroDefKind::Declarative,
- local_inner: false,
- };
- if let Some(name) = e.name() {
- self.body.item_scope.define_legacy_macro(name.as_name(), mac);
- }
- }
- }
- }
- }
-
fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
if let Some(block) = expr {
self.collect_block(block)
}
}
ast::Pat::TupleStructPat(p) => {
- let path = p.path().and_then(|path| self.expander.parse_path(path));
+ let path =
+ p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let (args, ellipsis) = self.collect_tuple_pat(p.fields());
Pat::TupleStruct { path, args, ellipsis }
}
Pat::Ref { pat, mutability }
}
ast::Pat::PathPat(p) => {
- let path = p.path().and_then(|path| self.expander.parse_path(path));
+ let path =
+ p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
path.map(Pat::Path).unwrap_or(Pat::Missing)
}
ast::Pat::OrPat(p) => {
}
ast::Pat::WildcardPat(_) => Pat::Wild,
ast::Pat::RecordPat(p) => {
- let path = p.path().and_then(|path| self.expander.parse_path(path));
+ let path =
+ p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let args: Vec<_> = p
.record_pat_field_list()
.expect("every struct should have a field list")
Pat::Missing
}
}
+ ast::Pat::MacroPat(mac) => match mac.macro_call() {
+ Some(call) => {
+ let macro_ptr = AstPtr::new(&call);
+ let mut pat = None;
+ self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
+ pat = Some(this.collect_pat_opt(expanded_pat));
+ });
+
+ match pat {
+ Some(pat) => return pat,
+ None => Pat::Missing,
+ }
+ }
+ None => Pat::Missing,
+ },
// FIXME: implement
- ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
+ ast::Pat::RangePat(_) => Pat::Missing,
};
let ptr = AstPtr::new(&pat);
self.alloc_pat(pattern, Either::Left(ptr))
let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
Literal::Float(Default::default(), ty)
}
- LiteralKind::ByteString(_) => Literal::ByteString(Default::default()),
+ LiteralKind::ByteString(bs) => {
+ let text = bs.value().map(Vec::from).unwrap_or_else(Default::default);
+ Literal::ByteString(text)
+ }
LiteralKind::String(_) => Literal::String(Default::default()),
LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
LiteralKind::Bool(val) => Literal::Bool(val),