]> git.lizzy.rs Git - rust.git/commitdiff
rustc: Implement floating point literal inference. r=nmatsakis
authorPatrick Walton <pcwalton@mimiga.net>
Thu, 8 Nov 2012 02:40:34 +0000 (18:40 -0800)
committerPatrick Walton <pcwalton@mimiga.net>
Mon, 12 Nov 2012 18:39:08 +0000 (10:39 -0800)
20 files changed:
src/librustc/metadata/tyencode.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/trans/consts.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/infer.rs
src/librustc/middle/typeck/infer/combine.rs
src/librustc/middle/typeck/infer/floating.rs [new file with mode: 0644]
src/librustc/middle/typeck/infer/resolve.rs
src/librustc/middle/typeck/infer/to_str.rs
src/librustc/middle/typeck/infer/unify.rs
src/librustc/rustc.rc
src/libsyntax/ast.rs
src/libsyntax/parse/lexer.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/test/compile-fail/float-literal-inference-restrictions.rs [new file with mode: 0644]
src/test/run-pass/float-literal-inference.rs [new file with mode: 0644]

index 4129066ff2863eca54c377bfb7144bc5ba55cd60..922fff18e9e59b63434f0b5b3bbed2d93caf6208 100644 (file)
@@ -286,6 +286,11 @@ fn enc_sty(w: io::Writer, cx: @ctxt, st: ty::sty) {
         w.write_char('I');
         w.write_uint(id.to_uint());
       }
+      ty::ty_infer(ty::FloatVar(id)) => {
+        w.write_char('X');
+        w.write_char('F');
+        w.write_uint(id.to_uint());
+      }
       ty::ty_param({idx: id, def_id: did}) => {
         w.write_char('p');
         w.write_str(cx.ds(did));
index 3e30bf50e023d5d548c058f63f646e15593229d4..cbe5430b5be40122aaa3087cf601851564cd3a7e 100644 (file)
@@ -389,6 +389,8 @@ fn lit_to_const(lit: @lit) -> const_val {
       lit_uint(n, _) => const_uint(n),
       lit_int_unsuffixed(n) => const_int(n),
       lit_float(n, _) => const_float(float::from_str(*n).get() as f64),
+      lit_float_unsuffixed(n) =>
+        const_float(float::from_str(*n).get() as f64),
       lit_nil => const_int(0i64),
       lit_bool(b) => const_bool(b)
     }
index 23ec0b6a9c184dbd4bba31498b2aa55d2d0763c0..6796d139bc76fd548e329c0ab523b2c769f64a52 100644 (file)
@@ -22,6 +22,19 @@ fn const_lit(cx: @crate_ctxt, e: @ast::expr, lit: ast::lit)
         }
       }
       ast::lit_float(fs, t) => C_floating(*fs, T_float_ty(cx, t)),
+      ast::lit_float_unsuffixed(fs) => {
+        let lit_float_ty = ty::node_id_to_type(cx.tcx, e.id);
+        match ty::get(lit_float_ty).sty {
+          ty::ty_float(t) => {
+            C_floating(*fs, T_float_ty(cx, t))
+          }
+          _ => {
+            cx.sess.span_bug(lit.span,
+                             ~"floating point literal doesn't have the right \
+                               type");
+          }
+        }
+      }
       ast::lit_bool(b) => C_bool(b),
       ast::lit_nil => C_nil(),
       ast::lit_str(s) => C_estr_slice(cx, *s)
index 52f05eb44de0115430619c1582ec1d110016e17a..e7cf5fa8ad8abb6b953f5b195f2a5ee500cfd342 100644 (file)
@@ -21,7 +21,7 @@
 
 export ProvidedMethodSource;
 export InstantiatedTraitRef;
-export TyVid, IntVid, FnVid, RegionVid, vid;
+export TyVid, IntVid, FloatVid, FnVid, RegionVid, vid;
 export br_hashmap;
 export is_instantiable;
 export node_id_to_type;
@@ -86,6 +86,7 @@
 export ty_fn_proto, ty_fn_purity, ty_fn_ret, ty_fn_ret_style, tys_in_fn_ty;
 export ty_int, mk_int, mk_mach_int, mk_char;
 export mk_i8, mk_u8, mk_i16, mk_u16, mk_i32, mk_u32, mk_i64, mk_u64;
+export mk_f32, mk_f64;
 export ty_estr, mk_estr, type_is_str;
 export ty_evec, mk_evec, type_is_vec;
 export ty_unboxed_vec, mk_unboxed_vec, mk_mut_unboxed_vec;
 export ty_type, mk_type;
 export ty_uint, mk_uint, mk_mach_uint;
 export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box;
-export ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var;
-export InferTy, TyVar, IntVar;
+export ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var, mk_float_var;
+export InferTy, TyVar, IntVar, FloatVar;
 export ty_self, mk_self, type_has_self;
 export ty_class;
 export Region, bound_region, encl_region;
 export normalize_ty;
 export to_str;
 export bound_const;
