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 | 121 |
1 files changed, 73 insertions, 48 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 4afdde6494..8a700027a3 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -403,11 +403,15 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.to_module_def(file) } - pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { + pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> { self.imp.scope(node) } - pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> { + pub fn scope_at_offset( + &self, + node: &SyntaxNode, + offset: TextSize, + ) -> Option<SemanticsScope<'db>> { self.imp.scope_at_offset(node, offset) } @@ -456,7 +460,7 @@ impl<'db> SemanticsImpl<'db> { } fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { - let sa = self.analyze_no_infer(macro_call.syntax()); + let sa = self.analyze_no_infer(macro_call.syntax())?; let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?; let node = self.parse_or_expand(file_id)?; Some(node) @@ -535,9 +539,9 @@ impl<'db> SemanticsImpl<'db> { token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, SyntaxToken)> { let SourceAnalyzer { file_id, resolver, .. } = - self.analyze_no_infer(actual_macro_call.syntax()); + self.analyze_no_infer(actual_macro_call.syntax())?; let macro_call = InFile::new(file_id, actual_macro_call); - let krate = resolver.krate()?; + let krate = resolver.krate(); let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { resolver .resolve_path_as_macro(self.db.upcast(), &path) @@ -669,7 +673,10 @@ impl<'db> SemanticsImpl<'db> { Some(it) => it, None => return, }; - let sa = self.analyze_no_infer(&parent); + let sa = match self.analyze_no_infer(&parent) { + Some(it) => it, + None => return, + }; let mut stack: SmallVec<[_; 4]> = smallvec![InFile::new(sa.file_id, token)]; let mut cache = self.expansion_info_cache.borrow_mut(); let mut mcache = self.macro_call_cache.borrow_mut(); @@ -903,70 +910,74 @@ impl<'db> SemanticsImpl<'db> { } fn resolve_type(&self, ty: &ast::Type) -> Option<Type> { - let scope = self.scope(ty.syntax()); - let ctx = body::LowerCtx::new(self.db.upcast(), scope.file_id); - let ty = hir_ty::TyLoweringContext::new(self.db, &scope.resolver) + let analyze = self.analyze(ty.syntax())?; + let ctx = body::LowerCtx::new(self.db.upcast(), analyze.file_id); + let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver) .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); - Type::new_with_resolver(self.db, &scope.resolver, ty) + Some(Type::new_with_resolver(self.db, &analyze.resolver, ty)) } fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> { - self.analyze(expr.syntax()).is_implicit_reborrow(self.db, expr) + self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr) } fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> { - self.analyze(expr.syntax()) + self.analyze(expr.syntax())? .type_of_expr(self.db, expr) .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced }) } fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> { - self.analyze(pat.syntax()) + self.analyze(pat.syntax())? .type_of_pat(self.db, pat) .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced }) } fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> { - self.analyze(param.syntax()).type_of_self(self.db, param) + self.analyze(param.syntax())?.type_of_self(self.db, param) } fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> { - self.analyze(call.syntax()).resolve_method_call(self.db, call).map(|(id, _)| id) + self.analyze(call.syntax())?.resolve_method_call(self.db, call).map(|(id, _)| id) } fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { - let (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?; + let source_analyzer = self.analyze(call.syntax())?; + let (func, subst) = source_analyzer.resolve_method_call(self.db, call)?; let ty = self.db.value_ty(func.into()).substitute(Interner, &subst); - let resolver = self.analyze(call.syntax()).resolver; - let ty = Type::new_with_resolver(self.db, &resolver, ty)?; + let resolver = source_analyzer.resolver; + let ty = Type::new_with_resolver(self.db, &resolver, ty); let mut res = ty.as_callable(self.db)?; res.is_bound_method = true; Some(res) } fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { - self.analyze(field.syntax()).resolve_field(self.db, field) + self.analyze(field.syntax())?.resolve_field(self.db, field) } fn resolve_record_field( &self, field: &ast::RecordExprField, ) -> Option<(Field, Option<Local>, Type)> { - self.analyze(field.syntax()).resolve_record_field(self.db, field) + self.analyze(field.syntax())?.resolve_record_field(self.db, field) } fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> { - self.analyze(field.syntax()).resolve_record_pat_field(self.db, field) + self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field) } fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<Macro> { - let sa = self.analyze(macro_call.syntax()); + let sa = self.analyze(macro_call.syntax())?; let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call); sa.resolve_macro_call(self.db, macro_call) } fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool { - let sa = self.analyze(macro_call.syntax()); + let sa = match self.analyze(macro_call.syntax()) { + Some(it) => it, + None => return false, + }; let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call); sa.is_unsafe_macro_call(self.db, macro_call) } @@ -981,11 +992,11 @@ impl<'db> SemanticsImpl<'db> { } fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> { - self.analyze(path.syntax()).resolve_path(self.db, path) + self.analyze(path.syntax())?.resolve_path(self.db, path) } fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> { - let krate = self.scope(extern_crate.syntax()).krate()?; + let krate = self.scope(extern_crate.syntax())?.krate(); let name = extern_crate.name_ref()?.as_name(); if name == known::SELF_PARAM { return Some(krate); @@ -997,22 +1008,22 @@ impl<'db> SemanticsImpl<'db> { } fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> { - self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) + self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit) } fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> { - self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) + self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat) } fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> { self.analyze(literal.syntax()) - .record_literal_missing_fields(self.db, literal) + .and_then(|it| it.record_literal_missing_fields(self.db, literal)) .unwrap_or_default() } fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { self.analyze(pattern.syntax()) - .record_pattern_missing_fields(self.db, pattern) + .and_then(|it| it.record_pattern_missing_fields(self.db, pattern)) .unwrap_or_default() } @@ -1026,15 +1037,22 @@ impl<'db> SemanticsImpl<'db> { self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from) } - fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { - let SourceAnalyzer { file_id, resolver, .. } = self.analyze_no_infer(node); - SemanticsScope { db: self.db, file_id, resolver } + fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> { + self.analyze_no_infer(node).map(|SourceAnalyzer { file_id, resolver, .. }| SemanticsScope { + db: self.db, + file_id, + resolver, + }) } - fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> { - let SourceAnalyzer { file_id, resolver, .. } = - self.analyze_with_offset_no_infer(node, offset); - SemanticsScope { db: self.db, file_id, resolver } + fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> Option<SemanticsScope<'db>> { + self.analyze_with_offset_no_infer(node, offset).map( + |SourceAnalyzer { file_id, resolver, .. }| SemanticsScope { + db: self.db, + file_id, + resolver, + }, + ) } fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { @@ -1052,15 +1070,21 @@ impl<'db> SemanticsImpl<'db> { Some(res) } - fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer { + /// Returns none if the file of the node is not part of a crate. + fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> { self.analyze_impl(node, None, true) } - fn analyze_no_infer(&self, node: &SyntaxNode) -> SourceAnalyzer { + /// Returns none if the file of the node is not part of a crate. + fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> { self.analyze_impl(node, None, false) } - fn analyze_with_offset_no_infer(&self, node: &SyntaxNode, offset: TextSize) -> SourceAnalyzer { + fn analyze_with_offset_no_infer( + &self, + node: &SyntaxNode, + offset: TextSize, + ) -> Option<SourceAnalyzer> { self.analyze_impl(node, Some(offset), false) } @@ -1069,22 +1093,22 @@ impl<'db> SemanticsImpl<'db> { node: &SyntaxNode, offset: Option<TextSize>, infer_body: bool, - ) -> SourceAnalyzer { + ) -> Option<SourceAnalyzer> { let _p = profile::span("Semantics::analyze_impl"); let node = self.find_file(node); let container = match self.with_ctx(|ctx| ctx.find_container(node)) { Some(it) => it, - None => return SourceAnalyzer::new_for_resolver(Resolver::default(), node), + None => return None, }; let resolver = match container { ChildContainer::DefWithBodyId(def) => { - return if infer_body { + return Some(if infer_body { SourceAnalyzer::new_for_body(self.db, def, node, offset) } else { SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset) - } + }) } ChildContainer::TraitId(it) => it.resolver(self.db.upcast()), ChildContainer::ImplId(it) => it.resolver(self.db.upcast()), @@ -1094,7 +1118,7 @@ impl<'db> SemanticsImpl<'db> { ChildContainer::TypeAliasId(it) => it.resolver(self.db.upcast()), ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()), }; - SourceAnalyzer::new_for_resolver(resolver, node) + Some(SourceAnalyzer::new_for_resolver(resolver, node)) } fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { @@ -1118,6 +1142,7 @@ impl<'db> SemanticsImpl<'db> { InFile::new(file_id, node) } + /// Wraps the node in a [`InFile`] with the file id it belongs to. fn find_file<'node>(&self, node: &'node SyntaxNode) -> InFile<&'node SyntaxNode> { let root_node = find_root(node); let file_id = self.lookup(&root_node).unwrap_or_else(|| { @@ -1319,12 +1344,12 @@ pub struct SemanticsScope<'a> { } impl<'a> SemanticsScope<'a> { - pub fn module(&self) -> Option<Module> { - Some(Module { id: self.resolver.module()? }) + pub fn module(&self) -> Module { + Module { id: self.resolver.module() } } - pub fn krate(&self) -> Option<Crate> { - Some(Crate { id: self.resolver.krate()? }) + pub fn krate(&self) -> Crate { + Crate { id: self.resolver.krate() } } pub(crate) fn resolver(&self) -> &Resolver { |