diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 4129066ff286..922fff18e9e5 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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)); diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 3e30bf50e023..cbe5430b5be4 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -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) } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 23ec0b6a9c18..6796d139bc76 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -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) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 52f05eb44de0..e7cf5fa8ad8a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -21,7 +21,7 @@ use util::ppaux::{ty_to_str, proto_ty_to_str, tys_to_str}; 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, FnTy, FnTyBase, FnMeta, FnSig, mk_fn; 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; @@ -102,8 +103,8 @@ export ty_tup, mk_tup; 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; @@ -172,7 +173,8 @@ export ty_sort_str; 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), 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 RegionVid = uint; 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!("", self.to_uint()) } } +impl FloatVid: vid { + pure fn to_uint() -> uint { *self } + pure fn to_str() -> ~str { fmt!("", self.to_uint()) } +} + impl FnVid: vid { pure fn to_uint() -> uint { *self } pure fn to_str() -> ~str { fmt!("", 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 @@ pure fn type_is_unique(ty: t) -> bool { 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 type_err_to_str(cx: ctxt, err: &type_err) -> ~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 is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool { 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) } diff --git a/src/librustc/middle/typeck/check.rs b/src/librustc/middle/typeck/check.rs index d9ab7306ac3a..3f96f5af1a1a 100644 --- a/src/librustc/middle/typeck/check.rs +++ b/src/librustc/middle/typeck/check.rs @@ -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) } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 8afd28a59146..ae6d7cd40e82 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -664,6 +664,7 @@ impl LookupContext { 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(*) | diff --git a/src/librustc/middle/typeck/infer.rs b/src/librustc/middle/typeck/infer.rs index 61dc10ee09e0..edb6452ab50e 100644 --- a/src/librustc/middle/typeck/infer.rs +++ b/src/librustc/middle/typeck/infer.rs @@ -209,6 +209,8 @@ overconstrains the type, it's a type error; if we reach the point at 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 @@ use std::smallintmap; 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 @@ use resolve::{resolve_nested_tvar, resolve_rvar, resolve_ivar, resolve_all, 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, + // The types that might instantiate a floating-point type variable are + // represented by an float_ty_set. + float_var_bindings: vals_and_bindings, + // 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 @@ impl infer_ctxt { 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))) } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index c43f1e9c3865..099b0469bcf9 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -385,6 +385,17 @@ fn super_tys( 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 index 000000000000..1f2158090533 --- /dev/null +++ b/src/librustc/middle/typeck/infer/floating.rs @@ -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 { + 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()") + } +} + diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index f0794bf752e9..956ab9998dea 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -15,8 +15,10 @@ // `resolve_nested_tvar` is passed, we will then go and recursively // resolve ``. // -// 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 // @@ -35,16 +37,19 @@ // 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 @@ impl resolve_state { 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 @@ impl resolve_state { // 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 @@ impl resolve_state { } } } + + 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) + } + } + } + } } diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs index 3c9b22ff66f4..73eef376b1ed 100644 --- a/src/librustc/middle/typeck/infer/to_str.rs +++ b/src/librustc/middle/typeck/infer/to_str.rs @@ -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 @@ impl int_ty_set: ToStr { } } +impl float_ty_set: ToStr { + fn to_str(_cx: infer_ctxt) -> ~str { + match self { + float_ty_set(v) => uint::to_str(v, 10u) + } + } +} + impl var_value: ToStr { fn to_str(cx: infer_ctxt) -> ~str { match self { diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index f865705563c6..88827849fa60 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -1,5 +1,6 @@ use combine::combine; use integral::*; +use floating::*; use to_str::ToStr; use std::smallintmap::SmallIntMap; @@ -294,28 +295,12 @@ fn bnds( // Integral variables impl infer_ctxt { - fn int_vars(a_id: ty::IntVid, b_id: ty::IntVid) -> ures { - let vb = &self.int_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 = intersection(a_pt, b_pt); - if *intersection == INT_TY_SET_EMPTY { - return Err(ty::terr_no_integral_type); - } - - // Rank optimization + fn optimize_ranks(vb: &vals_and_bindings, + nde_a: node, + nde_b: node, + 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, @@ -336,6 +321,31 @@ impl infer_ctxt { 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; + + 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 = integral::intersection(a_pt, b_pt); + if *intersection == INT_TY_SET_EMPTY { + return Err(ty::terr_no_integral_type); + } + + // Rank optimization + self.optimize_ranks(vb, nde_a, nde_b, a_id, b_id, intersection); uok() } @@ -349,7 +359,7 @@ impl infer_ctxt { 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 @@ impl infer_ctxt { 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 @@ impl infer_ctxt { } + +// ______________________________________________________________________ +// 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() + } +} + diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 0e6f6536bf57..0dd9ae7217f4 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -128,6 +128,7 @@ mod middle { mod glb; #[legacy_exports] mod integral; + mod floating; #[legacy_exports] mod lattice; #[legacy_exports] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7452e41fac33..dd90dfee683d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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 } diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 8f57d733eb51..482813f3fd02 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -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"); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2b42dcc0ed06..f1f49c63a7d6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,9 +43,9 @@ use ast::{_mod, add, arg, arm, attribute, 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 @@ impl Parser { 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); } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 0d139b101d8f..baf963942e2b 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -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 @@ pure fn can_begin_expr(t: Token) -> bool { 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, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0418f6776de6..54ed5085435d 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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 index 000000000000..e272b194fe1d --- /dev/null +++ b/src/test/compile-fail/float-literal-inference-restrictions.rs @@ -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 index 000000000000..f930537130c7 --- /dev/null +++ b/src/test/run-pass/float-literal-inference.rs @@ -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()); +} +