LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_resolve.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 355 368 96.5 %
Date: 2024-10-07 21:21:43 Functions: 11 11 100.0 %

          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             : }

Generated by: LCOV version 1.14