diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 128 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 37 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_dot.rs | 15 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 2 |
9 files changed, 88 insertions, 119 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index d0c455d0a..0cf45944f 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -318,7 +318,7 @@ impl Function { | |||
318 | db.fn_signature(self.def_id) | 318 | db.fn_signature(self.def_id) |
319 | } | 319 | } |
320 | 320 | ||
321 | pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> { | 321 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { |
322 | db.infer(self.def_id) | 322 | db.infer(self.def_id) |
323 | } | 323 | } |
324 | } | 324 | } |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 4a2b0b3dc..0a0994f5f 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; | 3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; |
4 | use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, Cancelable}; | 4 | use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId, | 7 | DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId, |
@@ -52,7 +52,7 @@ pub trait HirDatabase: SyntaxDatabase | |||
52 | use fn crate::adt::EnumVariantData::enum_variant_data_query; | 52 | use fn crate::adt::EnumVariantData::enum_variant_data_query; |
53 | } | 53 | } |
54 | 54 | ||
55 | fn infer(def_id: DefId) -> Cancelable<Arc<InferenceResult>> { | 55 | fn infer(def_id: DefId) -> Arc<InferenceResult> { |
56 | type InferQuery; | 56 | type InferQuery; |
57 | use fn crate::ty::infer; | 57 | use fn crate::ty::infer; |
58 | } | 58 | } |
@@ -102,7 +102,7 @@ pub trait HirDatabase: SyntaxDatabase | |||
102 | use fn crate::impl_block::impls_in_module; | 102 | use fn crate::impl_block::impls_in_module; |
103 | } | 103 | } |
104 | 104 | ||
105 | fn impls_in_crate(krate: Crate) -> Cancelable<Arc<CrateImplBlocks>> { | 105 | fn impls_in_crate(krate: Crate) -> Arc<CrateImplBlocks> { |
106 | type ImplsInCrateQuery; | 106 | type ImplsInCrateQuery; |
107 | use fn crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query; | 107 | use fn crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query; |
108 | } | 108 | } |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 45dda4f7f..ef7d049ee 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -5,15 +5,6 @@ | |||
5 | //! to a particular crate instance. That is, it has cfg flags and features | 5 | //! to a particular crate instance. That is, it has cfg flags and features |
6 | //! applied. So, the relation between syntax and HIR is many-to-one. | 6 | //! applied. So, the relation between syntax and HIR is many-to-one. |
7 | 7 | ||
8 | macro_rules! ctry { | ||
9 | ($expr:expr) => { | ||
10 | match $expr { | ||
11 | None => return Ok(None), | ||
12 | Some(it) => it, | ||
13 | } | ||
14 | }; | ||
15 | } | ||
16 | |||
17 | pub mod db; | 8 | pub mod db; |
18 | #[cfg(test)] | 9 | #[cfg(test)] |
19 | mod mock; | 10 | mod mock; |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 37fc8643a..dbbbce795 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -30,8 +30,6 @@ use ra_arena::map::ArenaMap; | |||
30 | use join_to_string::join; | 30 | use join_to_string::join; |
31 | use rustc_hash::FxHashMap; | 31 | use rustc_hash::FxHashMap; |
32 | 32 | ||
33 | use ra_db::Cancelable; | ||
34 | |||
35 | use crate::{ | 33 | use crate::{ |
36 | Def, DefId, Module, Function, Struct, Enum, EnumVariant, Path, Name, ImplBlock, | 34 | Def, DefId, Module, Function, Struct, Enum, EnumVariant, Path, Name, ImplBlock, |
37 | FnSignature, FnScopes, | 35 | FnSignature, FnScopes, |
@@ -41,14 +39,6 @@ use crate::{ | |||
41 | expr::{Body, Expr, Literal, ExprId, PatId, UnaryOp, BinaryOp, Statement}, | 39 | expr::{Body, Expr, Literal, ExprId, PatId, UnaryOp, BinaryOp, Statement}, |
42 | }; | 40 | }; |
43 | 41 | ||
44 | fn transpose<T>(x: Cancelable<Option<T>>) -> Option<Cancelable<T>> { | ||
45 | match x { | ||
46 | Ok(Some(t)) => Some(Ok(t)), | ||
47 | Ok(None) => None, | ||
48 | Err(e) => Some(Err(e)), | ||
49 | } | ||
50 | } | ||
51 | |||
52 | /// The ID of a type variable. | 42 | /// The ID of a type variable. |
53 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | 43 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] |
54 | pub struct TypeVarId(u32); | 44 | pub struct TypeVarId(u32); |
@@ -836,36 +826,36 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
836 | }) | 826 | }) |
837 | } | 827 | } |
838 | 828 | ||
839 | fn infer_path_expr(&mut self, expr: ExprId, path: &Path) -> Cancelable<Option<Ty>> { | 829 | fn infer_path_expr(&mut self, expr: ExprId, path: &Path) -> Option<Ty> { |
840 | if path.is_ident() || path.is_self() { | 830 | if path.is_ident() || path.is_self() { |
841 | // resolve locally | 831 | // resolve locally |
842 | let name = path.as_ident().cloned().unwrap_or_else(Name::self_param); | 832 | let name = path.as_ident().cloned().unwrap_or_else(Name::self_param); |
843 | if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) { | 833 | if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) { |
844 | let ty = ctry!(self.type_of_pat.get(scope_entry.pat())); | 834 | let ty = self.type_of_pat.get(scope_entry.pat())?; |
845 | let ty = self.resolve_ty_as_possible(ty.clone()); | 835 | let ty = self.resolve_ty_as_possible(ty.clone()); |
846 | return Ok(Some(ty)); | 836 | return Some(ty); |
847 | }; | 837 | }; |
848 | }; | 838 | }; |
849 | 839 | ||
850 | // resolve in module | 840 | // resolve in module |
851 | let resolved = ctry!(self.module.resolve_path(self.db, &path).take_values()); | 841 | let resolved = self.module.resolve_path(self.db, &path).take_values()?; |
852 | let ty = self.db.type_for_def(resolved); | 842 | let ty = self.db.type_for_def(resolved); |
853 | let ty = self.insert_type_vars(ty); | 843 | let ty = self.insert_type_vars(ty); |
854 | Ok(Some(ty)) | 844 | Some(ty) |
855 | } | 845 | } |
856 | 846 | ||
857 | fn resolve_variant(&self, path: Option<&Path>) -> Cancelable<(Ty, Option<DefId>)> { | 847 | fn resolve_variant(&self, path: Option<&Path>) -> (Ty, Option<DefId>) { |
858 | let path = if let Some(path) = path { | 848 | let path = if let Some(path) = path { |
859 | path | 849 | path |
860 | } else { | 850 | } else { |
861 | return Ok((Ty::Unknown, None)); | 851 | return (Ty::Unknown, None); |
862 | }; | 852 | }; |
863 | let def_id = if let Some(def_id) = self.module.resolve_path(self.db, &path).take_types() { | 853 | let def_id = if let Some(def_id) = self.module.resolve_path(self.db, &path).take_types() { |
864 | def_id | 854 | def_id |
865 | } else { | 855 | } else { |
866 | return Ok((Ty::Unknown, None)); | 856 | return (Ty::Unknown, None); |
867 | }; | 857 | }; |
868 | Ok(match def_id.resolve(self.db) { | 858 | match def_id.resolve(self.db) { |
869 | Def::Struct(s) => { | 859 | Def::Struct(s) => { |
870 | let ty = type_for_struct(self.db, s); | 860 | let ty = type_for_struct(self.db, s); |
871 | (ty, Some(def_id)) | 861 | (ty, Some(def_id)) |
@@ -875,10 +865,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
875 | (ty, Some(def_id)) | 865 | (ty, Some(def_id)) |
876 | } | 866 | } |
877 | _ => (Ty::Unknown, None), | 867 | _ => (Ty::Unknown, None), |
878 | }) | 868 | } |
879 | } | 869 | } |
880 | 870 | ||
881 | fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Cancelable<Ty> { | 871 | fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Ty { |
882 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 872 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
883 | let ty = match &body[expr] { | 873 | let ty = match &body[expr] { |
884 | Expr::Missing => Ty::Unknown, | 874 | Expr::Missing => Ty::Unknown, |
@@ -888,11 +878,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
888 | else_branch, | 878 | else_branch, |
889 | } => { | 879 | } => { |
890 | // if let is desugared to match, so this is always simple if | 880 | // if let is desugared to match, so this is always simple if |
891 | self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?; | 881 | self.infer_expr(*condition, &Expectation::has_type(Ty::Bool)); |
892 | let then_ty = self.infer_expr(*then_branch, expected)?; | 882 | let then_ty = self.infer_expr(*then_branch, expected); |
893 | match else_branch { | 883 | match else_branch { |
894 | Some(else_branch) => { | 884 | Some(else_branch) => { |
895 | self.infer_expr(*else_branch, expected)?; | 885 | self.infer_expr(*else_branch, expected); |
896 | } | 886 | } |
897 | None => { | 887 | None => { |
898 | // no else branch -> unit | 888 | // no else branch -> unit |
@@ -901,31 +891,31 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
901 | }; | 891 | }; |
902 | then_ty | 892 | then_ty |
903 | } | 893 | } |
904 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected)?, | 894 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), |
905 | Expr::Loop { body } => { | 895 | Expr::Loop { body } => { |
906 | self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?; | 896 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
907 | // TODO handle break with value | 897 | // TODO handle break with value |
908 | Ty::Never | 898 | Ty::Never |
909 | } | 899 | } |
910 | Expr::While { condition, body } => { | 900 | Expr::While { condition, body } => { |
911 | // while let is desugared to a match loop, so this is always simple while | 901 | // while let is desugared to a match loop, so this is always simple while |
912 | self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?; | 902 | self.infer_expr(*condition, &Expectation::has_type(Ty::Bool)); |
913 | self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?; | 903 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
914 | Ty::unit() | 904 | Ty::unit() |
915 | } | 905 | } |
916 | Expr::For { iterable, body, .. } => { | 906 | Expr::For { iterable, body, .. } => { |
917 | let _iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | 907 | let _iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
918 | // TODO write type for pat | 908 | // TODO write type for pat |
919 | self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?; | 909 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
920 | Ty::unit() | 910 | Ty::unit() |
921 | } | 911 | } |
922 | Expr::Lambda { body, .. } => { | 912 | Expr::Lambda { body, .. } => { |
923 | // TODO write types for args, infer lambda type etc. | 913 | // TODO write types for args, infer lambda type etc. |
924 | let _body_ty = self.infer_expr(*body, &Expectation::none())?; | 914 | let _body_ty = self.infer_expr(*body, &Expectation::none()); |
925 | Ty::Unknown | 915 | Ty::Unknown |
926 | } | 916 | } |
927 | Expr::Call { callee, args } => { | 917 | Expr::Call { callee, args } => { |
928 | let callee_ty = self.infer_expr(*callee, &Expectation::none())?; | 918 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); |
929 | let (param_tys, ret_ty) = match &callee_ty { | 919 | let (param_tys, ret_ty) = match &callee_ty { |
930 | Ty::FnPtr(sig) => (&sig.input[..], sig.output.clone()), | 920 | Ty::FnPtr(sig) => (&sig.input[..], sig.output.clone()), |
931 | _ => { | 921 | _ => { |
@@ -938,7 +928,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
938 | self.infer_expr( | 928 | self.infer_expr( |
939 | *arg, | 929 | *arg, |
940 | &Expectation::has_type(param_tys.get(i).cloned().unwrap_or(Ty::Unknown)), | 930 | &Expectation::has_type(param_tys.get(i).cloned().unwrap_or(Ty::Unknown)), |
941 | )?; | 931 | ); |
942 | } | 932 | } |
943 | ret_ty | 933 | ret_ty |
944 | } | 934 | } |
@@ -947,8 +937,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
947 | args, | 937 | args, |
948 | method_name, | 938 | method_name, |
949 | } => { | 939 | } => { |
950 | let receiver_ty = self.infer_expr(*receiver, &Expectation::none())?; | 940 | let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); |
951 | let resolved = receiver_ty.clone().lookup_method(self.db, method_name)?; | 941 | let resolved = receiver_ty.clone().lookup_method(self.db, method_name); |
952 | let method_ty = match resolved { | 942 | let method_ty = match resolved { |
953 | Some(def_id) => { | 943 | Some(def_id) => { |
954 | self.write_method_resolution(expr, def_id); | 944 | self.write_method_resolution(expr, def_id); |
@@ -974,32 +964,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
974 | self.infer_expr( | 964 | self.infer_expr( |
975 | *arg, | 965 | *arg, |
976 | &Expectation::has_type(param_tys.get(i).cloned().unwrap_or(Ty::Unknown)), | 966 | &Expectation::has_type(param_tys.get(i).cloned().unwrap_or(Ty::Unknown)), |
977 | )?; | 967 | ); |
978 | } | 968 | } |
979 | ret_ty | 969 | ret_ty |
980 | } | 970 | } |
981 | Expr::Match { expr, arms } => { | 971 | Expr::Match { expr, arms } => { |
982 | let _ty = self.infer_expr(*expr, &Expectation::none())?; | 972 | let _ty = self.infer_expr(*expr, &Expectation::none()); |
983 | for arm in arms { | 973 | for arm in arms { |
984 | // TODO type the bindings in pats | 974 | // TODO type the bindings in pats |
985 | // TODO type the guard | 975 | // TODO type the guard |
986 | let _ty = self.infer_expr(arm.expr, &Expectation::none())?; | 976 | let _ty = self.infer_expr(arm.expr, &Expectation::none()); |
987 | } | 977 | } |
988 | // TODO unify all the match arm types | 978 | // TODO unify all the match arm types |
989 | Ty::Unknown | 979 | Ty::Unknown |
990 | } | 980 | } |
991 | Expr::Path(p) => self.infer_path_expr(expr, p)?.unwrap_or(Ty::Unknown), | 981 | Expr::Path(p) => self.infer_path_expr(expr, p).unwrap_or(Ty::Unknown), |
992 | Expr::Continue => Ty::Never, | 982 | Expr::Continue => Ty::Never, |
993 | Expr::Break { expr } => { | 983 | Expr::Break { expr } => { |
994 | if let Some(expr) = expr { | 984 | if let Some(expr) = expr { |
995 | // TODO handle break with value | 985 | // TODO handle break with value |
996 | self.infer_expr(*expr, &Expectation::none())?; | 986 | self.infer_expr(*expr, &Expectation::none()); |
997 | } | 987 | } |
998 | Ty::Never | 988 | Ty::Never |
999 | } | 989 | } |
1000 | Expr::Return { expr } => { | 990 | Expr::Return { expr } => { |
1001 | if let Some(expr) = expr { | 991 | if let Some(expr) = expr { |
1002 | self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone()))?; | 992 | self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone())); |
1003 | } | 993 | } |
1004 | Ty::Never | 994 | Ty::Never |
1005 | } | 995 | } |
@@ -1008,7 +998,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1008 | fields, | 998 | fields, |
1009 | spread, | 999 | spread, |
1010 | } => { | 1000 | } => { |
1011 | let (ty, def_id) = self.resolve_variant(path.as_ref())?; | 1001 | let (ty, def_id) = self.resolve_variant(path.as_ref()); |
1012 | for field in fields { | 1002 | for field in fields { |
1013 | let field_ty = if let Some(def_id) = def_id { | 1003 | let field_ty = if let Some(def_id) = def_id { |
1014 | self.db | 1004 | self.db |
@@ -1017,37 +1007,35 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1017 | } else { | 1007 | } else { |
1018 | Ty::Unknown | 1008 | Ty::Unknown |
1019 | }; | 1009 | }; |
1020 | self.infer_expr(field.expr, &Expectation::has_type(field_ty))?; | 1010 | self.infer_expr(field.expr, &Expectation::has_type(field_ty)); |
1021 | } | 1011 | } |
1022 | if let Some(expr) = spread { | 1012 | if let Some(expr) = spread { |
1023 | self.infer_expr(*expr, &Expectation::has_type(ty.clone()))?; | 1013 | self.infer_expr(*expr, &Expectation::has_type(ty.clone())); |
1024 | } | 1014 | } |
1025 | ty | 1015 | ty |
1026 | } | 1016 | } |
1027 | Expr::Field { expr, name } => { | 1017 | Expr::Field { expr, name } => { |
1028 | let receiver_ty = self.infer_expr(*expr, &Expectation::none())?; | 1018 | let receiver_ty = self.infer_expr(*expr, &Expectation::none()); |
1029 | let ty = receiver_ty | 1019 | let ty = receiver_ty |
1030 | .autoderef(self.db) | 1020 | .autoderef(self.db) |
1031 | .find_map(|derefed_ty| match derefed_ty { | 1021 | .find_map(|derefed_ty| match derefed_ty { |
1032 | // this is more complicated than necessary because type_for_field is cancelable | 1022 | // this is more complicated than necessary because type_for_field is cancelable |
1033 | Ty::Tuple(fields) => { | 1023 | Ty::Tuple(fields) => { |
1034 | let i = name.to_string().parse::<usize>().ok(); | 1024 | let i = name.to_string().parse::<usize>().ok(); |
1035 | i.and_then(|i| fields.get(i).cloned()).map(Ok) | 1025 | i.and_then(|i| fields.get(i).cloned()) |
1036 | } | ||
1037 | Ty::Adt { def_id, .. } => { | ||
1038 | transpose(Ok(self.db.type_for_field(def_id, name.clone()))) | ||
1039 | } | 1026 | } |
1027 | Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, name.clone()), | ||
1040 | _ => None, | 1028 | _ => None, |
1041 | }) | 1029 | }) |
1042 | .unwrap_or(Ok(Ty::Unknown))?; | 1030 | .unwrap_or(Ty::Unknown); |
1043 | self.insert_type_vars(ty) | 1031 | self.insert_type_vars(ty) |
1044 | } | 1032 | } |
1045 | Expr::Try { expr } => { | 1033 | Expr::Try { expr } => { |
1046 | let _inner_ty = self.infer_expr(*expr, &Expectation::none())?; | 1034 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); |
1047 | Ty::Unknown | 1035 | Ty::Unknown |
1048 | } | 1036 | } |
1049 | Expr::Cast { expr, type_ref } => { | 1037 | Expr::Cast { expr, type_ref } => { |
1050 | let _inner_ty = self.infer_expr(*expr, &Expectation::none())?; | 1038 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); |
1051 | let cast_ty = | 1039 | let cast_ty = |
1052 | Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref); | 1040 | Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref); |
1053 | let cast_ty = self.insert_type_vars(cast_ty); | 1041 | let cast_ty = self.insert_type_vars(cast_ty); |
@@ -1056,12 +1044,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1056 | } | 1044 | } |
1057 | Expr::Ref { expr, mutability } => { | 1045 | Expr::Ref { expr, mutability } => { |
1058 | // TODO pass the expectation down | 1046 | // TODO pass the expectation down |
1059 | let inner_ty = self.infer_expr(*expr, &Expectation::none())?; | 1047 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); |
1060 | // TODO reference coercions etc. | 1048 | // TODO reference coercions etc. |
1061 | Ty::Ref(Arc::new(inner_ty), *mutability) | 1049 | Ty::Ref(Arc::new(inner_ty), *mutability) |
1062 | } | 1050 | } |
1063 | Expr::UnaryOp { expr, op } => { | 1051 | Expr::UnaryOp { expr, op } => { |
1064 | let inner_ty = self.infer_expr(*expr, &Expectation::none())?; | 1052 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); |
1065 | match op { | 1053 | match op { |
1066 | Some(UnaryOp::Deref) => { | 1054 | Some(UnaryOp::Deref) => { |
1067 | if let Some(derefed_ty) = inner_ty.builtin_deref() { | 1055 | if let Some(derefed_ty) = inner_ty.builtin_deref() { |
@@ -1082,11 +1070,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1082 | } | 1070 | } |
1083 | _ => Expectation::none(), | 1071 | _ => Expectation::none(), |
1084 | }; | 1072 | }; |
1085 | let lhs_ty = self.infer_expr(*lhs, &lhs_expectation)?; | 1073 | let lhs_ty = self.infer_expr(*lhs, &lhs_expectation); |
1086 | // TODO: find implementation of trait corresponding to operation | 1074 | // TODO: find implementation of trait corresponding to operation |
1087 | // symbol and resolve associated `Output` type | 1075 | // symbol and resolve associated `Output` type |
1088 | let rhs_expectation = binary_op_rhs_expectation(*op, lhs_ty); | 1076 | let rhs_expectation = binary_op_rhs_expectation(*op, lhs_ty); |
1089 | let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation))?; | 1077 | let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation)); |
1090 | 1078 | ||
1091 | // TODO: similar as above, return ty is often associated trait type | 1079 | // TODO: similar as above, return ty is often associated trait type |
1092 | binary_op_return_ty(*op, rhs_ty) | 1080 | binary_op_return_ty(*op, rhs_ty) |
@@ -1096,7 +1084,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1096 | Expr::Tuple { exprs } => { | 1084 | Expr::Tuple { exprs } => { |
1097 | let mut ty_vec = Vec::with_capacity(exprs.len()); | 1085 | let mut ty_vec = Vec::with_capacity(exprs.len()); |
1098 | for arg in exprs.iter() { | 1086 | for arg in exprs.iter() { |
1099 | ty_vec.push(self.infer_expr(*arg, &Expectation::none())?); | 1087 | ty_vec.push(self.infer_expr(*arg, &Expectation::none())); |
1100 | } | 1088 | } |
1101 | 1089 | ||
1102 | Ty::Tuple(Arc::from(ty_vec)) | 1090 | Ty::Tuple(Arc::from(ty_vec)) |
@@ -1121,7 +1109,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1121 | self.unify(&ty, &expected.ty); | 1109 | self.unify(&ty, &expected.ty); |
1122 | let ty = self.resolve_ty_as_possible(ty); | 1110 | let ty = self.resolve_ty_as_possible(ty); |
1123 | self.write_expr_ty(expr, ty.clone()); | 1111 | self.write_expr_ty(expr, ty.clone()); |
1124 | Ok(ty) | 1112 | ty |
1125 | } | 1113 | } |
1126 | 1114 | ||
1127 | fn infer_block( | 1115 | fn infer_block( |
@@ -1129,7 +1117,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1129 | statements: &[Statement], | 1117 | statements: &[Statement], |
1130 | tail: Option<ExprId>, | 1118 | tail: Option<ExprId>, |
1131 | expected: &Expectation, | 1119 | expected: &Expectation, |
1132 | ) -> Cancelable<Ty> { | 1120 | ) -> Ty { |
1133 | for stmt in statements { | 1121 | for stmt in statements { |
1134 | match stmt { | 1122 | match stmt { |
1135 | Statement::Let { | 1123 | Statement::Let { |
@@ -1145,7 +1133,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1145 | ); | 1133 | ); |
1146 | let decl_ty = self.insert_type_vars(decl_ty); | 1134 | let decl_ty = self.insert_type_vars(decl_ty); |
1147 | let ty = if let Some(expr) = initializer { | 1135 | let ty = if let Some(expr) = initializer { |
1148 | let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty))?; | 1136 | let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty)); |
1149 | expr_ty | 1137 | expr_ty |
1150 | } else { | 1138 | } else { |
1151 | decl_ty | 1139 | decl_ty |
@@ -1154,19 +1142,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1154 | self.write_pat_ty(*pat, ty); | 1142 | self.write_pat_ty(*pat, ty); |
1155 | } | 1143 | } |
1156 | Statement::Expr(expr) => { | 1144 | Statement::Expr(expr) => { |
1157 | self.infer_expr(*expr, &Expectation::none())?; | 1145 | self.infer_expr(*expr, &Expectation::none()); |
1158 | } | 1146 | } |
1159 | } | 1147 | } |
1160 | } | 1148 | } |
1161 | let ty = if let Some(expr) = tail { | 1149 | let ty = if let Some(expr) = tail { |
1162 | self.infer_expr(expr, expected)? | 1150 | self.infer_expr(expr, expected) |
1163 | } else { | 1151 | } else { |
1164 | Ty::unit() | 1152 | Ty::unit() |
1165 | }; | 1153 | }; |
1166 | Ok(ty) | 1154 | ty |
1167 | } | 1155 | } |
1168 | 1156 | ||
1169 | fn collect_fn_signature(&mut self, signature: &FnSignature) -> Cancelable<()> { | 1157 | fn collect_fn_signature(&mut self, signature: &FnSignature) { |
1170 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 1158 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
1171 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { | 1159 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { |
1172 | let ty = self.make_ty(type_ref); | 1160 | let ty = self.make_ty(type_ref); |
@@ -1178,19 +1166,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1178 | let ty = self.insert_type_vars(ty); | 1166 | let ty = self.insert_type_vars(ty); |
1179 | ty | 1167 | ty |
1180 | }; | 1168 | }; |
1181 | Ok(()) | ||
1182 | } | 1169 | } |
1183 | 1170 | ||
1184 | fn infer_body(&mut self) -> Cancelable<()> { | 1171 | fn infer_body(&mut self) { |
1185 | self.infer_expr( | 1172 | self.infer_expr( |
1186 | self.body.body_expr(), | 1173 | self.body.body_expr(), |
1187 | &Expectation::has_type(self.return_ty.clone()), | 1174 | &Expectation::has_type(self.return_ty.clone()), |
1188 | )?; | 1175 | ); |
1189 | Ok(()) | ||
1190 | } | 1176 | } |
1191 | } | 1177 | } |
1192 | 1178 | ||
1193 | pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { | 1179 | pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Arc<InferenceResult> { |
1194 | db.check_canceled(); | 1180 | db.check_canceled(); |
1195 | let function = Function::new(def_id); // TODO: consts also need inference | 1181 | let function = Function::new(def_id); // TODO: consts also need inference |
1196 | let body = function.body(db); | 1182 | let body = function.body(db); |
@@ -1200,9 +1186,9 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe | |||
1200 | let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block); | 1186 | let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block); |
1201 | 1187 | ||
1202 | let signature = function.signature(db); | 1188 | let signature = function.signature(db); |
1203 | ctx.collect_fn_signature(&signature)?; | 1189 | ctx.collect_fn_signature(&signature); |
1204 | 1190 | ||
1205 | ctx.infer_body()?; | 1191 | ctx.infer_body(); |
1206 | 1192 | ||
1207 | Ok(Arc::new(ctx.resolve_all())) | 1193 | Arc::new(ctx.resolve_all()) |
1208 | } | 1194 | } |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 0676a989d..b221bd142 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -6,7 +6,7 @@ use std::sync::Arc; | |||
6 | 6 | ||
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | 8 | ||
9 | use ra_db::{Cancelable, SourceRootId}; | 9 | use ra_db::SourceRootId; |
10 | 10 | ||
11 | use crate::{HirDatabase, DefId, module_tree::ModuleId, Module, Crate, Name, Function, impl_block::{ImplId, ImplBlock, ImplItem}}; | 11 | use crate::{HirDatabase, DefId, module_tree::ModuleId, Module, Crate, Name, Function, impl_block::{ImplId, ImplBlock, ImplItem}}; |
12 | use super::Ty; | 12 | use super::Ty; |
@@ -42,7 +42,7 @@ impl CrateImplBlocks { | |||
42 | &'a self, | 42 | &'a self, |
43 | db: &'a impl HirDatabase, | 43 | db: &'a impl HirDatabase, |
44 | ty: &Ty, | 44 | ty: &Ty, |
45 | ) -> impl Iterator<Item = Cancelable<ImplBlock>> + 'a { | 45 | ) -> impl Iterator<Item = ImplBlock> + 'a { |
46 | let fingerprint = TyFingerprint::for_impl(ty); | 46 | let fingerprint = TyFingerprint::for_impl(ty); |
47 | fingerprint | 47 | fingerprint |
48 | .and_then(|f| self.impls.get(&f)) | 48 | .and_then(|f| self.impls.get(&f)) |
@@ -50,11 +50,11 @@ impl CrateImplBlocks { | |||
50 | .flat_map(|i| i.iter()) | 50 | .flat_map(|i| i.iter()) |
51 | .map(move |(module_id, impl_id)| { | 51 | .map(move |(module_id, impl_id)| { |
52 | let module_impl_blocks = db.impls_in_module(self.source_root_id, *module_id); | 52 | let module_impl_blocks = db.impls_in_module(self.source_root_id, *module_id); |
53 | Ok(ImplBlock::from_id(module_impl_blocks, *impl_id)) | 53 | ImplBlock::from_id(module_impl_blocks, *impl_id) |
54 | }) | 54 | }) |
55 | } | 55 | } |
56 | 56 | ||
57 | fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> { | 57 | fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) { |
58 | let module_id = module.def_id.loc(db).module_id; | 58 | let module_id = module.def_id.loc(db).module_id; |
59 | let module_impl_blocks = db.impls_in_module(self.source_root_id, module_id); | 59 | let module_impl_blocks = db.impls_in_module(self.source_root_id, module_id); |
60 | 60 | ||
@@ -76,16 +76,14 @@ impl CrateImplBlocks { | |||
76 | } | 76 | } |
77 | 77 | ||
78 | for child in module.children(db) { | 78 | for child in module.children(db) { |
79 | self.collect_recursive(db, child)?; | 79 | self.collect_recursive(db, child); |
80 | } | 80 | } |
81 | |||
82 | Ok(()) | ||
83 | } | 81 | } |
84 | 82 | ||
85 | pub(crate) fn impls_in_crate_query( | 83 | pub(crate) fn impls_in_crate_query( |
86 | db: &impl HirDatabase, | 84 | db: &impl HirDatabase, |
87 | krate: Crate, | 85 | krate: Crate, |
88 | ) -> Cancelable<Arc<CrateImplBlocks>> { | 86 | ) -> Arc<CrateImplBlocks> { |
89 | let crate_graph = db.crate_graph(); | 87 | let crate_graph = db.crate_graph(); |
90 | let file_id = crate_graph.crate_root(krate.crate_id); | 88 | let file_id = crate_graph.crate_root(krate.crate_id); |
91 | let source_root_id = db.file_source_root(file_id); | 89 | let source_root_id = db.file_source_root(file_id); |
@@ -94,9 +92,9 @@ impl CrateImplBlocks { | |||
94 | impls: FxHashMap::default(), | 92 | impls: FxHashMap::default(), |
95 | }; | 93 | }; |
96 | if let Some(module) = krate.root_module(db) { | 94 | if let Some(module) = krate.root_module(db) { |
97 | crate_impl_blocks.collect_recursive(db, module)?; | 95 | crate_impl_blocks.collect_recursive(db, module); |
98 | } | 96 | } |
99 | Ok(Arc::new(crate_impl_blocks)) | 97 | Arc::new(crate_impl_blocks) |
100 | } | 98 | } |
101 | } | 99 | } |
102 | 100 | ||
@@ -111,13 +109,13 @@ impl Ty { | |||
111 | // TODO: cache this as a query? | 109 | // TODO: cache this as a query? |
112 | // - if so, what signature? (TyFingerprint, Name)? | 110 | // - if so, what signature? (TyFingerprint, Name)? |
113 | // - or maybe cache all names and def_ids of methods per fingerprint? | 111 | // - or maybe cache all names and def_ids of methods per fingerprint? |
114 | pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<DefId>> { | 112 | pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<DefId> { |
115 | self.iterate_methods(db, |f| { | 113 | self.iterate_methods(db, |f| { |
116 | let sig = f.signature(db); | 114 | let sig = f.signature(db); |
117 | if sig.name() == name && sig.has_self_param() { | 115 | if sig.name() == name && sig.has_self_param() { |
118 | Ok(Some(f.def_id())) | 116 | Some(f.def_id()) |
119 | } else { | 117 | } else { |
120 | Ok(None) | 118 | None |
121 | } | 119 | } |
122 | }) | 120 | }) |
123 | } | 121 | } |
@@ -127,8 +125,8 @@ impl Ty { | |||
127 | pub fn iterate_methods<T>( | 125 | pub fn iterate_methods<T>( |
128 | self, | 126 | self, |
129 | db: &impl HirDatabase, | 127 | db: &impl HirDatabase, |
130 | mut callback: impl FnMut(Function) -> Cancelable<Option<T>>, | 128 | mut callback: impl FnMut(Function) -> Option<T>, |
131 | ) -> Cancelable<Option<T>> { | 129 | ) -> Option<T> { |
132 | // For method calls, rust first does any number of autoderef, and then one | 130 | // For method calls, rust first does any number of autoderef, and then one |
133 | // autoref (i.e. when the method takes &self or &mut self). We just ignore | 131 | // autoref (i.e. when the method takes &self or &mut self). We just ignore |
134 | // the autoref currently -- when we find a method matching the given name, | 132 | // the autoref currently -- when we find a method matching the given name, |
@@ -143,15 +141,14 @@ impl Ty { | |||
143 | Some(krate) => krate, | 141 | Some(krate) => krate, |
144 | None => continue, | 142 | None => continue, |
145 | }; | 143 | }; |
146 | let impls = db.impls_in_crate(krate)?; | 144 | let impls = db.impls_in_crate(krate); |
147 | 145 | ||
148 | for impl_block in impls.lookup_impl_blocks(db, &derefed_ty) { | 146 | for impl_block in impls.lookup_impl_blocks(db, &derefed_ty) { |
149 | let impl_block = impl_block?; | ||
150 | for item in impl_block.items() { | 147 | for item in impl_block.items() { |
151 | match item { | 148 | match item { |
152 | ImplItem::Method(f) => { | 149 | ImplItem::Method(f) => { |
153 | if let Some(result) = callback(f.clone())? { | 150 | if let Some(result) = callback(f.clone()) { |
154 | return Ok(Some(result)); | 151 | return Some(result); |
155 | } | 152 | } |
156 | } | 153 | } |
157 | _ => {} | 154 | _ => {} |
@@ -159,6 +156,6 @@ impl Ty { | |||
159 | } | 156 | } |
160 | } | 157 | } |
161 | } | 158 | } |
162 | Ok(None) | 159 | None |
163 | } | 160 | } |
164 | } | 161 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index b44ac9987..929fee04c 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -321,7 +321,7 @@ fn infer(content: &str) -> String { | |||
321 | .filter_map(ast::FnDef::cast) | 321 | .filter_map(ast::FnDef::cast) |
322 | { | 322 | { |
323 | let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap(); | 323 | let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap(); |
324 | let inference_result = func.infer(&db).unwrap(); | 324 | let inference_result = func.infer(&db); |
325 | let body_syntax_mapping = func.body_syntax_mapping(&db); | 325 | let body_syntax_mapping = func.body_syntax_mapping(&db); |
326 | let mut types = Vec::new(); | 326 | let mut types = Vec::new(); |
327 | for (pat, ty) in inference_result.type_of_pat.iter() { | 327 | for (pat, ty) in inference_result.type_of_pat.iter() { |
@@ -405,7 +405,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
405 | let func = source_binder::function_from_position(&db, pos).unwrap(); | 405 | let func = source_binder::function_from_position(&db, pos).unwrap(); |
406 | { | 406 | { |
407 | let events = db.log_executed(|| { | 407 | let events = db.log_executed(|| { |
408 | func.infer(&db).unwrap(); | 408 | func.infer(&db); |
409 | }); | 409 | }); |
410 | assert!(format!("{:?}", events).contains("infer")) | 410 | assert!(format!("{:?}", events).contains("infer")) |
411 | } | 411 | } |
@@ -424,7 +424,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
424 | 424 | ||
425 | { | 425 | { |
426 | let events = db.log_executed(|| { | 426 | let events = db.log_executed(|| { |
427 | func.infer(&db).unwrap(); | 427 | func.infer(&db); |
428 | }); | 428 | }); |
429 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) | 429 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) |
430 | } | 430 | } |
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 30a0a3924..31a2478d1 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs | |||
@@ -9,7 +9,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Ca | |||
9 | (Some(function), Some(receiver)) => (function, receiver), | 9 | (Some(function), Some(receiver)) => (function, receiver), |
10 | _ => return Ok(()), | 10 | _ => return Ok(()), |
11 | }; | 11 | }; |
12 | let infer_result = function.infer(ctx.db)?; | 12 | let infer_result = function.infer(ctx.db); |
13 | let syntax_mapping = function.body_syntax_mapping(ctx.db); | 13 | let syntax_mapping = function.body_syntax_mapping(ctx.db); |
14 | let expr = match syntax_mapping.node_expr(receiver) { | 14 | let expr = match syntax_mapping.node_expr(receiver) { |
15 | Some(expr) => expr, | 15 | Some(expr) => expr, |
@@ -19,7 +19,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Ca | |||
19 | if !ctx.is_call { | 19 | if !ctx.is_call { |
20 | complete_fields(acc, ctx, receiver_ty.clone()); | 20 | complete_fields(acc, ctx, receiver_ty.clone()); |
21 | } | 21 | } |
22 | complete_methods(acc, ctx, receiver_ty)?; | 22 | complete_methods(acc, ctx, receiver_ty); |
23 | Ok(()) | 23 | Ok(()) |
24 | } | 24 | } |
25 | 25 | ||
@@ -55,11 +55,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) | |||
55 | } | 55 | } |
56 | } | 56 | } |
57 | 57 | ||
58 | fn complete_methods( | 58 | fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { |
59 | acc: &mut Completions, | ||
60 | ctx: &CompletionContext, | ||
61 | receiver: Ty, | ||
62 | ) -> Cancelable<()> { | ||
63 | receiver.iterate_methods(ctx.db, |func| { | 59 | receiver.iterate_methods(ctx.db, |func| { |
64 | let sig = func.signature(ctx.db); | 60 | let sig = func.signature(ctx.db); |
65 | if sig.has_self_param() { | 61 | if sig.has_self_param() { |
@@ -68,9 +64,8 @@ fn complete_methods( | |||
68 | .kind(CompletionItemKind::Method) | 64 | .kind(CompletionItemKind::Method) |
69 | .add_to(acc); | 65 | .add_to(acc); |
70 | } | 66 | } |
71 | Ok(None::<()>) | 67 | None::<()> |
72 | })?; | 68 | }); |
73 | Ok(()) | ||
74 | } | 69 | } |
75 | 70 | ||
76 | #[cfg(test)] | 71 | #[cfg(test)] |
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index cdd8e211d..e0f3deb0b 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -63,7 +63,7 @@ pub(crate) fn reference_definition( | |||
63 | .parent() | 63 | .parent() |
64 | .and_then(ast::MethodCallExpr::cast) | 64 | .and_then(ast::MethodCallExpr::cast) |
65 | { | 65 | { |
66 | let infer_result = function.infer(db)?; | 66 | let infer_result = function.infer(db); |
67 | let syntax_mapping = function.body_syntax_mapping(db); | 67 | let syntax_mapping = function.body_syntax_mapping(db); |
68 | let expr = ast::Expr::cast(method_call.syntax()).unwrap(); | 68 | let expr = ast::Expr::cast(method_call.syntax()).unwrap(); |
69 | if let Some(def_id) = syntax_mapping | 69 | if let Some(def_id) = syntax_mapping |
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 0e9c48421..6b5887bda 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs | |||
@@ -73,7 +73,7 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option | |||
73 | frange.file_id, | 73 | frange.file_id, |
74 | parent_fn | 74 | parent_fn |
75 | )); | 75 | )); |
76 | let infer = function.infer(db)?; | 76 | let infer = function.infer(db); |
77 | let syntax_mapping = function.body_syntax_mapping(db); | 77 | let syntax_mapping = function.body_syntax_mapping(db); |
78 | if let Some(expr) = ast::Expr::cast(node).and_then(|e| syntax_mapping.node_expr(e)) { | 78 | if let Some(expr) = ast::Expr::cast(node).and_then(|e| syntax_mapping.node_expr(e)) { |
79 | Ok(Some(infer[expr].to_string())) | 79 | Ok(Some(infer[expr].to_string())) |