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.rs | 173 |
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) } |