Resolve and typecheck patterns in pattern alt.

This commit is contained in:
Roy Frostig 2010-06-24 08:13:32 -07:00
parent f038f4d533
commit bc286c7f2c
9 changed files with 220 additions and 77 deletions

View file

@ -331,6 +331,7 @@ TEST_XFAILS_X86 := test/run-pass/mlist-cycle.rs \
TEST_XFAILS_LLVM := $(addprefix test/run-pass/, \
acyclic-unwind.rs \
alt-pattern-simple.rs \
alt-tag.rs \
argv.rs \
basic.rs \

View file

@ -300,7 +300,7 @@ and domain =
and pat =
PAT_lit of lit
| PAT_tag of ident * (pat array)
| PAT_tag of ((name identified) * (pat array))
| PAT_slot of ((slot identified) * ident)
| PAT_wild

View file

@ -224,24 +224,29 @@ and parse_stmts (ps:pstate) : Ast.stmt array =
let (stmts, lval) = bracketed LPAREN RPAREN parse_lval ps in
let rec parse_pat ps =
match peek ps with
IDENT ident ->
IDENT _ ->
let apos = lexpos ps in
bump ps;
let name = Pexp.parse_name ps in
let bpos = lexpos ps in
(* TODO: nullary constructors *)
if peek ps != LPAREN then
let slot =
{ Ast.slot_mode = Ast.MODE_interior;
Ast.slot_mutable = false;
Ast.slot_ty = None }
in
Ast.PAT_slot ((span ps apos bpos slot), ident)
begin
match name with
Ast.NAME_base (Ast.BASE_ident ident) ->
let slot =
{ Ast.slot_mode = Ast.MODE_interior;
Ast.slot_mutable = false;
Ast.slot_ty = None }
in
Ast.PAT_slot
((span ps apos bpos slot), ident)
|_ -> raise (unexpected ps)
end
else
let pats =
paren_comma_list parse_pat ps
in
Ast.PAT_tag (ident, pats)
Ast.PAT_tag ((span ps apos bpos name), pats)
| LIT_INT _ | LIT_CHAR _ | LIT_BOOL _ ->
Ast.PAT_lit (Pexp.parse_lit ps)
| UNDERSCORE -> bump ps; Ast.PAT_wild

View file

@ -870,28 +870,61 @@ let pattern_resolving_visitor
(cx:ctxt)
(scopes:scope list ref)
(inner:Walk.visitor) : Walk.visitor =
let not_tag_ctor (nid:Ast.name identified) : unit =
err (Some nid.id) "'%s' is not a tag constructor"
(string_of_name nid.node)
in
let resolve_pat_tag
(namei:Ast.name identified)
(pats:Ast.pat array)
(tag_ctor_id:node_id)
: unit =
let tag_ty =
fn_output_ty
(Hashtbl.find cx.ctxt_all_item_types tag_ctor_id)
in
begin
match tag_ty with
Ast.TY_tag _
| Ast.TY_iso _ ->
let tag_ty_tup = tag_or_iso_ty_tup_by_name tag_ty namei.node in
let arity = Array.length tag_ty_tup in
if (Array.length pats) == arity
then Hashtbl.add cx.ctxt_pattag_to_item namei.id tag_ctor_id
else err (Some namei.id)
"tag pattern '%s' with wrong number of components"
(string_of_name namei.node)
| _ -> not_tag_ctor namei
end
in
let resolve_arm { node = arm } =
match fst arm with
Ast.PAT_tag (namei, pats) ->
begin
match lookup_by_name cx !scopes namei.node with
None ->
err (Some namei.id) "unresolved tag constructor '%s'"
(string_of_name namei.node)
| Some (_, tag_ctor_id) when referent_is_item cx tag_ctor_id ->
(*
* FIXME we should actually check here that the function
* is a tag value-ctor. For now this actually allows any
* function returning a tag type to pass as a tag pattern.
*)
resolve_pat_tag namei pats tag_ctor_id
|_ -> not_tag_ctor namei
end
| _ -> ()
in
let visit_stmt_pre stmt =
begin
match stmt.node with
Ast.STMT_alt_tag { Ast.alt_tag_lval = _; Ast.alt_tag_arms = arms } ->
let resolve_arm { node = arm } =
match fst arm with
Ast.PAT_tag (ident, _) ->
begin
match lookup_by_ident cx !scopes ident with
None ->
err None "unresolved tag constructor '%s'" ident
| Some (_, tag_id) ->
match Hashtbl.find cx.ctxt_all_defns tag_id with
DEFN_item {
Ast.decl_item = Ast.MOD_ITEM_tag _
} -> ()
| _ ->
err None "'%s' is not a tag constructor" ident
end
| _ -> ()
in
Array.iter resolve_arm arms
| _ -> ()
end;

View file

@ -102,6 +102,7 @@ type ctxt =
(* reference id --> definition id *)
ctxt_lval_to_referent: (node_id,node_id) Hashtbl.t;
ctxt_pattag_to_item: (node_id,node_id) Hashtbl.t;
ctxt_required_items: (node_id, (required_lib * nabi_conv)) Hashtbl.t;
ctxt_required_syms: (node_id, string) Hashtbl.t;
@ -186,6 +187,7 @@ let new_ctxt sess abi crate =
ctxt_all_lvals = Hashtbl.create 0;
ctxt_all_defns = Hashtbl.create 0;
ctxt_lval_to_referent = Hashtbl.create 0;
ctxt_pattag_to_item = Hashtbl.create 0;
ctxt_required_items = crate.Ast.crate_required;
ctxt_required_syms = crate.Ast.crate_required_syms;
@ -396,6 +398,27 @@ let slot_ty (s:Ast.slot) : Ast.ty =
| None -> bug () "untyped slot"
;;
let fn_output_ty (fn_ty:Ast.ty) : Ast.ty =
match fn_ty with
Ast.TY_fn ({ Ast.sig_output_slot = slot }, _) ->
begin
match slot.Ast.slot_ty with
Some ty -> ty
| None -> bug () "function has untyped output slot"
end
| _ -> bug () "fn_output_ty on non-TY_fn"
;;
let tag_or_iso_ty_tup_by_name (ty:Ast.ty) (name:Ast.name) : Ast.ty_tup =
match ty with
Ast.TY_tag tags ->
Hashtbl.find tags name
| Ast.TY_iso { Ast.iso_index = i; Ast.iso_group = gp } ->
Hashtbl.find gp.(i) name
| _ ->
bug () "tag_or_iso_ty_tup_by_name called with non-tag or -iso type"
;;
let defn_is_slot (d:defn) : bool =
match d with
DEFN_slot _ -> true

View file

@ -3757,7 +3757,8 @@ let trans_visitor
emit (Il.jmp Il.JNE Il.CodeNone);
[ next_jump ]
| Ast.PAT_tag (ident, pats) ->
| Ast.PAT_tag (tag_namei, pats) ->
let tag_name = tag_namei.node in
let ty_tag =
match ty with
Ast.TY_tag tag_ty -> tag_ty
@ -3765,7 +3766,6 @@ let trans_visitor
| _ -> bug cx "expected tag type"
in
let tag_keys = sorted_htab_keys ty_tag in
let tag_name = Ast.NAME_base (Ast.BASE_ident ident) in
let tag_number = arr_idx tag_keys tag_name in
let ty_tup = Hashtbl.find ty_tag tag_name in

View file

@ -165,6 +165,7 @@ let process_crate (cx:ctxt) (crate:Ast.crate) : unit =
cx.ctxt_sess.Session.sess_log_type
cx.ctxt_sess.Session.sess_log_out
in
let retval_tvs = Stack.create () in
let push_retval_tv tv =
Stack.push tv retval_tvs
@ -175,6 +176,18 @@ let process_crate (cx:ctxt) (crate:Ast.crate) : unit =
let retval_tv _ =
Stack.top retval_tvs
in
let pat_tvs = Stack.create () in
let push_pat_tv tv =
Stack.push tv pat_tvs
in
let pop_pat_tv _ =
ignore (Stack.pop pat_tvs)
in
let pat_tv _ =
Stack.top pat_tvs
in
let (bindings:(node_id, tyvar) Hashtbl.t) = Hashtbl.create 10 in
let (item_params:(node_id, tyvar array) Hashtbl.t) = Hashtbl.create 10 in
let (lval_tyvars:(node_id, tyvar) Hashtbl.t) = Hashtbl.create 0 in
@ -737,23 +750,36 @@ let process_crate (cx:ctxt) (crate:Ast.crate) : unit =
a := TYSPEC_equiv c;
b := TYSPEC_equiv c
and unify_ty_parametric
(ty:Ast.ty)
(tps:Ast.ty_param array)
(tv:tyvar)
: unit =
unify_tyvars (ref (TYSPEC_resolved (tps, ty))) tv
and unify_ty (ty:Ast.ty) (tv:tyvar) : unit =
unify_tyvars (ref (TYSPEC_resolved ([||], ty))) tv
unify_ty_parametric ty [||] tv
in
let rec unify_atom (atom:Ast.atom) (tv:tyvar) : unit =
let rec unify_lit (lit:Ast.lit) (tv:tyvar) : unit =
let ty =
match lit with
Ast.LIT_nil -> Ast.TY_nil
| Ast.LIT_bool _ -> Ast.TY_bool
| Ast.LIT_mach (mty, _, _) -> Ast.TY_mach mty
| Ast.LIT_int (_, _) -> Ast.TY_int
| Ast.LIT_uint (_, _) -> Ast.TY_uint
| Ast.LIT_char _ -> Ast.TY_char
in
unify_ty ty tv
and unify_atom (atom:Ast.atom) (tv:tyvar) : unit =
match atom with
Ast.ATOM_literal { node = literal; id = _ } ->
let ty = match literal with
Ast.LIT_nil -> Ast.TY_nil
| Ast.LIT_bool _ -> Ast.TY_bool
| Ast.LIT_mach (mty, _, _) -> Ast.TY_mach mty
| Ast.LIT_int (_, _) -> Ast.TY_int
| Ast.LIT_uint (_, _) -> Ast.TY_uint
| Ast.LIT_char _ -> Ast.TY_char
in
unify_ty ty tv
| Ast.ATOM_lval lval -> unify_lval lval tv
unify_lit literal tv
| Ast.ATOM_lval lval ->
unify_lval lval tv
and unify_expr (expr:Ast.expr) (tv:tyvar) : unit =
match expr with
@ -886,39 +912,40 @@ let process_crate (cx:ctxt) (crate:Ast.crate) : unit =
| Ast.BASE_app (_, args) ->
note_args args;
ref (TYSPEC_app (tv, args))
| _ -> err None "bad lval / tyspec combination"
in
unify_tyvars (ref spec) tv
end
| Ast.LVAL_ext (base, comp) ->
let base_ts = match comp with
Ast.COMP_named (Ast.COMP_ident id) ->
let names = Hashtbl.create 1 in
Hashtbl.add names id tv;
TYSPEC_dictionary names
| _ -> err None "bad lval / tyspec combination"
in
unify_tyvars (ref spec) tv
end
| Ast.LVAL_ext (base, comp) ->
let base_ts = match comp with
Ast.COMP_named (Ast.COMP_ident id) ->
let names = Hashtbl.create 1 in
Hashtbl.add names id tv;
TYSPEC_dictionary names
| Ast.COMP_named (Ast.COMP_app (id, args)) ->
note_args args;
let tv = ref (TYSPEC_app (tv, args)) in
let names = Hashtbl.create 1 in
Hashtbl.add names id tv;
TYSPEC_dictionary names
| Ast.COMP_named (Ast.COMP_app (id, args)) ->
note_args args;
let tv = ref (TYSPEC_app (tv, args)) in
let names = Hashtbl.create 1 in
Hashtbl.add names id tv;
TYSPEC_dictionary names
| Ast.COMP_named (Ast.COMP_idx i) ->
let init j = if i + 1 == j then tv else ref TYSPEC_all in
TYSPEC_tuple (Array.init (i + 1) init)
| Ast.COMP_named (Ast.COMP_idx i) ->
let init j = if i + 1 == j then tv else ref TYSPEC_all in
TYSPEC_tuple (Array.init (i + 1) init)
| Ast.COMP_atom atom ->
unify_atom atom (ref (TYSPEC_resolved ([||], Ast.TY_int)));
TYSPEC_collection tv
in
let base_tv = ref base_ts in
unify_lval' base base_tv;
match !(resolve_tyvar base_tv) with
TYSPEC_resolved (_, ty) ->
unify_ty (slot_ty (project_type_to_slot ty comp)) tv
| _ ->
()
| Ast.COMP_atom atom ->
unify_atom atom
(ref (TYSPEC_resolved ([||], Ast.TY_int)));
TYSPEC_collection tv
in
let base_tv = ref base_ts in
unify_lval' base base_tv;
match !(resolve_tyvar base_tv) with
TYSPEC_resolved (_, ty) ->
unify_ty (slot_ty (project_type_to_slot ty comp)) tv
| _ ->
()
and unify_lval (lval:Ast.lval) (tv:tyvar) : unit =
let id = lval_base_id lval in
@ -1080,6 +1107,12 @@ let process_crate (cx:ctxt) (crate:Ast.crate) : unit =
unify_lval seq seq_tv;
unify_slot si.node (Some si.id) mem_tv
| Ast.STMT_alt_tag
{ Ast.alt_tag_lval = lval; Ast.alt_tag_arms = arms } ->
let lval_tv = ref TYSPEC_all in
unify_lval lval lval_tv;
Array.iter (fun _ -> push_pat_tv lval_tv) arms
(* FIXME (issue #52): plenty more to handle here. *)
| _ ->
log cx "warning: not typechecking stmt %s\n"
@ -1163,13 +1196,54 @@ let process_crate (cx:ctxt) (crate:Ast.crate) : unit =
| _ -> ()
in
let visit_pat_pre (pat:Ast.pat) : unit =
let expected = pat_tv() in
match pat with
Ast.PAT_lit lit -> unify_lit lit expected
| Ast.PAT_tag (namei, _) ->
let expect ty =
let tv = ref TYSPEC_all in
unify_ty ty tv;
push_pat_tv tv;
in
let item_id = Hashtbl.find cx.ctxt_pattag_to_item namei.id in
let tag_ty =
fn_output_ty (Hashtbl.find cx.ctxt_all_item_types item_id)
in
let tag_ty_tup = tag_or_iso_ty_tup_by_name tag_ty namei.node in
let tag_tv = ref TYSPEC_all in
unify_ty tag_ty tag_tv;
unify_tyvars expected tag_tv;
(* FIXME check arity here? *)
List.iter
begin
fun slot ->
match slot.Ast.slot_ty with
Some ty -> expect ty
| None -> bug () "no slot type in tag slot tuple"
end
(List.rev (Array.to_list tag_ty_tup));
| Ast.PAT_slot (sloti, _) ->
unify_slot sloti.node (Some sloti.id) expected
| Ast.PAT_wild -> ()
in
let visit_pat_post (_:Ast.pat) : unit =
pop_pat_tv()
in
{
inner with
Walk.visit_mod_item_pre = visit_mod_item_pre;
Walk.visit_mod_item_post = visit_mod_item_post;
Walk.visit_obj_fn_pre = visit_obj_fn_pre;
Walk.visit_obj_fn_post = visit_obj_fn_post;
Walk.visit_stmt_pre = visit_stmt_pre
Walk.visit_stmt_pre = visit_stmt_pre;
Walk.visit_pat_pre = visit_pat_pre;
Walk.visit_pat_post = visit_pat_post;
}
in
@ -1223,7 +1297,7 @@ let process_crate (cx:ctxt) (crate:Ast.crate) : unit =
Hashtbl.find bindings id
in
match defn with
DEFN_item ({ Ast.decl_item=Ast.MOD_ITEM_mod _ } as item) ->
DEFN_item ({ Ast.decl_item = Ast.MOD_ITEM_mod _ } as item) ->
ignore (tv_of_item id item)
| _ -> ()
in

View file

@ -652,10 +652,10 @@ and walk_pat
(v:visitor)
(p:Ast.pat)
: unit =
let rec walk p =
let walk p =
match p with
Ast.PAT_lit lit -> walk_lit v lit
| Ast.PAT_tag (_, pats) -> Array.iter walk pats
| Ast.PAT_tag (_, pats) -> Array.iter (walk_pat v) pats
| Ast.PAT_slot (si, _) -> walk_slot_identified v si
| Ast.PAT_wild -> ()
in

View file

@ -0,0 +1,7 @@
fn altsimple(int f) {
alt (f) {
case (x) {}
}
}
fn main() {}