Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * (author) M. Kersten
15 : *
16 : * Search the first definition of the operator in the current module
17 : * and check the parameter types.
18 : * For a polymorphic MAL function we make a fully instantiated clone.
19 : * It will be prepended to the symbol list as it is more restrictive.
20 : * This effectively overloads the MAL procedure.
21 : */
22 : #include "monetdb_config.h"
23 : #include "mal_resolve.h"
24 : #include "mal_namespace.h"
25 : #include "mal_private.h"
26 : #include "mal_linker.h"
27 :
28 : #define MAXTYPEVAR 4
29 :
30 : static malType getPolyType(malType t, int *polytype);
31 : static int updateTypeMap(int formal, int actual, int polytype[MAXTYPEVAR]);
32 : static bool typeResolved(MalBlkPtr mb, InstrPtr p, int i);
33 :
34 : int
35 193314331 : resolvedType(int dsttype, int srctype)
36 : {
37 193314331 : if (dsttype == srctype || dsttype == TYPE_any || srctype == TYPE_any)
38 : return 0;
39 :
40 129446381 : if (getOptBat(dsttype) && isaBatType(srctype)) {
41 2412 : int t1 = getBatType(dsttype);
42 2412 : int t2 = getBatType(srctype);
43 2412 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
44 : return 0;
45 : }
46 12311 : if (getOptBat(dsttype) && !isaBatType(srctype)) {
47 10378 : int t1 = getBatType(dsttype);
48 10378 : int t2 = srctype;
49 10378 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
50 : return 0;
51 : }
52 :
53 129445748 : if (isaBatType(dsttype) && isaBatType(srctype)) {
54 87603975 : int t1 = getBatType(dsttype);
55 87603975 : int t2 = getBatType(srctype);
56 87603975 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
57 48356855 : return 0;
58 : }
59 : return -1;
60 : }
61 :
62 : static int
63 51375672 : resolveType(int *rtype, int dsttype, int srctype)
64 : {
65 51375672 : if (dsttype == srctype) {
66 22235365 : *rtype = dsttype;
67 22235365 : return 0;
68 : }
69 29140307 : if (dsttype == TYPE_any) {
70 3178537 : *rtype = srctype;
71 3178537 : return 0;
72 : }
73 25961770 : if (srctype == TYPE_any) {
74 18196438 : *rtype = dsttype;
75 18196438 : return 0;
76 : }
77 : /*
78 : * A bat reference can be coerced to bat type.
79 : */
80 7765332 : if (isaBatType(dsttype) && isaBatType(srctype)) {
81 7737228 : int t1, t2, t3;
82 7737228 : t1 = getBatType(dsttype);
83 7737228 : t2 = getBatType(srctype);
84 7737228 : if (t1 == t2)
85 : t3 = t1;
86 7737225 : else if (t1 == TYPE_any)
87 : t3 = t2;
88 122036 : else if (t2 == TYPE_any)
89 : t3 = t1;
90 : else {
91 : return -1;
92 : }
93 7615198 : *rtype = newBatType(t3);
94 7615198 : return 0;
95 : }
96 : return -1;
97 : }
98 :
99 :
100 : /*
101 : * Since we now know the storage type of the receiving variable, we can
102 : * set the garbage collection flag.
103 : */
104 : #define prepostProcess(tp, p, b, mb) \
105 : do { \
106 : if( isaBatType(tp) || \
107 : ATOMtype(tp) == TYPE_str || \
108 : (!isPolyType(tp) && tp < TYPE_any && \
109 : tp >= 0 && ATOMextern(tp))) { \
110 : getInstrPtr(mb, 0)->gc = true; \
111 : setVarCleanup(mb, getArg(p, b)); \
112 : p->gc = true; \
113 : } \
114 : } while (0)
115 :
116 : static malType
117 303728436 : getFormalArgType( Symbol s, int arg)
118 : {
119 303728436 : if (s->kind == FUNCTIONsymbol)
120 37237 : return getArgType(s->def, getSignature(s), arg);
121 303691199 : mel_arg *a = s->func->args+arg;
122 303691199 : malType tpe = TYPE_any;
123 303691199 : if (a->nr || !a->type[0]) {
124 114331154 : if (a->isbat)
125 : tpe = newBatType(TYPE_any);
126 : else
127 16561245 : tpe = a->typeid;
128 114331154 : setTypeIndex(tpe, a->nr);
129 : } else {
130 189360045 : if (a->isbat)
131 76237439 : tpe = newBatType(a->typeid);
132 : else
133 113122606 : tpe = a->typeid;
134 : }
135 303691199 : if (a->opt == 1)
136 30389 : setOptBat(tpe);
137 : return tpe;
138 : }
139 :
140 : static malType
141 51978515 : findFunctionType(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
142 : {
143 51978515 : Module m;
144 51978515 : Symbol s;
145 51978515 : int i, k, unmatched = 0, s1;
146 51978515 : int polytype[MAXTYPEVAR];
147 51978515 : int returns[256];
148 51978515 : int *returntype = NULL;
149 : /*
150 : * Within a module find the element in its list
151 : * of symbols. A skiplist is used to speed up the search for the
152 : * definition of the function.
153 : *
154 : * For the implementation we should be aware that over 90% of the
155 : * functions in the kernel have just a few arguments and a single
156 : * return value.
157 : * A point of concern is that polymorphic arithmetic operations
158 : * lead to an explosion in the symbol table. This increase the
159 : * loop to find a candidate.
160 : *
161 : * Consider to collect the argument type into a separate structure, because
162 : * it will be looked up multiple types to resolve the instruction.[todo]
163 : * Simplify polytype using a map into the concrete argument table.
164 : */
165 :
166 51978515 : m = scope;
167 51978515 : s = m->space[(int) (getSymbolIndex(getFunctionId(p)))];
168 51978515 : if (s == 0)
169 : return -1;
170 :
171 51978328 : if (p->retc < 256) {
172 107138808 : for (i = 0; i < p->retc; i++)
173 55160520 : returns[i] = 0;
174 51978328 : returntype = returns;
175 : } else {
176 40 : returntype = (int *) GDKzalloc(p->retc * sizeof(int));
177 40 : if (returntype == 0)
178 : return -1;
179 : }
180 :
181 349518178 : while (s != NULL) { /* single scope element check */
182 349517407 : if (getFunctionId(p) != s->name) {
183 90560192 : s = s->skip;
184 90560192 : continue;
185 : }
186 : /*
187 : * Perform a strong type-check on the actual arguments. If it
188 : * turns out to be a polymorphic MAL function, we have to
189 : * clone it. Provided the actual/formal parameters are
190 : * compliant throughout the function call.
191 : *
192 : * Also look out for variable argument lists. This means that
193 : * we have to keep two iterators, one for the caller (i) and
194 : * one for the callee (k). Since a variable argument only
195 : * occurs as the last one, we simple avoid an increment when
196 : * running out of formal arguments.
197 : *
198 : * A call of the form (X1,..., Xi) := f(Y1,....,Yn) can be
199 : * matched against the function signature (B1,...,Bk):=
200 : * f(A1,...,Am) where i==k , n<=m and
201 : * type(Ai)=type(Yi). Furthermore, the variables Xi obtain
202 : * their type from Bi (or type(Bi)==type(Xi)).
203 : */
204 258957215 : int argc = 0, argcc = 0, retc = 0, varargs = 0, varrets = 0, unsafe = 0, inlineprop = 0, polymorphic = 0;
205 258957215 : if (s->kind == FUNCTIONsymbol) {
206 9239 : InstrPtr sig = getSignature(s);
207 9239 : retc = sig->retc;
208 9239 : argc = sig->argc;
209 9239 : varargs = (sig->varargs & (VARARGS | VARRETS));
210 9239 : varrets = (sig->varargs & VARRETS);
211 9239 : unsafe = s->def->unsafeProp;
212 9239 : inlineprop = s->def->inlineProp;
213 9239 : polymorphic = sig->polymorphic;
214 9239 : argcc = argc;
215 : } else {
216 258947976 : retc = s->func->retc;
217 258947976 : argc = s->func->argc;
218 258947976 : varargs = /*retc == 0 ||*/ s->func->vargs || s->func->vrets;
219 258947976 : varrets = retc == 0 || s->func->vrets;
220 258947976 : unsafe = s->func->unsafe;
221 258947976 : inlineprop = 0;
222 258947976 : polymorphic = s->func->poly;
223 258947976 : if (!retc && !polymorphic)
224 2165975 : polymorphic = 1;
225 258947976 : argcc = argc + ((retc == 0)?1:0);
226 : }
227 258957215 : unmatched = 0;
228 :
229 : /*
230 : * The simple case could be taken care of separately to
231 : * speedup processing
232 : * However, it turned out not to make a big difference. The
233 : * first time we encounter a polymorphic argument in the
234 : * signature.
235 : * Subsequently, the polymorphic arguments update this table
236 : * and check for any type mismatches that might occur. There
237 : * are at most 2 type variables involved per argument due to
238 : * the limited type nesting permitted. Note, each function
239 : * returns at least one value.
240 : */
241 258957215 : if (polymorphic) {
242 63185722 : int limit = polymorphic;
243 63185722 : if (!(argcc == p->argc || (argc < p->argc && varargs))) {
244 26836045 : s = s->peer;
245 26836045 : continue;
246 : }
247 36349677 : if (retc != p->retc && !varrets) {
248 298457 : s = s->peer;
249 298457 : continue;
250 : }
251 :
252 102392718 : for (k = 0; k < limit; k++)
253 66341498 : polytype[k] = TYPE_any;
254 : /*
255 : * Most polymorphic functions don't have a variable argument
256 : * list. So we save some instructions factoring this caise out.
257 : * Be careful, the variable number of return arguments should
258 : * be considered as well.
259 : */
260 : i = p->retc;
261 : /* first handle the variable argument list */
262 179875485 : for (k = retc; i < p->argc; k++, i++) {
263 146771577 : int actual = getArgType(mb, p, i);
264 146771577 : int formal = getFormalArgType(s, k);
265 146771577 : if (k == argc - 1 && varargs)
266 54085005 : k--;
267 : /*
268 : * Take care of variable argument lists.
269 : * They are allowed as the last in the signature only.
270 : * Furthermore, for patterns if the formal type is
271 : * 'any' then all remaining arguments are acceptable
272 : * and detailed type analysis becomes part of the
273 : * pattern implementation.
274 : * In all other cases the type should apply to all
275 : * remaining arguments.
276 : */
277 146771577 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
278 146771577 : formal = actual;
279 146771577 : if (formal == actual)
280 58358712 : continue;
281 88412865 : if (updateTypeMap(formal, actual, polytype)) {
282 : unmatched = i;
283 : break;
284 : }
285 86596704 : formal = getPolyType(formal, polytype);
286 : /*
287 : * Collect the polymorphic types and resolve them.
288 : * If it fails, we know this isn't the function we are
289 : * looking for.
290 : */
291 86596704 : if (resolvedType(formal, actual) < 0) {
292 : unmatched = i;
293 : break;
294 : }
295 : }
296 : /*
297 : * The last argument/result type could be a polymorphic
298 : * variable list. It should only be allowed for patterns,
299 : * where it can deal with the stack. If the type is
300 : * specified as :any then any mix of arguments is allowed.
301 : * If the type is a new numbered type variable then the
302 : * first element in the list determines the required type
303 : * of all.
304 : */
305 36043715 : if (varargs) {
306 6762366 : if (s->kind != PATTERNsymbol && retc)
307 : unmatched = i;
308 : else {
309 : /* resolve the arguments */
310 6764377 : for (; i < p->argc; i++) {
311 : /* the type of the last one has already been set */
312 1453731 : int actual = getArgType(mb, p, i);
313 1453731 : int formal = getFormalArgType(s, k);
314 1453731 : if (k == argc - 1 && varargs)
315 0 : k--;
316 :
317 1453731 : formal = getPolyType(formal, polytype);
318 1453731 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
319 1453731 : formal = actual;
320 1453731 : if (formal == actual || formal == TYPE_any)
321 1020 : continue;
322 1452711 : if (resolvedType(formal, actual) < 0) {
323 : unmatched = i;
324 : break;
325 : }
326 : }
327 : }
328 : }
329 : } else {
330 : /*
331 : * We have to check the argument types to determine a
332 : * possible match for the non-polymorphic case.
333 : */
334 195771493 : if (argc != p->argc || retc != p->retc) {
335 98248200 : s = s->peer;
336 98248200 : continue;
337 : }
338 :
339 :
340 124309032 : for (i = p->retc; i < p->argc; i++) {
341 105292074 : int actual = getArgType(mb, p, i);
342 105292074 : int formal = getFormalArgType(s, i);
343 105292074 : if (resolvedType(formal, actual) < 0) {
344 : unmatched = i;
345 : break;
346 : }
347 : }
348 : }
349 : /*
350 : * It is possible that you may have to coerce the value to
351 : * another type. We assume that coercions are explicit at the
352 : * MAL level. (e.g. var2:= var0:int). This avoids repeated
353 : * type analysis just before you execute a function.
354 : * An optimizer may at a later stage automatically insert such
355 : * coercion requests.
356 : */
357 :
358 133568655 : if (unmatched) {
359 81446827 : s = s->peer;
360 81446827 : continue;
361 : }
362 : /*
363 : * At this stage we know all arguments are type compatible
364 : * with the signature.
365 : * We should assure that also the target variables have the
366 : * proper types or can inherit them from the signature. The
367 : * result type vector should be build separately first,
368 : * because we may encounter an error later on.
369 : *
370 : * If any of the arguments refer to a constraint type, any_x,
371 : * then the resulting type can not be determined.
372 : */
373 52121828 : s1 = 0;
374 52121828 : if (polymorphic) {
375 64202838 : for (k = i = 0; i < p->retc && k < retc; k++, i++) {
376 31102183 : int actual = getArgType(mb, p, i);
377 31102183 : int formal = getFormalArgType(s, k);
378 :
379 31102183 : if (k == retc - 1 && varrets)
380 336235 : k--;
381 :
382 31102183 : s1 = getPolyType(formal, polytype);
383 :
384 31102183 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
385 31102183 : s1 = actual;
386 31102183 : if (resolveType(returntype+i, s1, actual) < 0) {
387 : s1 = -1;
388 : break;
389 : }
390 : }
391 : } else {
392 : /* check for non-polymorphic return */
393 38130223 : for (k = i = 0; i < p->retc; i++) {
394 19262112 : int actual = getArgType(mb, p, i);
395 19262112 : int formal = getFormalArgType(s, i);
396 :
397 19262112 : if (k == retc - 1 && varrets)
398 : k--;
399 :
400 19262112 : if (actual == formal) {
401 5708393 : returntype[i] = actual;
402 : } else {
403 13553719 : if (resolveType(returntype+i, formal, actual) < 0) {
404 : s1 = -1;
405 : break;
406 : }
407 : }
408 : }
409 : }
410 52118895 : if (s1 < 0) {
411 150129 : s = s->peer;
412 150129 : continue;
413 : }
414 : /*
415 : * If the return types are correct, copy them in place.
416 : * Beware that signatures should be left untouched, which
417 : * means that we may not overwrite any formal argument.
418 : * Using the knowledge dat the arguments occupy the header
419 : * of the symbol stack, it is easy to filter such errors.
420 : * Also mark all variables that are subject to garbage control.
421 : * Beware, this is not yet effectuated in the interpreter.
422 : */
423 :
424 51968766 : p->typeresolved = true;
425 51968766 : p->inlineProp = inlineprop;
426 51968766 : p->unsafeProp = unsafe;
427 107149161 : for (i = 0; i < p->retc; i++) {
428 55180395 : int ts = returntype[i];
429 55180395 : if (isVarConstant(mb, getArg(p, i))) {
430 0 : if (!silent) {
431 0 : mb->errors = createMalException(mb, idx, TYPE,
432 : "Assignment to constant");
433 : }
434 0 : p->typeresolved = false;
435 0 : goto wrapup;
436 : }
437 55180395 : if (!isVarFixed(mb, getArg(p, i)) && ts >= 0) {
438 29459101 : setVarType(mb, getArg(p, i), ts);
439 29459101 : setVarFixed(mb, getArg(p, i));
440 : }
441 55180395 : prepostProcess(ts, p, i, mb);
442 : }
443 : /*
444 : * Also the arguments may contain constants
445 : * to be garbage collected.
446 : */
447 211382757 : for (i = p->retc; i < p->argc; i++)
448 159413991 : if (ATOMtype(getArgType(mb, p, i)) == TYPE_str ||
449 128739551 : isaBatType(getArgType(mb, p, i)) ||
450 36108734 : (!isPolyType(getArgType(mb, p, i)) &&
451 36108722 : getArgType(mb, p, i) < TYPE_any &&
452 36108722 : getArgType(mb, p, i) >= 0 &&
453 36108722 : ATOMstorage(getArgType(mb, p, i)) == TYPE_str)) {
454 123308351 : getInstrPtr(mb, 0)->gc = true;
455 123308351 : p->gc = true;
456 : }
457 : /*
458 : * It may happen that an argument was still untyped and as a
459 : * result of the polymorphism matching became strongly
460 : * typed. This should be reflected in the symbol table.
461 : */
462 51968766 : s1 = returntype[0]; /* for those interested */
463 : /*
464 : * If the call refers to a polymorphic function, we clone it
465 : * to arrive at a bounded instance. Polymorphic patterns and
466 : * commands are responsible for type resolution themselves.
467 : * Note that cloning pre-supposes that the function being
468 : * cloned does not contain errors detected earlier in the
469 : * process, nor does it contain polymorphic actual arguments.
470 : */
471 51968766 : if (polymorphic) {
472 : int cnt = 0;
473 174147554 : for (k = i = p->retc; i < p->argc; i++) {
474 141044248 : int actual = getArgType(mb, p, i);
475 141044248 : if (isAnyExpression(actual))
476 10 : cnt++;
477 : }
478 33103306 : if (cnt == 0 && s->kind != COMMANDsymbol
479 16871301 : && s->kind != PATTERNsymbol) {
480 11 : assert(s->kind == FUNCTIONsymbol);
481 11 : s = cloneFunction(scope, s, mb, p);
482 11 : if (mb->errors)
483 3 : goto wrapup;
484 : }
485 : }
486 : /* Any previously found error in the block
487 : * turns the complete block into erroneous.
488 : if (mb->errors) {
489 : p->typeresolved = false;
490 : goto wrapup;
491 : }
492 : */
493 :
494 : /*
495 : * We found the proper function. Copy some properties. In
496 : * particular, determine the calling strategy, i.e. FCNcall,
497 : * CMDcall, PATcall Beware that polymorphic functions
498 : * may produce type-incorrect clones. This piece of code may be
499 : * shared by the separate binder
500 : */
501 51968763 : if (p->token == ASSIGNsymbol) {
502 51977461 : switch (s->kind) {
503 16906508 : case COMMANDsymbol:
504 16906508 : p->token = CMDcall;
505 16906508 : p->fcn = s->func->imp; /* C implementation mandatory */
506 16906508 : if (p->fcn == NULL) {
507 1 : if (!silent)
508 1 : mb->errors = createMalException(mb, idx, TYPE,
509 : "object code for command %s.%s missing",
510 : p->modname, p->fcnname);
511 1 : p->typeresolved = false;
512 1 : goto wrapup;
513 : }
514 : break;
515 35061749 : case PATTERNsymbol:
516 35061749 : p->token = PATcall;
517 35061749 : p->fcn = s->func->imp; /* C implementation optional */
518 35061749 : break;
519 9204 : case FUNCTIONsymbol:
520 9204 : p->token = FCNcall;
521 9204 : if (getSignature(s)->fcn)
522 0 : p->fcn = getSignature(s)->fcn; /* C implementation optional */
523 : break;
524 0 : default:
525 0 : if (!silent)
526 0 : mb->errors = createMalException(mb, idx, MAL,
527 : "MALresolve: unexpected token type");
528 0 : goto wrapup;
529 : }
530 51977460 : p->blk = s->def;
531 : }
532 :
533 51968762 : if (returntype != returns)
534 40 : GDKfree(returntype);
535 : return s1;
536 : } /* while */
537 : /*
538 : * We haven't found the correct function. To ease debugging, we
539 : * may reveal that we found an instruction with the proper
540 : * arguments, but that clashes with one of the target variables.
541 : */
542 771 : wrapup:
543 775 : if (returntype != returns)
544 0 : GDKfree(returntype);
545 : return -3;
546 : }
547 :
548 : /*
549 : * We try to clear the type check flag by looking up the
550 : * functions. Errors are simply ignored at this point of the game,
551 : * because they may be resolved as part of the calling sequence.
552 : */
553 : static void
554 5 : typeMismatch(MalBlkPtr mb, InstrPtr p, int idx, int lhs, int rhs, int silent)
555 : {
556 5 : str n1;
557 5 : str n2;
558 :
559 5 : if (!silent) {
560 5 : n1 = getTypeName(lhs);
561 5 : n2 = getTypeName(rhs);
562 5 : mb->errors = createMalException(mb, idx, TYPE, "type mismatch %s := %s", n1,
563 : n2);
564 5 : GDKfree(n1);
565 5 : GDKfree(n2);
566 : }
567 5 : p->typeresolved = false;
568 5 : }
569 :
570 : /*
571 : * A function search should inspect all modules unless a specific module
572 : * is given. Preference is given to the lower scopes.
573 : * The type check is set to TYPE_UNKNOWN first to enforce a proper
574 : * analysis. This way it forms a cheap mechanism to resolve
575 : * the type after a change by an optimizer.
576 : * If we can not find the function, the type check returns unsuccessfully.
577 : * In this case we should issue an error message to the user.
578 : *
579 : * A re-check after the optimizer call should reset the token
580 : * to assignment.
581 : */
582 : void
583 62064319 : typeChecker(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
584 : {
585 62064319 : int s1 = -1, i, k;
586 62064319 : Module m = 0;
587 :
588 62064319 : p->typeresolved = false;
589 62064319 : if ((p->fcn || p->blk) && p->token >= FCNcall && p->token <= PATcall) {
590 40972808 : p->token = ASSIGNsymbol;
591 40972808 : p->fcn = NULL;
592 40972808 : p->blk = NULL;
593 : }
594 :
595 62064319 : if (isaSignature(p)) {
596 3777429 : for (k = 0; k < p->argc; k++)
597 1893222 : setVarFixed(mb, getArg(p, k));
598 1887151 : for (k = p->retc; k < p->argc; k++) {
599 2944 : prepostProcess(getArgType(mb, p, k), p, k, mb);
600 : }
601 1884207 : p->typeresolved = true;
602 3774501 : for (k = 0; k < p->retc; k++)
603 1890294 : p->typeresolved &= typeResolved(mb, p, 0);
604 53854226 : return;
605 : }
606 60180112 : if (getFunctionId(p) && getModuleId(p)) {
607 51974932 : m = findModule(scope, getModuleId(p));
608 :
609 51972681 : if (!m || strcmp(m->name, getModuleId(p)) != 0) {
610 194 : if (!silent)
611 2 : mb->errors = createMalException(mb, idx, TYPE, "'%s%s%s' undefined",
612 : (getModuleId(p) ? getModuleId(p) : ""),
613 1 : (getModuleId(p) ? "." : ""),
614 : getFunctionId(p));
615 194 : return;
616 : }
617 51972487 : s1 = findFunctionType(m, mb, p, idx, silent);
618 :
619 51969840 : if (s1 >= 0)
620 : return;
621 : /*
622 : * Could not find a function that satisfies the constraints.
623 : * If the instruction is just a function header we may
624 : * continue. Likewise, the function and module may refer to
625 : * string variables known only at runtime.
626 : *
627 : * In all other cases we should generate a message, but only
628 : * if we know that the error was not caused by checking the
629 : * definition of a polymorphic function or the module or
630 : * function name are variables, In those cases, the detailed
631 : * analysis is performed upon an actual call.
632 : */
633 962 : if (!isaSignature(p) && !getInstrPtr(mb, 0)->polymorphic) {
634 951 : if (!silent) {
635 21 : char *errsig = NULL;
636 21 : if (!malLibraryEnabled(p->modname)) {
637 0 : mb->errors = createMalException(mb, idx, TYPE,
638 : "'%s%s%s' library error in: %s",
639 : (getModuleId(p) ?
640 : getModuleId(p) : ""),
641 0 : (getModuleId(p) ? "." : ""),
642 : getFunctionId(p),
643 : malLibraryHowToEnable(p->
644 : modname));
645 : } else {
646 21 : bool free_errsig = false, special_undefined = false;
647 21 : errsig = malLibraryHowToEnable(p->modname);
648 21 : if (!strcmp(errsig, "")) {
649 21 : errsig = instruction2str(mb, 0, p,
650 : (LIST_MAL_NAME | LIST_MAL_TYPE
651 : | LIST_MAL_VALUE));
652 21 : free_errsig = true;
653 : } else {
654 : special_undefined = true;
655 : }
656 63 : mb->errors = createMalException(mb, idx, TYPE,
657 : "'%s%s%s' undefined%s: %s",
658 : (getModuleId(p) ?
659 : getModuleId(p) : ""),
660 21 : (getModuleId(p) ? "." : ""),
661 : getFunctionId(p),
662 : special_undefined ? "" :
663 : " in",
664 : errsig ? errsig :
665 : "failed instruction2str()");
666 21 : if (free_errsig)
667 21 : GDKfree(errsig);
668 : }
669 : }
670 951 : p->typeresolved = false;
671 : } else
672 11 : p->typeresolved = true;
673 962 : return;
674 : }
675 : /*
676 : * When we arrive here the operator is an assignment.
677 : * The language should also recognize (a,b):=(1,2);
678 : * This is achieved by propagation of the rhs types to the lhs
679 : * variables.
680 : */
681 8205180 : if (getFunctionId(p)) {
682 : return;
683 : }
684 8205200 : if (p->retc >= 1 && p->argc > p->retc && p->argc != 2 * p->retc) {
685 7 : if (!silent) {
686 7 : mb->errors = createMalException(mb, idx, TYPE,
687 : "Multiple assignment mismatch");
688 : }
689 7 : p->typeresolved = true;
690 : } else
691 8205193 : p->typeresolved = true;
692 14915390 : for (k = 0, i = p->retc; k < p->retc && i < p->argc; i++, k++) {
693 6710040 : int rhs = getArgType(mb, p, i);
694 6710040 : int lhs = getArgType(mb, p, k);
695 :
696 6710040 : if (rhs != TYPE_void) {
697 6709889 : if (resolveType(&s1, lhs, rhs) < 0) {
698 5 : typeMismatch(mb, p, idx, lhs, rhs, silent);
699 5 : return;
700 : }
701 : } else {
702 : /*
703 : * The language permits assignment of 'nil' to any variable,
704 : * using the target type.
705 : */
706 151 : if (lhs != TYPE_void && lhs != TYPE_any) {
707 3 : ValRecord cst = { .vtype = TYPE_void, .val.oval = void_nil, .bat = isaBatType(lhs) };
708 3 : int k;
709 :
710 3 : k = defConstant(mb, lhs, &cst);
711 3 : if (k >= 0)
712 3 : p->argv[i] = k;
713 3 : rhs = lhs;
714 : }
715 : }
716 :
717 6710190 : if (!isVarFixed(mb, getArg(p, k))) {
718 2949226 : setVarType(mb, getArg(p, k), rhs);
719 2949226 : setVarFixed(mb, getArg(p, k));
720 : }
721 6710190 : prepostProcess(s1, p, i, mb);
722 6710190 : prepostProcess(s1, p, k, mb);
723 : }
724 : /* the case where we have no rhs */
725 8205350 : if (p->barrier && p->retc == p->argc)
726 414781 : for (k = 0; k < p->retc; k++) {
727 208651 : int tpe = getArgType(mb, p, k);
728 208651 : if (isaBatType(tpe) ||
729 204700 : ATOMtype(tpe) == TYPE_str ||
730 204700 : (!isPolyType(tpe) && tpe < MAXATOMS && ATOMextern(tpe)))
731 3957 : setVarCleanup(mb, getArg(p, k));
732 : }
733 : }
734 :
735 : /*
736 : * After the parser finishes, we have to look for semantic errors,
737 : * such as flow of control problems and possible typeing conflicts.
738 : * The nesting of BARRIER and CATCH statements with their associated
739 : * flow of control primitives LEAVE and RETRY should form a valid
740 : * hierarchy. Failure to comply is considered a structural error
741 : * and leads to flagging the function as erroneous.
742 : * Also check general conformaty of the ML block structure.
743 : * It should start with a signature and finish with and ENDsymbol
744 : *
745 : * Type checking a program is limited to those instructions that are
746 : * not resolved yet. Once the program is completely checked, further calls
747 : * should be ignored. This should be separately administered for the flow
748 : * as well, because a dynamically typed instruction should later on not
749 : * lead to a re-check when it was already fully analyzed.
750 : */
751 : str
752 2717213 : chkTypes(Module s, MalBlkPtr mb, int silent)
753 : {
754 2717213 : InstrPtr p = 0;
755 2717213 : int i;
756 2717213 : str msg = MAL_SUCCEED;
757 :
758 149095789 : for (i = 0; mb->errors == NULL && i < mb->stop; i++) {
759 146378861 : p = getInstrPtr(mb, i);
760 146378861 : assert(p != NULL);
761 146378861 : if (!p->typeresolved)
762 61261741 : typeChecker(s, mb, p, i, silent);
763 : }
764 2716928 : if (mb->errors) {
765 34 : msg = mb->errors;
766 34 : mb->errors = NULL;
767 : }
768 2716928 : return msg;
769 : }
770 :
771 : /*
772 : * Type checking an individual instruction is dangerous,
773 : * because it ignores data flow and variable declarations.
774 : */
775 : int
776 23 : chkInstruction(Module s, MalBlkPtr mb, InstrPtr p)
777 : {
778 23 : if (mb->errors == MAL_SUCCEED) {
779 23 : p->typeresolved = false;
780 23 : typeChecker(s, mb, p, getPC(mb, p), TRUE);
781 : }
782 23 : return mb->errors != MAL_SUCCEED;
783 : }
784 :
785 : /*
786 : * Perform silent check on the program, merely setting the error flag.
787 : */
788 : str
789 526666 : chkProgram(Module s, MalBlkPtr mb)
790 : {
791 526666 : str msg;
792 : /* it is not ready yet, too fragile
793 : mb->typefixed = mb->stop == chk; ignored END */
794 : /* if( mb->flowfixed == 0)*/
795 :
796 526666 : if (mb->errors) {
797 23 : msg = mb->errors;
798 23 : mb->errors = NULL;
799 23 : return msg;
800 : }
801 526643 : msg = chkTypes(s, mb, FALSE);
802 526665 : if (msg == MAL_SUCCEED)
803 526631 : msg = chkFlow(mb);
804 526627 : if (msg == MAL_SUCCEED)
805 526619 : msg = chkDeclarations(mb);
806 : return msg;
807 : }
808 :
809 : /*
810 : * Polymorphic type analysis
811 : * MAL provides for type variables of the form any$N. This feature
812 : * supports polymorphic types, but also complicates the subsequent
813 : * analysis. A variable typed with any$N not occurring in the function
814 : * header leads to a dynamic typed statement. In principle we have
815 : * to type check the function upon each call.
816 : */
817 : static bool
818 1890294 : typeResolved(MalBlkPtr mb, InstrPtr p, int i)
819 : {
820 1890294 : malType t = getArgType(mb, p, i);
821 1890294 : if (t == TYPE_any || isAnyExpression(t)) {
822 382205 : return false;
823 : }
824 : return true;
825 : }
826 :
827 : /*
828 : * For a polymorphic commands we do not generate a cloned version.
829 : * It suffices to determine the actual return value taking into
830 : * account the type variable constraints.
831 : */
832 : static malType
833 119157518 : getPolyType(malType t, int *polytype)
834 : {
835 119157518 : int ti;
836 119157518 : malType tail;
837 :
838 119157518 : ti = getTypeIndex(t);
839 119157518 : if (!isaBatType(t) && ti > 0) {
840 13040470 : tail = polytype[ti];
841 13040470 : if (getOptBat(t))
842 385 : setOptBat(tail);
843 13040470 : return tail;
844 : }
845 :
846 106117048 : tail = ti == 0 ? getBatType(t) : polytype[ti];
847 106117048 : if (isaBatType(t)) {
848 103364939 : tail = newBatType(tail);
849 : }
850 106117048 : if (getOptBat(t))
851 12417 : setOptBat(tail);
852 : return tail;
853 : }
854 :
855 : /*
856 : * Each argument is checked for binding of polymorphic arguments.
857 : * This routine assumes that the type index is indeed smaller than maxarg.
858 : * (The parser currently enforces a single digit from 1-2 )
859 : * The polymorphic type 'any', i.e. any_0, does never constraint an operation
860 : * it can match with all polymorphic types.
861 : * The routine returns the instantiated formal type for subsequent
862 : * type resolution.
863 : */
864 : static int
865 88421957 : updateTypeMap(int formal, int actual, int polytype[MAXTYPEVAR])
866 : {
867 88421957 : int h, t, ret = 0;
868 :
869 88421957 : if (!isAnyExpression(formal) && isaBatType(formal) && isaBatType(actual))
870 : return 0;
871 :
872 42288470 : if ((h = getTypeIndex(formal))) {
873 40141642 : if (isaBatType(actual) && !isaBatType(formal) && !getOptBat(formal) &&
874 3443359 : (polytype[h] == TYPE_any || polytype[h] == actual)) {
875 2925430 : polytype[h] = actual;
876 2925430 : return 0;
877 : }
878 37216212 : t = getBatType(actual);
879 37216212 : if (t != polytype[h]) {
880 22767031 : if (isaBatType(polytype[h]) && isaBatType(actual))
881 : ret = 0;
882 22765747 : else if (polytype[h] == TYPE_any)
883 22445256 : polytype[h] = t;
884 : else {
885 : return -1;
886 : }
887 : }
888 : }
889 39042549 : if (isaBatType(formal)) {
890 27708754 : if (!isaBatType(actual))
891 : return -1;
892 : }
893 : return ret;
894 : }
|