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 302223458 : resolvedType(int dsttype, int srctype)
36 : {
37 302223458 : if (dsttype == srctype || dsttype == TYPE_any || srctype == TYPE_any)
38 : return 0;
39 :
40 207818786 : if (getOptBat(dsttype) && isaBatType(srctype)) {
41 2376 : int t1 = getBatType(dsttype);
42 2376 : int t2 = getBatType(srctype);
43 2376 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
44 : return 0;
45 : }
46 12143 : if (getOptBat(dsttype) && !isaBatType(srctype)) {
47 10210 : int t1 = getBatType(dsttype);
48 10210 : int t2 = srctype;
49 10210 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
50 : return 0;
51 : }
52 :
53 207818189 : if (isaBatType(dsttype) && isaBatType(srctype)) {
54 150983759 : int t1 = getBatType(dsttype);
55 150983759 : int t2 = getBatType(srctype);
56 150983759 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
57 92747420 : return 0;
58 : }
59 : return -1;
60 : }
61 :
62 : static int
63 69109556 : resolveType(int *rtype, int dsttype, int srctype)
64 : {
65 69109556 : if (dsttype == srctype) {
66 32190297 : *rtype = dsttype;
67 32190297 : return 0;
68 : }
69 36919259 : if (dsttype == TYPE_any) {
70 3661094 : *rtype = srctype;
71 3661094 : return 0;
72 : }
73 33258165 : if (srctype == TYPE_any) {
74 20072857 : *rtype = dsttype;
75 20072857 : return 0;
76 : }
77 : /*
78 : * A bat reference can be coerced to bat type.
79 : */
80 13185308 : if (isaBatType(dsttype) && isaBatType(srctype)) {
81 13156619 : int t1, t2, t3;
82 13156619 : t1 = getBatType(dsttype);
83 13156619 : t2 = getBatType(srctype);
84 13156619 : if (t1 == t2)
85 : t3 = t1;
86 13156616 : else if (t1 == TYPE_any)
87 : t3 = t2;
88 174296 : else if (t2 == TYPE_any)
89 : t3 = t1;
90 : else {
91 : return -1;
92 : }
93 12982329 : *rtype = newBatType(t3);
94 12982329 : 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 459645505 : getFormalArgType( Symbol s, int arg)
118 : {
119 459645505 : if (s->kind == FUNCTIONsymbol)
120 41194 : return getArgType(s->def, getSignature(s), arg);
121 459604311 : mel_arg *a = s->func->args+arg;
122 459604311 : malType tpe = TYPE_any;
123 459604311 : if (a->nr || !a->type[0]) {
124 188696008 : if (a->isbat)
125 : tpe = newBatType(TYPE_any);
126 : else
127 21209910 : tpe = a->typeid;
128 188696008 : setTypeIndex(tpe, a->nr);
129 : } else {
130 270908303 : if (a->isbat)
131 110753542 : tpe = newBatType(a->typeid);
132 : else
133 160154761 : tpe = a->typeid;
134 : }
135 459604311 : if (a->opt == 1)
136 30093 : setOptBat(tpe);
137 : return tpe;
138 : }
139 :
140 : static malType
141 71051320 : findFunctionType(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
142 : {
143 71051320 : Module m;
144 71051320 : Symbol s;
145 71051320 : int i, k, unmatched = 0, s1;
146 71051320 : int polytype[MAXTYPEVAR];
147 71051320 : int returns[256];
148 71051320 : 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 71051320 : m = scope;
167 71051320 : s = m->space[(int) (getSymbolIndex(getFunctionId(p)))];
168 71051320 : if (s == 0)
169 : return -1;
170 :
171 71051133 : if (p->retc < 256) {
172 146934999 : for (i = 0; i < p->retc; i++)
173 75883906 : returns[i] = 0;
174 71051133 : returntype = returns;
175 : } else {
176 40 : returntype = (int *) GDKzalloc(p->retc * sizeof(int));
177 40 : if (returntype == 0)
178 : return -1;
179 : }
180 :
181 487122300 : while (s != NULL) { /* single scope element check */
182 487121091 : if (getFunctionId(p) != s->name) {
183 122576042 : s = s->skip;
184 122576042 : 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 364545049 : int argc = 0, argcc = 0, retc = 0, varargs = 0, varrets = 0, unsafe = 0, inlineprop = 0, polymorphic = 0;
205 364545049 : if (s->kind == FUNCTIONsymbol) {
206 10322 : InstrPtr sig = getSignature(s);
207 10322 : retc = sig->retc;
208 10322 : argc = sig->argc;
209 10322 : varargs = (sig->varargs & (VARARGS | VARRETS));
210 10322 : varrets = (sig->varargs & VARRETS);
211 10322 : unsafe = s->def->unsafeProp;
212 10322 : inlineprop = s->def->inlineProp;
213 10322 : polymorphic = sig->polymorphic;
214 10322 : argcc = argc;
215 : } else {
216 364534727 : retc = s->func->retc;
217 364534727 : argc = s->func->argc;
218 364534727 : varargs = /*retc == 0 ||*/ s->func->vargs || s->func->vrets;
219 364534727 : varrets = retc == 0 || s->func->vrets;
220 364534727 : unsafe = s->func->unsafe;
221 364534727 : inlineprop = 0;
222 364534727 : polymorphic = s->func->poly;
223 364534727 : if (!retc && !polymorphic)
224 2308418 : polymorphic = 1;
225 364534727 : argcc = argc + ((retc == 0)?1:0);
226 : }
227 364545049 : 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 364545049 : if (polymorphic) {
242 87944649 : int limit = polymorphic;
243 87944649 : if (!(argcc == p->argc || (argc < p->argc && varargs))) {
244 35621402 : s = s->peer;
245 35621402 : continue;
246 : }
247 52323247 : if (retc != p->retc && !varrets) {
248 418928 : s = s->peer;
249 418928 : continue;
250 : }
251 :
252 147427926 : for (k = 0; k < limit; k++)
253 95523607 : 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 284245642 : for (k = retc; i < p->argc; k++, i++) {
263 235774626 : int actual = getArgType(mb, p, i);
264 235774626 : int formal = getFormalArgType(s, k);
265 235774626 : if (k == argc - 1 && varargs)
266 99797453 : 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 235774626 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
278 235774626 : formal = actual;
279 235774626 : if (formal == actual)
280 86184252 : continue;
281 149590374 : if (updateTypeMap(formal, actual, polytype)) {
282 : unmatched = i;
283 : break;
284 : }
285 147502971 : 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 147502971 : 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 51891545 : if (varargs) {
306 9473712 : if (s->kind != PATTERNsymbol && retc)
307 : unmatched = i;
308 : else {
309 : /* resolve the arguments */
310 9477988 : for (; i < p->argc; i++) {
311 : /* the type of the last one has already been set */
312 1493800 : int actual = getArgType(mb, p, i);
313 1493800 : int formal = getFormalArgType(s, k);
314 1493800 : if (k == argc - 1 && varargs)
315 0 : k--;
316 :
317 1493800 : formal = getPolyType(formal, polytype);
318 1493800 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
319 1493800 : formal = actual;
320 1493800 : if (formal == actual || formal == TYPE_any)
321 1020 : continue;
322 1492780 : 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 276600400 : if (argc != p->argc || retc != p->retc) {
335 141596778 : s = s->peer;
336 141596778 : continue;
337 : }
338 :
339 :
340 176084651 : for (i = p->retc; i < p->argc; i++) {
341 153316427 : int actual = getArgType(mb, p, i);
342 153316427 : int formal = getFormalArgType(s, i);
343 153316427 : 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 186897222 : if (unmatched) {
359 115655043 : s = s->peer;
360 115655043 : 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 71242179 : s1 = 0;
374 71242179 : if (polymorphic) {
375 94751055 : for (k = i = 0; i < p->retc && k < retc; k++, i++) {
376 46272781 : int actual = getArgType(mb, p, i);
377 46272781 : int formal = getFormalArgType(s, k);
378 :
379 46272781 : if (k == retc - 1 && varrets)
380 357193 : k--;
381 :
382 46272781 : s1 = getPolyType(formal, polytype);
383 :
384 46272781 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
385 46272781 : s1 = actual;
386 46272781 : if (resolveType(returntype+i, s1, actual) < 0) {
387 : s1 = -1;
388 : break;
389 : }
390 : }
391 : } else {
392 : /* check for non-polymorphic return */
393 45760147 : for (k = i = 0; i < p->retc; i++) {
394 23180783 : int actual = getArgType(mb, p, i);
395 23180783 : int formal = getFormalArgType(s, i);
396 :
397 23180783 : if (k == retc - 1 && varrets)
398 : k--;
399 :
400 23180783 : if (actual == formal) {
401 8100184 : returntype[i] = actual;
402 : } else {
403 15080599 : if (resolveType(returntype+i, formal, actual) < 0) {
404 : s1 = -1;
405 : break;
406 : }
407 : }
408 : }
409 : }
410 71260612 : if (s1 < 0) {
411 202974 : s = s->peer;
412 202974 : 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 71057638 : p->typeresolved = true;
425 71057638 : p->inlineProp = inlineprop;
426 71057638 : p->unsafeProp = unsafe;
427 146953618 : for (i = 0; i < p->retc; i++) {
428 75895980 : int ts = returntype[i];
429 75895980 : 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 75895980 : if (!isVarFixed(mb, getArg(p, i)) && ts >= 0) {
438 39340706 : setVarType(mb, getArg(p, i), ts);
439 39340706 : setVarFixed(mb, getArg(p, i));
440 : }
441 75895980 : prepostProcess(ts, p, i, mb);
442 : }
443 : /*
444 : * Also the arguments may contain constants
445 : * to be garbage collected.
446 : */
447 329421192 : for (i = p->retc; i < p->argc; i++)
448 258363554 : if (ATOMtype(getArgType(mb, p, i)) == TYPE_str ||
449 213543096 : isaBatType(getArgType(mb, p, i)) ||
450 54261569 : (!isPolyType(getArgType(mb, p, i)) &&
451 54261557 : getArgType(mb, p, i) < TYPE_any &&
452 54261557 : getArgType(mb, p, i) >= 0 &&
453 54261557 : ATOMstorage(getArgType(mb, p, i)) == TYPE_str)) {
454 204105473 : getInstrPtr(mb, 0)->gc = true;
455 204105473 : 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 71057638 : 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 71057638 : if (polymorphic) {
472 : int cnt = 0;
473 277583125 : for (k = i = p->retc; i < p->argc; i++) {
474 229093406 : int actual = getArgType(mb, p, i);
475 229093406 : if (isAnyExpression(actual))
476 10 : cnt++;
477 : }
478 48489719 : if (cnt == 0 && s->kind != COMMANDsymbol
479 26078457 : && 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 71057635 : if (p->token == ASSIGNsymbol) {
502 71068958 : switch (s->kind) {
503 23202124 : case COMMANDsymbol:
504 23202124 : p->token = CMDcall;
505 23202124 : p->fcn = s->func->imp; /* C implementation mandatory */
506 23202124 : 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 47856541 : case PATTERNsymbol:
516 47856541 : p->token = PATcall;
517 47856541 : p->fcn = s->func->imp; /* C implementation optional */
518 47856541 : break;
519 10293 : case FUNCTIONsymbol:
520 10293 : p->token = FCNcall;
521 10293 : 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 71068957 : p->blk = s->def;
531 : }
532 :
533 71057634 : 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 1209 : wrapup:
543 1213 : 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 82638902 : typeChecker(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
584 : {
585 82638902 : int s1 = -1, i, k;
586 82638902 : Module m = 0;
587 :
588 82638902 : p->typeresolved = false;
589 82638902 : if ((p->fcn || p->blk) && p->token >= FCNcall && p->token <= PATcall) {
590 57129567 : p->token = ASSIGNsymbol;
591 57129567 : p->fcn = NULL;
592 57129567 : p->blk = NULL;
593 : }
594 :
595 82638902 : if (isaSignature(p)) {
596 4409365 : for (k = 0; k < p->argc; k++)
597 2209025 : setVarFixed(mb, getArg(p, k));
598 2203432 : for (k = p->retc; k < p->argc; k++) {
599 3092 : prepostProcess(getArgType(mb, p, k), p, k, mb);
600 : }
601 2200340 : p->typeresolved = true;
602 4406269 : for (k = 0; k < p->retc; k++)
603 2205929 : p->typeresolved &= typeResolved(mb, p, 0);
604 73260689 : return;
605 : }
606 80438562 : if (getFunctionId(p) && getModuleId(p)) {
607 71044886 : m = findModule(scope, getModuleId(p));
608 :
609 71057989 : if (!m || strcmp(m->name, getModuleId(p)) != 0) {
610 184 : 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 184 : return;
616 : }
617 71057805 : s1 = findFunctionType(m, mb, p, idx, silent);
618 :
619 71060153 : 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 1400 : if (!isaSignature(p) && !getInstrPtr(mb, 0)->polymorphic) {
634 1389 : 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 1389 : p->typeresolved = false;
671 : } else
672 11 : p->typeresolved = true;
673 1400 : 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 9393676 : if (getFunctionId(p)) {
682 : return;
683 : }
684 9393669 : 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 9393662 : p->typeresolved = true;
692 17145815 : for (k = 0, i = p->retc; k < p->retc && i < p->argc; i++, k++) {
693 7749902 : int rhs = getArgType(mb, p, i);
694 7749902 : int lhs = getArgType(mb, p, k);
695 :
696 7749902 : if (rhs != TYPE_void) {
697 7749751 : 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 7752146 : if (!isVarFixed(mb, getArg(p, k))) {
718 3425777 : setVarType(mb, getArg(p, k), rhs);
719 3425777 : setVarFixed(mb, getArg(p, k));
720 : }
721 7752146 : prepostProcess(s1, p, i, mb);
722 7752146 : prepostProcess(s1, p, k, mb);
723 : }
724 : /* the case where we have no rhs */
725 9395913 : if (p->barrier && p->retc == p->argc)
726 536973 : for (k = 0; k < p->retc; k++) {
727 272368 : int tpe = getArgType(mb, p, k);
728 272368 : if (isaBatType(tpe) ||
729 263193 : ATOMtype(tpe) == TYPE_str ||
730 263193 : (!isPolyType(tpe) && tpe < MAXATOMS && ATOMextern(tpe)))
731 9181 : 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 2977772 : chkTypes(Module s, MalBlkPtr mb, int silent)
753 : {
754 2977772 : InstrPtr p = 0;
755 2977772 : int i;
756 2977772 : str msg = MAL_SUCCEED;
757 :
758 191758757 : for (i = 0; mb->errors == NULL && i < mb->stop; i++) {
759 188779002 : p = getInstrPtr(mb, i);
760 188779002 : assert(p != NULL);
761 188779002 : if (!p->typeresolved)
762 80857767 : typeChecker(s, mb, p, i, silent);
763 : }
764 2979755 : if (mb->errors) {
765 34 : msg = mb->errors;
766 34 : mb->errors = NULL;
767 : }
768 2979755 : 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 14 : chkInstruction(Module s, MalBlkPtr mb, InstrPtr p)
777 : {
778 14 : if (mb->errors == MAL_SUCCEED) {
779 14 : p->typeresolved = false;
780 14 : typeChecker(s, mb, p, getPC(mb, p), TRUE);
781 : }
782 14 : return mb->errors != MAL_SUCCEED;
783 : }
784 :
785 : /*
786 : * Perform silent check on the program, merely setting the error flag.
787 : */
788 : str
789 572607 : chkProgram(Module s, MalBlkPtr mb)
790 : {
791 572607 : 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 572607 : if (mb->errors) {
797 23 : msg = mb->errors;
798 23 : mb->errors = NULL;
799 23 : return msg;
800 : }
801 572584 : msg = chkTypes(s, mb, FALSE);
802 573978 : if (msg == MAL_SUCCEED)
803 573962 : msg = chkFlow(mb);
804 572719 : if (msg == MAL_SUCCEED)
805 572886 : 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 2205929 : typeResolved(MalBlkPtr mb, InstrPtr p, int i)
819 : {
820 2205929 : malType t = getArgType(mb, p, i);
821 2205929 : if (t == TYPE_any || isAnyExpression(t)) {
822 555502 : 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 195272845 : getPolyType(malType t, int *polytype)
834 : {
835 195272845 : int ti;
836 195272845 : malType tail;
837 :
838 195272845 : ti = getTypeIndex(t);
839 195272845 : if (!isaBatType(t) && ti > 0) {
840 16192706 : tail = polytype[ti];
841 16192706 : if (getOptBat(t))
842 367 : setOptBat(tail);
843 16192706 : return tail;
844 : }
845 :
846 179080139 : tail = ti == 0 ? getBatType(t) : polytype[ti];
847 179080139 : if (isaBatType(t)) {
848 176151419 : tail = newBatType(tail);
849 : }
850 179080139 : if (getOptBat(t))
851 12231 : 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 149609435 : updateTypeMap(int formal, int actual, int polytype[MAXTYPEVAR])
866 : {
867 149609435 : int h, t, ret = 0;
868 :
869 149609435 : if (!isAnyExpression(formal) && isaBatType(formal) && isaBatType(actual))
870 : return 0;
871 :
872 59909438 : if ((h = getTypeIndex(formal))) {
873 57558456 : if (isaBatType(actual) && !isaBatType(formal) && !getOptBat(formal) &&
874 5210676 : (polytype[h] == TYPE_any || polytype[h] == actual)) {
875 4481577 : polytype[h] = actual;
876 4481577 : return 0;
877 : }
878 53076879 : t = getBatType(actual);
879 53076879 : if (t != polytype[h]) {
880 31755315 : if (isaBatType(polytype[h]) && isaBatType(actual))
881 : ret = 0;
882 31753973 : else if (polytype[h] == TYPE_any)
883 31329263 : polytype[h] = t;
884 : else {
885 : return -1;
886 : }
887 : }
888 : }
889 55003151 : if (isaBatType(formal)) {
890 42013522 : if (!isaBatType(actual))
891 : return -1;
892 : }
893 : return ret;
894 : }
|