Skip to content

Commit 90d67b2

Browse files
committed
---
yaml --- r: 15829 b: refs/heads/try c: da98e14 h: refs/heads/master i: 15827: 1429139 v: v3
1 parent 31d4124 commit 90d67b2

File tree

4 files changed

+260
-268
lines changed

4 files changed

+260
-268
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
refs/heads/master: 61b1875c16de39c166b0f4d54bba19f9c6777d1a
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 4a81779abd786ff22d71434c6d9a5917ea4cdfff
5-
refs/heads/try: 8d1c1720e331ea56cfde33ab047216d232236e4b
5+
refs/heads/try: da98e14c946d8ac124b845d65c1a52065791febe
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105

branches/try/src/rustc/middle/typeck/check.rs

Lines changed: 258 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,15 @@ fn valid_range_bounds(ccx: @crate_ctxt, from: @ast::expr, to: @ast::expr)
559559
const_eval::compare_lit_exprs(ccx.tcx, from, to) <= 0
560560
}
561561

562+
type pat_ctxt = {
563+
fcx: @fn_ctxt,
564+
map: pat_id_map,
565+
alt_region: ty::region,
566+
block_region: ty::region,
567+
/* Equal to either alt_region or block_region. */
568+
pat_region: ty::region
569+
};
570+
562571
// Helper for the other universally_quantify_*() routines. Extracts the bound
563572
// regions from bound_tys and then replaces those same regions with fresh
564573
// variables in `sty`, returning the resulting type.
@@ -664,6 +673,223 @@ fn replace_bound_regions(
664673
}
665674
}
666675

