this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
3/*
4 * Main authors:
5 * Guido Tack <guido.tack@monash.edu>
6 */
7
8/* This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11
12#include <minizinc/astexception.hh>
13#include <minizinc/astiterator.hh>
14#include <minizinc/flatten_internal.hh>
15#include <minizinc/hash.hh>
16#include <minizinc/prettyprinter.hh>
17#include <minizinc/typecheck.hh>
18
19#include <sstream>
20#include <string>
21#include <unordered_map>
22
23namespace MiniZinc {
24
25Scopes::Scopes(void) {
26 s.push_back(Scope());
27 s.back().toplevel = true;
28}
29
30void Scopes::add(EnvI& env, VarDecl* vd) {
31 if (!s.back().toplevel && vd->ti()->isEnum() && vd->e()) {
32 throw TypeError(env, vd->loc(), "enums are only allowed at top level");
33 }
34 if (vd->id()->idn() == -1 && vd->id()->v() == "") return;
35 DeclMap::iterator vdi = s.back().m.find(vd->id());
36 if (vdi == s.back().m.end()) {
37 s.back().m.insert(vd->id(), vd);
38 } else {
39 GCLock lock;
40 throw TypeError(env, vd->loc(), "identifier `" + vd->id()->str().str() + "' already defined");
41 }
42}
43
44void Scopes::push(bool toplevel) {
45 s.push_back(Scope());
46 s.back().toplevel = toplevel;
47}
48
49void Scopes::pop(void) { s.pop_back(); }
50
51VarDecl* Scopes::find(Id* ident) {
52 int cur = static_cast<int>(s.size()) - 1;
53 for (;;) {
54 DeclMap::iterator vdi = s[cur].m.find(ident);
55 if (vdi == s[cur].m.end()) {
56 if (s[cur].toplevel) {
57 if (cur > 0)
58 cur = 0;
59 else
60 return NULL;
61 } else {
62 cur--;
63 }
64 } else {
65 return vdi->second;
66 }
67 }
68}
69
70struct VarDeclCmp {
71 std::unordered_map<VarDecl*, int>& _pos;
72 VarDeclCmp(std::unordered_map<VarDecl*, int>& pos) : _pos(pos) {}
73 bool operator()(Expression* e0, Expression* e1) {
74 if (VarDecl* vd0 = Expression::dyn_cast<VarDecl>(e0)) {
75 if (VarDecl* vd1 = Expression::dyn_cast<VarDecl>(e1)) {
76 return _pos[vd0] < _pos[vd1];
77 } else {
78 return true;
79 }
80 } else {
81 return false;
82 }
83 }
84};
85struct ItemCmp {
86 std::unordered_map<VarDecl*, int>& _pos;
87 ItemCmp(std::unordered_map<VarDecl*, int>& pos) : _pos(pos) {}
88 bool operator()(Item* i0, Item* i1) {
89 if (VarDeclI* vd0 = i0->cast<VarDeclI>()) {
90 if (VarDeclI* vd1 = i1->cast<VarDeclI>()) {
91 return _pos[vd0->e()] < _pos[vd1->e()];
92 } else {
93 return true;
94 }
95 } else {
96 return false;
97 }
98 }
99};
100
101std::string createEnumToStringName(Id* ident, std::string prefix) {
102 std::string name = ident->str().str();
103 if (name[0] == '\'') {
104 name = "'" + prefix + name.substr(1);
105 } else {
106 name = prefix + name;
107 }
108 return name;
109}
110
111AssignI* createEnumMapper(EnvI& env, Model* m, unsigned int enumId, VarDecl* vd,
112 VarDecl* vd_enumToString, Model* enumItems) {
113 Id* ident = vd->id();
114 SetLit* sl = vd->e()->dyn_cast<SetLit>();
115 ArrayLit* enum_init_al = NULL;
116 AssignI* ret = NULL;
117
118 GCLock lock;
119 if (ArrayLit* al = vd->e()->dyn_cast<ArrayLit>()) {
120 enum_init_al = al;
121 } else if (Call* c = vd->e()->dyn_cast<Call>()) {
122 if (c->id() != "anon_enum") {
123 throw TypeError(env, c->loc(), "invalid initialisation for enum `" + ident->v().str() + "'");
124 }
125 if (c->n_args() == 1 && c->arg(0)->isa<ArrayLit>()) {
126 enum_init_al = c->arg(0)->cast<ArrayLit>();
127 }
128 }
129 if (enum_init_al) {
130 std::vector<Expression*> enumIds(enum_init_al->size());
131 for (unsigned int i = 0; i < enum_init_al->size(); i++) {
132 if (Id* eid = (*enum_init_al)[i]->dyn_cast<Id>()) {
133 enumIds[i] = eid;
134 } else {
135 throw TypeError(env, vd->e()->loc(),
136 "invalid initialisation for enum `" + ident->v().str() + "'");
137 }
138 }
139 sl = new SetLit(vd->e()->loc(), enumIds);
140 }
141 if (sl) {
142 for (unsigned int i = 0; i < sl->v().size(); i++) {
143 if (!sl->v()[i]->isa<Id>()) {
144 throw TypeError(env, sl->v()[i]->loc(),
145 "invalid initialisation for enum `" + ident->v().str() + "'");
146 }
147 TypeInst* ti_id = new TypeInst(sl->v()[i]->loc(), Type::parenum(enumId));
148
149 std::vector<Expression*> toEnumArgs(2);
150 toEnumArgs[0] = vd->id();
151 toEnumArgs[1] = IntLit::a(i + 1);
152 Call* toEnum = new Call(sl->v()[i]->loc(), ASTString("to_enum"), toEnumArgs);
153 toEnum->decl(env.model->matchFn(env, toEnum, false));
154 VarDecl* vd_id = new VarDecl(ti_id->loc(), ti_id, sl->v()[i]->cast<Id>()->str(), toEnum);
155 enumItems->addItem(new VarDeclI(vd_id->loc(), vd_id));
156 }
157 SetLit* nsl = new SetLit(vd->loc(), IntSetVal::a(1, sl->v().size()));
158 Type tt = nsl->type();
159 tt.enumId(vd->type().enumId());
160 nsl->type(tt);
161 vd->e(nsl);
162 } else if (!vd->e()->isa<Call>()) {
163 throw TypeError(env, vd->e()->loc(),
164 "invalid initialisation for enum `" + ident->v().str() + "'");
165 }
166
167 if (sl) {
168 std::string name = createEnumToStringName(ident, "_enum_to_string_");
169 std::vector<Expression*> al_args(sl->v().size());
170 for (unsigned int i = 0; i < sl->v().size(); i++) {
171 std::string str = sl->v()[i]->cast<Id>()->str().str();
172 if (str.size() >= 2 && str[0] == '\'' && str[str.size() - 1] == '\'') {
173 al_args[i] =
174 new StringLit(Location().introduce(), ASTString(str.substr(1, str.size() - 2)));
175 } else {
176 al_args[i] = new StringLit(Location().introduce(), ASTString(str));
177 }
178 env.reverseEnum[str] = i + 1;
179 }
180 ArrayLit* al = new ArrayLit(Location().introduce(), al_args);
181
182 if (vd_enumToString) {
183 ret = new AssignI(Location().introduce(), name, al);
184 ret->decl(vd_enumToString);
185 } else {
186 std::vector<TypeInst*> ranges(1);
187 ranges[0] = new TypeInst(Location().introduce(), Type::parint());
188 TypeInst* ti = new TypeInst(Location().introduce(), Type::parstring(1));
189 ti->setRanges(ranges);
190 vd_enumToString = new VarDecl(Location().introduce(), ti, name, al);
191 enumItems->addItem(new VarDeclI(Location().introduce(), vd_enumToString));
192 }
193
194 Type tx = Type::parint();
195 tx.ot(Type::OT_OPTIONAL);
196 TypeInst* ti_aa = new TypeInst(Location().introduce(), tx);
197 VarDecl* vd_aa = new VarDecl(Location().introduce(), ti_aa, "x");
198 vd_aa->toplevel(false);
199 TypeInst* ti_ab = new TypeInst(Location().introduce(), Type::parbool());
200 VarDecl* vd_ab = new VarDecl(Location().introduce(), ti_ab, "b");
201 vd_ab->toplevel(false);
202 TypeInst* ti_aj = new TypeInst(Location().introduce(), Type::parbool());
203 VarDecl* vd_aj = new VarDecl(Location().introduce(), ti_aj, "json");
204 vd_aj->toplevel(false);
205 TypeInst* ti_fi = new TypeInst(Location().introduce(), Type::parstring());
206 std::vector<VarDecl*> fi_params(3);
207 fi_params[0] = vd_aa;
208 fi_params[1] = vd_ab;
209 fi_params[2] = vd_aj;
210
211 std::vector<Expression*> deopt_args(1);
212 deopt_args[0] = vd_aa->id();
213 Call* deopt = new Call(Location().introduce(), "deopt", deopt_args);
214 Call* occurs = new Call(Location().introduce(), "occurs", deopt_args);
215 std::vector<Expression*> aa_args(1);
216 aa_args[0] = deopt;
217 ArrayAccess* aa = new ArrayAccess(Location().introduce(), vd_enumToString->id(), aa_args);
218
219 StringLit* sl_absent = new StringLit(Location().introduce(), "<>");
220
221 ITE* if_absent =
222 new ITE(Location().introduce(),
223 {vd_aj->id(), new StringLit(Location().introduce(), ASTString("null"))}, sl_absent);
224
225 StringLit* json_e_quote = new StringLit(Location().introduce(), ASTString("{\"e\":\""));
226 StringLit* json_e_quote_end = new StringLit(Location().introduce(), ASTString("\"}"));
227 BinOp* quote_aa = new BinOp(Location().introduce(), json_e_quote, BOT_PLUSPLUS, aa);
228 BinOp* quote_aa2 = new BinOp(Location().introduce(), quote_aa, BOT_PLUSPLUS, json_e_quote_end);
229
230 Call* quote_dzn = new Call(Location().introduce(), ASTString("showDznId"), {aa});
231
232 std::vector<Expression*> ite_ifelse(2);
233 ite_ifelse[0] = occurs;
234 ite_ifelse[1] =
235 new ITE(Location().introduce(), {vd_ab->id(), quote_dzn, vd_aj->id(), quote_aa2}, aa);
236
237 ITE* ite = new ITE(Location().introduce(), ite_ifelse, if_absent);
238
239 FunctionI* fi = new FunctionI(
240 Location().introduce(), createEnumToStringName(ident, "_toString_"), ti_fi, fi_params, ite);
241 enumItems->addItem(fi);
242 } else {
243 if (vd_enumToString) {
244 /// TODO: find a better solution (don't introduce the vd_enumToString until we
245 /// know it's a non-anonymous enum)
246 vd_enumToString->e(new ArrayLit(Location().introduce(), std::vector<Expression*>()));
247 }
248 {
249 Type tx = Type::parint();
250 tx.ot(Type::OT_OPTIONAL);
251 TypeInst* ti_aa = new TypeInst(Location().introduce(), tx);
252 VarDecl* vd_aa = new VarDecl(Location().introduce(), ti_aa, "x");
253 vd_aa->toplevel(false);
254
255 TypeInst* ti_ab = new TypeInst(Location().introduce(), Type::parbool());
256 VarDecl* vd_ab = new VarDecl(Location().introduce(), ti_ab, "b");
257 vd_ab->toplevel(false);
258
259 TypeInst* ti_aj = new TypeInst(Location().introduce(), Type::parbool());
260 VarDecl* vd_aj = new VarDecl(Location().introduce(), ti_aj, "json");
261 vd_aj->toplevel(false);
262
263 std::vector<Expression*> deopt_args(1);
264 deopt_args[0] = vd_aa->id();
265 Call* deopt = new Call(Location().introduce(), "deopt", deopt_args);
266 Call* if_absent = new Call(Location().introduce(), "absent", deopt_args);
267 StringLit* sl_absent_dzn = new StringLit(Location().introduce(), "<>");
268 ITE* sl_absent = new ITE(
269 Location().introduce(),
270 {vd_aj->id(), new StringLit(Location().introduce(), ASTString("null"))}, sl_absent_dzn);
271
272 StringLit* sl_dzn =
273 new StringLit(Location().introduce(), ASTString("to_enum(" + ident->str().str() + ","));
274 std::vector<Expression*> showIntArgs(1);
275 showIntArgs[0] = deopt;
276 Call* showInt = new Call(Location().introduce(), constants().ids.show, showIntArgs);
277 BinOp* construct_string_dzn =
278 new BinOp(Location().introduce(), sl_dzn, BOT_PLUSPLUS, showInt);
279 StringLit* closing_bracket = new StringLit(Location().introduce(), ASTString(")"));
280 BinOp* construct_string_dzn_2 =
281 new BinOp(Location().introduce(), construct_string_dzn, BOT_PLUSPLUS, closing_bracket);
282
283 StringLit* sl = new StringLit(Location().introduce(), ASTString(ident->str().str() + "_"));
284 BinOp* construct_string = new BinOp(Location().introduce(), sl, BOT_PLUSPLUS, showInt);
285
286 StringLit* json_e_quote = new StringLit(Location().introduce(), ASTString("{\"e\":\""));
287 StringLit* json_e_quote_end = new StringLit(Location().introduce(), ASTString("\"}"));
288 BinOp* construct_string_json =
289 new BinOp(Location().introduce(), json_e_quote, BOT_PLUSPLUS, construct_string);
290 BinOp* construct_string_json_2 =
291 new BinOp(Location().introduce(), construct_string_json, BOT_PLUSPLUS, json_e_quote_end);
292
293 std::vector<Expression*> if_then(6);
294 if_then[0] = if_absent;
295 if_then[1] = sl_absent;
296 if_then[2] = vd_ab->id();
297 if_then[3] = construct_string_dzn_2;
298 if_then[4] = vd_aj->id();
299 if_then[5] = construct_string_json_2;
300 ITE* ite = new ITE(Location().introduce(), if_then, construct_string);
301
302 TypeInst* ti_fi = new TypeInst(Location().introduce(), Type::parstring());
303 std::vector<VarDecl*> fi_params(3);
304 fi_params[0] = vd_aa;
305 fi_params[1] = vd_ab;
306 fi_params[2] = vd_aj;
307 FunctionI* fi =
308 new FunctionI(Location().introduce(), createEnumToStringName(ident, "_toString_"), ti_fi,
309 fi_params, ite);
310 enumItems->addItem(fi);
311 }
312 }
313
314 {
315 /*
316
317 function _toString_ENUM(array[$U] of opt Foo: x, bool: b, bool: json) =
318 let {
319 array[int] of opt ENUM: xx = array1d(x)
320 } in "[" ++ join(", ", [ _toString_ENUM(xx[i],b,json) | i in index_set(xx) ]) ++ "]";
321
322 */
323
324 TIId* tiid = new TIId(Location().introduce(), "U");
325 TypeInst* ti_range = new TypeInst(Location().introduce(), Type::parint(), tiid);
326 std::vector<TypeInst*> ranges(1);
327 ranges[0] = ti_range;
328
329 Type tx = Type::parint(-1);
330 tx.ot(Type::OT_OPTIONAL);
331 TypeInst* x_ti = new TypeInst(Location().introduce(), tx, ranges, ident);
332 VarDecl* vd_x = new VarDecl(Location().introduce(), x_ti, "x");
333 vd_x->toplevel(false);
334
335 TypeInst* b_ti = new TypeInst(Location().introduce(), Type::parbool());
336 VarDecl* vd_b = new VarDecl(Location().introduce(), b_ti, "b");
337 vd_b->toplevel(false);
338
339 TypeInst* j_ti = new TypeInst(Location().introduce(), Type::parbool());
340 VarDecl* vd_j = new VarDecl(Location().introduce(), j_ti, "json");
341 vd_j->toplevel(false);
342
343 TypeInst* xx_range = new TypeInst(Location().introduce(), Type::parint(), NULL);
344 std::vector<TypeInst*> xx_ranges(1);
345 xx_ranges[0] = xx_range;
346 TypeInst* xx_ti = new TypeInst(Location().introduce(), tx, xx_ranges, ident);
347
348 std::vector<Expression*> array1dArgs(1);
349 array1dArgs[0] = vd_x->id();
350 Call* array1dCall = new Call(Location().introduce(), "array1d", array1dArgs);
351
352 VarDecl* vd_xx = new VarDecl(Location().introduce(), xx_ti, "xx", array1dCall);
353 vd_xx->toplevel(false);
354
355 TypeInst* idx_i_ti = new TypeInst(Location().introduce(), Type::parint());
356 VarDecl* idx_i = new VarDecl(Location().introduce(), idx_i_ti, "i");
357 idx_i->toplevel(false);
358
359 std::vector<Expression*> aa_xxi_idx(1);
360 aa_xxi_idx[0] = idx_i->id();
361 ArrayAccess* aa_xxi = new ArrayAccess(Location().introduce(), vd_xx->id(), aa_xxi_idx);
362
363 std::vector<Expression*> _toString_ENUMArgs(3);
364 _toString_ENUMArgs[0] = aa_xxi;
365 _toString_ENUMArgs[1] = vd_b->id();
366 _toString_ENUMArgs[2] = vd_j->id();
367 Call* _toString_ENUM = new Call(
368 Location().introduce(), createEnumToStringName(ident, "_toString_"), _toString_ENUMArgs);
369
370 std::vector<Expression*> index_set_xx_args(1);
371 index_set_xx_args[0] = vd_xx->id();
372 Call* index_set_xx = new Call(Location().introduce(), "index_set", index_set_xx_args);
373 std::vector<VarDecl*> gen_exps(1);
374 gen_exps[0] = idx_i;
375 Generator gen(gen_exps, index_set_xx, NULL);
376
377 Generators generators;
378 generators._g.push_back(gen);
379 Comprehension* comp =
380 new Comprehension(Location().introduce(), _toString_ENUM, generators, false);
381
382 std::vector<Expression*> join_args(2);
383 join_args[0] = new StringLit(Location().introduce(), ", ");
384 join_args[1] = comp;
385 Call* join = new Call(Location().introduce(), "join", join_args);
386
387 StringLit* sl_open = new StringLit(Location().introduce(), "[");
388 BinOp* bopp0 = new BinOp(Location().introduce(), sl_open, BOT_PLUSPLUS, join);
389 StringLit* sl_close = new StringLit(Location().introduce(), "]");
390 BinOp* bopp1 = new BinOp(Location().introduce(), bopp0, BOT_PLUSPLUS, sl_close);
391
392 std::vector<Expression*> let_args(1);
393 let_args[0] = vd_xx;
394 Let* let = new Let(Location().introduce(), let_args, bopp1);
395
396 TypeInst* ti_fi = new TypeInst(Location().introduce(), Type::parstring());
397 std::vector<VarDecl*> fi_params(3);
398 fi_params[0] = vd_x;
399 fi_params[1] = vd_b;
400 fi_params[2] = vd_j;
401 FunctionI* fi = new FunctionI(
402 Location().introduce(), createEnumToStringName(ident, "_toString_"), ti_fi, fi_params, let);
403 enumItems->addItem(fi);
404 }
405
406 {
407 /*
408
409 function _toString_ENUM(opt set of ENUM: x, bool: b, bool: json) =
410 if absent(x) then "<>" else "{" ++ join(", ", [ _toString_ENUM(i,b,json) | i in x ]) ++ "}"
411 endif;
412
413 */
414
415 Type argType = Type::parsetenum(ident->type().enumId());
416 argType.ot(Type::OT_OPTIONAL);
417 TypeInst* x_ti = new TypeInst(Location().introduce(), argType, ident);
418 VarDecl* vd_x = new VarDecl(Location().introduce(), x_ti, "x");
419 vd_x->toplevel(false);
420
421 TypeInst* b_ti = new TypeInst(Location().introduce(), Type::parbool());
422 VarDecl* vd_b = new VarDecl(Location().introduce(), b_ti, "b");
423 vd_b->toplevel(false);
424
425 TypeInst* j_ti = new TypeInst(Location().introduce(), Type::parbool());
426 VarDecl* vd_j = new VarDecl(Location().introduce(), j_ti, "json");
427 vd_j->toplevel(false);
428
429 TypeInst* idx_i_ti = new TypeInst(Location().introduce(), Type::parint());
430 VarDecl* idx_i = new VarDecl(Location().introduce(), idx_i_ti, "i");
431 idx_i->toplevel(false);
432
433 std::vector<Expression*> _toString_ENUMArgs(3);
434 _toString_ENUMArgs[0] = idx_i->id();
435 _toString_ENUMArgs[1] = vd_b->id();
436 _toString_ENUMArgs[2] = vd_j->id();
437 Call* _toString_ENUM = new Call(
438 Location().introduce(), createEnumToStringName(ident, "_toString_"), _toString_ENUMArgs);
439
440 std::vector<Expression*> deopt_args(1);
441 deopt_args[0] = vd_x->id();
442 Call* deopt = new Call(Location().introduce(), "deopt", deopt_args);
443 Call* if_absent = new Call(Location().introduce(), "absent", deopt_args);
444 StringLit* sl_absent_dzn = new StringLit(Location().introduce(), "<>");
445 ITE* sl_absent = new ITE(Location().introduce(),
446 {vd_j->id(), new StringLit(Location().introduce(), ASTString("null"))},
447 sl_absent_dzn);
448
449 std::vector<VarDecl*> gen_exps(1);
450 gen_exps[0] = idx_i;
451 Generator gen(gen_exps, deopt, NULL);
452
453 Generators generators;
454 generators._g.push_back(gen);
455 Comprehension* comp =
456 new Comprehension(Location().introduce(), _toString_ENUM, generators, false);
457
458 std::vector<Expression*> join_args(2);
459 join_args[0] = new StringLit(Location().introduce(), ", ");
460 join_args[1] = comp;
461 Call* join = new Call(Location().introduce(), "join", join_args);
462
463 ITE* json_set =
464 new ITE(Location().introduce(),
465 {vd_j->id(), new StringLit(Location().introduce(), ASTString("\"set\":["))},
466 new StringLit(Location().introduce(), ASTString("")));
467 ITE* json_set_close = new ITE(
468 Location().introduce(), {vd_j->id(), new StringLit(Location().introduce(), ASTString("]"))},
469 new StringLit(Location().introduce(), ASTString("")));
470
471 StringLit* sl_open = new StringLit(Location().introduce(), "{");
472 BinOp* bopp0 = new BinOp(Location().introduce(), sl_open, BOT_PLUSPLUS, json_set);
473 BinOp* bopp1 = new BinOp(Location().introduce(), bopp0, BOT_PLUSPLUS, join);
474 BinOp* bopp2 = new BinOp(Location().introduce(), bopp1, BOT_PLUSPLUS, json_set_close);
475 StringLit* sl_close = new StringLit(Location().introduce(), "}");
476 BinOp* bopp3 = new BinOp(Location().introduce(), bopp2, BOT_PLUSPLUS, sl_close);
477
478 std::vector<Expression*> if_then(2);
479 if_then[0] = if_absent;
480 if_then[1] = sl_absent;
481 ITE* ite = new ITE(Location().introduce(), if_then, bopp3);
482
483 TypeInst* ti_fi = new TypeInst(Location().introduce(), Type::parstring());
484 std::vector<VarDecl*> fi_params(3);
485 fi_params[0] = vd_x;
486 fi_params[1] = vd_b;
487 fi_params[2] = vd_j;
488 FunctionI* fi = new FunctionI(
489 Location().introduce(), createEnumToStringName(ident, "_toString_"), ti_fi, fi_params, ite);
490 enumItems->addItem(fi);
491 }
492
493 {
494 /*
495
496 function _toString_ENUM(array[$U] of opt set of ENUM: x, bool: b, bool: json) =
497 let {
498 array[int] of opt set of ENUM: xx = array1d(x)
499 } in "[" ++ join(", ", [ _toString_ENUM(xx[i],b,json) | i in index_set(xx) ]) ++ "]";
500
501 */
502
503 TIId* tiid = new TIId(Location().introduce(), "U");
504 TypeInst* ti_range = new TypeInst(Location().introduce(), Type::parint(), tiid);
505 std::vector<TypeInst*> ranges(1);
506 ranges[0] = ti_range;
507
508 Type tx = Type::parsetint(-1);
509 tx.ot(Type::OT_OPTIONAL);
510 TypeInst* x_ti = new TypeInst(Location().introduce(), tx, ranges, ident);
511 VarDecl* vd_x = new VarDecl(Location().introduce(), x_ti, "x");
512 vd_x->toplevel(false);
513
514 TypeInst* b_ti = new TypeInst(Location().introduce(), Type::parbool());
515 VarDecl* vd_b = new VarDecl(Location().introduce(), b_ti, "b");
516 vd_b->toplevel(false);
517
518 TypeInst* j_ti = new TypeInst(Location().introduce(), Type::parbool());
519 VarDecl* vd_j = new VarDecl(Location().introduce(), j_ti, "json");
520 vd_j->toplevel(false);
521
522 TypeInst* xx_range = new TypeInst(Location().introduce(), Type::parint(), NULL);
523 std::vector<TypeInst*> xx_ranges(1);
524 xx_ranges[0] = xx_range;
525 TypeInst* xx_ti = new TypeInst(Location().introduce(), tx, xx_ranges, ident);
526
527 std::vector<Expression*> array1dArgs(1);
528 array1dArgs[0] = vd_x->id();
529 Call* array1dCall = new Call(Location().introduce(), "array1d", array1dArgs);
530
531 VarDecl* vd_xx = new VarDecl(Location().introduce(), xx_ti, "xx", array1dCall);
532 vd_xx->toplevel(false);
533
534 TypeInst* idx_i_ti = new TypeInst(Location().introduce(), Type::parint());
535 VarDecl* idx_i = new VarDecl(Location().introduce(), idx_i_ti, "i");
536 idx_i->toplevel(false);
537
538 std::vector<Expression*> aa_xxi_idx(1);
539 aa_xxi_idx[0] = idx_i->id();
540 ArrayAccess* aa_xxi = new ArrayAccess(Location().introduce(), vd_xx->id(), aa_xxi_idx);
541
542 std::vector<Expression*> _toString_ENUMArgs(3);
543 _toString_ENUMArgs[0] = aa_xxi;
544 _toString_ENUMArgs[1] = vd_b->id();
545 _toString_ENUMArgs[2] = vd_j->id();
546 Call* _toString_ENUM = new Call(
547 Location().introduce(), createEnumToStringName(ident, "_toString_"), _toString_ENUMArgs);
548
549 std::vector<Expression*> index_set_xx_args(1);
550 index_set_xx_args[0] = vd_xx->id();
551 Call* index_set_xx = new Call(Location().introduce(), "index_set", index_set_xx_args);
552 std::vector<VarDecl*> gen_exps(1);
553 gen_exps[0] = idx_i;
554 Generator gen(gen_exps, index_set_xx, NULL);
555
556 Generators generators;
557 generators._g.push_back(gen);
558 Comprehension* comp =
559 new Comprehension(Location().introduce(), _toString_ENUM, generators, false);
560
561 std::vector<Expression*> join_args(2);
562 join_args[0] = new StringLit(Location().introduce(), ", ");
563 join_args[1] = comp;
564 Call* join = new Call(Location().introduce(), "join", join_args);
565
566 StringLit* sl_open = new StringLit(Location().introduce(), "[");
567 BinOp* bopp0 = new BinOp(Location().introduce(), sl_open, BOT_PLUSPLUS, join);
568 StringLit* sl_close = new StringLit(Location().introduce(), "]");
569 BinOp* bopp1 = new BinOp(Location().introduce(), bopp0, BOT_PLUSPLUS, sl_close);
570
571 std::vector<Expression*> let_args(1);
572 let_args[0] = vd_xx;
573 Let* let = new Let(Location().introduce(), let_args, bopp1);
574
575 TypeInst* ti_fi = new TypeInst(Location().introduce(), Type::parstring());
576 std::vector<VarDecl*> fi_params(3);
577 fi_params[0] = vd_x;
578 fi_params[1] = vd_b;
579 fi_params[2] = vd_j;
580 FunctionI* fi = new FunctionI(
581 Location().introduce(), createEnumToStringName(ident, "_toString_"), ti_fi, fi_params, let);
582 enumItems->addItem(fi);
583 }
584 return ret;
585}
586
587void TopoSorter::add(EnvI& env, VarDeclI* vdi, bool handleEnums, Model* enumItems) {
588 VarDecl* vd = vdi->e();
589 if (handleEnums && vd->ti()->isEnum()) {
590 unsigned int enumId = env.registerEnum(vdi);
591 Type vdt = vd->type();
592 vdt.enumId(enumId);
593 vd->ti()->type(vdt);
594 vd->type(vdt);
595
596 if (vd->e()) {
597 (void)createEnumMapper(env, model, enumId, vd, NULL, enumItems);
598 } else {
599 GCLock lock;
600 std::string name = createEnumToStringName(vd->id(), "_enum_to_string_");
601 std::vector<TypeInst*> ranges(1);
602 ranges[0] = new TypeInst(Location().introduce(), Type::parint());
603 TypeInst* ti = new TypeInst(Location().introduce(), Type::parstring(1));
604 ti->setRanges(ranges);
605 VarDecl* vd_enumToString = new VarDecl(Location().introduce(), ti, name, NULL);
606 enumItems->addItem(new VarDeclI(Location().introduce(), vd_enumToString));
607 }
608 }
609 scopes.add(env, vd);
610}
611
612VarDecl* TopoSorter::get(EnvI& env, const ASTString& id_v, const Location& loc) {
613 GCLock lock;
614 Id* id = new Id(Location(), id_v, NULL);
615 VarDecl* decl = scopes.find(id);
616 if (decl == NULL) {
617 throw TypeError(env, loc, "undefined identifier `" + id->str().str() + "'");
618 }
619 return decl;
620}
621
622VarDecl* TopoSorter::checkId(EnvI& env, Id* ident, const Location& loc) {
623 VarDecl* decl = scopes.find(ident);
624 if (decl == NULL) {
625 GCLock lock;
626 throw TypeError(env, loc, "undefined identifier `" + ident->str().str() + "'");
627 }
628 PosMap::iterator pi = pos.find(decl);
629 if (pi == pos.end()) {
630 // new id
631 scopes.push(true);
632 run(env, decl);
633 scopes.pop();
634 } else {
635 // previously seen, check if circular
636 if (pi->second == -1) {
637 GCLock lock;
638 throw TypeError(env, loc, "circular definition of `" + ident->str().str() + "'");
639 }
640 }
641 return decl;
642}
643
644VarDecl* TopoSorter::checkId(EnvI& env, const ASTString& id_v, const Location& loc) {
645 GCLock lock;
646 Id* id = new Id(loc, id_v, NULL);
647 return checkId(env, id, loc);
648}
649
650void TopoSorter::run(EnvI& env, Expression* e) {
651 if (e == NULL) return;
652 switch (e->eid()) {
653 case Expression::E_INTLIT:
654 case Expression::E_FLOATLIT:
655 case Expression::E_BOOLLIT:
656 case Expression::E_STRINGLIT:
657 case Expression::E_ANON:
658 break;
659 case Expression::E_SETLIT: {
660 SetLit* sl = e->cast<SetLit>();
661 if (sl->isv() == NULL && sl->fsv() == NULL)
662 for (unsigned int i = 0; i < sl->v().size(); i++) run(env, sl->v()[i]);
663 } break;
664 case Expression::E_ID: {
665 if (e != constants().absent) {
666 VarDecl* vd = checkId(env, e->cast<Id>(), e->loc());
667 e->cast<Id>()->decl(vd);
668 }
669 } break;
670 case Expression::E_ARRAYLIT: {
671 ArrayLit* al = e->cast<ArrayLit>();
672 for (unsigned int i = 0; i < al->size(); i++) run(env, (*al)[i]);
673 } break;
674 case Expression::E_ARRAYACCESS: {
675 ArrayAccess* ae = e->cast<ArrayAccess>();
676 run(env, ae->v());
677 for (unsigned int i = 0; i < ae->idx().size(); i++) run(env, ae->idx()[i]);
678 } break;
679 case Expression::E_COMP: {
680 Comprehension* ce = e->cast<Comprehension>();
681 scopes.push(false);
682 for (int i = 0; i < ce->n_generators(); i++) {
683 run(env, ce->in(i));
684 for (int j = 0; j < ce->n_decls(i); j++) {
685 run(env, ce->decl(i, j));
686 scopes.add(env, ce->decl(i, j));
687 }
688 if (ce->where(i)) run(env, ce->where(i));
689 }
690 run(env, ce->e());
691 scopes.pop();
692 } break;
693 case Expression::E_ITE: {
694 ITE* ite = e->cast<ITE>();
695 for (int i = 0; i < ite->size(); i++) {
696 run(env, ite->e_if(i));
697 run(env, ite->e_then(i));
698 }
699 run(env, ite->e_else());
700 } break;
701 case Expression::E_BINOP: {
702 BinOp* be = e->cast<BinOp>();
703 std::vector<Expression*> todo;
704 todo.push_back(be->lhs());
705 todo.push_back(be->rhs());
706 while (!todo.empty()) {
707 Expression* e = todo.back();
708 todo.pop_back();
709 if (BinOp* e_bo = e->dyn_cast<BinOp>()) {
710 todo.push_back(e_bo->lhs());
711 todo.push_back(e_bo->rhs());
712 for (ExpressionSetIter it = e_bo->ann().begin(); it != e_bo->ann().end(); ++it)
713 run(env, *it);
714 } else {
715 run(env, e);
716 }
717 }
718 } break;
719 case Expression::E_UNOP: {
720 UnOp* ue = e->cast<UnOp>();
721 run(env, ue->e());
722 } break;
723 case Expression::E_CALL: {
724 Call* ce = e->cast<Call>();
725 for (unsigned int i = 0; i < ce->n_args(); i++) run(env, ce->arg(i));
726 } break;
727 case Expression::E_VARDECL: {
728 VarDecl* ve = e->cast<VarDecl>();
729 PosMap::iterator pi = pos.find(ve);
730 if (pi == pos.end()) {
731 pos.insert(std::pair<VarDecl*, int>(ve, -1));
732 run(env, ve->ti());
733 run(env, ve->e());
734 ve->payload(static_cast<int>(decls.size()));
735 decls.push_back(ve);
736 pi = pos.find(ve);
737 pi->second = static_cast<int>(decls.size()) - 1;
738 } else {
739 assert(pi->second != -1);
740 }
741 } break;
742 case Expression::E_TI: {
743 TypeInst* ti = e->cast<TypeInst>();
744 for (unsigned int i = 0; i < ti->ranges().size(); i++) run(env, ti->ranges()[i]);
745 run(env, ti->domain());
746 } break;
747 case Expression::E_TIID:
748 break;
749 case Expression::E_LET: {
750 Let* let = e->cast<Let>();
751 scopes.push(false);
752 for (unsigned int i = 0; i < let->let().size(); i++) {
753 run(env, let->let()[i]);
754 if (VarDecl* vd = let->let()[i]->dyn_cast<VarDecl>()) {
755 scopes.add(env, vd);
756 }
757 }
758 run(env, let->in());
759 VarDeclCmp poscmp(pos);
760 std::stable_sort(let->let().begin(), let->let().end(), poscmp);
761 for (unsigned int i = 0; i < let->let().size(); i++) {
762 if (VarDecl* vd = let->let()[i]->dyn_cast<VarDecl>()) {
763 let->let_orig()[i] = vd->e();
764 } else {
765 let->let_orig()[i] = NULL;
766 }
767 }
768 scopes.pop();
769 } break;
770 }
771 if (env.ignoreUnknownIds) {
772 std::vector<Expression*> toDelete;
773 for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) {
774 try {
775 run(env, *it);
776 } catch (TypeError&) {
777 toDelete.push_back(*it);
778 }
779 for (Expression* de : toDelete) e->ann().remove(de);
780 }
781 } else {
782 for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) {
783 run(env, *it);
784 }
785 }
786}
787
788KeepAlive addCoercion(EnvI& env, Model* m, Expression* e, const Type& funarg_t) {
789 if (e->isa<ArrayAccess>() && e->type().dim() > 0) {
790 ArrayAccess* aa = e->cast<ArrayAccess>();
791 // Turn ArrayAccess into a slicing operation
792 std::vector<Expression*> slice;
793 slice.reserve(aa->idx().size());
794 std::vector<Expression*> ndims;
795 GCLock lock;
796 for (unsigned int i = 0; i < aa->idx().size(); i++) {
797 if (aa->idx()[i]->type().is_set()) {
798 bool needIdxSet = true;
799 bool needInter = true;
800 if (SetLit* sl = aa->idx()[i]->dyn_cast<SetLit>()) {
801 if (sl->isv() && sl->isv()->size() == 1) {
802 if (sl->isv()->min().isFinite() && sl->isv()->max().isFinite()) {
803 ndims.push_back(sl);
804 needIdxSet = false;
805 } else if (sl->isv()->min() == -IntVal::infinity() &&
806 sl->isv()->max() == IntVal::infinity()) {
807 needInter = false;
808 }
809 }
810 }
811 if (needIdxSet) {
812 std::ostringstream oss;
813 oss << "index_set";
814 if (aa->idx().size() > 1) {
815 oss << "_" << (i + 1) << "of" << aa->idx().size();
816 }
817 std::vector<Expression*> origIdxsetArgs(1);
818 origIdxsetArgs[0] = aa->v();
819 Call* origIdxset = new Call(aa->v()->loc(), ASTString(oss.str()), origIdxsetArgs);
820 FunctionI* fi = m->matchFn(env, origIdxset, false);
821 if (!fi) throw TypeError(env, e->loc(), "missing builtin " + oss.str());
822 origIdxset->type(fi->rtype(env, origIdxsetArgs, false));
823 origIdxset->decl(fi);
824 if (needInter) {
825 BinOp* inter = new BinOp(aa->idx()[i]->loc(), aa->idx()[i], BOT_INTERSECT, origIdxset);
826 inter->type(Type::parsetint());
827 ndims.push_back(inter);
828 } else {
829 ndims.push_back(origIdxset);
830 }
831 }
832 slice.push_back(aa->idx()[i]);
833 } else {
834 BinOp* bo = new BinOp(aa->idx()[i]->loc(), aa->idx()[i], BOT_DOTDOT, aa->idx()[i]);
835 bo->type(Type::parsetint());
836 slice.push_back(bo);
837 }
838 }
839 ArrayLit* a_slice = new ArrayLit(e->loc().introduce(), slice);
840 a_slice->type(Type::parsetint(1));
841 ArrayLit* a_ndims = new ArrayLit(e->loc().introduce(), ndims);
842 a_ndims->type(Type::parsetint(1));
843 std::vector<Expression*> args = {aa->v(), a_slice, a_ndims};
844 Call* c = new Call(e->loc(), ASTString("slice_Xd"), args);
845 FunctionI* fi = m->matchFn(env, c, false);
846 if (!fi) throw TypeError(env, e->loc(), "missing builtin slice_Xd");
847 c->type(fi->rtype(env, args, false));
848 c->decl(fi);
849 e = c;
850 }
851 if (e->type().dim() == funarg_t.dim() &&
852 (funarg_t.bt() == Type::BT_BOT || funarg_t.bt() == Type::BT_TOP ||
853 e->type().bt() == funarg_t.bt() || e->type().bt() == Type::BT_BOT))
854 return e;
855 std::vector<Expression*> args(1);
856 args[0] = e;
857 GCLock lock;
858 Call* c = NULL;
859 if (e->type().dim() == 0 && funarg_t.dim() != 0) {
860 if (e->type().isvar()) {
861 throw TypeError(env, e->loc(), "cannot coerce var set into array");
862 }
863 if (e->type().isopt()) {
864 throw TypeError(env, e->loc(), "cannot coerce opt set into array");
865 }
866 std::vector<Expression*> set2a_args(1);
867 set2a_args[0] = e;
868 Call* set2a = new Call(e->loc(), ASTString("set2array"), set2a_args);
869 FunctionI* fi = m->matchFn(env, set2a, false);
870 if (fi) {
871 set2a->type(fi->rtype(env, args, false));
872 set2a->decl(fi);
873 e = set2a;
874 }
875 }
876 if (funarg_t.bt() == Type::BT_TOP || e->type().bt() == funarg_t.bt() ||
877 e->type().bt() == Type::BT_BOT) {
878 KeepAlive ka(e);
879 return ka;
880 }
881 if (e->type().bt() == Type::BT_BOOL) {
882 if (funarg_t.bt() == Type::BT_INT) {
883 c = new Call(e->loc(), constants().ids.bool2int, args);
884 } else if (funarg_t.bt() == Type::BT_FLOAT) {
885 c = new Call(e->loc(), constants().ids.bool2float, args);
886 }
887 } else if (e->type().bt() == Type::BT_INT) {
888 if (funarg_t.bt() == Type::BT_FLOAT) {
889 c = new Call(e->loc(), constants().ids.int2float, args);
890 }
891 }
892 if (c) {
893 FunctionI* fi = m->matchFn(env, c, false);
894 assert(fi);
895 c->type(fi->rtype(env, args, false));
896 c->decl(fi);
897 KeepAlive ka(c);
898 return ka;
899 }
900 throw TypeError(env, e->loc(),
901 "cannot determine coercion from type " + e->type().toString(env) + " to type " +
902 funarg_t.toString(env));
903}
904KeepAlive addCoercion(EnvI& env, Model* m, Expression* e, Expression* funarg) {
905 return addCoercion(env, m, e, funarg->type());
906}
907
908template <bool ignoreVarDecl>
909class Typer {
910public:
911 EnvI& _env;
912 Model* _model;
913 std::vector<TypeError>& _typeErrors;
914 bool _ignoreUndefined;
915 Typer(EnvI& env, Model* model, std::vector<TypeError>& typeErrors, bool ignoreUndefined)
916 : _env(env), _model(model), _typeErrors(typeErrors), _ignoreUndefined(ignoreUndefined) {}
917 /// Check annotations when expression is finished
918 void exit(Expression* e) {
919 for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it)
920 if (!(*it)->type().isann())
921 throw TypeError(_env, (*it)->loc(),
922 "expected annotation, got `" + (*it)->type().toString(_env) + "'");
923 }
924 bool enter(Expression*) { return true; }
925 /// Visit integer literal
926 void vIntLit(const IntLit&) {}
927 /// Visit floating point literal
928 void vFloatLit(const FloatLit&) {}
929 /// Visit Boolean literal
930 void vBoolLit(const BoolLit&) {}
931 /// Visit set literal
932 void vSetLit(SetLit& sl) {
933 Type ty;
934 ty.st(Type::ST_SET);
935 if (sl.isv()) {
936 ty.bt(Type::BT_INT);
937 ty.enumId(sl.type().enumId());
938 sl.type(ty);
939 return;
940 }
941 unsigned int enumId = sl.v().size() > 0 ? sl.v()[0]->type().enumId() : 0;
942 for (unsigned int i = 0; i < sl.v().size(); i++) {
943 if (sl.v()[i]->type().dim() > 0)
944 throw TypeError(_env, sl.v()[i]->loc(), "set literals cannot contain arrays");
945 if (sl.v()[i]->type().isvar()) ty.ti(Type::TI_VAR);
946 if (sl.v()[i]->type().isopt())
947 throw TypeError(_env, sl.v()[i]->loc(), "set literals cannot contain option type values");
948 if (sl.v()[i]->type().cv()) ty.cv(true);
949 if (enumId != sl.v()[i]->type().enumId()) enumId = 0;
950 if (!Type::bt_subtype(sl.v()[i]->type(), ty, true)) {
951 if (ty.bt() == Type::BT_UNKNOWN || Type::bt_subtype(ty, sl.v()[i]->type(), true)) {
952 ty.bt(sl.v()[i]->type().bt());
953 } else {
954 throw TypeError(_env, sl.loc(), "non-uniform set literal");
955 }
956 }
957 }
958 ty.enumId(enumId);
959 if (ty.bt() == Type::BT_UNKNOWN) {
960 ty.bt(Type::BT_BOT);
961 } else {
962 if (ty.isvar() && ty.bt() != Type::BT_INT) {
963 if (ty.bt() == Type::BT_BOOL)
964 ty.bt(Type::BT_INT);
965 else
966 throw TypeError(_env, sl.loc(), "cannot coerce set literal element to var int");
967 }
968 for (unsigned int i = 0; i < sl.v().size(); i++) {
969 sl.v()[i] = addCoercion(_env, _model, sl.v()[i], ty)();
970 }
971 }
972 sl.type(ty);
973 }
974 /// Visit string literal
975 void vStringLit(const StringLit&) {}
976 /// Visit identifier
977 void vId(Id& id) {
978 if (&id != constants().absent) {
979 assert(!id.decl()->type().isunknown());
980 id.type(id.decl()->type());
981 }
982 }
983 /// Visit anonymous variable
984 void vAnonVar(const AnonVar&) {}
985 /// Visit array literal
986 void vArrayLit(ArrayLit& al) {
987 Type ty;
988 ty.dim(al.dims());
989 std::vector<AnonVar*> anons;
990 bool haveAbsents = false;
991 bool haveInferredType = false;
992 for (unsigned int i = 0; i < al.size(); i++) {
993 Expression* vi = al[i];
994 if (vi->type().dim() > 0)
995 throw TypeError(_env, vi->loc(), "arrays cannot be elements of arrays");
996 if (vi == constants().absent) haveAbsents = true;
997 AnonVar* av = vi->dyn_cast<AnonVar>();
998 if (av) {
999 ty.ti(Type::TI_VAR);
1000 anons.push_back(av);
1001 } else if (vi->type().isvar()) {
1002 ty.ti(Type::TI_VAR);
1003 }
1004 if (vi->type().cv()) ty.cv(true);
1005 if (vi->type().isopt()) {
1006 ty.ot(Type::OT_OPTIONAL);
1007 }
1008
1009 if (ty.bt() == Type::BT_UNKNOWN) {
1010 if (av == NULL) {
1011 if (haveInferredType) {
1012 if (ty.st() != vi->type().st() && vi->type().ot() != Type::OT_OPTIONAL) {
1013 throw TypeError(_env, al.loc(), "non-uniform array literal");
1014 }
1015 } else {
1016 haveInferredType = true;
1017 ty.st(vi->type().st());
1018 }
1019 if (vi->type().bt() != Type::BT_BOT) {
1020 ty.bt(vi->type().bt());
1021 ty.enumId(vi->type().enumId());
1022 }
1023 }
1024 } else {
1025 if (av == NULL) {
1026 if (vi->type().bt() == Type::BT_BOT) {
1027 if (vi->type().st() != ty.st() && vi->type().ot() != Type::OT_OPTIONAL) {
1028 throw TypeError(_env, al.loc(), "non-uniform array literal");
1029 }
1030 if (vi->type().enumId() != 0 && ty.enumId() != vi->type().enumId()) {
1031 ty.enumId(0);
1032 }
1033 } else {
1034 unsigned int tyEnumId = ty.enumId();
1035 ty.enumId(vi->type().enumId());
1036 if (Type::bt_subtype(ty, vi->type(), true)) {
1037 ty.bt(vi->type().bt());
1038 }
1039 if (tyEnumId != vi->type().enumId()) ty.enumId(0);
1040 if (!Type::bt_subtype(vi->type(), ty, true) || ty.st() != vi->type().st()) {
1041 throw TypeError(_env, al.loc(), "non-uniform array literal");
1042 }
1043 }
1044 }
1045 }
1046 }
1047 if (ty.bt() == Type::BT_UNKNOWN) {
1048 ty.bt(Type::BT_BOT);
1049 if (!anons.empty())
1050 throw TypeError(_env, al.loc(),
1051 "array literal must contain at least one non-anonymous variable");
1052 if (haveAbsents)
1053 throw TypeError(_env, al.loc(), "array literal must contain at least one non-absent value");
1054 } else {
1055 Type at = ty;
1056 at.dim(0);
1057 if (at.ti() == Type::TI_VAR && at.st() == Type::ST_SET && at.bt() != Type::BT_INT) {
1058 if (at.bt() == Type::BT_BOOL) {
1059 ty.bt(Type::BT_INT);
1060 at.bt(Type::BT_INT);
1061 } else {
1062 throw TypeError(_env, al.loc(), "cannot coerce array element to var set of int");
1063 }
1064 }
1065 for (unsigned int i = 0; i < anons.size(); i++) {
1066 anons[i]->type(at);
1067 }
1068 for (unsigned int i = 0; i < al.size(); i++) {
1069 al.set(i, addCoercion(_env, _model, al[i], at)());
1070 }
1071 }
1072 if (ty.enumId() != 0) {
1073 std::vector<unsigned int> enumIds(ty.dim() + 1);
1074 for (int i = 0; i < ty.dim(); i++) enumIds[i] = 0;
1075 enumIds[ty.dim()] = ty.enumId();
1076 ty.enumId(_env.registerArrayEnum(enumIds));
1077 }
1078 al.type(ty);
1079 }
1080 /// Visit array access
1081 void vArrayAccess(ArrayAccess& aa) {
1082 if (aa.v()->type().dim() == 0) {
1083 if (aa.v()->type().st() == Type::ST_SET) {
1084 Type tv = aa.v()->type();
1085 tv.st(Type::ST_PLAIN);
1086 tv.dim(1);
1087 aa.v(addCoercion(_env, _model, aa.v(), tv)());
1088 } else {
1089 std::ostringstream oss;
1090 oss << "array access attempted on expression of type `" << aa.v()->type().toString(_env)
1091 << "'";
1092 throw TypeError(_env, aa.v()->loc(), oss.str());
1093 }
1094 } else if (aa.v()->isa<ArrayAccess>()) {
1095 aa.v(addCoercion(_env, _model, aa.v(), aa.v()->type())());
1096 }
1097 if (aa.v()->type().dim() != aa.idx().size()) {
1098 std::ostringstream oss;
1099 oss << aa.v()->type().dim() << "-dimensional array accessed with " << aa.idx().size()
1100 << (aa.idx().size() == 1 ? " expression" : " expressions");
1101 throw TypeError(_env, aa.v()->loc(), oss.str());
1102 }
1103 Type tt = aa.v()->type();
1104 if (tt.enumId() != 0) {
1105 const std::vector<unsigned int>& arrayEnumIds = _env.getArrayEnum(tt.enumId());
1106
1107 for (unsigned int i = 0; i < arrayEnumIds.size() - 1; i++) {
1108 Expression* aai = aa.idx()[i];
1109 // Check if index is slice operator, and convert to correct enum type
1110 if (SetLit* aai_sl = aai->dyn_cast<SetLit>()) {
1111 if (IntSetVal* aai_isv = aai_sl->isv()) {
1112 if (aai_isv->min() == -IntVal::infinity() && aai_isv->max() == IntVal::infinity()) {
1113 Type aai_sl_t = aai_sl->type();
1114 aai_sl_t.enumId(arrayEnumIds[i]);
1115 aai_sl->type(aai_sl_t);
1116 }
1117 }
1118 } else if (BinOp* aai_bo = aai->dyn_cast<BinOp>()) {
1119 if (aai_bo->op() == BOT_DOTDOT) {
1120 Type aai_bo_t = aai_bo->type();
1121 if (IntLit* il = aai_bo->lhs()->dyn_cast<IntLit>()) {
1122 if (il->v() == -IntVal::infinity()) {
1123 // Expression is ..X, so result gets enum type of X
1124 aai_bo_t.enumId(aai_bo->rhs()->type().enumId());
1125 }
1126 } else if (IntLit* il = aai_bo->rhs()->dyn_cast<IntLit>()) {
1127 if (il->v() == IntVal::infinity()) {
1128 // Expression is X.., so result gets enum type of X
1129 aai_bo_t.enumId(aai_bo->lhs()->type().enumId());
1130 }
1131 }
1132 aai_bo->type(aai_bo_t);
1133 }
1134 }
1135
1136 if (arrayEnumIds[i] != 0) {
1137 if (aa.idx()[i]->type().enumId() != arrayEnumIds[i]) {
1138 std::ostringstream oss;
1139 oss << "array index ";
1140 if (aa.idx().size() > 1) {
1141 oss << (i + 1) << " ";
1142 }
1143 oss << "must be `" << _env.getEnum(arrayEnumIds[i])->e()->id()->str().str()
1144 << "', but is `" << aa.idx()[i]->type().toString(_env) << "'";
1145 throw TypeError(_env, aa.loc(), oss.str());
1146 }
1147 }
1148 }
1149 tt.enumId(arrayEnumIds[arrayEnumIds.size() - 1]);
1150 }
1151 int n_dimensions = 0;
1152 bool isVarAccess = false;
1153 bool isSlice = false;
1154 for (unsigned int i = 0; i < aa.idx().size(); i++) {
1155 Expression* aai = aa.idx()[i];
1156 if (aai->isa<AnonVar>()) {
1157 aai->type(Type::varint());
1158 }
1159 if ((aai->type().bt() != Type::BT_INT && aai->type().bt() != Type::BT_BOOL) ||
1160 aai->type().dim() != 0) {
1161 throw TypeError(_env, aa.loc(),
1162 "array index must be `int' or `set of int', but is `" +
1163 aai->type().toString(_env) + "'");
1164 }
1165 if (aai->type().is_set()) {
1166 if (isVarAccess || aai->type().isvar()) {
1167 throw TypeError(_env, aa.loc(),
1168 "array slicing with variable range or index not supported");
1169 }
1170 isSlice = true;
1171 aa.idx()[i] = addCoercion(_env, _model, aai, Type::varsetint())();
1172 n_dimensions++;
1173 } else {
1174 aa.idx()[i] = addCoercion(_env, _model, aai, Type::varint())();
1175 }
1176
1177 if (aai->type().isopt()) {
1178 tt.ot(Type::OT_OPTIONAL);
1179 }
1180 if (aai->type().isvar()) {
1181 isVarAccess = true;
1182 if (isSlice) {
1183 throw TypeError(_env, aa.loc(),
1184 "array slicing with variable range or index not supported");
1185 }
1186 tt.ti(Type::TI_VAR);
1187 if (tt.bt() == Type::BT_ANN || tt.bt() == Type::BT_STRING) {
1188 throw TypeError(_env, aai->loc(),
1189 std::string("array access using a variable not supported for array of ") +
1190 (tt.bt() == Type::BT_ANN ? "ann" : "string"));
1191 }
1192 }
1193 tt.dim(n_dimensions);
1194 if (aai->type().cv()) tt.cv(true);
1195 }
1196 aa.type(tt);
1197 }
1198 /// Visit array comprehension
1199 void vComprehension(Comprehension& c) {
1200 Type tt = c.e()->type();
1201 typedef std::unordered_map<VarDecl*, std::pair<int, int> > genMap_t;
1202 typedef std::unordered_map<VarDecl*, std::vector<Expression*> > whereMap_t;
1203 genMap_t generatorMap;
1204 whereMap_t whereMap;
1205 int declCount = 0;
1206 bool didMoveWheres = false;
1207 for (int i = 0; i < c.n_generators(); i++) {
1208 for (int j = 0; j < c.n_decls(i); j++) {
1209 generatorMap[c.decl(i, j)] = std::pair<int, int>(i, declCount++);
1210 whereMap[c.decl(i, j)] = std::vector<Expression*>();
1211 }
1212 Expression* g_in = c.in(i);
1213 if (g_in) {
1214 const Type& ty_in = g_in->type();
1215 if (ty_in == Type::varsetint()) {
1216 tt.ot(Type::OT_OPTIONAL);
1217 tt.ti(Type::TI_VAR);
1218 tt.cv(true);
1219 }
1220 if (ty_in.cv()) tt.cv(true);
1221 if (c.where(i)) {
1222 if (c.where(i)->type() == Type::varbool()) {
1223 tt.ot(Type::OT_OPTIONAL);
1224 tt.ti(Type::TI_VAR);
1225 tt.cv(true);
1226 } else if (c.where(i)->type() != Type::parbool()) {
1227 throw TypeError(
1228 _env, c.where(i)->loc(),
1229 "where clause must be bool, but is `" + c.where(i)->type().toString(_env) + "'");
1230 }
1231 if (c.where(i)->type().cv()) tt.cv(true);
1232
1233 // Try to move parts of the where clause to earlier generators
1234 std::vector<Expression*> wherePartsStack;
1235 std::vector<Expression*> whereParts;
1236 wherePartsStack.push_back(c.where(i));
1237 while (!wherePartsStack.empty()) {
1238 Expression* e = wherePartsStack.back();
1239 wherePartsStack.pop_back();
1240 if (BinOp* bo = e->dyn_cast<BinOp>()) {
1241 if (bo->op() == BOT_AND) {
1242 wherePartsStack.push_back(bo->rhs());
1243 wherePartsStack.push_back(bo->lhs());
1244 } else {
1245 whereParts.push_back(e);
1246 }
1247 } else {
1248 whereParts.push_back(e);
1249 }
1250 }
1251
1252 for (unsigned int wpi = 0; wpi < whereParts.size(); wpi++) {
1253 Expression* wp = whereParts[wpi];
1254 class FindLatestGen : public EVisitor {
1255 public:
1256 int decl_idx;
1257 VarDecl* decl;
1258 const genMap_t& generatorMap;
1259 Comprehension* comp;
1260 FindLatestGen(const genMap_t& generatorMap0, Comprehension* comp0)
1261 : decl_idx(-1),
1262 decl(comp0->decl(0, 0)),
1263 generatorMap(generatorMap0),
1264 comp(comp0) {}
1265 void vId(const Id& ident) {
1266 genMap_t::const_iterator it = generatorMap.find(ident.decl());
1267 if (it != generatorMap.end() && it->second.second > decl_idx) {
1268 decl_idx = it->second.second;
1269 decl = ident.decl();
1270 int gen = it->second.first;
1271 while (comp->in(gen) == NULL && gen < comp->n_generators() - 1) {
1272 decl_idx++;
1273 gen++;
1274 decl = comp->decl(gen, 0);
1275 }
1276 }
1277 }
1278 } flg(generatorMap, &c);
1279 topDown(flg, wp);
1280 whereMap[flg.decl].push_back(wp);
1281
1282 if (flg.decl_idx < declCount - 1) didMoveWheres = true;
1283 }
1284 }
1285 } else {
1286 assert(c.where(i) != NULL);
1287 whereMap[c.decl(i, 0)].push_back(c.where(i));
1288 }
1289 }
1290
1291 if (didMoveWheres) {
1292 Generators generators;
1293 for (int i = 0; i < c.n_generators(); i++) {
1294 std::vector<VarDecl*> decls;
1295 for (int j = 0; j < c.n_decls(i); j++) {
1296 decls.push_back(c.decl(i, j));
1297 if (whereMap[c.decl(i, j)].size() != 0) {
1298 // need a generator for all the decls up to this point
1299 Expression* whereExpr = whereMap[c.decl(i, j)][0];
1300 for (unsigned int k = 1; k < whereMap[c.decl(i, j)].size(); k++) {
1301 GCLock lock;
1302 BinOp* bo =
1303 new BinOp(Location().introduce(), whereExpr, BOT_AND, whereMap[c.decl(i, j)][k]);
1304 Type bo_t = whereMap[c.decl(i, j)][k]->type().ispar() && whereExpr->type().ispar()
1305 ? Type::parbool()
1306 : Type::varbool();
1307 bo->type(bo_t);
1308 whereExpr = bo;
1309 }
1310 generators._g.push_back(Generator(decls, c.in(i), whereExpr));
1311 decls.clear();
1312 } else if (j == c.n_decls(i) - 1) {
1313 generators._g.push_back(Generator(decls, c.in(i), NULL));
1314 decls.clear();
1315 }
1316 }
1317 }
1318 GCLock lock;
1319 c.init(c.e(), generators);
1320 }
1321
1322 if (c.set()) {
1323 if (c.e()->type().dim() != 0 || c.e()->type().st() == Type::ST_SET)
1324 throw TypeError(_env, c.e()->loc(),
1325 "set comprehension expression must be scalar, but is `" +
1326 c.e()->type().toString(_env) + "'");
1327 tt.st(Type::ST_SET);
1328 if (tt.isvar()) {
1329 c.e(addCoercion(_env, _model, c.e(), Type::varint())());
1330 tt.bt(Type::BT_INT);
1331 }
1332 } else {
1333 if (c.e()->type().dim() != 0)
1334 throw TypeError(_env, c.e()->loc(), "array comprehension expression cannot be an array");
1335 tt.dim(1);
1336 if (tt.enumId() != 0) {
1337 std::vector<unsigned int> enumIds(2);
1338 enumIds[0] = 0;
1339 enumIds[1] = tt.enumId();
1340 tt.enumId(_env.registerArrayEnum(enumIds));
1341 }
1342 }
1343 c.type(tt);
1344 }
1345 /// Visit array comprehension generator
1346 void vComprehensionGenerator(Comprehension& c, int gen_i) {
1347 Expression* g_in = c.in(gen_i);
1348 if (g_in == NULL) {
1349 // This is an "assignment generator" (i = expr)
1350 assert(c.where(gen_i) != NULL);
1351 assert(c.n_decls(gen_i) == 1);
1352 const Type& ty_where = c.where(gen_i)->type();
1353 c.decl(gen_i, 0)->type(ty_where);
1354 c.decl(gen_i, 0)->ti()->type(ty_where);
1355 } else {
1356 const Type& ty_in = g_in->type();
1357 if (ty_in != Type::varsetint() && ty_in != Type::parsetint() && ty_in.dim() != 1) {
1358 throw TypeError(_env, g_in->loc(),
1359 "generator expression must be (par or var) set of int or one-dimensional "
1360 "array, but is `" +
1361 ty_in.toString(_env) + "'");
1362 }
1363 Type ty_id;
1364 bool needIntLit = false;
1365 if (ty_in.dim() == 0) {
1366 ty_id = Type::parint();
1367 ty_id.enumId(ty_in.enumId());
1368 needIntLit = true;
1369 } else {
1370 ty_id = ty_in;
1371 if (ty_in.enumId() != 0) {
1372 const std::vector<unsigned int>& enumIds = _env.getArrayEnum(ty_in.enumId());
1373 ty_id.enumId(enumIds.back());
1374 }
1375 ty_id.dim(0);
1376 }
1377 for (int j = 0; j < c.n_decls(gen_i); j++) {
1378 if (needIntLit) {
1379 GCLock lock;
1380 c.decl(gen_i, j)->e(IntLit::aEnum(0, ty_id.enumId()));
1381 }
1382 c.decl(gen_i, j)->type(ty_id);
1383 c.decl(gen_i, j)->ti()->type(ty_id);
1384 }
1385 }
1386 }
1387 /// Visit if-then-else
1388 void vITE(ITE& ite) {
1389 bool mustBeBool = false;
1390 if (ite.e_else() == NULL) {
1391 // this is an "if <cond> then <expr> endif" so the <expr> must be bool
1392 ite.e_else(constants().boollit(true));
1393 mustBeBool = true;
1394 }
1395 Type tret = ite.e_else()->type();
1396 std::vector<AnonVar*> anons;
1397 bool allpar = !(tret.isvar());
1398 if (tret.isunknown()) {
1399 if (AnonVar* av = ite.e_else()->dyn_cast<AnonVar>()) {
1400 allpar = false;
1401 anons.push_back(av);
1402 } else {
1403 throw TypeError(_env, ite.e_else()->loc(),
1404 "cannot infer type of expression in `else' branch of conditional");
1405 }
1406 }
1407 bool allpresent = !(tret.isopt());
1408 bool varcond = false;
1409 for (int i = 0; i < ite.size(); i++) {
1410 Expression* eif = ite.e_if(i);
1411 Expression* ethen = ite.e_then(i);
1412 varcond = varcond || (eif->type() == Type::varbool());
1413 if (eif->type() != Type::parbool() && eif->type() != Type::varbool())
1414 throw TypeError(
1415 _env, eif->loc(),
1416 "expected bool conditional expression, got `" + eif->type().toString(_env) + "'");
1417 if (eif->type().cv()) tret.cv(true);
1418 if (ethen->type().isunknown()) {
1419 if (AnonVar* av = ethen->dyn_cast<AnonVar>()) {
1420 allpar = false;
1421 anons.push_back(av);
1422 } else {
1423 throw TypeError(_env, ethen->loc(),
1424 "cannot infer type of expression in `then' branch of conditional");
1425 }
1426 } else {
1427 if (tret.isbot() || tret.isunknown()) tret.bt(ethen->type().bt());
1428 if (mustBeBool &&
1429 (ethen->type().bt() != Type::BT_BOOL || ethen->type().dim() > 0 ||
1430 ethen->type().st() != Type::ST_PLAIN || ethen->type().ot() != Type::OT_PRESENT)) {
1431 throw TypeError(_env, ite.loc(),
1432 std::string("conditional without `else' branch must have bool type, ") +
1433 "but `then' branch has type `" + ethen->type().toString(_env) + "'");
1434 }
1435 if ((!ethen->type().isbot() && !Type::bt_subtype(ethen->type(), tret, true) &&
1436 !Type::bt_subtype(tret, ethen->type(), true)) ||
1437 ethen->type().st() != tret.st() || ethen->type().dim() != tret.dim()) {
1438 throw TypeError(_env, ethen->loc(),
1439 "type mismatch in branches of conditional. `then' branch has type `" +
1440 ethen->type().toString(_env) + "', but `else' branch has type `" +
1441 tret.toString(_env) + "'");
1442 }
1443 if (Type::bt_subtype(tret, ethen->type(), true)) {
1444 tret.bt(ethen->type().bt());
1445 }
1446 if (ethen->type().isvar()) allpar = false;
1447 if (ethen->type().isopt()) allpresent = false;
1448 if (ethen->type().cv()) tret.cv(true);
1449 }
1450 }
1451 Type tret_var(tret);
1452 tret_var.ti(Type::TI_VAR);
1453 for (unsigned int i = 0; i < anons.size(); i++) {
1454 anons[i]->type(tret_var);
1455 }
1456 for (int i = 0; i < ite.size(); i++) {
1457 ite.e_then(i, addCoercion(_env, _model, ite.e_then(i), tret)());
1458 }
1459 ite.e_else(addCoercion(_env, _model, ite.e_else(), tret)());
1460 /// TODO: perhaps extend flattener to array types, but for now throw an error
1461 if (varcond && tret.dim() > 0)
1462 throw TypeError(_env, ite.loc(), "conditional with var condition cannot have array type");
1463 if (varcond || !allpar) tret.ti(Type::TI_VAR);
1464 if (!allpresent) tret.ot(Type::OT_OPTIONAL);
1465 ite.type(tret);
1466 }
1467 /// Visit binary operator
1468 void vBinOp(BinOp& bop) {
1469 std::vector<Expression*> args(2);
1470 args[0] = bop.lhs();
1471 args[1] = bop.rhs();
1472 if (FunctionI* fi = _model->matchFn(_env, bop.opToString(), args, true)) {
1473 bop.lhs(addCoercion(_env, _model, bop.lhs(), fi->argtype(_env, args, 0))());
1474 bop.rhs(addCoercion(_env, _model, bop.rhs(), fi->argtype(_env, args, 1))());
1475 args[0] = bop.lhs();
1476 args[1] = bop.rhs();
1477 Type ty = fi->rtype(_env, args, true);
1478 ty.cv(bop.lhs()->type().cv() || bop.rhs()->type().cv());
1479 bop.type(ty);
1480
1481 if (fi->e())
1482 bop.decl(fi);
1483 else
1484 bop.decl(NULL);
1485 } else {
1486 throw TypeError(_env, bop.loc(),
1487 std::string("type error in operator application for `") +
1488 bop.opToString().str() +
1489 "'. No matching operator found with left-hand side type `" +
1490 bop.lhs()->type().toString(_env) + "' and right-hand side type `" +
1491 bop.rhs()->type().toString(_env) + "'");
1492 }
1493 }
1494 /// Visit unary operator
1495 void vUnOp(UnOp& uop) {
1496 std::vector<Expression*> args(1);
1497 args[0] = uop.e();
1498 if (FunctionI* fi = _model->matchFn(_env, uop.opToString(), args, true)) {
1499 uop.e(addCoercion(_env, _model, uop.e(), fi->argtype(_env, args, 0))());
1500 args[0] = uop.e();
1501 Type ty = fi->rtype(_env, args, true);
1502 ty.cv(uop.e()->type().cv());
1503 uop.type(ty);
1504 if (fi->e()) uop.decl(fi);
1505 } else {
1506 throw TypeError(_env, uop.loc(),
1507 std::string("type error in operator application for `") +
1508 uop.opToString().str() + "'. No matching operator found with type `" +
1509 uop.e()->type().toString(_env) + "'");
1510 }
1511 }
1512 static std::string createEnumToStringName(Id* ident, std::string prefix) {
1513 std::string name = ident->str().str();
1514 if (name[0] == '\'') {
1515 name = "'" + prefix + name.substr(1);
1516 } else {
1517 name = prefix + name;
1518 }
1519 return name;
1520 }
1521
1522 /// Visit call
1523 void vCall(Call& call) {
1524 std::vector<Expression*> args(call.n_args());
1525 for (unsigned int i = static_cast<unsigned int>(args.size()); i--;) args[i] = call.arg(i);
1526 if (FunctionI* fi = _model->matchFn(_env, call.id(), args, true)) {
1527 bool cv = false;
1528 for (unsigned int i = 0; i < args.size(); i++) {
1529 if (Comprehension* c = call.arg(i)->dyn_cast<Comprehension>()) {
1530 Type t_before = c->e()->type();
1531 Type t = fi->argtype(_env, args, i);
1532 t.dim(0);
1533 c->e(addCoercion(_env, _model, c->e(), t)());
1534 Type t_after = c->e()->type();
1535 if (t_before != t_after) {
1536 Type ct = c->type();
1537 ct.bt(t_after.bt());
1538 c->type(ct);
1539 }
1540 } else {
1541 args[i] = addCoercion(_env, _model, call.arg(i), fi->argtype(_env, args, i))();
1542 call.arg(i, args[i]);
1543 }
1544 cv = cv || args[i]->type().cv();
1545 }
1546 // Replace par enums with their string versions
1547 if (call.id() == "format" || call.id() == "show" || call.id() == "showDzn" ||
1548 call.id() == "showJSON") {
1549 if (call.arg(call.n_args() - 1)->type().ispar()) {
1550 int enumId = call.arg(call.n_args() - 1)->type().enumId();
1551 if (enumId != 0 && call.arg(call.n_args() - 1)->type().dim() != 0) {
1552 const std::vector<unsigned int>& enumIds = _env.getArrayEnum(enumId);
1553 enumId = enumIds[enumIds.size() - 1];
1554 }
1555 if (enumId > 0) {
1556 VarDecl* enumDecl = _env.getEnum(enumId)->e();
1557 if (enumDecl->e()) {
1558 Id* ti_id = _env.getEnum(enumId)->e()->id();
1559 GCLock lock;
1560 std::vector<Expression*> args(3);
1561 args[0] = call.arg(call.n_args() - 1);
1562 if (args[0]->type().dim() > 1) {
1563 std::vector<Expression*> a1dargs(1);
1564 a1dargs[0] = args[0];
1565 Call* array1d = new Call(Location().introduce(), ASTString("array1d"), a1dargs);
1566 Type array1dt = args[0]->type();
1567 array1dt.dim(1);
1568 array1d->type(array1dt);
1569 args[0] = array1d;
1570 }
1571 args[1] = constants().boollit(call.id() == "showDzn");
1572 args[2] = constants().boollit(call.id() == "showJSON");
1573 ASTString enumName(createEnumToStringName(ti_id, "_toString_"));
1574 call.id(enumName);
1575 call.args(args);
1576 if (call.id() == "showDzn") {
1577 call.id(constants().ids.show);
1578 }
1579 fi = _model->matchFn(_env, &call, false);
1580 if (fi == NULL) {
1581 std::ostringstream oss;
1582 oss << "no function or predicate with this signature found: `";
1583 oss << call.id() << "(";
1584 for (unsigned int i = 0; i < call.n_args(); i++) {
1585 oss << call.arg(i)->type().toString(_env);
1586 if (i < call.n_args() - 1) oss << ",";
1587 }
1588 oss << ")'";
1589 throw TypeError(_env, call.loc(), oss.str());
1590 }
1591 }
1592 }
1593 }
1594 }
1595
1596 // Set type and decl
1597 Type ty = fi->rtype(_env, args, true);
1598 ty.cv(cv);
1599 call.type(ty);
1600 call.decl(fi);
1601 } else {
1602 std::ostringstream oss;
1603 oss << "no function or predicate with this signature found: `";
1604 oss << call.id() << "(";
1605 for (unsigned int i = 0; i < call.n_args(); i++) {
1606 oss << call.arg(i)->type().toString(_env);
1607 if (i < call.n_args() - 1) oss << ",";
1608 }
1609 oss << ")'";
1610 throw TypeError(_env, call.loc(), oss.str());
1611 }
1612 }
1613 /// Visit let
1614 void vLet(Let& let) {
1615 bool cv = false;
1616 bool isVar = false;
1617 for (unsigned int i = 0; i < let.let().size(); i++) {
1618 Expression* li = let.let()[i];
1619 cv = cv || li->type().cv();
1620 if (VarDecl* vdi = li->dyn_cast<VarDecl>()) {
1621 if (vdi->e() == NULL && vdi->type().is_set() && vdi->type().isvar() &&
1622 vdi->ti()->domain() == NULL) {
1623 _typeErrors.push_back(
1624 TypeError(_env, vdi->loc(),
1625 "set element type for `" + vdi->id()->str().str() + "' is not finite"));
1626 }
1627 if (vdi->type().ispar() && vdi->e() == NULL)
1628 throw TypeError(_env, vdi->loc(),
1629 "let variable `" + vdi->id()->v().str() + "' must be initialised");
1630 if (vdi->ti()->hasTiVariable()) {
1631 _typeErrors.push_back(
1632 TypeError(_env, vdi->loc(),
1633 "type-inst variables not allowed in type-inst for let variable `" +
1634 vdi->id()->str().str() + "'"));
1635 }
1636 let.let_orig()[i] = vdi->e();
1637 }
1638 isVar |= li->type().isvar();
1639 }
1640 Type ty = let.in()->type();
1641 ty.cv(cv);
1642 if (isVar && ty.bt() == Type::BT_BOOL && ty.dim() == 0) ty.ti(Type::TI_VAR);
1643 let.type(ty);
1644 }
1645 /// Visit variable declaration
1646 void vVarDecl(VarDecl& vd) {
1647 if (ignoreVarDecl) {
1648 if (vd.e()) {
1649 Type vdt = vd.ti()->type();
1650 Type vet = vd.e()->type();
1651 if (vdt.enumId() != 0 && vdt.dim() > 0 &&
1652 (vd.e()->isa<ArrayLit>() || vd.e()->isa<Comprehension>() ||
1653 (vd.e()->isa<BinOp>() && vd.e()->cast<BinOp>()->op() == BOT_PLUSPLUS))) {
1654 // Special case: index sets of array literals and comprehensions automatically
1655 // coerce to any enum index set
1656 const std::vector<unsigned int>& enumIds = _env.getArrayEnum(vdt.enumId());
1657 if (enumIds[enumIds.size() - 1] == 0) {
1658 vdt.enumId(0);
1659 } else {
1660 std::vector<unsigned int> nEnumIds(enumIds.size());
1661 for (unsigned int i = 0; i < nEnumIds.size() - 1; i++) nEnumIds[i] = 0;
1662 nEnumIds[nEnumIds.size() - 1] = enumIds[enumIds.size() - 1];
1663 vdt.enumId(_env.registerArrayEnum(nEnumIds));
1664 }
1665 } else if (vd.ti()->isEnum() && vd.e()->isa<Call>()) {
1666 if (vd.e()->cast<Call>()->id() == "anon_enum") {
1667 vet.enumId(vdt.enumId());
1668 }
1669 }
1670
1671 if (vd.type().isunknown()) {
1672 vd.ti()->type(vet);
1673 vd.type(vet);
1674 } else if (!_env.isSubtype(vet, vdt, true)) {
1675 if (vet == Type::bot(1) && vd.e()->isa<ArrayLit>() &&
1676 vd.e()->cast<ArrayLit>()->size() == 0 && vdt.dim() != 0) {
1677 // this is okay: assigning an empty array (one-dimensional) to an array variable
1678 } else {
1679 _typeErrors.push_back(TypeError(_env, vd.e()->loc(),
1680 "initialisation value for `" + vd.id()->str().str() +
1681 "' has invalid type-inst: expected `" +
1682 vd.ti()->type().toString(_env) + "', actual `" +
1683 vd.e()->type().toString(_env) + "'"));
1684 }
1685 } else {
1686 vd.e(addCoercion(_env, _model, vd.e(), vd.ti()->type())());
1687 }
1688 } else {
1689 assert(!vd.type().isunknown());
1690 }
1691 } else {
1692 vd.type(vd.ti()->type());
1693 vd.id()->type(vd.type());
1694 }
1695 }
1696 /// Visit type inst
1697 void vTypeInst(TypeInst& ti) {
1698 Type tt = ti.type();
1699 bool foundEnum = ti.ranges().size() > 0 && ti.domain() && ti.domain()->type().enumId() != 0;
1700 if (ti.ranges().size() > 0) {
1701 bool foundTIId = false;
1702 for (unsigned int i = 0; i < ti.ranges().size(); i++) {
1703 TypeInst* ri = ti.ranges()[i];
1704 assert(ri != NULL);
1705 if (ri->type().cv()) tt.cv(true);
1706 if (ri->type().enumId() != 0) {
1707 foundEnum = true;
1708 }
1709 if (ri->type() == Type::top()) {
1710 // if (foundTIId) {
1711 // throw TypeError(_env,ri->loc(),
1712 // "only one type-inst variable allowed in array index");
1713 // } else {
1714 foundTIId = true;
1715 // }
1716 } else if (ri->type() != Type::parint()) {
1717 assert(ri->isa<TypeInst>());
1718 TypeInst* riti = ri->cast<TypeInst>();
1719 if (riti->domain()) {
1720 throw TypeError(_env, ri->loc(),
1721 "array index set expression has invalid type, expected `set of int', "
1722 "actual `set of " +
1723 ri->type().toString(_env) + "'");
1724 } else {
1725 throw TypeError(_env, ri->loc(),
1726 "cannot use `" + ri->type().toString(_env) +
1727 "' as array index set (did you mean `int'?)");
1728 }
1729 }
1730 }
1731 tt.dim(foundTIId ? -1 : ti.ranges().size());
1732 }
1733 if (ti.domain() && ti.domain()->type().cv()) tt.cv(true);
1734 if (ti.domain()) {
1735 if (TIId* tiid = ti.domain()->dyn_cast<TIId>()) {
1736 if (tiid->isEnum()) {
1737 tt.bt(Type::BT_INT);
1738 }
1739 } else {
1740 if (ti.domain()->type().ti() != Type::TI_PAR || ti.domain()->type().st() != Type::ST_SET)
1741 throw TypeError(
1742 _env, ti.domain()->loc(),
1743 "type-inst must be par set but is `" + ti.domain()->type().toString(_env) + "'");
1744 if (ti.domain()->type().dim() != 0)
1745 throw TypeError(_env, ti.domain()->loc(), "type-inst cannot be an array");
1746 }
1747 }
1748 if (tt.isunknown() && ti.domain()) {
1749 assert(ti.domain());
1750 switch (ti.domain()->type().bt()) {
1751 case Type::BT_INT:
1752 case Type::BT_FLOAT:
1753 break;
1754 case Type::BT_BOT: {
1755 Type tidt = ti.domain()->type();
1756 tidt.bt(Type::BT_INT);
1757 ti.domain()->type(tidt);
1758 } break;
1759 default:
1760 throw TypeError(_env, ti.domain()->loc(), "type-inst must be int or float");
1761 }
1762 tt.bt(ti.domain()->type().bt());
1763 tt.enumId(ti.domain()->type().enumId());
1764 } else {
1765 // assert(ti.domain()==NULL || ti.domain()->isa<TIId>());
1766 }
1767 if (foundEnum) {
1768 std::vector<unsigned int> enumIds(ti.ranges().size() + 1);
1769 for (unsigned int i = 0; i < ti.ranges().size(); i++) {
1770 enumIds[i] = ti.ranges()[i]->type().enumId();
1771 }
1772 enumIds[ti.ranges().size()] = ti.domain() ? ti.domain()->type().enumId() : 0;
1773 int arrayEnumId = _env.registerArrayEnum(enumIds);
1774 tt.enumId(arrayEnumId);
1775 }
1776
1777 if (tt.st() == Type::ST_SET && tt.ti() == Type::TI_VAR && tt.bt() != Type::BT_INT &&
1778 tt.bt() != Type::BT_TOP)
1779 throw TypeError(_env, ti.loc(), "var set element types other than `int' not allowed");
1780 ti.type(tt);
1781 }
1782 void vTIId(TIId& id) {}
1783};
1784
1785void typecheck(Env& env, Model* origModel, std::vector<TypeError>& typeErrors,
1786 bool ignoreUndefinedParameters, bool allowMultiAssignment, bool isFlatZinc) {
1787 Model* m;
1788 if (!isFlatZinc && origModel == env.model()) {
1789 // Combine all items into single model
1790 Model* combinedModel = new Model;
1791 class Combiner : public ItemVisitor {
1792 public:
1793 Model* m;
1794 Combiner(Model* m0) : m(m0) {}
1795 bool enter(Item* i) {
1796 if (!i->isa<IncludeI>()) m->addItem(i);
1797 return true;
1798 }
1799 } _combiner(combinedModel);
1800 iterItems(_combiner, origModel);
1801 env.envi().orig_model = origModel;
1802 env.envi().model = combinedModel;
1803 m = combinedModel;
1804 } else {
1805 m = origModel;
1806 }
1807
1808 // Topological sorting
1809 TopoSorter ts(m);
1810
1811 std::vector<FunctionI*> functionItems;
1812 std::vector<AssignI*> assignItems;
1813 Model* enumItems = new Model;
1814
1815 class TSVFuns : public ItemVisitor {
1816 public:
1817 EnvI& env;
1818 Model* model;
1819 std::vector<FunctionI*>& fis;
1820 TSVFuns(EnvI& env0, Model* model0, std::vector<FunctionI*>& fis0)
1821 : env(env0), model(model0), fis(fis0) {}
1822 void vFunctionI(FunctionI* i) {
1823 model->registerFn(env, i);
1824 fis.push_back(i);
1825 }
1826 } _tsvf(env.envi(), m, functionItems);
1827 iterItems(_tsvf, m);
1828
1829 class TSV0 : public ItemVisitor {
1830 public:
1831 EnvI& env;
1832 TopoSorter& ts;
1833 Model* model;
1834 bool hadSolveItem;
1835 std::vector<AssignI*>& ais;
1836 VarDeclI* objective;
1837 Model* enumis;
1838 TSV0(EnvI& env0, TopoSorter& ts0, Model* model0, std::vector<AssignI*>& ais0, Model* enumis0)
1839 : env(env0),
1840 ts(ts0),
1841 model(model0),
1842 hadSolveItem(false),
1843 ais(ais0),
1844 objective(NULL),
1845 enumis(enumis0) {}
1846 void vAssignI(AssignI* i) { ais.push_back(i); }
1847 void vVarDeclI(VarDeclI* i) {
1848 ts.add(env, i, true, enumis);
1849 // initialise new identifier counter to be larger than existing identifier
1850 if (i->e()->id()->idn() >= 0) {
1851 env.minId(i->e()->id()->idn());
1852 } else if (i->e()->id()->v().beginsWith("X_INTRODUCED_") && i->e()->id()->v().endsWith("_")) {
1853 std::string numId = i->e()->id()->v().str().substr(std::string("X_INTRODUCED_").size());
1854 if (numId.size() > 0) {
1855 numId = numId.substr(0, numId.size() - 1);
1856 if (numId.size() > 0) {
1857 int vId = -1;
1858 try {
1859 vId = std::stoi(numId);
1860 } catch (std::exception&) {
1861 }
1862 if (vId >= 0) env.minId(vId);
1863 }
1864 }
1865 }
1866 }
1867 void vSolveI(SolveI* si) {
1868 if (hadSolveItem) throw TypeError(env, si->loc(), "Only one solve item allowed");
1869 hadSolveItem = true;
1870 if (si->e()) {
1871 GCLock lock;
1872 TypeInst* ti = new TypeInst(Location().introduce(), Type());
1873 VarDecl* obj = new VarDecl(Location().introduce(), ti, "_objective", si->e());
1874 si->e(obj->id());
1875 objective = new VarDeclI(Location().introduce(), obj);
1876 }
1877 }
1878 } _tsv0(env.envi(), ts, m, assignItems, enumItems);
1879 iterItems(_tsv0, m);
1880 if (_tsv0.objective) {
1881 m->addItem(_tsv0.objective);
1882 ts.add(env.envi(), _tsv0.objective, true, enumItems);
1883 }
1884
1885 for (unsigned int i = 0; i < enumItems->size(); i++) {
1886 if (AssignI* ai = (*enumItems)[i]->dyn_cast<AssignI>()) {
1887 assignItems.push_back(ai);
1888 } else if (VarDeclI* vdi = (*enumItems)[i]->dyn_cast<VarDeclI>()) {
1889 m->addItem(vdi);
1890 ts.add(env.envi(), vdi, false, enumItems);
1891 } else {
1892 FunctionI* fi = (*enumItems)[i]->dyn_cast<FunctionI>();
1893 m->addItem(fi);
1894 m->registerFn(env.envi(), fi);
1895 functionItems.push_back(fi);
1896 }
1897 }
1898
1899 Model* enumItems2 = new Model;
1900
1901 for (unsigned int i = 0; i < assignItems.size(); i++) {
1902 AssignI* ai = assignItems[i];
1903 VarDecl* vd = NULL;
1904 if (env.envi().ignoreUnknownIds) {
1905 try {
1906 vd = ts.get(env.envi(), ai->id(), ai->loc());
1907 } catch (TypeError&) {
1908 }
1909 } else {
1910 vd = ts.get(env.envi(), ai->id(), ai->loc());
1911 }
1912 if (vd) {
1913 if (vd->e()) {
1914 if (allowMultiAssignment) {
1915 GCLock lock;
1916 m->addItem(new ConstraintI(
1917 ai->loc(),
1918 new BinOp(ai->loc(), new Id(Location().introduce(), ai->id(), vd), BOT_EQ, ai->e())));
1919 } else {
1920 throw TypeError(env.envi(), ai->loc(), "multiple assignment to the same variable");
1921 }
1922 } else {
1923 vd->e(ai->e());
1924 vd->ann().add(constants().ann.rhs_from_assignment);
1925 if (vd->ti()->isEnum()) {
1926 GCLock lock;
1927 ASTString name(createEnumToStringName(vd->id(), "_enum_to_string_"));
1928 VarDecl* vd_enum = ts.get(env.envi(), name, vd->loc());
1929 if (vd_enum->e())
1930 throw TypeError(env.envi(), ai->loc(), "multiple definition of the same enum");
1931 AssignI* ai_enum =
1932 createEnumMapper(env.envi(), m, vd->ti()->type().enumId(), vd, vd_enum, enumItems2);
1933 if (ai_enum) {
1934 vd_enum->e(ai_enum->e());
1935 ai_enum->remove();
1936 }
1937 }
1938 }
1939 }
1940 ai->remove();
1941 }
1942
1943 for (unsigned int i = 0; i < enumItems2->size(); i++) {
1944 if (VarDeclI* vdi = (*enumItems2)[i]->dyn_cast<VarDeclI>()) {
1945 m->addItem(vdi);
1946 ts.add(env.envi(), vdi, false, enumItems);
1947 } else {
1948 FunctionI* fi = (*enumItems2)[i]->cast<FunctionI>();
1949 m->addItem(fi);
1950 m->registerFn(env.envi(), fi);
1951 functionItems.push_back(fi);
1952 }
1953 }
1954
1955 delete enumItems;
1956 delete enumItems2;
1957
1958 class TSV1 : public ItemVisitor {
1959 public:
1960 EnvI& env;
1961 TopoSorter& ts;
1962 TSV1(EnvI& env0, TopoSorter& ts0) : env(env0), ts(ts0) {}
1963 void vVarDeclI(VarDeclI* i) { ts.run(env, i->e()); }
1964 void vAssignI(AssignI* i) {}
1965 void vConstraintI(ConstraintI* i) { ts.run(env, i->e()); }
1966 void vSolveI(SolveI* i) {
1967 for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) ts.run(env, *it);
1968 ts.run(env, i->e());
1969 }
1970 void vOutputI(OutputI* i) { ts.run(env, i->e()); }
1971 void vFunctionI(FunctionI* fi) {
1972 ts.run(env, fi->ti());
1973 for (unsigned int i = 0; i < fi->params().size(); i++) ts.run(env, fi->params()[i]);
1974 for (ExpressionSetIter it = fi->ann().begin(); it != fi->ann().end(); ++it) ts.run(env, *it);
1975 ts.scopes.push(false);
1976 for (unsigned int i = 0; i < fi->params().size(); i++) ts.scopes.add(env, fi->params()[i]);
1977 ts.run(env, fi->e());
1978 ts.scopes.pop();
1979 }
1980 } _tsv1(env.envi(), ts);
1981 iterItems(_tsv1, m);
1982
1983 m->sortFn();
1984
1985 {
1986 struct SortByPayload {
1987 bool operator()(Item* i0, Item* i1) {
1988 if (i0->isa<IncludeI>()) return !i1->isa<IncludeI>();
1989 if (VarDeclI* vdi0 = i0->dyn_cast<VarDeclI>()) {
1990 if (VarDeclI* vdi1 = i1->dyn_cast<VarDeclI>()) {
1991 return vdi0->e()->payload() < vdi1->e()->payload();
1992 } else {
1993 return !i1->isa<IncludeI>();
1994 }
1995 }
1996 return false;
1997 }
1998 } _sbp;
1999
2000 std::stable_sort(m->begin(), m->end(), _sbp);
2001 }
2002
2003 {
2004 Typer<false> ty(env.envi(), m, typeErrors, ignoreUndefinedParameters);
2005 BottomUpIterator<Typer<false> > bu_ty(ty);
2006 for (unsigned int i = 0; i < ts.decls.size(); i++) {
2007 ts.decls[i]->payload(0);
2008 bu_ty.run(ts.decls[i]->ti());
2009 ty.vVarDecl(*ts.decls[i]);
2010 }
2011 for (unsigned int i = 0; i < functionItems.size(); i++) {
2012 bu_ty.run(functionItems[i]->ti());
2013 for (unsigned int j = 0; j < functionItems[i]->params().size(); j++)
2014 bu_ty.run(functionItems[i]->params()[j]);
2015 }
2016 }
2017
2018 m->fixFnMap();
2019
2020 {
2021 Typer<true> ty(env.envi(), m, typeErrors, ignoreUndefinedParameters);
2022 BottomUpIterator<Typer<true> > bu_ty(ty);
2023
2024 class TSV2 : public ItemVisitor {
2025 public:
2026 EnvI& env;
2027 Model* m;
2028 BottomUpIterator<Typer<true> >& bu_ty;
2029 std::vector<TypeError>& _typeErrors;
2030 TSV2(EnvI& env0, Model* m0, BottomUpIterator<Typer<true> >& b,
2031 std::vector<TypeError>& typeErrors)
2032 : env(env0), m(m0), bu_ty(b), _typeErrors(typeErrors) {}
2033 void vVarDeclI(VarDeclI* i) {
2034 bu_ty.run(i->e());
2035 if (i->e()->ti()->hasTiVariable()) {
2036 _typeErrors.push_back(TypeError(env, i->e()->loc(),
2037 "type-inst variables not allowed in type-inst for `" +
2038 i->e()->id()->str().str() + "'"));
2039 }
2040 VarDecl* vdi = i->e();
2041 if (vdi->e() == NULL && vdi->type().is_set() && vdi->type().isvar() &&
2042 vdi->ti()->domain() == NULL) {
2043 _typeErrors.push_back(
2044 TypeError(env, vdi->loc(),
2045 "set element type for `" + vdi->id()->str().str() + "' is not finite"));
2046 }
2047 if (i->e()->ann().contains(constants().ann.output_only) && vdi->e()->type().isvar()) {
2048 _typeErrors.push_back(
2049 TypeError(env, vdi->loc(), "variables annotated with ::output_only must be par"));
2050 }
2051 }
2052 void vAssignI(AssignI* i) {
2053 bu_ty.run(i->e());
2054 if (!env.isSubtype(i->e()->type(), i->decl()->ti()->type(), true)) {
2055 _typeErrors.push_back(TypeError(env, i->loc(),
2056 "assignment value for `" + i->decl()->id()->str().str() +
2057 "' has invalid type-inst: expected `" +
2058 i->decl()->ti()->type().toString(env) +
2059 "', actual `" + i->e()->type().toString(env) + "'"));
2060 // Assign to "true" constant to avoid generating further errors that the parameter
2061 // is undefined
2062 i->decl()->e(constants().lit_true);
2063 }
2064 }
2065 void vConstraintI(ConstraintI* i) {
2066 bu_ty.run(i->e());
2067 if (!env.isSubtype(i->e()->type(), Type::varbool(), true))
2068 throw TypeError(env, i->loc(),
2069 "invalid type of constraint, expected `" + Type::varbool().toString(env) +
2070 "', actual `" + i->e()->type().toString(env) + "'");
2071 }
2072 void vSolveI(SolveI* i) {
2073 for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) {
2074 bu_ty.run(*it);
2075 if (!(*it)->type().isann())
2076 throw TypeError(env, (*it)->loc(),
2077 "expected annotation, got `" + (*it)->type().toString(env) + "'");
2078 }
2079 bu_ty.run(i->e());
2080 if (i->e()) {
2081 Type et = i->e()->type();
2082
2083 bool needOptCoercion = et.isopt() && et.isint();
2084 if (needOptCoercion) {
2085 et.ot(Type::OT_PRESENT);
2086 }
2087
2088 if (!(env.isSubtype(et, Type::varint(), true) ||
2089 env.isSubtype(et, Type::varfloat(), true)))
2090 throw TypeError(env, i->e()->loc(),
2091 "objective has invalid type, expected int or float, actual `" +
2092 et.toString(env) + "'");
2093
2094 if (needOptCoercion) {
2095 GCLock lock;
2096 std::vector<Expression*> args(2);
2097 args[0] = i->e();
2098 args[1] = constants().boollit(i->st() == SolveI::ST_MAX);
2099 Call* c = new Call(Location().introduce(), ASTString("objective_deopt_"), args);
2100 c->decl(env.model->matchFn(env, c, false));
2101 assert(c->decl());
2102 c->type(et);
2103 i->e(c);
2104 }
2105 }
2106 }
2107 void vOutputI(OutputI* i) {
2108 bu_ty.run(i->e());
2109 if (i->e()->type() != Type::parstring(1) && i->e()->type() != Type::bot(1))
2110 throw TypeError(env, i->e()->loc(),
2111 "invalid type in output item, expected `" +
2112 Type::parstring(1).toString(env) + "', actual `" +
2113 i->e()->type().toString(env) + "'");
2114 }
2115 void vFunctionI(FunctionI* i) {
2116 for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) {
2117 bu_ty.run(*it);
2118 if (!(*it)->type().isann())
2119 throw TypeError(env, (*it)->loc(),
2120 "expected annotation, got `" + (*it)->type().toString(env) + "'");
2121 }
2122 bu_ty.run(i->ti());
2123 bu_ty.run(i->e());
2124 if (i->e() && !env.isSubtype(i->e()->type(), i->ti()->type(), true))
2125 throw TypeError(env, i->e()->loc(),
2126 "return type of function does not match body, declared type is `" +
2127 i->ti()->type().toString(env) + "', body type is `" +
2128 i->e()->type().toString(env) + "'");
2129 if (i->e() && i->e()->type().ispar() && i->ti()->type().isvar()) {
2130 // this is a par function declared as var, so change declared return type
2131 Type i_t = i->ti()->type();
2132 i_t.ti(Type::TI_PAR);
2133 i->ti()->type(i_t);
2134 }
2135 if (i->e()) i->e(addCoercion(env, m, i->e(), i->ti()->type())());
2136 }
2137 } _tsv2(env.envi(), m, bu_ty, typeErrors);
2138 iterItems(_tsv2, m);
2139 }
2140
2141 class TSV3 : public ItemVisitor {
2142 public:
2143 EnvI& env;
2144 Model* m;
2145 OutputI* outputItem;
2146 TSV3(EnvI& env0, Model* m0) : env(env0), m(m0), outputItem(NULL) {}
2147 void vAssignI(AssignI* i) { i->decl()->e(addCoercion(env, m, i->e(), i->decl()->type())()); }
2148 void vOutputI(OutputI* oi) {
2149 if (outputItem == NULL) {
2150 outputItem = oi;
2151 } else {
2152 GCLock lock;
2153 BinOp* bo = new BinOp(Location().introduce(), outputItem->e(), BOT_PLUSPLUS, oi->e());
2154 bo->type(Type::parstring(1));
2155 outputItem->e(bo);
2156 oi->remove();
2157 m->setOutputItem(outputItem);
2158 }
2159 }
2160 } _tsv3(env.envi(), m);
2161 if (typeErrors.empty()) {
2162 iterItems(_tsv3, m);
2163 }
2164
2165 try {
2166 m->checkFnOverloading(env.envi());
2167 } catch (TypeError& e) {
2168 typeErrors.push_back(e);
2169 }
2170
2171 for (unsigned int i = 0; i < ts.decls.size(); i++) {
2172 if (ts.decls[i]->toplevel() && ts.decls[i]->type().ispar() && !ts.decls[i]->type().isann() &&
2173 ts.decls[i]->e() == NULL) {
2174 if (ts.decls[i]->type().isopt() && ts.decls[i]->type().dim() == 0) {
2175 ts.decls[i]->e(constants().absent);
2176 } else if (!ignoreUndefinedParameters) {
2177 typeErrors.push_back(
2178 TypeError(env.envi(), ts.decls[i]->loc(),
2179 " symbol error: variable `" + ts.decls[i]->id()->str().str() +
2180 "' must be defined (did you forget to specify a data file?)"));
2181 }
2182 }
2183 if (ts.decls[i]->ti()->isEnum()) {
2184 ts.decls[i]->ti()->setIsEnum(false);
2185 Type vdt = ts.decls[i]->ti()->type();
2186 vdt.enumId(0);
2187 ts.decls[i]->ti()->type(vdt);
2188 }
2189 }
2190
2191 for (auto vd_k : env.envi().checkVars) {
2192 try {
2193 VarDecl* vd =
2194 ts.get(env.envi(), vd_k()->cast<VarDecl>()->id()->str(), vd_k()->cast<VarDecl>()->loc());
2195 vd->ann().add(constants().ann.mzn_check_var);
2196 if (vd->type().enumId() != 0) {
2197 GCLock lock;
2198 int enumId = vd->type().enumId();
2199 if (vd->type().dim() > 0) {
2200 const std::vector<unsigned int>& arrayEnumIds =
2201 env.envi().getArrayEnum(vd->type().enumId());
2202 enumId = arrayEnumIds[arrayEnumIds.size() - 1];
2203 }
2204 if (enumId > 0) {
2205 std::vector<Expression*> args({env.envi().getEnum(enumId)->e()->id()});
2206 Call* checkEnum =
2207 new Call(Location().introduce(), constants().ann.mzn_check_enum_var, args);
2208 checkEnum->type(Type::ann());
2209 checkEnum->decl(env.envi().model->matchFn(env.envi(), checkEnum, false));
2210 vd->ann().add(checkEnum);
2211 }
2212 }
2213 Type vdktype = vd_k()->type();
2214 vdktype.ti(Type::TI_VAR);
2215 if (!vd_k()->type().isSubtypeOf(vd->type(), false)) {
2216 GCLock lock;
2217
2218 typeErrors.push_back(TypeError(env.envi(), vd->loc(),
2219 "Solution checker requires `" + vd->id()->str().str() +
2220 "' to be of type `" + vdktype.toString(env.envi()) +
2221 "'"));
2222 }
2223 } catch (TypeError& e) {
2224 typeErrors.push_back(
2225 TypeError(env.envi(), e.loc(), e.msg() + " (required by solution checker model)"));
2226 }
2227 }
2228}
2229
2230void typecheck(Env& env, Model* m, AssignI* ai) {
2231 std::vector<TypeError> typeErrors;
2232 Typer<true> ty(env.envi(), m, typeErrors, false);
2233 BottomUpIterator<Typer<true> > bu_ty(ty);
2234 bu_ty.run(ai->e());
2235 if (!typeErrors.empty()) {
2236 throw typeErrors[0];
2237 }
2238 if (!env.envi().isSubtype(ai->e()->type(), ai->decl()->ti()->type(), true)) {
2239 throw TypeError(env.envi(), ai->e()->loc(),
2240 "assignment value for `" + ai->decl()->id()->str().str() +
2241 "' has invalid type-inst: expected `" +
2242 ai->decl()->ti()->type().toString(env.envi()) + "', actual `" +
2243 ai->e()->type().toString(env.envi()) + "'");
2244 }
2245}
2246
2247void output_var_desc_json(Env& env, VarDecl* vd, std::ostream& os, bool extra = false) {
2248 os << " \"" << *vd->id() << "\" : {";
2249 os << "\"type\" : ";
2250 switch (vd->type().bt()) {
2251 case Type::BT_INT:
2252 os << "\"int\"";
2253 break;
2254 case Type::BT_BOOL:
2255 os << "\"bool\"";
2256 break;
2257 case Type::BT_FLOAT:
2258 os << "\"float\"";
2259 break;
2260 case Type::BT_STRING:
2261 os << "\"string\"";
2262 break;
2263 case Type::BT_ANN:
2264 os << "\"ann\"";
2265 break;
2266 default:
2267 os << "\"?\"";
2268 break;
2269 }
2270 if (vd->type().ot() == Type::OT_OPTIONAL) {
2271 os << ", \"optional\" : true";
2272 }
2273 if (vd->type().st() == Type::ST_SET) {
2274 os << ", \"set\" : true";
2275 }
2276 if (vd->type().dim() > 0) {
2277 os << ", \"dim\" : " << vd->type().dim();
2278
2279 if (extra) {
2280 os << ", \"dims\" : [";
2281 bool had_dim = false;
2282 ASTExprVec<TypeInst> ranges = vd->ti()->ranges();
2283 for (int i = 0; i < static_cast<int>(ranges.size()); i++) {
2284 if (ranges[i]->type().enumId() > 0) {
2285 os << (had_dim ? "," : "") << "\""
2286 << *env.envi().getEnum(ranges[i]->type().enumId())->e()->id() << "\"";
2287 } else {
2288 os << (had_dim ? "," : "") << "\"int\"";
2289 }
2290 had_dim = true;
2291 }
2292 os << "]";
2293
2294 if (vd->type().enumId() > 0) {
2295 const std::vector<unsigned int>& enumIds = env.envi().getArrayEnum(vd->type().enumId());
2296 if (enumIds.back() > 0) {
2297 os << ", \"enum_type\" : \"" << *env.envi().getEnum(enumIds.back())->e()->id() << "\"";
2298 }
2299 }
2300 }
2301
2302 } else {
2303 if (extra) {
2304 if (vd->type().enumId() > 0) {
2305 os << ", \"enum_type\" : \"" << *env.envi().getEnum(vd->type().enumId())->e()->id() << "\"";
2306 }
2307 }
2308 }
2309 os << "}";
2310}
2311
2312void output_model_variable_types(Env& env, Model* m, std::ostream& os) {
2313 class VInfVisitor : public ItemVisitor {
2314 public:
2315 Env& env;
2316 bool had_var;
2317 bool had_enum;
2318 std::ostringstream oss_vars;
2319 std::ostringstream oss_enums;
2320 VInfVisitor(Env& env0) : env(env0), had_var(false), had_enum(false) {}
2321 bool enter(Item* i) {
2322 if (IncludeI* ii = i->dyn_cast<IncludeI>()) {
2323 std::string prefix =
2324 ii->m()->filepath().str().substr(0, ii->m()->filepath().size() - ii->f().size());
2325 return (prefix.empty() || prefix == "./");
2326 }
2327 return true;
2328 }
2329 void vVarDeclI(VarDeclI* vdi) {
2330 if (!vdi->e()->type().isann() && !vdi->e()->ti()->isEnum()) {
2331 if (had_var) oss_vars << ",\n";
2332 output_var_desc_json(env, vdi->e(), oss_vars, true);
2333 had_var = true;
2334 } else if (vdi->e()->type().st() == Type::ST_SET && vdi->e()->type().enumId() != 0 &&
2335 !vdi->e()->type().isann()) {
2336 if (had_enum) oss_enums << ", ";
2337 oss_enums << "\"" << *env.envi().getEnum(vdi->e()->type().enumId())->e()->id() << "\"";
2338 had_enum = true;
2339 }
2340 }
2341 } _vinf(env);
2342 iterItems(_vinf, m);
2343 os << "{\"var_types\": {";
2344 os << "\n \"vars\": {\n" << _vinf.oss_vars.str() << "\n },";
2345 os << "\n \"enums\": [" << _vinf.oss_enums.str() << "]\n";
2346 os << "}}\n";
2347}
2348
2349void output_model_interface(Env& env, Model* m, std::ostream& os) {
2350 class IfcVisitor : public ItemVisitor {
2351 public:
2352 Env& env;
2353 bool had_input;
2354 bool had_output;
2355 bool had_add_to_output = false;
2356 std::ostringstream oss_input;
2357 std::ostringstream oss_output;
2358 std::string method;
2359 IfcVisitor(Env& env0) : env(env0), had_input(false), had_output(false), method("sat") {}
2360 bool enter(Item* i) {
2361 if (IncludeI* ii = i->dyn_cast<IncludeI>()) {
2362 std::string prefix =
2363 ii->m()->filepath().str().substr(0, ii->m()->filepath().size() - ii->f().size());
2364 return (prefix.empty() || prefix == "./");
2365 }
2366 return true;
2367 }
2368 void vVarDeclI(VarDeclI* vdi) {
2369 VarDecl* vd = vdi->e();
2370 if (vd->type().ispar() && !vd->type().isann() &&
2371 (vd->e() == NULL || vd->e() == constants().absent)) {
2372 if (had_input) oss_input << ",\n";
2373 output_var_desc_json(env, vd, oss_input);
2374 had_input = true;
2375 } else {
2376 bool process_var = false;
2377 if (vd->ann().contains(constants().ann.add_to_output)) {
2378 if (!had_add_to_output) {
2379 oss_output.str("");
2380 had_output = false;
2381 }
2382 had_add_to_output = true;
2383 process_var = true;
2384 } else if (!had_add_to_output) {
2385 process_var =
2386 vd->type().isvar() &&
2387 (vd->e() == NULL || vd->ann().contains(constants().ann.rhs_from_assignment));
2388 }
2389 if (process_var) {
2390 if (had_output) {
2391 oss_output << ",\n";
2392 }
2393 output_var_desc_json(env, vd, oss_output);
2394 had_output = true;
2395 }
2396 }
2397 }
2398 void vSolveI(SolveI* si) {
2399 switch (si->st()) {
2400 case SolveI::ST_MIN:
2401 method = "min";
2402 break;
2403 case SolveI::ST_MAX:
2404 method = "max";
2405 break;
2406 case SolveI::ST_SAT:
2407 method = "sat";
2408 break;
2409 }
2410 }
2411 } _ifc(env);
2412 iterItems(_ifc, m);
2413 os << "{\n \"input\" : {\n"
2414 << _ifc.oss_input.str() << "\n },\n \"output\" : {\n"
2415 << _ifc.oss_output.str() << "\n }";
2416 os << ",\n \"method\": \"";
2417 os << _ifc.method;
2418 os << "\"";
2419 os << "\n}\n";
2420}
2421
2422} // namespace MiniZinc