Skip to content

Commit 7e4220d

Browse files
authored
Merge pull request #356 from LPCIC/oc-opt-out
attribute to disable occur check
2 parents 14b04f9 + fd3d3db commit 7e4220d

39 files changed

+1640
-561
lines changed

.github/workflows/users.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
- run: opam pin --ignore-constraints-on elpi add rocq-elpi https://github.com/LPCIC/coq-elpi.git#master
3434
- run: opam pin --ignore-constraints-on elpi add coq-elpi https://github.com/LPCIC/coq-elpi.git#master
3535
- run: opam pin --ignore-constraints-on elpi add rocq-stdlib https://github.com/rocq-prover/stdlib.git#master
36-
- run: opam pin --ignore-constraints-on elpi add rocq-hierarchy-builder https://github.com/math-comp/hierarchy-builder.git#rename-class
36+
- run: opam pin --ignore-constraints-on elpi add rocq-hierarchy-builder https://github.com/math-comp/hierarchy-builder.git#master
3737
- run: opam pin --ignore-constraints-on elpi add rocq-mathcomp-boot https://github.com/math-comp/math-comp.git#master
3838
- run: opam pin --ignore-constraints-on elpi add rocq-mathcomp-order https://github.com/math-comp/math-comp.git#master
3939
- run: opam pin --ignore-constraints-on elpi add rocq-mathcomp-fingroup https://github.com/math-comp/math-comp.git#master

CHANGES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# UNRELEASED
22

3+
- Language:
4+
- New attribute `:nooc` to disable occur check
5+
- Stdlib:
6+
- New `unsound_unif` performing unification without occur check
7+
- New `std.fset` and `std.fmap` that work on ground terms and
8+
disable occur check
39
- Compiler:
410
- Change raise an error in case of type/typeabbrev collision
511

src/API.ml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ module Execute = struct
237237
relocate_assignment_to_runtime = (fun ~target ~depth s ->
238238
Compiler.relocate_closed_term ~from
239239
(Util.StrMap.find s assignments |> full_deref ~depth:idepth |> uvar2discard ~depth:idepth) ~to_:target
240-
|> Stdlib.Result.map (hmove ?avoid:None ~from:depth ~to_:depth)
240+
|> Stdlib.Result.map (hmove ?oc:None ~from:depth ~to_:depth)
241241
);
242242
}
243243

@@ -479,7 +479,7 @@ module BuiltInData = struct
479479
let ty = Conversion.(TyName ty) in
480480
let embed ~depth state (x,from) =
481481
let module R = (val !r) in let open R in
482-
state, hmove ~from ~to_:depth ?avoid:None x, [] in
482+
state, hmove ~from ~to_:depth ?oc:None x, [] in
483483
let readback ~depth state t =
484484
state, fresh_copy t depth, [] in
485485
{ Conversion.embed; readback; ty;
@@ -906,7 +906,7 @@ module BuiltInPredicate = struct
906906

907907
let beta ~depth t args =
908908
let module R = (val !r) in let open R in
909-
deref_apparg ~from:depth ~to_:depth ?avoid:None t args
909+
deref_apparg ~from:depth ~to_:depth ?oc:None t args
910910

911911
module HOAdaptors = struct
912912

@@ -1300,7 +1300,7 @@ module Utils = struct
13001300

13011301
let move ~from ~to_ t =
13021302
let module R = (val !r) in let open R in
1303-
hmove ~from ~to_ ?avoid:None t
1303+
hmove ~from ~to_ ?oc:None t
13041304

13051305
let beta = BuiltInPredicate.beta
13061306
let error = Util.error

src/builtin.elpi

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,11 @@ external func same_term A, A.
462462
func (==) A, A.
463463
X == Y :- same_term X Y.
464464

465+
% Unification without occur check. It can create infinite terms.
466+
:nooc
467+
func unsound_unif -> A, A.
468+
unsound_unif X X.
469+
465470

466471
% [cmp_term A B Cmp] Compares A and B. Only works if A and B are ground.
467472
external func cmp_term any, any -> cmp.
@@ -1276,6 +1281,136 @@ bindings (node L V D R _) X X1 :-
12761281
} % std.map.private
12771282
} % std.map
12781283

1284+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285+
1286+
% Fast maps only work ground terms but do not perform occur check
1287+
1288+
kind std.fmap type -> type -> type.
1289+
type std.fmap std.fmap.private.map K V -> (func K, K -> cmp) -> std.fmap K V.
1290+
1291+
namespace std.fmap {
1292+
1293+
% [make Eq Ltn M] builds an empty map M where keys are compared using Eq and Ltn
1294+
func make (func K, K -> cmp) -> std.fmap K V.
1295+
make Cmp (std.fmap private.empty Cmp).
1296+
1297+
% [find K M V] looks in M for the value V associated to K
1298+
func find K, std.fmap K V -> V.
1299+
find K (std.fmap M Cmp) V :-
1300+
private.assert-ground K,
1301+
private.find M Cmp K V.
1302+
1303+
% [add K V M M1] M1 is M where K is bound to V
1304+
func add K, V, std.fmap K V -> std.fmap K V.
1305+
add K V (std.fmap M Cmp) R :-
1306+
private.assert-ground K,
1307+
private.assert-ground V,
1308+
private.add M Cmp K V M1,
1309+
unsound_unif R (std.fmap M1 Cmp).
1310+
1311+
% [remove K M M1] M1 is M where K is unbound
1312+
func remove K, std.fmap K V -> std.fmap K V.
1313+
remove K (std.fmap M Cmp) R :-
1314+
private.assert-ground K,
1315+
private.remove M Cmp K M1,
1316+
unsound_unif R (std.fmap M1 Cmp).
1317+
1318+
% [bindings M L] L is the key-value pairs in increasing order
1319+
func bindings std.fmap K V -> list (pair K V).
1320+
bindings (std.fmap M _) L :- private.bindings M [] L.
1321+
1322+
namespace private {
1323+
1324+
func assert-ground A.
1325+
assert-ground A :- std.assert! (ground_term A) "std.fmap: not ground".
1326+
1327+
% Taken from OCaml's map.ml
1328+
kind map type -> type -> type.
1329+
type empty map K V.
1330+
type node map K V -> K -> V -> map K V -> int -> map K V.
1331+
1332+
func height map K V -> int.
1333+
height empty 0.
1334+
height (node _ _ _ _ H) H.
1335+
1336+
func create map K V, K, V, map K V -> map K V.
1337+
create L K V R X :-
1338+
H is {std.max {height L} {height R}} + 1,
1339+
unsound_unif X (node L K V R H).
1340+
1341+
func bal map K V, K, V, map K V -> map K V.
1342+
bal L K V R T :-
1343+
height L HL,
1344+
height R HR,
1345+
HL2 is HL + 2,
1346+
HR2 is HR + 2,
1347+
bal.aux HL HR HL2 HR2 L K V R T.
1348+
1349+
func bal.aux int, int, int, int, map K V, K, V, map K V -> map K V.
1350+
bal.aux HL _ _ HR2 (node LL LV LD LR _) X D R T :-
1351+
HL > HR2, {height LL} >= {height LR}, !,
1352+
create LL LV LD {create LR X D R} T.
1353+
bal.aux HL _ _ HR2 (node LL LV LD (node LRL LRV LRD LRR _) _) X D R T :-
1354+
HL > HR2, !,
1355+
create {create LL LV LD LRL} LRV LRD {create LRR X D R} T.
1356+
bal.aux _ HR HL2 _ L X D (node RL RV RD RR _) T :-
1357+
HR > HL2, {height RR} >= {height RL}, !,
1358+
create {create L X D RL} RV RD RR T.
1359+
bal.aux _ HR HL2 _ L X D (node (node RLL RLV RLD RLR _) RV RD RR _) T :-
1360+
HR > HL2, !,
1361+
create {create L X D RLL} RLV RLD {create RLR RV RD RR} T.
1362+
bal.aux _ _ _ _ L K V R T :- create L K V R T.
1363+
1364+
func add map K V, (func K, K -> cmp), K, V -> map K V.
1365+
add empty _ K V T :- create empty K V empty T.
1366+
add (node _ X _ _ _ as M) Cmp X1 XD M1 :- Cmp X1 X E, add.aux E M Cmp X1 XD M1.
1367+
1368+
func add.aux cmp, map K V, (func K, K -> cmp), K, V -> map K V.
1369+
add.aux eq (node L _ _ R H) _ X XD T :- unsound_unif T (node L X XD R H).
1370+
add.aux lt (node L V D R _) Cmp X XD T :- bal {add L Cmp X XD} V D R T.
1371+
add.aux gt (node L V D R _) Cmp X XD T :- bal L V D {add R Cmp X XD} T.
1372+
1373+
func find map K V, (func K, K -> cmp), K -> V.
1374+
find (node L K1 V1 R _) Cmp K V :- Cmp K K1 E, find.aux E Cmp L R V1 K V.
1375+
1376+
func find.aux cmp, (func K, K -> cmp), map K V, map K V, V, K -> V.
1377+
find.aux eq _ _ _ V _ V.
1378+
find.aux lt Cmp L _ _ K V :- find L Cmp K V.
1379+
find.aux gt Cmp _ R _ K V :- find R Cmp K V.
1380+
1381+
func remove-min-binding map K V -> map K V.
1382+
remove-min-binding (node empty _ _ R _) R :- !.
1383+
remove-min-binding (node L V D R _) X :- bal {remove-min-binding L} V D R X.
1384+
1385+
func min-binding map K V -> K, V.
1386+
min-binding (node empty V D _ _) V D :- !.
1387+
min-binding (node L _ _ _ _) V D :- min-binding L V D.
1388+
1389+
func merge map K V, map K V -> map K V.
1390+
merge empty X X :- !.
1391+
merge X empty X :- !.
1392+
merge M1 M2 R :-
1393+
min-binding M2 X D,
1394+
bal M1 X D {remove-min-binding M2} R.
1395+
1396+
func remove map K V, (func K, K -> cmp), K -> map K V.
1397+
remove empty _ _ empty :- !.
1398+
remove (node L V D R _) Cmp X M :- Cmp X V E, remove.aux E Cmp L R V D X M.
1399+
1400+
func remove.aux cmp, (func K, K -> cmp), map K V, map K V, K, V, K -> map K V.
1401+
remove.aux eq _ L R _ _ _ M :- merge L R M.
1402+
remove.aux lt Cmp L R V D X M :- bal {remove L Cmp X} V D R M.
1403+
remove.aux gt Cmp L R V D X M :- bal L V D {remove R Cmp X} M.
1404+
1405+
func bindings map K V, list (pair K V) -> list (pair K V).
1406+
bindings empty X X.
1407+
bindings (node L V D R _) X X1 :-
1408+
bindings L [pr V D|{bindings R X}] X1.
1409+
1410+
1411+
} % std.fmap.private
1412+
} % std.fmap
1413+
12791414