676+
fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
677+
subpats: option<[@ast::pat]>, expected: ty::t) {
678+
679+
// Typecheck the path.
680+
let fcx = pcx.fcx;
681+
let tcx = pcx.fcx.ccx.tcx;
682+
683+
// Lookup the enum and variant def ids:
684+
let v_def = lookup_def(pcx.fcx, path.span, pat.id);
685+
let v_def_ids = ast_util::variant_def_ids(v_def);
686+
687+
// Assign the pattern the type of the *enum*, not the variant.
688+
let enum_tpt = ty::lookup_item_type(tcx, v_def_ids.enm);
689+
instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id);
690+
691+
// Take the enum type params out of `expected`.
692+
alt structure_of(pcx.fcx, pat.span, expected) {
693+
ty::ty_enum(_, expected_substs) {
694+
// check that the type of the value being matched is a subtype
695+
// of the type of the pattern:
696+
let pat_ty = fcx.node_ty(pat.id);
697+
demand::suptype(fcx, pat.span, pat_ty, expected);
698+
699+
// Get the expected types of the arguments.
700+
let arg_types = {
701+
let vinfo =
702+
ty::enum_variant_with_id(
703+
tcx, v_def_ids.enm, v_def_ids.var);
704+
vinfo.args.map { |t| ty::subst(tcx, expected_substs, t) }
705+
};
706+
let arg_len = arg_types.len(), subpats_len = alt subpats {
707+
none { arg_len }
708+
some(ps) { ps.len() }};
709+
if arg_len > 0u {
710+
// N-ary variant.
711+
if arg_len != subpats_len {
712+
let s = #fmt["this pattern has %u field%s, but the \
713+
corresponding variant has %u field%s",
714+
subpats_len,
715+
if subpats_len == 1u { "" } else { "s" },
716+
arg_len,
717+
if arg_len == 1u { "" } else { "s" }];
718+
tcx.sess.span_fatal(pat.span, s);
719+
}
720+
721+
option::iter(subpats) {|pats|
722+
vec::iter2(pats, arg_types) {|subpat, arg_ty|
723+
check_pat(pcx, subpat, arg_ty);
724+
}
725+
};
726+
} else if subpats_len > 0u {
727+
tcx.sess.span_fatal
728+
(pat.span, #fmt["this pattern has %u field%s, \
729+
but the corresponding variant has no fields",
730+
subpats_len,
731+
if subpats_len == 1u { "" }
732+
else { "s" }]);
733+
}
734+
}
735+
_ {
736+
tcx.sess.span_fatal
737+
(pat.span,
738+
#fmt["mismatched types: expected enum but found `%s`",
739+
fcx.ty_to_str(expected)]);
740+
}
741+
}
742+
}
743+
744+
// Pattern checking is top-down rather than bottom-up so that bindings get
745+
// their types immediately.
746+
fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
747+
let fcx = pcx.fcx;
748+
let tcx = pcx.fcx.ccx.tcx;
749+
alt pat.node {
750+
ast::pat_wild {
751+
fcx.write_ty(pat.id, expected);
752+
}
753+
ast::pat_lit(lt) {
754+
check_expr_with(pcx.fcx, lt, expected);
755+
fcx.write_ty(pat.id, fcx.expr_ty(lt));
756+
}
757+
ast::pat_range(begin, end) {
758+
check_expr_with(pcx.fcx, begin, expected);
759+
check_expr_with(pcx.fcx, end, expected);
760+
let b_ty = resolve_type_vars_if_possible(pcx.fcx,
761+
fcx.expr_ty(begin));
762+
if !require_same_types(
763+
tcx, pat.span, b_ty,
764+
resolve_type_vars_if_possible(
765+
pcx.fcx, fcx.expr_ty(end)),
766+
{|| "mismatched types in range" }) {
767+
// no-op
768+
} else if !ty::type_is_numeric(b_ty) {
769+
tcx.sess.span_err(pat.span, "non-numeric type used in range");
770+
} else if !valid_range_bounds(pcx.fcx.ccx, begin, end) {
771+
tcx.sess.span_err(begin.span, "lower range bound must be less \
772+
than upper");
773+
}
774+
fcx.write_ty(pat.id, b_ty);
775+
}
776+
ast::pat_ident(name, sub) if !pat_is_variant(tcx.def_map, pat) {
777+
let vid = lookup_local(pcx.fcx, pat.span, pat.id);
778+
let mut typ = ty::mk_var(tcx, vid);
779+
demand::suptype(pcx.fcx, pat.span, expected, typ);
780+
let canon_id = pcx.map.get(pat_util::path_to_ident(name));
781+
if canon_id != pat.id {
782+
let tv_id = lookup_local(pcx.fcx, pat.span, canon_id);
783+
let ct = ty::mk_var(tcx, tv_id);
784+
demand::suptype(pcx.fcx, pat.span, ct, typ);
785+
}
786+
fcx.write_ty(pat.id, typ);
787+
alt sub {
788+
some(p) { check_pat(pcx, p, expected); }
789+
_ {}
790+
}
791+
}
792+
ast::pat_ident(path, c) {
793+
check_pat_variant(pcx, pat, path, some([]), expected);
794+
}
795+
ast::pat_enum(path, subpats) {
796+
check_pat_variant(pcx, pat, path, subpats, expected);
797+
}
798+
ast::pat_rec(fields, etc) {
799+
let ex_fields = alt structure_of(pcx.fcx, pat.span, expected) {
800+
ty::ty_rec(fields) { fields }
801+
_ {
802+
tcx.sess.span_fatal
803+
(pat.span,
804+
#fmt["mismatched types: expected `%s` but found record",
805+
fcx.ty_to_str(expected)]);
806+
}
807+
};
808+
let f_count = vec::len(fields);
809+
let ex_f_count = vec::len(ex_fields);
810+
if ex_f_count < f_count || !etc && ex_f_count > f_count {
811+
tcx.sess.span_fatal
812+
(pat.span, #fmt["mismatched types: expected a record \
813+
with %u fields, found one with %u \
814+
fields",
815+
ex_f_count, f_count]);
816+
}
817+
fn matches(name: str, f: ty::field) -> bool {
818+
ret str::eq(name, f.ident);
819+
}
820+
for fields.each {|f|
821+
alt vec::find(ex_fields, bind matches(f.ident, _)) {
822+
some(field) {
823+
check_pat(pcx, f.pat, field.mt.ty);
824+
}
825+
none {
826+
tcx.sess.span_fatal(pat.span,
827+
#fmt["mismatched types: did not \
828+
expect a record with a field `%s`",
829+
f.ident]);
830+
}
831+
}
832+
}
833+
fcx.write_ty(pat.id, expected);
834+
}
835+
ast::pat_tup(elts) {
836+
let ex_elts = alt structure_of(pcx.fcx, pat.span, expected) {
837+
ty::ty_tup(elts) { elts }
838+
_ {
839+
tcx.sess.span_fatal
840+
(pat.span,
841+
#fmt["mismatched types: expected `%s`, found tuple",
842+
fcx.ty_to_str(expected)]);
843+
}
844+
};
845+
let e_count = vec::len(elts);
846+
if e_count != vec::len(ex_elts) {
847+
tcx.sess.span_fatal
848+
(pat.span, #fmt["mismatched types: expected a tuple \
849+
with %u fields, found one with %u \
850+
fields", vec::len(ex_elts), e_count]);
851+
}
852+
let mut i = 0u;
853+
for elts.each {|elt|
854+
check_pat(pcx, elt, ex_elts[i]);
855+
i += 1u;
856+
}
857+
858+
fcx.write_ty(pat.id, expected);
859+
}
860+
ast::pat_box(inner) {
861+
alt structure_of(pcx.fcx, pat.span, expected) {
862+
ty::ty_box(e_inner) {
863+
check_pat(pcx, inner, e_inner.ty);
864+
fcx.write_ty(pat.id, expected);
865+
}
866+
_ {
867+
tcx.sess.span_fatal(
868+
pat.span,
869+
"mismatched types: expected `" +
870+
pcx.fcx.ty_to_str(expected) +
871+
"` found box");
872+
}
873+
}
874+
}
875+
ast::pat_uniq(inner) {
876+
alt structure_of(pcx.fcx, pat.span, expected) {
877+
ty::ty_uniq(e_inner) {
878+
check_pat(pcx, inner, e_inner.ty);
879+
fcx.write_ty(pat.id, expected);
880+
}
881+
_ {
882+
tcx.sess.span_fatal(
883+
pat.span,
884+
"mismatched types: expected `" +
885+
pcx.fcx.ty_to_str(expected) +
886+
"` found uniq");
887+
}
888+
}
889+
}
890+
}
891+
}
892+
667893
fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool {
668894
check_expr(fcx, expr, some(expected))
669895
}
@@ -1644,7 +1870,38 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
16441870
bot = !may_break(body);
16451871
}
16461872
ast::expr_alt(discrim, arms, _) {
1647-
alt::check_alt(expr, discrim, arms);
1873+
let pattern_ty = fcx.next_ty_var();
1874+
bot = check_expr_with(fcx, discrim, pattern_ty);
1875+
1876+
// Typecheck the patterns first, so that we get types for all the
1877+
// bindings.
1878+
//let pattern_ty = fcx.expr_ty(discrim);
1879+
for arms.each {|arm|
1880+
let pcx = {
1881+
fcx: fcx,
1882+
map: pat_id_map(tcx.def_map, arm.pats[0]),
1883+
alt_region: ty::re_scope(expr.id),
1884+
block_region: ty::re_scope(arm.body.node.id),
1885+
pat_region: ty::re_scope(expr.id)
1886+
};
1887+
1888+
for arm.pats.each {|p| check_pat(pcx, p, pattern_ty);}
1889+
}
1890+
// Now typecheck the blocks.
1891+
let mut result_ty = fcx.next_ty_var();
1892+
let mut arm_non_bot = false;
1893+
for arms.each {|arm|
1894+
alt arm.guard {
1895+
some(e) { check_expr_with(fcx, e, ty::mk_bool(tcx)); }
1896+
none { }
1897+
}
1898+
if !check_block(fcx, arm.body) { arm_non_bot = true; }
1899+
let bty = fcx.node_ty(arm.body.node.id);
1900+
demand::suptype(fcx, arm.body.span, result_ty, bty);
1901+
}
1902+
bot |= !arm_non_bot;
1903+
if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
1904+
fcx.write_ty(id, result_ty);
16481905
}
16491906
ast::expr_fn(proto, decl, body, cap_clause) {
16501907
check_expr_fn(fcx, expr, proto, decl, body, false, expected);

0 commit comments

Comments
 (0)