mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-03 07:04:49 +00:00
Store patterns desugared from destructuring assignments in source map
And few more fixups. I was worried this will lead to more memory usage since `ExprOrPatId` is double the size of `ExprId`, but this does not regress `analysis-stats .`. If this turns out to be a problem, we can easily use the high bit to encode this information.
This commit is contained in:
parent
61f162a43d
commit
2d4d6b678f
16 changed files with 280 additions and 174 deletions
|
@ -3,7 +3,7 @@
|
|||
|
||||
use hir_def::{
|
||||
body::Body,
|
||||
hir::{Expr, ExprId, UnaryOp},
|
||||
hir::{Expr, ExprId, ExprOrPatId, Pat, UnaryOp},
|
||||
resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
|
||||
type_ref::Rawness,
|
||||
DefWithBodyId,
|
||||
|
@ -16,7 +16,7 @@ use crate::{
|
|||
/// Returns `(unsafe_exprs, fn_is_unsafe)`.
|
||||
///
|
||||
/// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`.
|
||||
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>, bool) {
|
||||
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprOrPatId>, bool) {
|
||||
let _p = tracing::info_span!("missing_unsafe").entered();
|
||||
|
||||
let mut res = Vec::new();
|
||||
|
@ -32,7 +32,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>,
|
|||
let infer = db.infer(def);
|
||||
unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| {
|
||||
if !expr.inside_unsafe_block {
|
||||
res.push(expr.expr);
|
||||
res.push(expr.node);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -40,7 +40,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>,
|
|||
}
|
||||
|
||||
pub struct UnsafeExpr {
|
||||
pub expr: ExprId,
|
||||
pub node: ExprOrPatId,
|
||||
pub inside_unsafe_block: bool,
|
||||
}
|
||||
|
||||
|
@ -75,26 +75,28 @@ fn walk_unsafe(
|
|||
inside_unsafe_block: bool,
|
||||
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
|
||||
) {
|
||||
let mut mark_unsafe_path = |path, node| {
|
||||
let g = resolver.update_to_inner_scope(db.upcast(), def, current);
|
||||
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path);
|
||||
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
|
||||
let static_data = db.static_data(id);
|
||||
if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) {
|
||||
unsafe_expr_cb(UnsafeExpr { node, inside_unsafe_block });
|
||||
}
|
||||
}
|
||||
resolver.reset_to_guard(g);
|
||||
};
|
||||
|
||||
let expr = &body.exprs[current];
|
||||
match expr {
|
||||
&Expr::Call { callee, .. } => {
|
||||
if let Some(func) = infer[callee].as_fn_def(db) {
|
||||
if is_fn_unsafe_to_call(db, func) {
|
||||
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||
unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
|
||||
}
|
||||
}
|
||||
}
|
||||
Expr::Path(path) => {
|
||||
let g = resolver.update_to_inner_scope(db.upcast(), def, current);
|
||||
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path);
|
||||
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
|
||||
let static_data = db.static_data(id);
|
||||
if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) {
|
||||
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||
}
|
||||
}
|
||||
resolver.reset_to_guard(g);
|
||||
}
|
||||
Expr::Path(path) => mark_unsafe_path(path, current.into()),
|
||||
Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => {
|
||||
if let Expr::Path(_) = body.exprs[*expr] {
|
||||
// Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`,
|
||||
|
@ -108,12 +110,12 @@ fn walk_unsafe(
|
|||
.map(|(func, _)| is_fn_unsafe_to_call(db, func))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||
unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
|
||||
}
|
||||
}
|
||||
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
|
||||
if let TyKind::Raw(..) = &infer[*expr].kind(Interner) {
|
||||
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||
unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
|
||||
}
|
||||
}
|
||||
Expr::Unsafe { .. } => {
|
||||
|
@ -121,6 +123,13 @@ fn walk_unsafe(
|
|||
walk_unsafe(db, infer, body, resolver, def, child, true, unsafe_expr_cb);
|
||||
});
|
||||
}
|
||||
&Expr::Assignment { target, value: _ } => {
|
||||
body.walk_pats(target, &mut |pat| {
|
||||
if let Pat::Path(path) = &body[pat] {
|
||||
mark_unsafe_path(path, pat.into());
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
|
@ -482,12 +482,27 @@ impl InferenceResult {
|
|||
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
|
||||
self.variant_resolutions.get(&id.into()).copied()
|
||||
}
|
||||
pub fn variant_resolution_for_expr_or_pat(&self, id: ExprOrPatId) -> Option<VariantId> {
|
||||
match id {
|
||||
ExprOrPatId::ExprId(id) => self.variant_resolution_for_expr(id),
|
||||
ExprOrPatId::PatId(id) => self.variant_resolution_for_pat(id),
|
||||
}
|
||||
}
|
||||
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<(AssocItemId, Substitution)> {
|
||||
self.assoc_resolutions.get(&id.into()).cloned()
|
||||
}
|
||||
pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, Substitution)> {
|
||||
self.assoc_resolutions.get(&id.into()).cloned()
|
||||
}
|
||||
pub fn assoc_resolutions_for_expr_or_pat(
|
||||
&self,
|
||||
id: ExprOrPatId,
|
||||
) -> Option<(AssocItemId, Substitution)> {
|
||||
match id {
|
||||
ExprOrPatId::ExprId(id) => self.assoc_resolutions_for_expr(id),
|
||||
ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id),
|
||||
}
|
||||
}
|
||||
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
|
||||
self.type_mismatches.get(&expr.into())
|
||||
}
|
||||
|
@ -506,6 +521,12 @@ impl InferenceResult {
|
|||
pub fn closure_info(&self, closure: &ClosureId) -> &(Vec<CapturedItem>, FnTrait) {
|
||||
self.closure_info.get(closure).unwrap()
|
||||
}
|
||||
pub fn type_of_expr_or_pat(&self, id: ExprOrPatId) -> Option<&Ty> {
|
||||
match id {
|
||||
ExprOrPatId::ExprId(id) => self.type_of_expr.get(id),
|
||||
ExprOrPatId::PatId(id) => self.type_of_pat.get(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<ExprId> for InferenceResult {
|
||||
|
@ -524,6 +545,14 @@ impl Index<PatId> for InferenceResult {
|
|||
}
|
||||
}
|
||||
|
||||
impl Index<ExprOrPatId> for InferenceResult {
|
||||
type Output = Ty;
|
||||
|
||||
fn index(&self, id: ExprOrPatId) -> &Ty {
|
||||
self.type_of_expr_or_pat(id).unwrap_or(&self.standard_types.unknown)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<BindingId> for InferenceResult {
|
||||
type Output = Ty;
|
||||
|
||||
|
|
|
@ -3418,11 +3418,11 @@ struct TS(usize);
|
|||
fn main() {
|
||||
let x;
|
||||
[x,] = &[1,];
|
||||
//^^^^expected &'? [i32; 1], got [{unknown}; _]
|
||||
//^^^^expected &'? [i32; 1], got [{unknown}]
|
||||
|
||||
let x;
|
||||
[(x,),] = &[(1,),];
|
||||
//^^^^^^^expected &'? [(i32,); 1], got [{unknown}; _]
|
||||
//^^^^^^^expected &'? [(i32,); 1], got [{unknown}]
|
||||
|
||||
let x;
|
||||
((x,),) = &((1,),);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue