1 | % (c) 2009-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
2 | % Heinrich Heine Universitaet Duesseldorf | |
3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
4 | ||
5 | :- module(kodkod_typing,[kodkod_insert_casts/4]). | |
6 | ||
7 | :- use_module(library(lists)). | |
8 | :- use_module(library(avl)). | |
9 | ||
10 | :- use_module(probsrc(module_information),[module_info/2]). | |
11 | :- use_module(probsrc(tools),[foldl/4]). | |
12 | ||
13 | :- use_module(kodkod_tools). | |
14 | ||
15 | :- module_info(group,kodkod). | |
16 | :- module_info(description,'This is a small internal type checker for Kodkod expressions. It\'s needed for inserting casts between different integer representations.'). | |
17 | ||
18 | kodkod_insert_casts(Kin,TypeMap,IdMap,Kout) :- | |
19 | create_refmap(TypeMap,IdMap,Env), | |
20 | type_kodkod(Kin,Env,formula,Kout). | |
21 | ||
22 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
23 | % create Kodkod typechecking environment | |
24 | create_refmap(TypeMap,IdMap,ktypenv(Env,StartEnv)) :- | |
25 | empty_avl(StartEnv), | |
26 | create_refmap_types(TypeMap,StartEnv,TypeEnv), | |
27 | create_refmap_ids(IdMap,TypeEnv,Env). | |
28 | lookup_reltypes(Id,ktypenv(Env,_Vars),Types) :- | |
29 | avl_fetch(Id,Env,Types). | |
30 | lookup_vartypes(Id,ktypenv(_Env,Vars),Types) :- | |
31 | avl_fetch(Id,Vars,Types). | |
32 | add_var_to_type_env(Id,Types,ktypenv(E,EnvIn),ktypenv(E,EnvOut)) :- | |
33 | avl_store(Id,EnvIn,Types,EnvOut). | |
34 | ||
35 | create_refmap_types(TypeMap,In,Out) :- | |
36 | avl_range(TypeMap,Relations1), | |
37 | maplist(remove_relation_wrapper,Relations1,Relations), | |
38 | foldl(add_to_refmap,Relations,In,Out). | |
39 | remove_relation_wrapper(relation(_,_,Rel),Rel). | |
40 | ||
41 | create_refmap_ids(IdMap,In,Out) :- | |
42 | avl_range(IdMap,Relations), | |
43 | foldl(add_to_refmap,Relations,In,Out). | |
44 | add_to_refmap(R,In,Inter) :- | |
45 | get_rel_types(R,Id,Types), | |
46 | avl_store(Id,In,Types,Inter). | |
47 | get_rel_types(reldef(Id,Types,_,_,_),Id,Types). | |
48 | get_rel_types(intsetrel(Id,_,_),Id,[R]) :- | |
49 | intset_relation_kodkod_name(R). | |
50 | get_rel_types(pow2rel(Id,_,_),Id,[R]) :- | |
51 | pow2integer_relation_kodkod_name(R). | |
52 | ||
53 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
54 | % typechecking kodkod expressions with inserting type-casts | |
55 | ||
56 | type_kodkod(KExpr1, Env, OuterType, OuterExpr) :- | |
57 | ( KExpr1 = KExpr:ExpectedType -> | |
58 | % The expression has an explicit type associated, | |
59 | % first make sure that this expected type matches the type seen | |
60 | % by the caller (insert cast if necessary) | |
61 | unify_kodkod_types(ExpectedType,OuterType,Expr,OuterExpr) | |
62 | ; | |
63 | % If there is no explicit type given, the type seen by the | |
64 | % outside is used as the expected type. No cast is needed | |
65 | KExpr=KExpr1, ExpectedType=OuterType, OuterExpr=Expr | |
66 | ), | |
67 | % Now type-check the expression itself | |
68 | type_kodkod2(KExpr, Env, InnerType, InnerExpr), | |
69 | % and try to match the types (insert cat if necessary) | |
70 | unify_kodkod_types(ExpectedType,InnerType,InnerExpr,Expr). | |
71 | ||
72 | :- block unify_kodkod_types(-,-,?,?). | |
73 | unify_kodkod_types(rel(A),rel(B),Expr,NewExpr) :- !, | |
74 | ( A=B -> Expr=NewExpr | |
75 | % both relations can be unified, good | |
76 | ; A=[IS],intset_relation_kodkod_name(IS), | |
77 | B=[P2I],pow2integer_relation_kodkod_name(P2I) -> | |
78 | % expected was a set of integers but given was a set representing | |
79 | % one integer by its bits | |
80 | % TODO: this conversion is not optimal, better try to avoid rel([p2i]) | |
81 | NewExpr = int2intset(expr2int(Expr)) | |
82 | ; A = [P2I],pow2integer_relation_kodkod_name(P2I), | |
83 | B = [IS],intset_relation_kodkod_name(IS) | |
84 | -> % happens in test 709 when rewriting (x=E or x=F) into x:{E,F} | |
85 | % ((x=y or x=z) => (y=x or z=x)) & ((x=y or x=z) <=> (y=x or z=x)) | |
86 | % Test 2197 tests it explicitly | |
87 | NewExpr = int2pow2(expr2int(Expr)) | |
88 | ). | |
89 | unify_kodkod_types(int_expression,int_expression,Expr,Expr) :- !. | |
90 | unify_kodkod_types(formula,formula,Expr,Expr) :- !. | |
91 | unify_kodkod_types(rel([R]),int_expression,Expr,int2intset(Expr)) :- | |
92 | intset_relation_kodkod_name(R),!. | |
93 | unify_kodkod_types(rel([R]),int_expression,Expr,int2pow2(Expr)) :- | |
94 | pow2integer_relation_kodkod_name(R),!. | |
95 | unify_kodkod_types(int_expression,rel([_]),Expr,expr2int(Expr)). | |
96 | % intset_relation_kodkod_name(R). | |
97 | ||
98 | ||
99 | ||
100 | type_kodkod2(relref(Id), Env, rel(Types), relref(Id)) :- !, | |
101 | lookup_reltypes(Id,Env,Types). | |
102 | type_kodkod2(varref(Id), Env, VType, K) :- !, | |
103 | lookup_vartypes(Id,Env,Types), | |
104 | ( Types = [p2i] -> | |
105 | VType = int_expression, K=expr2int(varref(Id)) | |
106 | ; | |
107 | VType = rel(Types), K=varref(Id)). | |
108 | type_kodkod2(int(I), _Env, int_expression, int(I)) :- !. | |
109 | type_kodkod2(prj(Pos,Arg), Env, rel(P), prj(Pos,NArg)) :- | |
110 | !,type_kodkod(Arg,Env,rel(S),NArg), | |
111 | nth0s(Pos,S,P). | |
112 | type_kodkod2(forall(Decls,Formula), Env, formula, forall(NDecls,NFormula)) :- | |
113 | !,type_quantifier(Decls,Formula,Env,_,NDecls,NFormula). | |
114 | type_kodkod2(exists(Decls,Formula), Env, formula, exists(NDecls,NFormula)) :- | |
115 | !,type_quantifier(Decls,Formula,Env,_,NDecls,NFormula). | |
116 | type_kodkod2(comp(Decls,Expr), Env, rel(Types), comp(NDecls,NExpr)) :- | |
117 | !,type_quantifier(Decls,Expr,Env,rel(Types),NDecls,NExpr). | |
118 | type_kodkod2(Expr, Env, Type, NExpr) :- | |
119 | functor(Expr,F,Arity), | |
120 | functor(Lookup,F,Arity), | |
121 | ktype(Lookup,Type),!, | |
122 | Expr =.. [_|Args], Lookup =.. [_|Types], | |
123 | maplist(type_kodkod3(Env),Args,Types,NArgs), | |
124 | NExpr =.. [F|NArgs]. | |
125 | type_kodkod2(Expr, _Env, _Type, _NExpr) :- | |
126 | throw( unsupported_kodkod_expression(Expr) ). | |
127 | ||
128 | % just to swap arguments | |
129 | type_kodkod3(Env,Expr,Type,NExpr) :- | |
130 | type_kodkod(Expr,Env,Type,NExpr). | |
131 | ||
132 | type_quantifier(Decls,Subexpr,Env,rel(Types),NDecls,NSubexpr) :- | |
133 | type_kodkod_declarations(Decls,Env,Env,NDecls,Subenv,Types), | |
134 | type_kodkod(Subexpr,Subenv,formula,NSubexpr). | |
135 | ||
136 | type_kodkod_declarations([],_,Env,[],Env,[]). | |
137 | type_kodkod_declarations([Decl|Drest],Env,EnvIn,[NDecl|Nrest],EnvOut,Types) :- | |
138 | type_kodkod_declaration(Decl,Env,EnvIn,NDecl,EnvInter,Types1), | |
139 | safe_append(Types1,Types2,Types), | |
140 | type_kodkod_declarations(Drest,Env,EnvInter,Nrest,EnvOut,Types2). | |
141 | type_kodkod_declaration(decl(Id,Arity,Mult,Expr),Env,EnvIn, | |
142 | decl(Id,Arity,Mult,NExpr),EnvOut,Types) :- | |
143 | add_var_to_type_env(Id,Types,Env,Subenv), | |
144 | type_kodkod(Expr,Subenv,rel(Types),NExpr), | |
145 | add_var_to_type_env(Id,Types,EnvIn,EnvOut). | |
146 | ||
147 | ||
148 | ktype(true,formula). | |
149 | ktype(false,formula). | |
150 | ktype(not(formula),formula). | |
151 | ktype(and(formula,formula),formula). | |
152 | ktype(or(formula,formula),formula). | |
153 | ktype(implies(formula,formula),formula). | |
154 | ktype(iff(formula,formula),formula). | |
155 | ||
156 | ktype(one(rel(_)), formula). | |
157 | ktype(some(rel(_)), formula). | |
158 | ktype(no(rel(_)), formula). | |
159 | ktype(lone(rel(_)), formula). | |
160 | ktype(set(rel(_)), formula). | |
161 | ||
162 | ktype(in(rel(T),rel(T)), formula). | |
163 | ktype(equals(T,T),formula). | |
164 | ktype(pfunc(rel(_),rel(_),rel(_)), formula). | |
165 | ktype(func(rel(_),rel(_),rel(_)), formula). | |
166 | ||
167 | ktype(empty,rel(_)). | |
168 | ktype(iden,rel(_)). | |
169 | ktype(univ,rel(_)). | |
170 | ktype(intersection(rel(A),rel(A)), rel(A)). | |
171 | ktype(union(rel(A),rel(A)), rel(A)). | |
172 | ktype(difference(rel(A),rel(A)), rel(A)). | |
173 | ktype(overwrite(rel(A),rel(A)), rel(A)). | |
174 | ktype(closure(rel(A)), rel(A)). | |
175 | ktype(reflexive_closure(rel(A)), rel(A)). | |
176 | ktype(product(rel(A),rel(B)), rel(C)) :- safe_append(A,B,C). | |
177 | ktype(transpose(rel(R)), rel(T)) :- safe_reverse(R,T). | |
178 | ktype(join(rel(A),rel([Bhead|Btail])), rel(C)) :- | |
179 | safe_append(Astart,[Bhead],A), | |
180 | safe_append(Astart,Btail,C). | |
181 | ktype(if(formula,rel(R),rel(R)), rel(R)). | |
182 | ||
183 | ktype(gt(int_expression,int_expression), formula). | |
184 | ktype(gte(int_expression,int_expression), formula). | |
185 | ktype(lt(int_expression,int_expression), formula). | |
186 | ktype(lte(int_expression,int_expression), formula). | |
187 | ||
188 | ktype(card(rel(_)), int_expression). | |
189 | ktype(add(int_expression,int_expression), int_expression). | |
190 | ktype(sub(int_expression,int_expression), int_expression). | |
191 | ktype(mul(int_expression,int_expression), int_expression). | |
192 | ktype(div(int_expression,int_expression), int_expression). | |
193 | ktype(floored_div(int_expression,int_expression), int_expression). | |
194 | ktype(mod(int_expression,int_expression), int_expression). | |
195 | ktype(sum(rel([_])), int_expression). | |
196 | ||
197 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
198 | ||
199 | nth0s(Positions,List,Elements) :- maplist(nth0s2(List),Positions,Elements). | |
200 | nth0s2(List,Position,Element) :- nth0(Position,List,Element). | |
201 | ||
202 | safe_append(A,B,C) :- | |
203 | complete_list(A,AComplete), | |
204 | complete_list(B,BComplete), | |
205 | complete_list(C,CComplete), | |
206 | safe_append2(A,B,C,AComplete,BComplete,CComplete). | |
207 | :- block safe_append2(?,?,?,-,-,?), safe_append2(?,?,?,-,?,-). | |
208 | safe_append2(A,B,C,1,1,1) :- append(A,B,C),!. | |
209 | :- block complete_list(-,?). | |
210 | complete_list([],1). | |
211 | complete_list([_|T],Trigger) :- complete_list(T,Trigger). | |
212 | ||
213 | safe_reverse(A,B) :- | |
214 | safe_reverse2(A,[],B), | |
215 | safe_reverse2(B,[],A). | |
216 | :- block safe_reverse2(-,?,?). | |
217 | safe_reverse2([],Acc,Acc). | |
218 | safe_reverse2([H|T],Acc,Rev) :- | |
219 | safe_reverse2(T,[H|Acc],Rev). |