diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-05-08 19:09:25 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-05-08 19:09:25 +0100 |
commit | f9ec7cebef732fbc9d4849d87d325efef5faadea (patch) | |
tree | 4a40dbed04c432dee54f8a8d016c89c7411b1e6d /crates/ra_hir_ty/src/infer.rs | |
parent | f1fa9aa4c4d4fcfe7d6e90ba9cefca90bc7c4998 (diff) | |
parent | d0129c4ddba3b72e7b26e94e9c25546d37dbf166 (diff) |
Merge #4377
4377: Implement better handling of divergence r=matklad a=flodiebold
Divergence here means that for some reason, the end of a block will not be reached. We tried to model this just using the never type, but that doesn't work fully (e.g. in `let x = { loop {}; "foo" };` x should still have type `&str`); so this introduces a `diverges` flag that the type checker keeps track of, like rustc does. We also add some checking for `break`, but no support for break-with-value or labeled breaks yet.
Co-authored-by: Florian Diebold <[email protected]>
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir_ty/src/infer.rs')
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index bd4ef69a0..a21ad8d86 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -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 | ||
@@ -666,15 +675,57 @@ impl Expectation { | |||
666 | } | 675 | } |
667 | } | 676 | } |
668 | 677 | ||
678 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] | ||
679 | enum Diverges { | ||
680 | Maybe, | ||
681 | Always, | ||
682 | } | ||
683 | |||
684 | impl Diverges { | ||
685 | fn is_always(self) -> bool { | ||
686 | self == Diverges::Always | ||
687 | } | ||
688 | } | ||
689 | |||
690 | impl std::ops::BitAnd for Diverges { | ||
691 | type Output = Self; | ||
692 | fn bitand(self, other: Self) -> Self { | ||
693 | std::cmp::min(self, other) | ||
694 | } | ||
695 | } | ||
696 | |||
697 | impl std::ops::BitOr for Diverges { | ||
698 | type Output = Self; | ||
699 | fn bitor(self, other: Self) -> Self { | ||
700 | std::cmp::max(self, other) | ||
701 | } | ||
702 | } | ||
703 | |||
704 | impl std::ops::BitAndAssign for Diverges { | ||
705 | fn bitand_assign(&mut self, other: Self) { | ||
706 | *self = *self & other; | ||
707 | } | ||
708 | } | ||
709 | |||
710 | impl std::ops::BitOrAssign for Diverges { | ||
711 | fn bitor_assign(&mut self, other: Self) { | ||
712 | *self = *self | other; | ||
713 | } | ||
714 | } | ||
715 | |||
669 | mod diagnostics { | 716 | mod diagnostics { |
670 | use hir_def::{expr::ExprId, FunctionId}; | 717 | use hir_def::{expr::ExprId, FunctionId}; |
671 | use hir_expand::diagnostics::DiagnosticSink; | 718 | use hir_expand::diagnostics::DiagnosticSink; |
672 | 719 | ||
673 | use crate::{db::HirDatabase, diagnostics::NoSuchField}; | 720 | use crate::{ |
721 | db::HirDatabase, | ||
722 | diagnostics::{BreakOutsideOfLoop, NoSuchField}, | ||
723 | }; | ||
674 | 724 | ||
675 | #[derive(Debug, PartialEq, Eq, Clone)] | 725 | #[derive(Debug, PartialEq, Eq, Clone)] |
676 | pub(super) enum InferenceDiagnostic { | 726 | pub(super) enum InferenceDiagnostic { |
677 | NoSuchField { expr: ExprId, field: usize }, | 727 | NoSuchField { expr: ExprId, field: usize }, |
728 | BreakOutsideOfLoop { expr: ExprId }, | ||
678 | } | 729 | } |
679 | 730 | ||
680 | impl InferenceDiagnostic { | 731 | impl InferenceDiagnostic { |
@@ -690,6 +741,13 @@ mod diagnostics { | |||
690 | let field = source_map.field_syntax(*expr, *field); | 741 | let field = source_map.field_syntax(*expr, *field); |
691 | sink.push(NoSuchField { file: field.file_id, field: field.value }) | 742 | sink.push(NoSuchField { file: field.file_id, field: field.value }) |
692 | } | 743 | } |
744 | InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | ||
745 | let (_, source_map) = db.body_with_source_map(owner.into()); | ||
746 | let ptr = source_map | ||
747 | .expr_syntax(*expr) | ||
748 | .expect("break outside of loop in synthetic syntax"); | ||
749 | sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value }) | ||
750 | } | ||
693 | } | 751 | } |
694 | } | 752 | } |
695 | } | 753 | } |