mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 22:31:43 +00:00
Track labels in the HIR
This commit is contained in:
parent
fd1fcf2c2e
commit
262b9c3982
9 changed files with 167 additions and 68 deletions
|
@ -26,7 +26,7 @@ pub(crate) use lower::LowerCtx;
|
|||
use crate::{
|
||||
attr::{Attrs, RawAttrs},
|
||||
db::DefDatabase,
|
||||
expr::{Expr, ExprId, Pat, PatId},
|
||||
expr::{Expr, ExprId, Label, LabelId, Pat, PatId},
|
||||
item_scope::BuiltinShadowMode,
|
||||
item_scope::ItemScope,
|
||||
nameres::CrateDefMap,
|
||||
|
@ -226,6 +226,7 @@ pub(crate) struct Mark {
|
|||
pub struct Body {
|
||||
pub exprs: Arena<Expr>,
|
||||
pub pats: Arena<Pat>,
|
||||
pub labels: Arena<Label>,
|
||||
/// The patterns for the function's parameters. While the parameter types are
|
||||
/// part of the function signature, the patterns are not (they don't change
|
||||
/// the external type of the function).
|
||||
|
@ -244,6 +245,8 @@ pub type ExprSource = InFile<ExprPtr>;
|
|||
pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
|
||||
pub type PatSource = InFile<PatPtr>;
|
||||
|
||||
pub type LabelPtr = AstPtr<ast::Label>;
|
||||
pub type LabelSource = InFile<LabelPtr>;
|
||||
/// An item body together with the mapping from syntax nodes to HIR expression
|
||||
/// IDs. This is needed to go from e.g. a position in a file to the HIR
|
||||
/// expression containing it; but for type inference etc., we want to operate on
|
||||
|
@ -261,6 +264,8 @@ pub struct BodySourceMap {
|
|||
expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
|
||||
pat_map: FxHashMap<PatSource, PatId>,
|
||||
pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
|
||||
label_map: FxHashMap<LabelSource, LabelId>,
|
||||
label_map_back: ArenaMap<LabelId, LabelSource>,
|
||||
field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordExprField>>>,
|
||||
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
|
||||
|
||||
|
@ -334,6 +339,14 @@ impl Index<PatId> for Body {
|
|||
}
|
||||
}
|
||||
|
||||
impl Index<LabelId> for Body {
|
||||
type Output = Label;
|
||||
|
||||
fn index(&self, label: LabelId) -> &Label {
|
||||
&self.labels[label]
|
||||
}
|
||||
}
|
||||
|
||||
impl BodySourceMap {
|
||||
pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
|
||||
self.expr_map_back[expr].clone()
|
||||
|
@ -363,6 +376,15 @@ impl BodySourceMap {
|
|||
self.pat_map.get(&src).cloned()
|
||||
}
|
||||
|
||||
pub fn label_syntax(&self, label: LabelId) -> LabelSource {
|
||||
self.label_map_back[label].clone()
|
||||
}
|
||||
|
||||
pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> {
|
||||
let src = node.map(|it| AstPtr::new(it));
|
||||
self.label_map.get(&src).cloned()
|
||||
}
|
||||
|
||||
pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordExprField>> {
|
||||
self.field_map[&(expr, field)].clone()
|
||||
}
|
||||
|
|
|
@ -22,13 +22,14 @@ use test_utils::mark;
|
|||
|
||||
use crate::{
|
||||
adt::StructKind,
|
||||
body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax},
|
||||
body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
|
||||
builtin_type::{BuiltinFloat, BuiltinInt},
|
||||
db::DefDatabase,
|
||||
diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro},
|
||||
expr::{
|
||||
dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal,
|
||||
LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
|
||||
dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
|
||||
LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
|
||||
Statement,
|
||||
},
|
||||
item_scope::BuiltinShadowMode,
|
||||
item_tree::{ItemTree, ItemTreeId, ItemTreeNode},
|
||||
|
@ -72,6 +73,7 @@ pub(super) fn lower(
|
|||
body: Body {
|
||||
exprs: Arena::default(),
|
||||
pats: Arena::default(),
|
||||
labels: Arena::default(),
|
||||
params: Vec::new(),
|
||||
body_expr: dummy_expr_id(),
|
||||
item_scope: Default::default(),
|
||||
|
@ -175,6 +177,18 @@ impl ExprCollector<'_> {
|
|||
id
|
||||
}
|
||||
|
||||
fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
|
||||
let src = self.expander.to_source(ptr);
|
||||
let id = self.make_label(label, src.clone());
|
||||
self.source_map.label_map.insert(src, id);
|
||||
id
|
||||
}
|
||||
fn make_label(&mut self, label: Label, src: LabelSource) -> LabelId {
|
||||
let id = self.body.labels.alloc(label);
|
||||
self.source_map.label_map_back.insert(id, src);
|
||||
id
|
||||
}
|
||||
|
||||
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
|
||||
let syntax_ptr = AstPtr::new(&expr);
|
||||
if self.check_cfg(&expr).is_none() {
|
||||
|
@ -228,19 +242,22 @@ impl ExprCollector<'_> {
|
|||
self.alloc_expr(Expr::Unsafe { body }, syntax_ptr)
|
||||
}
|
||||
// FIXME: we need to record these effects somewhere...
|
||||
ast::Effect::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 = label.lifetime().map(|t| Name::new_lifetime(&t))
|
||||
ast::Effect::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!(),
|
||||
}
|
||||
_ => unreachable!(),
|
||||
res
|
||||
}
|
||||
res
|
||||
None => self.missing_expr(),
|
||||
}
|
||||
None => self.missing_expr(),
|
||||
},
|
||||
}
|
||||
// FIXME: we need to record these effects somewhere...
|
||||
ast::Effect::Async(_) => {
|
||||
let body = self.collect_block_opt(e.block_expr());
|
||||
|
@ -249,16 +266,12 @@ impl ExprCollector<'_> {
|
|||
},
|
||||
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());
|
||||
self.alloc_expr(
|
||||
Expr::Loop {
|
||||
body,
|
||||
label: e.label().and_then(|l| l.lifetime()).map(|l| Name::new_lifetime(&l)),
|
||||
},
|
||||
syntax_ptr,
|
||||
)
|
||||
self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
|
||||
}
|
||||
ast::Expr::WhileExpr(e) => {
|
||||
let label = e.label().map(|label| self.collect_label(label));
|
||||
let body = self.collect_block_opt(e.loop_body());
|
||||
|
||||
let condition = match e.condition() {
|
||||
|
@ -279,42 +292,20 @@ impl ExprCollector<'_> {
|
|||
];
|
||||
let match_expr =
|
||||
self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
|
||||
return self.alloc_expr(
|
||||
Expr::Loop {
|
||||
body: match_expr,
|
||||
label: e
|
||||
.label()
|
||||
.and_then(|l| l.lifetime())
|
||||
.map(|l| Name::new_lifetime(&l)),
|
||||
},
|
||||
syntax_ptr,
|
||||
);
|
||||
return self
|
||||
.alloc_expr(Expr::Loop { body: match_expr, label }, syntax_ptr);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
self.alloc_expr(
|
||||
Expr::While {
|
||||
condition,
|
||||
body,
|
||||
label: e.label().and_then(|l| l.lifetime()).map(|l| Name::new_lifetime(&l)),
|
||||
},
|
||||
syntax_ptr,
|
||||
)
|
||||
self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
|
||||
}
|
||||
ast::Expr::ForExpr(e) => {
|
||||
let label = e.label().map(|label| self.collect_label(label));
|
||||
let iterable = self.collect_expr_opt(e.iterable());
|
||||
let pat = self.collect_pat_opt(e.pat());
|
||||
let body = self.collect_block_opt(e.loop_body());
|
||||
self.alloc_expr(
|
||||
Expr::For {
|
||||
iterable,
|
||||
pat,
|
||||
body,
|
||||
label: e.label().and_then(|l| l.lifetime()).map(|l| Name::new_lifetime(&l)),
|
||||
},
|
||||
syntax_ptr,
|
||||
)
|
||||
self.alloc_expr(Expr::For { iterable, pat, body, label }, syntax_ptr)
|
||||
}
|
||||
ast::Expr::CallExpr(e) => {
|
||||
let callee = self.collect_expr_opt(e.expr());
|
||||
|
@ -814,6 +805,13 @@ impl ExprCollector<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_label(&mut self, ast_label: ast::Label) -> LabelId {
|
||||
let label = Label {
|
||||
name: ast_label.lifetime().as_ref().map_or_else(Name::missing, Name::new_lifetime),
|
||||
};
|
||||
self.alloc_label(label, AstPtr::new(&ast_label))
|
||||
}
|
||||
|
||||
fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
|
||||
let pattern = match &pat {
|
||||
ast::Pat::IdentPat(bp) => {
|
||||
|
|
|
@ -29,6 +29,12 @@ pub(crate) fn dummy_expr_id() -> ExprId {
|
|||
|
||||
pub type PatId = Idx<Pat>;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Label {
|
||||
pub name: Name,
|
||||
}
|
||||
pub type LabelId = Idx<Label>;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum Literal {
|
||||
String(String),
|
||||
|
@ -52,22 +58,22 @@ pub enum Expr {
|
|||
Block {
|
||||
statements: Vec<Statement>,
|
||||
tail: Option<ExprId>,
|
||||
label: Option<Name>,
|
||||
label: Option<LabelId>,
|
||||
},
|
||||
Loop {
|
||||
body: ExprId,
|
||||
label: Option<Name>,
|
||||
label: Option<LabelId>,
|
||||
},
|
||||
While {
|
||||
condition: ExprId,
|
||||
body: ExprId,
|
||||
label: Option<Name>,
|
||||
label: Option<LabelId>,
|
||||
},
|
||||
For {
|
||||
iterable: ExprId,
|
||||
pat: PatId,
|
||||
body: ExprId,
|
||||
label: Option<Name>,
|
||||
label: Option<LabelId>,
|
||||
},
|
||||
Call {
|
||||
callee: ExprId,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue