Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/source_analyzer.rs')
| -rw-r--r-- | crates/hir/src/source_analyzer.rs | 206 |
1 files changed, 111 insertions, 95 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index c1a75ce7e5..ec2ccf8cba 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -10,7 +10,9 @@ use std::iter::{self, once}; use crate::{ Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait, - TraitAlias, TupleField, Type, TypeAlias, Variant, db::HirDatabase, semantics::PathResolution, + TraitAlias, TupleField, Type, TypeAlias, Variant, + db::HirDatabase, + semantics::{PathResolution, PathResolutionPerNs}, }; use either::Either; use hir_def::{ @@ -29,7 +31,7 @@ use hir_def::{ type_ref::{Mutability, TypeRefId}, }; use hir_expand::{ - HirFileId, InFile, MacroCallId, + HirFileId, InFile, mod_path::{ModPath, PathKind, path}, name::{AsName, Name}, }; @@ -57,9 +59,9 @@ use triomphe::Arc; /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of /// original source files. It should not be used inside the HIR itself. #[derive(Debug)] -pub(crate) struct SourceAnalyzer { +pub(crate) struct SourceAnalyzer<'db> { pub(crate) file_id: HirFileId, - pub(crate) resolver: Resolver, + pub(crate) resolver: Resolver<'db>, pub(crate) body_or_sig: Option<BodyOrSig>, } @@ -85,32 +87,32 @@ pub(crate) enum BodyOrSig { }, } -impl SourceAnalyzer { +impl<'db> SourceAnalyzer<'db> { pub(crate) fn new_for_body( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, def: DefWithBodyId, node: InFile<&SyntaxNode>, offset: Option<TextSize>, - ) -> SourceAnalyzer { + ) -> SourceAnalyzer<'db> { Self::new_for_body_(db, def, node, offset, Some(db.infer(def))) } pub(crate) fn new_for_body_no_infer( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, def: DefWithBodyId, node: InFile<&SyntaxNode>, offset: Option<TextSize>, - ) -> SourceAnalyzer { + ) -> SourceAnalyzer<'db> { Self::new_for_body_(db, def, node, offset, None) } pub(crate) fn new_for_body_( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, def: DefWithBodyId, node @ InFile { file_id, .. }: InFile<&SyntaxNode>, offset: Option<TextSize>, infer: Option<Arc<InferenceResult>>, - ) -> SourceAnalyzer { + ) -> SourceAnalyzer<'db> { let (body, source_map) = db.body_with_source_map(def); let scopes = db.expr_scopes(def); let scope = match offset { @@ -134,11 +136,11 @@ impl SourceAnalyzer { } pub(crate) fn new_generic_def( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, def: GenericDefId, InFile { file_id, .. }: InFile<&SyntaxNode>, _offset: Option<TextSize>, - ) -> SourceAnalyzer { + ) -> SourceAnalyzer<'db> { let (_params, store, source_map) = db.generic_params_and_store_and_source_map(def); let resolver = def.resolver(db); SourceAnalyzer { @@ -149,11 +151,11 @@ impl SourceAnalyzer { } pub(crate) fn new_variant_body( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, def: VariantId, InFile { file_id, .. }: InFile<&SyntaxNode>, _offset: Option<TextSize>, - ) -> SourceAnalyzer { + ) -> SourceAnalyzer<'db> { let (fields, source_map) = db.variant_fields_with_source_map(def); let resolver = def.resolver(db); SourceAnalyzer { @@ -168,9 +170,9 @@ impl SourceAnalyzer { } pub(crate) fn new_for_resolver( - resolver: Resolver, + resolver: Resolver<'db>, node: InFile<&SyntaxNode>, - ) -> SourceAnalyzer { + ) -> SourceAnalyzer<'db> { SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id } } @@ -216,11 +218,7 @@ impl SourceAnalyzer { }) } - pub(crate) fn expansion(&self, node: InFile<&ast::MacroCall>) -> Option<MacroCallId> { - self.store_sm()?.expansion(node) - } - - fn trait_environment(&self, db: &dyn HirDatabase) -> Arc<TraitEnvironment> { + fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment> { self.body_().map(|(def, ..)| def).map_or_else( || TraitEnvironment::empty(self.resolver.krate()), |def| db.trait_environment_for_body(def), @@ -259,7 +257,7 @@ impl SourceAnalyzer { infer.expr_adjustments.get(&expr_id).map(|v| &**v) } - pub(crate) fn type_of_type(&self, db: &dyn HirDatabase, ty: &ast::Type) -> Option<Type> { + pub(crate) fn type_of_type(&self, db: &'db dyn HirDatabase, ty: &ast::Type) -> Option<Type> { let type_ref = self.type_id(ty)?; let ty = TyLoweringContext::new( db, @@ -277,7 +275,7 @@ impl SourceAnalyzer { pub(crate) fn type_of_expr( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, expr: &ast::Expr, ) -> Option<(Type, Option<Type>)> { let expr_id = self.expr_id(expr.clone())?; @@ -293,7 +291,7 @@ impl SourceAnalyzer { pub(crate) fn type_of_pat( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, pat: &ast::Pat, ) -> Option<(Type, Option<Type>)> { let expr_or_pat_id = self.pat_id(pat)?; @@ -316,7 +314,7 @@ impl SourceAnalyzer { pub(crate) fn type_of_binding_in_pat( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, pat: &ast::IdentPat, ) -> Option<Type> { let binding_id = self.binding_id_of_pat(pat)?; @@ -328,7 +326,7 @@ impl SourceAnalyzer { pub(crate) fn type_of_self( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, _param: &ast::SelfParam, ) -> Option<Type> { let binding = self.body()?.self_param?; @@ -338,7 +336,7 @@ impl SourceAnalyzer { pub(crate) fn binding_mode_of_pat( &self, - _db: &dyn HirDatabase, + _db: &'db dyn HirDatabase, pat: &ast::IdentPat, ) -> Option<BindingMode> { let id = self.pat_id(&pat.clone().into())?; @@ -353,7 +351,7 @@ impl SourceAnalyzer { } pub(crate) fn pattern_adjustments( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, pat: &ast::Pat, ) -> Option<SmallVec<[Type; 1]>> { let pat_id = self.pat_id(pat)?; @@ -370,7 +368,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_method_call_as_callable( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, call: &ast::MethodCallExpr, ) -> Option<Callable> { let expr_id = self.expr_id(call.clone().into())?.as_expr()?; @@ -384,7 +382,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_method_call( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, call: &ast::MethodCallExpr, ) -> Option<Function> { let expr_id = self.expr_id(call.clone().into())?.as_expr()?; @@ -395,7 +393,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_method_call_fallback( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, call: &ast::MethodCallExpr, ) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> { let expr_id = self.expr_id(call.clone().into())?.as_expr()?; @@ -419,7 +417,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_expr_as_callable( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, call: &ast::Expr, ) -> Option<Callable> { let (orig, adjusted) = self.type_of_expr(db, &call.clone())?; @@ -441,7 +439,7 @@ impl SourceAnalyzer { &self, field_expr: ExprId, infer: &InferenceResult, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, ) -> Option<GenericSubstitution> { let body = self.store()?; if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] { @@ -457,7 +455,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_field_fallback( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, field: &ast::FieldExpr, ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> { let (def, ..) = self.body_()?; @@ -490,7 +488,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_range_pat( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, range_pat: &ast::RangePat, ) -> Option<StructId> { let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) { @@ -509,7 +507,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_range_expr( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, range_expr: &ast::RangeExpr, ) -> Option<StructId> { let path: ModPath = match (range_expr.op_kind()?, range_expr.start(), range_expr.end()) { @@ -529,7 +527,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_await_to_poll( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, await_expr: &ast::AwaitExpr, ) -> Option<FunctionId> { let mut ty = self.ty_of_expr(await_expr.expr()?)?.clone(); @@ -566,7 +564,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_prefix_expr( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, prefix_expr: &ast::PrefixExpr, ) -> Option<FunctionId> { let (op_trait, op_fn) = match prefix_expr.op_kind()? { @@ -608,7 +606,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_index_expr( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, index_expr: &ast::IndexExpr, ) -> Option<FunctionId> { let base_ty = self.ty_of_expr(index_expr.base()?)?; @@ -640,7 +638,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_bin_expr( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, binop_expr: &ast::BinExpr, ) -> Option<FunctionId> { let op = binop_expr.op_kind()?; @@ -661,7 +659,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_try_expr( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, try_expr: &ast::TryExpr, ) -> Option<FunctionId> { let ty = self.ty_of_expr(try_expr.expr()?)?; @@ -680,7 +678,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_record_field( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, field: &ast::RecordExprField, ) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> { let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; @@ -724,7 +722,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_record_pat_field( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, field: &ast::RecordPatField, ) -> Option<(Field, Type, GenericSubstitution)> { let field_name = field.field_name()?.as_name(); @@ -743,25 +741,9 @@ impl SourceAnalyzer { )) } - pub(crate) fn resolve_macro_call( - &self, - db: &dyn HirDatabase, - macro_call: InFile<&ast::MacroCall>, - ) -> Option<Macro> { - let bs = self.store_sm()?; - bs.expansion(macro_call).and_then(|it| { - // FIXME: Block def maps - let def = it.lookup(db).def; - db.crate_def_map(def.krate) - .macro_def_to_macro_id - .get(&def.kind.erased_ast_id()) - .map(|it| (*it).into()) - }) - } - pub(crate) fn resolve_bind_pat_to_const( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, pat: &ast::IdentPat, ) -> Option<ModuleDef> { let expr_or_pat_id = self.pat_id(&pat.clone().into())?; @@ -795,7 +777,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_offset_of_field( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, name_ref: &ast::NameRef, ) -> Option<(Either<crate::Variant, crate::Field>, GenericSubstitution)> { let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?; @@ -867,7 +849,7 @@ impl SourceAnalyzer { pub(crate) fn resolve_path( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, path: &ast::Path, ) -> Option<(PathResolution, Option<GenericSubstitution>)> { let parent = path.syntax().parent(); @@ -1159,7 +1141,9 @@ impl SourceAnalyzer { prefer_value_ns, name_hygiene(db, InFile::new(self.file_id, path.syntax())), Some(&store), - )?; + false, + ) + .any()?; let subst = (|| { let parent = parent()?; let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) { @@ -1209,9 +1193,29 @@ impl SourceAnalyzer { } } - pub(crate) fn record_literal_missing_fields( + pub(crate) fn resolve_hir_path_per_ns( &self, db: &dyn HirDatabase, + path: &ast::Path, + ) -> Option<PathResolutionPerNs> { + let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id); + let hir_path = + collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?; + let store = collector.store.finish(); + Some(resolve_hir_path_( + db, + &self.resolver, + &hir_path, + false, + name_hygiene(db, InFile::new(self.file_id, path.syntax())), + Some(&store), + true, + )) + } + + pub(crate) fn record_literal_missing_fields( + &self, + db: &'db dyn HirDatabase, literal: &ast::RecordExpr, ) -> Option<Vec<(Field, Type)>> { let body = self.store()?; @@ -1234,7 +1238,7 @@ impl SourceAnalyzer { pub(crate) fn record_pattern_missing_fields( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, pattern: &ast::RecordPat, ) -> Option<Vec<(Field, Type)>> { let body = self.store()?; @@ -1251,7 +1255,7 @@ impl SourceAnalyzer { fn missing_fields( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, substs: &Substitution, variant: VariantId, missing_fields: Vec<LocalFieldId>, @@ -1268,18 +1272,6 @@ impl SourceAnalyzer { .collect() } - pub(crate) fn expand( - &self, - db: &dyn HirDatabase, - macro_call: InFile<&ast::MacroCall>, - ) -> Option<MacroCallId> { - self.store_sm().and_then(|bs| bs.expansion(macro_call)).or_else(|| { - self.resolver.item_scope().macro_invoc( - macro_call.with_value(db.ast_id_map(macro_call.file_id).ast_id(macro_call.value)), - ) - }) - } - pub(crate) fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> { let infer = self.infer()?; let expr_id = self.expr_id(record_lit.into())?; @@ -1288,7 +1280,7 @@ impl SourceAnalyzer { pub(crate) fn is_unsafe_macro_call_expr( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, macro_expr: InFile<&ast::MacroExpr>, ) -> bool { if let Some((def, body, sm, Some(infer))) = self.body_() { @@ -1311,9 +1303,10 @@ impl SourceAnalyzer { false } + /// Returns the range of the implicit template argument and its resolution at the given `offset` pub(crate) fn resolve_offset_in_format_args( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, format_args: InFile<&ast::FormatArgsExpr>, offset: TextSize, ) -> Option<(TextRange, Option<PathResolution>)> { @@ -1384,7 +1377,7 @@ impl SourceAnalyzer { fn resolve_impl_method_or_trait_def( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, func: FunctionId, substs: Substitution, ) -> FunctionId { @@ -1393,7 +1386,7 @@ impl SourceAnalyzer { fn resolve_impl_method_or_trait_def_with_subst( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, func: FunctionId, substs: Substitution, ) -> (FunctionId, Substitution) { @@ -1407,7 +1400,7 @@ impl SourceAnalyzer { fn resolve_impl_const_or_trait_def_with_subst( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, const_id: ConstId, subs: Substitution, ) -> (ConstId, Substitution) { @@ -1421,7 +1414,7 @@ impl SourceAnalyzer { fn lang_trait_fn( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, lang_trait: LangItem, method_name: &Name, ) -> Option<(TraitId, FunctionId)> { @@ -1527,18 +1520,18 @@ fn adjust( #[inline] pub(crate) fn resolve_hir_path( db: &dyn HirDatabase, - resolver: &Resolver, + resolver: &Resolver<'_>, path: &Path, hygiene: HygieneId, store: Option<&ExpressionStore>, ) -> Option<PathResolution> { - resolve_hir_path_(db, resolver, path, false, hygiene, store) + resolve_hir_path_(db, resolver, path, false, hygiene, store, false).any() } #[inline] pub(crate) fn resolve_hir_path_as_attr_macro( db: &dyn HirDatabase, - resolver: &Resolver, + resolver: &Resolver<'_>, path: &Path, ) -> Option<Macro> { resolver @@ -1549,12 +1542,13 @@ pub(crate) fn resolve_hir_path_as_attr_macro( fn resolve_hir_path_( db: &dyn HirDatabase, - resolver: &Resolver, + resolver: &Resolver<'_>, path: &Path, prefer_value_ns: bool, hygiene: HygieneId, store: Option<&ExpressionStore>, -) -> Option<PathResolution> { + resolve_per_ns: bool, +) -> PathResolutionPerNs { let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => resolver.generic_def().and_then(|def| { @@ -1635,14 +1629,36 @@ fn resolve_hir_path_( .map(|(def, _)| PathResolution::Def(ModuleDef::Macro(def.into()))) }; - if prefer_value_ns { values().or_else(types) } else { types().or_else(values) } - .or_else(items) - .or_else(macros) + if resolve_per_ns { + PathResolutionPerNs { + type_ns: types().or_else(items), + value_ns: values(), + macro_ns: macros(), + } + } else { + let res = if prefer_value_ns { + values() + .map(|value_ns| PathResolutionPerNs::new(None, Some(value_ns), None)) + .unwrap_or_else(|| PathResolutionPerNs::new(types(), None, None)) + } else { + types() + .map(|type_ns| PathResolutionPerNs::new(Some(type_ns), None, None)) + .unwrap_or_else(|| PathResolutionPerNs::new(None, values(), None)) + }; + + if res.any().is_some() { + res + } else if let Some(type_ns) = items() { + PathResolutionPerNs::new(Some(type_ns), None, None) + } else { + PathResolutionPerNs::new(None, None, macros()) + } + } } fn resolve_hir_value_path( db: &dyn HirDatabase, - resolver: &Resolver, + resolver: &Resolver<'_>, body_owner: Option<DefWithBodyId>, path: &Path, hygiene: HygieneId, @@ -1680,7 +1696,7 @@ fn resolve_hir_value_path( /// then we know that `foo` in `my::foo::Bar` refers to the module, not the function. fn resolve_hir_path_qualifier( db: &dyn HirDatabase, - resolver: &Resolver, + resolver: &Resolver<'_>, path: &Path, store: &ExpressionStore, ) -> Option<PathResolution> { |