12801415
#line 1 "builtin_set.elpi"
12811416
kind std.set type -> type.
@@ -1396,6 +1531,139 @@ elements (node L E R _) Acc X :-
13961531
} % std.set.private
13971532
} % std.set
13981533

1534+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1535+
1536+
% Fast sets only work ground terms but do not perform occur check
1537+
1538+
kind std.fset type -> type.
1539+
type std.fset std.fset.private.set E -> (func E, E -> cmp) -> std.fset E.
1540+
1541+
namespace std.fset {
1542+
1543+
% [make Eq Ltn M] builds an empty set M where keys are compared using Eq and Ltn
1544+
func make (func E, E -> cmp) -> std.fset E.
1545+
make Cmp (std.fset private.empty Cmp).
1546+
1547+
% [mem E M] looks if E is in M
1548+
func mem E, std.fset E.
1549+
mem E (std.fset M Cmp):- private.mem M Cmp E.
1550+
1551+
% [add E M M1] M1 is M + {E}
1552+
func add E, std.fset E -> std.fset E.
1553+
add E (std.fset M Cmp) R :-
1554+
private.assert-ground E,
1555+
private.add M Cmp E M1,
1556+
unsound_unif R (std.fset M1 Cmp).
1557+
1558+
% [remove E M M1] M1 is M - {E}
1559+
func remove E, std.fset E -> std.fset E.
1560+
remove E (std.fset M Cmp) R :-
1561+
private.assert-ground E,
1562+
private.remove M Cmp E M1,
1563+
unsound_unif R (std.fset M1 Cmp).
1564+
1565+
% [cardinal S N] N is the number of elements of S
1566+
func cardinal std.fset E -> int.
1567+
cardinal (std.fset M _) N :- private.cardinal M N.
1568+
1569+
func elements std.fset E -> list E.
1570+
elements (std.fset M _) L :- private.elements M [] L.
1571+
1572+
namespace private {
1573+
1574+
func assert-ground A.
1575+
assert-ground A :- std.assert! (ground_term A) "std.fset: not ground".
1576+
1577+
% Taken from OCaml's set.ml
1578+
kind set type -> type.
1579+
type empty set E.
1580+
type node set E -> E -> set E -> int -> set E.
1581+
1582+
func height set E -> int.
1583+
height empty 0.
1584+
height (node _ _ _ H) H.
1585+
1586+
func create set E, E, set E -> set E.
1587+
create L E R S :-
1588+
H is {std.max {height L} {height R}} + 1,
1589+
unsound_unif S (node L E R H).
1590+
1591+
func bal set E, E, set E -> set E.
1592+
bal L E R T :-
1593+
height L HL,
1594+
height R HR,
1595+
HL2 is HL + 2,
1596+
HR2 is HR + 2,
1597+
bal.aux HL HR HL2 HR2 L E R T.
1598+
1599+
func bal.aux int, int, int, int, set E, E, set E -> set E.
1600+
bal.aux HL _ _ HR2 (node LL LV LR _) X R T :-
1601+
HL > HR2, {height LL} >= {height LR}, !,
1602+
create LL LV {create LR X R} T.
1603+
bal.aux HL _ _ HR2 (node LL LV (node LRL LRV LRR _) _) X R T :-
1604+
HL > HR2, !,
1605+
create {create LL LV LRL} LRV {create LRR X R} T.
1606+
bal.aux _ HR HL2 _ L X (node RL RV RR _) T :-
1607+
HR > HL2, {height RR} >= {height RL}, !,
1608+
create {create L X RL} RV RR T.
1609+
bal.aux _ HR HL2 _ L X (node (node RLL RLV RLR _) RV RR _) T :-
1610+
HR > HL2, !,
1611+
create {create L X RLL} RLV {create RLR RV RR} T.
1612+
bal.aux _ _ _ _ L E R T :- create L E R T.
1613+
1614+
func add set E, (func E, E -> cmp), E -> set E.
1615+
add empty _ E T :- create empty E empty T.
1616+
add (node L X R H) Cmp X1 S :- Cmp X1 X E, add.aux E Cmp L R X X1 H S.
1617+
1618+
func add.aux cmp, (func E, E -> cmp), set E, set E, E, E, int -> set E.
1619+
add.aux eq _ L R X _ H S :- unsound_unif S (node L X R H).
1620+
add.aux lt Cmp L R E X _ T :- bal {add L Cmp X} E R T.
1621+
add.aux gt Cmp L R E X _ T :- bal L E {add R Cmp X} T.
1622+
1623+
func mem set E, (func E, E -> cmp), E.
1624+
mem (node L K R _) Cmp E :- Cmp E K O, mem.aux O Cmp L R E.
1625+
1626+
func mem.aux cmp, (func E, E -> cmp), set E, set E, E.
1627+
mem.aux eq _ _ _ _.
1628+
mem.aux lt Cmp L _ E :- mem L Cmp E.
1629+
mem.aux gt Cmp _ R E :- mem R Cmp E.
1630+
1631+
func remove-min-binding set E -> set E.
1632+
remove-min-binding (node empty _ R _) R :- !.
1633+
remove-min-binding (node L E R _) X :- bal {remove-min-binding L} E R X.
1634+
1635+
func min-binding set E -> E.
1636+
min-binding (node empty E _ _) E :- !.
1637+
min-binding (node L _ _ _) E :- min-binding L E.
1638+
1639+
func merge set E, set E -> set E.
1640+
merge empty X X :- !.
1641+
merge X empty X :- !.
1642+
merge M1 M2 R :-
1643+
min-binding M2 X,
1644+
bal M1 X {remove-min-binding M2} R.
1645+
1646+
func remove set E, (func E, E -> cmp), E -> set E.
1647+
remove empty _ _ empty.
1648+
remove (node L E R _) Cmp X M :- Cmp X E O, remove.aux O Cmp L R E X M.
1649+
1650+
func remove.aux cmp, (func E, E -> cmp), set E, set E, E, E -> set E.
1651+
remove.aux eq _ L R _ _ M :- merge L R M.
1652+
remove.aux lt Cmp L R E X M :- bal {remove L Cmp X} E R M.
1653+
remove.aux gt Cmp L R E X M :- bal L E {remove R Cmp X} M.
1654+
1655+
func cardinal set E -> int.
1656+
cardinal empty 0.
1657+
cardinal (node L _ R _) N :- N is {cardinal L} + 1 + {cardinal R}.
1658+
1659+
func elements set E, list E -> list E.
1660+
elements empty X X.
1661+
elements (node L E R _) Acc X :-
1662+
elements L [E|{elements R Acc}] X.
1663+
1664+
} % std.fset.private
1665+
} % std.fset
1666+
13991667

14001668
% == Elpi runtime builtins =====================================
14011669

src/builtin.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,11 @@ let elpi_nonlogical_builtins = let open BuiltIn in let open BuiltInData in let o
851851
% Infix notation for same_term
852852
func (==) A, A.
853853
X == Y :- same_term X Y.
854+
855+
% Unification without occur check. It can create infinite terms.
856+
:nooc
857+
func unsound_unif -> A, A.
858+
unsound_unif X X.
854859
|};
855860

856861
MLCode(Pred("cmp_term",

0 commit comments

Comments
 (0)