aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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) '{}': ()