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.rs109
1 files changed, 67 insertions, 42 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 4a2e8e379f..adba59236a 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -25,7 +25,6 @@ use hir_expand::{
builtin::{BuiltinFnLikeExpander, EagerExpander},
db::ExpandDatabase,
files::{FileRangeWrapper, HirFileRange, InRealFile},
- inert_attr_macro::find_builtin_attr_idx,
mod_path::{ModPath, PathKind},
name::AsName,
};
@@ -124,15 +123,15 @@ impl PathResolutionPerNs {
}
#[derive(Debug)]
-pub struct TypeInfo {
+pub struct TypeInfo<'db> {
/// The original type of the expression or pattern.
- pub original: Type,
+ pub original: Type<'db>,
/// The adjusted type, if an adjustment happened.
- pub adjusted: Option<Type>,
+ pub adjusted: Option<Type<'db>>,
}
-impl TypeInfo {
- pub fn original(self) -> Type {
+impl<'db> TypeInfo<'db> {
+ pub fn original(self) -> Type<'db> {
self.original
}
@@ -141,7 +140,7 @@ impl TypeInfo {
}
/// The adjusted type, or the original in case no adjustments occurred.
- pub fn adjusted(self) -> Type {
+ pub fn adjusted(self) -> Type<'db> {
self.adjusted.unwrap_or(self.original)
}
}
@@ -159,13 +158,13 @@ pub struct SemanticsImpl<'db> {
macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroCallId>>,
}
-impl<DB> fmt::Debug for Semantics<'_, DB> {
+impl<DB: ?Sized> fmt::Debug for Semantics<'_, DB> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Semantics {{ ... }}")
}
}
-impl<'db, DB> ops::Deref for Semantics<'db, DB> {
+impl<'db, DB: ?Sized> ops::Deref for Semantics<'db, DB> {
type Target = SemanticsImpl<'db>;
fn deref(&self) -> &Self::Target {
@@ -173,12 +172,28 @@ impl<'db, DB> ops::Deref for Semantics<'db, DB> {
}
}
+// Note: while this variant of `Semantics<'_, _>` might seem unused, as it does not
+// find actual use within the rust-analyzer project itself, it exists to enable the use
+// within e.g. tracked salsa functions in third-party crates that build upon `ra_ap_hir`.
+impl Semantics<'_, dyn HirDatabase> {
+ /// Creates an instance that's weakly coupled to its underlying database type.
+ pub fn new_dyn(db: &'_ dyn HirDatabase) -> Semantics<'_, dyn HirDatabase> {
+ let impl_ = SemanticsImpl::new(db);
+ Semantics { db, imp: impl_ }
+ }
+}
+
impl<DB: HirDatabase> Semantics<'_, DB> {
+ /// Creates an instance that's strongly coupled to its underlying database type.
pub fn new(db: &DB) -> Semantics<'_, DB> {
let impl_ = SemanticsImpl::new(db);
Semantics { db, imp: impl_ }
}
+}
+// Note: We take `DB` as `?Sized` here in order to support type-erased
+// use of `Semantics` via `Semantics<'_, dyn HirDatabase>`:
+impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId {
self.imp.find_file(syntax_node).file_id
}
@@ -229,7 +244,7 @@ impl<DB: HirDatabase> Semantics<'_, DB> {
offset: TextSize,
) -> impl Iterator<Item = ast::NameLike> + 'slf {
node.token_at_offset(offset)
- .map(move |token| self.descend_into_macros_no_opaque(token))
+ .map(move |token| self.descend_into_macros_no_opaque(token, true))
.map(|descendants| descendants.into_iter().filter_map(move |it| it.value.parent()))
// re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first
// See algo::ancestors_at_offset, which uses the same approach
@@ -662,8 +677,7 @@ impl<'db> SemanticsImpl<'db> {
pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec<Local> {
let body = self.db.body(to_be_renamed.parent);
let resolver = to_be_renamed.parent.resolver(self.db);
- let starting_expr =
- body.binding_owners.get(&to_be_renamed.binding_id).copied().unwrap_or(body.body_expr);
+ let starting_expr = body.binding_owner(to_be_renamed.binding_id).unwrap_or(body.body_expr);
let mut visitor = RenameConflictsVisitor {
body: &body,
conflicts: FxHashSet::default(),
@@ -953,13 +967,6 @@ impl<'db> SemanticsImpl<'db> {
let Some(item) = ast::Item::cast(ancestor) else {
return false;
};
- // Optimization to skip the semantic check.
- if item.attrs().all(|attr| {
- attr.simple_name()
- .is_some_and(|attr| find_builtin_attr_idx(&Symbol::intern(&attr)).is_some())
- }) {
- return false;
- }
self.with_ctx(|ctx| {
if ctx.item_to_macro_call(token.with_value(&item)).is_some() {
return true;
@@ -1001,10 +1008,11 @@ impl<'db> SemanticsImpl<'db> {
pub fn descend_into_macros_no_opaque(
&self,
token: SyntaxToken,
+ always_descend_into_derives: bool,
) -> SmallVec<[InFile<SyntaxToken>; 1]> {
let mut res = smallvec![];
let token = self.wrap_token_infile(token);
- self.descend_into_macros_all(token.clone(), true, &mut |t, ctx| {
+ self.descend_into_macros_all(token.clone(), always_descend_into_derives, &mut |t, ctx| {
if !ctx.is_opaque(self.db) {
// Don't descend into opaque contexts
res.push(t);
@@ -1525,7 +1533,7 @@ impl<'db> SemanticsImpl<'db> {
Some(Label { parent, label_id })
}
- pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
+ pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type<'db>> {
let analyze = self.analyze(ty.syntax())?;
analyze.type_of_type(self.db, ty)
}
@@ -1544,7 +1552,7 @@ impl<'db> SemanticsImpl<'db> {
}
}
- pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> {
+ pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment<'db>>> {
let mutability = |m| match m {
hir_ty::Mutability::Not => Mutability::Shared,
hir_ty::Mutability::Mut => Mutability::Mut,
@@ -1587,13 +1595,13 @@ impl<'db> SemanticsImpl<'db> {
})
}
- pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
+ pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo<'db>> {
self.analyze(expr.syntax())?
.type_of_expr(self.db, expr)
.map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
}
- pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
+ pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo<'db>> {
self.analyze(pat.syntax())?
.type_of_pat(self.db, pat)
.map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
@@ -1602,15 +1610,15 @@ impl<'db> SemanticsImpl<'db> {
/// It also includes the changes that binding mode makes in the type. For example in
/// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option<T>` but the result
/// of this function is `&mut Option<T>`
- pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> {
+ pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type<'db>> {
self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat)
}
- pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
+ pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type<'db>> {
self.analyze(param.syntax())?.type_of_self(self.db, param)
}
- pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
+ pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type<'db>; 1]> {
self.analyze(pat.syntax())
.and_then(|it| it.pattern_adjustments(self.db, pat))
.unwrap_or_default()
@@ -1620,7 +1628,7 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat)
}
- pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option<Callable> {
+ pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option<Callable<'db>> {
self.analyze(call.syntax())?.resolve_expr_as_callable(self.db, call)
}
@@ -1632,7 +1640,7 @@ impl<'db> SemanticsImpl<'db> {
pub fn resolve_method_call_fallback(
&self,
call: &ast::MethodCallExpr,
- ) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
+ ) -> Option<(Either<Function, Field>, Option<GenericSubstitution<'db>>)> {
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
}
@@ -1640,10 +1648,10 @@ impl<'db> SemanticsImpl<'db> {
// FIXME: better api for the trait environment
pub fn resolve_trait_impl_method(
&self,
- env: Type,
+ env: Type<'db>,
trait_: Trait,
func: Function,
- subst: impl IntoIterator<Item = Type>,
+ subst: impl IntoIterator<Item = Type<'db>>,
) -> Option<Function> {
let mut substs = hir_ty::TyBuilder::subst_for_def(self.db, TraitId::from(trait_), None);
for s in subst {
@@ -1682,7 +1690,10 @@ impl<'db> SemanticsImpl<'db> {
// This does not resolve the method call to the correct trait impl!
// We should probably fix that.
- pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
+ pub fn resolve_method_call_as_callable(
+ &self,
+ call: &ast::MethodCallExpr,
+ ) -> Option<Callable<'db>> {
self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
}
@@ -1693,14 +1704,15 @@ impl<'db> SemanticsImpl<'db> {
pub fn resolve_field_fallback(
&self,
field: &ast::FieldExpr,
- ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
+ ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution<'db>>)>
+ {
self.analyze(field.syntax())?.resolve_field_fallback(self.db, field)
}
pub fn resolve_record_field(
&self,
field: &ast::RecordExprField,
- ) -> Option<(Field, Option<Local>, Type)> {
+ ) -> Option<(Field, Option<Local>, Type<'db>)> {
self.resolve_record_field_with_substitution(field)
.map(|(field, local, ty, _)| (field, local, ty))
}
@@ -1708,18 +1720,21 @@ impl<'db> SemanticsImpl<'db> {
pub fn resolve_record_field_with_substitution(
&self,
field: &ast::RecordExprField,
- ) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
+ ) -> Option<(Field, Option<Local>, Type<'db>, GenericSubstitution<'db>)> {
self.analyze(field.syntax())?.resolve_record_field(self.db, field)
}
- pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
+ pub fn resolve_record_pat_field(
+ &self,
+ field: &ast::RecordPatField,
+ ) -> Option<(Field, Type<'db>)> {
self.resolve_record_pat_field_with_subst(field).map(|(field, ty, _)| (field, ty))
}
pub fn resolve_record_pat_field_with_subst(
&self,
field: &ast::RecordPatField,
- ) -> Option<(Field, Type, GenericSubstitution)> {
+ ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> {
self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
}
@@ -1760,7 +1775,7 @@ impl<'db> SemanticsImpl<'db> {
pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
let Some(mac) = self.resolve_macro_call(macro_call) else { return false };
- if mac.is_asm_or_global_asm(self.db) {
+ if mac.is_asm_like(self.db) {
return true;
}
@@ -1792,7 +1807,7 @@ impl<'db> SemanticsImpl<'db> {
pub fn resolve_path_with_subst(
&self,
path: &ast::Path,
- ) -> Option<(PathResolution, Option<GenericSubstitution>)> {
+ ) -> Option<(PathResolution, Option<GenericSubstitution<'db>>)> {
self.analyze(path.syntax())?.resolve_path(self.db, path)
}
@@ -1803,7 +1818,7 @@ impl<'db> SemanticsImpl<'db> {
pub fn resolve_offset_of_field(
&self,
name_ref: &ast::NameRef,
- ) -> Option<(Either<Variant, Field>, GenericSubstitution)> {
+ ) -> Option<(Either<Variant, Field>, GenericSubstitution<'db>)> {
self.analyze_no_infer(name_ref.syntax())?.resolve_offset_of_field(self.db, name_ref)
}
@@ -1825,13 +1840,19 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat)
}
- pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
+ pub fn record_literal_missing_fields(
+ &self,
+ literal: &ast::RecordExpr,
+ ) -> Vec<(Field, Type<'db>)> {
self.analyze(literal.syntax())
.and_then(|it| it.record_literal_missing_fields(self.db, literal))
.unwrap_or_default()
}
- pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
+ pub fn record_pattern_missing_fields(
+ &self,
+ pattern: &ast::RecordPat,
+ ) -> Vec<(Field, Type<'db>)> {
self.analyze(pattern.syntax())
.and_then(|it| it.record_pattern_missing_fields(self.db, pattern))
.unwrap_or_default()
@@ -2177,6 +2198,10 @@ pub struct SemanticsScope<'db> {
}
impl<'db> SemanticsScope<'db> {
+ pub fn file_id(&self) -> HirFileId {
+ self.file_id
+ }
+
pub fn module(&self) -> Module {
Module { id: self.resolver.module() }
}