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-04-26 00:35:57 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   287936201 : resolvedType(int dsttype, int srctype)
      36             : {
      37   287936201 :         if (dsttype == srctype || dsttype == TYPE_any || srctype == TYPE_any)
      38             :                 return 0;
      39             : 
      40   198859190 :         if (getOptBat(dsttype) && isaBatType(srctype)) {
      41        2394 :                 int t1 = getBatType(dsttype);
      42        2394 :                 int t2 = getBatType(srctype);
      43        2394 :                 if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
      44             :                         return 0;
      45             :         }
      46       12275 :         if (getOptBat(dsttype) && !isaBatType(srctype)) {
      47       10351 :                 int t1 = getBatType(dsttype);
      48       10351 :                 int t2 = srctype;
      49       10351 :                 if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
      50             :                         return 0;
      51             :         }
      52             : 
      53   198858575 :         if (isaBatType(dsttype) && isaBatType(srctype)) {
      54   145597584 :                 int t1 = getBatType(dsttype);
      55   145597584 :                 int t2 = getBatType(srctype);
      56   145597584 :                 if (t1 == t2 || t1 == TYPE_any || t2 == TYPE_any)
      57    91435091 :                         return 0;
      58             :         }
      59             :         return -1;
      60             : }
      61             : 
      62             : static int
      63    65255472 : resolveType(int *rtype, int dsttype, int srctype)
      64             : {
      65    65255472 :         if (dsttype == srctype) {
      66    30064916 :                 *rtype = dsttype;
      67    30064916 :                 return 0;
      68             :         }
      69    35190556 :         if (dsttype == TYPE_any) {
      70     3336108 :                 *rtype = srctype;
      71     3336108 :                 return 0;
      72             :         }
      73    31854448 :         if (srctype == TYPE_any) {
      74    19193207 :                 *rtype = dsttype;
      75    19193207 :                 return 0;
      76             :         }
      77             :         /*
      78             :          * A bat reference can be coerced to bat type.
      79             :          */
      80    12661241 :         if (isaBatType(dsttype) && isaBatType(srctype)) {
      81    12632067 :                 int t1, t2, t3;
      82    12632067 :                 t1 = getBatType(dsttype);
      83    12632067 :                 t2 = getBatType(srctype);
      84    12632067 :                 if (t1 == t2)
      85             :                         t3 = t1;
      86    12632064 :                 else if (t1 == TYPE_any)
      87             :                         t3 = t2;
      88      171006 :                 else if (t2 == TYPE_any)
      89             :                         t3 = t1;
      90             :                 else {
      91             :                         return -1;
      92             :                 }
      93    12461067 :                 *rtype = newBatType(t3);
      94    12461067 :                 return 0;
      95             :         }
      96             :         return -1;
      97             : }
      98             : 
      99             : 
     100             : /*
     101             :  * Since we now know the storage type of the receiving variable, we can
     102             :  * set the garbage collection flag.
     103             :  */
     104             : #define prepostProcess(tp, p, b, mb)                                    \
     105             :         do {                                                                                            \
     106             :                 if( isaBatType(tp) ||                                                   \
     107             :                         ATOMtype(tp) == TYPE_str ||                                     \
     108             :                         (!isPolyType(tp) && tp < TYPE_any &&         \
     109             :                          tp >= 0 && ATOMextern(tp))) {                               \
     110             :                         getInstrPtr(mb, 0)->gc = true;                               \
     111             :                         setVarCleanup(mb, getArg(p, b));                        \
     112             :                         p->gc = true;                                                                \
     113             :                 }                                                                                               \
     114             :         } while (0)
     115             : 
     116             : static malType
     117   437514693 : getFormalArgType( Symbol s, int arg)
     118             : {
     119   437514693 :         if (s->kind == FUNCTIONsymbol)
     120       39169 :                 return getArgType(s->def, getSignature(s), arg);
     121   437475524 :         mel_arg *a = s->func->args+arg;
     122   437475524 :         malType tpe = TYPE_any;
     123   437475524 :         if (a->nr || !a->type[0]) {
     124   180703934 :                 if (a->isbat)
     125             :                         tpe = newBatType(TYPE_any);
     126             :                 else
     127    18826217 :                         tpe = a->typeid;
     128   180703934 :                 setTypeIndex(tpe, a->nr);
     129             :         } else {
     130   256771590 :                 if (a->isbat)
     131   104167064 :                         tpe = newBatType(a->typeid);
     132             :                 else
     133   152604526 :                         tpe = a->typeid;
     134             :         }
     135   437475524 :         if (a->opt == 1)
     136       30520 :                 setOptBat(tpe);
     137             :         return tpe;
     138             : }
     139             : 
     140             : static malType
     141    67466783 : findFunctionType(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
     142             : {
     143    67466783 :         Module m;
     144    67466783 :         Symbol s;
     145    67466783 :         int i, k, unmatched = 0, s1;
     146    67466783 :         int polytype[MAXTYPEVAR];
     147    67466783 :         int returns[256];
     148    67466783 :         int *returntype = NULL;
     149             :         /*
     150             :          * Within a module find the element in its list
     151             :          * of symbols. A skiplist is used to speed up the search for the
     152             :          * definition of the function.
     153             :          *
     154             :          * For the implementation we should be aware that over 90% of the
     155             :          * functions in the kernel have just a few arguments and a single
     156             :          * return value.
     157             :          * A point of concern is that polymorphic arithmetic operations
     158             :          * lead to an explosion in the symbol table. This increase the
     159             :          * loop to find a candidate.
     160             :          *
     161             :          * Consider to collect the argument type into a separate structure, because
     162             :          * it will be looked up multiple types to resolve the instruction.[todo]
     163             :          * Simplify polytype using a map into the concrete argument table.
     164             :          */
     165             : 
     166    67466783 :         m = scope;
     167    67466783 :         s = m->space[(int) (getSymbolIndex(getFunctionId(p)))];
     168    67466783 :         if (s == 0)
     169             :                 return -1;
     170             : 
     171    67466570 :         if (p->retc < 256) {
     172   139463541 :                 for (i = 0; i < p->retc; i++)
     173    71997011 :                         returns[i] = 0;
     174    67466570 :                 returntype = returns;
     175             :         } else {
     176          40 :                 returntype = (int *) GDKzalloc(p->retc * sizeof(int));
     177          40 :                 if (returntype == 0)
     178             :                         return -1;
     179             :         }
     180             : 
     181   451366891 :         while (s != NULL) {                     /* single scope element check */
     182   451366218 :                 if (getFunctionId(p) != s->name) {
     183   117702224 :                         s = s->skip;
     184   117702224 :                         continue;
     185             :                 }
     186             :                 /*
     187             :                  * Perform a strong type-check on the actual arguments. If it
     188             :                  * turns out to be a polymorphic MAL function, we have to
     189             :                  * clone it.  Provided the actual/formal parameters are
     190             :                  * compliant throughout the function call.
     191             :                  *
     192             :                  * Also look out for variable argument lists. This means that
     193             :                  * we have to keep two iterators, one for the caller (i) and
     194             :                  * one for the callee (k). Since a variable argument only
     195             :                  * occurs as the last one, we simple avoid an increment when
     196             :                  * running out of formal arguments.
     197             :                  *
     198             :                  * A call of the form (X1,..., Xi) := f(Y1,....,Yn) can be
     199             :                  * matched against the function signature (B1,...,Bk):=
     200             :                  * f(A1,...,Am) where i==k , n<=m and
     201             :                  * type(Ai)=type(Yi). Furthermore, the variables Xi obtain
     202             :                  * their type from Bi (or type(Bi)==type(Xi)).
     203             :                  */
     204   333663994 :                 int argc = 0, argcc = 0, retc = 0, varargs = 0, varrets = 0, unsafe = 0, inlineprop = 0, polymorphic = 0;
     205   333663994 :                 if (s->kind == FUNCTIONsymbol) {
     206        9747 :                         InstrPtr sig = getSignature(s);
     207        9747 :                         retc = sig->retc;
     208        9747 :                         argc = sig->argc;
     209        9747 :                         varargs = (sig->varargs & (VARARGS | VARRETS));
     210        9747 :                         varrets = (sig->varargs & VARRETS);
     211        9747 :                         unsafe = s->def->unsafeProp;
     212        9747 :                         inlineprop = s->def->inlineProp;
     213        9747 :                         polymorphic = sig->polymorphic;
     214        9747 :                         argcc = argc;
     215             :                 } else {
     216   333654247 :                         retc = s->func->retc;
     217   333654247 :                         argc = s->func->argc;
     218   333654247 :                         varargs = /*retc == 0 ||*/ s->func->vargs || s->func->vrets;
     219   333654247 :                         varrets = retc == 0 || s->func->vrets;
     220   333654247 :                         unsafe = s->func->unsafe;
     221   333654247 :                         inlineprop = 0;
     222   333654247 :                         polymorphic = s->func->poly;
     223   333654247 :                         if (!retc && !polymorphic)
     224     2237825 :                                 polymorphic = 1;
     225   333654247 :                         argcc = argc + ((retc == 0)?1:0);
     226             :                 }
     227   333663994 :                 unmatched = 0;
     228             : 
     229             :                 /*
     230             :                  * The simple case could be taken care of separately to
     231             :                  * speedup processing
     232             :                  * However, it turned out not to make a big difference.  The
     233             :                  * first time we encounter a polymorphic argument in the
     234             :                  * signature.
     235             :                  * Subsequently, the polymorphic arguments update this table
     236             :                  * and check for any type mismatches that might occur.  There
     237             :                  * are at most 2 type variables involved per argument due to
     238             :                  * the limited type nesting permitted.  Note, each function
     239             :                  * returns at least one value.
     240             :                  */
     241   333663994 :                 if (polymorphic) {
     242    83955573 :                         int limit = polymorphic;
     243    83955573 :                         if (!(argcc == p->argc || (argc < p->argc && varargs))) {
     244    34426099 :                                 s = s->peer;
     245    34426099 :                                 continue;
     246             :                         }
     247    49529474 :                         if (retc != p->retc && !varrets) {
     248      411998 :                                 s = s->peer;
     249      411998 :                                 continue;
     250             :                         }
     251             : 
     252   139168749 :                         for (k = 0; k < limit; k++)
     253    90051273 :                                 polytype[k] = TYPE_any;
     254             :                         /*
     255             :                          * Most polymorphic functions don't have a variable argument
     256             :                          * list. So we save some instructions factoring this caise out.
     257             :                          * Be careful, the variable number of return arguments should
     258             :                          * be considered as well.
     259             :                          */
     260             :                         i = p->retc;
     261             :                         /* first handle the variable argument list */
     262   272103030 :                         for (k = retc; i < p->argc; k++, i++) {
     263   226373080 :                                 int actual = getArgType(mb, p, i);
     264   226373080 :                                 int formal = getFormalArgType(s, k);
     265   226373080 :                                 if (k == argc - 1 && varargs)
     266    97781775 :                                         k--;
     267             :                                 /*
     268             :                                  * Take care of variable argument lists.
     269             :                                  * They are allowed as the last in the signature only.
     270             :                                  * Furthermore, for patterns if the formal type is
     271             :                                  * 'any' then all remaining arguments are acceptable
     272             :                                  * and detailed type analysis becomes part of the
     273             :                                  * pattern implementation.
     274             :                                  * In all other cases the type should apply to all
     275             :                                  * remaining arguments.
     276             :                                  */
     277   226373080 :                                 if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
     278   226373080 :                                         formal = actual;
     279   226373080 :                                 if (formal == actual)
     280    81900889 :                                         continue;
     281   144472191 :                                 if (updateTypeMap(formal, actual, polytype)) {
     282             :                                         unmatched = i;
     283             :                                         break;
     284             :                                 }
     285   142416581 :                                 formal = getPolyType(formal, polytype);
     286             :                                 /*
     287             :                                  * Collect the polymorphic types and resolve them.
     288             :                                  * If it fails, we know this isn't the function we are
     289             :                                  * looking for.
     290             :                                  */
     291   142416581 :                                 if (resolvedType(formal, actual) < 0) {
     292             :                                         unmatched = i;
     293             :                                         break;
     294             :                                 }
     295             :                         }
     296             :                         /*
     297             :                          * The last argument/result type could be a polymorphic
     298             :                          * variable list.  It should only be allowed for patterns,
     299             :                          * where it can deal with the stack.  If the type is
     300             :                          * specified as :any then any mix of arguments is allowed.
     301             :                          * If the type is a new numbered type variable then the
     302             :                          * first element in the list determines the required type
     303             :                          * of all.
     304             :                          */
     305    49106027 :                         if (varargs) {
     306     9174807 :                                 if (s->kind != PATTERNsymbol && retc)
     307             :                                         unmatched = i;
     308             :                                 else {
     309             :                                         /* resolve the arguments */
     310     9178313 :                                         for (; i < p->argc; i++) {
     311             :                                                 /* the type of the last one has already been set */
     312     1427328 :                                                 int actual = getArgType(mb, p, i);
     313     1427328 :                                                 int formal = getFormalArgType(s, k);
     314     1427328 :                                                 if (k == argc - 1 && varargs)
     315           0 :                                                         k--;
     316             : 
     317     1427328 :                                                 formal = getPolyType(formal, polytype);
     318     1427328 :                                                 if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
     319     1427328 :                                                         formal = actual;
     320     1427328 :                                                 if (formal == actual || formal == TYPE_any)
     321        1008 :                                                         continue;
     322     1426320 :                                                 if (resolvedType(formal, actual) < 0) {
     323             :                                                         unmatched = i;
     324             :                                                         break;
     325             :                                                 }
     326             :                                         }
     327             :                                 }
     328             :                         }
     329             :                 } else {
     330             :                         /*
     331             :                          * We have to check the argument types to determine a
     332             :                          * possible match for the non-polymorphic case.
     333             :                          */
     334   249708421 :                         if (argc != p->argc || retc != p->retc) {
     335   123116013 :                                 s = s->peer;
     336   123116013 :                                 continue;
     337             :                         }
     338             : 
     339             : 
     340   166106354 :                         for (i = p->retc; i < p->argc; i++) {
     341   144183170 :                                 int actual = getArgType(mb, p, i);
     342   144183170 :                                 int formal = getFormalArgType(s, i);
     343   144183170 :                                 if (resolvedType(formal, actual) < 0) {
     344             :                                         unmatched = i;
     345             :                                         break;
     346             :                                 }
     347             :                         }
     348             :                 }
     349             :                 /*
     350             :                  * It is possible that you may have to coerce the value to
     351             :                  * another type.  We assume that coercions are explicit at the
     352             :                  * MAL level. (e.g. var2:= var0:int). This avoids repeated
     353             :                  * type analysis just before you execute a function.
     354             :                  * An optimizer may at a later stage automatically insert such
     355             :                  * coercion requests.
     356             :                  */
     357             : 
     358   175699278 :                 if (unmatched) {
     359   108043817 :                         s = s->peer;
     360   108043817 :                         continue;
     361             :                 }
     362             :                 /*
     363             :                  * At this stage we know all arguments are type compatible
     364             :                  * with the signature.
     365             :                  * We should assure that also the target variables have the
     366             :                  * proper types or can inherit them from the signature. The
     367             :                  * result type vector should be build separately first,
     368             :                  * because we may encounter an error later on.
     369             :                  *
     370             :                  * If any of the arguments refer to a constraint type, any_x,
     371             :                  * then the resulting type can not be determined.
     372             :                  */
     373    67655461 :                 s1 = 0;
     374    67655461 :                 if (polymorphic) {
     375    89380270 :                         for (k = i = 0; i < p->retc && k < retc; k++, i++) {
     376    43640879 :                                 int actual = getArgType(mb, p, i);
     377    43640879 :                                 int formal = getFormalArgType(s, k);
     378             : 
     379    43640879 :                                 if (k == retc - 1 && varrets)
     380      323189 :                                         k--;
     381             : 
     382    43640879 :                                 s1 = getPolyType(formal, polytype);
     383             : 
     384    43640879 :                                 if (getOptBat(formal) && !isAnyExpression(formal) && getBatType(actual) == getBatType(formal))
     385    43640879 :                                         s1 = actual;
     386    43640879 :                                 if (resolveType(returntype+i, s1, actual) < 0) {
     387             :                                         s1 = -1;
     388             :                                         break;
     389             :                                 }
     390             :                         }
     391             :                 } else {
     392             :                         /* check for non-polymorphic return */
     393    44049642 :                         for (k = i = 0; i < p->retc; i++) {
     394    22315998 :                                 int actual = getArgType(mb, p, i);
     395    22315998 :                                 int formal = getFormalArgType(s, i);
     396             : 
     397    22315998 :                                 if (k == retc - 1 && varrets)
     398             :                                         k--;
     399             : 
     400    22315998 :                                 if (actual == formal) {
     401     7789431 :                                         returntype[i] = actual;
     402             :                                 } else {
     403    14526567 :                                         if (resolveType(returntype+i, formal, actual) < 0) {
     404             :                                                 s1 = -1;
     405             :                                                 break;
     406             :                                         }
     407             :                                 }
     408             :                         }
     409             :                 }
     410    67673205 :                 if (s1 < 0) {
     411      200170 :                         s = s->peer;
     412      200170 :                         continue;
     413             :                 }
     414             :                 /*
     415             :                  * If the return types are correct, copy them in place.
     416             :                  * Beware that signatures should be left untouched, which
     417             :                  * means that we may not overwrite any formal argument.
     418             :                  * Using the knowledge dat the arguments occupy the header
     419             :                  * of the symbol stack, it is easy to filter such errors.
     420             :                  * Also mark all variables that are subject to garbage control.
     421             :                  * Beware, this is not yet effectuated in the interpreter.
     422             :                  */
     423             : 
     424    67473035 :                 p->typeresolved = true;
     425    67473035 :                 p->inlineProp = inlineprop;
     426    67473035 :                 p->unsafeProp = unsafe;
     427   139477545 :                 for (i = 0; i < p->retc; i++) {
     428    72004510 :                         int ts = returntype[i];
     429    72004510 :                         if (isVarConstant(mb, getArg(p, i))) {
     430           0 :                                 if (!silent) {
     431           0 :                                         mb->errors = createMalException(mb, idx, TYPE,
     432             :                                                                                                         "Assignment to constant");
     433             :                                 }
     434           0 :                                 p->typeresolved = false;
     435           0 :                                 goto wrapup;
     436             :                         }
     437    72004510 :                         if (!isVarFixed(mb, getArg(p, i)) && ts >= 0) {
     438    37453979 :                                 setVarType(mb, getArg(p, i), ts);
     439    37453979 :                                 setVarFixed(mb, getArg(p, i));
     440             :                         }
     441    72004510 :                         prepostProcess(ts, p, i, mb);
     442             :                 }
     443             :                 /*
     444             :                  * Also the arguments may contain constants
     445             :                  * to be garbage collected.
     446             :                  */
     447   315543302 :                 for (i = p->retc; i < p->argc; i++)
     448   248070267 :                         if (ATOMtype(getArgType(mb, p, i)) == TYPE_str ||
     449   205628541 :                                 isaBatType(getArgType(mb, p, i)) ||
     450    51301493 :                                 (!isPolyType(getArgType(mb, p, i)) &&
     451    51301464 :                                  getArgType(mb, p, i) < TYPE_any &&
     452    51301464 :                                  getArgType(mb, p, i) >= 0 &&
     453    51301464 :                                  ATOMstorage(getArgType(mb, p, i)) == TYPE_str)) {
     454   196772328 :                                 getInstrPtr(mb, 0)->gc = true;
     455   196772328 :                                 p->gc = true;
     456             :                         }
     457             :                 /*
     458             :                  * It may happen that an argument was still untyped and as a
     459             :                  * result of the polymorphism matching became strongly
     460             :                  * typed. This should be reflected in the symbol table.
     461             :                  */
     462    67473035 :                 s1 = returntype[0];             /* for those interested */
     463             :                 /*
     464             :                  * If the call refers to a polymorphic function, we clone it
     465             :                  * to arrive at a bounded instance. Polymorphic patterns and
     466             :                  * commands are responsible for type resolution themselves.
     467             :                  * Note that cloning pre-supposes that the function being
     468             :                  * cloned does not contain errors detected earlier in the
     469             :                  * process, nor does it contain polymorphic actual arguments.
     470             :                  */
     471    67473035 :                 if (polymorphic) {
     472             :                         int cnt = 0;
     473   265429468 :                         for (k = i = p->retc; i < p->argc; i++) {
     474   219675456 :                                 int actual = getArgType(mb, p, i);
     475   219675456 :                                 if (isAnyExpression(actual))
     476          10 :                                         cnt++;
     477             :                         }
     478    45754012 :                         if (cnt == 0 && s->kind != COMMANDsymbol
     479    24471431 :                                 && s->kind != PATTERNsymbol) {
     480          11 :                                 assert(s->kind == FUNCTIONsymbol);
     481          11 :                                 s = cloneFunction(scope, s, mb, p);
     482          11 :                                 if (mb->errors)
     483           3 :                                         goto wrapup;
     484             :                         }
     485             :                 }
     486             :                 /* Any previousely found error in the block
     487             :                  * turns the complete block into erroneous.
     488             :                  if (mb->errors) {
     489             :                  p->typeresolved = false;
     490             :                  goto wrapup;
     491             :                  }
     492             :                  */
     493             : 
     494             :                 /*
     495             :                  * We found the proper function. Copy some properties. In
     496             :                  * particular, determine the calling strategy, i.e. FCNcall,
     497             :                  * CMDcall, PATcall Beware that polymorphic functions
     498             :                  * may produce type-incorrect clones.  This piece of code may be
     499             :                  * shared by the separate binder
     500             :                  */
     501    67473032 :                 if (p->token == ASSIGNsymbol) {
     502    67486841 :                         switch (s->kind) {
     503    22065541 :                         case COMMANDsymbol:
     504    22065541 :                                 p->token = CMDcall;
     505    22065541 :                                 p->fcn = s->func->imp;                         /* C implementation mandatory */
     506    22065541 :                                 if (p->fcn == NULL) {
     507           1 :                                         if (!silent)
     508           1 :                                                 mb->errors = createMalException(mb, idx, TYPE,
     509             :                                                                                                                 "object code for command %s.%s missing",
     510             :                                                                                                                 p->modname, p->fcnname);
     511           1 :                                         p->typeresolved = false;
     512           1 :                                         goto wrapup;
     513             :                                 }
     514             :                                 break;
     515    45411592 :                         case PATTERNsymbol:
     516    45411592 :                                 p->token = PATcall;
     517    45411592 :                                 p->fcn = s->func->imp;                         /* C implementation optional */
     518    45411592 :                                 break;
     519        9708 :                         case FUNCTIONsymbol:
     520        9708 :                                 p->token = FCNcall;
     521        9708 :                                 if (getSignature(s)->fcn)
     522           0 :                                         p->fcn = getSignature(s)->fcn;    /* C implementation optional */
     523             :                                 break;
     524           0 :                         default:
     525           0 :                                 if (!silent)
     526           0 :                                         mb->errors = createMalException(mb, idx, MAL,
     527             :                                                                                                         "MALresolve: unexpected token type");
     528           0 :                                 goto wrapup;
     529             :                         }
     530    67486840 :                         p->blk = s->def;
     531             :                 }
     532             : 
     533    67473031 :                 if (returntype != returns)
     534          40 :                         GDKfree(returntype);
     535             :                 return s1;
     536             :         }                                                       /* while */
     537             :         /*
     538             :          * We haven't found the correct function.  To ease debugging, we
     539             :          * may reveal that we found an instruction with the proper
     540             :          * arguments, but that clashes with one of the target variables.
     541             :          */
     542         673 :   wrapup:
     543         677 :         if (returntype != returns)
     544           0 :                 GDKfree(returntype);
     545             :         return -3;
     546             : }
     547             : 
     548             : /*
     549             :  * We try to clear the type check flag by looking up the
     550             :  * functions. Errors are simply ignored at this point of the game,
     551             :  * because they may be resolved as part of the calling sequence.
     552             :  */
     553             : static void
     554           5 : typeMismatch(MalBlkPtr mb, InstrPtr p, int idx, int lhs, int rhs, int silent)
     555             : {
     556           5 :         str n1;
     557           5 :         str n2;
     558             : 
     559           5 :         if (!silent) {
     560           5 :                 n1 = getTypeName(lhs);
     561           5 :                 n2 = getTypeName(rhs);
     562           5 :                 mb->errors = createMalException(mb, idx, TYPE, "type mismatch %s := %s", n1,
     563             :                                                                                 n2);
     564           5 :                 GDKfree(n1);
     565           5 :                 GDKfree(n2);
     566             :         }
     567           5 :         p->typeresolved = false;
     568           5 : }
     569             : 
     570             : /*
     571             :  * A function search should inspect all modules unless a specific module
     572             :  * is given. Preference is given to the lower scopes.
     573             :  * The type check is set to TYPE_UNKNOWN first to enforce a proper
     574             :  * analysis. This way it forms a cheap mechanism to resolve
     575             :  * the type after a change by an optimizer.
     576             :  * If we can not find the function, the type check returns unsuccessfully.
     577             :  * In this case we should issue an error message to the user.
     578             :  *
     579             :  * A re-check after the optimizer call should reset the token
     580             :  * to assignment.
     581             :  */
     582             : void
     583    78268704 : typeChecker(Module scope, MalBlkPtr mb, InstrPtr p, int idx, int silent)
     584             : {
     585    78268704 :         int s1 = -1, i, k;
     586    78268704 :         Module m = 0;
     587             : 
     588    78268704 :         p->typeresolved = false;
     589    78268704 :         if ((p->fcn || p->blk) && p->token >= FCNcall && p->token <= PATcall) {
     590    54408019 :                 p->token = ASSIGNsymbol;
     591    54408019 :                 p->fcn = NULL;
     592    54408019 :                 p->blk = NULL;
     593             :         }
     594             : 
     595    78268704 :         if (isaSignature(p)) {
     596     4291280 :                 for (k = 0; k < p->argc; k++)
     597     2149886 :                         setVarFixed(mb, getArg(p, k));
     598     2144397 :                 for (k = p->retc; k < p->argc; k++) {
     599        3003 :                         prepostProcess(getArgType(mb, p, k), p, k, mb);
     600             :                 }
     601     2141394 :                 p->typeresolved = true;
     602     4288147 :                 for (k = 0; k < p->retc; k++)
     603     2146753 :                         p->typeresolved &= typeResolved(mb, p, 0);
     604    69615793 :                 return;
     605             :         }
     606    76127310 :         if (getFunctionId(p) && getModuleId(p)) {
     607    67461390 :                 m = findModule(scope, getModuleId(p));
     608             : 
     609    67476409 :                 if (!m || strcmp(m->name, getModuleId(p)) != 0) {
     610         178 :                         if (!silent)
     611           2 :                                 mb->errors = createMalException(mb, idx, TYPE, "'%s%s%s' undefined",
     612             :                                         (getModuleId(p) ?  getModuleId(p) : ""),
     613           1 :                                         (getModuleId(p) ? "." : ""),
     614             :                                         getFunctionId(p));
     615         178 :                         return;
     616             :                 }
     617    67476231 :                 s1 = findFunctionType(m, mb, p, idx, silent);
     618             : 
     619    67474283 :                 if (s1 >= 0)
     620             :                         return;
     621             :                 /*
     622             :                  * Could not find a function that statisfies the constraints.
     623             :                  * If the instruction is just a function header we may
     624             :                  * continue.  Likewise, the function and module may refer to
     625             :                  * string variables known only at runtime.
     626             :                  *
     627             :                  * In all other cases we should generate a message, but only
     628             :                  * if we know that the error was not caused by checking the
     629             :                  * definition of a polymorphic function or the module or
     630             :                  * function name are variables, In those cases, the detailed
     631             :                  * analysis is performed upon an actual call.
     632             :                  */
     633         890 :                 if (!isaSignature(p) && !getInstrPtr(mb, 0)->polymorphic) {
     634         879 :                         if (!silent) {
     635          34 :                                 char *errsig = NULL;
     636          34 :                                 if (!malLibraryEnabled(p->modname)) {
     637           0 :                                         mb->errors = createMalException(mb, idx, TYPE,
     638             :                                                                                                         "'%s%s%s' library error in: %s",
     639             :                                                                                                         (getModuleId(p) ?
     640             :                                                                                                          getModuleId(p) : ""),
     641           0 :                                                                                                         (getModuleId(p) ? "." : ""),
     642             :                                                                                                         getFunctionId(p),
     643             :                                                                                                         malLibraryHowToEnable(p->
     644             :                                                                                                                                                   modname));
     645             :                                 } else {
     646          34 :                                         bool free_errsig = false, special_undefined = false;
     647          34 :                                         errsig = malLibraryHowToEnable(p->modname);
     648          34 :                                         if (!strcmp(errsig, "")) {
     649          34 :                                                 errsig = instruction2str(mb, 0, p,
     650             :                                                                                                  (LIST_MAL_NAME | LIST_MAL_TYPE
     651             :                                                                                                   | LIST_MAL_VALUE));
     652          34 :                                                 free_errsig = true;
     653             :                                         } else {
     654             :                                                 special_undefined = true;
     655             :                                         }
     656         102 :                                         mb->errors = createMalException(mb, idx, TYPE,
     657             :                                                                                                         "'%s%s%s' undefined%s: %s",
     658             :                                                                                                         (getModuleId(p) ?
     659             :                                                                                                          getModuleId(p) : ""),
     660          34 :                                                                                                         (getModuleId(p) ? "." : ""),
     661             :                                                                                                         getFunctionId(p),
     662             :                                                                                                         special_undefined ? "" :
     663             :                                                                                                         " in",
     664             :                                                                                                         errsig ? errsig :
     665             :                                                                                                         "failed instruction2str()");
     666          34 :                                         if (free_errsig)
     667          34 :                                                 GDKfree(errsig);
     668             :                                 }
     669             :                         }
     670         879 :                         p->typeresolved = false;
     671             :                 } else
     672          11 :                         p->typeresolved = true;
     673         890 :                 return;
     674             :         }
     675             :         /*
     676             :          * When we arrive here the operator is an assignment.
     677             :          * The language should also recognize (a,b):=(1,2);
     678             :          * This is achieved by propagation of the rhs types to the lhs
     679             :          * variables.
     680             :          */
     681     8665920 :         if (getFunctionId(p)) {
     682             :                 return;
     683             :         }
     684     8665987 :         if (p->retc >= 1 && p->argc > p->retc && p->argc != 2 * p->retc) {
     685           7 :                 if (!silent) {
     686           7 :                         mb->errors = createMalException(mb, idx, TYPE,
     687             :                                                                                         "Multiple assignment mismatch");
     688             :                 }
     689           7 :                 p->typeresolved = true;
     690             :         } else
     691     8665980 :                 p->typeresolved = true;
     692    15744920 :         for (k = 0, i = p->retc; k < p->retc && i < p->argc; i++, k++) {
     693     7076432 :                 int rhs = getArgType(mb, p, i);
     694     7076432 :                 int lhs = getArgType(mb, p, k);
     695             : 
     696     7076432 :                 if (rhs != TYPE_void) {
     697     7076285 :                         if (resolveType(&s1, lhs, rhs) < 0) {
     698           5 :                                 typeMismatch(mb, p, idx, lhs, rhs, silent);
     699           5 :                                 return;
     700             :                         }
     701             :                 } else {
     702             :                         /*
     703             :                          * The language permits assignment of 'nil' to any variable,
     704             :                          * using the target type.
     705             :                          */
     706         147 :                         if (lhs != TYPE_void && lhs != TYPE_any) {
     707           3 :                                 ValRecord cst = { .vtype = TYPE_void, .val.oval = void_nil, .bat = isaBatType(lhs) };
     708           3 :                                 int k;
     709             : 
     710           3 :                                 k = defConstant(mb, lhs, &cst);
     711           3 :                                 if (k >= 0)
     712           3 :                                         p->argv[i] = k;
     713           3 :                                 rhs = lhs;
     714             :                         }
     715             :                 }
     716             : 
     717     7078933 :                 if (!isVarFixed(mb, getArg(p, k))) {
     718     3114050 :                         setVarType(mb, getArg(p, k), rhs);
     719     3114050 :                         setVarFixed(mb, getArg(p, k));
     720             :                 }
     721     7078933 :                 prepostProcess(s1, p, i, mb);
     722     7078933 :                 prepostProcess(s1, p, k, mb);
     723             :         }
     724             :         /* the case where we have no rhs */
     725     8668488 :         if (p->barrier && p->retc == p->argc)
     726      494220 :                 for (k = 0; k < p->retc; k++) {
     727      247807 :                         int tpe = getArgType(mb, p, k);
     728      247807 :                         if (isaBatType(tpe) ||
     729      244974 :                                 ATOMtype(tpe) == TYPE_str ||
     730      244974 :                                 (!isPolyType(tpe) && tpe < MAXATOMS && ATOMextern(tpe)))
     731        2839 :                                 setVarCleanup(mb, getArg(p, k));
     732             :                 }
     733             : }
     734             : 
     735             : /*
     736             :  * After the parser finishes, we have to look for semantic errors,
     737             :  * such as flow of control problems and possible typeing conflicts.
     738             :  * The nesting of BARRIER and CATCH statements with their associated
     739             :  * flow of control primitives LEAVE and RETRY should form a valid
     740             :  * hierarchy. Failure to comply is considered a structural error
     741             :  * and leads to flagging the function as erroneous.
     742             :  * Also check general conformaty of the ML block structure.
     743             :  * It should start with a signature and finish with and ENDsymbol
     744             :  *
     745             :  * Type checking a program is limited to those instructions that are
     746             :  * not resolved yet. Once the program is completely checked, further calls
     747             :  * should be ignored. This should be separately administered for the flow
     748             :  * as well, because a dynamically typed instruction should later on not
     749             :  * lead to a re-check when it was already fully analyzed.
     750             :  */
     751             : str
     752     2884378 : chkTypes(Module s, MalBlkPtr mb, int silent)
     753             : {
     754     2884378 :         InstrPtr p = 0;
     755     2884378 :         int i;
     756     2884378 :         str msg = MAL_SUCCEED;
     757             : 
     758   180664989 :         for (i = 0; mb->errors == NULL && i < mb->stop; i++) {
     759   177778376 :                 p = getInstrPtr(mb, i);
     760   177778376 :                 assert(p != NULL);
     761   177778376 :                 if (!p->typeresolved)
     762    76619369 :                         typeChecker(s, mb, p, i, silent);
     763             :         }
     764     2886613 :         if (mb->errors) {
     765          47 :                 msg = mb->errors;
     766          47 :                 mb->errors = NULL;
     767             :         }
     768     2886613 :         return msg;
     769             : }
     770             : 
     771             : /*
     772             :  * Type checking an individual instruction is dangerous,
     773             :  * because it ignores data flow and variable declarations.
     774             :  */
     775             : int
     776          11 : chkInstruction(Module s, MalBlkPtr mb, InstrPtr p)
     777             : {
     778          11 :         if (mb->errors == MAL_SUCCEED) {
     779          11 :                 p->typeresolved = false;
     780          11 :                 typeChecker(s, mb, p, getPC(mb, p), TRUE);
     781             :         }
     782          11 :         return mb->errors != MAL_SUCCEED;
     783             : }
     784             : 
     785             : /*
     786             :  * Perform silent check on the program, merely setting the error flag.
     787             :  */
     788             : str
     789      556738 : chkProgram(Module s, MalBlkPtr mb)
     790             : {
     791      556738 :         str msg;
     792             : /* it is not ready yet, too fragile
     793             :                 mb->typefixed = mb->stop == chk; ignored END */
     794             : /*      if( mb->flowfixed == 0)*/
     795             : 
     796      556738 :         if (mb->errors) {
     797          23 :                 msg = mb->errors;
     798          23 :                 mb->errors = NULL;
     799          23 :                 return msg;
     800             :         }
     801      556715 :         msg = chkTypes(s, mb, FALSE);
     802      558101 :         if (msg == MAL_SUCCEED)
     803      558067 :                 msg = chkFlow(mb);
     804      557049 :         if (msg == MAL_SUCCEED)
     805      557151 :                 msg = chkDeclarations(mb);
     806             :         return msg;
     807             : }
     808             : 
     809             : /*
     810             :  * Polymorphic type analysis
     811             :  * MAL provides for type variables of the form any$N. This feature
     812             :  * supports polymorphic types, but also complicates the subsequent
     813             :  * analysis. A variable typed with any$N not occuring in the function
     814             :  * header leads to a dynamic typed statement. In principle we have
     815             :  * to type check the function upon each call.
     816             :  */
     817             : static bool
     818     2146753 : typeResolved(MalBlkPtr mb, InstrPtr p, int i)
     819             : {
     820     2146753 :         malType t = getArgType(mb, p, i);
     821     2146753 :         if (t == TYPE_any || isAnyExpression(t)) {
     822      545009 :                 return false;
     823             :         }
     824             :         return true;
     825             : }
     826             : 
     827             : /*
     828             :  * For a polymorphic commands we do not generate a cloned version.
     829             :  * It suffices to determine the actual return value taking into
     830             :  * account the type variable constraints.
     831             :  */
     832             : static malType
     833   187486644 : getPolyType(malType t, int *polytype)
     834             : {
     835   187486644 :         int ti;
     836   187486644 :         malType tail;
     837             : 
     838   187486644 :         ti = getTypeIndex(t);
     839   187486644 :         if (!isaBatType(t) && ti > 0) {
     840    14353710 :                 tail = polytype[ti];
     841    14353710 :                 if (getOptBat(t))
     842         376 :                         setOptBat(tail);
     843    14353710 :                 return tail;
     844             :         }
     845             : 
     846   173132934 :         tail = ti == 0 ? getBatType(t) : polytype[ti];
     847   173132934 :         if (isaBatType(t)) {
     848   170463153 :                 tail = newBatType(tail);
     849             :         }
     850   173132934 :         if (getOptBat(t))
     851       12381 :                 setOptBat(tail);
     852             :         return tail;
     853             : }
     854             : 
     855             : /*
     856             :  * Each argument is checked for binding of polymorphic arguments.
     857             :  * This routine assumes that the type index is indeed smaller than maxarg.
     858             :  * (The parser currently enforces a single digit from 1-2 )
     859             :  * The polymorphic type 'any', i.e. any_0, does never constraint an operation
     860             :  * it can match with all polymorphic types.
     861             :  * The routine returns the instanciated formal type for subsequent
     862             :  * type resolution.
     863             :  */
     864             : static int
     865   144492350 : updateTypeMap(int formal, int actual, int polytype[MAXTYPEVAR])
     866             : {
     867   144492350 :         int h, t, ret = 0;
     868             : 
     869   144492350 :         if (!isAnyExpression(formal) && isaBatType(formal) && isaBatType(actual))
     870             :                 return 0;
     871             : 
     872    55581077 :         if ((h = getTypeIndex(formal))) {
     873    53318997 :                 if (isaBatType(actual) && !isaBatType(formal) && !getOptBat(formal) &&
     874     4943373 :                         (polytype[h] == TYPE_any || polytype[h] == actual)) {
     875     4129654 :                         polytype[h] = actual;
     876     4129654 :                         return 0;
     877             :                 }
     878    49189343 :                 t = getBatType(actual);
     879    49189343 :                 if (t != polytype[h]) {
     880    29814922 :                         if (isaBatType(polytype[h]) && isaBatType(actual))
     881             :                                 ret = 0;
     882    29813599 :                         else if (polytype[h] == TYPE_any)
     883    29428713 :                                 polytype[h] = t;
     884             :                         else {
     885             :                                 return -1;
     886             :                         }
     887             :                 }
     888             :         }
     889    51066537 :         if (isaBatType(formal)) {
     890    39680517 :                 if (!isaBatType(actual))
     891             :                         return -1;
     892             :         }
     893             :         return ret;
     894             : }

Generated by: LCOV version 1.14