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 207086943 : resolvedType(int dsttype, int srctype)
36 : {
37 207086943 : if (dsttype == srctype || dsttype == TYPE_any || srctype == TYPE_any)
38 : return 0;
39 :
40 131382112 : 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 12245 : if (getOptBat(dsttype) && !isaBatType(srctype)) {
47 10312 : int t1 = getBatType(dsttype);
48 10312 : int t2 = srctype;
49 10312 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
50 : return 0;
51 : }
52 :
53 131381479 : if (isaBatType(dsttype) && isaBatType(srctype)) {
54 88781122 : int t1 = getBatType(dsttype);
55 88781122 : int t2 = getBatType(srctype);
56 88781122 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
57 48981198 : return 0;
58 : }
59 : return -1;
60 : }
61 :
62 : static int
63 56510446 : resolveType(int *rtype, int dsttype, int srctype)
64 : {
65 56510446 : if (dsttype == srctype) {
66 24649265 : *rtype = dsttype;
67 24649265 : return 0;
68 : }
69 31861181 : if (dsttype == TYPE_any) {
70 3557921 : *rtype = srctype;
71 3557921 : return 0;
72 : }
73 28303260 : if (srctype == TYPE_any) {
74 19820438 : *rtype = dsttype;
75 19820438 : return 0;
76 : }
77 : /*
78 : * A bat reference can be coerced to bat type.
79 : */
80 8482822 : if (isaBatType(dsttype) && isaBatType(srctype)) {
81 8454179 : int t1, t2, t3;
82 8454179 : t1 = getBatType(dsttype);
83 8454179 : t2 = getBatType(srctype);
84 8454179 : if (t1 == t2)
85 : t3 = t1;
86 8454176 : else if (t1 == TYPE_any)
87 : t3 = t2;
88 125529 : else if (t2 == TYPE_any)
89 : t3 = t1;
90 : else {
91 : return -1;
92 : }
93 8328656 : *rtype = newBatType(t3);
94 8328656 : 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 329886848 : getFormalArgType( Symbol s, int arg)
118 : {
119 329886848 : if (s->kind == FUNCTIONsymbol)
120 40925 : return getArgType(s->def, getSignature(s), arg);
121 329845923 : mel_arg *a = s->func->args+arg;
122 329845923 : malType tpe = TYPE_any;
123 329845923 : if (a->nr || !a->type[0]) {
124 123021146 : if (a->isbat)
125 : tpe = newBatType(TYPE_any);
126 : else
127 19082806 : tpe = a->typeid;
128 123021146 : setTypeIndex(tpe, a->nr);
129 : } else {
130 206824777 : if (a->isbat)
131 80550525 : tpe = newBatType(a->typeid);
132 : else
133 126274252 : tpe = a->typeid;
134 : }
135 329845923 : if (a->opt == 1)
136 30663 : setOptBat(tpe);
137 : return tpe;
138 : }
139 :
140 : static malType
141 57623315 : findFunctionType(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
142 : {
143 57623315 : Module m;
144 57623315 : Symbol s;
145 57623315 : int i, k, unmatched = 0, s1;
146 57623315 : int polytype[MAXTYPEVAR];
147 57623315 : int returns[256];
148 57623315 : 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 57623315 : m = scope;
167 57623315 : s = m->space[(int) (getSymbolIndex(getFunctionId(p)))];
168 57623315 : if (s == 0)
169 : return -1;
170 :
171 57623044 : if (p->retc < 256) {
172 118984676 : for (i = 0; i < p->retc; i++)
173 61361672 : returns[i] = 0;
174 57623044 : returntype = returns;
175 : } else {
176 40 : returntype = (int *) GDKzalloc(p->retc * sizeof(int));
177 40 : if (returntype == 0)
178 : return -1;
179 : }
180 :
181 379271381 : while (s != NULL) { /* single scope element check */
182 379270223 : if (getFunctionId(p) != s->name) {
183 107352409 : s = s->skip;
184 107352409 : 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 271917814 : int argc = 0, argcc = 0, retc = 0, varargs = 0, varrets = 0, unsafe = 0, inlineprop = 0, polymorphic = 0;
205 271917814 : if (s->kind == FUNCTIONsymbol) {
206 10321 : InstrPtr sig = getSignature(s);
207 10321 : retc = sig->retc;
208 10321 : argc = sig->argc;
209 10321 : varargs = (sig->varargs & (VARARGS | VARRETS));
210 10321 : varrets = (sig->varargs & VARRETS);
211 10321 : unsafe = s->def->unsafeProp;
212 10321 : inlineprop = s->def->inlineProp;
213 10321 : polymorphic = sig->polymorphic;
214 10321 : argcc = argc;
215 : } else {
216 271907493 : retc = s->func->retc;
217 271907493 : argc = s->func->argc;
218 271907493 : varargs = /*retc == 0 ||*/ s->func->vargs || s->func->vrets;
219 271907493 : varrets = retc == 0 || s->func->vrets;
220 271907493 : unsafe = s->func->unsafe;
221 271907493 : inlineprop = 0;
222 271907493 : polymorphic = s->func->poly;
223 271907493 : if (!retc && !polymorphic)
224 2284851 : polymorphic = 1;
225 271907493 : argcc = argc + ((retc == 0)?1:0);
226 : }
227 271917814 : 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 271917814 : if (polymorphic) {
242 69552562 : int limit = polymorphic;
243 69552562 : if (!(argcc == p->argc || (argc < p->argc && varargs))) {
244 29600531 : s = s->peer;
245 29600531 : continue;
246 : }
247 39952031 : if (retc != p->retc && !varrets) {
248 329066 : s = s->peer;
249 329066 : continue;
250 : }
251 :
252 112899093 : for (k = 0; k < limit; k++)
253 73276128 : 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 195063222 : for (k = retc; i < p->argc; k++, i++) {
263 158781711 : int actual = getArgType(mb, p, i);
264 158781711 : int formal = getFormalArgType(s, k);
265 158781711 : if (k == argc - 1 && varargs)
266 55609221 : 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 158781711 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
278 158781711 : formal = actual;
279 158781711 : if (formal == actual)
280 64737962 : continue;
281 94043749 : if (updateTypeMap(formal, actual, polytype)) {
282 : unmatched = i;
283 : break;
284 : }
285 92023288 : 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 92023288 : 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 39619000 : if (varargs) {
306 7105855 : if (s->kind != PATTERNsymbol && retc)
307 : unmatched = i;
308 : else {
309 : /* resolve the arguments */
310 7107550 : for (; i < p->argc; i++) {
311 : /* the type of the last one has already been set */
312 1486258 : int actual = getArgType(mb, p, i);
313 1486258 : int formal = getFormalArgType(s, k);
314 1486258 : if (k == argc - 1 && varargs)
315 0 : k--;
316 :
317 1486258 : formal = getPolyType(formal, polytype);
318 1486258 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
319 1486258 : formal = actual;
320 1486258 : if (formal == actual || formal == TYPE_any)
321 1020 : continue;
322 1485238 : 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 202365252 : if (argc != p->argc || retc != p->retc) {
335 101279556 : s = s->peer;
336 101279556 : continue;
337 : }
338 :
339 :
340 135090537 : for (i = p->retc; i < p->argc; i++) {
341 113599537 : int actual = getArgType(mb, p, i);
342 113599537 : int formal = getFormalArgType(s, i);
343 113599537 : 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 140705799 : if (unmatched) {
359 82932614 : s = s->peer;
360 82932614 : 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 57773185 : s1 = 0;
374 57773185 : if (polymorphic) {
375 70582174 : for (k = i = 0; i < p->retc && k < retc; k++, i++) {
376 34308515 : int actual = getArgType(mb, p, i);
377 34308515 : int formal = getFormalArgType(s, k);
378 :
379 34308515 : if (k == retc - 1 && varrets)
380 354005 : k--;
381 :
382 34308515 : s1 = getPolyType(formal, polytype);
383 :
384 34308515 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
385 34308515 : s1 = actual;
386 34308515 : if (resolveType(returntype+i, s1, actual) < 0) {
387 : s1 = -1;
388 : break;
389 : }
390 : }
391 : } else {
392 : /* check for non-polymorphic return */
393 43190995 : for (k = i = 0; i < p->retc; i++) {
394 21856666 : int actual = getArgType(mb, p, i);
395 21856666 : int formal = getFormalArgType(s, i);
396 :
397 21856666 : if (k == retc - 1 && varrets)
398 : k--;
399 :
400 21856666 : if (actual == formal) {
401 7118397 : returntype[i] = actual;
402 : } else {
403 14738269 : if (resolveType(returntype+i, formal, actual) < 0) {
404 : s1 = -1;
405 : break;
406 : }
407 : }
408 : }
409 : }
410 57762149 : if (s1 < 0) {
411 154161 : s = s->peer;
412 154161 : 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 57607988 : p->typeresolved = true;
425 57607988 : p->inlineProp = inlineprop;
426 57607988 : p->unsafeProp = unsafe;
427 118985482 : for (i = 0; i < p->retc; i++) {
428 61377494 : int ts = returntype[i];
429 61377494 : 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 61377494 : if (!isVarFixed(mb, getArg(p, i)) && ts >= 0) {
438 32410313 : setVarType(mb, getArg(p, i), ts);
439 32410313 : setVarFixed(mb, getArg(p, i));
440 : }
441 61377494 : prepostProcess(ts, p, i, mb);
442 : }
443 : /*
444 : * Also the arguments may contain constants
445 : * to be garbage collected.
446 : */
447 235196022 : for (i = p->retc; i < p->argc; i++)
448 177588034 : if (ATOMtype(getArgType(mb, p, i)) == TYPE_str ||
449 140961711 : isaBatType(getArgType(mb, p, i)) ||
450 42342765 : (!isPolyType(getArgType(mb, p, i)) &&
451 42342753 : getArgType(mb, p, i) < TYPE_any &&
452 42342753 : getArgType(mb, p, i) >= 0 &&
453 42342753 : ATOMstorage(getArgType(mb, p, i)) == TYPE_str)) {
454 135248455 : getInstrPtr(mb, 0)->gc = true;
455 135248455 : 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 57607988 : 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 57607988 : if (polymorphic) {
472 : int cnt = 0;
473 188405261 : for (k = i = p->retc; i < p->argc; i++) {
474 152130365 : int actual = getArgType(mb, p, i);
475 152130365 : if (isAnyExpression(actual))
476 10 : cnt++;
477 : }
478 36274896 : if (cnt == 0 && s->kind != COMMANDsymbol
479 18517121 : && 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 57607985 : if (p->token == ASSIGNsymbol) {
502 57619275 : switch (s->kind) {
503 18464762 : case COMMANDsymbol:
504 18464762 : p->token = CMDcall;
505 18464762 : p->fcn = s->func->imp; /* C implementation mandatory */
506 18464762 : 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 39144227 : case PATTERNsymbol:
516 39144227 : p->token = PATcall;
517 39144227 : p->fcn = s->func->imp; /* C implementation optional */
518 39144227 : break;
519 10286 : case FUNCTIONsymbol:
520 10286 : p->token = FCNcall;
521 10286 : 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 57619274 : p->blk = s->def;
531 : }
532 :
533 57607984 : 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 1158 : wrapup:
543 1162 : 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 68823642 : typeChecker(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
584 : {
585 68823642 : int s1 = -1, i, k;
586 68823642 : Module m = 0;
587 :
588 68823642 : p->typeresolved = false;
589 68823642 : if ((p->fcn || p->blk) && p->token >= FCNcall && p->token <= PATcall) {
590 45274560 : p->token = ASSIGNsymbol;
591 45274560 : p->fcn = NULL;
592 45274560 : p->blk = NULL;
593 : }
594 :
595 68823642 : if (isaSignature(p)) {
596 4268510 : for (k = 0; k < p->argc; k++)
597 2138870 : setVarFixed(mb, getArg(p, k));
598 2132744 : for (k = p->retc; k < p->argc; k++) {
599 3104 : prepostProcess(getArgType(mb, p, k), p, k, mb);
600 : }
601 2129640 : p->typeresolved = true;
602 4265340 : for (k = 0; k < p->retc; k++)
603 2135700 : p->typeresolved &= typeResolved(mb, p, 0);
604 59740240 : return;
605 : }
606 66694002 : if (getFunctionId(p) && getModuleId(p)) {
607 57618561 : m = findModule(scope, getModuleId(p));
608 :
609 57616162 : 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 57615968 : s1 = findFunctionType(m, mb, p, idx, silent);
618 :
619 57610566 : 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 1433 : if (!isaSignature(p) && !getInstrPtr(mb, 0)->polymorphic) {
634 1422 : 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 1422 : p->typeresolved = false;
671 : } else
672 11 : p->typeresolved = true;
673 1433 : 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 9075441 : if (getFunctionId(p)) {
682 : return;
683 : }
684 9075606 : 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 9075599 : p->typeresolved = true;
692 16530480 : for (k = 0, i = p->retc; k < p->retc && i < p->argc; i++, k++) {
693 7454688 : int rhs = getArgType(mb, p, i);
694 7454688 : int lhs = getArgType(mb, p, k);
695 :
696 7454688 : if (rhs != TYPE_void) {
697 7454537 : 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 7454874 : if (!isVarFixed(mb, getArg(p, k))) {
718 3313968 : setVarType(mb, getArg(p, k), rhs);
719 3313968 : setVarFixed(mb, getArg(p, k));
720 : }
721 7454874 : prepostProcess(s1, p, i, mb);
722 7454874 : prepostProcess(s1, p, k, mb);
723 : }
724 : /* the case where we have no rhs */
725 9075792 : if (p->barrier && p->retc == p->argc)
726 510299 : for (k = 0; k < p->retc; k++) {
727 257483 : int tpe = getArgType(mb, p, k);
728 257483 : if (isaBatType(tpe) ||
729 251504 : ATOMtype(tpe) == TYPE_str ||
730 251504 : (!isPolyType(tpe) && tpe < MAXATOMS && ATOMextern(tpe)))
731 5985 : 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 2939684 : chkTypes(Module s, MalBlkPtr mb, int silent)
753 : {
754 2939684 : InstrPtr p = 0;
755 2939684 : int i;
756 2939684 : str msg = MAL_SUCCEED;
757 :
758 166105346 : for (i = 0; mb->errors == NULL && i < mb->stop; i++) {
759 163165888 : p = getInstrPtr(mb, i);
760 163165888 : assert(p != NULL);
761 163165888 : if (!p->typeresolved)
762 67924065 : typeChecker(s, mb, p, i, silent);
763 : }
764 2939458 : if (mb->errors) {
765 34 : msg = mb->errors;
766 34 : mb->errors = NULL;
767 : }
768 2939458 : 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 564602 : chkProgram(Module s, MalBlkPtr mb)
790 : {
791 564602 : 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 564602 : if (mb->errors) {
797 23 : msg = mb->errors;
798 23 : mb->errors = NULL;
799 23 : return msg;
800 : }
801 564579 : msg = chkTypes(s, mb, FALSE);
802 564590 : if (msg == MAL_SUCCEED)
803 564558 : msg = chkFlow(mb);
804 564567 : if (msg == MAL_SUCCEED)
805 564555 : 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 2135700 : typeResolved(MalBlkPtr mb, InstrPtr p, int i)
819 : {
820 2135700 : malType t = getArgType(mb, p, i);
821 2135700 : if (t == TYPE_any || isAnyExpression(t)) {
822 513550 : 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 127822306 : getPolyType(malType t, int *polytype)
834 : {
835 127822306 : int ti;
836 127822306 : malType tail;
837 :
838 127822306 : ti = getTypeIndex(t);
839 127822306 : if (!isaBatType(t) && ti > 0) {
840 14617989 : tail = polytype[ti];
841 14617989 : if (getOptBat(t))
842 385 : setOptBat(tail);
843 14617989 : return tail;
844 : }
845 :
846 113204317 : tail = ti == 0 ? getBatType(t) : polytype[ti];
847 113204317 : if (isaBatType(t)) {
848 110301965 : tail = newBatType(tail);
849 : }
850 113204317 : if (getOptBat(t))
851 12351 : 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 94054380 : updateTypeMap(int formal, int actual, int polytype[MAXTYPEVAR])
866 : {
867 94054380 : int h, t, ret = 0;
868 :
869 94054380 : if (!isAnyExpression(formal) && isaBatType(formal) && isaBatType(actual))
870 : return 0;
871 :
872 47316690 : if ((h = getTypeIndex(formal))) {
873 44955103 : if (isaBatType(actual) && !isaBatType(formal) && !getOptBat(formal) &&
874 3887032 : (polytype[h] == TYPE_any || polytype[h] == actual)) {
875 3210501 : polytype[h] = actual;
876 3210501 : return 0;
877 : }
878 41744602 : t = getBatType(actual);
879 41744602 : if (t != polytype[h]) {
880 25246104 : if (isaBatType(polytype[h]) && isaBatType(actual))
881 : ret = 0;
882 25244820 : else if (polytype[h] == TYPE_any)
883 24881435 : polytype[h] = t;
884 : else {
885 : return -1;
886 : }
887 : }
888 : }
889 43742804 : if (isaBatType(formal)) {
890 31052160 : if (!isaBatType(actual))
891 : return -1;
892 : }
893 : return ret;
894 : }
|