diff options
Diffstat (limited to 'crates/ra_hir_ty/src/infer.rs')
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 68 |
1 files changed, 65 insertions, 3 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index bd4ef69a0..fb7c6cd8c 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -22,7 +22,7 @@ use rustc_hash::FxHashMap; | |||
22 | 22 | ||
23 | use hir_def::{ | 23 | use hir_def::{ |
24 | body::Body, | 24 | body::Body, |
25 | data::{ConstData, FunctionData}, | 25 | data::{ConstData, FunctionData, StaticData}, |
26 | expr::{BindingAnnotation, ExprId, PatId}, | 26 | expr::{BindingAnnotation, ExprId, PatId}, |
27 | lang_item::LangItemTarget, | 27 | lang_item::LangItemTarget, |
28 | path::{path, Path}, | 28 | path::{path, Path}, |
@@ -71,7 +71,7 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer | |||
71 | match def { | 71 | match def { |
72 | DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)), | 72 | DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)), |
73 | DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)), | 73 | DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)), |
74 | DefWithBodyId::StaticId(s) => ctx.collect_const(&db.static_data(s)), | 74 | DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)), |
75 | } | 75 | } |
76 | 76 | ||
77 | ctx.infer_body(); | 77 | ctx.infer_body(); |
@@ -210,6 +210,13 @@ struct InferenceContext<'a> { | |||
210 | /// closures, but currently this is the only field that will change there, | 210 | /// closures, but currently this is the only field that will change there, |
211 | /// so it doesn't make sense. | 211 | /// so it doesn't make sense. |
212 | return_ty: Ty, | 212 | return_ty: Ty, |
213 | diverges: Diverges, | ||
214 | breakables: Vec<BreakableContext>, | ||
215 | } | ||
216 | |||
217 | #[derive(Clone, Debug)] | ||
218 | struct BreakableContext { | ||
219 | pub may_break: bool, | ||
213 | } | 220 | } |
214 | 221 | ||
215 | impl<'a> InferenceContext<'a> { | 222 | impl<'a> InferenceContext<'a> { |
@@ -224,6 +231,8 @@ impl<'a> InferenceContext<'a> { | |||
224 | owner, | 231 | owner, |
225 | body: db.body(owner), | 232 | body: db.body(owner), |
226 | resolver, | 233 | resolver, |
234 | diverges: Diverges::Maybe, | ||
235 | breakables: Vec::new(), | ||
227 | } | 236 | } |
228 | } | 237 | } |
229 | 238 | ||
@@ -476,6 +485,10 @@ impl<'a> InferenceContext<'a> { | |||
476 | self.return_ty = self.make_ty(&data.type_ref); | 485 | self.return_ty = self.make_ty(&data.type_ref); |
477 | } | 486 | } |
478 | 487 | ||
488 | fn collect_static(&mut self, data: &StaticData) { | ||
489 | self.return_ty = self.make_ty(&data.type_ref); | ||
490 | } | ||
491 | |||
479 | fn collect_fn(&mut self, data: &FunctionData) { | 492 | fn collect_fn(&mut self, data: &FunctionData) { |
480 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 493 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
481 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) | 494 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) |
@@ -666,15 +679,57 @@ impl Expectation { | |||
666 | } | 679 | } |
667 | } | 680 | } |
668 | 681 | ||
682 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] | ||
683 | enum Diverges { | ||
684 | Maybe, | ||
685 | Always, | ||
686 | } | ||
687 | |||
688 | impl Diverges { | ||
689 | fn is_always(self) -> bool { | ||
690 | self == Diverges::Always | ||
691 | } | ||
692 | } | ||
693 | |||
694 | impl std::ops::BitAnd for Diverges { | ||
695 | type Output = Self; | ||
696 | fn bitand(self, other: Self) -> Self { | ||
697 | std::cmp::min(self, other) | ||
698 | } | ||
699 | } | ||
700 | |||
701 | impl std::ops::BitOr for Diverges { | ||
702 | type Output = Self; | ||
703 | fn bitor(self, other: Self) -> Self { | ||
704 | std::cmp::max(self, other) | ||
705 | } | ||
706 | } | ||
707 | |||
708 | impl std::ops::BitAndAssign for Diverges { | ||
709 | fn bitand_assign(&mut self, other: Self) { | ||
710 | *self = *self & other; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | impl std::ops::BitOrAssign for Diverges { | ||
715 | fn bitor_assign(&mut self, other: Self) { | ||
716 | *self = *self | other; | ||
717 | } | ||
718 | } | ||
719 | |||
669 | mod diagnostics { | 720 | mod diagnostics { |
670 | use hir_def::{expr::ExprId, FunctionId}; | 721 | use hir_def::{expr::ExprId, FunctionId}; |
671 | use hir_expand::diagnostics::DiagnosticSink; | 722 | use hir_expand::diagnostics::DiagnosticSink; |
672 | 723 | ||
673 | use crate::{db::HirDatabase, diagnostics::NoSuchField}; | 724 | use crate::{ |
725 | db::HirDatabase, | ||
726 | diagnostics::{BreakOutsideOfLoop, NoSuchField}, | ||
727 | }; | ||
674 | 728 | ||
675 | #[derive(Debug, PartialEq, Eq, Clone)] | 729 | #[derive(Debug, PartialEq, Eq, Clone)] |
676 | pub(super) enum InferenceDiagnostic { | 730 | pub(super) enum InferenceDiagnostic { |
677 | NoSuchField { expr: ExprId, field: usize }, | 731 | NoSuchField { expr: ExprId, field: usize }, |
732 | BreakOutsideOfLoop { expr: ExprId }, | ||
678 | } | 733 | } |
679 | 734 | ||
680 | impl InferenceDiagnostic { | 735 | impl InferenceDiagnostic { |
@@ -690,6 +745,13 @@ mod diagnostics { | |||
690 | let field = source_map.field_syntax(*expr, *field); | 745 | let field = source_map.field_syntax(*expr, *field); |
691 | sink.push(NoSuchField { file: field.file_id, field: field.value }) | 746 | sink.push(NoSuchField { file: field.file_id, field: field.value }) |
692 | } | 747 | } |
748 | InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | ||
749 | let (_, source_map) = db.body_with_source_map(owner.into()); | ||
750 | let ptr = source_map | ||
751 | .expr_syntax(*expr) | ||
752 | .expect("break outside of loop in synthetic syntax"); | ||
753 | sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value }) | ||
754 | } | ||
693 | } | 755 | } |
694 | } | 756 | } |
695 | } | 757 | } |