diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 76a7f75b7a..c47988fc4c 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -89,7 +89,7 @@ pub use crate::{ UnresolvedModule, UnresolvedProcMacro, }, has_source::HasSource, - semantics::{PathResolution, Semantics, SemanticsScope}, + semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo}, }; // Be careful with these re-exports. diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index e17bd9594c..c94c7923c9 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -87,6 +87,28 @@ impl PathResolution { } } +#[derive(Debug)] +pub struct TypeInfo { + /// The original type of the expression or pattern. + pub ty: Type, + /// The coerced type, if a coercion happened. + pub coerced: Option, +} + +impl TypeInfo { + pub fn ty(self) -> Type { + self.ty + } + + pub fn coerced(self) -> Option { + self.coerced + } + + pub fn coerced_or_original(self) -> Type { + self.coerced.unwrap_or(self.ty) + } +} + /// Primary API to get semantic information, like types, from syntax trees. pub struct Semantics<'db, DB> { pub db: &'db DB, @@ -212,23 +234,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_type(ty) } - pub fn type_of_expr(&self, expr: &ast::Expr) -> Option { + pub fn type_of_expr(&self, expr: &ast::Expr) -> Option { self.imp.type_of_expr(expr) } - /// Returns true in case a coercion happened. - pub fn type_of_expr_with_coercion(&self, expr: &ast::Expr) -> Option<(Type, bool)> { - self.imp.type_of_expr_with_coercion(expr) - } - - pub fn type_of_pat(&self, pat: &ast::Pat) -> Option { + pub fn type_of_pat(&self, pat: &ast::Pat) -> Option { self.imp.type_of_pat(pat) } - pub fn type_of_pat_with_coercion(&self, expr: &ast::Pat) -> Option<(Type, bool)> { - self.imp.type_of_pat_with_coercion(expr) - } - pub fn type_of_self(&self, param: &ast::SelfParam) -> Option { self.imp.type_of_self(param) } @@ -565,20 +578,16 @@ impl<'db> SemanticsImpl<'db> { Type::new_with_resolver(self.db, &scope.resolver, ty) } - fn type_of_expr(&self, expr: &ast::Expr) -> Option { - self.analyze(expr.syntax()).type_of_expr(self.db, expr) + fn type_of_expr(&self, expr: &ast::Expr) -> Option { + self.analyze(expr.syntax()) + .type_of_expr(self.db, expr) + .map(|(ty, coerced)| TypeInfo { ty, coerced }) } - fn type_of_expr_with_coercion(&self, expr: &ast::Expr) -> Option<(Type, bool)> { - self.analyze(expr.syntax()).type_of_expr_with_coercion(self.db, expr) - } - - 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, bool)> { - self.analyze(pat.syntax()).type_of_pat_with_coercion(self.db, pat) + fn type_of_pat(&self, pat: &ast::Pat) -> Option { + self.analyze(pat.syntax()) + .type_of_pat(self.db, pat) + .map(|(ty, coerced)| TypeInfo { ty, coerced }) } fn type_of_self(&self, param: &ast::SelfParam) -> Option { @@ -757,7 +766,7 @@ impl<'db> SemanticsImpl<'db> { ast::Expr::FieldExpr(field_expr) => field_expr, _ => return None, }; - let ty = self.type_of_expr(&field_expr.expr()?)?; + let ty = self.type_of_expr(&field_expr.expr()?)?.ty; if !ty.is_packed(self.db) { return None; } @@ -784,7 +793,7 @@ impl<'db> SemanticsImpl<'db> { self.type_of_expr(&expr) }) // Binding a reference to a packed type is possibly unsafe. - .map(|ty| ty.is_packed(self.db)) + .map(|ty| ty.ty.is_packed(self.db)) .unwrap_or(false) // FIXME This needs layout computation to be correct. It will highlight @@ -830,7 +839,7 @@ impl<'db> SemanticsImpl<'db> { } }) // Binding a reference to a packed type is possibly unsafe. - .map(|ty| ty.is_packed(self.db)) + .map(|ty| ty.ty.is_packed(self.db)) .unwrap_or(false) } } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index e18d27e722..cb6fd69bc6 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -116,46 +116,36 @@ impl SourceAnalyzer { Some(res) } - pub(crate) fn type_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option { - let expr_id = self.expr_id(db, expr)?; - let ty = self.infer.as_ref()?[expr_id].clone(); - Type::new_with_resolver(db, &self.resolver, ty) - } - - pub(crate) fn type_of_expr_with_coercion( + pub(crate) fn type_of_expr( &self, db: &dyn HirDatabase, expr: &ast::Expr, - ) -> Option<(Type, bool)> { + ) -> Option<(Type, Option)> { let expr_id = self.expr_id(db, expr)?; let infer = self.infer.as_ref()?; - let (ty, coerced) = infer + let coerced = infer .expr_adjustments .get(&expr_id) - .and_then(|adjusts| adjusts.last().map(|adjust| (&adjust.target, true))) - .unwrap_or_else(|| (&infer[expr_id], false)); - Type::new_with_resolver(db, &self.resolver, ty.clone()).zip(Some(coerced)) + .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); + mk_ty(ty.clone()).zip(Some(coerced.and_then(mk_ty))) } - pub(crate) fn type_of_pat(&self, db: &dyn HirDatabase, pat: &ast::Pat) -> Option { - let pat_id = self.pat_id(pat)?; - let ty = self.infer.as_ref()?[pat_id].clone(); - Type::new_with_resolver(db, &self.resolver, ty) - } - - pub(crate) fn type_of_pat_with_coercion( + pub(crate) fn type_of_pat( &self, db: &dyn HirDatabase, pat: &ast::Pat, - ) -> Option<(Type, bool)> { + ) -> Option<(Type, Option)> { let pat_id = self.pat_id(pat)?; let infer = self.infer.as_ref()?; - let (ty, coerced) = infer + let coerced = infer .pat_adjustments .get(&pat_id) - .and_then(|adjusts| adjusts.last().map(|adjust| (&adjust.target, true))) - .unwrap_or_else(|| (&infer[pat_id], false)); - Type::new_with_resolver(db, &self.resolver, ty.clone()).zip(Some(coerced)) + .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone())); + let ty = infer[pat_id].clone(); + let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); + mk_ty(ty.clone()).zip(Some(coerced.and_then(mk_ty))) } pub(crate) fn type_of_self( diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index 7bf35d2b36..428f3f1c6d 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs @@ -86,7 +86,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio let name_ref = call_node.name_ref()?; let func_target = match call_node { FnCallNode::CallExpr(expr) => { - let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?; + let callable = sema.type_of_expr(&expr.expr()?)?.ty.as_callable(db)?; match callable.kind() { hir::CallableKind::Function(it) => it.try_to_nav(db), _ => None, diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index d51f154c6c..3e9dfb8cb6 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs @@ -32,8 +32,8 @@ pub(crate) fn goto_type_definition( let (ty, node) = sema.token_ancestors_with_macros(token).find_map(|node| { let ty = match_ast! { match node { - ast::Expr(it) => sema.type_of_expr(&it)?, - ast::Pat(it) => sema.type_of_pat(&it)?, + ast::Expr(it) => sema.type_of_expr(&it)?.ty, + ast::Pat(it) => sema.type_of_pat(&it)?.ty, ast::SelfParam(it) => sema.type_of_self(&it)?, ast::Type(it) => sema.resolve_type(&it)?, ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index fd154ede44..a1c50c6364 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -123,7 +123,7 @@ fn highlight_exit_points( } } ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_) | ast::Expr::MacroCall(_) => { - if sema.type_of_expr(&expr).map_or(false, |ty| ty.is_never()) { + if sema.type_of_expr(&expr).map_or(false, |ty| ty.ty.is_never()) { highlights .push(HighlightedRange { access: None, range: expr.syntax().text_range() }); } diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 732cc75e5f..9ca20776b5 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -1,5 +1,5 @@ use either::Either; -use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics}; +use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo}; use ide_db::{ base_db::{FileRange, SourceDatabase}, defs::{Definition, NameClass, NameRefClass}, @@ -225,19 +225,15 @@ fn hover_type_info( config: &HoverConfig, expr_or_pat: &Either, ) -> Option { - let (ty, coerced) = match expr_or_pat { - Either::Left(expr) => sema.type_of_expr_with_coercion(expr)?, - Either::Right(pat) => sema.type_of_pat_with_coercion(pat)?, + let TypeInfo { ty, coerced } = match expr_or_pat { + Either::Left(expr) => sema.type_of_expr(expr)?, + Either::Right(pat) => sema.type_of_pat(pat)?, }; let mut res = HoverResult::default(); - res.markup = if coerced { - let uncoerced_ty = match expr_or_pat { - Either::Left(expr) => sema.type_of_expr(expr)?, - Either::Right(pat) => sema.type_of_pat(pat)?, - }; - let uncoerced = uncoerced_ty.display(sema.db).to_string(); - let coerced = ty.display(sema.db).to_string(); + res.markup = if let Some(coerced_ty) = coerced { + let uncoerced = ty.display(sema.db).to_string(); + let coerced = coerced_ty.display(sema.db).to_string(); format!( "```text\nType: {:>upad$}\nCoerced to: {:>cpad$}\n```\n", uncoerced = uncoerced, diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 8c533d641b..48c2f893aa 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -1,5 +1,5 @@ use either::Either; -use hir::{known, Callable, HasVisibility, HirDisplay, Semantics}; +use hir::{known, Callable, HasVisibility, HirDisplay, Semantics, TypeInfo}; use ide_db::helpers::FamousDefs; use ide_db::RootDatabase; use stdx::to_lower_snake_case; @@ -117,7 +117,7 @@ fn get_chaining_hints( next_next = tokens.next()?.kind(); } if next_next == T![.] { - let ty = sema.type_of_expr(&expr)?; + let ty = sema.type_of_expr(&expr)?.ty; if ty.is_unknown() { return None; } @@ -189,7 +189,7 @@ fn get_bind_pat_hints( let krate = sema.scope(pat.syntax()).module().map(|it| it.krate()); let famous_defs = FamousDefs(sema, krate); - let ty = sema.type_of_pat(&pat.clone().into())?; + let ty = sema.type_of_pat(&pat.clone().into())?.ty; if should_not_display_type_hint(sema, &pat, &ty) { return None; @@ -308,6 +308,7 @@ fn should_not_display_type_hint( return it.in_token().is_none() || it.iterable() .and_then(|iterable_expr| sema.type_of_expr(&iterable_expr)) + .map(TypeInfo::ty) .map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit()) }, _ => (), @@ -393,7 +394,7 @@ fn is_enum_name_similar_to_param_name( argument: &ast::Expr, param_name: &str, ) -> bool { - match sema.type_of_expr(argument).and_then(|t| t.as_adt()) { + match sema.type_of_expr(argument).and_then(|t| t.ty.as_adt()) { Some(hir::Adt::Enum(e)) => to_lower_snake_case(&e.name(sema.db).to_string()) == param_name, _ => false, } @@ -430,7 +431,7 @@ fn get_callable( ) -> Option<(hir::Callable, ast::ArgList)> { match expr { ast::Expr::CallExpr(expr) => { - sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db).zip(expr.arg_list()) + sema.type_of_expr(&expr.expr()?)?.ty.as_callable(sema.db).zip(expr.arg_list()) } ast::Expr::MethodCallExpr(expr) => { sema.resolve_method_call_as_callable(expr).zip(expr.arg_list()) diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 6ace8ce83c..9d028c2901 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs @@ -123,7 +123,7 @@ pub(super) fn element( let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; let expr = prefix_expr.expr()?; - let ty = sema.type_of_expr(&expr)?; + let ty = sema.type_of_expr(&expr)?.ty; if ty.is_raw_ptr() { HlTag::Operator(HlOperator::Other) | HlMod::Unsafe } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() { @@ -555,7 +555,7 @@ fn highlight_method_call( if let Some(receiver_ty) = method_call.receiver().and_then(|it| sema.type_of_expr(&it)) { - if !receiver_ty.is_copy(sema.db) { + if !receiver_ty.ty.is_copy(sema.db) { h |= HlMod::Consuming } } diff --git a/crates/ide_assists/src/handlers/add_explicit_type.rs b/crates/ide_assists/src/handlers/add_explicit_type.rs index 5375095df6..9b5bb71b1b 100644 --- a/crates/ide_assists/src/handlers/add_explicit_type.rs +++ b/crates/ide_assists/src/handlers/add_explicit_type.rs @@ -54,9 +54,10 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio } let ty = match (pat, expr) { - (ast::Pat::IdentPat(_), Some(expr)) => ctx.sema.type_of_expr_with_coercion(&expr)?.0, + (ast::Pat::IdentPat(_), Some(expr)) => ctx.sema.type_of_expr(&expr)?, (pat, _) => ctx.sema.type_of_pat(&pat)?, - }; + } + .coerced_or_original(); // Unresolved or unnameable types can't be annotated if ty.contains_unknown() || ty.is_closure() { diff --git a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs index 70754adf9a..b6457da362 100644 --- a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs +++ b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs @@ -86,7 +86,7 @@ fn validate_method_call_expr( let receiver = expr.receiver()?; let expr = ast::Expr::MethodCallExpr(expr); - let it_type = sema.type_of_expr(&receiver)?; + let it_type = sema.type_of_expr(&receiver)?.ty; let module = sema.scope(receiver.syntax()).module()?; let krate = module.krate(); diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index 33c439a850..3ac794f45e 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs @@ -2,7 +2,7 @@ use std::{hash::BuildHasherDefault, iter}; use ast::make; use either::Either; -use hir::{HirDisplay, Local, Semantics}; +use hir::{HirDisplay, Local, Semantics, TypeInfo}; use ide_db::{ defs::{Definition, NameRefClass}, search::{FileReference, ReferenceAccess, SearchScope}, @@ -344,7 +344,9 @@ impl FlowKind { match self { FlowKind::Return(Some(expr)) | FlowKind::Break(Some(expr)) - | FlowKind::TryReturn { expr, .. } => ctx.sema.type_of_expr(expr), + | FlowKind::TryReturn { expr, .. } => { + ctx.sema.type_of_expr(expr).map(TypeInfo::coerced_or_original) + } FlowKind::Try { .. } => { stdx::never!("try does not have defined expr_ty"); None @@ -850,10 +852,7 @@ fn either_syntax(value: &Either) -> &SyntaxNode { fn body_return_ty(ctx: &AssistContext, body: &FunctionBody) -> Option { match body.tail_expr() { - Some(expr) => { - let ty = ctx.sema.type_of_expr(&expr)?; - Some(RetType::Expr(ty)) - } + Some(expr) => ctx.sema.type_of_expr(&expr).map(TypeInfo::ty).map(RetType::Expr), None => Some(RetType::Stmt), } } @@ -950,7 +949,7 @@ fn expr_err_kind(expr: &ast::Expr, ctx: &AssistContext) -> Option { let text = func_name.syntax().text(); if text == "Err" { - Some(TryKind::Result { ty: ctx.sema.type_of_expr(expr)? }) + Some(TryKind::Result { ty: ctx.sema.type_of_expr(expr).map(TypeInfo::ty)? }) } else if text == "None" { Some(TryKind::Option) } else { diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs index 176f52aa4d..6d457f3191 100644 --- a/crates/ide_assists/src/handlers/extract_variable.rs +++ b/crates/ide_assists/src/handlers/extract_variable.rs @@ -39,8 +39,8 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option .ancestors() .take_while(|it| it.text_range().contains_range(ctx.frange.range)) .find_map(valid_target_expr)?; - if let Some(ty) = ctx.sema.type_of_expr(&to_extract) { - if ty.is_unit() { + if let Some(ty_info) = ctx.sema.type_of_expr(&to_extract) { + if ty_info.ty.is_unit() { return None; } } diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs index 7b117acb36..4e060529a9 100644 --- a/crates/ide_assists/src/handlers/fill_match_arms.rs +++ b/crates/ide_assists/src/handlers/fill_match_arms.rs @@ -223,7 +223,7 @@ impl ExtendedEnum { } fn resolve_enum_def(sema: &Semantics, expr: &ast::Expr) -> Option { - sema.type_of_expr(expr)?.autoderef(sema.db).find_map(|ty| match ty.as_adt() { + sema.type_of_expr(expr)?.ty.autoderef(sema.db).find_map(|ty| match ty.as_adt() { Some(Adt::Enum(e)) => Some(ExtendedEnum::Enum(e)), _ => ty.is_bool().then(|| ExtendedEnum::Bool), }) @@ -234,6 +234,7 @@ fn resolve_tuple_of_enum_def( expr: &ast::Expr, ) -> Option> { sema.type_of_expr(expr)? + .ty .tuple_fields(sema.db) .iter() .map(|ty| { diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs index d06e3f7094..365f26a02a 100644 --- a/crates/ide_assists/src/handlers/generate_function.rs +++ b/crates/ide_assists/src/handlers/generate_function.rs @@ -1,4 +1,4 @@ -use hir::HirDisplay; +use hir::{HirDisplay, TypeInfo}; use ide_db::{base_db::FileId, helpers::SnippetCap}; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::to_lower_snake_case; @@ -153,7 +153,7 @@ impl FunctionBuilder { // type, but that the current state of their code doesn't allow that return type // to be accurately inferred. let (ret_ty, should_render_snippet) = { - match ctx.sema.type_of_expr(&ast::Expr::CallExpr(call.clone())) { + match ctx.sema.type_of_expr(&ast::Expr::CallExpr(call.clone())).map(TypeInfo::ty) { Some(ty) if ty.is_unknown() || ty.is_unit() => (make::ty_unit(), true), Some(ty) => { let rendered = ty.display_source_code(ctx.db(), target_module.into()); @@ -331,7 +331,7 @@ fn fn_arg_type( target_module: hir::Module, fn_arg: &ast::Expr, ) -> Option { - let ty = ctx.sema.type_of_expr(fn_arg)?; + let ty = ctx.sema.type_of_expr(fn_arg)?.ty; if ty.is_unknown() { return None; } diff --git a/crates/ide_assists/src/handlers/infer_function_return_type.rs b/crates/ide_assists/src/handlers/infer_function_return_type.rs index 66113751c6..0dfce46466 100644 --- a/crates/ide_assists/src/handlers/infer_function_return_type.rs +++ b/crates/ide_assists/src/handlers/infer_function_return_type.rs @@ -18,7 +18,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn infer_function_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { let (fn_type, tail_expr, builder_edit_pos) = extract_tail(ctx)?; let module = ctx.sema.scope(tail_expr.syntax()).module()?; - let ty = ctx.sema.type_of_expr(&tail_expr)?; + let ty = ctx.sema.type_of_expr(&tail_expr)?.ty; if ty.is_unit() { return None; } diff --git a/crates/ide_assists/src/handlers/inline_call.rs b/crates/ide_assists/src/handlers/inline_call.rs index 0ecf930cb9..fd098bcaf9 100644 --- a/crates/ide_assists/src/handlers/inline_call.rs +++ b/crates/ide_assists/src/handlers/inline_call.rs @@ -1,5 +1,5 @@ use ast::make; -use hir::{HasSource, PathResolution}; +use hir::{HasSource, PathResolution, TypeInfo}; use ide_db::{defs::Definition, search::FileReference}; use itertools::izip; use syntax::{ @@ -189,10 +189,9 @@ pub(crate) fn inline_( _ => { let ty = ctx .sema - .type_of_expr_with_coercion(&expr) - .map_or(false, |(_, coerced)| coerced) - .then(|| param_ty) - .flatten(); + .type_of_expr(&expr) + .and_then(TypeInfo::coerced) + .and_then(|_| param_ty); body.push_front( make::let_stmt(pat, ty, Some(expr)).clone_for_update().into(), ) diff --git a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs index 5f2aa016f4..b67ec8b14c 100644 --- a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs +++ b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs @@ -80,13 +80,13 @@ fn is_ref_and_impls_iter_method( }; let wanted_method = if ref_expr.mut_token().is_some() { known::iter_mut } else { known::iter }; let expr_behind_ref = ref_expr.expr()?; - let typ = sema.type_of_expr(&expr_behind_ref)?; + let ty = sema.type_of_expr(&expr_behind_ref)?.ty; let scope = sema.scope(iterable.syntax()); let krate = scope.module()?.krate(); let traits_in_scope = scope.traits_in_scope(); let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; - let has_wanted_method = typ + let has_wanted_method = ty .iterate_method_candidates( sema.db, krate, @@ -110,7 +110,7 @@ fn is_ref_and_impls_iter_method( /// Whether iterable implements core::Iterator fn impls_core_iter(sema: &hir::Semantics, iterable: &ast::Expr) -> bool { let it_typ = match sema.type_of_expr(iterable) { - Some(it) => it, + Some(it) => it.ty, None => return false, }; diff --git a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs index 25a9e71502..a458bced0c 100644 --- a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs @@ -127,7 +127,7 @@ fn make_else_arm( let pattern = if let [(Either::Left(pat), _)] = conditionals { ctx.sema .type_of_pat(&pat) - .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty)) + .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.ty)) .zip(Some(pat)) } else { None @@ -268,7 +268,7 @@ fn binds_name(pat: &ast::Pat) -> bool { fn is_sad_pat(sema: &hir::Semantics, pat: &ast::Pat) -> bool { sema.type_of_pat(pat) - .and_then(|ty| TryEnum::from_ty(sema, &ty)) + .and_then(|ty| TryEnum::from_ty(sema, &ty.ty)) .map_or(false, |it| does_pat_match_variant(pat, &it.sad_pattern())) } diff --git a/crates/ide_assists/src/handlers/replace_let_with_if_let.rs b/crates/ide_assists/src/handlers/replace_let_with_if_let.rs index 614fb3cb4f..2f95af8ef2 100644 --- a/crates/ide_assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/ide_assists/src/handlers/replace_let_with_if_let.rs @@ -50,7 +50,7 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> |edit| { let ty = ctx.sema.type_of_expr(&init); let happy_variant = - ty.and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty)).map(|it| it.happy_case()); + ty.and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.ty)).map(|it| it.happy_case()); let pat = match happy_variant { None => original_pat, Some(var_name) => { diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs index 81463745a4..2e58c58c19 100644 --- a/crates/ide_assists/src/utils.rs +++ b/crates/ide_assists/src/utils.rs @@ -273,7 +273,9 @@ fn bin_impls_ord(sema: &Semantics, bin: &ast::BinExpr) -> bool { bin.lhs().and_then(|lhs| sema.type_of_expr(&lhs)), bin.rhs().and_then(|rhs| sema.type_of_expr(&rhs)), ) { - (Some(lhs_ty), Some(rhs_ty)) if lhs_ty == rhs_ty => { + (Some(hir::TypeInfo { ty: lhs_ty, .. }), Some(hir::TypeInfo { ty: rhs_ty, .. })) + if lhs_ty == rhs_ty => + { let krate = sema.scope(bin.syntax()).module().map(|it| it.krate()); let ord_trait = FamousDefs(sema, krate).core_cmp_Ord(); ord_trait.map_or(false, |ord_trait| { diff --git a/crates/ide_assists/src/utils/suggest_name.rs b/crates/ide_assists/src/utils/suggest_name.rs index cb8bc8b2fe..da5370a6d0 100644 --- a/crates/ide_assists/src/utils/suggest_name.rs +++ b/crates/ide_assists/src/utils/suggest_name.rs @@ -197,7 +197,7 @@ fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option { let func = call.expr()?; - let func_ty = sema.type_of_expr(&func)?; + let func_ty = sema.type_of_expr(&func)?.ty; func_ty.as_callable(sema.db)? }, ast::MethodCallExpr(method) => sema.resolve_method_call_as_callable(&method)?, @@ -225,7 +225,7 @@ fn var_name_from_pat(pat: &ast::Pat) -> Option { } fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option { - let ty = sema.type_of_expr(expr)?; + let ty = sema.type_of_expr(expr)?.ty; let ty = ty.remove_ref().unwrap_or(ty); name_of_type(&ty, sema.db) diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index fc3f9005e7..564f5f2eae 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs @@ -14,7 +14,7 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { }; let receiver_ty = match ctx.sema.type_of_expr(dot_receiver) { - Some(ty) => ty, + Some(ty) => ty.ty, _ => return, }; diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 0118d94641..e10eb26936 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs @@ -180,7 +180,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option it, + Some(it) => it.ty, None => return, }; diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index 151297042b..d15375634d 100644 --- a/crates/ide_completion/src/completions/record.rs +++ b/crates/ide_completion/src/completions/record.rs @@ -14,7 +14,7 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default(); let impl_default_trait = default_trait .zip(ty) - .map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[])); + .map_or(false, |(default_trait, ty)| ty.ty.impls_trait(ctx.db, default_trait, &[])); let missing_fields = ctx.sema.record_literal_missing_fields(record_expr); if impl_default_trait && !missing_fields.is_empty() { diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 06f16f9338..6922c203ce 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -1,7 +1,7 @@ //! See `CompletionContext` structure. use base_db::SourceDatabaseExt; -use hir::{Local, Name, ScopeDef, Semantics, SemanticsScope, Type}; +use hir::{Local, Name, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo}; use ide_db::{ base_db::{FilePosition, SourceDatabase}, call_info::ActiveParameter, @@ -453,7 +453,8 @@ impl<'a> CompletionContext<'a> { cov_mark::hit!(expected_type_let_without_leading_char); let ty = it.pat() .and_then(|pat| self.sema.type_of_pat(&pat)) - .or_else(|| it.initializer().and_then(|it| self.sema.type_of_expr(&it))); + .or_else(|| it.initializer().and_then(|it| self.sema.type_of_expr(&it))) + .map(TypeInfo::ty); let name = if let Some(ast::Pat::IdentPat(ident)) = it.pat() { ident.name().map(NameOrNameRef::Name) } else { @@ -496,27 +497,27 @@ impl<'a> CompletionContext<'a> { ast::RecordExprField(it) => { cov_mark::hit!(expected_type_struct_field_with_leading_char); ( - it.expr().as_ref().and_then(|e| self.sema.type_of_expr(e)), + it.expr().as_ref().and_then(|e| self.sema.type_of_expr(e)).map(TypeInfo::ty), it.field_name().map(NameOrNameRef::NameRef), ) }, ast::MatchExpr(it) => { cov_mark::hit!(expected_type_match_arm_without_leading_char); - let ty = it.expr() - .and_then(|e| self.sema.type_of_expr(&e)); + let ty = it.expr().and_then(|e| self.sema.type_of_expr(&e)).map(TypeInfo::ty); (ty, None) }, ast::IfExpr(it) => { cov_mark::hit!(expected_type_if_let_without_leading_char); let ty = it.condition() .and_then(|cond| cond.expr()) - .and_then(|e| self.sema.type_of_expr(&e)); + .and_then(|e| self.sema.type_of_expr(&e)) + .map(TypeInfo::ty); (ty, None) }, ast::IdentPat(it) => { cov_mark::hit!(expected_type_if_let_with_leading_char); cov_mark::hit!(expected_type_match_arm_with_leading_char); - let ty = self.sema.type_of_pat(&ast::Pat::from(it)); + let ty = self.sema.type_of_pat(&ast::Pat::from(it)).map(TypeInfo::ty); (ty, None) }, ast::Fn(it) => { @@ -527,7 +528,7 @@ impl<'a> CompletionContext<'a> { }, ast::ClosureExpr(it) => { let ty = self.sema.type_of_expr(&it.into()); - ty.and_then(|ty| ty.as_callable(self.db)) + ty.and_then(|ty| ty.ty.as_callable(self.db)) .map(|c| (Some(c.return_type()), None)) .unwrap_or((None, None)) }, diff --git a/crates/ide_db/src/call_info.rs b/crates/ide_db/src/call_info.rs index 4795e25650..ea2662185f 100644 --- a/crates/ide_db/src/call_info.rs +++ b/crates/ide_db/src/call_info.rs @@ -118,7 +118,7 @@ fn call_info_impl( let calling_node = FnCallNode::with_node(&token.parent()?)?; let callable = match &calling_node { - FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?, + FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.ty.as_callable(sema.db)?, FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?, }; let active_param = if let Some(arg_list) = calling_node.arg_list() { diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index 23489aca99..6e174ffb84 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs @@ -543,7 +543,7 @@ impl ImportCandidate { match sema.resolve_method_call(method_call) { Some(_) => None, None => Some(Self::TraitMethod(TraitImportCandidate { - receiver_ty: sema.type_of_expr(&method_call.receiver()?)?, + receiver_ty: sema.type_of_expr(&method_call.receiver()?)?.ty, assoc_item_name: NameToImport::Exact(method_call.name_ref()?.to_string()), })), } diff --git a/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs index 469ab21d3c..06dc8dcd8b 100644 --- a/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs +++ b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs @@ -1,4 +1,4 @@ -use hir::db::AstDatabase; +use hir::{db::AstDatabase, TypeInfo}; use ide_db::{assists::Assist, helpers::for_each_tail_expr, source_change::SourceChange}; use syntax::AstNode; use text_edit::TextEdit; @@ -35,7 +35,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingOkOrSomeInTailExpr) -> Op let tail_expr_range = tail_expr.syntax().text_range(); let mut builder = TextEdit::builder(); for_each_tail_expr(&tail_expr, &mut |expr| { - if ctx.sema.type_of_expr(expr).as_ref() != Some(&d.expected) { + if ctx.sema.type_of_expr(expr).map(TypeInfo::ty).as_ref() != Some(&d.expected) { builder.insert(expr.syntax().text_range().start(), format!("{}(", d.required)); builder.insert(expr.syntax().text_range().end(), ")".to_string()); } diff --git a/crates/ide_diagnostics/src/handlers/no_such_field.rs b/crates/ide_diagnostics/src/handlers/no_such_field.rs index 92e8867f42..cf0d5f9b25 100644 --- a/crates/ide_diagnostics/src/handlers/no_such_field.rs +++ b/crates/ide_diagnostics/src/handlers/no_such_field.rs @@ -62,7 +62,7 @@ fn missing_record_expr_field_fixes( }; let def_file_id = def_file_id.original_file(sema.db); - let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?; + let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?.ty; if new_field_type.is_unknown() { return None; } diff --git a/crates/ide_ssr/src/matching.rs b/crates/ide_ssr/src/matching.rs index fb92a0ccc7..6699d29f97 100644 --- a/crates/ide_ssr/src/matching.rs +++ b/crates/ide_ssr/src/matching.rs @@ -609,9 +609,13 @@ impl<'db, 'sema> Matcher<'db, 'sema> { expr: &ast::Expr, ) -> Result { use hir::HirDisplay; - let code_type = self.sema.type_of_expr(expr).ok_or_else(|| { - match_error!("Failed to get receiver type for `{}`", expr.syntax().text()) - })?; + let code_type = self + .sema + .type_of_expr(expr) + .ok_or_else(|| { + match_error!("Failed to get receiver type for `{}`", expr.syntax().text()) + })? + .ty; // Temporary needed to make the borrow checker happy. let res = code_type .autoderef(self.sema.db)