Skip to content

Commit 241305c

Browse files
committed
Resolve and typecheck patterns in pattern alt redux. This time featuring way more correctness.
1 parent 0d9565a commit 241305c

File tree

8 files changed

+142
-81
lines changed

8 files changed

+142
-81
lines changed

src/boot/fe/ast.ml

+7-1
Original file line numberDiff line numberDiff line change
@@ -299,9 +299,14 @@ and domain =
299299
DOMAIN_local
300300
| DOMAIN_thread
301301

302+
(*
303+
* PAT_tag uses lval for the tag constructor so that we can reuse our lval
304+
* resolving machinery. The lval is restricted during parsing to have only
305+
* named components.
306+
*)
302307
and pat =
303308
PAT_lit of lit
304-
| PAT_tag of ((name identified) * (pat array))
309+
| PAT_tag of (lval * (pat array))
305310
| PAT_slot of ((slot identified) * ident)
306311
| PAT_wild
307312

@@ -331,6 +336,7 @@ and lval_component =
331336
| COMP_atom of atom
332337

333338

339+
(* identifying the name_base here is sufficient to identify the full lval *)
334340
and lval =
335341
LVAL_base of name_base identified
336342
| LVAL_ext of (lval * lval_component)

src/boot/fe/item.ml

+16-14
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ and parse_auto_slot_and_init
127127

128128
and parse_stmts (ps:pstate) : Ast.stmt array =
129129
let apos = lexpos ps in
130+
131+
let rec name_to_lval (apos:pos) (bpos:pos) (name:Ast.name)
132+
: Ast.lval =
133+
match name with
134+
Ast.NAME_base nb ->
135+
Ast.LVAL_base (span ps apos bpos nb)
136+
| Ast.NAME_ext (n, nc) ->
137+
Ast.LVAL_ext (name_to_lval apos bpos n, Ast.COMP_named nc)
138+
in
139+
130140
match peek ps with
131141

132142
LOG ->
@@ -139,15 +149,6 @@ and parse_stmts (ps:pstate) : Ast.stmt array =
139149
bump ps;
140150
begin
141151

142-
let rec name_to_lval (bpos:pos) (name:Ast.name)
143-
: Ast.lval =
144-
match name with
145-
Ast.NAME_base nb ->
146-
Ast.LVAL_base (span ps apos bpos nb)
147-
| Ast.NAME_ext (n, nc) ->
148-
Ast.LVAL_ext (name_to_lval bpos n, Ast.COMP_named nc)
149-
in
150-
151152
let rec carg_path_to_lval (bpos:pos) (path:Ast.carg_path)
152153
: Ast.lval =
153154
match path with
@@ -171,7 +172,7 @@ and parse_stmts (ps:pstate) : Ast.stmt array =
171172

172173
let synthesise_check_call (bpos:pos) (constr:Ast.constr)
173174
: (Ast.lval * (Ast.atom array)) =
174-
let lval = name_to_lval bpos constr.Ast.constr_name in
175+
let lval = name_to_lval apos bpos constr.Ast.constr_name in
175176
let args =
176177
Array.map (carg_to_atom bpos) constr.Ast.constr_args
177178
in
@@ -243,13 +244,14 @@ and parse_stmts (ps:pstate) : Ast.stmt array =
243244
|_ -> raise (unexpected ps)
244245
end
245246
else
246-
let pats =
247-
paren_comma_list parse_pat ps
248-
in
249-
Ast.PAT_tag ((span ps apos bpos name), pats)
247+
let lv = name_to_lval apos bpos name in
248+
Ast.PAT_tag (lv, paren_comma_list parse_pat ps)
249+
250250
| LIT_INT _ | LIT_CHAR _ | LIT_BOOL _ ->
251251
Ast.PAT_lit (Pexp.parse_lit ps)
252+
252253
| UNDERSCORE -> bump ps; Ast.PAT_wild
254+
253255
| tok -> raise (Parse_err (ps,
254256
"Expected pattern but found '" ^
255257
(string_of_tok tok) ^ "'"))

src/boot/me/resolve.ml

+32-31
Original file line numberDiff line numberDiff line change
@@ -868,56 +868,57 @@ let resolve_recursion
868868

869869
let pattern_resolving_visitor
870870
(cx:ctxt)
871-
(scopes:scope list ref)
872871
(inner:Walk.visitor) : Walk.visitor =
873872

