Skip to content

Commit 68a75f0

Browse files
committed
Introducing (#a : Type | deq) syntax for types + constraints
This syntax simplifies writing several constraints over the same type. The constraints can just be added to the set after the bar, and many of them can be given. E.g. ```fstar let foo5 (#a #b : Type | deq, ord) ... ``` This has two implicit arguments for the types, then `deq` and `ord` constraints for `a`, and then for `b`. The constraints could also be partially applied
1 parent a81e235 commit 68a75f0

File tree

6 files changed

+301
-92
lines changed

6 files changed

+301
-92
lines changed

src/ml/FStarC_Parser_Parse.mly

Lines changed: 137 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,54 @@ type tc_constraint = {
6767
r: FStarC_Range.t;
6868
}
6969

70+
let pattern_must_be_binder (p : pattern) : binder =
71+
match p.pat with
72+
| PatConst Const_unit ->
73+
(* A unit pattern: `()`. Unsure if this is the right place to look
74+
for it. *)
75+
let x = gen p.prange in
76+
let u =
77+
unit_type p.prange
78+
(* mk_term (Const Const_unit) p.prange Expr *)
79+
in
80+
mk_binder (Annotated (x, u)) p.prange Expr None
81+
82+
| PatAscribed ({ pat = PatVar (x, aq, attrs)}, (t, _tac_opt)) ->
83+
mk_binder_with_attrs (Annotated (x, t)) p.prange Expr aq attrs
84+
85+
| PatVar (x, aq, attrs) ->
86+
mk_binder_with_attrs (Variable x) p.prange Expr aq attrs
87+
88+
| PatAscribed ({ pat = PatWild (aq, attrs)}, (t, _tac_opt)) ->
89+
let x = gen p.prange in
90+
mk_binder_with_attrs (Annotated (x, t)) p.prange Expr aq attrs
91+
92+
| PatWild (aq, attrs) ->
93+
let x = gen p.prange in
94+
mk_binder_with_attrs (Variable x) p.prange Expr aq attrs
95+
96+
| _ ->
97+
raise_error_text p.prange Fatal_SyntaxError
98+
("Must be a simple binder: " ^ pat_to_string p)
99+
100+
(* For a multibinder like `(a b c : Type | eq, ord)`, this generates
101+
binders
102+
{| _ : eq a |} {| _ : ord a |}
103+
{| _ : eq b |} {| _ : ord b |}
104+
{| _ : eq c |} {| _ : ord c |}
105+
in that order.
106+
*)
107+
let expand_inline_constraints (cts : term list) (xs : ident list) : pattern list =
108+
List.concat_map (fun x ->
109+
List.concat_map (fun ct ->
110+
let r = ct.range in
111+
let x_t = mk_term (Var (lid_of_ids [x])) r Expr in
112+
let ct = mk_term (App (ct, x_t, Nothing)) r Expr in
113+
let id = gen r in
114+
[ mk_pattern (PatAscribed(mk_pattern (PatVar (id, Some TypeClassArg, [])) r, (ct, None))) r ]
115+
) cts
116+
) xs
117+
70118
%}
71119

72120
%token <string> STRING
@@ -510,7 +558,7 @@ letoperatorbinding:
510558
}
511559

