From 49da9a3e814a42a2f4dea0cd79dbdae86bea5ce4 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Fri, 1 Mar 2019 18:26:49 -0500 Subject: [PATCH 1/7] Make goto definition/hover resolve constructors --- crates/ra_hir/src/ty/infer.rs | 43 ++++++++++++++++++++++-- crates/ra_ide_api/src/goto_definition.rs | 29 +++++++++++++--- crates/ra_ide_api/src/hover.rs | 22 ++++++++++++ 3 files changed, 87 insertions(+), 7 deletions(-) diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 5e4d49ffbf..f7a35f05b5 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -54,6 +54,24 @@ pub fn infer(db: &impl HirDatabase, func: Function) -> Arc { Arc::new(ctx.resolve_all()) } +#[derive(Debug, Copy, Clone)] +enum ExprOrPatId { + Expr(ExprId), + Pat(PatId), +} + +impl From for ExprOrPatId { + fn from(id: ExprId) -> Self { + ExprOrPatId::Expr(id) + } +} + +impl From for ExprOrPatId { + fn from(id: PatId) -> Self { + ExprOrPatId::Pat(id) + } +} + /// The result of type inference: A mapping from expressions and patterns to types. #[derive(Clone, PartialEq, Eq, Debug)] pub struct InferenceResult { @@ -61,6 +79,8 @@ pub struct InferenceResult { method_resolutions: FxHashMap, /// For each field access expr, records the field it resolves to. field_resolutions: FxHashMap, + /// For each associated function call expr, records the function it resolves to + assoc_fn_resolutions: FxHashMap, pub(super) type_of_expr: ArenaMap, pub(super) type_of_pat: ArenaMap, } @@ -72,6 +92,9 @@ impl InferenceResult { pub fn field_resolution(&self, expr: ExprId) -> Option { self.field_resolutions.get(&expr).map(|it| *it) } + pub fn assoc_fn_resolutions(&self, expr: ExprId) -> Option { + self.assoc_fn_resolutions.get(&expr).map(|it| *it) + } } impl Index for InferenceResult { @@ -99,6 +122,7 @@ struct InferenceContext<'a, D: HirDatabase> { var_unification_table: InPlaceUnificationTable, method_resolutions: FxHashMap, field_resolutions: FxHashMap, + assoc_fn_resolutions: FxHashMap, type_of_expr: ArenaMap, type_of_pat: ArenaMap, /// The return type of the function being inferred. @@ -110,6 +134,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { InferenceContext { method_resolutions: FxHashMap::default(), field_resolutions: FxHashMap::default(), + assoc_fn_resolutions: FxHashMap::default(), type_of_expr: ArenaMap::default(), type_of_pat: ArenaMap::default(), var_unification_table: InPlaceUnificationTable::new(), @@ -135,6 +160,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { InferenceResult { method_resolutions: self.method_resolutions, field_resolutions: self.field_resolutions, + assoc_fn_resolutions: self.assoc_fn_resolutions, type_of_expr: expr_types, type_of_pat: pat_types, } @@ -152,6 +178,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.field_resolutions.insert(expr, field); } + fn write_assoc_fn_resolution(&mut self, expr: ExprId, func: Function) { + self.assoc_fn_resolutions.insert(expr, func); + } + fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { self.type_of_pat.insert(pat, ty); } @@ -341,7 +371,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }) } - fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option { + fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option { let resolved = resolver.resolve_path_segments(self.db, &path); let (def, remaining_index) = resolved.into_inner(); @@ -421,6 +451,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let typable: Option = def.into(); let typable = typable?; + if let ExprOrPatId::Expr(expr) = id { + match typable { + TypableDef::Function(func) => self.write_assoc_fn_resolution(expr, func), + _ => {} + }; + } + let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs); let ty = self.insert_type_vars(ty); @@ -572,7 +609,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Pat::Path(path) => { // TODO use correct resolver for the surrounding expression let resolver = self.resolver.clone(); - self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown) + self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) } Pat::Bind { mode, name: _name, subpat } => { let inner_ty = if let Some(subpat) = subpat { @@ -782,7 +819,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Expr::Path(p) => { // TODO this could be more efficient... let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); - self.infer_path_expr(&resolver, p).unwrap_or(Ty::Unknown) + self.infer_path_expr(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) } Expr::Continue => Ty::Never, Expr::Break { expr } => { diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 9ec179593a..e4febe8ccd 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -47,9 +47,10 @@ pub(crate) fn reference_definition( name_ref: &ast::NameRef, ) -> ReferenceResult { use self::ReferenceResult::*; - if let Some(function) = - hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax()) - { + + let function = hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax()); + + if let Some(function) = function { // Check if it is a method if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { tested_by!(goto_definition_works_for_methods); @@ -122,9 +123,29 @@ pub(crate) fn reference_definition( Some(Resolution::SelfType(_impl_block)) => { // TODO: go to the implemented type } - None => {} + None => { + // If we failed to resolve then check associated items + if let Some(function) = function { + // Should we do this above and then grab path from the PathExpr? + if let Some(path_expr) = + name_ref.syntax().ancestors().find_map(ast::PathExpr::cast) + { + let infer_result = function.infer(db); + let syntax_mapping = function.body_syntax_mapping(db); + let expr = ast::Expr::cast(path_expr.syntax()).unwrap(); + + if let Some(func) = syntax_mapping + .node_expr(expr) + .and_then(|it| infer_result.assoc_fn_resolutions(it)) + { + return Exact(NavigationTarget::from_function(db, func)); + } + } + } + } } } + // If that fails try the index based approach. let navs = crate::symbol_index::index_resolve(db, name_ref) .into_iter() diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 8ec60090db..0f13777d7d 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -512,4 +512,26 @@ mod tests { let hover = analysis.hover(position).unwrap().unwrap(); assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing")); } + + #[test] + fn test_hover_infer_associated_method_exact() { + let (analysis, position) = single_file_with_position( + " + struct Thing { x: u32 } + + impl Thing { + fn new() -> Thing { + Thing { x: 0 } + } + } + + fn main() { + let foo_test = Thing::new<|>(); + } + ", + ); + let hover = analysis.hover(position).unwrap().unwrap(); + assert_eq!(hover.info.first(), Some("```rust\nfn new() -> Thing\n```")); + assert_eq!(hover.info.is_exact(), true); + } } From 3d8d880c59bee2f6aa21800b8b147aff47d6b0b8 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sat, 2 Mar 2019 14:05:37 -0500 Subject: [PATCH 2/7] Use ImplItems instead of just Function --- crates/ra_hir/src/ty/infer.rs | 82 ++++++++++++++---------- crates/ra_ide_api/src/goto_definition.rs | 21 ++++-- crates/ra_ide_api/src/hover.rs | 2 +- 3 files changed, 65 insertions(+), 40 deletions(-) diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index f7a35f05b5..39a2c7a496 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -29,6 +29,7 @@ use crate::{ Function, StructField, Path, Name, FnSignature, AdtDef, HirDatabase, + ImplItem, type_ref::{TypeRef, Mutability}, expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, generics::GenericParams, @@ -54,8 +55,8 @@ pub fn infer(db: &impl HirDatabase, func: Function) -> Arc { Arc::new(ctx.resolve_all()) } -#[derive(Debug, Copy, Clone)] -enum ExprOrPatId { +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum ExprOrPatId { Expr(ExprId), Pat(PatId), } @@ -79,8 +80,8 @@ pub struct InferenceResult { method_resolutions: FxHashMap, /// For each field access expr, records the field it resolves to. field_resolutions: FxHashMap, - /// For each associated function call expr, records the function it resolves to - assoc_fn_resolutions: FxHashMap, + /// For each associated item record what it resolves to + assoc_resolutions: FxHashMap, pub(super) type_of_expr: ArenaMap, pub(super) type_of_pat: ArenaMap, } @@ -92,8 +93,8 @@ impl InferenceResult { pub fn field_resolution(&self, expr: ExprId) -> Option { self.field_resolutions.get(&expr).map(|it| *it) } - pub fn assoc_fn_resolutions(&self, expr: ExprId) -> Option { - self.assoc_fn_resolutions.get(&expr).map(|it| *it) + pub fn assoc_resolutions(&self, id: ExprOrPatId) -> Option { + self.assoc_resolutions.get(&id).map(|it| *it) } } @@ -122,7 +123,7 @@ struct InferenceContext<'a, D: HirDatabase> { var_unification_table: InPlaceUnificationTable, method_resolutions: FxHashMap, field_resolutions: FxHashMap, - assoc_fn_resolutions: FxHashMap, + assoc_resolutions: FxHashMap, type_of_expr: ArenaMap, type_of_pat: ArenaMap, /// The return type of the function being inferred. @@ -134,7 +135,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { InferenceContext { method_resolutions: FxHashMap::default(), field_resolutions: FxHashMap::default(), - assoc_fn_resolutions: FxHashMap::default(), + assoc_resolutions: FxHashMap::default(), type_of_expr: ArenaMap::default(), type_of_pat: ArenaMap::default(), var_unification_table: InPlaceUnificationTable::new(), @@ -160,7 +161,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { InferenceResult { method_resolutions: self.method_resolutions, field_resolutions: self.field_resolutions, - assoc_fn_resolutions: self.assoc_fn_resolutions, + assoc_resolutions: self.assoc_resolutions, type_of_expr: expr_types, type_of_pat: pat_types, } @@ -178,8 +179,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.field_resolutions.insert(expr, field); } - fn write_assoc_fn_resolution(&mut self, expr: ExprId, func: Function) { - self.assoc_fn_resolutions.insert(expr, func); + fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: ImplItem) { + self.assoc_resolutions.insert(id, item); } fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { @@ -423,26 +424,47 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // Attempt to find an impl_item for the type which has a name matching // the current segment log::debug!("looking for path segment: {:?}", segment); - let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| match item { - crate::ImplItem::Method(func) => { - let sig = func.signature(self.db); - if segment.name == *sig.name() { - return Some(func.into()); + let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| { + let matching_def: Option = match item { + crate::ImplItem::Method(func) => { + let sig = func.signature(self.db); + if segment.name == *sig.name() { + Some(func.into()) + } else { + None + } } - None - } - crate::ImplItem::Const(konst) => { - let sig = konst.signature(self.db); - if segment.name == *sig.name() { - return Some(konst.into()); + crate::ImplItem::Const(konst) => { + let sig = konst.signature(self.db); + if segment.name == *sig.name() { + Some(konst.into()) + } else { + None + } } - None - } - // TODO: Resolve associated types - crate::ImplItem::TypeAlias(_) => None, + // TODO: Resolve associated types + crate::ImplItem::TypeAlias(_) => None, + }; + match matching_def { + Some(_) => { + self.write_assoc_resolution(id, item); + return matching_def; + } + None => None, + } })?; + + /* + if let ExprOrPatId::Expr(expr) = id { + match typable { + TypableDef::Function(func) => self.write_assoc_fn_resolution(expr, func), + _ => {} + }; + } + */ + resolved = Resolution::Def(item.into()); } @@ -450,14 +472,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Resolution::Def(def) => { let typable: Option = def.into(); let typable = typable?; - - if let ExprOrPatId::Expr(expr) = id { - match typable { - TypableDef::Function(func) => self.write_assoc_fn_resolution(expr, func), - _ => {} - }; - } - let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs); let ty = self.insert_type_vars(ty); diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index e4febe8ccd..3b66483cb1 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -5,7 +5,7 @@ use ra_syntax::{ SyntaxNode, }; use test_utils::tested_by; -use hir::Resolution; +use hir::{ImplItem, Resolution}; use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; @@ -131,14 +131,25 @@ pub(crate) fn reference_definition( name_ref.syntax().ancestors().find_map(ast::PathExpr::cast) { let infer_result = function.infer(db); - let syntax_mapping = function.body_syntax_mapping(db); + let source_map = function.body_source_map(db); let expr = ast::Expr::cast(path_expr.syntax()).unwrap(); - if let Some(func) = syntax_mapping + if let Some(res) = source_map .node_expr(expr) - .and_then(|it| infer_result.assoc_fn_resolutions(it)) + .and_then(|it| infer_result.assoc_resolutions(it.into())) { - return Exact(NavigationTarget::from_function(db, func)); + match res { + ImplItem::Method(f) => { + return Exact(NavigationTarget::from_function(db, f)); + } + ImplItem::Const(c) => { + let (file, node) = c.source(db); + let file = file.original_file(db); + let node = &*node; + return Exact(NavigationTarget::from_named(file, node)); + } + _ => {} + } } } } diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 0f13777d7d..bcd052c8bc 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -531,7 +531,7 @@ mod tests { ", ); let hover = analysis.hover(position).unwrap().unwrap(); - assert_eq!(hover.info.first(), Some("```rust\nfn new() -> Thing\n```")); + assert_eq!(trim_markup_opt(hover.info.first()), Some("fn new() -> Thing")); assert_eq!(hover.info.is_exact(), true); } } From ad2da5b1dac87896772b4ae4087b4f9c83dc8ac9 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sat, 2 Mar 2019 14:09:31 -0500 Subject: [PATCH 3/7] Remove commented out code --- crates/ra_hir/src/ty/infer.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 39a2c7a496..792d021327 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -456,15 +456,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } })?; - /* - if let ExprOrPatId::Expr(expr) = id { - match typable { - TypableDef::Function(func) => self.write_assoc_fn_resolution(expr, func), - _ => {} - }; - } - */ - resolved = Resolution::Def(item.into()); } From e1b59bfe0b00157a97f167b4857418b914ec1fd3 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sat, 2 Mar 2019 14:57:40 -0500 Subject: [PATCH 4/7] Add NavigationTarget::from_impl_item --- crates/ra_ide_api/src/goto_definition.rs | 15 ++------------- crates/ra_ide_api/src/navigation_target.rs | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 3b66483cb1..f16c3bda4b 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -5,7 +5,7 @@ use ra_syntax::{ SyntaxNode, }; use test_utils::tested_by; -use hir::{ImplItem, Resolution}; +use hir::Resolution; use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; @@ -138,18 +138,7 @@ pub(crate) fn reference_definition( .node_expr(expr) .and_then(|it| infer_result.assoc_resolutions(it.into())) { - match res { - ImplItem::Method(f) => { - return Exact(NavigationTarget::from_function(db, f)); - } - ImplItem::Const(c) => { - let (file, node) = c.source(db); - let file = file.original_file(db); - let node = &*node; - return Exact(NavigationTarget::from_named(file, node)); - } - _ => {} - } + return Exact(NavigationTarget::from_impl_item(db, res)); } } } diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs index 6538081ac6..ff8d2f15ba 100644 --- a/crates/ra_ide_api/src/navigation_target.rs +++ b/crates/ra_ide_api/src/navigation_target.rs @@ -3,7 +3,7 @@ use ra_syntax::{ SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, ast, SyntaxKind::{self, NAME}, }; -use hir::{ModuleSource, FieldSource, Name}; +use hir::{ModuleSource, FieldSource, Name, ImplItem}; use crate::{FileSymbol, db::RootDatabase}; @@ -174,6 +174,25 @@ impl NavigationTarget { ) } + pub(crate) fn from_impl_item( + db: &RootDatabase, + impl_item: hir::ImplItem, + ) -> NavigationTarget { + match impl_item { + ImplItem::Method(f) => { + NavigationTarget::from_function(db, f) + } + ImplItem::Const(c) => { + let (file_id, node) = c.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + ImplItem::TypeAlias(a) => { + let (file_id, node) = a.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*node) + } + } + } + #[cfg(test)] pub(crate) fn assert_match(&self, expected: &str) { let actual = self.debug_render(); From 79f61dcb0e3de873c4685c9abaaf4ec5af748000 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Mon, 4 Mar 2019 08:34:41 -0500 Subject: [PATCH 5/7] Format --- crates/ra_ide_api/src/navigation_target.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs index ff8d2f15ba..d806cb368d 100644 --- a/crates/ra_ide_api/src/navigation_target.rs +++ b/crates/ra_ide_api/src/navigation_target.rs @@ -174,14 +174,9 @@ impl NavigationTarget { ) } - pub(crate) fn from_impl_item( - db: &RootDatabase, - impl_item: hir::ImplItem, - ) -> NavigationTarget { + pub(crate) fn from_impl_item(db: &RootDatabase, impl_item: hir::ImplItem) -> NavigationTarget { match impl_item { - ImplItem::Method(f) => { - NavigationTarget::from_function(db, f) - } + ImplItem::Method(f) => NavigationTarget::from_function(db, f), ImplItem::Const(c) => { let (file_id, node) = c.source(db); NavigationTarget::from_named(file_id.original_file(db), &*node) From 1578375b89848b98a4d5187aaf794bc227d1eda6 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Mon, 4 Mar 2019 09:49:18 -0500 Subject: [PATCH 6/7] Make ExpOrPatId private --- crates/ra_hir/src/ty/infer.rs | 9 ++++++--- crates/ra_ide_api/src/goto_definition.rs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 792d021327..40559c3de7 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -56,7 +56,7 @@ pub fn infer(db: &impl HirDatabase, func: Function) -> Arc { } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum ExprOrPatId { +enum ExprOrPatId { Expr(ExprId), Pat(PatId), } @@ -93,8 +93,11 @@ impl InferenceResult { pub fn field_resolution(&self, expr: ExprId) -> Option { self.field_resolutions.get(&expr).map(|it| *it) } - pub fn assoc_resolutions(&self, id: ExprOrPatId) -> Option { - self.assoc_resolutions.get(&id).map(|it| *it) + pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option { + self.assoc_resolutions.get(&id.into()).map(|it| *it) + } + pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option { + self.assoc_resolutions.get(&id.into()).map(|it| *it) } } diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index f16c3bda4b..364263d9bb 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -136,7 +136,7 @@ pub(crate) fn reference_definition( if let Some(res) = source_map .node_expr(expr) - .and_then(|it| infer_result.assoc_resolutions(it.into())) + .and_then(|it| infer_result.assoc_resolutions_for_expr(it.into())) { return Exact(NavigationTarget::from_impl_item(db, res)); } From ac678473b85da24fc15315054e9737347fadb55c Mon Sep 17 00:00:00 2001 From: kjeremy Date: Mon, 4 Mar 2019 09:52:48 -0500 Subject: [PATCH 7/7] Use impl_froms! --- crates/ra_hir/src/ty/infer.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 40559c3de7..268d2c1104 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -57,21 +57,11 @@ pub fn infer(db: &impl HirDatabase, func: Function) -> Arc { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] enum ExprOrPatId { - Expr(ExprId), - Pat(PatId), + ExprId(ExprId), + PatId(PatId), } -impl From for ExprOrPatId { - fn from(id: ExprId) -> Self { - ExprOrPatId::Expr(id) - } -} - -impl From for ExprOrPatId { - fn from(id: PatId) -> Self { - ExprOrPatId::Pat(id) - } -} +impl_froms!(ExprOrPatId: ExprId, PatId); /// The result of type inference: A mapping from expressions and patterns to types. #[derive(Clone, PartialEq, Eq, Debug)]