874-
let not_tag_ctor (nid:Ast.name identified) : unit =
875-
err (Some nid.id) "'%s' is not a tag constructor"
876-
(string_of_name nid.node)
873+
let not_tag_ctor nm id : unit =
874+
err (Some id) "'%s' is not a tag constructor" (string_of_name nm)
877875
in
878876

879877
let resolve_pat_tag
880-
(namei:Ast.name identified)
878+
(name:Ast.name)
879+
(id:node_id)
881880
(pats:Ast.pat array)
882881
(tag_ctor_id:node_id)
883882
: unit =
884883

884+
(* NB this isn't really the proper tag type, since we aren't applying any
885+
* type parameters from the tag constructor in the pattern, but since we
886+
* are only looking at the fact that it's a tag-like type at all, and
887+
* asking for its arity, it doesn't matter that the possibly parametric
888+
* tag type has its parameters unbound here. *)
885889
let tag_ty =
886-
fn_output_ty
887-
(Hashtbl.find cx.ctxt_all_item_types tag_ctor_id)
890+
fn_output_ty (Hashtbl.find cx.ctxt_all_item_types tag_ctor_id)
888891
in
889892
begin
890893
match tag_ty with
891894
Ast.TY_tag _
892895
| Ast.TY_iso _ ->
893-
let tag_ty_tup = tag_or_iso_ty_tup_by_name tag_ty namei.node in
896+
let tag_ty_tup = tag_or_iso_ty_tup_by_name tag_ty name in
894897
let arity = Array.length tag_ty_tup in
895-
if (Array.length pats) == arity
896-
then Hashtbl.add cx.ctxt_pattag_to_item namei.id tag_ctor_id
897-
else err (Some namei.id)
898-
"tag pattern '%s' with wrong number of components"
899-
(string_of_name namei.node)
900-
| _ -> not_tag_ctor namei
898+
if (Array.length pats) != arity
899+
then
900+
err (Some id)
901+
"tag pattern '%s' with wrong number of components"
902+
(string_of_name name)
903+
else ()
904+
| _ -> not_tag_ctor name id
901905
end
902906
in
903907

904908
let resolve_arm { node = arm } =
905909
match fst arm with
906-
Ast.PAT_tag (namei, pats) ->
907-
begin
908-
match lookup_by_name cx !scopes namei.node with
909-
None ->
910-
err (Some namei.id) "unresolved tag constructor '%s'"
911-
(string_of_name namei.node)
912-
| Some (_, tag_ctor_id) when referent_is_item cx tag_ctor_id ->
913-
(*
914-
* FIXME we should actually check here that the function
915-
* is a tag value-ctor. For now this actually allows any
916-
* function returning a tag type to pass as a tag pattern.
917-
*)
918-
resolve_pat_tag namei pats tag_ctor_id
919-
|_ -> not_tag_ctor namei
920-
end
910+
Ast.PAT_tag (lval, pats) ->
911+
let lval_nm = lval_to_name lval in
912+
let lval_id = lval_base_id lval in
913+
let tag_ctor_id = lval_to_referent cx lval_id in
914+
if referent_is_item cx tag_ctor_id
915+
(*
916+
* FIXME we should actually check here that the function
917+
* is a tag value-ctor. For now this actually allows any
918+
* function returning a tag type to pass as a tag pattern.
919+
*)
920+
then resolve_pat_tag lval_nm lval_id pats tag_ctor_id
921+
else not_tag_ctor lval_nm lval_id
921922
| _ -> ()
922923
in
923924

@@ -968,8 +969,8 @@ let process_crate
968969
let passes_2 =
969970
[|
970971
(scope_stack_managing_visitor scopes
971-
(pattern_resolving_visitor cx scopes
972-
Walk.empty_visitor))
972+
(pattern_resolving_visitor cx
973+
Walk.empty_visitor))
973974
|]
974975
in
975976
log cx "running primary resolve passes";

src/boot/me/semant.ml

+38-9
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ type ctxt =
102102

103103
(* reference id --> definition id *)
104104
ctxt_lval_to_referent: (node_id,node_id) Hashtbl.t;
105-
ctxt_pattag_to_item: (node_id,node_id) Hashtbl.t;
106105

107106
ctxt_required_items: (node_id, (required_lib * nabi_conv)) Hashtbl.t;
108107
ctxt_required_syms: (node_id, string) Hashtbl.t;
@@ -187,7 +186,6 @@ let new_ctxt sess abi crate =
187186
ctxt_all_lvals = Hashtbl.create 0;
188187
ctxt_all_defns = Hashtbl.create 0;
189188
ctxt_lval_to_referent = Hashtbl.create 0;
190-
ctxt_pattag_to_item = Hashtbl.create 0;
191189
ctxt_required_items = crate.Ast.crate_required;
192190
ctxt_required_syms = crate.Ast.crate_required_syms;
193191