512560
letbinding:
513-
| focus_opt=maybeFocus lid=lidentOrOperator lbp=nonempty_list(patternOrMultibinder) ascr_opt=ascribeTyp? EQUALS tm=term
561+
| focus_opt=maybeFocus lid=lidentOrOperator lbp=nonempty_list(genBinder) ascr_opt=ascribeTyp? EQUALS tm=term
514562
{
515563
let pat = mk_pattern (PatVar(lid, None, [])) (rr $loc(lid)) in
516564
let pat = mk_pattern (PatApp (pat, flatten lbp)) (rr2 $loc(focus_opt) $loc(lbp)) in
@@ -683,40 +731,75 @@ tuplePattern:
683731
constructorPattern:
684732
| pat=constructorPattern COLON_COLON pats=constructorPattern
685733
{ mk_pattern (consPat (rr $loc(pats)) pat pats) (rr $loc) }
686-
| uid=quident args=nonempty_list(atomicPattern)
734+
| uid=quident args=nonempty_list(singleAtomicPattern)
687735
{
688736
let head_pat = mk_pattern (PatName uid) (rr $loc(uid)) in
689737
mk_pattern (PatApp (head_pat, args)) (rr $loc)
690738
}
691-
| pat=atomicPattern
739+
| pat=singleAtomicPattern
692740
{ pat }
693741

742+
singleAtomicPattern:
743+
| pats=atomicPattern
744+
{
745+
match pats with
746+
| [p] -> p
747+
| _ -> raise_error_text (rr $loc) Fatal_SyntaxError "Syntax error: expected a single atomic pattern, not a list"
748+
}
749+
694750
atomicPattern:
695-
| DOT_DOT
751+
| a=atomicPatternNoLParen
752+
{ [a] }
753+
| LPAREN
754+
pats=nonempty_list(tuplePattern)
755+
ann=genBinderAnnotation
756+
RPAREN
696757
{
697-
mk_pattern PatRest (rr $loc)
758+
let t_ann, ref_opt, tc_cts = ann in
759+
let t_pos = rr $loc(ann) in
760+
(* let pats = List.flatten pats in *)
761+
let n = List.length pats in
762+
let bs : pattern list =
763+
List.mapi (fun idx pat ->
764+
(* let pat = mk_pattern (PatVar (x, aq, attrs)) pos in *)
765+
(* Only the last binder carries the refinement, if any. *)
766+
let ref_opt = if idx = Int.sub n 1 then ref_opt else None in
767+
(* ^ The - symbol resolves to F* addition. *)
768+
match t_ann with
769+
| Some ty ->
770+
mkRefinedPattern pat ty true ref_opt t_pos pat.prange
771+
| None -> pat
772+
) pats
773+
in
774+
let rec pat_names bs =
775+
match bs with
776+
| [] -> []
777+
| b::bs' ->
778+
match b.pat with
779+
| PatAscribed ({pat = PatVar (x, _, _)}, _)
780+
| PatVar (x, _, _) -> x::pat_names bs'
781+
| _ -> pat_names bs'
782+
in
783+
bs @ expand_inline_constraints tc_cts (pat_names bs)
698784
}
699-
| LPAREN pat=tuplePattern COLON t=simpleArrow phi_opt=refineOpt RPAREN
785+
786+
atomicPatternNoLParen:
787+
| DOT_DOT
700788
{
701-
let pos_t = rr2 $loc(pat) $loc(t) in
702-
let pos = rr $loc in
703-
mkRefinedPattern pat t true phi_opt pos_t pos
789+
mk_pattern PatRest (rr $loc)
704790
}
705791
| LBRACK pats=right_flexible_list(SEMICOLON, tuplePattern) RBRACK
706792
{ mk_pattern (PatList pats) (rr2 $loc($1) $loc($3)) }
707793
| LBRACE record_pat=right_flexible_list(SEMICOLON, fieldPattern) RBRACE
708794
{ mk_pattern (PatRecord record_pat) (rr $loc) }
709795
| LENS_PAREN_LEFT pat0=constructorPattern COMMA pats=separated_nonempty_list(COMMA, constructorPattern) LENS_PAREN_RIGHT
710796
{ mk_pattern (PatTuple(pat0::pats, true)) (rr $loc) }
711-
| LPAREN pat=tuplePattern RPAREN { pat }
797+
// | LPAREN pat=tuplePattern RPAREN { pat }
712798
| LPAREN op=operator RPAREN
713799
{ mk_pattern (PatOp op) (rr $loc) }
714-
| UNDERSCORE
715-
{ mk_pattern (PatWild (None, [])) (rr $loc) }
716-
| HASH UNDERSCORE
717-
{ mk_pattern (PatWild (Some Implicit, [])) (rr $loc) }
718800
| c=constant
719801
{ mk_pattern (PatConst c) (rr $loc(c)) }
802+
(* I would not call this atomic. *)
720803
| tok=MINUS c=constant
721804
{ let r = rr2 $loc(tok) $loc(c) in
722805
let c =
@@ -735,6 +818,10 @@ atomicPattern:
735818
{
736819
let (aqual, attrs), lid = qual_id in
737820
mk_pattern (PatVar (lid, aqual, attrs)) (rr $loc(qual_id)) }
821+
| qual_id=aqualifiedWithAttrs(UNDERSCORE)
822+
{
823+
let (aqual, attrs), _ = qual_id in
824+
mk_pattern (PatWild (aqual, attrs)) (rr $loc(qual_id)) }
738825
| uid=quident
739826
{ mk_pattern (PatName uid) (rr $loc(uid)) }
740827

@@ -751,83 +838,24 @@ tc_constraint:
751838
{id; t; r}
752839
}
753840

841+
(* Typeclass constraints: what appears inside a {| ... |}. They can
842+
be named or anonymous *)
754843
tc_constraints:
755844
| constraints=right_flexible_nonempty_list(COMMA, tc_constraint) { constraints }
756-
757-
(* (x : t) is already covered by atomicPattern *)
758-
(* we do *NOT* allow _ in multibinder () since it creates reduce/reduce conflicts when*)
759-
(* preprocessing to ocamlyacc/fsyacc (which is expected since the macro are expanded) *)
760-
patternOrMultibinder:
761-
| LBRACE_BAR constraints=tc_constraints BAR_RBRACE
762-
{
763-
let constraint_as_pat (c:tc_constraint) =
764-
let w = mk_pattern (PatVar (c.id, Some TypeClassArg, [])) c.r in
765-
let asc = (c.t, None) in
766-
mk_pattern (PatAscribed(w, asc)) c.r
767-
in
768-
List.map constraint_as_pat constraints
769-
}
770-
771-
| pat=atomicPattern { [pat] }
772-
| LPAREN
773-
qual_id0=aqualifiedWithAttrs(lident)
774-
qual_ids=nonempty_list(aqualifiedWithAttrs(lident))
775-
COLON
776-
t=simpleArrow r=refineOpt
777-
RPAREN
778-
{
779-
let pos = rr $loc in
780-
let t_pos = rr $loc(t) in
781-
let qual_ids = qual_id0 :: qual_ids in
782-
let n = List.length qual_ids in
783-
List.mapi (fun idx ((aq, attrs), x) ->
784-
let pat = mk_pattern (PatVar (x, aq, attrs)) pos in
785-
(* Only the last binder carries the refinement, if any. *)
786-
let refine_opt = if idx = Int.sub n 1 then r else None in
787-
(* ^ The - symbol resolves to F* addition. *)
788-
mkRefinedPattern pat t true refine_opt t_pos pos
789-
) qual_ids
790-
}
791-
792-
binder:
793-
| aqualifiedWithAttrs_lid=aqualifiedWithAttrs(lidentOrUnderscore)
794-
{
795-
let (q, attrs), lid = aqualifiedWithAttrs_lid in
796-
mk_binder_with_attrs (Variable lid) (rr $loc(aqualifiedWithAttrs_lid)) Type_level q attrs
797-
}
845+
846+
(* Constraints on binders: like (#a : Type | deq) *)
847+
type_tc_constraints:
848+
| BAR constraints=right_flexible_nonempty_list(COMMA, tmEqNoRefinement) { constraints }
849+
| { [] }
798850

799851
%public
800-
multiBinder:
801-
| LBRACE_BAR constraints=tc_constraints BAR_RBRACE
802-
{
803-
let constraint_as_binder (c:tc_constraint) =
804-
mk_binder (Annotated (c.id, c.t)) c.r Type_level (Some TypeClassArg)
805-
in
806-
List.map constraint_as_binder constraints
807-
}
808-
809-
| LPAREN qual_ids=nonempty_list(aqualifiedWithAttrs(lidentOrUnderscore)) COLON t=simpleArrow r=refineOpt RPAREN
810-
{
811-
let should_bind_var = match qual_ids with | [ _ ] -> true | _ -> false in
812-
let n = List.length qual_ids in
813-
List.mapi (fun idx ((q, attrs), x) ->
814-
let refine_opt = if idx = Int.sub n 1 then r else None in
815-
mkRefinedBinder x t true refine_opt (rr $loc) q attrs
816-
) qual_ids
817-
}
818-
819-
| LPAREN_RPAREN
852+
binders:
853+
| bss=list(genBinder)
820854
{
821-
let r = rr $loc in
822-
let unit_t = mk_term (Var (lid_of_ids [(mk_ident("unit", r))])) r Un in
823-
[mk_binder (Annotated (gen r, unit_t)) r Un None]
855+
let bs = flatten bss in
856+
List.map pattern_must_be_binder bs
824857
}
825858

826-
| b=binder { [b] }
827-
828-
%public
829-
binders: bss=list(bs=multiBinder {bs}) { flatten bss }
830-
831859
aqualifiedWithAttrs(X):
832860
| aq=aqual attrs=binderAttributes x=X { (Some aq, attrs), x }
833861
| aq=aqual x=X { (Some aq, []), x }
@@ -1257,6 +1285,7 @@ simpleArrowDomain:
12571285

12581286
(* Tm already accounts for ( term ), we need to add an explicit case for (#Tm), (#[@@@...]Tm) and ([@@@...]Tm) *)
12591287
%inline tmArrowDomain(Tm):
1288+
(* Replace all this for genBinder? *)
12601289
| LBRACE_BAR t=Tm BAR_RBRACE { ((Some TypeClassArg, []), t) }
12611290
| LPAREN q=aqual attrs_opt=ioption(binderAttributes) dom_tm=Tm RPAREN { (Some q, none_to_empty_list attrs_opt), dom_tm }
12621291
| LPAREN attrs=binderAttributes dom_tm=Tm RPAREN { (None, attrs), dom_tm }
@@ -1471,7 +1500,7 @@ trailingTerm:
14711500
{ x }
14721501

14731502
onlyTrailingTerm:
1474-
| FUN pats=nonempty_list(patternOrMultibinder) RARROW e=term
1503+
| FUN pats=nonempty_list(genBinder) RARROW e=term
14751504
{ mk_term (Abs(flatten pats, e)) (rr2 $loc($1) $loc(e)) Un }
14761505
| q=quantifier bs=binders DOT trigger=trigger e=term
14771506
{
@@ -1690,3 +1719,26 @@ reverse_left_flexible_nonempty_list(delim, X):
16901719
%inline left_flexible_nonempty_list(delim, X):
16911720
xs = reverse_left_flexible_nonempty_list(delim, X)
16921721
{ List.rev xs }
1722+
1723+
genBinderAnnotation:
1724+
| { None, None, [] }
1725+
| COLON
1726+
t=simpleArrow
1727+
r=refineOpt
1728+
cts=type_tc_constraints
1729+
{
1730+
(Some t), r, cts
1731+
}
1732+
1733+
genBinder:
1734+
| LBRACE_BAR constraints=tc_constraints BAR_RBRACE
1735+
{
1736+
let constraint_as_pat (c:tc_constraint) =
1737+
let w = mk_pattern (PatVar (c.id, Some TypeClassArg, [])) c.r in
1738+
let asc = (c.t, None) in
1739+
mk_pattern (PatAscribed(w, asc)) c.r
1740+
in
1741+
List.map constraint_as_pat constraints
1742+
}
1743+
1744+
| pats=atomicPattern { pats }

src/parser/FStarC.Parser.AST.fst

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ let mkListLit r elts =
177177
let mkSeqLit r elts =
178178
mk_term (SeqLiteral elts) r Expr
179179

180-
let unit_const r = mk_term(Const Const_unit) r Expr
180+
let unit_const r = mk_term (Const Const_unit) r Expr
181+
let unit_type r = mk_term (Var (Ident.lid_of_str (`%unit))) r Expr
181182

182183
let ml_comp t =
183184
let lid = C.effect_ML_lid () in
@@ -996,12 +997,14 @@ instance pretty_quote_kind : pretty quote_kind = {
996997
997998
let ctor (n: string) (args: list document) =
998999
nest 2 (group (parens (flow (break_ 1) (doc_of_string n :: args))))
1000+
// let ctor (n: string) (arg: document) : document =
1001+
// nest 2 (group (parens (doc_of_string n ^/^ arg)))
9991002
10001003
let pp_list' (#a:Type) (f: a -> document) (xs: list a) : document =
10011004
(pp_list a { pp = f }).pp xs // hack
10021005
10031006
instance showable_arg_qualifier : showable arg_qualifier = {
1004-
show = function
1007+
show = function
10051008
| Implicit -> "Implicit"
10061009
| Equality -> "Equality"
10071010
| Meta i -> "Meta"
@@ -1046,7 +1049,7 @@ let rec pp_term (t:term) : document =
10461049
ctor "LetOpBinding" [pp i; pp_pattern p; pp_term b]
10471050
in
10481051
ctor "LetOperator" [pp_list' pp_letopbinding lbs; pp_term body]
1049-
| LetOpen (lid, t) ->
1052+
| LetOpen (lid, t) ->
10501053
ctor "LetOpen" [pp lid; pp_term t]
10511054
| LetOpenRecord (t1, t2, t3) ->
10521055
ctor "LetOpenRecord" [pp_term t1; pp_term t2; pp_term t3]
@@ -1221,7 +1224,7 @@ instance pretty_constructor_payload : pretty constructor_payload = { pp = pp_con
12211224
12221225
let pp_tycon (tc : tycon) : document =
12231226
match tc with
1224-
| TyconAbstract (i, bs, knd) ->
1227+
| TyconAbstract (i, bs, knd) ->
12251228
ctor "TyconAbstract" [pp i; pp bs; pp knd]
12261229
| TyconAbbrev (i, bs, knd, t) ->
12271230
ctor "TyconAbbrev" [pp i; pp bs; pp knd; doc_of_string "_"]
@@ -1251,7 +1254,7 @@ let pp_decl (d:decl) : document =
12511254
let pp_pat_term (p, t) =
12521255
ctor "PatTerm" [pp p; pp t] in
12531256
ctor "TopLevelLet" [doc_of_string (show q); pp_list' pp_pat_term pats]
1254-
| Assume (i, t_opt) ->
1257+
| Assume (i, t_opt) ->
12551258
let pp_opt_term = function None -> doc_of_string "None" | Some t -> pp_term t in
12561259
ctor "Assume" [pp i; pp_term t_opt]
12571260
| Tycon (r, tps, tys) ->

src/parser/FStarC.Parser.AST.fsti

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ val consPat : range -> pattern -> pattern -> pattern'
328328
val consTerm : range -> term -> term -> term
329329

330330
val unit_const : range -> term
331+
val unit_type : range -> term
331332
val ml_comp : term -> term
332333
val tot_comp : term -> term
333334

0 commit comments

Comments
 (0)