mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 20:09:19 +00:00
Merge pull request #18254 from ChayimFriedman2/fix-mut
fix: Nail destructuring assignment once and for all
This commit is contained in:
commit
c286786888
29 changed files with 1171 additions and 860 deletions
|
@ -18,7 +18,7 @@ use hir_def::{
|
|||
scope::{ExprScopes, ScopeId},
|
||||
Body, BodySourceMap,
|
||||
},
|
||||
hir::{BindingId, ExprId, Pat, PatId},
|
||||
hir::{BindingId, ExprId, ExprOrPatId, Pat, PatId},
|
||||
lang_item::LangItem,
|
||||
lower::LowerCtx,
|
||||
nameres::MacroSubNs,
|
||||
|
@ -120,7 +120,7 @@ impl SourceAnalyzer {
|
|||
self.def.as_ref().map(|(_, body, _)| &**body)
|
||||
}
|
||||
|
||||
fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
|
||||
fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprOrPatId> {
|
||||
let src = match expr {
|
||||
ast::Expr::MacroExpr(expr) => {
|
||||
self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?.into()
|
||||
|
@ -174,7 +174,9 @@ impl SourceAnalyzer {
|
|||
db: &dyn HirDatabase,
|
||||
expr: &ast::Expr,
|
||||
) -> Option<&[Adjustment]> {
|
||||
let expr_id = self.expr_id(db, expr)?;
|
||||
// It is safe to omit destructuring assignments here because they have no adjustments (neither
|
||||
// expressions nor patterns).
|
||||
let expr_id = self.expr_id(db, expr)?.as_expr()?;
|
||||
let infer = self.infer.as_ref()?;
|
||||
infer.expr_adjustments.get(&expr_id).map(|v| &**v)
|
||||
}
|
||||
|
@ -186,9 +188,9 @@ impl SourceAnalyzer {
|
|||
) -> Option<(Type, Option<Type>)> {
|
||||
let expr_id = self.expr_id(db, expr)?;
|
||||
let infer = self.infer.as_ref()?;
|
||||
let coerced = infer
|
||||
.expr_adjustments
|
||||
.get(&expr_id)
|
||||
let coerced = expr_id
|
||||
.as_expr()
|
||||
.and_then(|expr_id| infer.expr_adjustments.get(&expr_id))
|
||||
.and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
|
||||
let ty = infer[expr_id].clone();
|
||||
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
|
||||
|
@ -268,7 +270,7 @@ impl SourceAnalyzer {
|
|||
db: &dyn HirDatabase,
|
||||
call: &ast::MethodCallExpr,
|
||||
) -> Option<Callable> {
|
||||
let expr_id = self.expr_id(db, &call.clone().into())?;
|
||||
let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
|
||||
let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
|
||||
let ty = db.value_ty(func.into())?.substitute(Interner, &substs);
|
||||
let ty = Type::new_with_resolver(db, &self.resolver, ty);
|
||||
|
@ -282,7 +284,7 @@ impl SourceAnalyzer {
|
|||
db: &dyn HirDatabase,
|
||||
call: &ast::MethodCallExpr,
|
||||
) -> Option<Function> {
|
||||
let expr_id = self.expr_id(db, &call.clone().into())?;
|
||||
let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
|
||||
let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
|
||||
|
||||
Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs).into())
|
||||
|
@ -293,7 +295,7 @@ impl SourceAnalyzer {
|
|||
db: &dyn HirDatabase,
|
||||
call: &ast::MethodCallExpr,
|
||||
) -> Option<Either<Function, Field>> {
|
||||
let expr_id = self.expr_id(db, &call.clone().into())?;
|
||||
let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
|
||||
let inference_result = self.infer.as_ref()?;
|
||||
match inference_result.method_resolution(expr_id) {
|
||||
Some((f_in_trait, substs)) => Some(Either::Left(
|
||||
|
@ -322,7 +324,7 @@ impl SourceAnalyzer {
|
|||
field: &ast::FieldExpr,
|
||||
) -> Option<Either<Field, TupleField>> {
|
||||
let &(def, ..) = self.def.as_ref()?;
|
||||
let expr_id = self.expr_id(db, &field.clone().into())?;
|
||||
let expr_id = self.expr_id(db, &field.clone().into())?.as_expr()?;
|
||||
self.infer.as_ref()?.field_resolution(expr_id).map(|it| {
|
||||
it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index })
|
||||
})
|
||||
|
@ -334,7 +336,7 @@ impl SourceAnalyzer {
|
|||
field: &ast::FieldExpr,
|
||||
) -> Option<Either<Either<Field, TupleField>, Function>> {
|
||||
let &(def, ..) = self.def.as_ref()?;
|
||||
let expr_id = self.expr_id(db, &field.clone().into())?;
|
||||
let expr_id = self.expr_id(db, &field.clone().into())?.as_expr()?;
|
||||
let inference_result = self.infer.as_ref()?;
|
||||
match inference_result.field_resolution(expr_id) {
|
||||
Some(field) => Some(Either::Left(field.map_either(Into::into, |f| TupleField {
|
||||
|
@ -442,7 +444,7 @@ impl SourceAnalyzer {
|
|||
self.infer
|
||||
.as_ref()
|
||||
.and_then(|infer| {
|
||||
let expr = self.expr_id(db, &prefix_expr.clone().into())?;
|
||||
let expr = self.expr_id(db, &prefix_expr.clone().into())?.as_expr()?;
|
||||
let (func, _) = infer.method_resolution(expr)?;
|
||||
let (deref_mut_trait, deref_mut) = self.lang_trait_fn(
|
||||
db,
|
||||
|
@ -488,7 +490,7 @@ impl SourceAnalyzer {
|
|||
.infer
|
||||
.as_ref()
|
||||
.and_then(|infer| {
|
||||
let expr = self.expr_id(db, &index_expr.clone().into())?;
|
||||
let expr = self.expr_id(db, &index_expr.clone().into())?.as_expr()?;
|
||||
let (func, _) = infer.method_resolution(expr)?;
|
||||
let (index_mut_trait, index_mut_fn) = self.lang_trait_fn(
|
||||
db,
|
||||
|
@ -576,8 +578,8 @@ impl SourceAnalyzer {
|
|||
_ => None,
|
||||
}
|
||||
};
|
||||
let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
|
||||
let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
|
||||
let (_, subst) = self.infer.as_ref()?.type_of_expr_or_pat(expr_id)?.as_adt()?;
|
||||
let variant = self.infer.as_ref()?.variant_resolution_for_expr_or_pat(expr_id)?;
|
||||
let variant_data = variant.variant_data(db.upcast());
|
||||
let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
|
||||
let field_ty =
|
||||
|
@ -645,10 +647,10 @@ impl SourceAnalyzer {
|
|||
let infer = self.infer.as_deref()?;
|
||||
if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
|
||||
let expr_id = self.expr_id(db, &path_expr.into())?;
|
||||
if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr(expr_id) {
|
||||
if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_id) {
|
||||
let assoc = match assoc {
|
||||
AssocItemId::FunctionId(f_in_trait) => {
|
||||
match infer.type_of_expr.get(expr_id) {
|
||||
match infer.type_of_expr_or_pat(expr_id) {
|
||||
None => assoc,
|
||||
Some(func_ty) => {
|
||||
if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
|
||||
|
@ -673,7 +675,7 @@ impl SourceAnalyzer {
|
|||
return Some(PathResolution::Def(AssocItem::from(assoc).into()));
|
||||
}
|
||||
if let Some(VariantId::EnumVariantId(variant)) =
|
||||
infer.variant_resolution_for_expr(expr_id)
|
||||
infer.variant_resolution_for_expr_or_pat(expr_id)
|
||||
{
|
||||
return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
|
||||
}
|
||||
|
@ -697,7 +699,7 @@ impl SourceAnalyzer {
|
|||
} else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
|
||||
let expr_id = self.expr_id(db, &rec_lit.into())?;
|
||||
if let Some(VariantId::EnumVariantId(variant)) =
|
||||
infer.variant_resolution_for_expr(expr_id)
|
||||
infer.variant_resolution_for_expr_or_pat(expr_id)
|
||||
{
|
||||
return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
|
||||
}
|
||||
|
@ -829,10 +831,16 @@ impl SourceAnalyzer {
|
|||
let infer = self.infer.as_ref()?;
|
||||
|
||||
let expr_id = self.expr_id(db, &literal.clone().into())?;
|
||||
let substs = infer.type_of_expr[expr_id].as_adt()?.1;
|
||||
let substs = infer[expr_id].as_adt()?.1;
|
||||
|
||||
let (variant, missing_fields, _exhaustive) =
|
||||
record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
|
||||
let (variant, missing_fields, _exhaustive) = match expr_id {
|
||||
ExprOrPatId::ExprId(expr_id) => {
|
||||
record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?
|
||||
}
|
||||
ExprOrPatId::PatId(pat_id) => {
|
||||
record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?
|
||||
}
|
||||
};
|
||||
let res = self.missing_fields(db, substs, variant, missing_fields);
|
||||
Some(res)
|
||||
}
|
||||
|
@ -895,7 +903,7 @@ impl SourceAnalyzer {
|
|||
) -> Option<VariantId> {
|
||||
let infer = self.infer.as_ref()?;
|
||||
let expr_id = self.expr_id(db, &record_lit.into())?;
|
||||
infer.variant_resolution_for_expr(expr_id)
|
||||
infer.variant_resolution_for_expr_or_pat(expr_id)
|
||||
}
|
||||
|
||||
pub(crate) fn is_unsafe_macro_call_expr(
|
||||
|
@ -906,14 +914,24 @@ impl SourceAnalyzer {
|
|||
if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
|
||||
if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) {
|
||||
let mut is_unsafe = false;
|
||||
unsafe_expressions(
|
||||
db,
|
||||
infer,
|
||||
*def,
|
||||
body,
|
||||
expanded_expr,
|
||||
&mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block,
|
||||
);
|
||||
let mut walk_expr = |expr_id| {
|
||||
unsafe_expressions(
|
||||
db,
|
||||
infer,
|
||||
*def,
|
||||
body,
|
||||
expr_id,
|
||||
&mut |UnsafeExpr { inside_unsafe_block, .. }| {
|
||||
is_unsafe |= !inside_unsafe_block
|
||||
},
|
||||
)
|
||||
};
|
||||
match expanded_expr {
|
||||
ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr),
|
||||
ExprOrPatId::PatId(expanded_pat) => {
|
||||
body.walk_exprs_in_pat(expanded_pat, &mut walk_expr)
|
||||
}
|
||||
}
|
||||
return is_unsafe;
|
||||
}
|
||||
}
|
||||
|
@ -1030,7 +1048,7 @@ impl SourceAnalyzer {
|
|||
}
|
||||
|
||||
fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
|
||||
self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, expr)?)
|
||||
self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1043,7 +1061,7 @@ fn scope_for(
|
|||
node.ancestors_with_macros(db.upcast())
|
||||
.take_while(|it| !ast::Item::can_cast(it.kind()) || ast::MacroCall::can_cast(it.kind()))
|
||||
.filter_map(|it| it.map(ast::Expr::cast).transpose())
|
||||
.filter_map(|it| source_map.node_expr(it.as_ref()))
|
||||
.filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr())
|
||||
.find_map(|it| scopes.scope_for(it))
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue