Skip to content

Commit d556004

Browse files
committed
Respect coercions in inline_call
1 parent 7e6f40b commit d556004

File tree

4 files changed

+66
-18
lines changed

4 files changed

+66
-18
lines changed

crates/hir/src/source_analyzer.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use hir_def::{
2121
use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
2222
use hir_ty::{
2323
diagnostics::{record_literal_missing_fields, record_pattern_missing_fields},
24-
InferenceResult, Interner, Substitution, TyExt, TyLoweringContext,
24+
InferenceResult, Interner, Substitution, Ty, TyExt, TyLoweringContext,
2525
};
2626
use syntax::{
2727
ast::{self, AstNode},
@@ -129,12 +129,12 @@ impl SourceAnalyzer {
129129
) -> Option<(Type, Option<Type>)> {
130130
let expr_id = self.expr_id(db, expr)?;
131131
let infer = self.infer.as_ref()?;
132-
let ty = infer
132+
let coerced = infer
133133
.expr_adjustments
134134
.get(&expr_id)
135135
.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)))
136+
let mk_ty = |ty: &Ty| Type::new_with_resolver(db, &self.resolver, ty.clone());
137+
mk_ty(&infer[expr_id]).map(|ty| (ty, coerced.and_then(mk_ty)))
138138
}
139139

140140
pub(crate) fn type_of_pat(&self, db: &dyn HirDatabase, pat: &ast::Pat) -> Option<Type> {
@@ -150,12 +150,12 @@ impl SourceAnalyzer {
150150
) -> Option<(Type, Option<Type>)> {
151151
let pat_id = self.pat_id(pat)?;
152152
let infer = self.infer.as_ref()?;
153-
let ty = infer
153+
let coerced = infer
154154
.pat_adjustments
155155
.get(&pat_id)
156156
.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)))
157+
let mk_ty = |ty: &Ty| Type::new_with_resolver(db, &self.resolver, ty.clone());
158+
mk_ty(&infer[pat_id]).map(|ty| (ty, coerced.and_then(mk_ty)))
159159
}
160160

161161
pub(crate) fn type_of_self(

crates/ide_assists/src/handlers/early_return.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
146146
make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
147147
};
148148

149-
let let_stmt = make::let_stmt(bound_ident, Some(match_expr));
149+
let let_stmt = make::let_stmt(bound_ident, None, Some(match_expr));
150150
let let_stmt = let_stmt.indent(if_indent_level);
151151
replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
152152
}

crates/ide_assists/src/handlers/inline_call.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,12 @@ pub(crate) fn inline_(
8585
make::name("this"),
8686
)
8787
.into(),
88+
None,
8889
assoc_fn_params.next()?,
8990
));
9091
}
9192
for param in param_list.params() {
92-
params.push((param.pat()?, assoc_fn_params.next()?));
93+
params.push((param.pat()?, param.ty(), assoc_fn_params.next()?));
9394
}
9495

9596
if arg_list.len() != params.len() {
@@ -123,7 +124,7 @@ pub(crate) fn inline_(
123124
// has a pattern that does not allow inlining
124125
let param_use_nodes: Vec<Vec<_>> = params
125126
.iter()
126-
.map(|(pat, param)| {
127+
.map(|(pat, _, param)| {
127128
if !matches!(pat, ast::Pat::IdentPat(pat) if pat.is_simple_ident()) {
128129
return Vec::new();
129130
}
@@ -145,7 +146,7 @@ pub(crate) fn inline_(
145146
// Rewrite `self` to `this`
146147
if param_list.self_param().is_some() {
147148
let this = || make::name_ref("this").syntax().clone_for_update();
148-
usages_for_locals(params[0].1.as_local(ctx.sema.db))
149+
usages_for_locals(params[0].2.as_local(ctx.sema.db))
149150
.flat_map(|FileReference { name, range, .. }| match name {
150151
ast::NameLike::NameRef(_) => Some(body.syntax().covering_element(range)),
151152
_ => None,
@@ -156,7 +157,8 @@ pub(crate) fn inline_(
156157
}
157158

158159
// Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
159-
for ((pat, _), usages, expr) in izip!(params, param_use_nodes, arg_list).rev() {
160+
for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arg_list).rev()
161+
{
160162
let expr_is_name_ref = matches!(&expr,
161163
ast::Expr::PathExpr(expr)
162164
if expr.path().and_then(|path| path.as_single_name_ref()).is_some()
@@ -184,8 +186,17 @@ pub(crate) fn inline_(
184186
});
185187
}
186188
// cant inline, emit a let statement
187-
// FIXME: emit type ascriptions when a coercion happens?
188-
_ => body.push_front(make::let_stmt(pat, Some(expr)).clone_for_update().into()),
189+
_ => {
190+
let ty = ctx
191+
.sema
192+
.type_of_expr_with_coercion(&expr)
193+
.map_or(false, |(_, coerced)| coerced.is_some())
194+
.then(|| param_ty)
195+
.flatten();
196+
body.push_front(
197+
make::let_stmt(pat, ty, Some(expr)).clone_for_update().into(),
198+
)
199+
}
189200
}
190201
}
191202

@@ -606,6 +617,34 @@ fn foo(x: u32) -> u32{
606617
fn main() {
607618
222;
608619
}
620+
"#,
621+
);
622+
}
623+
624+
#[test]
625+
fn inline_emits_type_for_coercion() {
626+
check_assist(
627+
inline_call,
628+
r#"
629+
fn foo(x: *const u32) -> u32 {
630+
x as u32
631+
}
632+
633+
fn main() {
634+
foo$0(&222);
635+
}
636+
"#,
637+
r#"
638+
fn foo(x: *const u32) -> u32 {
639+
x as u32
640+
}
641+
642+
fn main() {
643+
{
644+
let x: *const u32 = &222;
645+
x as u32
646+
};
647+
}
609648
"#,
610649
);
611650
}

crates/syntax/src/ast/make.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -492,10 +492,19 @@ pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::Whe
492492
}
493493
}
494494

495-
pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetStmt {
496-
let text = match initializer {
497-
Some(it) => format!("let {} = {};", pattern, it),
498-
None => format!("let {};", pattern),
495+
pub fn let_stmt(
496+
pattern: ast::Pat,
497+
ty: Option<ast::Type>,
498+
initializer: Option<ast::Expr>,
499+
) -> ast::LetStmt {
500+
let mut text = String::new();
501+
format_to!(text, "let {}", pattern);
502+
if let Some(ty) = ty {
503+
format_to!(text, ": {}", ty);
504+
}
505+
match initializer {
506+
Some(it) => format_to!(text, " = {};", it),
507+
None => format_to!(text, ";"),
499508
};
500509
ast_from_text(&format!("fn f() {{ {} }}", text))
501510
}

0 commit comments

Comments
 (0)