From 1574715be5d3fc7e07160708810dcbc9c1b01733 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Thu, 10 Jan 2019 18:08:54 +0100 Subject: Use type variables to determine exact type for ambiguous numeric literals --- crates/ra_hir/src/expr.rs | 17 ++++++++++- crates/ra_hir/src/ty.rs | 45 ++++++++++++++++++++++++---- crates/ra_hir/src/ty/tests.rs | 1 + crates/ra_hir/src/ty/tests/data/basics.txt | 2 +- crates/ra_hir/src/ty/tests/data/literals.txt | 9 +++--- crates/ra_hir/src/ty/tests/data/struct.txt | 4 +-- 6 files changed, 64 insertions(+), 14 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index bc8515836..2798937a6 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -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(); diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 13a1c2907..b4b338874 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -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, diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 97d3d222f..0c43415a6 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -145,6 +145,7 @@ fn test() { 3.14; 5000; (0u32, -5isize); + false; [true, true, false] } "#, diff --git a/crates/ra_hir/src/ty/tests/data/basics.txt b/crates/ra_hir/src/ty/tests/data/basics.txt index 4a3b69b7e..e65fe07aa 100644 --- a/crates/ra_hir/src/ty/tests/data/basics.txt +++ b/crates/ra_hir/src/ty/tests/data/basics.txt @@ -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 diff --git a/crates/ra_hir/src/ty/tests/data/literals.txt b/crates/ra_hir/src/ty/tests/data/literals.txt index e139d57a8..df435edd7 100644 --- a/crates/ra_hir/src/ty/tests/data/literals.txt +++ b/crates/ra_hir/src/ty/tests/data/literals.txt @@ -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]': () diff --git a/crates/ra_hir/src/ty/tests/data/struct.txt b/crates/ra_hir/src/ty/tests/data/struct.txt index 7b324c82f..dcdf61363 100644 --- a/crates/ra_hir/src/ty/tests/data/struct.txt +++ b/crates/ra_hir/src/ty/tests/data/struct.txt @@ -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 -- cgit v1.2.3