Skip to content

Commit 6aa612a

Browse files
committed
auto merge of #5461 : catamorphism/rust/flagless, r=nikomatsakis
r? @nikomatsakis The typechecker previously passed around a boolean return flag to indicate whether it saw something with type _|_ (that is, something it knows at compile-time will definitely diverge) and also had some manual checks for the `ty_err` pseudo-type that represents a previous type error. This was because the typing rules implemented by the typechecker didn't properly propagate _|_ and ty_err. I fixed it. This also required changing expected error messages in a few tests, as now we're printing out fewer derived errors -- in fact, at this point we should print out no derived errors, so report any that you see (ones that include "[type error]") as bugs.
2 parents 87d9316 + f36f9fc commit 6aa612a

File tree

13 files changed

+824
-495
lines changed

13 files changed

+824
-495
lines changed

src/librustc/middle/trans/consts.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use util::ppaux::{expr_repr, ty_to_str};
2828

2929
use core::libc::c_uint;
3030
use syntax::{ast, ast_util, codemap, ast_map};
31+
use util::ppaux::ty_to_str;
3132

3233
pub fn const_lit(cx: @CrateContext, e: @ast::expr, lit: ast::lit)
3334
-> ValueRef {
@@ -45,7 +46,8 @@ pub fn const_lit(cx: @CrateContext, e: @ast::expr, lit: ast::lit)
4546
C_integral(T_uint_ty(cx, t), i as u64, False)
4647
}
4748
_ => cx.sess.span_bug(lit.span,
48-
~"integer literal doesn't have a type")
49+
fmt!("integer literal has type %s (expected int or uint)",
50+
ty_to_str(cx.tcx, lit_int_ty)))
4951
}
5052
}
5153
ast::lit_float(fs, t) => C_floating(/*bad*/copy *fs, T_float_ty(cx, t)),

src/librustc/middle/ty.rs

+22-6
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ enum tbox_flag {
310310
needs_infer = 4,
311311
has_regions = 8,
312312
has_ty_err = 16,
313+
has_ty_bot = 32,
313314

314315
// a meta-flag: subst may be required if the type has parameters, a self
315316
// type, or references bound regions
@@ -355,9 +356,6 @@ pub pure fn type_needs_infer(t: t) -> bool {
355356
pub pure fn type_has_regions(t: t) -> bool {
356357
tbox_has_flag(get(t), has_regions)
357358
}
358-
pub pure fn type_contains_err(t: t) -> bool {
359-
tbox_has_flag(get(t), has_ty_err)
360-
}
361359
pub pure fn type_def_id(t: t) -> Option<ast::def_id> { get(t).o_def_id }
362360
pub pure fn type_id(t: t) -> uint { get(t).id }
363361

@@ -892,9 +890,17 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option<ast::def_id>) -> t {
892890
flags |= rflags(r);
893891
flags |= get(mt.ty).flags;
894892
}
895-
&ty_nil | &ty_bot | &ty_bool | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
893+
&ty_nil | &ty_bool | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
896894
&ty_estr(_) | &ty_type | &ty_opaque_closure_ptr(_) |
897895
&ty_opaque_box => (),
896+
// You might think that we could just return ty_err for
897+
// any type containing ty_err as a component, and get
898+
// rid of the has_ty_err flag -- likewise for ty_bot (with
899+
// the exception of function types that return bot).
900+
// But doing so caused sporadic memory corruption, and
901+
// neither I (tjc) nor nmatsakis could figure out why,
902+
// so we're doing it this way.
903+
&ty_bot => flags |= has_ty_bot as uint,
898904
&ty_err => flags |= has_ty_err as uint,
899905
&ty_param(_) => flags |= has_params as uint,
900906
&ty_infer(_) => flags |= needs_infer as uint,
@@ -914,12 +920,16 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option<ast::def_id>) -> t {
914920
&ty_tup(ref ts) => for ts.each |tt| { flags |= get(*tt).flags; },
915921
&ty_bare_fn(ref f) => {
916922
for f.sig.inputs.each |a| { flags |= get(a.ty).flags; }
917-
flags |= get(f.sig.output).flags;
923+
flags |= get(f.sig.output).flags;
924+
// T -> _|_ is *not* _|_ !
925+
flags &= !(has_ty_bot as uint);
918926
}
919927
&ty_closure(ref f) => {
920928
flags |= rflags(f.region);
921929
for f.sig.inputs.each |a| { flags |= get(a.ty).flags; }
922930
flags |= get(f.sig.output).flags;
931+
// T -> _|_ is *not* _|_ !
932+
flags &= !(has_ty_bot as uint);
923933
}
924934
}
925935

