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.rs134
1 files changed, 106 insertions, 28 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 2e1f88ba09..e0d2610391 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -2,14 +2,17 @@
mod source_to_def;
-use std::{cell::RefCell, fmt, iter, ops};
+use std::{cell::RefCell, fmt, iter, mem, ops};
use base_db::{FileId, FileRange};
+use either::Either;
use hir_def::{
- body, macro_id_to_def_id,
+ body,
+ expr::Expr,
+ macro_id_to_def_id,
resolver::{self, HasResolver, Resolver, TypeNs},
type_ref::Mutability,
- AsMacroCall, FunctionId, MacroId, TraitId, VariantId,
+ AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId,
};
use hir_expand::{
db::AstDatabase,
@@ -29,7 +32,7 @@ use crate::{
db::HirDatabase,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
source_analyzer::{resolve_hir_path, SourceAnalyzer},
- Access, Adjust, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate,
+ Access, Adjust, Adjustment, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate,
DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local,
Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, ToolModule, Trait, Type,
TypeAlias, TypeParam, VariantDef,
@@ -334,7 +337,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.resolve_trait(trait_)
}
- pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjust>> {
+ pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> {
self.imp.expr_adjustments(expr)
}
@@ -438,8 +441,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
}
pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
- let src = self.imp.find_file(src.syntax()).with_value(src).cloned();
- T::to_def(&self.imp, src)
+ self.imp.to_def(src)
}
pub fn to_module_def(&self, file: FileId) -> Option<Module> {
@@ -481,6 +483,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
self.imp.is_unsafe_ident_pat(ident_pat)
}
+
+ /// Returns `true` if the `node` is inside an `unsafe` context.
+ pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
+ self.imp.is_inside_unsafe(expr)
+ }
}
impl<'db> SemanticsImpl<'db> {
@@ -788,7 +795,7 @@ impl<'db> SemanticsImpl<'db> {
// requeue the tokens we got from mapping our current token down
stack.extend(mapped_tokens);
// if the length changed we have found a mapping for the token
- (stack.len() != len).then(|| ())
+ (stack.len() != len).then_some(())
};
// Remap the next token in the queue into a macro call its in, if it is not being remapped
@@ -840,7 +847,7 @@ impl<'db> SemanticsImpl<'db> {
}
};
process_expansion_for_token(&mut stack, file_id, None, token.as_ref())
- } else if let Some(meta) = ast::Meta::cast(parent.clone()) {
+ } else if let Some(meta) = ast::Meta::cast(parent) {
// attribute we failed expansion for earlier, this might be a derive invocation
// or derive helper attribute
let attr = meta.parent_attr()?;
@@ -1067,26 +1074,42 @@ impl<'db> SemanticsImpl<'db> {
}
}
- fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjust>> {
+ fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> {
let mutability = |m| match m {
hir_ty::Mutability::Not => Mutability::Shared,
hir_ty::Mutability::Mut => Mutability::Mut,
};
- self.analyze(expr.syntax())?.expr_adjustments(self.db, expr).map(|it| {
+
+ let analyzer = self.analyze(expr.syntax())?;
+
+ let (mut source_ty, _) = analyzer.type_of_expr(self.db, expr)?;
+
+ analyzer.expr_adjustments(self.db, expr).map(|it| {
it.iter()
- .map(|adjust| match adjust.kind {
- hir_ty::Adjust::NeverToAny => Adjust::NeverToAny,
- hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => {
- Adjust::Deref(Some(OverloadedDeref(mutability(m))))
- }
- hir_ty::Adjust::Deref(None) => Adjust::Deref(None),
- hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => {
- Adjust::Borrow(AutoBorrow::RawPtr(mutability(m)))
- }
- hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => {
- Adjust::Borrow(AutoBorrow::Ref(mutability(m)))
- }
- hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc),
+ .map(|adjust| {
+ let target =
+ Type::new_with_resolver(self.db, &analyzer.resolver, adjust.target.clone());
+ let kind = match adjust.kind {
+ hir_ty::Adjust::NeverToAny => Adjust::NeverToAny,
+ hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => {
+ Adjust::Deref(Some(OverloadedDeref(mutability(m))))
+ }
+ hir_ty::Adjust::Deref(None) => Adjust::Deref(None),
+ hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => {
+ Adjust::Borrow(AutoBorrow::RawPtr(mutability(m)))
+ }
+ hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => {
+ Adjust::Borrow(AutoBorrow::Ref(mutability(m)))
+ }
+ hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc),
+ };
+
+ // Update `source_ty` for the next adjustment
+ let source = mem::replace(&mut source_ty, target.clone());
+
+ let adjustment = Adjustment { source, target, kind };
+
+ adjustment
})
.collect()
})
@@ -1198,7 +1221,7 @@ impl<'db> SemanticsImpl<'db> {
krate
.dependencies(self.db)
.into_iter()
- .find_map(|dep| (dep.name == name).then(|| dep.krate))
+ .find_map(|dep| (dep.name == name).then_some(dep.krate))
}
fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
@@ -1223,10 +1246,15 @@ impl<'db> SemanticsImpl<'db> {
fn with_ctx<F: FnOnce(&mut SourceToDefCtx<'_, '_>) -> T, T>(&self, f: F) -> T {
let mut cache = self.s2d_cache.borrow_mut();
- let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache };
+ let mut ctx = SourceToDefCtx { db: self.db, cache: &mut cache };
f(&mut ctx)
}
+ fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
+ let src = self.find_file(src.syntax()).with_value(src).cloned();
+ T::to_def(self, src)
+ }
+
fn to_module_def(&self, file: FileId) -> impl Iterator<Item = Module> {
self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
}
@@ -1350,7 +1378,7 @@ impl<'db> SemanticsImpl<'db> {
self.cache
.borrow()
.keys()
- .map(|it| format!("{:?}", it))
+ .map(|it| format!("{it:?}"))
.collect::<Vec<_>>()
.join(", ")
)
@@ -1442,6 +1470,56 @@ impl<'db> SemanticsImpl<'db> {
.map(|ty| ty.original.is_packed(self.db))
.unwrap_or(false)
}
+
+ fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
+ let item_or_variant = |ancestor: SyntaxNode| {
+ if ast::Item::can_cast(ancestor.kind()) {
+ ast::Item::cast(ancestor).map(Either::Left)
+ } else {
+ ast::Variant::cast(ancestor).map(Either::Right)
+ }
+ };
+ let Some(enclosing_item) = expr.syntax().ancestors().find_map(item_or_variant) else { return false };
+
+ let def = match &enclosing_item {
+ Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true,
+ Either::Left(ast::Item::Fn(it)) => {
+ self.to_def(it).map(<_>::into).map(DefWithBodyId::FunctionId)
+ }
+ Either::Left(ast::Item::Const(it)) => {
+ self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId)
+ }
+ Either::Left(ast::Item::Static(it)) => {
+ self.to_def(it).map(<_>::into).map(DefWithBodyId::StaticId)
+ }
+ Either::Left(_) => None,
+ Either::Right(it) => self.to_def(it).map(<_>::into).map(DefWithBodyId::VariantId),
+ };
+ let Some(def) = def else { return false };
+ let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax());
+
+ let (body, source_map) = self.db.body_with_source_map(def);
+
+ let file_id = self.find_file(expr.syntax()).file_id;
+
+ let Some(mut parent) = expr.syntax().parent() else { return false };
+ loop {
+ if &parent == enclosing_node {
+ break false;
+ }
+
+ if let Some(parent) = ast::Expr::cast(parent.clone()) {
+ if let Some(expr_id) = source_map.node_expr(InFile { file_id, value: &parent }) {
+ if let Expr::Unsafe { .. } = body[expr_id] {
+ break true;
+ }
+ }
+ }
+
+ let Some(parent_) = parent.parent() else { break false };
+ parent = parent_;
+ }
+ }
}
fn macro_call_to_macro_id(
@@ -1600,7 +1678,7 @@ impl<'a> SemanticsScope<'a> {
self.db,
def,
resolution.in_type_ns()?,
- |name, _, id| cb(name, id.into()),
+ |name, id| cb(name, id.into()),
)
}
}