diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 120 |
1 files changed, 62 insertions, 58 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index d11f80cff..45a01679c 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -522,6 +522,8 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
522 | impl_block: Option<ImplBlock>, | 522 | impl_block: Option<ImplBlock>, |
523 | var_unification_table: InPlaceUnificationTable<TypeVarId>, | 523 | var_unification_table: InPlaceUnificationTable<TypeVarId>, |
524 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, | 524 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, |
525 | /// The return type of the function being inferred. | ||
526 | return_ty: Ty, | ||
525 | } | 527 | } |
526 | 528 | ||
527 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 529 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
@@ -534,7 +536,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
534 | InferenceContext { | 536 | InferenceContext { |
535 | type_of: FxHashMap::default(), | 537 | type_of: FxHashMap::default(), |
536 | var_unification_table: InPlaceUnificationTable::new(), | 538 | var_unification_table: InPlaceUnificationTable::new(), |
537 | self_param: None, // set during parameter typing | 539 | self_param: None, // set during parameter typing |
540 | return_ty: Ty::Unknown, // set in collect_fn_signature | ||
538 | db, | 541 | db, |
539 | scopes, | 542 | scopes, |
540 | module, | 543 | module, |
@@ -555,6 +558,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
555 | self.type_of.insert(LocalSyntaxPtr::new(node), ty); | 558 | self.type_of.insert(LocalSyntaxPtr::new(node), ty); |
556 | } | 559 | } |
557 | 560 | ||
561 | fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> { | ||
562 | Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref) | ||
563 | } | ||
564 | |||
565 | fn make_ty_opt(&self, type_ref: Option<&TypeRef>) -> Cancelable<Ty> { | ||
566 | Ty::from_hir_opt(self.db, &self.module, self.impl_block.as_ref(), type_ref) | ||
567 | } | ||
568 | |||
558 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 569 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { |
559 | match (ty1, ty2) { | 570 | match (ty1, ty2) { |
560 | (Ty::Unknown, ..) => true, | 571 | (Ty::Unknown, ..) => true, |
@@ -952,78 +963,71 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
952 | self.write_ty(node.syntax(), ty.clone()); | 963 | self.write_ty(node.syntax(), ty.clone()); |
953 | Ok(ty) | 964 | Ok(ty) |
954 | } | 965 | } |
955 | } | ||
956 | |||
957 | pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { | ||
958 | let function = Function::new(def_id); // TODO: consts also need inference | ||
959 | let scopes = function.scopes(db); | ||
960 | let module = function.module(db)?; | ||
961 | let impl_block = function.impl_block(db)?; | ||
962 | let mut ctx = InferenceContext::new(db, scopes, module, impl_block); | ||
963 | 966 | ||
964 | let syntax = function.syntax(db); | 967 | fn collect_fn_signature(&mut self, node: ast::FnDef) -> Cancelable<()> { |
965 | let node = syntax.borrowed(); | 968 | if let Some(param_list) = node.param_list() { |
966 | 969 | if let Some(self_param) = param_list.self_param() { | |
967 | if let Some(param_list) = node.param_list() { | 970 | let self_type = if let Some(type_ref) = self_param.type_ref() { |
968 | if let Some(self_param) = param_list.self_param() { | 971 | let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; |
969 | let self_type = if let Some(impl_block) = &ctx.impl_block { | 972 | self.insert_type_vars(ty) |
970 | if let Some(type_ref) = self_param.type_ref() { | ||
971 | let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?; | ||
972 | ctx.insert_type_vars(ty) | ||
973 | } else { | 973 | } else { |
974 | // TODO this should be handled by desugaring during HIR conversion | 974 | // TODO this should be handled by desugaring during HIR conversion |
975 | let ty = Ty::from_hir( | 975 | let ty = self.make_ty_opt(self.impl_block.as_ref().map(|i| i.target()))?; |
976 | db, | ||
977 | &ctx.module, | ||
978 | ctx.impl_block.as_ref(), | ||
979 | impl_block.target(), | ||
980 | )?; | ||
981 | let ty = match self_param.flavor() { | 976 | let ty = match self_param.flavor() { |
982 | ast::SelfParamFlavor::Owned => ty, | 977 | ast::SelfParamFlavor::Owned => ty, |
983 | ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared), | 978 | ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared), |
984 | ast::SelfParamFlavor::MutRef => Ty::Ref(Arc::new(ty), Mutability::Mut), | 979 | ast::SelfParamFlavor::MutRef => Ty::Ref(Arc::new(ty), Mutability::Mut), |
985 | }; | 980 | }; |
986 | ctx.insert_type_vars(ty) | 981 | self.insert_type_vars(ty) |
982 | }; | ||
983 | if let Some(self_kw) = self_param.self_kw() { | ||
984 | let self_param = LocalSyntaxPtr::new(self_kw.syntax()); | ||
985 | self.self_param = Some(self_param); | ||
986 | self.type_of.insert(self_param, self_type); | ||
987 | } | 987 | } |
988 | } else { | 988 | } |
989 | log::debug!( | 989 | for param in param_list.params() { |
990 | "No impl block found, but self param for function {:?}", | 990 | let pat = if let Some(pat) = param.pat() { |
991 | def_id | 991 | pat |
992 | ); | 992 | } else { |
993 | ctx.new_type_var() | 993 | continue; |
994 | }; | 994 | }; |
995 | if let Some(self_kw) = self_param.self_kw() { | 995 | let ty = if let Some(type_ref) = param.type_ref() { |
996 | let self_param = LocalSyntaxPtr::new(self_kw.syntax()); | 996 | let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; |
997 | ctx.self_param = Some(self_param); | 997 | self.insert_type_vars(ty) |
998 | ctx.type_of.insert(self_param, self_type); | 998 | } else { |
999 | // missing type annotation | ||
1000 | self.new_type_var() | ||
1001 | }; | ||
1002 | self.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty); | ||
999 | } | 1003 | } |
1000 | } | 1004 | } |
1001 | for param in param_list.params() { | 1005 | |
1002 | let pat = if let Some(pat) = param.pat() { | 1006 | self.return_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) { |
1003 | pat | 1007 | let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; |
1004 | } else { | 1008 | self.insert_type_vars(ty) |
1005 | continue; | 1009 | } else { |
1006 | }; | 1010 | Ty::unit() |
1007 | let ty = if let Some(type_ref) = param.type_ref() { | 1011 | }; |
1008 | let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?; | 1012 | |
1009 | ctx.insert_type_vars(ty) | 1013 | Ok(()) |
1010 | } else { | ||
1011 | // missing type annotation | ||
1012 | ctx.new_type_var() | ||
1013 | }; | ||
1014 | ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty); | ||
1015 | } | ||
1016 | } | 1014 | } |
1015 | } | ||
1017 | 1016 | ||
1018 | let ret_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) { | 1017 | pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { |
1019 | let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?; | 1018 | let function = Function::new(def_id); // TODO: consts also need inference |
1020 | ctx.insert_type_vars(ty) | 1019 | let scopes = function.scopes(db); |
1021 | } else { | 1020 | let module = function.module(db)?; |
1022 | Ty::unit() | 1021 | let impl_block = function.impl_block(db)?; |
1023 | }; | 1022 | let mut ctx = InferenceContext::new(db, scopes, module, impl_block); |
1023 | |||
1024 | let syntax = function.syntax(db); | ||
1025 | let node = syntax.borrowed(); | ||
1026 | |||
1027 | ctx.collect_fn_signature(node)?; | ||
1024 | 1028 | ||
1025 | if let Some(block) = node.body() { | 1029 | if let Some(block) = node.body() { |
1026 | ctx.infer_block(block, &Expectation::has_type(ret_ty))?; | 1030 | ctx.infer_block(block, &Expectation::has_type(ctx.return_ty.clone()))?; |
1027 | } | 1031 | } |
1028 | 1032 | ||
1029 | Ok(Arc::new(ctx.resolve_all())) | 1033 | Ok(Arc::new(ctx.resolve_all())) |