From 77e6573929702731bc0bd2c41724e6a587c7f268 Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Thu, 14 Jun 2012 19:41:40 -0700 Subject: [PATCH] Further work on integer literal suffix inference (#1425) In this commit: * Change the lit_int_unsuffixed AST node to not carry a type, since it doesn't need one * Don't print "(unsuffixed)" when pretty-printing unsuffixed integer literals * Just print "I" instead of "(integral)" for integral type variables * Set up trans to use the information that will be gathered during typeck to construct the appropriate constants for unsuffixed int literals * Add logic for handling int_ty_sets in typeck::infer * Clean up unnecessary code in typeck::infer * Add missing mk_ functions to middle::ty * Add ty_var_integral to a few of the type utility functions it was missing from in middle::ty --- src/libsyntax/ast.rs | 2 +- src/libsyntax/parse/classify.rs | 2 +- src/libsyntax/parse/lexer.rs | 2 +- src/libsyntax/parse/parser.rs | 6 +- src/libsyntax/parse/token.rs | 10 +- src/libsyntax/print/pprust.rs | 10 +- src/rustc/metadata/tyencode.rs | 3 +- src/rustc/middle/const_eval.rs | 2 +- src/rustc/middle/trans/base.rs | 28 ++-- src/rustc/middle/ty.rs | 30 ++++- src/rustc/middle/typeck/check.rs | 26 +--- src/rustc/middle/typeck/infer.rs | 223 +++++++++++++++++++------------ 12 files changed, 201 insertions(+), 143 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5381a9f345d..edc90fe8676 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -402,7 +402,7 @@ enum lit_ { lit_str(@str), lit_int(i64, int_ty), lit_uint(u64, uint_ty), - lit_int_unsuffixed(i64, int_ty), + lit_int_unsuffixed(i64), lit_float(@str, float_ty), lit_nil, lit_bool(bool), diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs index aff0334a946..a3d55df320b 100644 --- a/src/libsyntax/parse/classify.rs +++ b/src/libsyntax/parse/classify.rs @@ -54,7 +54,7 @@ fn ends_in_lit_int(ex: @ast::expr) -> bool { ast::expr_lit(node) { alt node { @{node: ast::lit_int(_, ast::ty_i), _} | - @{node: ast::lit_int_unsuffixed(_, ast::ty_i), _} + @{node: ast::lit_int_unsuffixed(_), _} { true } _ { false } } diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 115a9957c28..72b2462feb1 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -285,7 +285,7 @@ fn scan_number(c: char, rdr: reader) -> token::token { #debug["lexing %s as an unsuffixed integer literal", num_str]; - ret token::LIT_INT_UNSUFFIXED(parsed as i64, ast::ty_i); + ret token::LIT_INT_UNSUFFIXED(parsed as i64); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 20452cd8724..62ec5cc50f6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -501,7 +501,7 @@ class parser { let lo = self.span.lo; self.bump(); alt copy self.token { - token::LIT_INT_UNSUFFIXED(num, _) { + token::LIT_INT_UNSUFFIXED(num) { self.bump(); some(mac_var(num as uint)) } @@ -534,7 +534,7 @@ class parser { token::UNDERSCORE { self.bump(); some(vstore_fixed(none)) } - token::LIT_INT_UNSUFFIXED(i, _) if i >= 0i64 { + token::LIT_INT_UNSUFFIXED(i) if i >= 0i64 { self.bump(); some(vstore_fixed(some(i as uint))) } token::BINOP(token::AND) { @@ -553,7 +553,7 @@ class parser { alt tok { token::LIT_INT(i, it) { lit_int(i, it) } token::LIT_UINT(u, ut) { lit_uint(u, ut) } - token::LIT_INT_UNSUFFIXED(i, it) { lit_int_unsuffixed(i, it) } + token::LIT_INT_UNSUFFIXED(i) { lit_int_unsuffixed(i) } token::LIT_FLOAT(s, ft) { lit_float(self.get_str(s), ft) } token::LIT_STR(s) { lit_str(self.get_str(s)) } token::LPAREN { self.expect(token::RPAREN); lit_nil } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 6bf6347704d..4f4c2ee0064 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -57,7 +57,7 @@ enum token { /* Literals */ LIT_INT(i64, ast::int_ty), LIT_UINT(u64, ast::uint_ty), - LIT_INT_UNSUFFIXED(i64, ast::int_ty), + LIT_INT_UNSUFFIXED(i64), LIT_FLOAT(str_num, ast::float_ty), LIT_STR(str_num), @@ -129,8 +129,8 @@ fn to_str(in: interner<@str>, t: token) -> str { LIT_UINT(u, t) { uint::to_str(u as uint, 10u) + ast_util::uint_ty_to_str(t) } - LIT_INT_UNSUFFIXED(i, t) { - int::to_str(i as int, 10u) + ast_util::int_ty_to_str(t) + LIT_INT_UNSUFFIXED(i) { + int::to_str(i as int, 10u) } LIT_FLOAT(s, t) { *interner::get(in, s) + @@ -160,7 +160,7 @@ pure fn can_begin_expr(t: token) -> bool { TILDE { true } LIT_INT(_, _) { true } LIT_UINT(_, _) { true } - LIT_INT_UNSUFFIXED(_, _) { true } + LIT_INT_UNSUFFIXED(_) { true } LIT_FLOAT(_, _) { true } LIT_STR(_) { true } POUND { true } @@ -178,7 +178,7 @@ fn is_lit(t: token) -> bool { alt t { LIT_INT(_, _) { true } LIT_UINT(_, _) { true } - LIT_INT_UNSUFFIXED(_, _) { true } + LIT_INT_UNSUFFIXED(_) { true } LIT_FLOAT(_, _) { true } LIT_STR(_) { true } _ { false } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a63e3139b5b..43b498eae62 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1628,15 +1628,11 @@ fn print_literal(s: ps, &&lit: @ast::lit) { u64::to_str(u, 10u) + ast_util::uint_ty_to_str(t)); } - ast::lit_int_unsuffixed(i, t) { + ast::lit_int_unsuffixed(i) { if i < 0_i64 { - word(s.s, - "-" + u64::to_str(-i as u64, 10u) - + ast_util::int_ty_to_str(t)); + word(s.s, "-" + u64::to_str(-i as u64, 10u)); } else { - word(s.s, - u64::to_str(i as u64, 10u) - + ast_util::int_ty_to_str(t)); + word(s.s, u64::to_str(i as u64, 10u)); } } ast::lit_float(f, t) { diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs index a158b0b01fd..f21b3850a98 100644 --- a/src/rustc/metadata/tyencode.rs +++ b/src/rustc/metadata/tyencode.rs @@ -278,10 +278,9 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) { w.write_uint(id.to_uint()); } ty::ty_var_integral(id) { - // TODO: should we have a different character for these? (Issue #1425) w.write_char('X'); + w.write_char('I'); w.write_uint(id.to_uint()); - w.write_str("(integral)"); } ty::ty_param(id, did) { w.write_char('p'); diff --git a/src/rustc/middle/const_eval.rs b/src/rustc/middle/const_eval.rs index a72e7fb0208..661ad87dfa8 100644 --- a/src/rustc/middle/const_eval.rs +++ b/src/rustc/middle/const_eval.rs @@ -111,7 +111,7 @@ fn lit_to_const(lit: @lit) -> const_val { lit_str(s) { const_str(*s) } lit_int(n, _) { const_int(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(option::get(float::from_str(*n)) as f64) } lit_nil { const_int(0i64) } lit_bool(b) { const_int(b as i64) } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index d46a47f0bd0..590440ecb7f 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -1473,15 +1473,25 @@ fn store_temp_expr(cx: block, action: copy_action, dst: ValueRef, ret move_val(cx, action, dst, src, t); } -fn trans_crate_lit(cx: @crate_ctxt, lit: ast::lit) -> ValueRef { +fn trans_crate_lit(cx: @crate_ctxt, e: @ast::expr, lit: ast::lit) + -> ValueRef { let _icx = cx.insn_ctxt("trans_crate_lit"); alt lit.node { ast::lit_int(i, t) { C_integral(T_int_ty(cx, t), i as u64, True) } ast::lit_uint(u, t) { C_integral(T_uint_ty(cx, t), u, False) } - ast::lit_int_unsuffixed(i, t) { - // FIXME (#1425): should we be using cx.fcx.infcx to figure out what - // to actually generate from this? - C_integral(T_int_ty(cx, t), i as u64, True) + ast::lit_int_unsuffixed(i) { + let lit_int_ty = ty::node_id_to_type(cx.tcx, e.id); + alt ty::get(lit_int_ty).struct { + ty::ty_int(t) { + C_integral(T_int_ty(cx, t), i as u64, True) + } + ty::ty_uint(t) { + C_integral(T_uint_ty(cx, t), i as u64, False) + } + _ { cx.sess.span_bug(lit.span, + "integer literal doesn't have a type"); + } + } } ast::lit_float(fs, t) { C_floating(*fs, T_float_ty(cx, t)) } ast::lit_bool(b) { C_bool(b) } @@ -1492,13 +1502,13 @@ fn trans_crate_lit(cx: @crate_ctxt, lit: ast::lit) -> ValueRef { } } -fn trans_lit(cx: block, lit: ast::lit, dest: dest) -> block { +fn trans_lit(cx: block, e: @ast::expr, lit: ast::lit, dest: dest) -> block { let _icx = cx.insn_ctxt("trans_lit"); if dest == ignore { ret cx; } alt lit.node { ast::lit_str(s) { tvec::trans_estr(cx, s, ast::vstore_uniq, dest) } _ { - store_in_dest(cx, trans_crate_lit(cx.ccx(), lit), dest) + store_in_dest(cx, trans_crate_lit(cx.ccx(), e, lit), dest) } } } @@ -3584,7 +3594,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block { } ast::expr_tup(args) { ret trans_tup(bcx, args, dest); } ast::expr_vstore(e, v) { ret tvec::trans_vstore(bcx, e, v, dest); } - ast::expr_lit(lit) { ret trans_lit(bcx, *lit, dest); } + ast::expr_lit(lit) { ret trans_lit(bcx, e, *lit, dest); } ast::expr_vec(args, _) { ret tvec::trans_evec(bcx, args, ast::vstore_uniq, e.id, dest); } @@ -4684,7 +4694,7 @@ fn trans_enum_variant(ccx: @crate_ctxt, enum_id: ast::node_id, fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { let _icx = cx.insn_ctxt("trans_const_expr"); alt e.node { - ast::expr_lit(lit) { ret trans_crate_lit(cx, *lit); } + ast::expr_lit(lit) { ret trans_crate_lit(cx, e, *lit); } ast::expr_binary(b, e1, e2) { let te1 = trans_const_expr(cx, e1); let te2 = trans_const_expr(cx, e2); diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 421bbf38e14..b7ceaa8ab47 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -84,6 +84,7 @@ export ty_float, mk_float, mk_mach_float, type_is_fp; export ty_fn, fn_ty, mk_fn; export ty_fn_proto, 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 ty_str, mk_str, type_is_str; export ty_vec, mk_vec, type_is_vec; export ty_estr, mk_estr; @@ -416,7 +417,8 @@ enum type_err { terr_vstores_differ(terr_vstore_kind, vstore, vstore), terr_in_field(@type_err, ast::ident), terr_sorts(t, t), - terr_self_substs + terr_self_substs, + terr_no_integral_type, } enum param_bound { @@ -442,7 +444,7 @@ impl of vid for tv_vid { impl of vid for tvi_vid { fn to_uint() -> uint { *self } - fn to_str() -> str { #fmt["", self.to_uint()] } + fn to_str() -> str { #fmt["", self.to_uint()] } } impl of vid for region_vid { @@ -619,12 +621,26 @@ fn mk_bool(cx: ctxt) -> t { mk_t(cx, ty_bool) } fn mk_int(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i)) } +fn mk_i8(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i8)) } + +fn mk_i16(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i16)) } + +fn mk_i32(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i32)) } + +fn mk_i64(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i64)) } + fn mk_float(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f)) } fn mk_uint(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u)) } fn mk_u8(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u8)) } +fn mk_u16(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u16)) } + +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_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)) } @@ -1188,7 +1204,7 @@ pure fn type_is_unique(ty: t) -> bool { pure fn type_is_scalar(ty: t) -> bool { alt get(ty).struct { ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | - ty_type | ty_ptr(_) | ty_rptr(_, _) { true } + ty_var_integral(_) | ty_type | ty_ptr(_) | ty_rptr(_, _) { true } _ { false } } } @@ -1827,7 +1843,7 @@ fn type_structurally_contains_uniques(cx: ctxt, ty: t) -> bool { fn type_is_integral(ty: t) -> bool { alt get(ty).struct { - ty_int(_) | ty_uint(_) | ty_bool { true } + ty_var_integral(_) | ty_int(_) | ty_uint(_) | ty_bool { true } _ { false } } } @@ -2531,6 +2547,10 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> str { terr_self_substs { ret "inconsistent self substitution"; // XXX this is more of a bug } + terr_no_integral_type { + ret "couldn't determine an appropriate integral type for integer \ + literal"; + } } } @@ -2966,7 +2986,7 @@ fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool { fn tycat(ty: t) -> int { alt get(ty).struct { ty_bool { tycat_bool } - ty_int(_) | ty_uint(_) { tycat_int } + ty_int(_) | ty_uint(_) | ty_var_integral(_) { tycat_int } ty_float(_) { tycat_float } ty_estr(_) | ty_str { tycat_str } ty_evec(_, _) | ty_vec(_) { tycat_vec } diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 6dfa89549e7..10cb4c9f494 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -73,11 +73,9 @@ import middle::ty::{tv_vid, vid}; import regionmanip::{replace_bound_regions_in_fn_ty, region_of}; import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope}; import rscope::{in_binding_rscope, region_scope, type_rscope}; -import syntax::ast::{ty_char, ty_i8, ty_i16, ty_i32, ty_i64, ty_i}; +import syntax::ast::{ty_char, ty_i}; import typeck::infer::{root, to_str}; import typeck::infer::{unify_methods}; // infcx.set() -import typeck::infer::{min_8bit_tys, min_16bit_tys, min_32bit_tys, - min_64bit_tys}; type fn_ctxt = // var_bindings, locals and next_var_id are shared @@ -623,29 +621,13 @@ fn check_lit(fcx: @fn_ctxt, lit: @ast::lit) -> ty::t { ast::lit_str(_) { ty::mk_str(tcx) } ast::lit_int(_, t) { ty::mk_mach_int(tcx, t) } ast::lit_uint(_, t) { ty::mk_mach_uint(tcx, t) } - ast::lit_int_unsuffixed(v, t) { + ast::lit_int_unsuffixed(v) { // An unsuffixed integer literal could have any integral type, // so we create an integral type variable for it. - let vid = fcx.infcx.next_ty_var_integral_id(); - - // We need to sniff at the value `v` and figure out how big of - // an int it is; that determines the range of possible types - // that the integral type variable could take on. - let possible_types = alt v { - 0i64 to 127i64 { min_8bit_tys() } - 128i64 to 65535i64 { min_16bit_tys() } - 65536i64 to 4294967295i64 { min_32bit_tys() } - _ { min_64bit_tys() } - }; - - // Store the set of possible types and return the integral - // type variable. - fcx.infcx.set(fcx.infcx.tvib, vid, - root(possible_types)); - ty::mk_var_integral(tcx, vid); + ty::mk_var_integral(tcx, fcx.infcx.next_ty_var_integral_id()); // FIXME: remove me when #1425 is finished. - ty::mk_mach_int(tcx, t) + ty::mk_mach_int(tcx, ty_i) } ast::lit_float(_, t) { ty::mk_mach_float(tcx, t) } ast::lit_nil { ty::mk_nil(tcx) } diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs index 1c080ba8c5c..b5770528a3e 100644 --- a/src/rustc/middle/typeck/infer.rs +++ b/src/rustc/middle/typeck/infer.rs @@ -147,7 +147,8 @@ import std::smallintmap::smallintmap; import std::smallintmap::map; import std::map::hashmap; import middle::ty; -import middle::ty::{tv_vid, tvi_vid, region_vid, vid}; +import middle::ty::{tv_vid, tvi_vid, region_vid, vid, + ty_int, ty_uint, get}; import syntax::{ast, ast_util}; import syntax::ast::{ret_style, purity}; import util::ppaux::{ty_to_str, mt_to_str}; @@ -174,7 +175,7 @@ export compare_tys; export fixup_err, fixup_err_to_str; export assignment; export root, to_str; -export min_8bit_tys, min_16bit_tys, min_32bit_tys, min_64bit_tys; +export int_ty_set_all; // Bitvector to represent sets of integral types enum int_ty_set = uint; @@ -193,9 +194,7 @@ const INT_TY_SET_u64 : uint = 0b00_1000_0000u; const INT_TY_SET_i : uint = 0b01_0000_0000u; const INT_TY_SET_u : uint = 0b10_0000_0000u; -fn mk_int_ty_set() -> int_ty_set { int_ty_set(INT_TY_SET_EMPTY) } - -fn min_8bit_tys() -> int_ty_set { +fn int_ty_set_all() -> int_ty_set { int_ty_set(INT_TY_SET_i8 | INT_TY_SET_u8 | INT_TY_SET_i16 | INT_TY_SET_u16 | INT_TY_SET_i32 | INT_TY_SET_u32 | @@ -203,22 +202,58 @@ fn min_8bit_tys() -> int_ty_set { INT_TY_SET_i | INT_TY_SET_u) } -fn min_16bit_tys() -> int_ty_set { - int_ty_set(INT_TY_SET_i16 | INT_TY_SET_u16 | - INT_TY_SET_i32 | INT_TY_SET_u32 | - INT_TY_SET_i64 | INT_TY_SET_u64 | - INT_TY_SET_i | INT_TY_SET_u) +fn intersection(a: int_ty_set, b: int_ty_set) -> int_ty_set { + int_ty_set(*a & *b) } -fn min_32bit_tys() -> int_ty_set { - int_ty_set(INT_TY_SET_i32 | INT_TY_SET_u32 | - INT_TY_SET_i64 | INT_TY_SET_u64 | - // uh, can we count on ty_i and ty_u being 32 bits? - INT_TY_SET_i | INT_TY_SET_u) +fn single_type_contained_in(tcx: ty::ctxt, a: int_ty_set) -> + option { + #debug["type_contained_in(a=%s)", uint::to_str(*a, 10u)]; + + if *a == INT_TY_SET_i8 { ret some(ty::mk_i8(tcx)); } + if *a == INT_TY_SET_u8 { ret some(ty::mk_u8(tcx)); } + if *a == INT_TY_SET_i16 { ret some(ty::mk_i16(tcx)); } + if *a == INT_TY_SET_u16 { ret some(ty::mk_u16(tcx)); } + if *a == INT_TY_SET_i32 { ret some(ty::mk_i32(tcx)); } + if *a == INT_TY_SET_u32 { ret some(ty::mk_u32(tcx)); } + if *a == INT_TY_SET_i64 { ret some(ty::mk_i64(tcx)); } + if *a == INT_TY_SET_u64 { ret some(ty::mk_u64(tcx)); } + if *a == INT_TY_SET_i { ret(some(ty::mk_int(tcx))); } + if *a == INT_TY_SET_u { ret(some(ty::mk_uint(tcx))); } + ret none; } -fn min_64bit_tys() -> int_ty_set { - int_ty_set(INT_TY_SET_i64 | INT_TY_SET_u64) +fn is_subset_of(a: int_ty_set, b: int_ty_set) -> bool { + (*a & *b) == *a +} + +fn convert_integral_ty_to_int_ty_set(tcx: ty::ctxt, t: ty::t) + -> int_ty_set { + + alt get(t).struct { + ty_int(int_ty) { + alt int_ty { + ast::ty_i8 { int_ty_set(INT_TY_SET_i8) } + ast::ty_i16 { int_ty_set(INT_TY_SET_i16) } + ast::ty_i32 { int_ty_set(INT_TY_SET_i32) } + ast::ty_i64 { int_ty_set(INT_TY_SET_i64) } + ast::ty_i { int_ty_set(INT_TY_SET_i) } + ast::ty_char { tcx.sess.bug( + "char type passed to convert_integral_ty_to_int_ty_set()"); } + } + } + ty_uint(uint_ty) { + alt uint_ty { + ast::ty_u8 { int_ty_set(INT_TY_SET_u8) } + ast::ty_u16 { int_ty_set(INT_TY_SET_u16) } + ast::ty_u32 { int_ty_set(INT_TY_SET_u32) } + ast::ty_u64 { int_ty_set(INT_TY_SET_u64) } + ast::ty_u { int_ty_set(INT_TY_SET_u) } + } + } + _ { tcx.sess.bug("non-integral type passed to \ + convert_integral_ty_to_int_ty_set()"); } + } } // Extra information needed to perform an assignment that may borrow. @@ -265,6 +300,7 @@ enum infer_ctxt = @{ }; enum fixup_err { + unresolved_int_ty(tvi_vid), unresolved_ty(tv_vid), cyclic_ty(tv_vid), unresolved_region(region_vid), @@ -273,6 +309,7 @@ enum fixup_err { fn fixup_err_to_str(f: fixup_err) -> str { alt f { + unresolved_int_ty(_) { "unconstrained integral type" } unresolved_ty(_) { "unconstrained type" } cyclic_ty(_) { "cyclic type of infinite size" } unresolved_region(_) { "unconstrained region" } @@ -410,7 +447,7 @@ impl of to_str for bound { fn to_str(cx: infer_ctxt) -> str { alt self { some(v) { v.to_str(cx) } - none { "none " } + none { "none" } } } } @@ -555,7 +592,7 @@ impl methods for infer_ctxt { *self.ty_var_integral_counter += 1u; self.tvib.vals.insert(id, - root(mk_int_ty_set())); + root(int_ty_set_all())); ret tvi_vid(id); } @@ -771,9 +808,24 @@ impl unify_methods for infer_ctxt { } fn vars_integral( - _vb: vals_and_bindings, - _a_id: V, _b_id: V) -> ures { - // FIXME (#1425): do something real here. + vb: vals_and_bindings, + a_id: V, b_id: V) -> ures { + + let {root: a_id, possible_types: a_pt} = self.get(vb, a_id); + let {root: b_id, possible_types: b_pt} = self.get(vb, b_id); + + // If we're already dealing with the same two variables, + // there's nothing to do. + if a_id == b_id { ret 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 { + ret err(ty::terr_no_integral_type); + } + self.set(vb, a_id, root(intersection)); + self.set(vb, b_id, redirect(a_id)); uok() } @@ -789,11 +841,21 @@ impl unify_methods for infer_ctxt { self.set_var_to_merged_bounds(vb, a_id, a_bounds, b_bounds) } - // FIXME (#1425): this is a terrible name. - fn vart_integral( - _vb: vals_and_bindings, - _a_id: V, _b: T) -> ures { - // FIXME (#1425): do something real here. + fn vart_integral( + vb: vals_and_bindings, + a_id: V, b: ty::t) -> ures { + + assert ty::type_is_integral(b); + + let {root: a_id, possible_types: a_pt} = self.get(vb, a_id); + + let intersection = + intersection(a_pt, convert_integral_ty_to_int_ty_set( + self.tcx, b)); + if *intersection == INT_TY_SET_EMPTY { + ret err(ty::terr_no_integral_type); + } + self.set(vb, a_id, root(intersection)); uok() } @@ -809,10 +871,21 @@ impl unify_methods for infer_ctxt { self.set_var_to_merged_bounds(vb, b_id, a_bounds, b_bounds) } - fn tvar_integral( - _vb: vals_and_bindings, - _a: T, _b_id: V) -> ures { - // FIXME (#1425): do something real here. + fn tvar_integral( + vb: vals_and_bindings, + a: ty::t, b_id: V) -> ures { + + assert ty::type_is_integral(a); + + let {root: b_id, possible_types: b_pt} = self.get(vb, b_id); + + let intersection = + intersection(b_pt, convert_integral_ty_to_int_ty_set( + self.tcx, a)); + if *intersection == INT_TY_SET_EMPTY { + ret err(ty::terr_no_integral_type); + } + self.set(vb, b_id, root(intersection)); uok() } @@ -1066,13 +1139,26 @@ impl methods for resolve_state { } fn resolve_ty_var_integral(vid: tvi_vid) -> ty::t { - let {root:_, possible_types: its} = + let {root:_, possible_types: pt} = self.infcx.get(self.infcx.tvib, vid); - let t1 = alt its { - // FIXME (#1425): do something real here. - int_ty_set(_) { ty::mk_int(self.infcx.tcx) } - }; - ret t1; + // If there's only one type in the set of possible types, then + // that's the answer. + alt single_type_contained_in(self.infcx.tcx, pt) { + some(t) { t } + none { + if self.force_vars { + // As a last resort, default to int. + let ty = ty::mk_int(self.infcx.tcx); + self.infcx.set( + self.infcx.tvib, vid, + root(convert_integral_ty_to_int_ty_set(self.infcx.tcx, + ty))); + ty + } else { + ty::mk_var_integral(self.infcx.tcx, vid) + } + } + } } } @@ -1324,7 +1410,6 @@ iface combine { fn mts(a: ty::mt, b: ty::mt) -> cres; fn contratys(a: ty::t, b: ty::t) -> cres; fn tys(a: ty::t, b: ty::t) -> cres; - fn int_tys(a: ty::t, b: ty::t) -> cres; fn tps(as: [ty::t], bs: [ty::t]) -> cres<[ty::t]>; fn self_tys(a: option, b: option) -> cres>; fn substs(as: ty::substs, bs: ty::substs) -> cres; @@ -1516,12 +1601,6 @@ fn super_fns( } } -fn super_int_tys( - self: C, _a: ty::t, _b: ty::t) -> cres { - // FIXME (#1425): do something real here? - ok(ty::mk_int(self.infcx().tcx)) -} - fn super_tys( self: C, a: ty::t, b: ty::t) -> cres { @@ -1539,6 +1618,20 @@ fn super_tys( b.to_str(self.infcx())]); } + // Have to handle these first + (ty::ty_var_integral(a_id), ty::ty_var_integral(b_id)) { + self.infcx().vars_integral(self.infcx().tvib, a_id, b_id).then {|| + ok(a) } + } + (ty::ty_var_integral(a_id), _) { + self.infcx().vart_integral(self.infcx().tvib, a_id, b).then {|| + ok(a) } + } + (_, ty::ty_var_integral(b_id)) { + self.infcx().tvar_integral(self.infcx().tvib, a, b_id).then {|| + ok(a) } + } + (ty::ty_int(_), _) | (ty::ty_uint(_), _) | (ty::ty_float(_), _) { @@ -1787,21 +1880,6 @@ impl of combine for sub { (_, ty::ty_bot) { err(ty::terr_sorts(b, a)) } - - // FIXME (#1425): I'm not sure if these three cases - // belong here or if they belong in super_tys. - (ty::ty_var_integral(a_id), ty::ty_var_integral(b_id)) { - self.infcx().vars_integral(self.tvib, a_id, b_id).then {|| - ok(a) } - } - (ty::ty_var_integral(a_id), _) { - self.infcx().vart_integral(self.tvib, a_id, b).then {|| - ok(a) } - } - (_, ty::ty_var_integral(b_id)) { - self.infcx().tvar_integral(self.tvib, a, b_id).then {|| - ok(a) } - } _ { super_tys(self, a, b) } @@ -1847,10 +1925,6 @@ impl of combine for sub { // Traits please: - fn int_tys(a: ty::t, b: ty::t) -> cres { - super_int_tys(self, a, b) - } - fn flds(a: ty::field, b: ty::field) -> cres { super_flds(self, a, b) } @@ -2029,10 +2103,6 @@ impl of combine for lub { // Traits please: - fn int_tys(a: ty::t, b: ty::t) -> cres { - super_int_tys(self, a, b) - } - fn tys(a: ty::t, b: ty::t) -> cres { lattice_tys(self, a, b) } @@ -2236,10 +2306,6 @@ impl of combine for glb { // Traits please: - fn int_tys(a: ty::t, b: ty::t) -> cres { - super_int_tys(self, a, b) - } - fn flds(a: ty::field, b: ty::field) -> cres { super_flds(self, a, b) } @@ -2333,21 +2399,6 @@ fn lattice_tys( lattice_var_t(self, self.infcx().tvb, b_id, a, {|x, y| self.tys(x, y) }) } - (ty::ty_var_integral(a_id), ty::ty_var_integral(b_id)) { - // FIXME (#1425): do something real here? - ok(a) - } - - (ty::ty_var_integral(a_id), _) { - // FIXME (#1425): do something real here? - ok(a) - } - - (_, ty::ty_var_integral(b_id)) { - // FIXME (#1425): do something real here? - ok(a) - } - _ { super_tys(self, a, b) }