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).
This commit is contained in:
parent
f60153ee9e
commit
1212e59bee
@ -18,6 +18,7 @@ mod primitive;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Index;
|
||||
use std::sync::Arc;
|
||||
use std::{fmt, mem};
|
||||
@ -671,7 +672,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
}
|
||||
|
||||
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
|
||||
match (ty1, ty2) {
|
||||
// try to resolve type vars first
|
||||
let ty1 = self.resolve_ty_shallow(ty1);
|
||||
let ty2 = self.resolve_ty_shallow(ty2);
|
||||
match (&*ty1, &*ty2) {
|
||||
(Ty::Unknown, ..) => true,
|
||||
(.., Ty::Unknown) => true,
|
||||
(Ty::Bool, _)
|
||||
@ -698,10 +702,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
.zip(ts2.iter())
|
||||
.all(|(t1, t2)| self.unify(t1, t2)),
|
||||
(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) => {
|
||||
// both type vars are unknown since we tried to resolve them
|
||||
self.var_unification_table.union(*tv1, *tv2);
|
||||
true
|
||||
}
|
||||
(Ty::Infer(InferTy::TypeVar(tv)), other) | (other, Ty::Infer(InferTy::TypeVar(tv))) => {
|
||||
// the type var is unknown since we tried to resolve it
|
||||
self.var_unification_table
|
||||
.union_value(*tv, TypeVarValue::Known(other.clone()));
|
||||
true
|
||||
@ -746,6 +752,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
})
|
||||
}
|
||||
|
||||
/// If `ty` is a type variable with known type, returns that type;
|
||||
/// otherwise, return ty.
|
||||
fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
|
||||
match ty {
|
||||
Ty::Infer(InferTy::TypeVar(tv)) => {
|
||||
match self.var_unification_table.probe_value(*tv).known() {
|
||||
Some(known_ty) => {
|
||||
// The known_ty can't be a type var itself
|
||||
Cow::Owned(known_ty.clone())
|
||||
}
|
||||
_ => Cow::Borrowed(ty),
|
||||
}
|
||||
}
|
||||
_ => Cow::Borrowed(ty),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the type completely; type variables without known type are
|
||||
/// replaced by Ty::Unknown.
|
||||
fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
|
||||
@ -816,12 +839,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
// if let is desugared to match, so this is always simple if
|
||||
self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?;
|
||||
let then_ty = self.infer_expr(*then_branch, expected)?;
|
||||
if let Some(else_branch) = else_branch {
|
||||
self.infer_expr(*else_branch, expected)?;
|
||||
} else {
|
||||
// no else branch -> unit
|
||||
self.unify(&expected.ty, &Ty::unit()); // actually coerce
|
||||
}
|
||||
match else_branch {
|
||||
Some(else_branch) => {
|
||||
self.infer_expr(*else_branch, expected)?;
|
||||
}
|
||||
None => {
|
||||
// no else branch -> unit
|
||||
self.unify(&then_ty, &Ty::unit()); // actually coerce
|
||||
}
|
||||
};
|
||||
then_ty
|
||||
}
|
||||
Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected)?,
|
||||
|
@ -230,6 +230,18 @@ fn test2(a1: *const A, a2: *mut A) {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_bug_484() {
|
||||
check_inference(
|
||||
r#"
|
||||
fn test() {
|
||||
let x = if true {};
|
||||
}
|
||||
"#,
|
||||
"bug_484.txt",
|
||||
);
|
||||
}
|
||||
|
||||
fn infer(content: &str) -> String {
|
||||
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
||||
let source_file = db.source_file(file_id);
|
||||
|
5
crates/ra_hir/src/ty/tests/data/bug_484.txt
Normal file
5
crates/ra_hir/src/ty/tests/data/bug_484.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[11; 37) '{ l... {}; }': ()
|
||||
[20; 21) 'x': ()
|
||||
[24; 34) 'if true {}': ()
|
||||
[27; 31) 'true': bool
|
||||
[32; 34) '{}': ()
|
Loading…
x
Reference in New Issue
Block a user