@@ -409,14 +407,29 @@ let fn_output_ty (fn_ty:Ast.ty) : Ast.ty =
409407
| _ -> bug () "fn_output_ty on non-TY_fn"
410408
;;
411409

410+
(* name of tag constructor function -> name for indexing in the ty_tag *)
411+
let rec tag_ctor_name_to_tag_name (name:Ast.name) : Ast.name =
412+
match name with
413+
Ast.NAME_base nb ->
414+
begin
415+
match nb with
416+
Ast.BASE_ident _ -> name
417+
| Ast.BASE_app (id, _) -> Ast.NAME_base (Ast.BASE_ident id)
418+
| _ ->
419+
bug () "tag_or_iso_ty_tup_by_name with non-tag-ctor name"
420+
end
421+
| Ast.NAME_ext (inner_name, _) -> tag_ctor_name_to_tag_name inner_name
422+
;;
423+
412424
let tag_or_iso_ty_tup_by_name (ty:Ast.ty) (name:Ast.name) : Ast.ty_tup =
413-
match ty with
414-
Ast.TY_tag tags ->
415-
Hashtbl.find tags name
416-
| Ast.TY_iso { Ast.iso_index = i; Ast.iso_group = gp } ->
417-
Hashtbl.find gp.(i) name
418-
| _ ->
419-
bug () "tag_or_iso_ty_tup_by_name called with non-tag or -iso type"
425+
let tagname = tag_ctor_name_to_tag_name name in
426+
match ty with
427+
Ast.TY_tag tags ->
428+
Hashtbl.find tags tagname
429+
| Ast.TY_iso { Ast.iso_index = i; Ast.iso_group = gp } ->
430+
Hashtbl.find gp.(i) tagname
431+
| _ ->
432+
bug () "tag_or_iso_ty_tup_by_name called with non-tag or -iso type"
420433
;;
421434

422435
let defn_is_slot (d:defn) : bool =
@@ -499,6 +512,22 @@ let atoms_to_names (atoms:Ast.atom array)
499512
atoms
500513
;;
501514

515+
let rec lval_to_name (lv:Ast.lval) : Ast.name =
516+
match lv with
517+
Ast.LVAL_base { node = nb } ->
518+
Ast.NAME_base nb
519+
| Ast.LVAL_ext (lv, lv_comp) ->
520+
let comp =
521+
begin
522+
match lv_comp with
523+
Ast.COMP_named comp -> comp
524+
| _ -> bug ()
525+
"lval_to_name with lval that contains non-name components"
526+
end
527+
in
528+
Ast.NAME_ext (lval_to_name lv, comp)
529+
;;
530+
502531
let rec lval_base_id (lv:Ast.lval) : node_id =
503532
match lv with
504533
Ast.LVAL_base nbi -> nbi.id

src/boot/me/trans.ml

+2-2
Original file line numberDiff line numberDiff line change
@@ -3761,8 +3761,8 @@ let trans_visitor
37613761
Ast.PAT_lit lit ->
37623762
trans_compare Il.JNE (trans_lit lit) (Il.Cell src_cell)
37633763

3764-
| Ast.PAT_tag (tag_namei, pats) ->
3765-
let tag_name = tag_namei.node in
3764+
| Ast.PAT_tag (lval, pats) ->
3765+
let tag_name = tag_ctor_name_to_tag_name (lval_to_name lval) in
37663766
let ty_tag =
37673767
match slot_ty src_slot with
37683768
Ast.TY_tag tag_ty -> tag_ty

src/boot/me/type.ml

+38-17
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,7 @@ let process_crate (cx:ctxt) (crate:Ast.crate) : unit =
881881
in
882882
match lval with
883883
Ast.LVAL_base nbi ->
884-
let referent = Hashtbl.find cx.ctxt_lval_to_referent nbi.id in
884+
let referent = lval_to_referent cx nbi.id in
885885
begin
886886
match Hashtbl.find cx.ctxt_all_defns referent with
887887
DEFN_slot slot ->
@@ -1196,33 +1196,54 @@ let process_crate (cx:ctxt) (crate:Ast.crate) : unit =
11961196
| _ -> ()
11971197
in
11981198

