Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/semantics.rs')
-rw-r--r--crates/hir/src/semantics.rs173
1 files changed, 109 insertions, 64 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 4bc757da44..4e9e3c44be 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -13,9 +13,10 @@ use std::{
use base_db::FxIndexSet;
use either::Either;
use hir_def::{
- BuiltinDeriveImplId, DefWithBodyId, HasModule, MacroId, StructId, TraitId, VariantId,
+ BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, HasModule, MacroId, StructId,
+ TraitId, VariantId,
attrs::parse_extra_crate_attrs,
- expr_store::{Body, ExprOrPatSource, HygieneId, path::Path},
+ expr_store::{Body, ExprOrPatSource, ExpressionStore, HygieneId, path::Path},
hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
nameres::{ModuleOrigin, crate_def_map},
resolver::{self, HasResolver, Resolver, TypeNs, ValueNs},
@@ -31,7 +32,7 @@ use hir_expand::{
};
use hir_ty::{
InferenceResult,
- diagnostics::{unsafe_operations, unsafe_operations_for_body},
+ diagnostics::unsafe_operations,
infer_query_with_inspect,
next_solver::{
AnyImplId, DbInterner, Span,
@@ -54,10 +55,10 @@ use syntax::{
use crate::{
Adjust, Adjustment, Adt, AnyFunctionId, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
- ConstParam, Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution,
- HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro,
- Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait,
- TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
+ ConstParam, Crate, DeriveHelper, Enum, EnumVariant, ExpressionStoreOwner, Field, Function,
+ GenericSubstitution, HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam,
+ Local, Macro, Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule,
+ Trait, TupleField, Type, TypeAlias, TypeParam, Union, Variant,
db::HirDatabase,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
source_analyzer::{SourceAnalyzer, resolve_hir_path},
@@ -90,7 +91,7 @@ impl PathResolution {
}
PathResolution::Def(
ModuleDef::Const(_)
- | ModuleDef::Variant(_)
+ | ModuleDef::EnumVariant(_)
| ModuleDef::Macro(_)
| ModuleDef::Function(_)
| ModuleDef::Module(_)
@@ -367,8 +368,8 @@ impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
self.imp.resolve_try_expr(try_expr)
}
- pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
- self.imp.resolve_variant(record_lit).map(VariantDef::from)
+ pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<Variant> {
+ self.imp.resolve_variant(record_lit).map(Variant::from)
}
pub fn file_to_module_def(&self, file: impl Into<FileId>) -> Option<Module> {
@@ -409,7 +410,7 @@ impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
self.imp.to_def(e)
}
- pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option<Variant> {
+ pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option<EnumVariant> {
self.imp.to_def(v)
}
@@ -472,12 +473,12 @@ impl<'db> SemanticsImpl<'db> {
pub fn attach_first_edition_opt(&self, file: FileId) -> Option<EditionedFileId> {
let krate = self.file_to_module_defs(file).next()?.krate(self.db);
- Some(EditionedFileId::new(self.db, file, krate.edition(self.db), krate.id))
+ Some(EditionedFileId::new(self.db, file, krate.edition(self.db)))
}
pub fn attach_first_edition(&self, file: FileId) -> EditionedFileId {
self.attach_first_edition_opt(file)
- .unwrap_or_else(|| EditionedFileId::current_edition_guess_origin(self.db, file))
+ .unwrap_or_else(|| EditionedFileId::current_edition(self.db, file))
}
pub fn parse_guess_edition(&self, file_id: FileId) -> ast::SourceFile {
@@ -785,16 +786,21 @@ impl<'db> SemanticsImpl<'db> {
/// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals,
/// and returns the conflicting locals.
pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec<Local> {
- let body = self.db.body(to_be_renamed.parent);
+ // FIXME: signatures
+ let Some(def) = to_be_renamed.parent.as_def_with_body() else {
+ return Vec::new();
+ };
+ let body = Body::of(self.db, def);
let resolver = to_be_renamed.parent.resolver(self.db);
- let starting_expr = body.binding_owner(to_be_renamed.binding_id).unwrap_or(body.body_expr);
+ let starting_expr =
+ body.binding_owner(to_be_renamed.binding_id).unwrap_or(body.root_expr());
let mut visitor = RenameConflictsVisitor {
- body: &body,
+ body,
conflicts: FxHashSet::default(),
db: self.db,
new_name: new_name.symbol().clone(),
old_name: to_be_renamed.name(self.db).symbol().clone(),
- owner: to_be_renamed.parent,
+ owner: def,
to_be_renamed: to_be_renamed.binding_id,
resolver,
};
@@ -1819,6 +1825,28 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
}
+ /// The type that the associated `try` block, closure or function expects.
+ pub fn try_expr_returned_type(&self, try_expr: &ast::TryExpr) -> Option<Type<'db>> {
+ self.ancestors_with_macros(try_expr.syntax().clone()).find_map(|parent| {
+ if let Some(try_block) = ast::BlockExpr::cast(parent.clone())
+ && try_block.try_block_modifier().is_some()
+ {
+ Some(self.type_of_expr(&try_block.into())?.original)
+ } else if let Some(closure) = ast::ClosureExpr::cast(parent.clone()) {
+ Some(
+ self.type_of_expr(&closure.into())?
+ .original
+ .as_callable(self.db)?
+ .return_type(),
+ )
+ } else if let Some(function) = ast::Fn::cast(parent) {
+ Some(self.to_def(&function)?.ret_type(self.db))
+ } else {
+ None
+ }
+ })
+ }
+
// This does not resolve the method call to the correct trait impl!
// We should probably fix that.
pub fn resolve_method_call_as_callable(
@@ -1891,36 +1919,32 @@ impl<'db> SemanticsImpl<'db> {
self.db.parse_macro_expansion(file_id).value.1.matched_arm
}
- pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet<ExprOrPatSource> {
- let Ok(def) = DefWithBodyId::try_from(def) else {
- return FxHashSet::default();
- };
- let (body, source_map) = self.db.body_with_source_map(def);
- let infer = InferenceResult::for_body(self.db, def);
+ pub fn get_unsafe_ops(&self, def: ExpressionStoreOwner) -> FxHashSet<ExprOrPatSource> {
+ let Ok(def) = ExpressionStoreOwnerId::try_from(def) else { return Default::default() };
+ let (body, source_map) = ExpressionStore::with_source_map(self.db, def);
+ let infer = InferenceResult::of(self.db, def);
let mut res = FxHashSet::default();
- unsafe_operations_for_body(self.db, infer, def, &body, &mut |node| {
- if let Ok(node) = source_map.expr_or_pat_syntax(node) {
- res.insert(node);
- }
- });
+ for root in body.expr_roots() {
+ unsafe_operations(self.db, infer, def, body, root, &mut |node, _| {
+ if let Ok(node) = source_map.expr_or_pat_syntax(node) {
+ res.insert(node);
+ }
+ });
+ }
res
}
pub fn get_unsafe_ops_for_unsafe_block(&self, block: ast::BlockExpr) -> Vec<ExprOrPatSource> {
always!(block.unsafe_token().is_some());
+ let Some(sa) = self.analyze(block.syntax()) else { return vec![] };
+ let Some((def, store, sm, Some(infer))) = sa.def() else { return vec![] };
let block = self.wrap_node_infile(ast::Expr::from(block));
- let Some(def) = self.body_for(block.syntax()) else { return Vec::new() };
- let Ok(def) = def.try_into() else {
- return Vec::new();
- };
- let (body, source_map) = self.db.body_with_source_map(def);
- let infer = InferenceResult::for_body(self.db, def);
- let Some(ExprOrPatId::ExprId(block)) = source_map.node_expr(block.as_ref()) else {
+ let Some(ExprOrPatId::ExprId(block)) = sm.node_expr(block.as_ref()) else {
return Vec::new();
};
let mut res = Vec::default();
- unsafe_operations(self.db, infer, def, &body, block, &mut |node, _| {
- if let Ok(node) = source_map.expr_or_pat_syntax(node) {
+ unsafe_operations(self.db, infer, def, store, block, &mut |node, _| {
+ if let Ok(node) = sm.expr_or_pat_syntax(node) {
res.push(node);
}
});
@@ -1972,7 +1996,7 @@ impl<'db> SemanticsImpl<'db> {
pub fn resolve_offset_of_field(
&self,
name_ref: &ast::NameRef,
- ) -> Option<(Either<Variant, Field>, GenericSubstitution<'db>)> {
+ ) -> Option<(Either<EnumVariant, Field>, GenericSubstitution<'db>)> {
self.analyze_no_infer(name_ref.syntax())?.resolve_offset_of_field(self.db, name_ref)
}
@@ -2092,13 +2116,9 @@ impl<'db> SemanticsImpl<'db> {
Some(res)
}
- pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option<DefWithBody> {
+ pub fn store_owner_for(&self, node: InFile<&SyntaxNode>) -> Option<ExpressionStoreOwner> {
let container = self.with_ctx(|ctx| ctx.find_container(node))?;
-
- match container {
- ChildContainer::DefWithBodyId(def) => Some(def.into()),
- _ => None,
- }
+ container.as_expression_store_owner().map(|id| id.into())
}
/// Returns none if the file of the node is not part of a crate.
@@ -2127,7 +2147,7 @@ impl<'db> SemanticsImpl<'db> {
node: InFile<&SyntaxNode>,
offset: Option<TextSize>,
// replace this, just make the inference result a `LazyCell`
- infer_body: bool,
+ infer: bool,
) -> Option<SourceAnalyzer<'db>> {
let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered();
@@ -2135,26 +2155,42 @@ impl<'db> SemanticsImpl<'db> {
let resolver = match container {
ChildContainer::DefWithBodyId(def) => {
- return Some(if infer_body {
+ return Some(if infer {
SourceAnalyzer::new_for_body(self.db, def, node, offset)
} else {
SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset)
});
}
ChildContainer::VariantId(def) => {
- return Some(SourceAnalyzer::new_variant_body(self.db, def, node, offset));
+ return Some(SourceAnalyzer::new_variant_body(self.db, def, node, offset, infer));
}
ChildContainer::TraitId(it) => {
- return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset));
+ return Some(if infer {
+ SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)
+ } else {
+ SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset)
+ });
}
ChildContainer::ImplId(it) => {
- return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset));
+ return Some(if infer {
+ SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)
+ } else {
+ SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset)
+ });
}
ChildContainer::EnumId(it) => {
- return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset));
+ return Some(if infer {
+ SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)
+ } else {
+ SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset)
+ });
}
ChildContainer::GenericDefId(it) => {
- return Some(SourceAnalyzer::new_generic_def(self.db, it, node, offset));
+ return Some(if infer {
+ SourceAnalyzer::new_generic_def(self.db, it, node, offset)
+ } else {
+ SourceAnalyzer::new_generic_def_no_infer(self.db, it, node, offset)
+ });
}
ChildContainer::ModuleId(it) => it.resolver(self.db),
};
@@ -2237,7 +2273,7 @@ impl<'db> SemanticsImpl<'db> {
let Some(def) = def else { return false };
let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax());
- let (body, source_map) = self.db.body_with_source_map(def);
+ let (body, source_map) = Body::with_source_map(self.db, def);
let file_id = self.find_file(expr.syntax()).file_id;
@@ -2288,7 +2324,7 @@ impl<'db> SemanticsImpl<'db> {
let sa = self.analyze(element.either(|e| e.syntax(), |s| s.syntax()))?;
let store = sa.store()?;
let mut resolver = sa.resolver.clone();
- let def = resolver.body_owner()?;
+ let def = resolver.expression_store_owner()?;
let is_not_generated = |path: &Path| {
!path.mod_path().and_then(|path| path.as_ident()).is_some_and(Name::is_generated)
@@ -2479,7 +2515,7 @@ to_def_impls![
(crate::Function, ast::Fn, fn_to_def),
(crate::Field, ast::RecordField, record_field_to_def),
(crate::Field, ast::TupleField, tuple_field_to_def),
- (crate::Variant, ast::Variant, enum_variant_to_def),
+ (crate::EnumVariant, ast::Variant, enum_variant_to_def),
(crate::TypeParam, ast::TypeParam, type_param_to_def),
(crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
(crate::ConstParam, ast::ConstParam, const_param_to_def),
@@ -2538,13 +2574,18 @@ impl<'db> SemanticsScope<'db> {
Crate { id: self.resolver.krate() }
}
+ // FIXME: This is a weird function, we shouldn't have this?
pub fn containing_function(&self) -> Option<Function> {
- self.resolver.body_owner().and_then(|owner| match owner {
- DefWithBodyId::FunctionId(id) => Some(id.into()),
+ self.resolver.expression_store_owner().and_then(|owner| match owner {
+ ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => Some(id.into()),
_ => None,
})
}
+ pub fn expression_store_owner(&self) -> Option<ExpressionStoreOwner> {
+ self.resolver.expression_store_owner().map(Into::into)
+ }
+
pub(crate) fn resolver(&self) -> &Resolver<'db> {
&self.resolver
}
@@ -2566,14 +2607,18 @@ impl<'db> SemanticsScope<'db> {
resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()),
resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()),
resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()),
- resolver::ScopeDef::Local(binding_id) => match self.resolver.body_owner() {
- Some(parent) => ScopeDef::Local(Local { parent, binding_id }),
- None => continue,
- },
- resolver::ScopeDef::Label(label_id) => match self.resolver.body_owner() {
- Some(parent) => ScopeDef::Label(Label { parent, label_id }),
- None => continue,
- },
+ resolver::ScopeDef::Local(binding_id) => {
+ match self.resolver.expression_store_owner() {
+ Some(parent) => ScopeDef::Local(Local { parent, binding_id }),
+ None => continue,
+ }
+ }
+ resolver::ScopeDef::Label(label_id) => {
+ match self.resolver.expression_store_owner() {
+ Some(parent) => ScopeDef::Label(Label { parent, label_id }),
+ None => continue,
+ }
+ }
};
f(name.clone(), def)
}