rustc: Implement floating point literal inference. r=nmatsakis
This commit is contained in:
parent
f05e2da709
commit
fe02814a63
@ -286,6 +286,11 @@ fn enc_sty(w: io::Writer, cx: @ctxt, st: ty::sty) {
|
|||||||
w.write_char('I');
|
w.write_char('I');
|
||||||
w.write_uint(id.to_uint());
|
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}) => {
|
ty::ty_param({idx: id, def_id: did}) => {
|
||||||
w.write_char('p');
|
w.write_char('p');
|
||||||
w.write_str(cx.ds(did));
|
w.write_str(cx.ds(did));
|
||||||
|
@ -389,6 +389,8 @@ fn lit_to_const(lit: @lit) -> const_val {
|
|||||||
lit_uint(n, _) => const_uint(n),
|
lit_uint(n, _) => const_uint(n),
|
||||||
lit_int_unsuffixed(n) => const_int(n),
|
lit_int_unsuffixed(n) => const_int(n),
|
||||||
lit_float(n, _) => const_float(float::from_str(*n).get() as f64),
|
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_nil => const_int(0i64),
|
||||||
lit_bool(b) => const_bool(b)
|
lit_bool(b) => const_bool(b)
|
||||||
}
|
}
|
||||||
|
@ -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(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_bool(b) => C_bool(b),
|
||||||
ast::lit_nil => C_nil(),
|
ast::lit_nil => C_nil(),
|
||||||
ast::lit_str(s) => C_estr_slice(cx, *s)
|
ast::lit_str(s) => C_estr_slice(cx, *s)
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
export ProvidedMethodSource;
|
export ProvidedMethodSource;
|
||||||
export InstantiatedTraitRef;
|
export InstantiatedTraitRef;
|
||||||
export TyVid, IntVid, FnVid, RegionVid, vid;
|
export TyVid, IntVid, FloatVid, FnVid, RegionVid, vid;
|
||||||
export br_hashmap;
|
export br_hashmap;
|
||||||
export is_instantiable;
|
export is_instantiable;
|
||||||
export node_id_to_type;
|
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_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 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_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_estr, mk_estr, type_is_str;
|
||||||
export ty_evec, mk_evec, type_is_vec;
|
export ty_evec, mk_evec, type_is_vec;
|
||||||
export ty_unboxed_vec, mk_unboxed_vec, mk_mut_unboxed_vec;
|
export ty_unboxed_vec, mk_unboxed_vec, mk_mut_unboxed_vec;
|
||||||
@ -102,8 +103,8 @@
|
|||||||
export ty_type, mk_type;
|
export ty_type, mk_type;
|
||||||
export ty_uint, mk_uint, mk_mach_uint;
|
export ty_uint, mk_uint, mk_mach_uint;
|
||||||
export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box;
|
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 ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var, mk_float_var;
|
||||||
export InferTy, TyVar, IntVar;
|
export InferTy, TyVar, IntVar, FloatVar;
|
||||||
export ty_self, mk_self, type_has_self;
|
export ty_self, mk_self, type_has_self;
|
||||||
export ty_class;
|
export ty_class;
|
||||||
export Region, bound_region, encl_region;
|
export Region, bound_region, encl_region;
|
||||||
@ -172,7 +173,8 @@
|
|||||||
export normalize_ty;
|
export normalize_ty;
|
||||||
export to_str;
|
export to_str;
|
||||||
export bound_const;
|
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_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_sorts, terr_vec, terr_str, terr_record_size, terr_tuple_size;
|
||||||
export terr_regions_does_not_outlive, terr_mutability, terr_purity_mismatch;
|
export terr_regions_does_not_outlive, terr_mutability, terr_purity_mismatch;
|
||||||
@ -666,6 +668,7 @@ enum type_err {
|
|||||||
terr_sorts(expected_found<t>),
|
terr_sorts(expected_found<t>),
|
||||||
terr_self_substs,
|
terr_self_substs,
|
||||||
terr_no_integral_type,
|
terr_no_integral_type,
|
||||||
|
terr_no_floating_point_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum param_bound {
|
enum param_bound {
|
||||||
@ -678,6 +681,7 @@ enum param_bound {
|
|||||||
|
|
||||||
enum TyVid = uint;
|
enum TyVid = uint;
|
||||||
enum IntVid = uint;
|
enum IntVid = uint;
|
||||||
|
enum FloatVid = uint;
|
||||||
enum FnVid = uint;
|
enum FnVid = uint;
|
||||||
#[auto_serialize]
|
#[auto_serialize]
|
||||||
#[auto_deserialize]
|
#[auto_deserialize]
|
||||||
@ -685,14 +689,16 @@ enum param_bound {
|
|||||||
|
|
||||||
enum InferTy {
|
enum InferTy {
|
||||||
TyVar(TyVid),
|
TyVar(TyVid),
|
||||||
IntVar(IntVid)
|
IntVar(IntVid),
|
||||||
|
FloatVar(FloatVid)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InferTy : to_bytes::IterBytes {
|
impl InferTy : to_bytes::IterBytes {
|
||||||
pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
|
pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
|
||||||
match self {
|
match self {
|
||||||
TyVar(ref tv) => to_bytes::iter_bytes_2(&0u8, tv, lsb0, f),
|
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()) }
|
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 {
|
impl FnVid: vid {
|
||||||
pure fn to_uint() -> uint { *self }
|
pure fn to_uint() -> uint { *self }
|
||||||
pure fn to_str() -> ~str { fmt!("<F%u>", self.to_uint()) }
|
pure fn to_str() -> ~str { fmt!("<F%u>", self.to_uint()) }
|
||||||
@ -773,6 +784,7 @@ impl InferTy {
|
|||||||
match self {
|
match self {
|
||||||
TyVar(v) => v.to_uint() << 1,
|
TyVar(v) => v.to_uint() << 1,
|
||||||
IntVar(v) => (v.to_uint() << 1) + 1,
|
IntVar(v) => (v.to_uint() << 1) + 1,
|
||||||
|
FloatVar(v) => (v.to_uint() << 1) + 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,6 +792,7 @@ impl InferTy {
|
|||||||
match self {
|
match self {
|
||||||
TyVar(v) => v.to_str(),
|
TyVar(v) => v.to_str(),
|
||||||
IntVar(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 {
|
impl FnVid : to_bytes::IterBytes {
|
||||||
pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
|
pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
|
||||||
(*self).iter_bytes(lsb0, f)
|
(*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_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_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)) }
|
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_var(cx: ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) }
|
||||||
|
|
||||||
fn mk_int_var(cx: ctxt, v: IntVid) -> t {
|
fn mk_int_var(cx: ctxt, v: IntVid) -> t { mk_infer(cx, IntVar(v)) }
|
||||||
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)) }
|
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 {
|
pure fn type_is_scalar(ty: t) -> bool {
|
||||||
match get(ty).sty {
|
match get(ty).sty {
|
||||||
ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
|
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
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2428,7 +2452,7 @@ fn type_is_integral(ty: t) -> bool {
|
|||||||
|
|
||||||
fn type_is_fp(ty: t) -> bool {
|
fn type_is_fp(ty: t) -> bool {
|
||||||
match get(ty).sty {
|
match get(ty).sty {
|
||||||
ty_float(_) => true,
|
ty_infer(FloatVar(_)) | ty_float(_) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3260,6 +3284,7 @@ fn ty_sort_str(cx: ctxt, t: t) -> ~str {
|
|||||||
ty_tup(_) => ~"tuple",
|
ty_tup(_) => ~"tuple",
|
||||||
ty_infer(TyVar(_)) => ~"inferred type",
|
ty_infer(TyVar(_)) => ~"inferred type",
|
||||||
ty_infer(IntVar(_)) => ~"integral variable",
|
ty_infer(IntVar(_)) => ~"integral variable",
|
||||||
|
ty_infer(FloatVar(_)) => ~"floating-point variable",
|
||||||
ty_param(_) => ~"type parameter",
|
ty_param(_) => ~"type parameter",
|
||||||
ty_self => ~"self"
|
ty_self => ~"self"
|
||||||
}
|
}
|
||||||
@ -3387,6 +3412,10 @@ fn to_str(s: ast::ret_style) -> ~str {
|
|||||||
~"couldn't determine an appropriate integral type for integer \
|
~"couldn't determine an appropriate integral type for integer \
|
||||||
literal"
|
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 {
|
match get(ty).sty {
|
||||||
ty_bool => tycat_bool,
|
ty_bool => tycat_bool,
|
||||||
ty_int(_) | ty_uint(_) | ty_infer(IntVar(_)) => tycat_int,
|
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_rec(_) | ty_tup(_) | ty_enum(_, _) => tycat_struct,
|
||||||
ty_bot => tycat_bot,
|
ty_bot => tycat_bot,
|
||||||
_ => tycat_other
|
_ => tycat_other
|
||||||
@ -4230,6 +4259,11 @@ impl IntVid : cmp::Eq {
|
|||||||
pure fn ne(other: &IntVid) -> bool { *self != *(*other) }
|
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 {
|
impl FnVid : cmp::Eq {
|
||||||
pure fn eq(other: &FnVid) -> bool { *self == *(*other) }
|
pure fn eq(other: &FnVid) -> bool { *self == *(*other) }
|
||||||
pure fn ne(other: &FnVid) -> bool { *self != *(*other) }
|
pure fn ne(other: &FnVid) -> bool { *self != *(*other) }
|
||||||
|
@ -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())
|
ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
|
||||||
}
|
}
|
||||||
ast::lit_float(_, t) => ty::mk_mach_float(tcx, t),
|
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_nil => ty::mk_nil(tcx),
|
||||||
ast::lit_bool(_) => ty::mk_bool(tcx)
|
ast::lit_bool(_) => ty::mk_bool(tcx)
|
||||||
}
|
}
|
||||||
|
@ -664,6 +664,7 @@ fn search_for_autoptrd_method(
|
|||||||
match ty::get(self_ty).sty {
|
match ty::get(self_ty).sty {
|
||||||
ty_box(*) | ty_uniq(*) | ty_rptr(*) |
|
ty_box(*) | ty_uniq(*) | ty_rptr(*) |
|
||||||
ty_infer(IntVar(_)) | // FIXME(#3211)---should be resolved
|
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_self | ty_param(*) | ty_nil | ty_bot | ty_bool |
|
||||||
ty_int(*) | ty_uint(*) |
|
ty_int(*) | ty_uint(*) |
|
||||||
ty_float(*) | ty_enum(*) | ty_ptr(*) | ty_rec(*) |
|
ty_float(*) | ty_enum(*) | ty_ptr(*) | ty_rec(*) |
|
||||||
|
@ -209,6 +209,8 @@ fn bar() {
|
|||||||
which type variables must be resolved and an integral type variable is
|
which type variables must be resolved and an integral type variable is
|
||||||
still underconstrained, it defaults to `int` as a last resort.
|
still underconstrained, it defaults to `int` as a last resort.
|
||||||
|
|
||||||
|
Floating point types are handled similarly to integral types.
|
||||||
|
|
||||||
## GLB/LUB
|
## GLB/LUB
|
||||||
|
|
||||||
Computing the greatest-lower-bound and least-upper-bound of two
|
Computing the greatest-lower-bound and least-upper-bound of two
|
||||||
@ -250,8 +252,8 @@ fn bar() {
|
|||||||
use std::smallintmap::smallintmap;
|
use std::smallintmap::smallintmap;
|
||||||
use std::map::HashMap;
|
use std::map::HashMap;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty::{TyVid, IntVid, RegionVid, vid,
|
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, vid,
|
||||||
ty_int, ty_uint, get, terr_fn, TyVar, IntVar};
|
ty_int, ty_uint, get, terr_fn, TyVar, IntVar, FloatVar};
|
||||||
use syntax::{ast, ast_util};
|
use syntax::{ast, ast_util};
|
||||||
use syntax::ast::{ret_style, purity};
|
use syntax::ast::{ret_style, purity};
|
||||||
use util::ppaux::{ty_to_str, mt_to_str};
|
use util::ppaux::{ty_to_str, mt_to_str};
|
||||||
@ -272,6 +274,7 @@ fn bar() {
|
|||||||
resolve_and_force_all_but_regions, resolver};
|
resolve_and_force_all_but_regions, resolver};
|
||||||
use unify::{vals_and_bindings, root};
|
use unify::{vals_and_bindings, root};
|
||||||
use integral::{int_ty_set, int_ty_set_all};
|
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 combine::{combine_fields, eq_tys};
|
||||||
use assignment::Assign;
|
use assignment::Assign;
|
||||||
use to_str::ToStr;
|
use to_str::ToStr;
|
||||||
@ -318,12 +321,17 @@ enum infer_ctxt = @{
|
|||||||
// represented by an int_ty_set.
|
// represented by an int_ty_set.
|
||||||
int_var_bindings: vals_and_bindings<ty::IntVid, 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.
|
// For region variables.
|
||||||
region_vars: RegionVarBindings,
|
region_vars: RegionVarBindings,
|
||||||
|
|
||||||
// For keeping track of existing type and region variables.
|
// For keeping track of existing type and region variables.
|
||||||
ty_var_counter: @mut uint,
|
ty_var_counter: @mut uint,
|
||||||
int_var_counter: @mut uint,
|
int_var_counter: @mut uint,
|
||||||
|
float_var_counter: @mut uint,
|
||||||
region_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,
|
infer_ctxt(@{tcx: tcx,
|
||||||
ty_var_bindings: new_vals_and_bindings(),
|
ty_var_bindings: new_vals_and_bindings(),
|
||||||
int_var_bindings: new_vals_and_bindings(),
|
int_var_bindings: new_vals_and_bindings(),
|
||||||
|
float_var_bindings: new_vals_and_bindings(),
|
||||||
region_vars: RegionVarBindings(tcx),
|
region_vars: RegionVarBindings(tcx),
|
||||||
ty_var_counter: @mut 0u,
|
ty_var_counter: @mut 0u,
|
||||||
int_var_counter: @mut 0u,
|
int_var_counter: @mut 0u,
|
||||||
|
float_var_counter: @mut 0u,
|
||||||
region_var_counter: @mut 0u})}
|
region_var_counter: @mut 0u})}
|
||||||
|
|
||||||
fn mk_subty(cx: infer_ctxt, a_is_expected: bool, span: span,
|
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())
|
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 {
|
fn next_region_var_nb(span: span) -> ty::Region {
|
||||||
ty::re_infer(ty::ReVar(self.region_vars.new_region_var(span)))
|
ty::re_infer(ty::ReVar(self.region_vars.new_region_var(span)))
|
||||||
}
|
}
|
||||||
|
@ -385,6 +385,17 @@ fn super_tys<C:combine>(
|
|||||||
self.infcx().t_sub_int_var(a, b_id).then(|| Ok(a) )
|
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_int(_), _) |
|
||||||
(ty::ty_uint(_), _) |
|
(ty::ty_uint(_), _) |
|
||||||
(ty::ty_float(_), _) => {
|
(ty::ty_float(_), _) => {
|
||||||
|
48
src/librustc/middle/typeck/infer/floating.rs
Normal file
48
src/librustc/middle/typeck/infer/floating.rs
Normal file
@ -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()")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,8 +15,10 @@
|
|||||||
// `resolve_nested_tvar` is passed, we will then go and recursively
|
// `resolve_nested_tvar` is passed, we will then go and recursively
|
||||||
// resolve `<T1>`.
|
// resolve `<T1>`.
|
||||||
//
|
//
|
||||||
// The options `resolve_rvar` and `resolve_ivar` control whether we
|
// The options `resolve_rvar` controls whether we resolve region
|
||||||
// resolve region and integral variables, respectively.
|
// variables. The options `resolve_fvar` and `resolve_ivar` control
|
||||||
|
// whether we resolve floating point and integral variables,
|
||||||
|
// respectively.
|
||||||
//
|
//
|
||||||
// # What do if things are unconstrained
|
// # What do if things are unconstrained
|
||||||
//
|
//
|
||||||
@ -35,16 +37,19 @@
|
|||||||
// probably better off writing `resolve_all - resolve_ivar`.
|
// probably better off writing `resolve_all - resolve_ivar`.
|
||||||
|
|
||||||
use integral::*;
|
use integral::*;
|
||||||
|
use floating::*;
|
||||||
use to_str::ToStr;
|
use to_str::ToStr;
|
||||||
|
|
||||||
const resolve_nested_tvar: uint = 0b00000001;
|
const resolve_nested_tvar: uint = 0b00000001;
|
||||||
const resolve_rvar: uint = 0b00000010;
|
const resolve_rvar: uint = 0b00000010;
|
||||||
const resolve_ivar: uint = 0b00000100;
|
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_tvar: uint = 0b00010000;
|
||||||
const force_rvar: uint = 0b00100000;
|
const force_rvar: uint = 0b00100000;
|
||||||
const force_ivar: uint = 0b01000000;
|
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);
|
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)) => {
|
ty::ty_infer(IntVar(vid)) => {
|
||||||
self.resolve_int_var(vid)
|
self.resolve_int_var(vid)
|
||||||
}
|
}
|
||||||
|
ty::ty_infer(FloatVar(vid)) => {
|
||||||
|
self.resolve_float_var(vid)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if !self.should(resolve_rvar) &&
|
if !self.should(resolve_rvar) &&
|
||||||
!self.should(resolve_nested_tvar) {
|
!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
|
// If there's only one type in the set of possible types, then
|
||||||
// that's the answer.
|
// 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,
|
Some(t) => t,
|
||||||
None => {
|
None => {
|
||||||
if self.should(force_ivar) {
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use integral::{int_ty_set};
|
use integral::{int_ty_set};
|
||||||
|
use floating::{float_ty_set};
|
||||||
use unify::{var_value, redirect, root};
|
use unify::{var_value, redirect, root};
|
||||||
|
|
||||||
trait ToStr {
|
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 {
|
impl<V:Copy vid, T:Copy ToStr> var_value<V, T>: ToStr {
|
||||||
fn to_str(cx: infer_ctxt) -> ~str {
|
fn to_str(cx: infer_ctxt) -> ~str {
|
||||||
match self {
|
match self {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use combine::combine;
|
use combine::combine;
|
||||||
use integral::*;
|
use integral::*;
|
||||||
|
use floating::*;
|
||||||
use to_str::ToStr;
|
use to_str::ToStr;
|
||||||
use std::smallintmap::SmallIntMap;
|
use std::smallintmap::SmallIntMap;
|
||||||
|
|
||||||
@ -294,28 +295,12 @@ fn bnds<C: combine>(
|
|||||||
// Integral variables
|
// Integral variables
|
||||||
|
|
||||||
impl infer_ctxt {
|
impl infer_ctxt {
|
||||||
fn int_vars(a_id: ty::IntVid, b_id: ty::IntVid) -> ures {
|
fn optimize_ranks<V:Copy vid Eq,T:Copy ToStr>(vb: &vals_and_bindings<V,T>,
|
||||||
let vb = &self.int_var_bindings;
|
nde_a: node<V,T>,
|
||||||
|
nde_b: node<V,T>,
|
||||||
let nde_a = self.get(vb, a_id);
|
a_id: V,
|
||||||
let nde_b = self.get(vb, b_id);
|
b_id: V,
|
||||||
let a_id = nde_a.root;
|
intersection: T) {
|
||||||
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
|
|
||||||
if nde_a.rank > nde_b.rank {
|
if nde_a.rank > nde_b.rank {
|
||||||
debug!("int_vars(): a has smaller rank");
|
debug!("int_vars(): a has smaller rank");
|
||||||
// a has greater rank, so a should become b's parent,
|
// a has greater rank, so a should become b's parent,
|
||||||
@ -336,6 +321,31 @@ fn int_vars(a_id: ty::IntVid, b_id: ty::IntVid) -> ures {
|
|||||||
self.set(vb, a_id, root(intersection, nde_a.rank + 1u));
|
self.set(vb, a_id, root(intersection, nde_a.rank + 1u));
|
||||||
self.set(vb, b_id, redirect(a_id));
|
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()
|
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 a_pt = nde_a.possible_types;
|
||||||
|
|
||||||
let intersection =
|
let intersection =
|
||||||
intersection(a_pt,
|
integral::intersection(a_pt,
|
||||||
convert_integral_ty_to_int_ty_set(self.tcx, b));
|
convert_integral_ty_to_int_ty_set(self.tcx, b));
|
||||||
if *intersection == INT_TY_SET_EMPTY {
|
if *intersection == INT_TY_SET_EMPTY {
|
||||||
return Err(ty::terr_no_integral_type);
|
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 b_pt = nde_b.possible_types;
|
||||||
|
|
||||||
let intersection =
|
let intersection =
|
||||||
intersection(b_pt,
|
integral::intersection(b_pt,
|
||||||
convert_integral_ty_to_int_ty_set(self.tcx, a));
|
convert_integral_ty_to_int_ty_set(self.tcx, a));
|
||||||
if *intersection == INT_TY_SET_EMPTY {
|
if *intersection == INT_TY_SET_EMPTY {
|
||||||
return Err(ty::terr_no_integral_type);
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -128,6 +128,7 @@ mod middle {
|
|||||||
mod glb;
|
mod glb;
|
||||||
#[legacy_exports]
|
#[legacy_exports]
|
||||||
mod integral;
|
mod integral;
|
||||||
|
mod floating;
|
||||||
#[legacy_exports]
|
#[legacy_exports]
|
||||||
mod lattice;
|
mod lattice;
|
||||||
#[legacy_exports]
|
#[legacy_exports]
|
||||||
|
@ -862,6 +862,7 @@ enum lit_ {
|
|||||||
lit_uint(u64, uint_ty),
|
lit_uint(u64, uint_ty),
|
||||||
lit_int_unsuffixed(i64),
|
lit_int_unsuffixed(i64),
|
||||||
lit_float(@~str, float_ty),
|
lit_float(@~str, float_ty),
|
||||||
|
lit_float_unsuffixed(@~str),
|
||||||
lit_nil,
|
lit_nil,
|
||||||
lit_bool(bool),
|
lit_bool(bool),
|
||||||
}
|
}
|
||||||
@ -880,6 +881,7 @@ impl ast::lit_: cmp::Eq {
|
|||||||
(lit_float(val_a, ty_a), lit_float(val_b, ty_b)) => {
|
(lit_float(val_a, ty_a), lit_float(val_b, ty_b)) => {
|
||||||
val_a == val_b && ty_a == 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_nil, lit_nil) => true,
|
||||||
(lit_bool(a), lit_bool(b)) => a == b,
|
(lit_bool(a), lit_bool(b)) => a == b,
|
||||||
(lit_str(_), _) => false,
|
(lit_str(_), _) => false,
|
||||||
@ -887,6 +889,7 @@ impl ast::lit_: cmp::Eq {
|
|||||||
(lit_uint(*), _) => false,
|
(lit_uint(*), _) => false,
|
||||||
(lit_int_unsuffixed(*), _) => false,
|
(lit_int_unsuffixed(*), _) => false,
|
||||||
(lit_float(*), _) => false,
|
(lit_float(*), _) => false,
|
||||||
|
(lit_float_unsuffixed(*), _) => false,
|
||||||
(lit_nil, _) => false,
|
(lit_nil, _) => false,
|
||||||
(lit_bool(_), _) => false
|
(lit_bool(_), _) => false
|
||||||
}
|
}
|
||||||
|
@ -385,6 +385,8 @@ fn scan_number(c: char, rdr: string_reader) -> token::Token {
|
|||||||
}
|
}
|
||||||
None => ()
|
None => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut is_machine_float = false;
|
||||||
if rdr.curr == 'f' {
|
if rdr.curr == 'f' {
|
||||||
bump(rdr);
|
bump(rdr);
|
||||||
c = rdr.curr;
|
c = rdr.curr;
|
||||||
@ -404,10 +406,14 @@ fn scan_number(c: char, rdr: string_reader) -> token::Token {
|
|||||||
back-end. */
|
back-end. */
|
||||||
} else {
|
} else {
|
||||||
is_float = true;
|
is_float = true;
|
||||||
|
is_machine_float = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_float {
|
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 {
|
} else {
|
||||||
if str::len(num_str) == 0u {
|
if str::len(num_str) == 0u {
|
||||||
rdr.fatal(~"no valid digits found for number");
|
rdr.fatal(~"no valid digits found for number");
|
||||||
|
@ -43,9 +43,9 @@
|
|||||||
ident, impure_fn, infer, inherited,
|
ident, impure_fn, infer, inherited,
|
||||||
item, item_, item_class, item_const, item_enum, item_fn,
|
item, item_, item_class, item_const, item_enum, item_fn,
|
||||||
item_foreign_mod, item_impl, item_mac, item_mod, item_trait,
|
item_foreign_mod, item_impl, item_mac, item_mod, item_trait,
|
||||||
item_ty, lit, lit_, lit_bool, lit_float, lit_int,
|
item_ty, lit, lit_, lit_bool, lit_float, lit_float_unsuffixed,
|
||||||
lit_int_unsuffixed, lit_nil, lit_str, lit_uint, local, m_const,
|
lit_int, lit_int_unsuffixed, lit_nil, lit_str, lit_uint, local,
|
||||||
m_imm, m_mutbl, mac_, mac_aq, mac_ellipsis, mac_invoc,
|
m_const, m_imm, m_mutbl, mac_, mac_aq, mac_ellipsis, mac_invoc,
|
||||||
mac_invoc_tt, mac_var, matcher, match_nonterminal, match_seq,
|
mac_invoc_tt, mac_var, matcher, match_nonterminal, match_seq,
|
||||||
match_tok, method, mode, module_ns, mt, mul, mutability,
|
match_tok, method, mode, module_ns, mt, mul, mutability,
|
||||||
named_field, neg, noreturn, not, pat, pat_box, pat_enum,
|
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_UINT(u, ut) => lit_uint(u, ut),
|
||||||
token::LIT_INT_UNSUFFIXED(i) => lit_int_unsuffixed(i),
|
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(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::LIT_STR(s) => lit_str(self.id_to_str(s)),
|
||||||
token::LPAREN => { self.expect(token::RPAREN); lit_nil },
|
token::LPAREN => { self.expect(token::RPAREN); lit_nil },
|
||||||
_ => { self.unexpected_last(tok); }
|
_ => { self.unexpected_last(tok); }
|
||||||
|
@ -62,6 +62,7 @@ enum Token {
|
|||||||
LIT_UINT(u64, ast::uint_ty),
|
LIT_UINT(u64, ast::uint_ty),
|
||||||
LIT_INT_UNSUFFIXED(i64),
|
LIT_INT_UNSUFFIXED(i64),
|
||||||
LIT_FLOAT(ast::ident, ast::float_ty),
|
LIT_FLOAT(ast::ident, ast::float_ty),
|
||||||
|
LIT_FLOAT_UNSUFFIXED(ast::ident),
|
||||||
LIT_STR(ast::ident),
|
LIT_STR(ast::ident),
|
||||||
|
|
||||||
/* Name components */
|
/* Name components */
|
||||||
@ -164,6 +165,13 @@ fn to_str(in: @ident_interner, t: Token) -> ~str {
|
|||||||
}
|
}
|
||||||
body + ast_util::float_ty_to_str(t)
|
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)) + ~"\"" }
|
LIT_STR(s) => { ~"\"" + str::escape_default(*in.get(s)) + ~"\"" }
|
||||||
|
|
||||||
/* Name components */
|
/* Name components */
|
||||||
@ -204,6 +212,7 @@ fn to_str(in: @ident_interner, t: Token) -> ~str {
|
|||||||
LIT_UINT(_, _) => true,
|
LIT_UINT(_, _) => true,
|
||||||
LIT_INT_UNSUFFIXED(_) => true,
|
LIT_INT_UNSUFFIXED(_) => true,
|
||||||
LIT_FLOAT(_, _) => true,
|
LIT_FLOAT(_, _) => true,
|
||||||
|
LIT_FLOAT_UNSUFFIXED(_) => true,
|
||||||
LIT_STR(_) => true,
|
LIT_STR(_) => true,
|
||||||
POUND => true,
|
POUND => true,
|
||||||
AT => true,
|
AT => true,
|
||||||
@ -243,6 +252,7 @@ fn is_lit(t: Token) -> bool {
|
|||||||
LIT_UINT(_, _) => true,
|
LIT_UINT(_, _) => true,
|
||||||
LIT_INT_UNSUFFIXED(_) => true,
|
LIT_INT_UNSUFFIXED(_) => true,
|
||||||
LIT_FLOAT(_, _) => true,
|
LIT_FLOAT(_, _) => true,
|
||||||
|
LIT_FLOAT_UNSUFFIXED(_) => true,
|
||||||
LIT_STR(_) => true,
|
LIT_STR(_) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
@ -684,6 +694,12 @@ impl Token : cmp::Eq {
|
|||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LIT_FLOAT_UNSUFFIXED(e0a) => {
|
||||||
|
match (*other) {
|
||||||
|
LIT_FLOAT_UNSUFFIXED(e0b) => e0a == e0b,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
LIT_STR(e0a) => {
|
LIT_STR(e0a) => {
|
||||||
match (*other) {
|
match (*other) {
|
||||||
LIT_STR(e0b) => e0a == e0b,
|
LIT_STR(e0b) => e0a == e0b,
|
||||||
|
@ -1970,6 +1970,7 @@ fn print_literal(s: ps, &&lit: @ast::lit) {
|
|||||||
ast::lit_float(f, t) => {
|
ast::lit_float(f, t) => {
|
||||||
word(s.s, *f + ast_util::float_ty_to_str(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_nil => word(s.s, ~"()"),
|
||||||
ast::lit_bool(val) => {
|
ast::lit_bool(val) => {
|
||||||
if val { word(s.s, ~"true"); } else { word(s.s, ~"false"); }
|
if val { word(s.s, ~"true"); } else { word(s.s, ~"false"); }
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
fn main() {
|
||||||
|
let x: f32 = 1; //~ ERROR mismatched types
|
||||||
|
let y: f32 = 1f; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
13
src/test/run-pass/float-literal-inference.rs
Normal file
13
src/test/run-pass/float-literal-inference.rs
Normal file
@ -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());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user