mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
internal: Enforce Resolver to always have a module scope
This commit is contained in:
parent
ef92453dfe
commit
75689f2ad8
71 changed files with 360 additions and 398 deletions
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue