From 9e1eb77f6b65bca03b324687fcbb9abcdff4b2d6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 10 Jul 2021 19:16:32 +0200 Subject: [PATCH] Respect coercions in `inline_call` --- crates/hir/src/semantics.rs | 2 +- crates/hir/src/source_analyzer.rs | 14 ++--- .../ide_assists/src/handlers/early_return.rs | 2 +- .../ide_assists/src/handlers/inline_call.rs | 51 ++++++++++++++++--- crates/syntax/src/ast/make.rs | 17 +++++-- 5 files changed, 67 insertions(+), 19 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index a4028c523fe..cac4bce3f90 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -576,7 +576,7 @@ fn type_of_pat(&self, pat: &ast::Pat) -> Option { self.analyze(pat.syntax()).type_of_pat(self.db, pat) } - fn type_of_pat_with_coercion(&self, pat: &ast::Pat)-> Option<(Type, Option)> { + fn type_of_pat_with_coercion(&self, pat: &ast::Pat) -> Option<(Type, Option)> { self.analyze(pat.syntax()).type_of_pat_with_coercion(self.db, pat) } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index ff0b6697c79..2ba8284fcbf 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -21,7 +21,7 @@ use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; use hir_ty::{ diagnostics::{record_literal_missing_fields, record_pattern_missing_fields}, - InferenceResult, Interner, Substitution, TyExt, TyLoweringContext, + InferenceResult, Interner, Substitution, Ty, TyExt, TyLoweringContext, }; use syntax::{ ast::{self, AstNode}, @@ -129,12 +129,12 @@ pub(crate) fn type_of_expr_with_coercion( ) -> Option<(Type, Option)> { let expr_id = self.expr_id(db, expr)?; let infer = self.infer.as_ref()?; - let ty = infer + let coerced = infer .expr_adjustments .get(&expr_id) .and_then(|adjusts| adjusts.last().map(|adjust| &adjust.target)); - let mk_ty = |ty: &hir_ty::Ty| Type::new_with_resolver(db, &self.resolver, ty.clone()); - mk_ty(&infer[expr_id]).map(|it| (it, ty.and_then(mk_ty))) + let mk_ty = |ty: &Ty| Type::new_with_resolver(db, &self.resolver, ty.clone()); + mk_ty(&infer[expr_id]).map(|ty| (ty, coerced.and_then(mk_ty))) } pub(crate) fn type_of_pat(&self, db: &dyn HirDatabase, pat: &ast::Pat) -> Option { @@ -150,12 +150,12 @@ pub(crate) fn type_of_pat_with_coercion( ) -> Option<(Type, Option)> { let pat_id = self.pat_id(pat)?; let infer = self.infer.as_ref()?; - let ty = infer + let coerced = infer .pat_adjustments .get(&pat_id) .and_then(|adjusts| adjusts.last().map(|adjust| &adjust.target)); - let mk_ty = |ty: &hir_ty::Ty| Type::new_with_resolver(db, &self.resolver, ty.clone()); - mk_ty(&infer[pat_id]).map(|it| (it, ty.and_then(mk_ty))) + let mk_ty = |ty: &Ty| Type::new_with_resolver(db, &self.resolver, ty.clone()); + mk_ty(&infer[pat_id]).map(|ty| (ty, coerced.and_then(mk_ty))) } pub(crate) fn type_of_self( diff --git a/crates/ide_assists/src/handlers/early_return.rs b/crates/ide_assists/src/handlers/early_return.rs index a8e451e7eea..b4745b84242 100644 --- a/crates/ide_assists/src/handlers/early_return.rs +++ b/crates/ide_assists/src/handlers/early_return.rs @@ -146,7 +146,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) }; - let let_stmt = make::let_stmt(bound_ident, Some(match_expr)); + let let_stmt = make::let_stmt(bound_ident, None, Some(match_expr)); let let_stmt = let_stmt.indent(if_indent_level); replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) } diff --git a/crates/ide_assists/src/handlers/inline_call.rs b/crates/ide_assists/src/handlers/inline_call.rs index 5bd81ba0513..0dcc12d8cb9 100644 --- a/crates/ide_assists/src/handlers/inline_call.rs +++ b/crates/ide_assists/src/handlers/inline_call.rs @@ -85,11 +85,12 @@ pub(crate) fn inline_( make::name("this"), ) .into(), + None, assoc_fn_params.next()?, )); } for param in param_list.params() { - params.push((param.pat()?, assoc_fn_params.next()?)); + params.push((param.pat()?, param.ty(), assoc_fn_params.next()?)); } if arg_list.len() != params.len() { @@ -123,7 +124,7 @@ pub(crate) fn inline_( // has a pattern that does not allow inlining let param_use_nodes: Vec> = params .iter() - .map(|(pat, param)| { + .map(|(pat, _, param)| { if !matches!(pat, ast::Pat::IdentPat(pat) if pat.is_simple_ident()) { return Vec::new(); } @@ -145,7 +146,7 @@ pub(crate) fn inline_( // Rewrite `self` to `this` if param_list.self_param().is_some() { let this = || make::name_ref("this").syntax().clone_for_update(); - usages_for_locals(params[0].1.as_local(ctx.sema.db)) + usages_for_locals(params[0].2.as_local(ctx.sema.db)) .flat_map(|FileReference { name, range, .. }| match name { ast::NameLike::NameRef(_) => Some(body.syntax().covering_element(range)), _ => None, @@ -156,7 +157,8 @@ pub(crate) fn inline_( } // Inline parameter expressions or generate `let` statements depending on whether inlining works or not. - for ((pat, _), usages, expr) in izip!(params, param_use_nodes, arg_list).rev() { + for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arg_list).rev() + { let expr_is_name_ref = matches!(&expr, ast::Expr::PathExpr(expr) if expr.path().and_then(|path| path.as_single_name_ref()).is_some() @@ -184,8 +186,17 @@ pub(crate) fn inline_( }); } // cant inline, emit a let statement - // FIXME: emit type ascriptions when a coercion happens? - _ => body.push_front(make::let_stmt(pat, Some(expr)).clone_for_update().into()), + _ => { + let ty = ctx + .sema + .type_of_expr_with_coercion(&expr) + .map_or(false, |(_, coerced)| coerced.is_some()) + .then(|| param_ty) + .flatten(); + body.push_front( + make::let_stmt(pat, ty, Some(expr)).clone_for_update().into(), + ) + } } } @@ -606,6 +617,34 @@ fn foo(x: u32) -> u32{ fn main() { 222; } +"#, + ); + } + + #[test] + fn inline_emits_type_for_coercion() { + check_assist( + inline_call, + r#" +fn foo(x: *const u32) -> u32 { + x as u32 +} + +fn main() { + foo$0(&222); +} +"#, + r#" +fn foo(x: *const u32) -> u32 { + x as u32 +} + +fn main() { + { + let x: *const u32 = &222; + x as u32 + }; +} "#, ); } diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 1eaf40f4cbe..f84e1755389 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -492,10 +492,19 @@ fn from_text(text: &str) -> ast::WhereClause { } } -pub fn let_stmt(pattern: ast::Pat, initializer: Option) -> ast::LetStmt { - let text = match initializer { - Some(it) => format!("let {} = {};", pattern, it), - None => format!("let {};", pattern), +pub fn let_stmt( + pattern: ast::Pat, + ty: Option, + initializer: Option, +) -> ast::LetStmt { + let mut text = String::new(); + format_to!(text, "let {}", pattern); + if let Some(ty) = ty { + format_to!(text, ": {}", ty); + } + match initializer { + Some(it) => format_to!(text, " = {};", it), + None => format_to!(text, ";"), }; ast_from_text(&format!("fn f() {{ {} }}", text)) }