-export terr_no_integral_type, terr_ty_param_size, terr_self_substs;
+export terr_no_integral_type, terr_no_floating_point_type;
+export terr_ty_param_size, terr_self_substs;
 export terr_in_field, terr_record_fields, terr_vstores_differ, terr_arg_count;
 export terr_sorts, terr_vec, terr_str, terr_record_size, terr_tuple_size;
 export terr_regions_does_not_outlive, terr_mutability, terr_purity_mismatch;
@@ -666,6 +668,7 @@ enum type_err {
     terr_sorts(expected_found<t>),
     terr_self_substs,
     terr_no_integral_type,
+    terr_no_floating_point_type,
 }
 
 enum param_bound {
@@ -678,6 +681,7 @@ enum param_bound {
 
 enum TyVid = uint;
 enum IntVid = uint;
+enum FloatVid = uint;
 enum FnVid = uint;
 #[auto_serialize]
 #[auto_deserialize]
@@ -685,14 +689,16 @@ enum param_bound {
 
 enum InferTy {
     TyVar(TyVid),
-    IntVar(IntVid)
+    IntVar(IntVid),
+    FloatVar(FloatVid)
 }
 
 impl InferTy : to_bytes::IterBytes {
     pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
         match self {
           TyVar(ref tv) => to_bytes::iter_bytes_2(&0u8, tv, lsb0, f),
-          IntVar(ref iv) => to_bytes::iter_bytes_2(&1u8, iv, lsb0, f)
+          IntVar(ref iv) => to_bytes::iter_bytes_2(&1u8, iv, lsb0, f),
+          FloatVar(ref fv) => to_bytes::iter_bytes_2(&2u8, fv, lsb0, f)
         }
     }
 }
@@ -758,6 +764,11 @@ impl IntVid: vid {
     pure fn to_str() -> ~str { fmt!("<VI%u>", self.to_uint()) }
 }
 
+impl FloatVid: vid {
+    pure fn to_uint() -> uint { *self }
+    pure fn to_str() -> ~str { fmt!("<VF%u>", self.to_uint()) }
+}
+
 impl FnVid: vid {
     pure fn to_uint() -> uint { *self }
     pure fn to_str() -> ~str { fmt!("<F%u>", self.to_uint()) }
@@ -773,6 +784,7 @@ impl InferTy {
         match self {
             TyVar(v) => v.to_uint() << 1,
             IntVar(v) => (v.to_uint() << 1) + 1,
+            FloatVar(v) => (v.to_uint() << 1) + 2
         }
     }
 
@@ -780,6 +792,7 @@ impl InferTy {
         match self {
             TyVar(v) => v.to_str(),
             IntVar(v) => v.to_str(),
+            FloatVar(v) => v.to_str()
         }
     }
 }
@@ -812,6 +825,12 @@ impl IntVid : to_bytes::IterBytes {
     }
 }
 
+impl FloatVid : to_bytes::IterBytes {
+    pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
+        (*self).iter_bytes(lsb0, f)
+    }
+}
+
 impl FnVid : to_bytes::IterBytes {
     pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
         (*self).iter_bytes(lsb0, f)
@@ -1030,6 +1049,10 @@ fn mk_u32(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u32)) }
 
 fn mk_u64(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u64)) }
 
+fn mk_f32(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f32)) }
+
+fn mk_f64(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f64)) }
+
 fn mk_mach_int(cx: ctxt, tm: ast::int_ty) -> t { mk_t(cx, ty_int(tm)) }
 
 fn mk_mach_uint(cx: ctxt, tm: ast::uint_ty) -> t { mk_t(cx, ty_uint(tm)) }
@@ -1110,9 +1133,9 @@ fn mk_class(cx: ctxt, class_id: ast::def_id, +substs: substs) -> t {
 
 fn mk_var(cx: ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) }
 
-fn mk_int_var(cx: ctxt, v: IntVid) -> t {
-    mk_infer(cx, IntVar(v))
-}
+fn mk_int_var(cx: ctxt, v: IntVid) -> t { mk_infer(cx, IntVar(v)) }
+
+fn mk_float_var(cx: ctxt, v: FloatVid) -> t { mk_infer(cx, FloatVar(v)) }
 
 fn mk_infer(cx: ctxt, it: InferTy) -> t { mk_t(cx, ty_infer(it)) }
 
@@ -1661,7 +1684,8 @@ fn get_element_type(ty: t, i: uint) -> t {
 pure fn type_is_scalar(ty: t) -> bool {
     match get(ty).sty {
       ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
-      ty_infer(IntVar(_)) | ty_type | ty_ptr(_) => true,
+      ty_infer(IntVar(_)) | ty_infer(FloatVar(_)) | ty_type |
+      ty_ptr(_) => true,
       _ => false
     }
 }
@@ -2428,7 +2452,7 @@ fn type_is_integral(ty: t) -> bool {
 
 fn type_is_fp(ty: t) -> bool {
     match get(ty).sty {
-      ty_float(_) => true,
+      ty_infer(FloatVar(_)) | ty_float(_) => true,
       _ => false
     }
 }
@@ -3260,6 +3284,7 @@ fn ty_sort_str(cx: ctxt, t: t) -> ~str {
       ty_tup(_) => ~"tuple",
       ty_infer(TyVar(_)) => ~"inferred type",
       ty_infer(IntVar(_)) => ~"integral variable",
+      ty_infer(FloatVar(_)) => ~"floating-point variable",
       ty_param(_) => ~"type parameter",
       ty_self => ~"self"
     }
@@ -3387,6 +3412,10 @@ fn to_str(s: ast::ret_style) -> ~str {
             ~"couldn't determine an appropriate integral type for integer \
               literal"
         }
+        terr_no_floating_point_type => {
+            ~"couldn't determine an appropriate floating point type for \
+              floating point literal"
+        }
     }
 }
 
