Skip to content

Commit 7e6f40b

Browse files
committed
Expose coercions for patterns and expressions in semantics
1 parent 576e3a4 commit 7e6f40b

File tree

3 files changed

+31
-7
lines changed

3 files changed

+31
-7
lines changed

crates/hir/src/semantics.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,14 +216,18 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
216216
self.imp.type_of_expr(expr)
217217
}
218218

219-
pub fn type_of_expr_with_coercion(&self, expr: &ast::Expr) -> Option<Type> {
219+
pub fn type_of_expr_with_coercion(&self, expr: &ast::Expr) -> Option<(Type, Option<Type>)> {
220220
self.imp.type_of_expr_with_coercion(expr)
221221
}
222222

223223
pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
224224
self.imp.type_of_pat(pat)
225225
}
226226

227+
pub fn type_of_pat_with_coercion(&self, expr: &ast::Pat) -> Option<(Type, Option<Type>)> {
228+
self.imp.type_of_pat_with_coercion(expr)
229+
}
230+
227231
pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
228232
self.imp.type_of_self(param)
229233
}
@@ -564,14 +568,18 @@ impl<'db> SemanticsImpl<'db> {
564568
self.analyze(expr.syntax()).type_of_expr(self.db, expr)
565569
}
566570

567-
fn type_of_expr_with_coercion(&self, expr: &ast::Expr) -> Option<Type> {
571+
fn type_of_expr_with_coercion(&self, expr: &ast::Expr) -> Option<(Type, Option<Type>)> {
568572
self.analyze(expr.syntax()).type_of_expr_with_coercion(self.db, expr)
569573
}
570574

571575
fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
572576
self.analyze(pat.syntax()).type_of_pat(self.db, pat)
573577
}
574578

579+
fn type_of_pat_with_coercion(&self, pat: &ast::Pat)-> Option<(Type, Option<Type>)> {
580+
self.analyze(pat.syntax()).type_of_pat_with_coercion(self.db, pat)
581+
}
582+
575583
fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
576584
self.analyze(param.syntax()).type_of_self(self.db, param)
577585
}

crates/hir/src/source_analyzer.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,15 @@ impl SourceAnalyzer {
126126
&self,
127127
db: &dyn HirDatabase,
128128
expr: &ast::Expr,
129-
) -> Option<Type> {
129+
) -> Option<(Type, Option<Type>)> {
130130
let expr_id = self.expr_id(db, expr)?;
131131
let infer = self.infer.as_ref()?;
132132
let ty = infer
133133
.expr_adjustments
134134
.get(&expr_id)
135-
.and_then(|adjusts| adjusts.last().map(|adjust| &adjust.target))
136-
.unwrap_or_else(|| &infer[expr_id]);
137-
Type::new_with_resolver(db, &self.resolver, ty.clone())
135+
.and_then(|adjusts| adjusts.last().map(|adjust| &adjust.target));
136+
let mk_ty = |ty: &hir_ty::Ty| Type::new_with_resolver(db, &self.resolver, ty.clone());
137+
mk_ty(&infer[expr_id]).map(|it| (it, ty.and_then(mk_ty)))
138138
}
139139

140140
pub(crate) fn type_of_pat(&self, db: &dyn HirDatabase, pat: &ast::Pat) -> Option<Type> {
@@ -143,6 +143,21 @@ impl SourceAnalyzer {
143143
Type::new_with_resolver(db, &self.resolver, ty)
144144
}
145145

146+
pub(crate) fn type_of_pat_with_coercion(
147+
&self,
148+
db: &dyn HirDatabase,
149+
pat: &ast::Pat,
150+
) -> Option<(Type, Option<Type>)> {
151+
let pat_id = self.pat_id(pat)?;
152+
let infer = self.infer.as_ref()?;
153+
let ty = infer
154+
.pat_adjustments
155+
.get(&pat_id)
156+
.and_then(|adjusts| adjusts.last().map(|adjust| &adjust.target));
157+
let mk_ty = |ty: &hir_ty::Ty| Type::new_with_resolver(db, &self.resolver, ty.clone());
158+
mk_ty(&infer[pat_id]).map(|it| (it, ty.and_then(mk_ty)))
159+
}
160+
146161
pub(crate) fn type_of_self(
147162
&self,
148163
db: &dyn HirDatabase,

crates/ide_assists/src/handlers/add_explicit_type.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
5555
}
5656

5757
// Infer type
58-
let ty = ctx.sema.type_of_expr_with_coercion(&expr)?;
58+
let (ty, coerced) = ctx.sema.type_of_expr_with_coercion(&expr)?;
59+
let ty = coerced.unwrap_or(ty);
5960
if ty.contains_unknown() || ty.is_closure() {
6061
cov_mark::hit!(add_explicit_type_not_applicable_if_ty_not_inferred);
6162
return None;

0 commit comments

Comments
 (0)