aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-01-10 21:49:43 +0000
committerFlorian Diebold <[email protected]>2019-01-11 21:59:00 +0000
commit1212e59beed25d768bfaf7bb202aa955a87106e9 (patch)
treee2996f670efd50d346cfa8dd0f836bcb65aca4dc /crates
parentf60153ee9e1d598c170743633448aa3ede8cb72e (diff)
Fix assertion error in unification (hopefully)
Currently, all types that we handle during inference need to be resolved as far as possible at the time. It's maybe too brittle of an invariant; I need to think how we can do this better. This should fix #484 though, I hope (if it's the same case as I managed to reproduce).
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/ty.rs40
-rw-r--r--crates/ra_hir/src/ty/tests.rs12
-rw-r--r--crates/ra_hir/src/ty/tests/data/bug_484.txt5
3 files changed, 50 insertions, 7 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 0c24a0652..2d533eb6a 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -18,6 +18,7 @@ mod primitive;
18#[cfg(test)] 18#[cfg(test)]
19mod tests; 19mod tests;
20 20
21use std::borrow::Cow;
21use std::ops::Index; 22use std::ops::Index;
22use std::sync::Arc; 23use std::sync::Arc;
23use std::{fmt, mem}; 24use std::{fmt, mem};
@@ -671,7 +672,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
671 } 672 }
672 673
673 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 674 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
674 match (ty1, ty2) { 675 // try to resolve type vars first
676 let ty1 = self.resolve_ty_shallow(ty1);
677 let ty2 = self.resolve_ty_shallow(ty2);
678 match (&*ty1, &*ty2) {
675 (Ty::Unknown, ..) => true, 679 (Ty::Unknown, ..) => true,
676 (.., Ty::Unknown) => true, 680 (.., Ty::Unknown) => true,
677 (Ty::Bool, _) 681 (Ty::Bool, _)
@@ -698,10 +702,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
698 .zip(ts2.iter()) 702 .zip(ts2.iter())
699 .all(|(t1, t2)| self.unify(t1, t2)), 703 .all(|(t1, t2)| self.unify(t1, t2)),
700 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) => { 704 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) => {
705 // both type vars are unknown since we tried to resolve them
701 self.var_unification_table.union(*tv1, *tv2); 706 self.var_unification_table.union(*tv1, *tv2);
702 true 707 true
703 } 708 }
704 (Ty::Infer(InferTy::TypeVar(tv)), other) | (other, Ty::Infer(InferTy::TypeVar(tv))) => { 709 (Ty::Infer(InferTy::TypeVar(tv)), other) | (other, Ty::Infer(InferTy::TypeVar(tv))) => {
710 // the type var is unknown since we tried to resolve it
705 self.var_unification_table 711 self.var_unification_table
706 .union_value(*tv, TypeVarValue::Known(other.clone())); 712 .union_value(*tv, TypeVarValue::Known(other.clone()));
707 true 713 true
@@ -746,6 +752,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
746 }) 752 })
747 } 753 }
748 754
755 /// If `ty` is a type variable with known type, returns that type;
756 /// otherwise, return ty.
757 fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
758 match ty {
759 Ty::Infer(InferTy::TypeVar(tv)) => {
760 match self.var_unification_table.probe_value(*tv).known() {
761 Some(known_ty) => {
762 // The known_ty can't be a type var itself
763 Cow::Owned(known_ty.clone())
764 }
765 _ => Cow::Borrowed(ty),
766 }
767 }
768 _ => Cow::Borrowed(ty),
769 }
770 }
771
749 /// Resolves the type completely; type variables without known type are 772 /// Resolves the type completely; type variables without known type are
750 /// replaced by Ty::Unknown. 773 /// replaced by Ty::Unknown.
751 fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { 774 fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
@@ -816,12 +839,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
816 // if let is desugared to match, so this is always simple if 839 // if let is desugared to match, so this is always simple if
817 self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?; 840 self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?;
818 let then_ty = self.infer_expr(*then_branch, expected)?; 841 let then_ty = self.infer_expr(*then_branch, expected)?;
819 if let Some(else_branch) = else_branch { 842 match else_branch {
820 self.infer_expr(*else_branch, expected)?; 843 Some(else_branch) => {
821 } else { 844 self.infer_expr(*else_branch, expected)?;
822 // no else branch -> unit 845 }
823 self.unify(&expected.ty, &Ty::unit()); // actually coerce 846 None => {
824 } 847 // no else branch -> unit
848 self.unify(&then_ty, &Ty::unit()); // actually coerce
849 }
850 };
825 then_ty 851 then_ty
826 } 852 }
827 Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected)?, 853 Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected)?,
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index d8c0af326..815aecda7 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -230,6 +230,18 @@ fn test2(a1: *const A, a2: *mut A) {
230 ); 230 );
231} 231}
232 232
233#[test]
234fn infer_bug_484() {
235 check_inference(
236 r#"
237fn test() {
238 let x = if true {};
239}
240"#,
241 "bug_484.txt",
242 );
243}
244
233fn infer(content: &str) -> String { 245fn infer(content: &str) -> String {
234 let (db, _, file_id) = MockDatabase::with_single_file(content); 246 let (db, _, file_id) = MockDatabase::with_single_file(content);
235 let source_file = db.source_file(file_id); 247 let source_file = db.source_file(file_id);
diff --git a/crates/ra_hir/src/ty/tests/data/bug_484.txt b/crates/ra_hir/src/ty/tests/data/bug_484.txt
new file mode 100644
index 000000000..300530551
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/bug_484.txt
@@ -0,0 +1,5 @@
1[11; 37) '{ l... {}; }': ()
2[20; 21) 'x': ()
3[24; 34) 'if true {}': ()
4[27; 31) 'true': bool
5[32; 34) '{}': ()