@@ -4000,7 +4029,7 @@ fn tycat(ty: t) -> int {
         match get(ty).sty {
           ty_bool => tycat_bool,
           ty_int(_) | ty_uint(_) | ty_infer(IntVar(_)) => tycat_int,
-          ty_float(_) => tycat_float,
+          ty_float(_) | ty_infer(FloatVar(_)) => tycat_float,
           ty_rec(_) | ty_tup(_) | ty_enum(_, _) => tycat_struct,
           ty_bot => tycat_bot,
           _ => tycat_other
@@ -4230,6 +4259,11 @@ impl IntVid : cmp::Eq {
     pure fn ne(other: &IntVid) -> bool { *self != *(*other) }
 }
 
+impl FloatVid : cmp::Eq {
+    pure fn eq(other: &FloatVid) -> bool { *self == *(*other) }
+    pure fn ne(other: &FloatVid) -> bool { *self != *(*other) }
+}
+
 impl FnVid : cmp::Eq {
     pure fn eq(other: &FnVid) -> bool { *self == *(*other) }
     pure fn ne(other: &FnVid) -> bool { *self != *(*other) }
index d9ab7306ac3aa0de2dafdb2d141dbc9d25cc8e75..3f96f5af1a1a3fac2c16d43a178314e63e519680 100644 (file)
@@ -850,6 +850,11 @@ fn check_lit(fcx: @fn_ctxt, lit: @ast::lit) -> ty::t {
         ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
       }
       ast::lit_float(_, t) => ty::mk_mach_float(tcx, t),
+      ast::lit_float_unsuffixed(_) => {
+        // An unsuffixed floating point literal could have any floating point
+        // type, so we create a floating point type variable for it.
+        ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
+      }
       ast::lit_nil => ty::mk_nil(tcx),
       ast::lit_bool(_) => ty::mk_bool(tcx)
     }
index 8afd28a5914683ab7f6db9c303235d9e5d6138b0..ae6d7cd40e824168a80c190b5594dc71ad0c5d7c 100644 (file)
@@ -664,6 +664,7 @@ fn search_for_autoptrd_method(
         match ty::get(self_ty).sty {
             ty_box(*) | ty_uniq(*) | ty_rptr(*) |
             ty_infer(IntVar(_)) | // FIXME(#3211)---should be resolved
+            ty_infer(FloatVar(_)) | // FIXME(#3211)---should be resolved
             ty_self | ty_param(*) | ty_nil | ty_bot | ty_bool |
             ty_int(*) | ty_uint(*) |
             ty_float(*) | ty_enum(*) | ty_ptr(*) | ty_rec(*) |
index 61dc10ee09e05d935cb46e335a1b2e78414df29e..edb6452ab50e4300e01491693478a9ded1375d11 100644 (file)
@@ -209,6 +209,8 @@ fn bar() {
 which type variables must be resolved and an integral type variable is
 still underconstrained, it defaults to `int` as a last resort.
 
+Floating point types are handled similarly to integral types.
+
 ## GLB/LUB
 
 Computing the greatest-lower-bound and least-upper-bound of two
@@ -250,8 +252,8 @@ fn bar() {
 use std::smallintmap::smallintmap;
 use std::map::HashMap;
 use middle::ty;
-use middle::ty::{TyVid, IntVid, RegionVid, vid,
-                 ty_int, ty_uint, get, terr_fn, TyVar, IntVar};
+use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, vid,
+                 ty_int, ty_uint, get, terr_fn, TyVar, IntVar, FloatVar};
 use syntax::{ast, ast_util};
 use syntax::ast::{ret_style, purity};
 use util::ppaux::{ty_to_str, mt_to_str};
@@ -272,6 +274,7 @@ fn bar() {
                  resolve_and_force_all_but_regions, resolver};
 use unify::{vals_and_bindings, root};
 use integral::{int_ty_set, int_ty_set_all};
+use floating::{float_ty_set, float_ty_set_all};
 use combine::{combine_fields, eq_tys};
 use assignment::Assign;
 use to_str::ToStr;
@@ -318,12 +321,17 @@ enum infer_ctxt = @{
     // represented by an int_ty_set.
     int_var_bindings: vals_and_bindings<ty::IntVid, int_ty_set>,
 
+    // The types that might instantiate a floating-point type variable are
+    // represented by an float_ty_set.
+    float_var_bindings: vals_and_bindings<ty::FloatVid, float_ty_set>,
+
     // For region variables.
     region_vars: RegionVarBindings,
 
     // For keeping track of existing type and region variables.
     ty_var_counter: @mut uint,
     int_var_counter: @mut uint,
+    float_var_counter: @mut uint,
     region_var_counter: @mut uint
 };
 
@@ -359,9 +367,11 @@ fn new_infer_ctxt(tcx: ty::ctxt) -> infer_ctxt {
     infer_ctxt(@{tcx: tcx,
                  ty_var_bindings: new_vals_and_bindings(),
                  int_var_bindings: new_vals_and_bindings(),
+                 float_var_bindings: new_vals_and_bindings(),
                  region_vars: RegionVarBindings(tcx),
                  ty_var_counter: @mut 0u,
                  int_var_counter: @mut 0u,
+                 float_var_counter: @mut 0u,
                  region_var_counter: @mut 0u})}
 
 fn mk_subty(cx: infer_ctxt, a_is_expected: bool, span: span,
@@ -627,6 +637,18 @@ fn next_int_var() -> ty::t {
         ty::mk_int_var(self.tcx, self.next_int_var_id())
     }
 
+    fn next_float_var_id() -> FloatVid {
+        let id = *self.float_var_counter;
+        *self.float_var_counter += 1;
+
+        self.float_var_bindings.vals.insert(id, root(float_ty_set_all(), 0));
+        return FloatVid(id);
+    }
+
+    fn next_float_var() -> ty::t {
+        ty::mk_float_var(self.tcx, self.next_float_var_id())
+    }
+
     fn next_region_var_nb(span: span) -> ty::Region {
         ty::re_infer(ty::ReVar(self.region_vars.new_region_var(span)))
     }
index c43f1e9c3865ca36582426c8293904d793ead5f9..099b0469bcf90de60012437ab91edf1406866d28 100644 (file)
@@ -385,6 +385,17 @@ fn super_tys<C:combine>(
         self.infcx().t_sub_int_var(a, b_id).then(|| Ok(a) )
       }
 
+      // Relate floating-point variables to other types
+      (ty::ty_infer(FloatVar(a_id)), ty::ty_infer(FloatVar(b_id))) => {
+        self.infcx().float_vars(a_id, b_id).then(|| Ok(a) )
+      }
+      (ty::ty_infer(FloatVar(a_id)), ty::ty_float(_)) => {
+        self.infcx().float_var_sub_t(a_id, b).then(|| Ok(a) )
+      }
+      (ty::ty_float(_), ty::ty_infer(FloatVar(b_id))) => {
+        self.infcx().t_sub_float_var(a, b_id).then(|| Ok(a) )
+      }
+
       (ty::ty_int(_), _) |
       (ty::ty_uint(_), _) |
       (ty::ty_float(_), _) => {
diff --git a/src/librustc/middle/typeck/infer/floating.rs b/src/librustc/middle/typeck/infer/floating.rs
new file mode 100644 (file)
index 0000000..1f21580
--- /dev/null
@@ -0,0 +1,48 @@
+/*!
+
+Code related to floating-point type inference.
+
+*/
+
+use to_str::ToStr;
+use middle::ty::ty_float;
+
+// Bitvector to represent sets of floating-point types.
+pub enum float_ty_set = uint;
+
+// Constants representing singleton sets containing each of the floating-point
+// types.
+pub const FLOAT_TY_SET_EMPTY: uint = 0b000u;
+pub const FLOAT_TY_SET_FLOAT: uint = 0b001u;
+pub const FLOAT_TY_SET_F32:   uint = 0b010u;
+pub const FLOAT_TY_SET_F64:   uint = 0b100u;
+
+pub fn float_ty_set_all() -> float_ty_set {
+    float_ty_set(FLOAT_TY_SET_FLOAT | FLOAT_TY_SET_F32 | FLOAT_TY_SET_F64)
+}
+
+pub fn intersection(a: float_ty_set, b: float_ty_set) -> float_ty_set {
+    float_ty_set(*a & *b)
+}
+
+pub fn single_type_contained_in(tcx: ty::ctxt, a: float_ty_set)
+                             -> Option<ty::t> {
+    debug!("single_type_contained_in(a=%s)", uint::to_str(*a, 10));
+
+    if *a == FLOAT_TY_SET_FLOAT { return Some(ty::mk_float(tcx)); }
+    if *a == FLOAT_TY_SET_F32   { return Some(ty::mk_f32(tcx));   }
+    if *a == FLOAT_TY_SET_F64   { return Some(ty::mk_f64(tcx));   }
+    return None;
+}
+
+pub fn convert_floating_point_ty_to_float_ty_set(tcx: ty::ctxt, t: ty::t)
+                                              -> float_ty_set {
+    match get(t).sty {
+        ty::ty_float(ast::ty_f)     => float_ty_set(FLOAT_TY_SET_FLOAT),
+        ty::ty_float(ast::ty_f32)   => float_ty_set(FLOAT_TY_SET_F32),
+        ty::ty_float(ast::ty_f64)   => float_ty_set(FLOAT_TY_SET_F64),
+        _ => tcx.sess.bug(~"non-floating-point type passed to \
+                            convert_floating_point_ty_to_float_ty_set()")
+    }
+}
+
index f0794bf752e98d0aa0acce3a6a4eacdfde42adbe..956ab9998dea0e431372841426c3c473c80308b6 100644 (file)
 // `resolve_nested_tvar` is passed, we will then go and recursively
 // resolve `<T1>`.
 //
-// The options `resolve_rvar` and `resolve_ivar` control whether we
-// resolve region and integral variables, respectively.
+// The options `resolve_rvar` controls whether we resolve region
+// variables. The options `resolve_fvar` and `resolve_ivar` control
+// whether we resolve floating point and integral variables,
+// respectively.
 //
 // # What do if things are unconstrained
 //
 // probably better off writing `resolve_all - resolve_ivar`.
 
 use integral::*;
+use floating::*;
 use to_str::ToStr;
 
 const resolve_nested_tvar: uint = 0b00000001;
 const resolve_rvar: uint        = 0b00000010;
 const resolve_ivar: uint        = 0b00000100;
-const resolve_all: uint         = 0b00000111;
+const resolve_fvar: uint        = 0b00001000;
+const resolve_all: uint         = 0b00001111;
 const force_tvar: uint          = 0b00010000;
 const force_rvar: uint          = 0b00100000;
 const force_ivar: uint          = 0b01000000;
-const force_all: uint           = 0b01110000;
+const force_fvar: uint          = 0b11000000;
+const force_all: uint           = 0b11110000;
 
 const not_regions: uint         = !(force_rvar | resolve_rvar);
 
@@ -119,6 +124,9 @@ fn resolve_type(typ: ty::t) -> ty::t {
               ty::ty_infer(IntVar(vid)) => {
                 self.resolve_int_var(vid)
               }
+              ty::ty_infer(FloatVar(vid)) => {
+                self.resolve_float_var(vid)
+              }
               _ => {
                 if !self.should(resolve_rvar) &&
                     !self.should(resolve_nested_tvar) {
@@ -212,7 +220,7 @@ fn resolve_int_var(vid: IntVid) -> ty::t {
 
         // If there's only one type in the set of possible types, then
         // that's the answer.
-        match single_type_contained_in(self.infcx.tcx, pt) {
+        match integral::single_type_contained_in(self.infcx.tcx, pt) {
           Some(t) => t,
           None => {
             if self.should(force_ivar) {
@@ -230,5 +238,36 @@ fn resolve_int_var(vid: IntVid) -> ty::t {
           }
         }
     }
+
+    fn resolve_float_var(vid: FloatVid) -> ty::t {
+        if !self.should(resolve_fvar) {
+            return ty::mk_float_var(self.infcx.tcx, vid);
+        }
+
+        let nde = self.infcx.get(&self.infcx.float_var_bindings, vid);
+        let pt = nde.possible_types;
+
+        // If there's only one type in the set of possible types, then
+        // that's the answer.
+        match floating::single_type_contained_in(self.infcx.tcx, pt) {
+          Some(t) => t,
+          None => {
+            if self.should(force_fvar) {
+                // As a last resort, default to float.
+                let ty = ty::mk_float(self.infcx.tcx);
+                self.infcx.set(
+                    &self.infcx.float_var_bindings,
+                    vid,
+                    root(
+                        convert_floating_point_ty_to_float_ty_set(
+                            self.infcx.tcx, ty),
+                        nde.rank));
+                ty
+            } else {
+                ty::mk_float_var(self.infcx.tcx, vid)
+            }
+          }
+        }
+    }
 }
 
index 3c9b22ff66f4ddf42f3f00a5efdfe67665f0ff68..73eef376b1ed29615c63815d9bf4e45e997fe95a 100644 (file)
@@ -1,4 +1,5 @@
 use integral::{int_ty_set};
+use floating::{float_ty_set};
 use unify::{var_value, redirect, root};
 
 trait ToStr {
@@ -54,6 +55,14 @@ fn to_str(_cx: infer_ctxt) -> ~str {
     }
 }
 
+impl float_ty_set: ToStr {
+    fn to_str(_cx: infer_ctxt) -> ~str {
+        match self {
+          float_ty_set(v) => uint::to_str(v, 10u)
+        }
+    }
+}
+
 impl<V:Copy vid, T:Copy ToStr> var_value<V, T>: ToStr {
     fn to_str(cx: infer_ctxt) -> ~str {
         match self {
index f865705563c60e3fac6d46ba4caf703f8e82ae7b..88827849fa60845cf79d579a0c187297ad1aff74 100644 (file)
@@ -1,5 +1,6 @@
 use combine::combine;
 use integral::*;
+use floating::*;
 use to_str::ToStr;
 use std::smallintmap::SmallIntMap;
 
@@ -294,6 +295,34 @@ fn bnds<C: combine>(
 // Integral variables
 
 impl infer_ctxt {
+    fn optimize_ranks<V:Copy vid Eq,T:Copy ToStr>(vb: &vals_and_bindings<V,T>,
+                                                  nde_a: node<V,T>,
+                                                  nde_b: node<V,T>,
+                                                  a_id: V,
+                                                  b_id: V,
+                                                  intersection: T) {
+        if nde_a.rank > nde_b.rank {
+            debug!("int_vars(): a has smaller rank");
+            // a has greater rank, so a should become b's parent,
+            // i.e., b should redirect to a.
+            self.set(vb, a_id, root(intersection, nde_a.rank));
+            self.set(vb, b_id, redirect(a_id));
+        } else if nde_a.rank < nde_b.rank {
+            debug!("int_vars(): b has smaller rank");
+            // b has greater rank, so a should redirect to b.
+            self.set(vb, b_id, root(intersection, nde_b.rank));
+            self.set(vb, a_id, redirect(b_id));
+        } else {
+            debug!("int_vars(): a and b have equal rank");
+            assert nde_a.rank == nde_b.rank;
+            // If equal, just redirect one to the other and increment
+            // the other's rank.  We choose arbitrarily to redirect b
+            // to a and increment a's rank.
+            self.set(vb, a_id, root(intersection, nde_a.rank + 1u));
+            self.set(vb, b_id, redirect(a_id));
+        };
+    }
+
     fn int_vars(a_id: ty::IntVid, b_id: ty::IntVid) -> ures {
         let vb = &self.int_var_bindings;
 
@@ -310,32 +339,13 @@ fn int_vars(a_id: ty::IntVid, b_id: ty::IntVid) -> ures {
 
         // Otherwise, take the intersection of the two sets of
         // possible types.
-        let intersection = intersection(a_pt, b_pt);
+        let intersection = integral::intersection(a_pt, b_pt);
         if *intersection == INT_TY_SET_EMPTY {
             return Err(ty::terr_no_integral_type);
         }
 
         // Rank optimization
-        if nde_a.rank > nde_b.rank {
-            debug!("int_vars(): a has smaller rank");
-            // a has greater rank, so a should become b's parent,
-            // i.e., b should redirect to a.
-            self.set(vb, a_id, root(intersection, nde_a.rank));
-            self.set(vb, b_id, redirect(a_id));
-        } else if nde_a.rank < nde_b.rank {
-            debug!("int_vars(): b has smaller rank");
-            // b has greater rank, so a should redirect to b.
-            self.set(vb, b_id, root(intersection, nde_b.rank));
-            self.set(vb, a_id, redirect(b_id));
-        } else {
-            debug!("int_vars(): a and b have equal rank");
-            assert nde_a.rank == nde_b.rank;
-            // If equal, just redirect one to the other and increment
-            // the other's rank.  We choose arbitrarily to redirect b
-            // to a and increment a's rank.
-            self.set(vb, a_id, root(intersection, nde_a.rank + 1u));
-            self.set(vb, b_id, redirect(a_id));
-        };
+        self.optimize_ranks(vb, nde_a, nde_b, a_id, b_id, intersection);
 
         uok()
     }
@@ -349,7 +359,7 @@ fn int_var_sub_t(a_id: ty::IntVid, b: ty::t) -> ures {
         let a_pt = nde_a.possible_types;
 
         let intersection =
-            intersection(a_pt,
+            integral::intersection(a_pt,
                          convert_integral_ty_to_int_ty_set(self.tcx, b));
         if *intersection == INT_TY_SET_EMPTY {
             return Err(ty::terr_no_integral_type);
@@ -367,7 +377,7 @@ fn t_sub_int_var(a: ty::t, b_id: ty::IntVid) -> ures {
         let b_pt = nde_b.possible_types;
 
         let intersection =
-            intersection(b_pt,
+            integral::intersection(b_pt,
                          convert_integral_ty_to_int_ty_set(self.tcx, a));
         if *intersection == INT_TY_SET_EMPTY {
             return Err(ty::terr_no_integral_type);
@@ -378,3 +388,74 @@ fn t_sub_int_var(a: ty::t, b_id: ty::IntVid) -> ures {
 
 
 }
+
+// ______________________________________________________________________
+// Floating point variables
+
+impl infer_ctxt {
+    fn float_vars(a_id: ty::FloatVid, b_id: ty::FloatVid) -> ures {
+        let vb = &self.float_var_bindings;
+
+        let nde_a = self.get(vb, a_id);
+        let nde_b = self.get(vb, b_id);
+        let a_id = nde_a.root;
+        let b_id = nde_b.root;
+        let a_pt = nde_a.possible_types;
+        let b_pt = nde_b.possible_types;
+
+        // If we're already dealing with the same two variables,
+        // there's nothing to do.
+        if a_id == b_id { return uok(); }
+
+        // Otherwise, take the intersection of the two sets of
+        // possible types.
+        let intersection = floating::intersection(a_pt, b_pt);
+        if *intersection == FLOAT_TY_SET_EMPTY {
+            return Err(ty::terr_no_floating_point_type);
+        }
+
+        // Rank optimization
+        self.optimize_ranks(vb, nde_a, nde_b, a_id, b_id, intersection);
+
+        uok()
+    }
+
+    fn float_var_sub_t(a_id: ty::FloatVid, b: ty::t) -> ures {
+        assert ty::type_is_fp(b);
+
+        let vb = &self.float_var_bindings;
+        let nde_a = self.get(vb, a_id);
+        let a_id = nde_a.root;
+        let a_pt = nde_a.possible_types;
+
+        let intersection =
+            floating::intersection(
+                a_pt,
+                convert_floating_point_ty_to_float_ty_set(self.tcx, b));
+        if *intersection == FLOAT_TY_SET_EMPTY {
+            return Err(ty::terr_no_floating_point_type);
+        }
+        self.set(vb, a_id, root(intersection, nde_a.rank));
+        uok()
+    }
+
+    fn t_sub_float_var(a: ty::t, b_id: ty::FloatVid) -> ures {
+        assert ty::type_is_fp(a);
+        let vb = &self.float_var_bindings;
+
+        let nde_b = self.get(vb, b_id);
+        let b_id = nde_b.root;
+        let b_pt = nde_b.possible_types;
+
+        let intersection =
+            floating::intersection(
+                b_pt,
+                convert_floating_point_ty_to_float_ty_set(self.tcx, a));
+        if *intersection == FLOAT_TY_SET_EMPTY {
+            return Err(ty::terr_no_floating_point_type);
+        }
+        self.set(vb, b_id, root(intersection, nde_b.rank));
+        uok()
+    }
+}
+
index 0e6f6536bf57e7ca00bfe5afb96711d3901699fd..0dd9ae7217f478641fd65049f5633891a7d6cbed 100644 (file)
@@ -128,6 +128,7 @@ mod middle {
             mod glb;
             #[legacy_exports]
             mod integral;
+            mod floating;
             #[legacy_exports]
             mod lattice;
             #[legacy_exports]
index 7452e41fac33760be7dfb070b0c044496a4ee002..dd90dfee683da74f571e65f42478734187e09c5e 100644 (file)
@@ -862,6 +862,7 @@ enum lit_ {
     lit_uint(u64, uint_ty),
     lit_int_unsuffixed(i64),
     lit_float(@~str, float_ty),
+    lit_float_unsuffixed(@~str),
     lit_nil,
     lit_bool(bool),
 }
@@ -880,6 +881,7 @@ impl ast::lit_: cmp::Eq {
             (lit_float(val_a, ty_a), lit_float(val_b, ty_b)) => {
                 val_a == val_b && ty_a == ty_b
             }
+            (lit_float_unsuffixed(a), lit_float_unsuffixed(b)) => a == b,
             (lit_nil, lit_nil) => true,
             (lit_bool(a), lit_bool(b)) => a == b,
             (lit_str(_), _) => false,
@@ -887,6 +889,7 @@ impl ast::lit_: cmp::Eq {
             (lit_uint(*), _) => false,
             (lit_int_unsuffixed(*), _) => false,
             (lit_float(*), _) => false,
+            (lit_float_unsuffixed(*), _) => false,
             (lit_nil, _) => false,
             (lit_bool(_), _) => false
         }
index 8f57d733eb51f9421e6d86a7309268caf0e2d0dc..482813f3fd02e14c6e09b09d38137f6793d77c8d 100644 (file)
@@ -385,6 +385,8 @@ fn scan_number(c: char, rdr: string_reader) -> token::Token {
       }
       None => ()
     }
+
+    let mut is_machine_float = false;
     if rdr.curr == 'f' {
         bump(rdr);
         c = rdr.curr;
@@ -404,10 +406,14 @@ fn scan_number(c: char, rdr: string_reader) -> token::Token {
             back-end.  */
         } else {
             is_float = true;
+            is_machine_float = true;
         }
     }
     if is_float {
-        return token::LIT_FLOAT(rdr.interner.intern(@num_str), ast::ty_f);
+        if is_machine_float {
+            return token::LIT_FLOAT(rdr.interner.intern(@num_str), ast::ty_f);
+        }
+        return token::LIT_FLOAT_UNSUFFIXED(rdr.interner.intern(@num_str));
     } else {
         if str::len(num_str) == 0u {
             rdr.fatal(~"no valid digits found for number");
index 2b42dcc0ed06af8fc93378950e17a286c61f481f..f1f49c63a7d69110af66e85a5e3260a35f33988f 100644 (file)
@@ -43,9 +43,9 @@
              ident, impure_fn, infer, inherited,
              item, item_, item_class, item_const, item_enum, item_fn,
              item_foreign_mod, item_impl, item_mac, item_mod, item_trait,
-             item_ty, lit, lit_, lit_bool, lit_float, lit_int,
-             lit_int_unsuffixed, lit_nil, lit_str, lit_uint, local, m_const,
-             m_imm, m_mutbl, mac_, mac_aq, mac_ellipsis, mac_invoc,
+             item_ty, lit, lit_, lit_bool, lit_float, lit_float_unsuffixed,
+             lit_int, lit_int_unsuffixed, lit_nil, lit_str, lit_uint, local,
+             m_const, m_imm, m_mutbl, mac_, mac_aq, mac_ellipsis, mac_invoc,
              mac_invoc_tt, mac_var, matcher, match_nonterminal, match_seq,
              match_tok, method, mode, module_ns, mt, mul, mutability,
              named_field, neg, noreturn, not, pat, pat_box, pat_enum,
@@ -787,6 +787,8 @@ fn lit_from_token(tok: token::Token) -> lit_ {
           token::LIT_UINT(u, ut) => lit_uint(u, ut),
           token::LIT_INT_UNSUFFIXED(i) => lit_int_unsuffixed(i),
           token::LIT_FLOAT(s, ft) => lit_float(self.id_to_str(s), ft),
+          token::LIT_FLOAT_UNSUFFIXED(s) =>
+            lit_float_unsuffixed(self.id_to_str(s)),
           token::LIT_STR(s) => lit_str(self.id_to_str(s)),
           token::LPAREN => { self.expect(token::RPAREN); lit_nil },
           _ => { self.unexpected_last(tok); }
index 0d139b101d8f385572e10891cdb66c738786314d..baf963942e2b8c0eb77b6016da24889bddc32eb6 100644 (file)
@@ -62,6 +62,7 @@ enum Token {
     LIT_UINT(u64, ast::uint_ty),
     LIT_INT_UNSUFFIXED(i64),
     LIT_FLOAT(ast::ident, ast::float_ty),
+    LIT_FLOAT_UNSUFFIXED(ast::ident),
     LIT_STR(ast::ident),
 
     /* Name components */
@@ -164,6 +165,13 @@ fn to_str(in: @ident_interner, t: Token) -> ~str {
         }
         body + ast_util::float_ty_to_str(t)
       }
+      LIT_FLOAT_UNSUFFIXED(s) => {
+        let mut body = *in.get(s);
+        if body.ends_with(~".") {
+            body = body + ~"0";  // `10.f` is not a float literal
+        }
+        body
+      }
       LIT_STR(s) => { ~"\"" + str::escape_default(*in.get(s)) + ~"\"" }
 
       /* Name components */
@@ -204,6 +212,7 @@ fn to_str(in: @ident_interner, t: Token) -> ~str {
       LIT_UINT(_, _) => true,
       LIT_INT_UNSUFFIXED(_) => true,
       LIT_FLOAT(_, _) => true,
+      LIT_FLOAT_UNSUFFIXED(_) => true,
       LIT_STR(_) => true,
       POUND => true,
       AT => true,
@@ -243,6 +252,7 @@ fn is_lit(t: Token) -> bool {
       LIT_UINT(_, _) => true,
       LIT_INT_UNSUFFIXED(_) => true,
       LIT_FLOAT(_, _) => true,
+      LIT_FLOAT_UNSUFFIXED(_) => true,
       LIT_STR(_) => true,
       _ => false
     }
@@ -684,6 +694,12 @@ impl Token : cmp::Eq {
                     _ => false
                 }
             }
+            LIT_FLOAT_UNSUFFIXED(e0a) => {
+                match (*other) {
+                    LIT_FLOAT_UNSUFFIXED(e0b) => e0a == e0b,
+                    _ => false
+                }
+            }
             LIT_STR(e0a) => {
                 match (*other) {
                     LIT_STR(e0b) => e0a == e0b,
index 0418f6776de6b8861b7e43665cb0c059997a9c42..54ed5085435d8daca33d183c4c32da6571879c36 100644 (file)
@@ -1970,6 +1970,7 @@ fn print_literal(s: ps, &&lit: @ast::lit) {
       ast::lit_float(f, t) => {
         word(s.s, *f + ast_util::float_ty_to_str(t));
       }
+      ast::lit_float_unsuffixed(f) => word(s.s, *f),
       ast::lit_nil => word(s.s, ~"()"),
       ast::lit_bool(val) => {
         if val { word(s.s, ~"true"); } else { word(s.s, ~"false"); }
diff --git a/src/test/compile-fail/float-literal-inference-restrictions.rs b/src/test/compile-fail/float-literal-inference-restrictions.rs
new file mode 100644 (file)
index 0000000..e272b19
--- /dev/null
@@ -0,0 +1,5 @@
+fn main() {
+    let x: f32 = 1; //~ ERROR mismatched types
+    let y: f32 = 1f; //~ ERROR mismatched types
+}
+
diff --git a/src/test/run-pass/float-literal-inference.rs b/src/test/run-pass/float-literal-inference.rs
new file mode 100644 (file)
index 0000000..f930537
--- /dev/null
@@ -0,0 +1,13 @@
+struct S {
+    z: f64
+}
+
+fn main() {
+    let x: f32 = 4.0;
+    io::println(x.to_str());
+    let y: float = 64.0;
+    io::println(y.to_str());
+    let z = S { z: 1.0 };
+    io::println(z.z.to_str());
+}
+