internal: Enforce Resolver to always have a module scope

This commit is contained in:
Lukas Wirth 2022-03-31 11:12:08 +02:00
parent ef92453dfe
commit 75689f2ad8
71 changed files with 360 additions and 398 deletions

View file

@ -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 {