Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion crates/hir/src/code_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use hir_def::{
adt::StructKind,
adt::VariantData,
builtin_type::BuiltinType,
expr::{BindingAnnotation, Pat, PatId},
expr::{BindingAnnotation, LabelId, Pat, PatId},
import_map,
item_tree::ItemTreeNode,
lang_item::LangItemTarget,
Expand Down Expand Up @@ -1205,6 +1205,34 @@ impl Local {
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Label {
pub(crate) parent: DefWithBodyId,
pub(crate) label_id: LabelId,
}

impl Label {
pub fn module(self, db: &dyn HirDatabase) -> Module {
self.parent(db).module(db)
}

pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
self.parent.into()
}

pub fn name(self, db: &dyn HirDatabase) -> Name {
let body = db.body(self.parent.into());
body[self.label_id].name.clone()
}

pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> {
let (_body, source_map) = db.body_with_source_map(self.parent.into());
let src = source_map.label_syntax(self.label_id);
let root = src.file_syntax(db.upcast());
src.map(|ast| ast.to_node(&root))
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum GenericParam {
TypeParam(TypeParam),
Expand Down
15 changes: 12 additions & 3 deletions crates/hir/src/from_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
//! are splitting the hir.

use hir_def::{
expr::PatId, item_scope::ItemInNs, AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId,
GenericDefId, ModuleDefId, VariantId,
expr::{LabelId, PatId},
item_scope::ItemInNs,
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, ModuleDefId,
VariantId,
};

use crate::{
Adt, AssocItem, DefWithBody, Field, GenericDef, Local, MacroDef, ModuleDef, Variant, VariantDef,
Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, MacroDef, ModuleDef, Variant,
VariantDef,
};

macro_rules! from_id {
Expand Down Expand Up @@ -228,6 +231,12 @@ impl From<(DefWithBodyId, PatId)> for Local {
}
}

impl From<(DefWithBodyId, LabelId)> for Label {
fn from((parent, label_id): (DefWithBodyId, LabelId)) -> Self {
Label { parent, label_id }
}
}

impl From<MacroDef> for ItemInNs {
fn from(macro_def: MacroDef) -> Self {
ItemInNs::Macros(macro_def.into())
Expand Down
4 changes: 2 additions & 2 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ pub use crate::{
code_model::{
Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const,
Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, GenericDef,
HasVisibility, Impl, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef, Static,
Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef,
Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
},
has_source::HasSource,
semantics::{PathResolution, Semantics, SemanticsScope},
Expand Down
33 changes: 30 additions & 3 deletions crates/hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
use syntax::{
algo::find_node_at_offset,
ast::{self, GenericParamsOwner},
ast::{self, GenericParamsOwner, LoopBodyOwner},
match_ast, AstNode, SyntaxNode, SyntaxToken, TextSize,
};

Expand All @@ -25,8 +25,8 @@ use crate::{
diagnostics::Diagnostic,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
source_analyzer::{resolve_hir_path, SourceAnalyzer},
AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, LifetimeParam, Local,
MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, Label, LifetimeParam,
Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
VariantDef,
};

Expand Down Expand Up @@ -182,6 +182,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.resolve_lifetime_param(lifetime)
}

pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
self.imp.resolve_label(lifetime)
}

pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
self.imp.type_of_expr(expr)
}
Expand Down Expand Up @@ -425,6 +429,28 @@ impl<'db> SemanticsImpl<'db> {
ToDef::to_def(self, src)
}

fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
let text = lifetime.text();
let label = lifetime.syntax().ancestors().find_map(|syn| {
let label = match_ast! {
match syn {
ast::ForExpr(it) => it.label(),
ast::WhileExpr(it) => it.label(),
ast::LoopExpr(it) => it.label(),
ast::EffectExpr(it) => it.label(),
_ => None,
}
};
label.filter(|l| {
l.lifetime()
.and_then(|lt| lt.lifetime_ident_token())
.map_or(false, |lt| lt.text() == text)
})
})?;
let src = self.find_file(label.syntax().clone()).with_value(label);
ToDef::to_def(self, src)
}

fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
self.analyze(expr.syntax()).type_of_expr(self.db, expr)
}
Expand Down Expand Up @@ -720,6 +746,7 @@ to_def_impls![
(crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
(crate::MacroDef, ast::MacroRules, macro_rules_to_def),
(crate::Local, ast::IdentPat, bind_pat_to_def),
(crate::Label, ast::Label, label_to_def),
];

fn find_root(node: &SyntaxNode) -> SyntaxNode {
Expand Down
15 changes: 12 additions & 3 deletions crates/hir/src/semantics/source_to_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use base_db::FileId;
use hir_def::{
child_by_source::ChildBySource,
dyn_map::DynMap,
expr::PatId,
expr::{LabelId, PatId},
keys::{self, Key},
ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId,
LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
Expand Down Expand Up @@ -108,12 +108,21 @@ impl SourceToDefCtx<'_, '_> {
&mut self,
src: InFile<ast::IdentPat>,
) -> Option<(DefWithBodyId, PatId)> {
let container = self.find_pat_container(src.as_ref().map(|it| it.syntax()))?;
let container = self.find_pat_or_label_container(src.as_ref().map(|it| it.syntax()))?;
let (_body, source_map) = self.db.body_with_source_map(container);
let src = src.map(ast::Pat::from);
let pat_id = source_map.node_pat(src.as_ref())?;
Some((container, pat_id))
}
pub(super) fn label_to_def(
&mut self,
src: InFile<ast::Label>,
) -> Option<(DefWithBodyId, LabelId)> {
let container = self.find_pat_or_label_container(src.as_ref().map(|it| it.syntax()))?;
let (_body, source_map) = self.db.body_with_source_map(container);
let label_id = source_map.node_label(src.as_ref())?;
Some((container, label_id))
}

fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>(
&mut self,
Expand Down Expand Up @@ -237,7 +246,7 @@ impl SourceToDefCtx<'_, '_> {
None
}

fn find_pat_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> {
fn find_pat_or_label_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> {
for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
let res: DefWithBodyId = match_ast! {
match (container.value) {
Expand Down
24 changes: 23 additions & 1 deletion crates/hir_def/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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).
Expand All @@ -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
Expand All @@ -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>,

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
}
Expand Down
Loading