Use type variables to determine exact type for ambiguous numeric literals

This commit is contained in:
Marcus Klaas de Vries 2019-01-10 18:08:54 +01:00
parent 5f5dc20d85
commit 1574715be5
6 changed files with 64 additions and 14 deletions

View File

@ -699,7 +699,22 @@ impl ExprCollector {
// TODO: actually parse integer
Literal::Int(0u64, ty)
}
SyntaxKind::FLOAT_NUMBER => Literal::Float(0, UncertainFloatTy::Unknown),
SyntaxKind::FLOAT_NUMBER => {
let text = c.text().to_string();
// FIXME: don't do it like this. maybe use something like
// the IntTy::from_name functions
let ty = if text.ends_with("f64") {
UncertainFloatTy::Known(FloatTy::F64)
} else if text.ends_with("f32") {
UncertainFloatTy::Known(FloatTy::F32)
} else {
UncertainFloatTy::Unknown
};
// TODO: actually parse value
Literal::Float(0, ty)
}
SyntaxKind::STRING => {
// FIXME: this likely includes the " characters
let text = c.text().to_string();

View File

@ -114,6 +114,8 @@ impl UnifyValue for TypeVarValue {
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum InferTy {
TypeVar(TypeVarId),
IntVar(TypeVarId),
FloatVar(TypeVarId),
}
/// When inferring an expression, we propagate downward whatever type hint we
@ -718,12 +720,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
.iter()
.zip(ts2.iter())
.all(|(t1, t2)| self.unify(t1, t2)),
(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) => {
(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
| (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(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))) => {
(Ty::Infer(InferTy::TypeVar(tv)), other)
| (other, Ty::Infer(InferTy::TypeVar(tv)))
| (Ty::Infer(InferTy::IntVar(tv)), other)
| (other, Ty::Infer(InferTy::IntVar(tv)))
| (Ty::Infer(InferTy::FloatVar(tv)), other)
| (other, Ty::Infer(InferTy::FloatVar(tv))) => {
// the type var is unknown since we tried to resolve it
self.var_unification_table
.union_value(*tv, TypeVarValue::Known(other.clone()));
@ -739,10 +748,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
))
}
fn new_integer_var(&mut self) -> Ty {
Ty::Infer(InferTy::IntVar(
self.var_unification_table.new_key(TypeVarValue::Unknown),
))
}
fn new_float_var(&mut self) -> Ty {
Ty::Infer(InferTy::FloatVar(
self.var_unification_table.new_key(TypeVarValue::Unknown),
))
}
/// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
match ty {
Ty::Unknown => self.new_type_var(),
Ty::Int(primitive::UncertainIntTy::Unknown) => self.new_integer_var(),
Ty::Float(primitive::UncertainFloatTy::Unknown) => self.new_float_var(),
_ => ty,
}
}
@ -757,12 +780,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
/// known type.
fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty {
ty.fold(&mut |ty| match ty {
Ty::Infer(InferTy::TypeVar(tv)) => {
Ty::Infer(InferTy::TypeVar(tv))
| Ty::Infer(InferTy::IntVar(tv))
| Ty::Infer(InferTy::FloatVar(tv)) => {
if let Some(known_ty) = self.var_unification_table.probe_value(tv).known() {
// known_ty may contain other variables that are known by now
self.resolve_ty_as_possible(known_ty.clone())
} else {
Ty::Infer(InferTy::TypeVar(tv))
ty
}
}
_ => ty,
@ -790,12 +815,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
/// replaced by Ty::Unknown.
fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
ty.fold(&mut |ty| match ty {
Ty::Infer(InferTy::TypeVar(tv)) => {
Ty::Infer(i) => {
let tv = match i {
InferTy::TypeVar(tv) | InferTy::IntVar(tv) | InferTy::FloatVar(tv) => tv,
};
if let Some(known_ty) = self.var_unification_table.probe_value(tv).known() {
// known_ty may contain other variables that are known by now
self.resolve_ty_completely(known_ty.clone())
} else {
Ty::Unknown
match i {
InferTy::TypeVar(..) => Ty::Unknown,
InferTy::IntVar(..) => Ty::Int(primitive::UncertainIntTy::Unknown),
InferTy::FloatVar(..) => Ty::Float(primitive::UncertainFloatTy::Unknown),
}
}
}
_ => ty,

View File

@ -145,6 +145,7 @@ fn test() {
3.14;
5000;
(0u32, -5isize);
false;
[true, true, false]
}
"#,

View File

@ -10,4 +10,4 @@
[76; 82) '1usize': usize
[88; 94) '1isize': isize
[100; 106) '"test"': &str
[112; 118) '1.0f32': [unknown]
[112; 118) '1.0f32': f32

View File

@ -1,10 +1,11 @@
[11; 135) '{ ...lse] }': ()
[11; 146) '{ ...lse] }': ()
[17; 21) '5i32': i32
[27; 34) '"hello"': &str
[40; 48) 'b"bytes"': &[u8]
[54; 57) ''c'': char
[63; 67) 'b'b'': u8
[73; 77) '3.14': [unknown]
[83; 87) '5000': [unknown]
[73; 77) '3.14': {float}
[83; 87) '5000': {integer}
[93; 108) '(0u32, -5isize)': [unknown]
[114; 133) '[true,...false]': ()
[114; 119) 'false': bool
[125; 144) '[true,...false]': ()

View File

@ -2,14 +2,14 @@
[82; 83) 'c': [unknown]
[86; 87) 'C': [unknown]
[86; 90) 'C(1)': [unknown]
[88; 89) '1': [unknown]
[88; 89) '1': {integer}
[96; 97) 'B': [unknown]
[107; 108) 'a': A
[114; 133) 'A { b:...C(1) }': A
[121; 122) 'B': B
[127; 128) 'C': [unknown]
[127; 131) 'C(1)': C
[129; 130) '1': [unknown]
[129; 130) '1': {integer}
[139; 140) 'a': A
[139; 142) 'a.b': B
[148; 149) 'a': A