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 199259180 : resolvedType(int dsttype, int srctype)
36 : {
37 199259180 : if (dsttype == srctype || dsttype == TYPE_any || srctype == TYPE_any)
38 : return 0;
39 :
40 124300595 : if (getOptBat(dsttype) && isaBatType(srctype)) {
41 2412 : int t1 = getBatType(dsttype);
42 2412 : int t2 = getBatType(srctype);
43 2412 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
44 : return 0;
45 : }
46 12311 : if (getOptBat(dsttype) && !isaBatType(srctype)) {
47 10378 : int t1 = getBatType(dsttype);
48 10378 : int t2 = srctype;
49 10378 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
50 : return 0;
51 : }
52 :
53 124299962 : if (isaBatType(dsttype) && isaBatType(srctype)) {
54 85542531 : int t1 = getBatType(dsttype);
55 85542531 : int t2 = getBatType(srctype);
56 85542531 : if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
57 48372353 : return 0;
58 : }
59 : return -1;
60 : }
61 :
62 : static int
63 56264863 : resolveType(int *rtype, int dsttype, int srctype)
64 : {
65 56264863 : if (dsttype == srctype) {
66 24070850 : *rtype = dsttype;
67 24070850 : return 0;
68 : }
69 32194013 : if (dsttype == TYPE_any) {
70 3673328 : *rtype = srctype;
71 3673328 : return 0;
72 : }
73 28520685 : if (srctype == TYPE_any) {
74 20151456 : *rtype = dsttype;
75 20151456 : return 0;
76 : }
77 : /*
78 : * A bat reference can be coerced to bat type.
79 : */
80 8369229 : if (isaBatType(dsttype) && isaBatType(srctype)) {
81 8340696 : int t1, t2, t3;
82 8340696 : t1 = getBatType(dsttype);
83 8340696 : t2 = getBatType(srctype);
84 8340696 : if (t1 == t2)
85 : t3 = t1;
86 8340693 : else if (t1 == TYPE_any)
87 : t3 = t2;
88 119229 : else if (t2 == TYPE_any)
89 : t3 = t1;
90 : else {
91 : return -1;
92 : }
93 8221473 : *rtype = newBatType(t3);
94 8221473 : 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 320607285 : getFormalArgType( Symbol s, int arg)
118 : {
119 320607285 : if (s->kind == FUNCTIONsymbol)
120 40925 : return getArgType(s->def, getSignature(s), arg);
121 320566360 : mel_arg *a = s->func->args+arg;
122 320566360 : malType tpe = TYPE_any;
123 320566360 : if (a->nr || !a->type[0]) {
124 120784208 : if (a->isbat)
125 : tpe = newBatType(TYPE_any);
126 : else
127 18463328 : tpe = a->typeid;
128 120784208 : setTypeIndex(tpe, a->nr);
129 : } else {
130 199782152 : if (a->isbat)
131 76197038 : tpe = newBatType(a->typeid);
132 : else
133 123585114 : tpe = a->typeid;
134 : }
135 320566360 : if (a->opt == 1)
136 30729 : setOptBat(tpe);
137 : return tpe;
138 : }
139 :
140 : static malType
141 57121405 : findFunctionType(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
142 : {
143 57121405 : Module m;
144 57121405 : Symbol s;
145 57121405 : int i, k, unmatched = 0, s1;
146 57121405 : int polytype[MAXTYPEVAR];
147 57121405 : int returns[256];
148 57121405 : 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 57121405 : m = scope;
167 57121405 : s = m->space[(int) (getSymbolIndex(getFunctionId(p)))];
168 57121405 : if (s == 0)
169 : return -1;
170 :
171 57121218 : if (p->retc < 256) {
172 117939890 : for (i = 0; i < p->retc; i++)
173 60818712 : returns[i] = 0;
174 57121218 : returntype = returns;
175 : } else {
176 40 : returntype = (int *) GDKzalloc(p->retc * sizeof(int));
177 40 : if (returntype == 0)
178 : return -1;
179 : }
180 :
181 369758787 : while (s != NULL) { /* single scope element check */
182 369757569 : if (getFunctionId(p) != s->name) {
183 109058279 : s = s->skip;
184 109058279 : 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 260699290 : int argc = 0, argcc = 0, retc = 0, varargs = 0, varrets = 0, unsafe = 0, inlineprop = 0, polymorphic = 0;
205 260699290 : 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 260688969 : retc = s->func->retc;
217 260688969 : argc = s->func->argc;
218 260688969 : varargs = /*retc == 0 ||*/ s->func->vargs || s->func->vrets;
219 260688969 : varrets = retc == 0 || s->func->vrets;
220 260688969 : unsafe = s->func->unsafe;
221 260688969 : inlineprop = 0;
222 260688969 : polymorphic = s->func->poly;
223 260688969 : if (!retc && !polymorphic)
224 2318179 : polymorphic = 1;
225 260688969 : argcc = argc + ((retc == 0)?1:0);
226 : }
227 260699290 : 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 260699290 : if (polymorphic) {
242 67873470 : int limit = polymorphic;
243 67873470 : if (!(argcc == p->argc || (argc < p->argc && varargs))) {
244 28943987 : s = s->peer;
245 28943987 : continue;
246 : }
247 38929483 : if (retc != p->retc && !varrets) {
248 324255 : s = s->peer;
249 324255 : continue;
250 : }
251 :
252 109795318 : for (k = 0; k < limit; k++)
253 71190090 : 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 191010775 : for (k = retc; i < p->argc; k++, i++) {
263 155747745 : int actual = getArgType(mb, p, i);
264 155747745 : int formal = getFormalArgType(s, k);
265 155747745 : if (k == argc - 1 && varargs)
266 55278799 : 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 155747745 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
278 155747745 : formal = actual;
279 155747745 : if (formal == actual)
280 63534349 : continue;
281 92213396 : if (updateTypeMap(formal, actual, polytype)) {
282 : unmatched = i;
283 : break;
284 : }
285 90186489 : 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 90186489 : 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 38595712 : if (varargs) {
306 7026062 : if (s->kind != PATTERNsymbol && retc)
307 : unmatched = i;
308 : else {
309 : /* resolve the arguments */
310 7028228 : for (; i < p->argc; i++) {
311 : /* the type of the last one has already been set */
312 1497544 : int actual = getArgType(mb, p, i);
313 1497544 : int formal = getFormalArgType(s, k);
314 1497544 : if (k == argc - 1 && varargs)
315 0 : k--;
316 :
317 1497544 : formal = getPolyType(formal, polytype);
318 1497544 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
319 1497544 : formal = actual;
320 1497544 : if (formal == actual || formal == TYPE_any)
321 1020 : continue;
322 1496524 : 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 192825820 : if (argc != p->argc || retc != p->retc) {
335 97712616 : s = s->peer;
336 97712616 : continue;
337 : }
338 :
339 :
340 129594460 : for (i = p->retc; i < p->argc; i++) {
341 107598975 : int actual = getArgType(mb, p, i);
342 107598975 : int formal = getFormalArgType(s, i);
343 107598975 : 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 133710265 : if (unmatched) {
359 76450681 : s = s->peer;
360 76450681 : 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 57259584 : s1 = 0;
374 57259584 : if (polymorphic) {
375 68784424 : for (k = i = 0; i < p->retc && k < retc; k++, i++) {
376 33526191 : int actual = getArgType(mb, p, i);
377 33526191 : int formal = getFormalArgType(s, k);
378 :
379 33526191 : if (k == retc - 1 && varrets)
380 358830 : k--;
381 :
382 33526191 : s1 = getPolyType(formal, polytype);
383 :
384 33526191 : if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
385 33526191 : s1 = actual;
386 33526191 : if (resolveType(returntype+i, s1, actual) < 0) {
387 : s1 = -1;
388 : break;
389 : }
390 : }
391 : } else {
392 : /* check for non-polymorphic return */
393 44253301 : for (k = i = 0; i < p->retc; i++) {
394 22398028 : int actual = getArgType(mb, p, i);
395 22398028 : int formal = getFormalArgType(s, i);
396 :
397 22398028 : if (k == retc - 1 && varrets)
398 : k--;
399 :
400 22398028 : if (actual == formal) {
401 7316268 : returntype[i] = actual;
402 : } else {
403 15081760 : if (resolveType(returntype+i, formal, actual) < 0) {
404 : s1 = -1;
405 : break;
406 : }
407 : }
408 : }
409 : }
410 57261257 : if (s1 < 0) {
411 147751 : s = s->peer;
412 147751 : 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 57113506 : p->typeresolved = true;
425 57113506 : p->inlineProp = inlineprop;
426 57113506 : p->unsafeProp = unsafe;
427 117944628 : for (i = 0; i < p->retc; i++) {
428 60831122 : int ts = returntype[i];
429 60831122 : 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 60831122 : if (!isVarFixed(mb, getArg(p, i)) && ts >= 0) {
438 32096527 : setVarType(mb, getArg(p, i), ts);
439 32096527 : setVarFixed(mb, getArg(p, i));
440 : }
441 60831122 : prepostProcess(ts, p, i, mb);
442 : }
443 : /*
444 : * Also the arguments may contain constants
445 : * to be garbage collected.
446 : */
447 232945737 : for (i = p->retc; i < p->argc; i++)
448 175832231 : if (ATOMtype(getArgType(mb, p, i)) == TYPE_str ||
449 138641903 : isaBatType(getArgType(mb, p, i)) ||
450 41911364 : (!isPolyType(getArgType(mb, p, i)) &&
451 41911352 : getArgType(mb, p, i) < TYPE_any &&
452 41911352 : getArgType(mb, p, i) >= 0 &&
453 41911352 : ATOMstorage(getArgType(mb, p, i)) == TYPE_str)) {
454 133923961 : getInstrPtr(mb, 0)->gc = true;
455 133923961 : 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 57113506 : 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 57113506 : if (polymorphic) {
472 : int cnt = 0;
473 184413175 : for (k = i = p->retc; i < p->argc; i++) {
474 149151857 : int actual = getArgType(mb, p, i);
475 149151857 : if (isAnyExpression(actual))
476 10 : cnt++;
477 : }
478 35261318 : if (cnt == 0 && s->kind != COMMANDsymbol
479 18199222 : && 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 57113503 : if (p->token == ASSIGNsymbol) {
502 57120289 : switch (s->kind) {
503 17750012 : case COMMANDsymbol:
504 17750012 : p->token = CMDcall;
505 17750012 : p->fcn = s->func->imp; /* C implementation mandatory */
506 17750012 : 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 39359991 : case PATTERNsymbol:
516 39359991 : p->token = PATcall;
517 39359991 : p->fcn = s->func->imp; /* C implementation optional */
518 39359991 : 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 57120288 : p->blk = s->def;
531 : }
532 :
533 57113502 : 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 1218 : wrapup:
543 1222 : 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 68628950 : typeChecker(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
584 : {
585 68628950 : int s1 = -1, i, k;
586 68628950 : Module m = 0;
587 :
588 68628950 : p->typeresolved = false;
589 68628950 : if ((p->fcn || p->blk) && p->token >= FCNcall && p->token <= PATcall) {
590 44719746 : p->token = ASSIGNsymbol;
591 44719746 : p->fcn = NULL;
592 44719746 : p->blk = NULL;
593 : }
594 :
595 68628950 : if (isaSignature(p)) {
596 4423203 : for (k = 0; k < p->argc; k++)
597 2216214 : setVarFixed(mb, getArg(p, k));
598 2210093 : for (k = p->retc; k < p->argc; k++) {
599 3104 : prepostProcess(getArgType(mb, p, k), p, k, mb);
600 : }
601 2206989 : p->typeresolved = true;
602 4420081 : for (k = 0; k < p->retc; k++)
603 2213092 : p->typeresolved &= typeResolved(mb, p, 0);
604 59322282 : return;
605 : }
606 66421961 : if (getFunctionId(p) && getModuleId(p)) {
607 57120971 : m = findModule(scope, getModuleId(p));
608 :
609 57118299 : 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 57118115 : s1 = findFunctionType(m, mb, p, idx, silent);
618 :
619 57115162 : 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 1409 : if (!isaSignature(p) && !getInstrPtr(mb, 0)->polymorphic) {
634 1398 : 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 1398 : p->typeresolved = false;
671 : } else
672 11 : p->typeresolved = true;
673 1409 : 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 9300990 : if (getFunctionId(p)) {
682 : return;
683 : }
684 9301048 : 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 9301041 : p->typeresolved = true;
692 16949379 : for (k = 0, i = p->retc; k < p->retc && i < p->argc; i++, k++) {
693 7648172 : int rhs = getArgType(mb, p, i);
694 7648172 : int lhs = getArgType(mb, p, k);
695 :
696 7648172 : if (rhs != TYPE_void) {
697 7648021 : 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 7648331 : if (!isVarFixed(mb, getArg(p, k))) {
718 3396713 : setVarType(mb, getArg(p, k), rhs);
719 3396713 : setVarFixed(mb, getArg(p, k));
720 : }
721 7648331 : prepostProcess(s1, p, i, mb);
722 7648331 : prepostProcess(s1, p, k, mb);
723 : }
724 : /* the case where we have no rhs */
725 9301207 : if (p->barrier && p->retc == p->argc)
726 529259 : for (k = 0; k < p->retc; k++) {
727 266841 : int tpe = getArgType(mb, p, k);
728 266841 : if (isaBatType(tpe) ||
729 261096 : ATOMtype(tpe) == TYPE_str ||
730 261096 : (!isPolyType(tpe) && tpe < MAXATOMS && ATOMextern(tpe)))
731 5751 : 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 2992948 : chkTypes(Module s, MalBlkPtr mb, int silent)
753 : {
754 2992948 : InstrPtr p = 0;
755 2992948 : int i;
756 2992948 : str msg = MAL_SUCCEED;
757 :
758 165563899 : for (i = 0; mb->errors == NULL && i < mb->stop; i++) {
759 162571112 : p = getInstrPtr(mb, i);
760 162571112 : assert(p != NULL);
761 162571112 : if (!p->typeresolved)
762 67628908 : typeChecker(s, mb, p, i, silent);
763 : }
764 2992787 : if (mb->errors) {
765 34 : msg = mb->errors;
766 34 : mb->errors = NULL;
767 : }
768 2992787 : 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 575932 : chkProgram(Module s, MalBlkPtr mb)
790 : {
791 575932 : 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 575932 : if (mb->errors) {
797 23 : msg = mb->errors;
798 23 : mb->errors = NULL;
799 23 : return msg;
800 : }
801 575909 : msg = chkTypes(s, mb, FALSE);
802 575915 : if (msg == MAL_SUCCEED)
803 575880 : msg = chkFlow(mb);
804 575876 : if (msg == MAL_SUCCEED)
805 575864 : 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 2213092 : typeResolved(MalBlkPtr mb, InstrPtr p, int i)
819 : {
820 2213092 : malType t = getArgType(mb, p, i);
821 2213092 : if (t == TYPE_any || isAnyExpression(t)) {
822 556021 : 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 125214908 : getPolyType(malType t, int *polytype)
834 : {
835 125214908 : int ti;
836 125214908 : malType tail;
837 :
838 125214908 : ti = getTypeIndex(t);
839 125214908 : if (!isaBatType(t) && ti > 0) {
840 13942369 : tail = polytype[ti];
841 13942369 : if (getOptBat(t))
842 385 : setOptBat(tail);
843 13942369 : return tail;
844 : }
845 :
846 111272539 : tail = ti == 0 ? getBatType(t) : polytype[ti];
847 111272539 : if (isaBatType(t)) {
848 108348745 : tail = newBatType(tail);
849 : }
850 111272539 : if (getOptBat(t))
851 12417 : setOptBat(tail);
852 : return tail;
853 : }
854 :
855 : /*
856 : * Each argument is checked for binding of polymorphic arguments.
857 : * This routine assumes that the type index is indeed smaller than maxarg.
858 : * (The parser currently enforces a single digit from 1-2 )
859 : * The polymorphic type 'any', i.e. any_0, does never constraint an operation
860 : * it can match with all polymorphic types.
861 : * The routine returns the instantiated formal type for subsequent
862 : * type resolution.
863 : */
864 : static int
865 92219649 : updateTypeMap(int formal, int actual, int polytype[MAXTYPEVAR])
866 : {
867 92219649 : int h, t, ret = 0;
868 :
869 92219649 : if (!isAnyExpression(formal) && isaBatType(formal) && isaBatType(actual))
870 : return 0;
871 :
872 45925865 : if ((h = getTypeIndex(formal))) {
873 43559253 : if (isaBatType(actual) && !isaBatType(formal) && !getOptBat(formal) &&
874 3500382 : (polytype[h] == TYPE_any || polytype[h] == actual)) {
875 2842441 : polytype[h] = actual;
876 2842441 : return 0;
877 : }
878 40716812 : t = getBatType(actual);
879 40716812 : if (t != polytype[h]) {
880 24574512 : if (isaBatType(polytype[h]) && isaBatType(actual))
881 : ret = 0;
882 24573228 : else if (polytype[h] == TYPE_any)
883 24213883 : polytype[h] = t;
884 : else {
885 : return -1;
886 : }
887 : }
888 : }
889 42724079 : if (isaBatType(formal)) {
890 30333090 : if (!isaBatType(actual))
891 : return -1;
892 : }
893 : return ret;
894 : }
|