Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/source_analyzer.rs')
-rw-r--r--crates/hir/src/source_analyzer.rs84
1 files changed, 51 insertions, 33 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 9d32229e8f..430b646e97 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -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))
}