@@ -1465,7 +1475,13 @@ pub fn subst_substs(cx: ctxt, sup: &substs, sub: &substs) -> substs {
14651475
14661476
pub fn type_is_nil(ty: t) -> bool { get(ty).sty == ty_nil }
14671477
1468-
pub fn type_is_bot(ty: t) -> bool { get(ty).sty == ty_bot }
1478+
pub fn type_is_bot(ty: t) -> bool {
1479+
(get(ty).flags & (has_ty_bot as uint)) != 0
1480+
}
1481+
1482+
pub fn type_is_error(ty: t) -> bool {
1483+
(get(ty).flags & (has_ty_err as uint)) != 0
1484+
}
14691485
14701486
pub fn type_is_ty_var(ty: t) -> bool {
14711487
match get(ty).sty {

src/librustc/middle/typeck/check/_match.rs

+34-8
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,11 @@ use syntax::print::pprust;
2828
pub fn check_match(fcx: @mut FnCtxt,
2929
expr: @ast::expr,
3030
discrim: @ast::expr,
31-
arms: &[ast::arm]) -> bool {
31+
arms: &[ast::arm]) {
3232
let tcx = fcx.ccx.tcx;
33-
let mut bot;
3433

3534
let pattern_ty = fcx.infcx().next_ty_var();
36-
bot = check_expr_has_type(fcx, discrim, pattern_ty);
35+
check_expr_has_type(fcx, discrim, pattern_ty);
3736

3837
// Typecheck the patterns first, so that we get types for all the
3938
// bindings.
@@ -51,19 +50,46 @@ pub fn check_match(fcx: @mut FnCtxt,
5150
// Now typecheck the blocks.
5251
let mut result_ty = fcx.infcx().next_ty_var();
5352
let mut arm_non_bot = false;
53+
let mut saw_err = false;
5454
for arms.each |arm| {
55+
let mut guard_err = false;
56+
let mut guard_bot = false;
5557
match arm.guard {
56-
Some(e) => { check_expr_has_type(fcx, e, ty::mk_bool(tcx)); },
58+
Some(e) => {
59+
check_expr_has_type(fcx, e, ty::mk_bool(tcx));
60+
let e_ty = fcx.expr_ty(e);
61+
if ty::type_is_error(e_ty) {
62+
guard_err = true;
63+
}
64+
else if ty::type_is_bot(e_ty) {
65+
guard_bot = true;
66+
}
67+
},
5768
None => ()
5869
}
59-
if !check_block(fcx, &arm.body) { arm_non_bot = true; }
70+
check_block(fcx, &arm.body);
6071
let bty = fcx.node_ty(arm.body.node.id);
72+
saw_err = saw_err || ty::type_is_error(bty);
73+
if guard_err {
74+
fcx.write_error(arm.body.node.id);
75+
saw_err = true;
76+
}
77+
else if guard_bot {
78+
fcx.write_bot(arm.body.node.id);
79+
}
80+
else if !ty::type_is_bot(bty) {
81+
arm_non_bot = true; // If the match *may* evaluate to a non-_|_
82+
// expr, the whole thing is non-_|_
83+
}
6184
demand::suptype(fcx, arm.body.span, result_ty, bty);
6285
}
63-
bot |= !arm_non_bot;
64-
if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
86+
if saw_err {
87+
result_ty = ty::mk_err(tcx);
88+
}
89+
else if !arm_non_bot {
90+
result_ty = ty::mk_bot(tcx);
91+
}
6592
fcx.write_ty(expr.id, result_ty);
66-
return bot;
6793
}
6894

6995
pub struct pat_ctxt {

src/librustc/middle/typeck/check/method.rs

+4
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ pub enum TransformTypeFlag {
194194

195195
pub impl LookupContext/&self {
196196
fn do_lookup(&self, self_ty: ty::t) -> Option<method_map_entry> {
197+
let mut self_ty = structurally_resolved_type(self.fcx,
198+
self.self_expr.span,
199+
self_ty);
200+
197201
debug!("do_lookup(self_ty=%s, expr=%s, self_expr=%s)",
198202
self.ty_to_str(self_ty),
199203
expr_repr(self.tcx(), self.expr),

0 commit comments

Comments
 (0)