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 287936201 : resolvedType(int dsttype, int srctype)
36 : {
37 287936201 : if (dsttype == srctype || dsttype == TYPE_any || srctype == TYPE_any)
38 : return 0;
39 :
40 198859190 : if (getOptBat(dsttype) && isaBatType(srctype)) {
41 2394 : int t1 = getBatType(dsttype);
42 2394 : int t2 = getBatType(srctype);
43 2394 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
44 : return 0;
45 : }
46 12275 : if (getOptBat(dsttype) && !isaBatType(srctype)) {
47 10351 : int t1 = getBatType(dsttype);
48 10351 : int t2 = srctype;
49 10351 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
50 : return 0;
51 : }
52 :
53 198858575 : if (isaBatType(dsttype) && isaBatType(srctype)) {
54 145597584 : int t1 = getBatType(dsttype);
55 145597584 : int t2 = getBatType(srctype);
56 145597584 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
57 91435091 : return 0;
58 : }
59 : return -1;
60 : }
61 :
62 : static int
63 65255472 : resolveType(int *rtype, int dsttype, int srctype)
64 : {
65 65255472 : if (dsttype == srctype) {
66 30064916 : *rtype = dsttype;
67 30064916 : return 0;
68 : }
69 35190556 : if (dsttype == TYPE_any) {
70 3336108 : *rtype = srctype;
71 3336108 : return 0;
72 : }
73 31854448 : if (srctype == TYPE_any) {
74 19193207 : *rtype = dsttype;
75 19193207 : return 0;
76 : }
77 : /*
78 : * A bat reference can be coerced to bat type.
79 : */
80 12661241 : if (isaBatType(dsttype) && isaBatType(srctype)) {
81 12632067 : int t1, t2, t3;
82 12632067 : t1 = getBatType(dsttype);
83 12632067 : t2 = getBatType(srctype);
84 12632067 : if (t1 == t2)
85 : t3 = t1;
86 12632064 : else if (t1 == TYPE_any)
87 : t3 = t2;
88 171006 : else if (t2 == TYPE_any)
89 : t3 = t1;
90 : else {
91 : return -1;
92 : }
93 12461067 : *rtype = newBatType(t3);
94 12461067 : 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 437514693 : getFormalArgType( Symbol s, int arg)
118 : {
119 437514693 : if (s->kind == FUNCTIONsymbol)
120 39169 : return getArgType(s->def, getSignature(s), arg);
121 437475524 : mel_arg *a = s->func->args+arg;
122 437475524 : malType tpe = TYPE_any;
123 437475524 : if (a->nr || !a->type[0]) {
124 180703934 : if (a->isbat)
125 : tpe = newBatType(TYPE_any);
126 : else
127 18826217 : tpe = a->typeid;
128 180703934 : setTypeIndex(tpe, a->nr);
129 : } else {
130 256771590 : if (a->isbat)
131 104167064 : tpe = newBatType(a->typeid);
132 : else
133 152604526 : tpe = a->typeid;
134 : }
135 437475524 : if (a->opt == 1)
136 30520 : setOptBat(tpe);
137 : return tpe;
138 : }
139 :
140 : static malType
141 67466783 : findFunctionType(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
142 : {
143 67466783 : Module m;
144 67466783 : Symbol s;
145 67466783 : int i, k, unmatched = 0, s1;
146 67466783 : int polytype[MAXTYPEVAR];
147 67466783 : int returns[256];
148 67466783 : 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 67466783 : m = scope;
167 67466783 : s = m->space[(int) (getSymbolIndex(getFunctionId(p)))];
168 67466783 : if (s == 0)
169 : return -1;
170 :
171 67466570 : if (p->retc < 256) {
172 139463541 : for (i = 0; i < p->retc; i++)
173 71997011 : returns[i] = 0;
174 67466570 : returntype = returns;
175 : } else {
176 40 : returntype = (int *) GDKzalloc(p->retc * sizeof(int));
177 40 : if (returntype == 0)
178 : return -1;
179 : }
180 :
181 451366891 : while (s != NULL) { /* single scope element check */
182 451366218 : if (getFunctionId(p) != s->name) {
183 117702224 : s = s->skip;
184 117702224 : 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 333663994 : int argc = 0, argcc = 0, retc = 0, varargs = 0, varrets = 0, unsafe = 0, inlineprop = 0, polymorphic = 0;
205 333663994 : if (s->kind == FUNCTIONsymbol) {
206 9747 : InstrPtr sig = getSignature(s);
207 9747 : retc = sig->retc;
208 9747 : argc = sig->argc;
209 9747 : varargs = (sig->varargs & (VARARGS | VARRETS));
210 9747 : varrets = (sig->varargs & VARRETS);
211 9747 : unsafe = s->def->unsafeProp;
212 9747 : inlineprop = s->def->inlineProp;
213 9747 : polymorphic = sig->polymorphic;
214 9747 : argcc = argc;
215 : } else {
216 333654247 : retc = s->func->retc;
217 333654247 : argc = s->func->argc;
218 333654247 : varargs = /*retc == 0 ||*/ s->func->vargs || s->func->vrets;
219 333654247 : varrets = retc == 0 || s->func->vrets;
220 333654247 : unsafe = s->func->unsafe;
221 333654247 : inlineprop = 0;
222 333654247 : polymorphic = s->func->poly;
223 333654247 : if (!retc && !polymorphic)
224 2237825 : polymorphic = 1;
225 333654247 : argcc = argc + ((retc == 0)?1:0);
226 : }
227 333663994 : 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 333663994 : if (polymorphic) {
242 83955573 : int limit = polymorphic;
243 83955573 : if (!(argcc == p->argc || (argc < p->argc && varargs))) {
244 34426099 : s = s->peer;
245 34426099 : continue;
246 : }
247 49529474 : if (retc != p->retc && !varrets) {
248 411998 : s = s->peer;
249 411998 : continue;
250 : }
251 :
252 139168749 : for (k = 0; k < limit; k++)
253 90051273 : 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 272103030 : for (k = retc; i < p->argc; k++, i++) {
263 226373080 : int actual = getArgType(mb, p, i);
264 226373080 : int formal = getFormalArgType(s, k);
265 226373080 : if (k == argc - 1 && varargs)
266 97781775 : 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 226373080 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
278 226373080 : formal = actual;
279 226373080 : if (formal == actual)
280 81900889 : continue;
281 144472191 : if (updateTypeMap(formal, actual, polytype)) {
282 : unmatched = i;
283 : break;
284 : }
285 142416581 : 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 142416581 : 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 49106027 : if (varargs) {
306 9174807 : if (s->kind != PATTERNsymbol && retc)
307 : unmatched = i;
308 : else {
309 : /* resolve the arguments */
310 9178313 : for (; i < p->argc; i++) {
311 : /* the type of the last one has already been set */
312 1427328 : int actual = getArgType(mb, p, i);
313 1427328 : int formal = getFormalArgType(s, k);
314 1427328 : if (k == argc - 1 && varargs)
315 0 : k--;
316 :
317 1427328 : formal = getPolyType(formal, polytype);
318 1427328 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
319 1427328 : formal = actual;
320 1427328 : if (formal == actual || formal == TYPE_any)
321 1008 : continue;
322 1426320 : 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 249708421 : if (argc != p->argc || retc != p->retc) {
335 123116013 : s = s->peer;
336 123116013 : continue;
337 : }
338 :
339 :
340 166106354 : for (i = p->retc; i < p->argc; i++) {
341 144183170 : int actual = getArgType(mb, p, i);
342 144183170 : int formal = getFormalArgType(s, i);
343 144183170 : 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 175699278 : if (unmatched) {
359 108043817 : s = s->peer;
360 108043817 : 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 67655461 : s1 = 0;
374 67655461 : if (polymorphic) {
375 89380270 : for (k = i = 0; i < p->retc && k < retc; k++, i++) {
376 43640879 : int actual = getArgType(mb, p, i);
377 43640879 : int formal = getFormalArgType(s, k);
378 :
379 43640879 : if (k == retc - 1 && varrets)
380 323189 : k--;
381 :
382 43640879 : s1 = getPolyType(formal, polytype);
383 :
384 43640879 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
385 43640879 : s1 = actual;
386 43640879 : if (resolveType(returntype+i, s1, actual) < 0) {
387 : s1 = -1;
388 : break;
389 : }
390 : }
391 : } else {
392 : /* check for non-polymorphic return */
393 44049642 : for (k = i = 0; i < p->retc; i++) {
394 22315998 : int actual = getArgType(mb, p, i);
395 22315998 : int formal = getFormalArgType(s, i);
396 :
397 22315998 : if (k == retc - 1 && varrets)
398 : k--;
399 :
400 22315998 : if (actual == formal) {
401 7789431 : returntype[i] = actual;
402 : } else {
403 14526567 : if (resolveType(returntype+i, formal, actual) < 0) {
404 : s1 = -1;
405 : break;
406 : }
407 : }
408 : }
409 : }
410 67673205 : if (s1 < 0) {
411 200170 : s = s->peer;
412 200170 : 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 67473035 : p->typeresolved = true;
425 67473035 : p->inlineProp = inlineprop;
426 67473035 : p->unsafeProp = unsafe;
427 139477545 : for (i = 0; i < p->retc; i++) {
428 72004510 : int ts = returntype[i];
429 72004510 : 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 72004510 : if (!isVarFixed(mb, getArg(p, i)) && ts >= 0) {
438 37453979 : setVarType(mb, getArg(p, i), ts);
439 37453979 : setVarFixed(mb, getArg(p, i));
440 : }
441 72004510 : prepostProcess(ts, p, i, mb);
442 : }
443 : /*
444 : * Also the arguments may contain constants
445 : * to be garbage collected.
446 : */
447 315543302 : for (i = p->retc; i < p->argc; i++)
448 248070267 : if (ATOMtype(getArgType(mb, p, i)) == TYPE_str ||
449 205628541 : isaBatType(getArgType(mb, p, i)) ||
450 51301493 : (!isPolyType(getArgType(mb, p, i)) &&
451 51301464 : getArgType(mb, p, i) < TYPE_any &&
452 51301464 : getArgType(mb, p, i) >= 0 &&
453 51301464 : ATOMstorage(getArgType(mb, p, i)) == TYPE_str)) {
454 196772328 : getInstrPtr(mb, 0)->gc = true;
455 196772328 : 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 67473035 : 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 67473035 : if (polymorphic) {
472 : int cnt = 0;
473 265429468 : for (k = i = p->retc; i < p->argc; i++) {
474 219675456 : int actual = getArgType(mb, p, i);
475 219675456 : if (isAnyExpression(actual))
476 10 : cnt++;
477 : }
478 45754012 : if (cnt == 0 && s->kind != COMMANDsymbol
479 24471431 : && 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 previousely 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 67473032 : if (p->token == ASSIGNsymbol) {
502 67486841 : switch (s->kind) {
503 22065541 : case COMMANDsymbol:
504 22065541 : p->token = CMDcall;
505 22065541 : p->fcn = s->func->imp; /* C implementation mandatory */
506 22065541 : 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 45411592 : case PATTERNsymbol:
516 45411592 : p->token = PATcall;
517 45411592 : p->fcn = s->func->imp; /* C implementation optional */
518 45411592 : break;
519 9708 : case FUNCTIONsymbol:
520 9708 : p->token = FCNcall;
521 9708 : 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 67486840 : p->blk = s->def;
531 : }
532 :
533 67473031 : 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 673 : wrapup:
543 677 : 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 78268704 : typeChecker(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
584 : {
585 78268704 : int s1 = -1, i, k;
586 78268704 : Module m = 0;
587 :
588 78268704 : p->typeresolved = false;
589 78268704 : if ((p->fcn || p->blk) && p->token >= FCNcall && p->token <= PATcall) {
590 54408019 : p->token = ASSIGNsymbol;
591 54408019 : p->fcn = NULL;
592 54408019 : p->blk = NULL;
593 : }
594 :
595 78268704 : if (isaSignature(p)) {
596 4291280 : for (k = 0; k < p->argc; k++)
597 2149886 : setVarFixed(mb, getArg(p, k));
598 2144397 : for (k = p->retc; k < p->argc; k++) {
599 3003 : prepostProcess(getArgType(mb, p, k), p, k, mb);
600 : }
601 2141394 : p->typeresolved = true;
602 4288147 : for (k = 0; k < p->retc; k++)
603 2146753 : p->typeresolved &= typeResolved(mb, p, 0);
604 69615793 : return;
605 : }
606 76127310 : if (getFunctionId(p) && getModuleId(p)) {
607 67461390 : m = findModule(scope, getModuleId(p));
608 :
609 67476409 : if (!m || strcmp(m->name, getModuleId(p)) != 0) {
610 178 : 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 178 : return;
616 : }
617 67476231 : s1 = findFunctionType(m, mb, p, idx, silent);
618 :
619 67474283 : if (s1 >= 0)
620 : return;
621 : /*
622 : * Could not find a function that statisfies 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 890 : if (!isaSignature(p) && !getInstrPtr(mb, 0)->polymorphic) {
634 879 : if (!silent) {
635 34 : char *errsig = NULL;
636 34 : 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 34 : bool free_errsig = false, special_undefined = false;
647 34 : errsig = malLibraryHowToEnable(p->modname);
648 34 : if (!strcmp(errsig, "")) {
649 34 : errsig = instruction2str(mb, 0, p,
650 : (LIST_MAL_NAME | LIST_MAL_TYPE
651 : | LIST_MAL_VALUE));
652 34 : free_errsig = true;
653 : } else {
654 : special_undefined = true;
655 : }
656 102 : mb->errors = createMalException(mb, idx, TYPE,
657 : "'%s%s%s' undefined%s: %s",
658 : (getModuleId(p) ?
659 : getModuleId(p) : ""),
660 34 : (getModuleId(p) ? "." : ""),
661 : getFunctionId(p),
662 : special_undefined ? "" :
663 : " in",
664 : errsig ? errsig :
665 : "failed instruction2str()");
666 34 : if (free_errsig)
667 34 : GDKfree(errsig);
668 : }
669 : }
670 879 : p->typeresolved = false;
671 : } else
672 11 : p->typeresolved = true;
673 890 : 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 8665920 : if (getFunctionId(p)) {
682 : return;
683 : }
684 8665987 : 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 8665980 : p->typeresolved = true;
692 15744920 : for (k = 0, i = p->retc; k < p->retc && i < p->argc; i++, k++) {
693 7076432 : int rhs = getArgType(mb, p, i);
694 7076432 : int lhs = getArgType(mb, p, k);
695 :
696 7076432 : if (rhs != TYPE_void) {
697 7076285 : 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 147 : 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 7078933 : if (!isVarFixed(mb, getArg(p, k))) {
718 3114050 : setVarType(mb, getArg(p, k), rhs);
719 3114050 : setVarFixed(mb, getArg(p, k));
720 : }
721 7078933 : prepostProcess(s1, p, i, mb);
722 7078933 : prepostProcess(s1, p, k, mb);
723 : }
724 : /* the case where we have no rhs */
725 8668488 : if (p->barrier && p->retc == p->argc)
726 494220 : for (k = 0; k < p->retc; k++) {
727 247807 : int tpe = getArgType(mb, p, k);
728 247807 : if (isaBatType(tpe) ||
729 244974 : ATOMtype(tpe) == TYPE_str ||
730 244974 : (!isPolyType(tpe) && tpe < MAXATOMS && ATOMextern(tpe)))
731 2839 : 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 2884378 : chkTypes(Module s, MalBlkPtr mb, int silent)
753 : {
754 2884378 : InstrPtr p = 0;
755 2884378 : int i;
756 2884378 : str msg = MAL_SUCCEED;
757 :
758 180664989 : for (i = 0; mb->errors == NULL && i < mb->stop; i++) {
759 177778376 : p = getInstrPtr(mb, i);
760 177778376 : assert(p != NULL);
761 177778376 : if (!p->typeresolved)
762 76619369 : typeChecker(s, mb, p, i, silent);
763 : }
764 2886613 : if (mb->errors) {
765 47 : msg = mb->errors;
766 47 : mb->errors = NULL;
767 : }
768 2886613 : 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 11 : chkInstruction(Module s, MalBlkPtr mb, InstrPtr p)
777 : {
778 11 : if (mb->errors == MAL_SUCCEED) {
779 11 : p->typeresolved = false;
780 11 : typeChecker(s, mb, p, getPC(mb, p), TRUE);
781 : }
782 11 : return mb->errors != MAL_SUCCEED;
783 : }
784 :
785 : /*
786 : * Perform silent check on the program, merely setting the error flag.
787 : */
788 : str
789 556738 : chkProgram(Module s, MalBlkPtr mb)
790 : {
791 556738 : 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 556738 : if (mb->errors) {
797 23 : msg = mb->errors;
798 23 : mb->errors = NULL;
799 23 : return msg;
800 : }
801 556715 : msg = chkTypes(s, mb, FALSE);
802 558101 : if (msg == MAL_SUCCEED)
803 558067 : msg = chkFlow(mb);
804 557049 : if (msg == MAL_SUCCEED)
805 557151 : 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 occuring 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 2146753 : typeResolved(MalBlkPtr mb, InstrPtr p, int i)
819 : {
820 2146753 : malType t = getArgType(mb, p, i);
821 2146753 : if (t == TYPE_any || isAnyExpression(t)) {
822 545009 : 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 187486644 : getPolyType(malType t, int *polytype)
834 : {
835 187486644 : int ti;
836 187486644 : malType tail;
837 :
838 187486644 : ti = getTypeIndex(t);
839 187486644 : if (!isaBatType(t) && ti > 0) {
840 14353710 : tail = polytype[ti];
841 14353710 : if (getOptBat(t))
842 376 : setOptBat(tail);
843 14353710 : return tail;
844 : }
845 :
846 173132934 : tail = ti == 0 ? getBatType(t) : polytype[ti];
847 173132934 : if (isaBatType(t)) {
848 170463153 : tail = newBatType(tail);
849 : }
850 173132934 : if (getOptBat(t))
851 12381 : 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 instanciated formal type for subsequent
862 : * type resolution.
863 : */
864 : static int
865 144492350 : updateTypeMap(int formal, int actual, int polytype[MAXTYPEVAR])
866 : {
867 144492350 : int h, t, ret = 0;
868 :
869 144492350 : if (!isAnyExpression(formal) && isaBatType(formal) && isaBatType(actual))
870 : return 0;
871 :
872 55581077 : if ((h = getTypeIndex(formal))) {
873 53318997 : if (isaBatType(actual) && !isaBatType(formal) && !getOptBat(formal) &&
874 4943373 : (polytype[h] == TYPE_any || polytype[h] == actual)) {
875 4129654 : polytype[h] = actual;
876 4129654 : return 0;
877 : }
878 49189343 : t = getBatType(actual);
879 49189343 : if (t != polytype[h]) {
880 29814922 : if (isaBatType(polytype[h]) && isaBatType(actual))
881 : ret = 0;
882 29813599 : else if (polytype[h] == TYPE_any)
883 29428713 : polytype[h] = t;
884 : else {
885 : return -1;
886 : }
887 : }
888 : }
889 51066537 : if (isaBatType(formal)) {
890 39680517 : if (!isaBatType(actual))
891 : return -1;
892 : }
893 : return ret;
894 : }
|