1199+
(*
1200+
* Tag patterns give us the type of every sub-pattern in the tag tuple, so
1201+
* we can "expect" those types by pushing them on a stack. Checking a
1202+
* pattern therefore involves seeing that it matches the "expected" type,
1203+
* and in turn setting any expectations for the inner descent.
1204+
*)
11991205
let visit_pat_pre (pat:Ast.pat) : unit =
12001206
let expected = pat_tv() in
12011207
match pat with
12021208
Ast.PAT_lit lit -> unify_lit lit expected
12031209

1204-
| Ast.PAT_tag (namei, _) ->
1210+
| Ast.PAT_tag (lval, _) ->
12051211
let expect ty =
12061212
let tv = ref TYSPEC_all in
12071213
unify_ty ty tv;
12081214
push_pat_tv tv;
12091215
in
1210-
let item_id = Hashtbl.find cx.ctxt_pattag_to_item namei.id in
1211-
let tag_ty =
1212-
fn_output_ty (Hashtbl.find cx.ctxt_all_item_types item_id)
1213-
in
1214-
let tag_ty_tup = tag_or_iso_ty_tup_by_name tag_ty namei.node in
1215-
let tag_tv = ref TYSPEC_all in
1216-
unify_ty tag_ty tag_tv;
1217-
unify_tyvars expected tag_tv;
1218-
List.iter
1219-
begin
1220-
fun slot ->
1221-
match slot.Ast.slot_ty with
1216+
1217+
let lval_nm = lval_to_name lval in
1218+
1219+
(* The lval here is our tag constructor, which we've already
1220+
* resolved (in Resolve) to have a the actual tag constructor
1221+
* function item as its referent. It should hence unify
1222+
* exactly to that function type, rebuilt under any latent type
1223+
* parameters applied in the lval. *)
1224+
let lval_tv = ref TYSPEC_all in
1225+
unify_lval lval lval_tv;
1226+
let tag_ctor_ty =
1227+
match !(resolve_tyvar lval_tv) with
1228+
TYSPEC_resolved (_, ty) -> ty
1229+
| _ ->
1230+
bug () "tag constructor is not a fully resolved type."
1231+
in
1232+
1233+
let tag_ty = fn_output_ty tag_ctor_ty in
1234+
let tag_ty_tup = tag_or_iso_ty_tup_by_name tag_ty lval_nm in
1235+
1236+
let tag_tv = ref TYSPEC_all in
1237+
unify_ty tag_ty tag_tv;
1238+
unify_tyvars expected tag_tv;
1239+
List.iter
1240+
begin
1241+
fun slot ->
1242+
match slot.Ast.slot_ty with
12221243
Some ty -> expect ty
1223-
| None -> bug () "no slot type in tag slot tuple"
1224-
end
1225-
(List.rev (Array.to_list tag_ty_tup));
1244+
| None -> bug () "no slot type in tag slot tuple"
1245+
end
1246+
(List.rev (Array.to_list tag_ty_tup));
12261247

12271248
| Ast.PAT_slot (sloti, _) ->
12281249
unify_slot sloti.node (Some sloti.id) expected

src/boot/me/walk.ml

+8-6
Original file line numberDiff line numberDiff line change
@@ -655,15 +655,17 @@ and walk_pat
655655
let walk p =
656656
match p with
657657
Ast.PAT_lit lit -> walk_lit v lit
658-
| Ast.PAT_tag (_, pats) -> Array.iter (walk_pat v) pats
658+
| Ast.PAT_tag (lv, pats) ->
659+
walk_lval v lv;
660+
Array.iter (walk_pat v) pats
659661
| Ast.PAT_slot (si, _) -> walk_slot_identified v si
660662
| Ast.PAT_wild -> ()
661663
in
662-
walk_bracketed
663-
v.visit_pat_pre
664-
(fun _ -> walk p)
665-
v.visit_pat_post
666-
p
664+
walk_bracketed
665+
v.visit_pat_pre
666+
(fun _ -> walk p)
667+
v.visit_pat_post
668+
p
667669

668670

669671
and walk_block

src/test/run-pass/generic-tag-alt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ type foo[T] = tag(arm(T));
33
fn altfoo[T](foo[T] f) {
44
auto hit = false;
55
alt (f) {
6-
case (arm(x)) {
6+
case (arm[T](x)) {
77
log "in arm";
88
hit = true;
99
}

0 commit comments

Comments
 (0)