pike.git / src / pike_types.c

version» Context lines:

pike.git/src/pike_types.c:1:   /*   || This file is part of Pike. For copyright information see COPYRIGHT.   || Pike is distributed under GPL, LGPL and MPL. See the file COPYING   || for more information. - || $Id$ +    */      #include "global.h"   #include <ctype.h>   #include "svalue.h" - #include "pike_types.h" +    #include "stralloc.h" -  + #include "pike_types.h"   #include "stuff.h"   #include "array.h"   #include "program.h"   #include "constants.h"   #include "object.h"   #include "multiset.h"   #include "mapping.h"   #include "pike_macros.h"   #include "pike_error.h"   #include "las.h"   #include "lex.h"   #include "pike_memory.h"   #include "bignum.h"   #include "main.h"   #include "opcodes.h"   #include "cyclic.h"   #include "gc.h"   #include "pike_compiler.h" - #include "block_alloc.h" + #include "block_allocator.h" + #include "bitvector.h"      #ifdef PIKE_DEBUG   #define PIKE_TYPE_DEBUG   #endif /* PIKE_DEBUG */      /*    * Flags used by low_match_types().    */   #define A_EXACT 1   #define B_EXACT 2
pike.git/src/pike_types.c:52:    * Relevant for markers.    */   #ifdef TYPE_GROUPING   #define LE_A_GROUPED 4 /* Argument A has been grouped.    * Perform weaker checking for OR-nodes. */   #define LE_B_GROUPED 8 /* Argument B has been grouped.    * Perform weaker checking for OR-nodes. */   #define LE_A_B_GROUPED 12 /* Both the above two flags. */   #endif   #define LE_USE_HANDLERS 16 /* Call handlers if appropriate. */ + #define LE_EXPLICIT_ZERO 32 /* Zero is not subtype of all others. */      /*    * Flags used by low_get_first_arg_type() -  +  * +  * Note that these differ for the flags to get_first_arg_type().    */   #define FILTER_KEEP_VOID 1 /* Keep void during the filtering. */      /*    * Flags used as flag_method to mk_type()    */   #define PT_COPY_CAR 1   #define PT_COPY_CDR 2   #define PT_COPY_BOTH 3   #define PT_IS_MARKER 4 /* The node is a marker. */      /* Number of entries in the struct pike_type hash-table. */ - #define PIKE_TYPE_HASH_SIZE 32768 + /* 256Kb */ + #define PIKE_TYPE_HASH_SIZE 32767    -  +    #ifdef PIKE_TYPE_DEBUG   static int indent=0;   #endif      int max_correct_args;      PMOD_EXPORT struct pike_type *string0_type_string;   PMOD_EXPORT struct pike_type *string_type_string;   PMOD_EXPORT struct pike_type *int_type_string;   PMOD_EXPORT struct pike_type *float_type_string;   PMOD_EXPORT struct pike_type *function_type_string;   PMOD_EXPORT struct pike_type *object_type_string;   PMOD_EXPORT struct pike_type *program_type_string;   PMOD_EXPORT struct pike_type *array_type_string;   PMOD_EXPORT struct pike_type *multiset_type_string;   PMOD_EXPORT struct pike_type *mapping_type_string;   PMOD_EXPORT struct pike_type *type_type_string;   PMOD_EXPORT struct pike_type *mixed_type_string;   PMOD_EXPORT struct pike_type *void_type_string;   PMOD_EXPORT struct pike_type *zero_type_string; -  + PMOD_EXPORT struct pike_type *inheritable_type_string; + PMOD_EXPORT struct pike_type *typeable_type_string; + PMOD_EXPORT struct pike_type *enumerable_type_string;   PMOD_EXPORT struct pike_type *any_type_string;   PMOD_EXPORT struct pike_type *weak_type_string; /* array|mapping|multiset|function */   struct pike_type *sscanf_type_string; - struct pike_type *sscanf_76_type_string; +     -  + PMOD_EXPORT struct pike_string *literal_string_string; + PMOD_EXPORT struct pike_string *literal_int_string; + PMOD_EXPORT struct pike_string *literal_float_string; + PMOD_EXPORT struct pike_string *literal_function_string; + PMOD_EXPORT struct pike_string *literal_object_string; + PMOD_EXPORT struct pike_string *literal_program_string; + PMOD_EXPORT struct pike_string *literal_array_string; + PMOD_EXPORT struct pike_string *literal_multiset_string; + PMOD_EXPORT struct pike_string *literal_mapping_string; + PMOD_EXPORT struct pike_string *literal_type_string; + PMOD_EXPORT struct pike_string *literal_mixed_string; +  +    #ifdef DO_PIKE_CLEANUP   struct pike_type_location *all_pike_type_locations = NULL;   #endif /* DO_PIKE_CLEANUP */      static struct pike_type *a_markers[10], *b_markers[10];      static struct program *implements_a;   static struct program *implements_b;   static int implements_mode;      #ifdef PIKE_DEBUG - void TYPE_STACK_DEBUG(const char *fun) + void TYPE_STACK_DEBUG(const char *UNUSED(fun))   {   #if 0    fprintf(stderr, "%25s(): stack_depth:%ld mark_stack_depth:%ld\n",    fun, (long)(Pike_compiler->type_stackp - type_stack),    (long)(Pike_compiler->pike_type_mark_stackp - pike_type_mark_stack));   #endif /* 0 */   }   #endif /* PIKE_DEBUG */      static void clear_markers(void)
pike.git/src/pike_types.c:268:    * INT min (int) max (int)    * OBJECT implements/is object id(int)    *    * Note that the cdr of a FUNCTION is a valid FUNCTION for the rest of    * the arguments.    *    * Note also that functions that don't take any arguments, or just    * a many argument just have a MANY node, and no FUNCTION node.    *    */ - #define PIKE_TYPE_CHUNK 128 - BLOCK_ALLOC(pike_type, PIKE_TYPE_CHUNK) + static struct block_allocator type_allocator = BA_INIT(sizeof(struct pike_type), 128);    -  + PMOD_EXPORT void really_free_pike_type(struct pike_type * t) { +  ba_free(&type_allocator, t); + } +  + ATTRIBUTE((malloc)) + PMOD_EXPORT struct pike_type * alloc_pike_type(void) { +  return ba_alloc(&type_allocator); + } +  + PMOD_EXPORT void count_memory_in_pike_types(size_t *n, size_t *s) { +  ba_count_all(&type_allocator, n, s); + } +    struct pike_type **pike_type_hash = NULL;   size_t pike_type_hash_size = 0;      void debug_free_type(struct pike_type *t)   {   #ifdef DEBUG_MALLOC    if (t == (struct pike_type *)(size_t)0x55555555) {    Pike_fatal("Freeing dead type.\n");    }   #endif /* DEBUG_MALLOC */    loop:    if (!sub_ref(t)) { -  unsigned INT32 hash = t->hash % pike_type_hash_size; +  unsigned INT32 hash = t->hash & pike_type_hash_size;    struct pike_type **t2 = pike_type_hash + hash;    struct pike_type *car, *cdr;    unsigned INT32 type; -  + #ifdef PIKE_DEBUG    /* PIKE_DEBUG code */ -  if (hash >= pike_type_hash_size) { +  if (hash > pike_type_hash_size) {    Pike_fatal("Modulo operation failed for hash:%u, index:%u, size:%u.\n",    t->hash, hash, pike_type_hash_size);    }    /* End PIKE_DEBUG code */ -  + #endif    while (*t2) {    if (*t2 == t) {    *t2 = t->next;    break;    }    t2 = &((*t2)->next);    }       car = t->car;    cdr = t->cdr;    type = t->type;    -  really_free_pike_type((struct pike_type *)debug_malloc_pass(t)); +  really_free_pike_type((struct pike_type*)debug_malloc_pass(t));       /* FIXME: Recursion: Should we use a stack? */    switch(type) {    case T_FUNCTION:    case T_MANY:    case T_TUPLE:    case T_MAPPING:    case T_OR:    case T_AND:    case PIKE_T_RING:
pike.git/src/pike_types.c:385:   }      static inline struct pike_type *debug_mk_type(unsigned INT32 type,    struct pike_type *car,    struct pike_type *cdr,    int flag_method)   {    /* FIXME: The hash ought to be based on the tree contents, regardless    * of what the adresses of the type nodes are.    */ -  unsigned INT32 hash = DO_NOT_WARN((unsigned INT32) +  struct pike_type *t; +  unsigned INT32 index, +  hash = (unsigned INT32)    ((ptrdiff_t)type*0x10204081)^    (0x8003*PTR_TO_INT(car))^ -  ~(0x10001*PTR_TO_INT(cdr))); -  unsigned INT32 index = hash % pike_type_hash_size; -  struct pike_type *t; +  ~(0x10001*PTR_TO_INT(cdr)); +  +  hash ^= (hash >> 20) ^ (hash >> 12); +  hash ^= (hash >> 7) ^ (hash >> 4); +  +  index = hash & pike_type_hash_size;   #ifdef PIKE_EXTRA_DEBUG    static unsigned INT32 extra_debug_index = (unsigned INT32)~0;   #endif /* PIKE_EXTRA_DEBUG */ -  + #ifdef PIKE_DEBUG    /* PIKE_DEBUG code */    if (type & ~255) {    /* The bad type node on OSF/1 seems to be:    *    * type: 0xffff    * car: valid pointer.    * cdr: 0x400000000    * next: 0x100000000    */    Pike_fatal("Attempt to create an invalid type node: %d(%s)\n"    " car: %p\n"    " cdr: %p\n",    type, get_name_of_type(type),    car, cdr);    } -  if (index >= pike_type_hash_size) { +  if (index > pike_type_hash_size) {    Pike_fatal("Modulo operation failed for hash:%u, index:%u, "    "size:%"PRINTSIZET"d.\n",    hash, index, pike_type_hash_size);    }    /* End PIKE_DEBUG code */ -  + #endif   #ifdef PIKE_EXTRA_DEBUG    if ((!~extra_debug_index) &&    (type == T_FUNCTION) &&    (car->type == T_STRING) &&    (cdr->type == T_FUNCTION) &&    (cdr->car->type == T_STRING) &&    (cdr->cdr->type == T_MANY) &&    (cdr->cdr->car->type == T_VOID) &&    (cdr->cdr->cdr->type == T_STRING)) {    /* Attempt to detect why we get a core-dump on OSF/1
pike.git/src/pike_types.c:508:    case T_ASSIGN:    /* Free cdr */    free_type((struct pike_type *)debug_malloc_pass(cdr));    break;       case PIKE_T_ATTRIBUTE:    case PIKE_T_NAME:    free_string((struct pike_string *)debug_malloc_pass(car));    free_type((struct pike_type *)debug_malloc_pass(cdr));    break; -  +    #ifdef PIKE_DEBUG    case '0':    case '1':    case '2':    case '3':    case '4':    case '5':    case '6':    case '7':    case '8':
pike.git/src/pike_types.c:545:    return t;    }    }      #ifdef PIKE_DEBUG    if ((type == T_OR) && (car->type == T_OR)) {    Pike_fatal("Invalid CAR to OR node.\n");    }   #endif    -  debug_malloc_pass(t = alloc_pike_type()); +  debug_malloc_pass(t = ba_alloc(&type_allocator));    - #ifdef ATOMIC_SVALUE -  t->ref_type = PIKE_T_TYPE; - #endif +     t->refs = 0;    add_ref(t); /* For DMALLOC... */    t->type = type;    t->flags = 0;    t->car = car;    t->cdr = cdr;       t->hash = hash;    t->next = pike_type_hash[index];    pike_type_hash[index] = t;
pike.git/src/pike_types.c:650:       return t;   }      #ifdef DEBUG_MALLOC   #define mk_type(T,CAR,CDR,FLAG) ((struct pike_type *)debug_malloc_pass(debug_mk_type(T,CAR,CDR,FLAG)))   #else /* !DEBUG_MALLOC */   #define mk_type debug_mk_type   #endif /* DEBUG_MALLOC */    - #ifdef PIKE_DEBUG - void debug_check_type_string(struct pike_type *s) - { -  /* FIXME: Add verification code here */ - } + struct pike_type **type_stack; + struct pike_type ***pike_type_mark_stack;    - #endif /* PIKE_DEBUG */ -  - struct pike_type *type_stack[PIKE_TYPE_STACK_SIZE]; - struct pike_type **pike_type_mark_stack[PIKE_TYPE_STACK_SIZE/4]; -  +    ptrdiff_t pop_stack_mark(void)   {    Pike_compiler->pike_type_mark_stackp--;    if(Pike_compiler->pike_type_mark_stackp<pike_type_mark_stack)    Pike_fatal("Type mark stack underflow\n");       TYPE_STACK_DEBUG("pop_stack_mark");       return Pike_compiler->type_stackp - *Pike_compiler->pike_type_mark_stackp;   }
pike.git/src/pike_types.c:692:   struct pike_type *debug_peek_type_stack(void)   {    return *(Pike_compiler->type_stackp);   }      void debug_push_int_type(INT_TYPE min, INT_TYPE max)   {   #if SIZEOF_INT_TYPE > 4   /* a bit kludgy: should maybe really allow 64 bit INT_TYPE */   /* see also extract_type_int */ -  +     if (min<MIN_INT32) min=MIN_INT32;    else if (min>MAX_INT32) min=MAX_INT32;    if (max<MIN_INT32) max=MIN_INT32;    else if (max>MAX_INT32) max=MAX_INT32; -  - #if 0 -  if (min!=(INT32)min || -  max!=(INT32)max) -  Pike_fatal("push_int_type(): int outside INT32 range (sorry)" -  " (%"PRINTPIKEINT"d..%"PRINTPIKEINT"d)\n", -  min,max); +    #endif - #endif +     - #ifdef PIKE_DEBUG -  if (min > max) + #ifdef PIKE_DEBUG /* FIXME: Kludge to support 2^32-1 */ +  if (((min>0 && max>0) || (min<0 && max<0)) && min > max)    Pike_fatal("push_int_type(): Bad integer range:"    " min:%"PRINTPIKEINT"d, max:%"PRINTPIKEINT"d.\n",    min, max);   #endif /* PIKE_DEBUG */       if (!min && !max) {    /* Special case... */    push_type(T_ZERO);    } else {    *(++Pike_compiler->type_stackp) = mk_type(T_INT,    (void *)(ptrdiff_t)min,    (void *)(ptrdiff_t)max, 0);    }    TYPE_STACK_DEBUG("push_int_type");   }    -  + static int (*program_id_to_id)(int) = NULL; +  + PMOD_EXPORT void set_program_id_to_id( int (*to)(int) ) + { +  program_id_to_id = to; + } +    void debug_push_object_type(int flag, INT32 id)   { -  +  if( program_id_to_id ) +  id = program_id_to_id(id);    *(++Pike_compiler->type_stackp) = mk_type(T_OBJECT,    (void *)(ptrdiff_t)flag,    (void *)(ptrdiff_t)id, 0);       TYPE_STACK_DEBUG("push_object_type");   }      void debug_push_object_type_backwards(int flag, INT32 id)   {    push_object_type(flag, id);
pike.git/src/pike_types.c:794:    TYPE_STACK_DEBUG("push_type_name");   }      void debug_push_finished_type(struct pike_type *t)   {    copy_pike_type(*(++Pike_compiler->type_stackp), t);       TYPE_STACK_DEBUG("push_finished_type");   }    - /* Only to be used from {or,and}_pike_types() et al! */ - static void push_joiner_type(unsigned int type) - { -  /* fprintf(stderr, "push_joiner_type(%d)\n", type); */ -  -  switch(type) { -  case T_OR: -  case T_AND: -  /* Special case: Check if the two top elements are equal. */ -  if (Pike_compiler->type_stackp[-1] == Pike_compiler->type_stackp[0]) { -  free_type(*(Pike_compiler->type_stackp--)); -  return; -  } -  /* Make a new type of the top two types. */ -  --Pike_compiler->type_stackp; - #ifdef PIKE_DEBUG -  if ((*Pike_compiler->type_stackp+1)->type == type) { -  Pike_fatal("Invalid CAR to push_joiner_type().\n"); -  } - #endif /* PIKE_DEBUG */ -  *Pike_compiler->type_stackp = mk_type(type, -  *(Pike_compiler->type_stackp+1), -  *Pike_compiler->type_stackp, -  PT_COPY_BOTH); -  break; -  default: -  Pike_fatal("Illegal joiner type: %d\n", type); -  } - } -  +    static void push_reverse_joiner_type(unsigned int type)   {    /* fprintf(stderr, "push_reverse_joiner_type(%d)\n", type); */       switch(type) {    case T_OR:    case T_AND:    /* Special case: Check if the two top elements are equal. */    if (Pike_compiler->type_stackp[-1] == Pike_compiler->type_stackp[0]) {    free_type(*(Pike_compiler->type_stackp--));
pike.git/src/pike_types.c:903:    case T_MAPPING:    case PIKE_T_RING:    /* Make a new type of the top two types. */    --Pike_compiler->type_stackp;    *Pike_compiler->type_stackp = mk_type(type,    *(Pike_compiler->type_stackp+1),    *Pike_compiler->type_stackp,    PT_COPY_BOTH);    break;    +  case T_PROGRAM: +  if ((*Pike_compiler->type_stackp)->type != T_OBJECT) { +  struct pike_type *t = (*Pike_compiler->type_stackp); +  while ((t->type == PIKE_T_NAME) || (t->type == PIKE_T_ATTRIBUTE)) { +  t = t->cdr; +  } +  if (t->type != T_OBJECT) { +  /* Not a program type, convert it to a type type. */ +  type = T_TYPE; +  } +  } +  /* FALL_THROUGH */    case T_ARRAY:    case T_MULTISET:    case T_NOT:    case T_TYPE: -  case T_PROGRAM: +     case T_STRING:    /* Make a new type of the top type, and put it in car. */    *Pike_compiler->type_stackp = mk_type(type,    *Pike_compiler->type_stackp, NULL,    PT_COPY_CAR);    break;       case T_SCOPE:    case T_ASSIGN:    case T_INT:
pike.git/src/pike_types.c:1059:    Pike_compiler->type_stackp[0] = Pike_compiler->type_stackp[-1];    Pike_compiler->type_stackp[-1] = tmp;    break;    }    }    push_type(type);       TYPE_STACK_DEBUG("push_reverse_type");   }    + static int is_int_type(struct pike_type *t) + { +  loop: +  switch(t->type) { +  case T_INT: +  case T_ZERO: +  case T_VOID: +  case '0': case '1': case '2': case '3': case '4': +  case '5': case '6': case '7': case '8': case '9': +  return 1; +  case T_OR: +  case T_AND: +  return is_int_type(t->car) && is_int_type(t->cdr); +  case PIKE_T_NAME: +  case PIKE_T_ATTRIBUTE: +  case PIKE_T_SCOPE: +  case T_ASSIGN: +  t = t->cdr; +  goto loop; +  default: +  return 0; +  } + } +    /* The marker_set is used as follows:    *    * PT_FLAG_MARKER_n Indicates that marker #n should be kept after    * expansion.    *    * PT_FLAG_ASSIGN_n Indicates that the assign to marker #n should    * NOT be removed.    */   static void debug_push_finished_type_with_markers(struct pike_type *type,    struct pike_type **markers,
pike.git/src/pike_types.c:1092:    */    if (!(type->flags & (~marker_set | PT_FLAG_MARKER) & PT_FLAG_MARK_ASSIGN)) {    /* Nothing to replace in this subtree. */   #ifdef PIKE_TYPE_DEBUG    if (l_flag > 2) {    fprintf(stderr, "Nothing to replace in this subtree.\n");    simple_describe_type(type);    fprintf(stderr, "\n");    }   #endif /* PIKE_TYPE_DEBUG */ +  if ((marker_set & PT_FLAG_INT_ONLY) && !is_int_type(type)) { +  push_finished_type(int_type_string); +  } else {    push_finished_type(type); -  +  }    return;    }    if ((type->type >= '0') && (type->type <= '9')) {    /* Marker. */    unsigned int m = type->type - '0';   #ifdef PIKE_TYPE_DEBUG    if ((l_flag > 2) && m) {    fprintf(stderr, "Marker %d: %p.\n", m, markers[m]);    }   #endif /* PIKE_TYPE_DEBUG */    if (markers[m]) {    /* The marker has a value. */    struct pike_type *type = dmalloc_touch(struct pike_type *, markers[m]);   #ifdef PIKE_TYPE_DEBUG    if (l_flag > 2) {    fprintf(stderr, "Marker value.\n");    }   #endif    /* FIXME: We probably ought to switch to the other marker set here. */    markers[m] = NULL; -  push_finished_type_with_markers(type, markers, 0); +  push_finished_type_with_markers(type, markers, +  marker_set & PT_FLAG_INT_ONLY);    if (type->flags & (PT_FLAG_MARKER|PT_FLAG_ASSIGN)) {    push_scope_type(0);    }    if (markers[m]) free_type(markers[m]);    markers[m] = dmalloc_touch(struct pike_type *, type);    } else {    /* The marker has not been set. */   #ifdef PIKE_TYPE_DEBUG    if (l_flag > 2) {    fprintf(stderr, "No marker value.\n");
pike.git/src/pike_types.c:1181:    goto recurse;    }    } else if (type->type == PIKE_T_NAME) {    /* Strip the name, since it won't be correct anymore. */    type = type->cdr;    goto recurse;    } else if (type->type == PIKE_T_ATTRIBUTE) {    /* Keep the attribute. */    push_finished_type_with_markers(type->cdr, markers, marker_set);    push_type_attribute((struct pike_string *)type->car); +  goto done;    }    /* FIXME: T_SCOPE */       if (type->car) {    /* Keep markers for assigns in the car. */    cdr_set = marker_set |    ((type->car->flags & PT_FLAG_ASSIGN)>>PT_ASSIGN_SHIFT);    } else {    cdr_set = marker_set;    }
pike.git/src/pike_types.c:1238:    pop_stack_mark();    pop_stack_mark();    push_type(T_AND);    }    }    } else {    if (type->cdr) {    /* In all other cases type->cdr will be a valid node if is not NULL. */    push_finished_type_with_markers(type->cdr, markers, cdr_set);    } +  /* Make sure to filter invalid nodes from the marker in case +  * it is a string type. +  */ +  if (type->type == PIKE_T_STRING) car_set |= PT_FLAG_INT_ONLY;    /* In all other cases type->car will be a valid node. */    push_finished_type_with_markers(type->car, markers, car_set);    /* push_type has sufficient magic to recreate the type. */    push_type(type->type);    } -  +  done:    TYPE_STACK_DEBUG("push_finished_type_with_markers");   }      static void push_type_field(TYPE_FIELD field)   {    field &= (BIT_BASIC|BIT_COMPLEX);    if (!field) {    /* No values. */    push_type(T_ZERO);    } else if (field == (BIT_BASIC|BIT_COMPLEX)) {
pike.git/src/pike_types.c:1319:    if (field & BIT_FLOAT) {    push_type(T_FLOAT);    push_type(T_OR);    }    }    }   }      INT32 extract_type_int(char *p)   { -  int e; -  INT32 ret=0; -  for(e=0;e<(int)sizeof(INT32);e++) -  ret=(ret<<8) | EXTRACT_UCHAR(p+e); -  return ret; +  return get_unaligned_be32(p);   }      struct pike_type *debug_pop_unfinished_type(void)   {    ptrdiff_t len;       len = pop_stack_mark();       if (len != 1) {    Pike_fatal("pop_unfinished_type(): Unexpected len: %"PRINTPTRDIFFT"d\n", len);
pike.git/src/pike_types.c:1348:    return *(Pike_compiler->type_stackp--);   }      /******/      static struct pike_string *internal_parse_type_string(const char **_s)   {    const unsigned char **s = (const unsigned char **)_s;    const unsigned char *p;    struct string_builder tmp; -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s != '\"') yyerror("Expected '\"'.");    else    ++*s;    init_string_builder(&tmp, 0);    p = *s;    while(1) {    int c;    do {    c = *p++;    } while ((c > '\\') || ((c != '\"') && (c != '\\') && (c != '\n')));
pike.git/src/pike_types.c:1387:    }    return finish_string_builder(&tmp);   }      static void internal_parse_typeA(const char **_s)   {    char buf[80];    unsigned int len;    const unsigned char **s = (const unsigned char **)_s;    -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;       for(len=0;isidchar(EXTRACT_UCHAR(s[0]+len));len++)    {    if(len>=sizeof(buf)-1) {    my_yyerror("Buffer overflow in parse_type(\"%s\") (limit %"PRINTSIZET"d).",    *s, sizeof(buf));    push_type(T_MIXED);    return;    }    buf[len] = s[0][len];
pike.git/src/pike_types.c:1411:       switch(buf[0])    {    case 'z':    if(!strcmp(buf,"zero")) { push_type(T_ZERO); break; }    goto bad_type;       case 'i':    if(!strcmp(buf,"int"))    { -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s=='(')    {    INT32 min,max;    ++*s; -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if (**s != '.') { -  min=STRTOL((const char *)*s,(char **)s,0); -  while(ISSPACE(**s)) ++*s; +  min=strtol((const char *)*s,(char **)s,0); +  while(isspace(**s)) ++*s;    } else {    min = MIN_INT32;    }    if(s[0][0]=='.' && s[0][1]=='.')    s[0]+=2;    else {    yyerror("Missing .. in integer type.");    }    -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if (**s != ')') { -  max=STRTOL((const char *)*s,(char **)s,0); -  while(ISSPACE(**s)) ++*s; +  max=strtol((const char *)*s,(char **)s,0); +  while(isspace(**s)) ++*s;    } else {    max = MAX_INT32;    }       if(**s != ')') yyerror("Missing ')' in integer range.");    else    ++*s;    push_int_type(min, max);    }else{    push_int_type(MIN_INT32, MAX_INT32);    }    break;    }    goto bad_type;       case 'f':    if(!strcmp(buf,"function"))    { -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s == '(')    {    int nargs = 0;    ++*s; -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    while(1)    {    if(**s == ':')    {    push_type(T_VOID);    break;    }    internal_parse_type(_s);    if(**s==',')    {    nargs++;    ++*s; -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    }    else if(s[0][0]=='.' && s[0][1]=='.' && s[0][2]=='.')    {    *s+=3; -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s != ':') {    yyerror("Missing ':' after ... in function type.");    --*s;    }    break;    } else {    nargs++;    }    }    /* Skip the colon. */
pike.git/src/pike_types.c:1513:    push_type(T_MANY);    }    break;    }    if(!strcmp(buf,"float")) { push_type(T_FLOAT); break; }    goto bad_type;       case 'o':    if(!strcmp(buf,"object"))    { -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s == '(') /* object({,is,implements} {id,this_program}) */    {    int is = 0, id;    ++*s; -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if( **s != 'i' )    goto no_is_implements;    ++*s;    if( **s == 's' ) {    ++*s;    if (**s != ' ') {    goto bad_type;    }    is = 1;    ++*s;    } else {    if (strncmp((const char *)*s, "mplements ", 10)) {    goto bad_type;    }    *s += 10;    } -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    no_is_implements:    if( !**s )    goto bad_type;    if (!strncmp((const char *)*s, "this_program", 12)) {    id = Pike_compiler->new_program->id;    *s += 12;    } else {    id = atoi( (const char *)*s );    while( **s >= '0' && **s <= '9' )    ++*s;    } -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if( !**s || **s != ')' )    goto bad_type;    ++*s;    push_object_type(is, id);    }    else    push_object_type(0, 0);    break;    }    goto bad_type;
pike.git/src/pike_types.c:1571:    if(!strcmp(buf,"program")) {    push_object_type(0, 0);    push_type(T_PROGRAM);    break;    }    goto bad_type;          case 's':    if(!strcmp(buf,"string")) { -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s == '(')    {    INT32 min,max;    ++*s; -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if (**s != '.') { -  min=STRTOL((const char *)*s,(char **)s,0); -  while(ISSPACE(**s)) ++*s; +  min=strtol((const char *)*s,(char **)s,0); +  while(isspace(**s)) ++*s;    } else {    min = MIN_INT32;    }    if(s[0][0]=='.' && s[0][1]=='.')    s[0]+=2;    else {    yyerror("Missing .. in integer type.");    }    -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if (**s != ')') { -  max=STRTOL((const char *)*s,(char **)s,0); -  while(ISSPACE(**s)) ++*s; +  max=strtol((const char *)*s,(char **)s,0); +  while(isspace(**s)) ++*s;    } else {    max = MAX_INT32;    }    if(**s != ')') yyerror("Missing ')' in string width.");    else    ++*s;    push_int_type(min, max);    } else {    push_finished_type(int_type_string);    }
pike.git/src/pike_types.c:1615:    }    goto bad_type;       case 'v':    if(!strcmp(buf,"void")) { push_type(T_VOID); break; }    goto bad_type;       case 't':    if (!strcmp(buf,"tuple"))    { -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s == '(')    {    ++*s;    internal_parse_type(_s);    if(**s != ',') yyerror("Expected ','.");    else    ++*s;    internal_parse_type(_s);    if(**s != ')') yyerror("Expected ')'.");    else
pike.git/src/pike_types.c:1642:    break;    }    /* FIXME: Handle type(T) */    if(!strcmp(buf,"type")) { push_type(T_MIXED); push_type(T_TYPE); break; }    goto bad_type;       case 'm':    if(!strcmp(buf,"mixed")) { push_type(T_MIXED); break; }    if(!strcmp(buf,"mapping"))    { -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s == '(')    {    ++*s;    internal_parse_type(_s);    if(**s != ':') yyerror("Expected ':'.");    else    ++*s;    internal_parse_type(_s);    if(**s != ')') yyerror("Expected ')'.");    else    ++*s;    }else{    push_type(T_MIXED);    push_type(T_MIXED);    }    push_reverse_type(T_MAPPING);    break;    }    if(!strcmp(buf,"multiset"))    { -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s == '(')    {    ++*s;    internal_parse_type(_s);    if(**s != ')') yyerror("Expected ')'.");    else    ++*s;    }else{    push_type(T_MIXED);    }
pike.git/src/pike_types.c:1686:    }    goto bad_type;       case 'u':    if(!strcmp(buf,"unknown")) { push_type(PIKE_T_UNKNOWN); break; }    goto bad_type;       case 'a':    if(!strcmp(buf,"array"))    { -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s == '(')    {    ++*s;    internal_parse_type(_s);    if(**s != ')') yyerror("Expected ')'.");    else    ++*s;    }else{    push_type(T_MIXED);    }    push_type(T_ARRAY);    break;    }    goto bad_type;       case '_':    if (!strcmp(buf, "__attribute__")) { -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s == '(')    {    struct pike_string *attr;    ++*s;    attr = internal_parse_type_string(_s); -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s != ',') yyerror("Expected ','.");    else    ++*s;    internal_parse_type(_s);    if(**s != ')') yyerror("Expected ')'.");    else    ++*s;    push_type_attribute(attr);    free_string(attr);    }else{    push_type(T_MIXED);    }    break;    } else if (!strcmp(buf, "__deprecated__")) {    struct pike_string *deprecated_string;    MAKE_CONST_STRING(deprecated_string, "deprecated"); -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s == '(')    {    ++*s;    internal_parse_type(_s);    if(**s != ')') yyerror("Expected ')'.");    else    ++*s;    }else{    push_type(T_MIXED);    }
pike.git/src/pike_types.c:1756:    case '2':    case '3':    case '4':    case '5':    case '6':    case '7':    case '8':    case '9':    if(atoi(buf)<10)    { -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;    if(**s=='=')    {    ++*s;    internal_parse_type(_s);    push_assign_type(buf[0]);    }else{    push_type(buf[0]);    }    break;    }       default:    bad_type:    push_type(T_MIXED);    my_yyerror("Couldn't parse type. (%s).", buf);    }    -  while(ISSPACE(**s)) ++*s; +  while(isspace(**s)) ++*s;   }         static void internal_parse_typeB(const char **s)   { -  while(ISSPACE(EXTRACT_UCHAR(*s))) ++*s; +  while(isspace(EXTRACT_UCHAR(*s))) ++*s;    switch(**s)    {    case '!':    ++*s;    internal_parse_typeB(s);    push_type(T_NOT);    break;       case '(':    ++*s;    internal_parse_type(s); -  while(ISSPACE(EXTRACT_UCHAR(*s))) ++*s; +  while(isspace(EXTRACT_UCHAR(*s))) ++*s;    if(**s != ')') {    yyerror("Expected ')' in type.");    }    ++*s;    break;       default:       internal_parse_typeA(s);    }   }      static void internal_parse_typeCC(const char **s)   {    internal_parse_typeB(s);    -  while(ISSPACE(EXTRACT_UCHAR(*s))) ++*s; +  while(isspace(EXTRACT_UCHAR(*s))) ++*s;       while(**s == '*')    {    ++*s; -  while(ISSPACE(EXTRACT_UCHAR(*s))) ++*s; +  while(isspace(EXTRACT_UCHAR(*s))) ++*s;    push_type(T_ARRAY);    }   }      static void internal_parse_typeC(const char **s)   {    internal_parse_typeCC(s);       if(**s == '&')    {
pike.git/src/pike_types.c:1900: Inside #if defined(PIKE_DEBUG)
   break;       case T_SCOPE: fprintf(stderr, "scope"); break;    case T_TUPLE: fprintf(stderr, "tuple"); break;    case T_ASSIGN: fprintf(stderr, "="); break;    case T_INT:    {    INT32 min=extract_type_int(a+e+1);    INT32 max=extract_type_int(a+e+1+sizeof(INT32));    fprintf(stderr, "int"); -  if(min!=MIN_INT32 || max!=MAX_INT32) +  if(min!=MIN_INT32 || max!=MAX_INT32) { +  if (!min && max && !(max & (max+1))) { +  int j = 0; +  while (max) { +  max >>= 1; +  j++; +  } +  fprintf(stderr, "(%dbit)", j); +  } else {    fprintf(stderr, "(%ld..%ld)",(long)min,(long)max); -  +  } +  }    e+=sizeof(INT32)*2;    break;    }    case T_FLOAT: fprintf(stderr, "float"); break;    case T_STRING: fprintf(stderr, "string"); break;    case T_TYPE: fprintf(stderr, "type"); break;    case T_PROGRAM: fprintf(stderr, "program"); break;    case T_OBJECT:    fprintf(stderr, "object(%s %ld)",    EXTRACT_UCHAR(a+e+1)?"is":"implements",
pike.git/src/pike_types.c:1989:    case T_ASSIGN:    fprintf(stderr, "(%"PRINTPTRDIFFT"d = ", CAR_TO_INT(s));    simple_describe_type(s->cdr);    fprintf(stderr, ")");    break;    case T_INT:    {    INT32 min = CAR_TO_INT(s);    INT32 max = CDR_TO_INT(s);    fprintf(stderr, "int"); -  if(min!=MIN_INT32 || max!=MAX_INT32) +  if(min!=MIN_INT32 || max!=MAX_INT32) { +  if (!min && max && !(max & (max+1))) { +  int j = 0; +  while (max) { +  max >>= 1; +  j++; +  } +  fprintf(stderr, "(%dbit)", j); +  } else {    fprintf(stderr, "(%ld..%ld)",(long)min,(long)max); -  +  } +  }    break;    }    case T_FLOAT: fprintf(stderr, "float"); break;    case T_STRING:    {    INT32 min;    INT32 max;    s = s->car;    fprintf(stderr, "string");    if (s != int_type_string) {
pike.git/src/pike_types.c:2013:    struct pike_type *char_type = s->car;    while(char_type->type == T_ASSIGN) {    char_type = char_type->cdr;    }       if (char_type->type == T_ZERO) {    fprintf(stderr, "zero | ");    s = s->cdr;    continue;    } +  if ((char_type->type >= '0') && (char_type->type <= '9')) { +  fprintf(stderr, "$%c | ", char_type->type); +  s = s->cdr; +  continue; +  }   #ifdef PIKE_DEBUG    if (char_type->type != T_INT) {    Pike_fatal("Invalid node type (%d:%s) in string type.\n",    char_type->type, get_name_of_type(char_type->type));    }   #endif /* PIKE_DEBUG */    min = CAR_TO_INT(char_type);    max = CDR_TO_INT(char_type); -  +  if (!min && max && max != MAX_INT32 && !(max & (max+1))) { +  int j = 0; +  while (max) { +  max >>= 1; +  j++; +  } +  fprintf(stderr, "%dbit", j); +  } else {    if (min != MIN_INT32) {    fprintf(stderr, "%d", min);    }    fprintf(stderr, "..");    if (max != MAX_INT32) {    fprintf(stderr, "%d", max);    } -  +  }    fprintf(stderr, " | ");    s = s->cdr;    }    while(s->type == T_ASSIGN) {    s = s->cdr;    }    if (s->type == T_ZERO) {    fprintf(stderr, "zero"); -  +  } else if ((s->type >= '0') && (s->type <= '9')) { +  fprintf(stderr, "$%c", s->type);    } else {   #ifdef PIKE_DEBUG    if (s->type != T_INT) {    Pike_fatal("Invalid node type (%d:%s) in string type.\n",    s->type, get_name_of_type(s->type));    }   #endif /* PIKE_DEBUG */    min = CAR_TO_INT(s);    max = CDR_TO_INT(s); -  +  if (!min && max && max != MAX_INT32 && !(max & (max+1))) { +  int j = 0; +  while (max) { +  max >>= 1; +  j++; +  } +  fprintf(stderr, "%dbit", j); +  } else {    if (min != MIN_INT32) {    fprintf(stderr, "%d", min);    }    fprintf(stderr, "..");    if (max != MAX_INT32) {    fprintf(stderr, "%d", max);    }    } -  +  }    fprintf(stderr, ")");    }    break;    }    case T_TYPE:    fprintf(stderr, "type(");    simple_describe_type(s->car);    fprintf(stderr, ")");    break;    case T_PROGRAM:
pike.git/src/pike_types.c:2117:    case T_MULTISET:    fprintf(stderr, "multiset(");    simple_describe_type(s->car);    fprintf(stderr, ")");    break;       case PIKE_T_UNKNOWN: fprintf(stderr, "unknown"); break;    case PIKE_T_RING:    fprintf(stderr, "ring(");    simple_describe_type(s->car); -  fprintf(stderr, "°"); +  fprintf(stderr, "\260");    simple_describe_type(s->cdr);    fprintf(stderr, ")");    break;    case T_OR:    fprintf(stderr, "or(");    simple_describe_type(s->car);    fprintf(stderr, "|");    simple_describe_type(s->cdr);    fprintf(stderr, ")");    break;
pike.git/src/pike_types.c:2160:    break;    }    if (s->flags) {    fprintf(stderr, "[%06x]", s->flags);    }    } else {    fprintf(stderr, "NULL");    }   }    - static void low_describe_type(struct pike_type *t) + void low_describe_type(struct string_builder *s, struct pike_type *t)   { -  char buffer[100]; -  +     check_c_stack(1024); -  /**** FIXME: ****/ +     switch(t->type)    {    case '0': case '1': case '2': case '3': case '4':    case '5': case '6': case '7': case '8': case '9': -  my_putchar(t->type); +  string_builder_putchar(s, t->type);    break;       case T_ASSIGN: -  my_putchar('('); -  my_putchar('0' + CAR_TO_INT(t)); -  my_putchar('='); -  my_describe_type(t->cdr); -  my_putchar(')'); +  string_builder_sprintf(s, "(%c=%T)", '0' + CAR_TO_INT(t), t->cdr);    break;       case T_SCOPE: -  my_strcat("scope("); -  my_putchar('0' + CAR_TO_INT(t)); -  my_putchar(','); -  my_describe_type(t->cdr); -  my_putchar(')'); +  string_builder_sprintf(s, "scope(%c,%T)", '0' + CAR_TO_INT(t), t->cdr);    break;       case T_TUPLE: -  my_putchar('['); -  my_describe_type(t->car); -  my_putchar(','); -  my_describe_type(t->cdr); -  my_putchar(']'); +  string_builder_sprintf(s, "[%T,%T]", t->car, t->cdr);    break;    -  case T_VOID: my_strcat("void"); break; -  case T_ZERO: my_strcat("zero"); break; -  case T_MIXED: my_strcat("mixed"); break; -  case PIKE_T_UNKNOWN: my_strcat("unknown"); break; +  case T_VOID: string_builder_strcat(s, "void"); break; +  case T_ZERO: string_builder_strcat(s, "zero"); break; +  case T_MIXED: string_builder_strcat(s, "mixed"); break; +  case PIKE_T_UNKNOWN: string_builder_strcat(s, "unknown"); break;    case T_INT:    {    INT32 min=CAR_TO_INT(t);    INT32 max=CDR_TO_INT(t); -  my_strcat("int"); +     -  if(min!=MIN_INT32 || max!=MAX_INT32) -  { -  sprintf(buffer,"(%ld..%ld)",(long)min,(long)max); -  my_strcat(buffer); +  if (!min && max && max != MAX_INT32 && !(max & (max+1))) { +  int j = 0; +  while (max) { +  max >>= 1; +  j++;    } -  +  string_builder_sprintf(s, "int(%dbit)", j); +  } else if(min!=MIN_INT32 || max!=MAX_INT32) { +  string_builder_sprintf(s, "int(%ld..%ld)", (long)min, (long)max); +  } else { +  string_builder_strcat(s, "int"); +  }    break;    } -  case T_FLOAT: my_strcat("float"); break; +  case T_FLOAT: string_builder_strcat(s, "float"); break;    case T_PROGRAM:    if ((t->car->type == T_OBJECT) &&    (!t->car->cdr)) { -  my_strcat("program"); +  string_builder_strcat(s, "program");    } else { -  my_strcat("program("); -  my_describe_type(t->car); -  my_strcat(")"); +  string_builder_sprintf(s, "program(%T)", t->car);    }    break;    case T_OBJECT:    if (t->cdr)    { -  dynamic_buffer save_buf; -  ONERROR err; -  struct svalue s; +  struct svalue sval;    if (t->car) { -  my_strcat("object(is "); +  string_builder_strcat(s, "object(is ");    } else { -  my_strcat("object(implements "); +  string_builder_strcat(s, "object(implements ");    }    /* We need to save the global buffer, in case id_to_program()    * starts running Pike code. */ -  save_buffer(&save_buf); -  SET_ONERROR(err, restore_buffer, &save_buf); -  s.u.program = id_to_program(CDR_TO_INT(t)); -  CALL_AND_UNSET_ONERROR(err); -  if (s.u.program) { -  SET_SVAL_TYPE(s, T_PROGRAM); -  SET_SVAL_SUBTYPE(s, 0); -  describe_svalue(&s, 0, NULL); -  my_strcat(")"); +  sval.u.program = id_to_program(CDR_TO_INT(t)); +  if (sval.u.program) { +  SET_SVAL_TYPE(sval, T_PROGRAM); +  SET_SVAL_SUBTYPE(sval, 0); +  string_builder_sprintf(s, "%O)", &sval);    } else { -  char buffer[100]; -  sprintf(buffer,"%"PRINTPTRDIFFT"d)", -  CDR_TO_INT(t)); -  my_strcat(buffer); +  string_builder_sprintf(s, "%"PRINTPTRDIFFT"d)", CDR_TO_INT(t));    }    }else{ -  my_strcat("object"); +  string_builder_strcat(s, "object");    }    break;       case T_STRING:    {    INT32 min;    INT32 max;    t = t->car; -  my_strcat("string"); +     if (t->type == T_ZERO) { -  my_strcat("(zero)"); +  string_builder_strcat(s, "string(zero)");    } else if (t != int_type_string) { -  my_strcat("("); +  string_builder_strcat(s, "string(");    while (t->type == T_OR) {    struct pike_type *char_type = t->car;    while(char_type->type == T_ASSIGN) {    char_type = char_type->cdr;    } - #ifdef PIKE_DEBUG +     if (char_type->type != T_INT) { -  Pike_fatal("Invalid node type (%d:%s) in string type.\n", -  char_type->type, get_name_of_type(char_type->type)); -  } - #endif /* PIKE_DEBUG */ +  low_describe_type(s, char_type); +  } else {    min = CAR_TO_INT(char_type);    max = CDR_TO_INT(char_type); -  +  if (!min && max && max != MAX_INT32 && !(max & (max+1))) { +  int j = 0; +  while (max) { +  max >>= 1; +  j++; +  } +  string_builder_sprintf(s, "%dbit", j); +  } else {    if (min != MIN_INT32) { -  sprintf(buffer, "%d", min); -  my_strcat(buffer); +  string_builder_sprintf(s, "%d", min);    } -  my_strcat(".."); +  string_builder_strcat(s, "..");    if (max != MAX_INT32) { -  sprintf(buffer, "%d", max); -  my_strcat(buffer); +  string_builder_sprintf(s, "%d", max);    } -  my_strcat(" | "); +  } +  } +  string_builder_strcat(s, " | ");    t = t->cdr;    }    while(t->type == T_ASSIGN) {    t = t->cdr;    } - #ifdef PIKE_DEBUG +     if (t->type != T_INT) { -  Pike_fatal("Invalid node type (%d:%s) in string type.\n", -  t->type, get_name_of_type(t->type)); -  } - #endif /* PIKE_DEBUG */ +  low_describe_type(s, t); +  } else {    min = CAR_TO_INT(t);    max = CDR_TO_INT(t); -  +  if (!min && max && max != MAX_INT32 && !(max & (max+1))) { +  int j = 0; +  while (max) { +  max >>= 1; +  j++; +  } +  string_builder_sprintf(s, "%dbit", j); +  } else {    if (min != MIN_INT32) { -  sprintf(buffer, "%d", min); -  my_strcat(buffer); +  string_builder_sprintf(s, "%d", min);    } -  my_strcat(".."); +  string_builder_strcat(s, "..");    if (max != MAX_INT32) { -  sprintf(buffer, "%d", max); -  my_strcat(buffer); +  string_builder_sprintf(s, "%d", max);    } -  my_strcat(")"); +     } -  +  } +  string_builder_putchar(s, ')'); +  } else { +  string_builder_strcat(s, "string"); +  }    break;    }    case T_TYPE: -  my_strcat("type("); -  my_describe_type(t->car); -  my_strcat(")"); +  string_builder_sprintf(s, "type(%T)", t->car);    break;       case PIKE_T_NAME: -  if (!((struct pike_string *)t->car)->size_shift) { -  my_strcat("{ "); -  my_binary_strcat(((struct pike_string *)t->car)->str, -  ((struct pike_string *)t->car)->len); -  my_strcat(" = "); -  my_describe_type(t->cdr); -  my_strcat(" }"); -  } else { -  my_describe_type(t->cdr); -  } +  string_builder_sprintf(s, "{ %S = %T }", +  (struct pike_string *)t->car, t->cdr);    break;       case PIKE_T_ATTRIBUTE: -  if (!((struct pike_string *)t->car)->size_shift) { +  {    struct pike_string *deprecated;    MAKE_CONST_STRING(deprecated, "deprecated");    if (((struct pike_string *)t->car) == deprecated) { -  my_strcat("__deprecated__("); +  string_builder_sprintf(s, "__deprecated__(%T)", t->cdr);    } else { -  my_strcat("__attribute__(\""); -  my_binary_strcat(((struct pike_string *)t->car)->str, -  ((struct pike_string *)t->car)->len); -  my_strcat("\", "); +  struct svalue sval; +  SET_SVAL(sval, PIKE_T_STRING, 0, string, +  (struct pike_string *)t->car); +  string_builder_sprintf(s, "__attribute__(%O, %T)", &sval, t->cdr);    } -  my_describe_type(t->cdr); -  my_strcat(")"); -  } else { -  my_describe_type(t->cdr); +     }    break;       case T_FUNCTION:    case T_MANY:    { -  int s; -  my_strcat("function"); +     if(t->type == T_MANY &&    t->cdr->type == T_OR &&    ((t->cdr->car->type == T_MIXED && t->cdr->cdr->type == T_VOID) ||    (t->cdr->cdr->type == T_MIXED && t->cdr->car->type == T_VOID)) &&    (t->car->type == T_ZERO ||    (t->car->type == T_OR &&    ((t->car->car->type == T_ZERO && t->car->cdr->type == T_VOID) ||    (t->car->cdr->type == T_ZERO && t->car->car->type == T_VOID)))))    {    /* function == function(zero...:mixed|void) or    * function(zero|void...:mixed|void)    */ -  +  string_builder_strcat(s, "function");    /* done */ -  +  break;    } else { -  my_strcat("("); -  s=0; +  int arg = 0; +  string_builder_strcat(s, "function(");    while(t->type != T_MANY)    { -  if(s++) my_strcat(", "); -  my_describe_type(t->car); +  if(arg++) string_builder_strcat(s, ", "); +  low_describe_type(s, t->car);    t = t->cdr;    while(t->type == T_ASSIGN) { -  my_putchar('0' + CAR_TO_INT(t)); -  my_putchar('='); +  string_builder_sprintf(s, "%c=", '0' + CAR_TO_INT(t));    t = t->cdr;    }    }    if(t->car->type != T_VOID)    { -  if(s++) my_strcat(", "); -  my_describe_type(t->car); -  my_strcat(" ..."); +  if(arg++) string_builder_strcat(s, ", "); +  low_describe_type(s, t->car); +  string_builder_strcat(s, " ...");    } -  my_strcat(" : "); -  my_describe_type(t->cdr); -  my_strcat(")"); +  string_builder_sprintf(s, " : %T)", t->cdr);    }    break;    }       case T_ARRAY: -  my_strcat("array"); +     if(t->car->type != T_MIXED) { -  my_strcat("("); -  my_describe_type(t->car); -  my_strcat(")"); +  string_builder_sprintf(s, "array(%T)", t->car); +  } else { +  string_builder_strcat(s, "array");    }    break;       case T_MULTISET: -  my_strcat("multiset"); +     if(t->car->type != T_MIXED) { -  my_strcat("("); -  my_describe_type(t->car); -  my_strcat(")"); +  string_builder_sprintf(s, "multiset(%T)", t->car); +  } else { +  string_builder_strcat(s, "multiset");    }    break;       case T_NOT: -  my_strcat("!"); +     if (t->car->type > T_NOT) { -  my_strcat("("); -  my_describe_type(t->car); -  my_strcat(")"); +  string_builder_sprintf(s, "!(%T)", t->car);    } else { -  my_describe_type(t->car); +  string_builder_sprintf(s, "!%T", t->car);    }    break;       case PIKE_T_RING:    /* FIXME: Should be renumbered for correct parenthesing. */ -  my_strcat("("); -  my_describe_type(t->car); -  my_strcat(")°("); -  my_describe_type(t->cdr); -  my_strcat(")"); +  string_builder_sprintf(s, "(%T)\260(%T)", t->car, t->cdr);    break;       case T_OR:    if (t->car->type > T_OR) { -  my_strcat("("); -  my_describe_type(t->car); -  my_strcat(")"); +  string_builder_sprintf(s, "(%T)", t->car);    } else { -  my_describe_type(t->car); +  low_describe_type(s, t->car);    } -  my_strcat(" | "); +  string_builder_strcat(s, " | ");    if (t->cdr->type > T_OR) { -  my_strcat("("); -  my_describe_type(t->cdr); -  my_strcat(")"); +  string_builder_sprintf(s, "(%T)", t->cdr);    } else { -  my_describe_type(t->cdr); +  low_describe_type(s, t->cdr);    }    break;       case T_AND:    if (t->car->type > T_AND) { -  my_strcat("("); -  my_describe_type(t->car); -  my_strcat(")"); +  string_builder_sprintf(s, "(%T)", t->car);    } else { -  my_describe_type(t->car); +  low_describe_type(s, t->car);    } -  my_strcat(" & "); +  string_builder_strcat(s, " & ");    if (t->cdr->type > T_AND) { -  my_strcat("("); -  my_describe_type(t->cdr); -  my_strcat(")"); +  string_builder_sprintf(s, "(%T)", t->cdr);    } else { -  my_describe_type(t->cdr); +  low_describe_type(s, t->cdr);    }    break;       case T_MAPPING: -  my_strcat("mapping"); +     if(t->car->type != T_MIXED || t->cdr->type != T_MIXED) { -  my_strcat("("); -  my_describe_type(t->car); -  my_strcat(":"); -  my_describe_type(t->cdr); -  my_strcat(")"); +  string_builder_sprintf(s, "mapping(%T:%T)", t->car, t->cdr); +  } else { +  string_builder_strcat(s, "mapping");    }    break;    default:    { -  char buf[20]; -  my_strcat("unknown code("); -  sprintf(buf, "%d", t->type); -  my_strcat(buf); -  my_strcat(")"); +  string_builder_sprintf(s, "unknown code(%d)", t->type);    break;    }    }   }    - void my_describe_type(struct pike_type *type) - { -  low_describe_type(type); - } -  +    struct pike_string *describe_type(struct pike_type *type)   { -  dynamic_buffer save_buf; -  check_type_string(type); +  struct string_builder s; +  ONERROR err;    if(!type) return make_shared_string("mixed"); -  init_buf(&save_buf); -  low_describe_type(type); -  return free_buf(&save_buf); +  init_string_builder(&s, 0); +  SET_ONERROR(err, free_string_builder, &s); +  low_describe_type(&s, type); +  UNSET_ONERROR(err); +  return finish_string_builder(&s);   }         /******/    - static int low_is_same_type(struct pike_type *a, struct pike_type *b) - { -  return a == b; - } -  +    TYPE_T compile_type_to_runtime_type(struct pike_type *t)   {    switch(t->type)    {    case PIKE_T_RING:    return compile_type_to_runtime_type(t->car);       case T_OR:    {    TYPE_T tmp = compile_type_to_runtime_type(t->car);
pike.git/src/pike_types.c:2567:    case T_FUNCTION:       case T_STRING:    case T_TYPE:    case T_INT:    case T_FLOAT:    return t->type;    }   }    -  - static int low_find_exact_type_match(struct pike_type *needle, -  struct pike_type *haystack, -  unsigned int separator) - { -  while(haystack->type == separator) -  { -  if(low_find_exact_type_match(needle, haystack->car, separator)) -  return 1; -  haystack = haystack->cdr; -  } -  return low_is_same_type(needle, haystack); - } -  +    static void low_or_pike_types(struct pike_type *t1,    struct pike_type *t2,    int zero_implied);      /* Push either t1, t2 or the OR of t1 and t2.    * Returns -1 if t1 was pushed.    * 0 if the OR was pushed. (Successful join)    * 1 if t2 was pushed.    *    * zero_implied: One of:
pike.git/src/pike_types.c:3203:   #endif   static struct pike_type *low_match_types(struct pike_type *a,    struct pike_type *b,    int flags)   #ifdef PIKE_TYPE_DEBUG   {    int e;    char *s;       if (l_flag>2) { -  dynamic_buffer save_buf; -  init_buf(&save_buf); -  for(e=0;e<indent;e++) my_strcat(" "); -  my_strcat("low_match_types("); -  my_describe_type(a); -  my_strcat(",\n"); -  for(e=0;e<indent;e++) my_strcat(" "); -  my_strcat(" "); -  my_describe_type(b); -  my_strcat(",\n"); -  for(e=0;e<indent;e++) my_strcat(" "); -  my_strcat(" "); +  fprintf(stderr, "%*slow_match_types(", indent*2, ""); +  simple_describe_type(a); +  fprintf(stderr, ",\n"); +  fprintf(stderr, "%*s%s", indent*2, "", " "); +  simple_describe_type(b); +  fprintf(stderr, ",\n"); +  fprintf(stderr, "%*s%s", indent*2, "", " ");       if (flags) {    int f = 0;    if (flags & A_EXACT) { -  my_strcat("A_EXACT"); +  fprintf(stderr, "A_EXACT");    f = 1;    }    if (flags & B_EXACT) {    if (f) { -  my_strcat(" | "); +  fprintf(stderr, " | ");    } -  my_strcat("B_EXACT"); +  fprintf(stderr, "B_EXACT");    f = 1;    }    if (flags & NO_MAX_ARGS) {    if (f) { -  my_strcat(" | "); +  fprintf(stderr," | ");    } -  my_strcat("NO_MAX_ARGS"); +  fprintf(stderr, "NO_MAX_ARGS");    f = 1;    }    if (flags & NO_SHORTCUTS) {    if (f) { -  my_strcat(" | "); +  fprintf(stderr, " | ");    } -  my_strcat("NO_SHORTCUTS"); +  fprintf(stderr, "NO_SHORTCUTS");    f = 1;    }    } else { -  my_strcat("0"); +  fputc('0', stderr);    } -  my_strcat(");\n"); -  fprintf(stderr,"%s",(s=simple_free_buf(&save_buf))); -  free(s); +  fprintf(stderr, ");\n");    indent++;    }       a = low_match_types2(a, b, flags);       if (l_flag>2) { -  dynamic_buffer save_buf; +     indent--; -  init_buf(&save_buf); -  for(e=0;e<indent;e++) my_strcat(" "); -  my_strcat("= "); +  fprintf(stderr, "%*s= ", indent*2, "");    if(a) -  my_describe_type(a); +  simple_describe_type(a);    else -  my_strcat("NULL"); -  my_strcat("\n"); -  fprintf(stderr,"%s",(s=simple_free_buf(&save_buf))); -  free(s); +  fprintf(stderr, "NULL"); +  fputc('\n', stderr);    }    return a;   }      static struct pike_type *low_match_types2(struct pike_type *a,    struct pike_type *b,    int flags)   #endif   {    int correct_args;
pike.git/src/pike_types.c:3341:    tmp = pop_unfinished_type();       type_stack_mark();    low_or_pike_types(a_markers[m], tmp, 0);    if(a_markers[m]) free_type(a_markers[m]);    free_type(tmp);    a_markers[m] = pop_unfinished_type();      #ifdef PIKE_TYPE_DEBUG    if (l_flag>2) { -  dynamic_buffer save_buf; -  char *s; -  int e; -  init_buf(&save_buf); -  for(e=0;e<indent;e++) my_strcat(" "); -  my_strcat("a_markers["); -  my_putchar((char)(m+'0')); -  my_strcat("]="); -  my_describe_type(a_markers[m]); -  my_strcat("\n"); -  fprintf(stderr,"%s",(s=simple_free_buf(&save_buf))); -  free(s); +  fprintf(stderr, "%*sa_markers[%d]=", +  indent*2, "", m); +  simple_describe_type(a_markers[m]); +  fputc('\n', stderr);    }   #endif   #ifdef PIKE_DEBUG    if(a_markers[m]->type == m+'0')    Pike_fatal("Cyclic type!\n");   #endif    }    return ret;    }    case '0': case '1': case '2': case '3': case '4':
pike.git/src/pike_types.c:3444:    push_finished_type_with_markers(a, a_markers, 0);    tmp=pop_unfinished_type();       type_stack_mark();    low_or_pike_types(b_markers[m], tmp, 0);    if(b_markers[m]) free_type(b_markers[m]);    free_type(tmp);    b_markers[m] = pop_unfinished_type();   #ifdef PIKE_TYPE_DEBUG    if (l_flag>2) { -  dynamic_buffer save_buf; -  char *s; -  int e; -  init_buf(&save_buf); -  for(e=0;e<indent;e++) my_strcat(" "); -  my_strcat("b_markers["); -  my_putchar((char)(m+'0')); -  my_strcat("]="); -  my_describe_type(b_markers[m]); -  my_strcat("\n"); -  fprintf(stderr,"%s",(s=simple_free_buf(&save_buf))); -  free(s); +  fprintf(stderr, "%*sb_markers[%d]=", +  indent*2, "", m); +  simple_describe_type(b_markers[m]); +  fputc('\n', stderr);    }   #endif   #ifdef PIKE_DEBUG    if(b_markers[m]->type == m+'0')    Pike_fatal("Cyclic type!\n");   #endif    }    return ret;    }    case '0': case '1': case '2': case '3': case '4':
pike.git/src/pike_types.c:3718: Inside #if 0
   stupid_describe_type(b,type_length(b));    }   #endif       /* object(* 0) matches any object */    if(!a->cdr || !b->cdr) break;       /* object(* x) =? object(* x) */    if (a->cdr == b->cdr) break;    -  /* object(x *) =? object(x *) */ -  if(TEST_COMPAT(7,4) && a->car == b->car) -  { -  /* x? */ -  if(a->car) -  { -  /* object(1 x) =? object(1 x) */ -  return 0; -  }else{ -  /* object(0 *) =? object(0 *) */ -  break; -  } -  } -  +     /* Note: In Pike 7.4 and earlier the following was only done    * when a->car != b->car.    */    {    struct program *ap,*bp;    ap = id_to_program(CDR_TO_INT(a));    bp = id_to_program(CDR_TO_INT(b));       if(!ap || !bp) break;   
pike.git/src/pike_types.c:4278:    if (array_cnt >= 0) {    /* !array(mixed) */    return 0;    }    }       if (a->type == T_ZERO) {    /* void <= zero <= any_type */    if (array_cnt >= 0) {    /* !array(zero) */ +  if (!(flags & LE_EXPLICIT_ZERO) || +  ((b->type == T_INT) && !array_cnt)) {    return 1;    }    } -  +  }       if (b->type == T_ZERO) {    if (array_cnt <= 0) {    /* !array(zero) */    return 0;    }    }       /* Special cases (tm) */    switch(TWOT(a->type, b->type))
pike.git/src/pike_types.c:4485:    if(!b->cdr)    return 1;       if(!a->cdr)    return 0;       /* The 'is' flag is now ignored.    * /grubba 2003-11-11    */    -  if (TEST_COMPAT(7,4)) { -  if ((a->car || !b->car) && -  (a->cdr == b->cdr)) -  return 1; -  -  if (b->car) { -  return 0; -  } -  } -  else { +     if (a->cdr == b->cdr)    return 1; -  } +        {    struct program *ap = id_to_program(CDR_TO_INT(a));    struct program *bp = id_to_program(CDR_TO_INT(b));      #if 0    fprintf(stderr,    "id_to_program(%d) ==> %p\n"    "id_to_program(%d) ==> %p\n",    CDR_TO_INT(a), ap,    CDR_TO_INT(b), bp);   #endif /* 0 */       if (!ap || !bp) {    /* Shouldn't happen... */    /* fprintf(stderr, "ap:%p bp:%p\n", ap, bp); */    return 0;    } -  if ((flags & LE_WEAK_OBJECTS) && -  (!TEST_COMPAT(7,4) || (!a->car))) { +  if ((flags & LE_WEAK_OBJECTS) && !a->car) {    implements_mode = 0;   #if 0    fprintf(stderr, " is_compat(%p(%d), %p(%d))\n",    ap, ap->id, bp, bp->id);   #endif /* 0 */    return is_compatible(implements_a=ap, implements_b=bp);    }    implements_mode = 1;   #if 0    fprintf(stderr, " implements(%p(%d), %p(%d))\n",
pike.git/src/pike_types.c:4714:    push_type(T_MIXED);    return 1;    }    }    return 0;   }         int match_types(struct pike_type *a, struct pike_type *b)   { -  check_type_string(a); -  check_type_string(b); +     clear_markers();    return !!low_match_types(a, b, 0);   }      int pike_types_le(struct pike_type *a,struct pike_type *b)   { -  check_type_string(a); -  check_type_string(b); +     clear_markers();    return low_pike_types_le(a, b, 0, 0);   }         #ifdef DEBUG_MALLOC   #define low_index_type(X,Y,Z) ((struct pike_type *)debug_malloc_pass(debug_low_index_type((X),(Y),(Z))))   #else   #define low_index_type debug_low_index_type   #endif
pike.git/src/pike_types.c:4759:       switch(low_check_indexing(t, index_type, n))    {    case 0: return 0;    case -1:    add_ref(zero_type_string);    return zero_type_string;    }       while((t->type == PIKE_T_NAME) || -  (t->type == PIKE_T_ATTRIBUTE)) { +  (t->type == PIKE_T_ATTRIBUTE) || +  (t->type == T_ASSIGN) || +  (t->type == T_SCOPE)) {    t = t->cdr;    }    while((index_type->type == PIKE_T_NAME) || -  (index_type->type == PIKE_T_ATTRIBUTE)) { +  (index_type->type == PIKE_T_ATTRIBUTE) || +  (index_type->type == T_ASSIGN) || +  (index_type->type == T_SCOPE)) {    index_type = index_type->cdr;    }       switch(t->type)    {    case T_OBJECT:    {    p = id_to_program(CDR_TO_INT(t));       comefrom_int_index:
pike.git/src/pike_types.c:4825:    {    add_ref(mixed_type_string);    return mixed_type_string;    }else{    add_ref(ID_FROM_INT(p, i)->type);    return ID_FROM_INT(p, i)->type;    }    }    }    } +  /* FALL_THROUGH */ +     default:    add_ref(mixed_type_string);    return mixed_type_string;       case T_MIXED:    if (pragmas & ID_STRICT_TYPES) {    yywarning("Indexing mixed.");    }    add_ref(mixed_type_string);    return mixed_type_string;       case T_INT: - #ifdef AUTO_BIGNUM -  /* Don't force Gmp.mpz to be loaded here since this function -  * is called long before the master object is compiled... -  * /Hubbe -  */ -  p=get_auto_bignum_program_or_zero(); +  p=bignum_program;    goto comefrom_int_index; - #endif +     case T_ZERO:    case T_TYPE:    case PIKE_T_RING:    case T_VOID:    case T_FLOAT:    return 0;       case T_OR:    {    struct pike_type *a,*b;
pike.git/src/pike_types.c:5206:    if(p && n)    {    if(n->token == F_ARROW)    {    int i;    if((i = FIND_LFUN(p,LFUN_ARROW))!=-1 ||    (i = FIND_LFUN(p,LFUN_ASSIGN_ARROW))!=-1)    {    /* Get the type of the first argument of the function. */    struct pike_type *res = -  get_first_arg_type(ID_FROM_INT(p, i)->type, 0); +  get_first_arg_type(ID_FROM_INT(p, i)->type, CALL_NOT_LAST_ARG);    if (res) return res;    /* FIXME: Warn? */    add_ref(string_type_string);    return string_type_string;    }    }else{    int i;    if((i = FIND_LFUN(p,LFUN_INDEX)) != -1 ||    (i = FIND_LFUN(p,LFUN_ASSIGN_INDEX)) != -1)    {    /* Get the type of the first argument of the function. */    struct pike_type *res = -  get_first_arg_type(ID_FROM_INT(p, i)->type, 0); +  get_first_arg_type(ID_FROM_INT(p, i)->type, CALL_NOT_LAST_ARG);    if (res) return res;    /* FIXME: Warn? */    add_ref(mixed_type_string);    return mixed_type_string;    }    }    }    add_ref(string_type_string);    return string_type_string;    }
pike.git/src/pike_types.c:5312:       case T_AND:    return low_check_indexing(type->car, index_type, n) &&    low_check_indexing(type->cdr, index_type, n);       case T_NOT:    return low_check_indexing(type->car, index_type, n) != 1;       case PIKE_T_NAME:    case PIKE_T_ATTRIBUTE: +  case T_ASSIGN: +  case T_SCOPE:    return low_check_indexing(type->cdr, index_type, n);       case T_ARRAY:    if(low_match_types(string_type_string, index_type, 0) &&    low_check_indexing(type->car, index_type, n))    return 1;    /* FALL_THROUGH */    case T_STRING:    return !!low_match_types(int_type_string, index_type, 0);       case T_OBJECT:    {    struct program *p = id_to_program(CDR_TO_INT(type));    if(p)    {    int i = -1;    /* Check against the LFUN types. */ -  if(n->token == F_ARROW) +  if(n && (n->token == F_ARROW))    {    (i = FIND_LFUN(p,LFUN_ARROW))!=-1 ||    (i = FIND_LFUN(p,LFUN_ASSIGN_ARROW));    }else{    (i = FIND_LFUN(p,LFUN_INDEX))!=-1 ||    (i = FIND_LFUN(p,LFUN_ASSIGN_INDEX));    }    if (i != -1) {    if ((type = low_new_check_call(ID_FROM_INT(p, i)->type, index_type, -  0, NULL))) { +  CALL_NOT_LAST_ARG, NULL))) {    free_type(type);    return 1;    }    return 0;    }    return !!low_match_types(string_type_string, index_type,0);    }else{    return 1;    }    }       case T_MULTISET:    case T_MAPPING:    /* FIXME: Why -1 and not 0?    *    * - There were complaints when people got compilation errors    * for indexing operations that would always fail.    */    return low_match_types(type->car, index_type, 0) ? 1 : -1;    - #ifdef AUTO_BIGNUM +  case T_FUNCTION: +  while ((type = type->cdr) && (type->type == T_FUNCTION)) +  ; +  if (!type) return 0; +  +  /* FALL_THROUGH */ +  +  case T_MANY: +  type = type->cdr; +  if (!type || (type->type != T_OBJECT) || !type->car) +  return 0; +  /* function(... : object(is foo)) -- ie probably program(foo). */ +  +  /* FALL_THROUGH */ +     case T_INT: - #endif +     case T_PROGRAM:    return !!low_match_types(string_type_string, index_type, 0);       case T_MIXED:    return 1;       default:    return 0;    }   }      int check_indexing(struct pike_type *type,    struct pike_type *index_type,    node *n)   { -  check_type_string(type); -  check_type_string(index_type); -  +     return low_check_indexing(type, index_type, n);   }      static int low_count_arguments(struct pike_type *q)   {    int num=0, num2;       switch(q->type)    {    case T_OR:
pike.git/src/pike_types.c:5408:    case T_AND:    num = low_count_arguments(q->car);    num2 = low_count_arguments(q->cdr);    if(num<0 && num2>0) return num2;    if(num2<0 && num>0) return num;    if(num2<0 && num<0) return ~num<~num2?num:num2;    return num<num2?num:num2;       case PIKE_T_NAME:    case PIKE_T_ATTRIBUTE: +  case T_ASSIGN: +  case T_SCOPE:    return low_count_arguments(q->cdr);       default: return MAX_INT32;       case T_FUNCTION:    while(q->type == T_FUNCTION)    {    num++;    q = q->cdr;    }
pike.git/src/pike_types.c:5432:    return num;    }   }      /* Count the number of arguments for a funciton type.    * return -1-n if the function can take number of arguments    * >= n (varargs)    */   int count_arguments(struct pike_type *s)   { -  check_type_string(s); -  +     return low_count_arguments(s);   }         static int low_minimum_arguments(struct pike_type *q)   {    int num;       switch(q->type)    {    case T_OR:    case T_AND:    return MAXIMUM(low_count_arguments(q->car),    low_count_arguments(q->cdr));       default: return 0;       case PIKE_T_NAME:    case PIKE_T_ATTRIBUTE: -  +  case T_ASSIGN: +  case T_SCOPE:    return low_minimum_arguments(q->cdr);       case T_FUNCTION:    num = 0;    while(q->type == T_FUNCTION)    {    if(low_match_types(void_type_string, q->car, B_EXACT))    return num;       num++;
pike.git/src/pike_types.c:5476:    case T_MANY:    return 0;    }   }      /* Count the minimum number of arguments for a function type.    */   int minimum_arguments(struct pike_type *s)   {    int ret; -  check_type_string(s); +        ret = low_minimum_arguments(s);      #if 0    fprintf(stderr,"minimum_arguments(");    simple_describe_type(s);    fprintf(stderr," ) -> %d\n",ret);   #endif       return ret;   }      struct pike_type *check_call(struct pike_type *args,    struct pike_type *type,    int strict)   { -  check_type_string(args); -  check_type_string(type); +     clear_markers();    type_stack_mark();    max_correct_args=0;       if(low_get_return_type(type, args))    {    if (strict) {    if (!strict_check_call(type, args)) {    struct pike_type *func_zero_type;   
pike.git/src/pike_types.c:5533:    return 0;    }   }      /* Get the type for the specified argument in a function type.    * Argument number -1 is the return type.    * True arguments are counted from zero.    */   struct pike_type *get_argument_type(struct pike_type *fun, int arg_no)   { +  struct pike_type *tmp; +     loop:    switch(fun->type) {    case T_OR:    return or_pike_types(get_argument_type(fun->car, arg_no),    get_argument_type(fun->cdr, arg_no),    1);    case T_FUNCTION:    if (arg_no > 0) {    arg_no--;    fun = fun->cdr;
pike.git/src/pike_types.c:5568:    case T_ARRAY:    if (arg_no < 0) {    type_stack_mark();    push_finished_type(fun = get_argument_type(fun->car, arg_no));    push_type(T_ARRAY);    free_type(fun);    return pop_unfinished_type();    }    return get_argument_type(fun->car, arg_no);    +  case PIKE_T_ATTRIBUTE: +  type_stack_mark(); +  push_finished_type(tmp = get_argument_type(fun->cdr, arg_no)); +  push_type_attribute((struct pike_string *)(fun->car)); +  free_type(tmp); +  return pop_unfinished_type(); +  +  case PIKE_T_SCOPE: +  case T_ASSIGN: +  case PIKE_T_NAME: +  fun = fun->cdr; +  goto loop; +     default: -  + #if 0 +  fprintf(stderr, +  "Failed to resolve argument type for argument %d.\n" +  "Type: ", +  arg_no); +  simple_describe_type(fun); +  fprintf(stderr, "\n" +  "Node type: %d\n", +  fun->type); + #endif    add_ref(zero_type_string);    return zero_type_string;    }   }      /* Get the resulting type from a soft cast.    *    * Flags:    * 1 SOFT_WEAKER Weaker type.    */
pike.git/src/pike_types.c:5980:    }    break;    }    }    if (tmp) free_type(tmp);    if (tmp2) free_type(tmp2);    if (tmp3) free_type(tmp3);    return res;   }    + /** +  * Check whether sval is a valid value for a variable of +  * type type. +  * +  * Returns 1 if ok, and 0 (zero) otherwise. +  */ + static int match_type_svalue(struct pike_type *type, +  int flags, +  struct svalue *sval) + { +  int res = 0; +  struct pike_type *sub; +  loop: +  switch(type->type) { +  case T_SCOPE: +  case T_ASSIGN: +  case PIKE_T_NAME: +  case PIKE_T_ATTRIBUTE: +  type = type->cdr; +  goto loop; +  case T_OR: +  res = match_type_svalue(type->car, 0, sval) || +  match_type_svalue(type->cdr, 0, sval); +  break; +  case T_AND: +  res = match_type_svalue(type->car, 0, sval) && +  match_type_svalue(type->cdr, 0, sval); +  break; +  case T_NOT: +  flags ^= CALL_INVERTED_TYPES; +  type = type->car; +  goto loop; +  case T_VOID: +  /* Allow UNDEFINED for voidable arguments. */ +  res = (TYPEOF(*sval) == T_INT) && !sval->u.integer && SUBTYPEOF(*sval); +  break; +  case T_ZERO: +  res = SAFE_IS_ZERO(sval); +  break; +  case PIKE_T_TYPE: +  res = 1; +  break; +  case PIKE_T_PROGRAM: +  case PIKE_T_FUNCTION: +  case T_MANY: +  { +  struct pike_type *t = NULL; +  /* Identify if sval is callable. */ +  if (TYPEOF(*sval) == PIKE_T_OBJECT) { +  struct program *p; +  int f; +  struct identifier *id; +  if (!sval->u.object || !(p = sval->u.object->prog)) break; +  p = p->inherits[SUBTYPEOF(*sval)].prog; +  if ((f = FIND_LFUN(p, LFUN_CALL)) == -1) break; +  id = ID_FROM_INT(p, f); +  t = id->type; +  res = 1; +  } else { +  res = +  (TYPEOF(*sval) == T_FUNCTION) || +  (TYPEOF(*sval) == T_PROGRAM) || +  (TYPEOF(*sval) == T_ARRAY) || +  (TYPEOF(*sval) == T_TYPE); +  } +  /* FIXME: Check arguments */ +  /* FIXME: Check return type */ +  } +  break; +  case PIKE_T_MIXED: +  res = 1; +  break; +  case PIKE_T_OBJECT: +  if( TYPEOF( *sval ) == PIKE_T_OBJECT ) +  { +  struct object *o = sval->u.object; +  if( o->prog ) +  { +  if( !type->cdr ) +  { +  res = 1; +  } +  else +  { +  struct program *mark = id_to_program( CDR_TO_INT( type ) ); +  if( mark == o->prog ) +  res = 1; +  else if( type->car ) +  res = is_compatible( o->prog, mark ); +  else +  res = implements( o->prog, mark ); +  } +  } +  } +  break; +  case PIKE_T_STRING: +  if( TYPEOF( *sval ) == PIKE_T_STRING ) +  { +  sub = type->car; +  if (sub->type == T_ZERO) +  { +  res = (sval->u.string->len == 0); +  break; +  } +  else if( sub->type == PIKE_T_INT ) +  { +  struct pike_string *s = sval->u.string; +  INT32 min = CAR_TO_INT( sub ), max = CDR_TO_INT( sub ); +  INT32 string_min, string_max; +  int checked = 0; +  +  check_string_range( s, 1, &string_min, &string_max ); +  +  if( min != MIN_INT32 ) +  { +  if( string_min < min ) +  { +  if( s->size_shift ) +  check_string_range( s, 0, &string_min, &string_max ); +  if( string_min < min ) +  goto do_return; +  checked = 1; +  } +  } +  +  if( max != MIN_INT32 ) +  { +  if( string_max > max ) +  { +  if( s->size_shift && !checked ) +  check_string_range( s, 0, NULL, &string_max ); +  +  if( string_max > max ) +  goto do_return; +  } +  } +  } +  res = 1; +  } +  break; +  case PIKE_T_INT: +  if( TYPEOF( *sval ) == PIKE_T_INT ) +  { +  INT_TYPE current = sval->u.integer; +  INT32 min, max; +  min = CAR_TO_INT( type ); +  max = CDR_TO_INT( type ); +  if( min != MIN_INT32 ) +  { +  if( current < min ) +  break; +  } +  if( max != MAX_INT32 ) +  { +  if( current > max ) +  break; +  } +  res = 1; +  } +  /* FIXME: Objects that emulate integers? */ +  else if( TYPEOF(*sval) == PIKE_T_OBJECT ) +  { +  if( is_bignum_object(sval->u.object) ) +  { +  INT32 min = CAR_TO_INT( type ); +  INT32 max = CDR_TO_INT( type ); +  if( min != MIN_INT32 && max != MAX_INT32 ) +  { +  struct svalue tmp; +  TYPEOF(tmp)=PIKE_T_INT; +  if( min != MIN_INT32 ) +  { +  tmp.u.integer = min; +  if( is_lt( sval, &tmp ) ) +  break; +  } +  if( max != MAX_INT32 ) +  { +  tmp.u.integer = max; +  if( is_gt( sval, &tmp ) ) +  break; +  } +  } +  res = 1; +  } +  } +  break; +  default: +  res = (type->type == TYPEOF(*sval)); +  break; +  } +  do_return: +  if (flags & CALL_INVERTED_TYPES) return !res; +  return res; + } +  + /** +  * Check whether sval is a valid first argument to fun_type. +  * +  * Returns NULL on failure. +  * +  * Returns continuation function type on success. +  */ + struct pike_type *check_call_svalue(struct pike_type *fun_type, +  INT32 flags, +  struct svalue *sval) + { +  struct pike_type *res = NULL; +  struct pike_type *tmp; +  struct pike_type *tmp2; +  INT32 array_cnt = 0; +  + #ifdef PIKE_DEBUG +  if (Pike_interpreter.trace_level > 2) { +  fprintf(stderr, " check_call_svalue("); +  simple_describe_type(fun_type); +  fprintf(stderr, ", 0x%08x, ", flags); +  debug_describe_svalue(sval); +  fprintf(stderr, ")...\n"); +  } + #endif /* PIKE_DEBUG */ +  +  loop: +  /* Count the number of array levels. */ +  while(fun_type->type == PIKE_T_ARRAY) { +  array_cnt++; +  fun_type = fun_type->car; +  } +  +  switch(fun_type->type) { +  case T_SCOPE: +  /* FIXME: Save and restore the corresponding marker set. */ +  case T_ASSIGN: +  case PIKE_T_NAME: +  fun_type = fun_type->cdr; +  goto loop; +  +  case PIKE_T_ATTRIBUTE: +  fun_type = fun_type->cdr; +  goto loop; +  +  case T_OR: +  res = check_call_svalue(fun_type->car, flags, sval); +  if (!res) { +  fun_type = fun_type->cdr; +  goto loop; +  } +  tmp = check_call_svalue(fun_type->cdr, flags, sval); +  if (!tmp) break; +  res = or_pike_types(tmp2 = res, tmp, 1); +  free_type(tmp); +  free_type(tmp2); +  break; +  +  case T_AND: +  res = check_call_svalue(fun_type->car, flags, sval); +  if (!res) break; +  tmp = check_call_svalue(fun_type->cdr, flags, sval); +  if (!tmp) { +  free_type(res); +  res = NULL; +  break; +  } +  if (res == tmp) { +  /* Common case. */ +  free_type(tmp); +  break; +  } +  /* and_pike_types() doesn't handle and of functions +  * in the way we want here. +  */ +  type_stack_mark(); +  push_finished_type(tmp); +  push_finished_type(res); +  push_type(T_AND); +  free_type(tmp); +  free_type(res); +  res = pop_unfinished_type(); +  break; +  +  case T_NOT: +  fun_type = fun_type->car; +  flags ^= CALL_INVERTED_TYPES; +  goto loop; +  +  case PIKE_T_TYPE: +  /* FIXME: Check that the cast is valid. */ +  type_stack_mark(); +  push_finished_type(fun_type->car); +  push_type(T_VOID); +  push_type(T_MANY); +  res = pop_unfinished_type(); +  break; +  +  case PIKE_T_PROGRAM: +  tmp = low_object_lfun_type(fun_type->car, LFUN_CREATE); +  if (!tmp) { +  /* No create() -- No arguments. */ +  /* FIXME: Multiple cases: +  * Untyped object. function(mixed|void...:obj) +  * Failed to lookup program id. function(mixed|void...:obj) +  * Program does not have a create(). function(:obj) +  * +  * We simply ignore the args. +  */ +  +  type_stack_mark(); +  push_finished_type(fun_type->car); +  push_type(T_MIXED); +  push_type(T_VOID); +  push_type(T_OR); +  push_type(T_MANY); +  fun_type = pop_unfinished_type(); +  } else { +  fun_type = zzap_function_return(tmp, fun_type->car); +  } +  res = check_call_svalue(fun_type, flags, sval); +  free_type(fun_type); +  break; +  +  case PIKE_T_OBJECT: +  fun_type = low_object_lfun_type(fun_type, LFUN_CALL); +  if (fun_type) goto loop; +  +  /* FIXME: Multiple cases: +  * Untyped object. mixed +  * Failed to lookup program id. mixed +  * Program does not have the lfun `()(). NULL +  */ +  +  /* FALL_THROUGH */ +  case PIKE_T_MIXED: +  copy_pike_type(res, mixed_type_string); +  break; +  +  case PIKE_T_FUNCTION: +  /* Note: Use the low variants of pike_types_le and match_types, +  * so that markers get set and kept. */ +  if (match_type_svalue(fun_type->car, flags, sval)) { +  add_ref(res = fun_type->cdr); +  break; +  } +  res = NULL; +  break; +  case T_MANY: +  /* Note: Use the low variants of pike_types_le and match_types, +  * so that markers get set and kept. */ +  if (match_type_svalue(fun_type->car, flags, sval)) { +  add_ref(res = fun_type); +  break; +  } +  res = NULL; +  break; +  default: +  /* Not a callable. */ +  break; +  } +  +  if (!array_cnt || !res) { + #ifdef PIKE_DEBUG +  if (Pike_interpreter.trace_level > 2) { +  if (res) { +  fprintf(stderr, " ==> "); +  simple_describe_type(res); +  } else { +  fprintf(stderr, " ==> NULL"); +  } +  fprintf(stderr, "\n"); +  } + #endif /* PIKE_DEBUG */ +  return res; +  } +  +  type_stack_mark(); +  push_finished_type(res); +  free_type(res); +  while(array_cnt--) { +  push_type(PIKE_T_ARRAY); +  } +  res = pop_type(); +  + #ifdef PIKE_DEBUG +  if (Pike_interpreter.trace_level > 2) { +  fprintf(stderr, " ==> "); +  simple_describe_type(res); +  fprintf(stderr, "\n"); +  } + #endif /* PIKE_DEBUG */ +  +  return res; + } +    /* Check whether arg_type may be used as the type of the first argument    * in a call to fun_type.    *    * The first argument has no OR or AND nodes.    *    * Returns NULL on failure.    *    * Returns continuation function type on success.    */   static struct pike_type *lower_new_check_call(struct pike_type *fun_type,
pike.git/src/pike_types.c:6100:    free_type(tmp);    free_type(res);    res = pop_unfinished_type();    break;       case T_NOT:    if (arg_type->type == T_NOT) {    /* Both sides are inverted. Pop both inversions. */    arg_type = arg_type->car;    fun_type = fun_type->car; +  flags ^= CALL_INVERTED_TYPES;    goto loop;    } else {    /* Move the inversion to the argument type. */    type_stack_mark();    push_finished_type(arg_type);    push_type(T_NOT);    arg_type = pop_unfinished_type(); -  res = lower_new_check_call(fun_type->car, arg_type, flags, sval CHECK_CALL_ARGS); +  res = lower_new_check_call(fun_type->car, arg_type, +  flags ^ CALL_INVERTED_TYPES, +  sval CHECK_CALL_ARGS);    free_type(arg_type);    if (res) {    /* Move the inversion back to the function type. */    if (res->type == T_NOT) {    tmp = res->car;    free_type(res);    res = tmp;    } else {    type_stack_mark();    if ((res->type == T_MANY) &&
pike.git/src/pike_types.c:6137:    push_finished_type(mixed_type_string);    free_type(res);    } else {    /* More arguments to check. */    push_finished_type(res);    free_type(res);    push_type(T_NOT);    }    res = pop_unfinished_type();    } -  } else if (!(flags & CALL_LAST_ARG) && +  } else if ((flags & CALL_NOT_LAST_ARG) &&    (fun_type->car->type == T_MANY)) {    /* The next argument might match. */    add_ref(fun_type);    res = fun_type;    }    }    break;       case PIKE_T_TYPE:    /* FIXME: Check that the cast is valid. */
pike.git/src/pike_types.c:6202:    case PIKE_T_MIXED:    copy_pike_type(res, mixed_type_string);    break;       case PIKE_T_FUNCTION:    case T_MANY:    /* Special case to detect workarounds for the old    * function call checker.    */    tmp = NULL; -  if ((fun_type->car->type == T_NOT) && +  if (((arg_type->type != T_NOT) || +  (arg_type->car->type != T_MIXED)) && +  (fun_type->car->type == T_NOT) &&    (fun_type->car->car->type == T_OR) &&    ((fun_type->car->car->car->type == T_MIXED) ||    (fun_type->car->car->cdr->type == T_MIXED))) {    /* Rebuild the function type without the negated mixed    * in the first argument.    */    type_stack_mark();    push_finished_type(fun_type->cdr);    if (fun_type->car->car->car->type == T_MIXED) {    push_finished_type(fun_type->car->car->cdr);
pike.git/src/pike_types.c:6233: Inside #if defined(PIKE_DEBUG)
   if (l_flag>2) {    fprintf(stderr, "%*sChecking argument type ", indent*2+2, "");    simple_describe_type(arg_type);    fprintf(stderr, " against function type ");    simple_describe_type(fun_type);    fprintf(stderr, ".\n");    }   #endif /* PIKE_DEBUG */    /* No need to perform advanced checking in the trivial case... */    if (arg_type != (tmp2 = fun_type->car)) { -  if ((flags & CALL_7_6) && (arg_type == void_type_string)) { -  /* Compat with Pike 7.6 and earlier. */ -  arg_type = zero_type_string; -  } -  -  if (!low_pike_types_le(arg_type, tmp2, 0, 0) && +  if (!((flags & CALL_INVERTED_TYPES)? +  low_pike_types_le(tmp2, arg_type, 0, +  LE_A_B_SWAPPED|LE_EXPLICIT_ZERO): +  low_pike_types_le(arg_type, tmp2, 0, 0)) &&    ((flags & CALL_STRICT) ||    !low_match_types(arg_type, tmp2, NO_SHORTCUTS))) {    /* No match. */   #ifdef PIKE_DEBUG    if (l_flag>2) {    fprintf(stderr, "%*sNo match.\n", indent*2+2, "");    }   #endif /* PIKE_DEBUG */    res = NULL;    if (tmp) free_type(tmp);    break;    }    }    /* Match. */    if (fun_type->type == PIKE_T_FUNCTION) {    /* Advance to the next argument. */    fun_type = fun_type->cdr; -  if ((flags & CALL_LAST_ARG) && -  (fun_type->type == PIKE_T_FUNCTION)) { + #if 0 +  /* This test is too strict, and causes the type checker +  * to complain about the last argument (even if correct) +  * when there are too few arguments to the function. +  */ +  if (!(flags & CALL_NOT_LAST_ARG) && +  (fun_type->type == PIKE_T_FUNCTION) && +  !low_match_types(fun_type->car, void_type_string, 0)) {    /* There are more required arguments. */   #ifdef PIKE_DEBUG    if (l_flag>2) {    fprintf(stderr, "%*sMore arguments required.\n", indent*2+2, "");    }   #endif /* PIKE_DEBUG */    res = NULL;    if (tmp) free_type(tmp);    break;    } -  + #endif /* 0 */    }    type_stack_mark();    push_finished_type_with_markers(fun_type, b_markers, 0);    res = pop_unfinished_type();    if (tmp) free_type(tmp);       if ((Pike_compiler->compiler_pass == 2) && sval) {    while (tmp2->type == PIKE_T_NAME) {    tmp2 = tmp2->cdr;    }
pike.git/src/pike_types.c:6431:    flags & ~CALL_WEAK_VOID, sval))) {    free_type(tmp);    return NULL;    }    res = and_pike_types(tmp, tmp2);    free_type(tmp);    free_type(tmp2);    return res;       case T_VOID: -  if (!(flags & CALL_7_6)) { +     if ((flags & (CALL_WEAK_VOID|CALL_STRICT)) == CALL_STRICT) {    return NULL;    }    /* Promote void arguments to zero. */    arg_type = zero_type_string; -  } +     break;    }       if (!(tmp = lower_new_check_call(fun_type, arg_type,    flags & ~CALL_WEAK_VOID, sval   #ifdef PIKE_TYPE_DEBUG    , 0   #endif    ))) { -  +  struct pike_type *tmp2; +  if (!(flags & CALL_STRICT) || (arg_type->type != T_INT) || +  (CAR_TO_INT(arg_type) >= 0) || (CDR_TO_INT(arg_type) <= 0)) {    return NULL;    } -  +  /* KLUDGE: Special case for integers spanning zero. +  * +  * Try splitting the argument at zero. The proper fix would be +  * to split at all the integer range limits for the first +  * declared argument to the function. +  * +  * Test the most likely problematic range first (ie negative). +  */ +  type_stack_mark(); +  push_int_type(CAR_TO_INT(arg_type), -1); +  tmp2 = pop_unfinished_type(); +  if (!(tmp = lower_new_check_call(fun_type, tmp2, +  flags & ~CALL_WEAK_VOID, sval + #ifdef PIKE_TYPE_DEBUG +  , 0 + #endif +  ))) { +  free_type(tmp2); +  return NULL; +  } +  free_type(tmp2); +  +  type_stack_mark(); +  push_finished_type(tmp); +  free_type(tmp); +  +  /* Then the positive range. */ +  type_stack_mark(); +  push_int_type(1, CDR_TO_INT(arg_type)); +  tmp2 = pop_unfinished_type(); +  if (!(tmp = lower_new_check_call(fun_type, tmp2, +  flags & ~CALL_WEAK_VOID, sval + #ifdef PIKE_TYPE_DEBUG +  , 0 + #endif +  ))) { +  free_type(tmp2); +  free_type(pop_unfinished_type()); +  return NULL; +  } +  free_type(tmp2); +  +  push_finished_type(tmp); +  free_type(tmp); +  +  /* NB: Zero always succeeds. */ +  push_type(T_OR); +  tmp = pop_unfinished_type(); +  }    return tmp;   }      /* Return the return type for the function type fun_type, if    * no further arguments are passed.    *    * Returns NULL if more arguments are required.    *    * Returns a the type of the return value otherwise.    */
pike.git/src/pike_types.c:6557:    if (!(tmp = new_get_return_type(fun_type->cdr, flags))) {    free_type(res);    res = NULL;    break;    }    res = and_pike_types(tmp2 = res, tmp);    free_type(tmp);    free_type(tmp2);    break;    case T_NOT: -  /* Doesn't match. */ +  if (!(res = new_get_return_type(fun_type->car, flags))) { +  copy_pike_type(res, mixed_type_string); +  } else if (res->type == T_NOT) { +  tmp = res; +  copy_pike_type(res, tmp->car); +  free_type(tmp); +  } else { +  type_stack_mark(); +  push_finished_type(res); +  push_type(T_NOT); +  free_type(res); +  res = pop_unfinished_type(); +  }    break;    case PIKE_T_TYPE:    /* Casting requires an argument... */    res = NULL;    break;    case PIKE_T_PROGRAM:    tmp = low_object_lfun_type(fun_type->car, LFUN_CREATE);    if (!tmp) {    /* No create(). */    add_ref(fun_type->car);
pike.git/src/pike_types.c:6708:    } else {    tmp = low_get_first_arg_type(arg_type->car->car,    flags|FILTER_KEEP_VOID);    }    type_stack_mark();    push_finished_type(tmp);    free_type(tmp);    push_type(arg_type->type);    return pop_unfinished_type();    } +  /* FALL_THROUGH */ +     case T_ARRAY:    case T_MULTISET:    /* Keep void! */    tmp = low_get_first_arg_type(arg_type->car, flags|FILTER_KEEP_VOID);    type_stack_mark();    push_finished_type(tmp);    free_type(tmp);    push_type(arg_type->type);    return pop_unfinished_type();   
pike.git/src/pike_types.c:6762:   {    struct pike_type *res = NULL;    struct pike_type *tmp;    struct pike_type *tmp2;    loop:    /* Get rid of the array levels. */    while(fun_type->type == PIKE_T_ARRAY) {    fun_type = fun_type->car;    }    + #ifdef PIKE_DEBUG +  if (l_flag > 2) { +  fprintf(stderr, "get_first_arg_type("); +  simple_describe_type(fun_type); +  fprintf(stderr, ", 0x%04x)\n", flags); +  } + #endif +     switch(fun_type->type) {    case PIKE_T_SCOPE:    case T_ASSIGN:    case PIKE_T_NAME:    case PIKE_T_ATTRIBUTE:    case PIKE_T_RING:    fun_type = fun_type->cdr;    goto loop;       case T_OR:
pike.git/src/pike_types.c:6805:    * ==>    * string | string|int    *    * This is however not true in the case where neither is inverted:    *    * function(attribute(sprintf_args, mixed)...:string) &    * function(object|string:string)    * ==>    * attribute(sprintf_args, mixed) & object|string    */ -  if ((fun_type->car->type == T_NOT) == (fun_type->cdr->type == T_NOT)) { +  if (!(flags & CALL_NOT_LAST_ARG) || +  ((fun_type->car->type == T_NOT) == (fun_type->cdr->type == T_NOT))) {    res = and_pike_types(tmp2 = res, tmp);    } else {    res = or_pike_types(tmp2 = res, tmp, 1);    }    free_type(tmp);    free_type(tmp2);    break;    case T_NOT:    if (!(res = get_first_arg_type(fun_type->car, flags))) {    break;
pike.git/src/pike_types.c:6865:    * Failed to lookup program id.    * Program does not have the lfun `()().    */       /* FALL_THROUGH */    case PIKE_T_MIXED:    copy_pike_type(res, mixed_type_string);    break;       case PIKE_T_FUNCTION: +  if (!(flags & CALL_NOT_LAST_ARG) && +  (fun_type->cdr->type == PIKE_T_FUNCTION) && +  !low_match_types(fun_type->cdr->car, void_type_string, 0)) { +  /* Last argument and more arguments required. */ +  res = NULL; +  break; +  } +  /* FALL_THROUGH */    case T_MANY:    if ((res = fun_type->car)->type == T_VOID) {    res = NULL;    break;    }    res = low_get_first_arg_type(res, 0);    break;       default:    /* Not a callable. */    break;    }    -  + #ifdef PIKE_DEBUG +  if (l_flag > 2) { +  fprintf(stderr, "get_first_arg_type("); +  simple_describe_type(fun_type); +  fprintf(stderr, ", 0x%04x) ==> ", flags); +  simple_describe_type(res); +  fprintf(stderr, "\n"); +  } + #endif +     return res;   }      /* NOTE: fun_type loses a reference. */   struct pike_type *check_splice_call(struct pike_string *fun_name,    struct pike_type *fun_type,    INT32 argno,    struct pike_type *arg_type,    struct svalue *sval,    INT32 flags)
pike.git/src/pike_types.c:6901:    struct pike_type *res = NULL;    struct pike_type *prev = fun_type;    int cnt = 256;    /* This argument can expand to anything between zero and MAX_ARGS args. */       copy_pike_type(res, fun_type);       /* Loop until we get a stable fun_type, or it's an invalid argument. */    while ((fun_type = low_new_check_call(debug_malloc_pass(prev),    debug_malloc_pass(arg_type), -  flags, sval)) && +  flags|CALL_NOT_LAST_ARG, sval)) &&    (fun_type != prev) && --cnt) {      #ifdef PIKE_DEBUG    if (l_flag>4) {    fprintf(stderr, "\n sub_result_type: ");    simple_describe_type(fun_type);    }   #endif /* PIKE_DEBUG */       res = dmalloc_touch(struct pike_type *,
pike.git/src/pike_types.c:6949:    } else if (c->lex.pragmas & ID_STRICT_TYPES) {    yywarning("In argument %d to %S: The @-operator argument has a max length of %d.",    argno, fun_name, 256-cnt);    }    }       return res;   }      /* NOTE: fun_type loses a reference. */ - struct pike_type *new_check_call(struct pike_string *fun_name, + static struct pike_type *new_check_call_arg(struct pike_string *fun_name,    struct pike_type *fun_type, -  node *args, INT32 *argno, INT32 flags) +  node *args, INT32 *argno, +  INT32 flags)   {    struct compilation *c = THIS_COMPILATION;    struct pike_type *tmp = NULL;    struct pike_type *res = NULL;    struct svalue *sval = NULL;       CHECK_COMPILER();       debug_malloc_touch(fun_type);    -  while (args && -  ((args->token == F_ARG_LIST) || (args->token == F_LVALUE_LIST)) && -  fun_type) { -  if (args->token == F_LVALUE_LIST) flags |= CALL_ARG_LVALUE; -  fun_type = new_check_call(fun_name, fun_type, CAR(args), argno, flags); -  debug_malloc_touch(fun_type); -  args = CDR(args); -  } -  +     if (!args || !fun_type) {    debug_malloc_touch(fun_type);    return fun_type;    }       (*argno)++;       if (args->token == F_CONSTANT) {    sval = &args->u.sval;    }
pike.git/src/pike_types.c:6995: Inside #if defined(PIKE_DEBUG)
   simple_describe_type(args->type);    if (sval) {    fprintf(stderr, "\n Constant of type %s",    get_name_of_type(TYPEOF(*sval)));    }    fprintf(stderr, "\n fun_type: ");    simple_describe_type(fun_type);    }   #endif /* PIKE_DEBUG */    -  if (TEST_COMPAT(7, 6)) { -  /* Attempt to reduce strictness to Pike 7.6 levels. */ -  flags |= CALL_7_6; -  } -  +     if (args->token == F_PUSH_ARRAY) {   #ifdef PIKE_DEBUG    if (l_flag>2) {    fprintf(stderr, "\n The argument is a splice operator.\n");    }   #endif /* PIKE_DEBUG */       res = check_splice_call(fun_name, fun_type, *argno,    args->type, sval, flags);   
pike.git/src/pike_types.c:7035: Inside #if defined(PIKE_DEBUG)
  #ifdef PIKE_DEBUG    if (l_flag>2) {    fprintf(stderr, " OK.\n");    }   #endif /* PIKE_DEBUG */    if ((c->lex.pragmas & ID_STRICT_TYPES) &&    /* FIXME: Strict types not supported for lvalues yet. */    !(flags & CALL_ARG_LVALUE)){    if (!(tmp = low_new_check_call(fun_type, args->type,    flags|CALL_STRICT, sval))) { -  tmp = get_first_arg_type(fun_type, 0); +  tmp = get_first_arg_type(fun_type, flags);    yytype_report(REPORT_WARNING, NULL, 0, tmp,    NULL, 0, args->type,    0, "Type mismatch in argument %d to %S.",    *argno, fun_name);    if (tmp) free_type(tmp);    } else {    free_type(tmp);    }    }    free_type(fun_type);    return res;    }    }    -  if ((tmp = get_first_arg_type(fun_type, flags))) { +  if ((tmp = get_first_arg_type(fun_type, flags|CALL_NOT_LAST_ARG))) {    struct pike_type *tmp2;      #ifdef PIKE_DEBUG    if (l_flag>2) {    fprintf(stderr, " Bad argument.\n");    }   #endif /* PIKE_DEBUG */    yytype_report(REPORT_ERROR, NULL, 0, tmp, NULL, 0, args->type,    0, "Bad argument %d to %S.", *argno, fun_name);   
pike.git/src/pike_types.c:7098:   #endif /* PIKE_DEBUG */    yytype_report(REPORT_ERROR, NULL, 0, NULL,    NULL, 0, args->type,    0, "Too many arguments to %S (expected %d arguments).",    fun_name, *argno - 1);    }    free_type(fun_type);    return NULL;   }    + /* NOTE: fun_type loses a reference. */ + struct pike_type *new_check_call(struct pike_string *fun_name, +  struct pike_type *fun_type, +  node *args, INT32 *argno, INT32 flags) + { +  node *orig_arg_parent = NULL; +  INT32 orig_flags = flags; +  int num_cdr = 0; +  int num_lvalue = 0; +  +  if (!args || !fun_type) { +  debug_malloc_touch(fun_type); +  return fun_type; +  } +  +  orig_arg_parent = args->parent; +  args->parent = NULL; /* End marker. */ +  +  debug_malloc_touch(fun_type); +  +  while (args && fun_type) { +  if ((args->token == F_ARG_LIST) || (args->token == F_LVALUE_LIST)) { +  if (CDR(args)) { +  num_cdr++; +  flags |= CALL_NOT_LAST_ARG; +  } +  if (args->token == F_LVALUE_LIST) { +  num_lvalue++; +  flags |= CALL_ARG_LVALUE; +  } +  if (CAR(args)) { +  CAR(args)->parent = args; +  args = CAR(args); +  continue; +  } else if (CDR(args)) { +  CDR(args)->parent = args; +  args = CDR(args); +  if (!--num_cdr) { +  flags = orig_flags | (num_lvalue?CALL_ARG_LVALUE:0); +  } +  continue; +  } +  } else { +  fun_type = new_check_call_arg(fun_name, fun_type, args, argno, flags); +  debug_malloc_touch(fun_type); +  +  if (!fun_type) return NULL; +  } +  +  do { +  node *prev = args; +  if (args->token == F_LVALUE_LIST) { +  if (!--num_lvalue) { +  flags = orig_flags | (num_cdr?CALL_NOT_LAST_ARG:0); +  } +  } +  args = args->parent; +  if (!args) { +  prev->parent = orig_arg_parent; +  break; +  } +  if ((CAR(args) == prev) && CDR(args)) { +  if (!--num_cdr) { +  flags = orig_flags | (num_lvalue?CALL_ARG_LVALUE:0); +  } +  if (CDR(args) != prev) { +  CDR(args)->parent = args; +  args = CDR(args); +  break; +  } +  /* CAR(args) == CDR(args), so we need to recurse +  * since we can't differentiate otherwise. +  * +  * This should be a quite rare case, and the tree is +  * most likely very shallow, so this should be safe. +  */ +  fun_type = new_check_call(fun_name, fun_type, prev, argno, flags); +  debug_malloc_touch(fun_type); +  +  if (!fun_type) return NULL; +  } +  } while(args); +  } +  +  return fun_type; + } +    struct pike_type *zzap_function_return(struct pike_type *a,    struct pike_type *fun_ret)   {    struct pike_type *ret = NULL;    switch(a->type)    {    case T_SCOPE:    ret = zzap_function_return(a->cdr, fun_ret);    if (!ret) return NULL;    type_stack_mark();
pike.git/src/pike_types.c:7182:    push_type(T_MANY);    return pop_unfinished_type();    }   /* This error is bogus /Hubbe    Pike_fatal("zzap_function_return() called with unexpected value: %d\n",    EXTRACT_UCHAR(a));   */    return NULL;   }    + struct pike_type *get_lax_type_of_svalue( const struct svalue *c ) + { +  struct pike_type *res; +  if (TYPEOF(*c) == T_INT) +  { +  if (c->u.integer) +  copy_pike_type(res, int_type_string); +  else +  copy_pike_type(res, zero_type_string); +  } +  else if (TYPEOF(*c) == T_STRING ) +  copy_pike_type(res, string_type_string); +  else +  return get_type_of_svalue(c); +  +  return res; + } +    struct pike_type *get_type_of_svalue(const struct svalue *s)   {    struct pike_type *ret;    switch(TYPEOF(*s))    {    case T_FUNCTION:    if(SUBTYPEOF(*s) == FUNCTION_BUILTIN)    {    copy_pike_type(ret, s->u.efun->type);    }else{
pike.git/src/pike_types.c:7272:    push_type(T_ZERO);    push_type(T_ZERO);    }    push_type(T_MAPPING);    return pop_unfinished_type();       case T_OBJECT:    type_stack_mark();    if(s->u.object->prog)    { - #ifdef AUTO_BIGNUM +     if(is_bignum_object(s->u.object))    {    push_int_type(MIN_INT32, MAX_INT32);    }    else - #endif +     {    push_object_type(1, s->u.object->prog->id);    }    }else{    /* Destructed object */    push_type(T_ZERO);    }    return pop_unfinished_type();       case T_INT:
pike.git/src/pike_types.c:7363:       case T_TYPE:    type_stack_mark();    push_finished_type(s->u.type);    push_type(T_TYPE);    return pop_unfinished_type();       case T_STRING:    type_stack_mark();    if (s->u.string->len) { -  /* FIXME: Could be extended to detect 7-bit strings, etc. */ -  if (s->u.string->size_shift == 2) { -  push_int_type(MIN_INT32, MAX_INT32); +  INT32 min, max; +  check_string_range( s->u.string, 0, &min, &max ); +  push_int_type(min, max);    } else { -  push_int_type(0, (1<<(8 << s->u.string->size_shift)) - 1); -  } -  } else { +     push_type(T_ZERO);    }    push_type(T_STRING);    return pop_unfinished_type();       default:    type_stack_mark();    push_type(TYPEOF(*s));    return pop_unfinished_type();    }
pike.git/src/pike_types.c:7530:    if(implements_a && implements_b) {    if (implements_mode) {    yyexplain_not_implements(severity_level, implements_a, implements_b);    } else {    yyexplain_not_compatible(severity_level, implements_a, implements_b);    }    }    END_CYCLIC();   }    + /* FIXME: Code duplication! */ + void string_builder_explain_nonmatching_types(struct string_builder *s, +  struct pike_type *type_a, +  struct pike_type *type_b) + { +  DECLARE_CYCLIC();    -  +  implements_a=0; +  implements_b=0; +  implements_mode=0; +  +  /* Note the argument order. */ +  pike_types_le(type_b, type_a); +  + #if 0 +  if(!(implements_a && implements_b && +  type_a->str[0]==T_OBJECT && +  type_b->str[0]==T_OBJECT)) + #endif /* 0 */ +  { +  ref_push_type_value(type_a); +  ref_push_type_value(type_b); +  string_builder_sprintf(s, +  "Expected: %O.\n" +  "Got : %O.\n", +  Pike_sp-2, Pike_sp-1); +  } +  +  /* Protect against circularities. */ +  if (BEGIN_CYCLIC(type_a, type_b)) { +  END_CYCLIC(); +  return; +  } +  SET_CYCLIC_RET(1); +  +  if(implements_a && implements_b) { +  if (implements_mode) { +  string_builder_explain_not_implements(s, implements_a, implements_b); +  } else { +  string_builder_explain_not_compatible(s, implements_a, implements_b); +  } +  } +  END_CYCLIC(); + } +    /******/      static void low_make_pike_type(unsigned char *type_string,    unsigned char **cont);      static void low_make_function_type(unsigned char *type_string,    unsigned char **cont)   {    if (*type_string == T_MANY) {    low_make_pike_type(type_string+1, cont);
pike.git/src/pike_types.c:7553:    return;    }    low_make_pike_type(type_string, cont);    low_make_function_type(*cont, cont);    push_reverse_type(T_FUNCTION);   }      static void low_make_pike_type(unsigned char *type_string,    unsigned char **cont)   { -  unsigned INT32 type; +  unsigned INT32 type = *type_string;    -  switch(type = *type_string) { +  if (type <= MAX_TYPE) { +  /* Remap from old type enumeration to +  * keep compat with output from __parse_pike_type(). +  */ +  type ^= MIN_REF_TYPE; +  } +  +  switch(type) {   #ifdef PIKE_DEBUG    case T_SCOPE:    Pike_fatal("Not supported yet.\n");   #endif    case T_ASSIGN:    if ((type_string[1] < '0') || (type_string[1] > '9')) {    Pike_fatal("low_make_pike_type(): Bad marker: %d\n", type_string[1]);    }    low_make_pike_type(type_string+2, cont);    push_assign_type(type_string[1]);
pike.git/src/pike_types.c:7691:    break;    break;    case 6:    for(bytes=0; ; bytes+=4)    if(!type_string[bytes+2] && !type_string[bytes+3] &&    !type_string[bytes+4] && !type_string[bytes+5])    break;    break;    }    str = begin_wide_shared_string(bytes>>size_shift, size_shift); -  MEMCPY(str->str, type_string+2, bytes); +  memcpy(str->str, type_string+2, bytes);    if (size_shift &&   #if (PIKE_BYTEORDER == 1234)    /* Little endian */    !(type_string[1] & 0x04)   #else /* PIKE_BYTEORDER != 1234 */    /* Big endian */    (type_string[1] & 0x04)   #endif /* PIKE_BYTEORDER == 1234 */    ) {    int len;
pike.git/src/pike_types.c:7732:    push_type_name(str = end_shared_string(str));    } else {    push_type_attribute(str = end_shared_string(str));    }    free_string(str);    break;    }   #ifdef PIKE_DEBUG    default:    Pike_fatal("compile_type_string(): Error in type string %d.\n", type); -  /* NOT_REACHED */ -  break; +  UNREACHABLE(break);   #endif    }   }    -  + void type_stack_mark(void) + { +  if(UNLIKELY(Pike_compiler->pike_type_mark_stackp >= pike_type_mark_stack + (PIKE_TYPE_STACK_SIZE>>4))) +  Pike_fatal("Type mark stack overflow.\n"); +  *Pike_compiler->pike_type_mark_stackp=Pike_compiler->type_stackp; +  Pike_compiler->pike_type_mark_stackp++; +  TYPE_STACK_DEBUG("type_stack_mark"); + } +    /* Make a pike-type from a serialized (old-style) type. */   struct pike_type *debug_make_pike_type(const char *serialized_type)   {    unsigned char *dummy;    type_stack_mark();    low_make_pike_type((unsigned char *)serialized_type, &dummy);   #if 1    if ((Pike_compiler->type_stackp[0]->flags &    (PT_FLAG_MARKER|PT_FLAG_ASSIGN)) ||    (((Pike_compiler->type_stackp[0]->type == T_OR) ||
pike.git/src/pike_types.c:7769: Inside #if 0
  #if 0    fprintf(stderr, "pike_type_allow_premature_toss(): Type: %d\n",    type->type);   #endif /* 0 */    switch(type->type)    {    default:   #ifdef PIKE_DEBUG    Pike_fatal("pike_type_allow_premature_toss: Unknown type (code: %d)\n",    type->type); -  /* NOT_REACHED */ -  return 0; +  UNREACHABLE(return 0);   #endif    case T_NOT:    return !pike_type_allow_premature_toss(type->car);       case T_OBJECT:    case T_MIXED:    case T_FUNCTION:    case T_MANY:    return 0;   
pike.git/src/pike_types.c:7826:    }   }      static void low_type_to_string(struct pike_type *t)   {    recurse:    switch(t->type) {    case T_ARRAY:    case T_MULTISET:    case T_TYPE: -  case T_NOT: +     case T_PROGRAM: -  +  my_putchar(t->type ^ MIN_REF_TYPE); +  t = t->car; +  goto recurse; +  +  case T_NOT:    my_putchar(t->type); -  /* FALL_THROUGH */ +     t = t->car;    goto recurse;    -  +  case T_MAPPING: +  my_putchar(t->type ^ MIN_REF_TYPE); +  low_type_to_string(t->car); +  t = t->cdr; +  goto recurse; +     case PIKE_T_RING:    case T_TUPLE: -  case T_MAPPING: +     case T_OR:    case T_AND:    my_putchar(t->type);    low_type_to_string(t->car);    t = t->cdr;    goto recurse;    -  +  case T_FLOAT: +  case T_ZERO: +  my_putchar(t->type ^ MIN_REF_TYPE); +  break; +     case '0':    case '1':    case '2':    case '3':    case '4':    case '5':    case '6':    case '7':    case '8':    case '9': -  case T_FLOAT: -  case T_ZERO: +     case T_VOID:    case T_MIXED:    my_putchar(t->type);    break;       case T_OBJECT:    {    INT32 i; -  my_putchar(T_OBJECT); +  my_putchar(T_OBJECT ^ MIN_REF_TYPE);    i = (INT32)CAR_TO_INT(t);    my_putchar( i );    i = (INT32)CDR_TO_INT(t);       if( i > 65535 ) i = 0; /* Not constant between recompilations */       my_putchar((i >> 24) & 0xff);    my_putchar((i >> 16) & 0xff);    my_putchar((i >> 8) & 0xff);    my_putchar(i & 0xff);    }    break;       case T_STRING:    {    if (t->car == int_type_string) { -  my_putchar(T_STRING); +  my_putchar(T_STRING ^ MIN_REF_TYPE);    } else {    my_putchar(PIKE_T_NSTRING);    low_type_to_string(t->car);    }    }    break;       case T_INT:    {    INT32 i; -  my_putchar(T_INT); +  my_putchar(T_INT ^ MIN_REF_TYPE);    i = (INT32)CAR_TO_INT(t);    my_putchar((i >> 24) & 0xff);    my_putchar((i >> 16) & 0xff);    my_putchar((i >> 8) & 0xff);    my_putchar(i & 0xff);    i = (INT32)CDR_TO_INT(t);    my_putchar((i >> 24) & 0xff);    my_putchar((i >> 16) & 0xff);    my_putchar((i >> 8) & 0xff);    my_putchar(i & 0xff);    }    break;       case T_FUNCTION:    case T_MANY: -  my_putchar(T_FUNCTION); +  my_putchar(T_FUNCTION ^ MIN_REF_TYPE);    while(t->type == T_FUNCTION) {    low_type_to_string(t->car);    t = t->cdr;    }    my_putchar(T_MANY);    low_type_to_string(t->car);    t = t->cdr;    goto recurse;       case T_SCOPE:
pike.git/src/pike_types.c:7955:    low_type_to_string(t);    UNSET_ONERROR(err);    return free_buf(&save_buf);   }      #ifdef PIKE_DEBUG   static void gc_mark_external_types(struct callback *cb, void *a, void *b);   static struct callback *pike_type_gc_callback = NULL;   #endif /* PIKE_DEBUG */    + #ifdef HAVE_SYS_MMAN_H + #include <sys/mman.h> + #endif +  + #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) + #define MAP_ANONYMOUS MAP_ANON + #endif /* !MAP_ANONYMOUS && MAP_ANON */ +  + #ifdef MAP_ANONYMOUS + static int type_stack_mmap, pike_type_mark_stack_mmap; + #endif +    void init_types(void)   {    /* Initialize hashtable here. */ -  pike_type_hash = (struct pike_type **)xalloc(sizeof(struct pike_type *) * -  PIKE_TYPE_HASH_SIZE); -  MEMSET(pike_type_hash, 0, sizeof(struct pike_type *) * PIKE_TYPE_HASH_SIZE); +  pike_type_hash = xcalloc(sizeof(struct pike_type *), +  (PIKE_TYPE_HASH_SIZE+1));    pike_type_hash_size = PIKE_TYPE_HASH_SIZE; -  init_pike_type_blocks(); +     -  +  /* if possible, use mmap with on-demand allocation */ + #if defined(MAP_ANONYMOUS) + #ifndef MAP_NORESERVE + #define MAP_NORESERVE 0 + #endif +  type_stack = mmap( NULL, sizeof(struct pike_type *)*PIKE_TYPE_STACK_SIZE, +  PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); +  if( type_stack != MAP_FAILED ) { +  type_stack_mmap = 1; +  } else { +  type_stack = NULL; +  } +  pike_type_mark_stack = +  mmap( NULL, sizeof(struct pike_type **)*PIKE_TYPE_STACK_SIZE>>2, +  PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); +  if( pike_type_mark_stack != MAP_FAILED ) { +  pike_type_mark_stack_mmap = 1; +  } else { +  pike_type_mark_stack = NULL; +  } + #endif +  if( !type_stack ) +  type_stack = xalloc(sizeof(struct pike_type *)*PIKE_TYPE_STACK_SIZE); +  if( !pike_type_mark_stack ) +  pike_type_mark_stack = xalloc(sizeof(struct pike_type *)*PIKE_TYPE_STACK_SIZE / 4); +  +  Pike_compiler->type_stackp = type_stack; +  Pike_compiler->pike_type_mark_stackp = pike_type_mark_stack; +     int_type_string = CONSTTYPE(tInt); /* MUST come before string! */    string0_type_string = CONSTTYPE(tStr0);    string_type_string = CONSTTYPE(tStr32);    object_type_string = CONSTTYPE(tObj);    program_type_string = CONSTTYPE(tPrg(tObj));    float_type_string = CONSTTYPE(tFloat);    mixed_type_string = CONSTTYPE(tMix);    array_type_string = CONSTTYPE(tArray);    multiset_type_string = CONSTTYPE(tMultiset);    mapping_type_string = CONSTTYPE(tMapping);    function_type_string = CONSTTYPE(tFunction);    type_type_string = CONSTTYPE(tType(tMix));    void_type_string = CONSTTYPE(tVoid);    zero_type_string = CONSTTYPE(tZero); -  +  inheritable_type_string = CONSTTYPE(tOr3(tPrg(tObj), tObj, +  tFuncV(tNone, tOr(tVoid, tMix), +  tObj))); +  typeable_type_string = CONSTTYPE(tOr4(tPrg(tObj), tObj, +  tFuncV(tNone, tOr(tVoid, tMix), +  tObj), +  tType(tMix))); +  enumerable_type_string = CONSTTYPE(tOr3(tString,tInt,tFloat));    any_type_string = CONSTTYPE(tOr(tVoid,tMix));    weak_type_string = CONSTTYPE(tOr4(tArray,tMultiset,tMapping,    tFuncV(tNone,tZero,tOr(tMix,tVoid))));    sscanf_type_string = CONSTTYPE(tFuncV(tStr tAttr("sscanf_format", tStr),    tAttr("sscanf_args", tMix), tIntPos)); -  sscanf_76_type_string = CONSTTYPE(tFuncV(tStr tAttr("sscanf_76_format", tStr), -  tAttr("sscanf_args", tMix), tIntPos)); +     /* add_ref(weak_type_string); *//* LEAK */    -  +  literal_string_string = make_shared_string("string"); +  literal_int_string = make_shared_string("int"); +  literal_float_string = make_shared_string("float"); +  literal_function_string = make_shared_string("function"); +  literal_object_string = make_shared_string("object"); +  literal_program_string = make_shared_string("program"); +  literal_array_string = make_shared_string("array"); +  literal_multiset_string = make_shared_string("multiset"); +  literal_mapping_string = make_shared_string("mapping"); +  literal_type_string = make_shared_string("type"); +  literal_mixed_string = make_shared_string("mixed"); +    #ifdef PIKE_DEBUG    pike_type_gc_callback = add_gc_callback(gc_mark_external_types, NULL, NULL);   #endif   }      void cleanup_pike_types(void)   {   #ifdef DO_PIKE_CLEANUP    while (all_pike_type_locations) {    free_type(all_pike_type_locations->t);    all_pike_type_locations = all_pike_type_locations->next;    } -  + #ifdef MAP_ANONYMOUS +  if( type_stack_mmap ) +  { +  munmap( type_stack, sizeof(struct pike_type *)*PIKE_TYPE_STACK_SIZE); +  type_stack = NULL; +  } +  if( pike_type_mark_stack_mmap ) +  { +  munmap( pike_type_mark_stack, sizeof(struct pike_type *)*PIKE_TYPE_STACK_SIZE>>2); +  pike_type_mark_stack = NULL; +  } + #endif +  free( type_stack ); +  free( pike_type_mark_stack );   #endif /* DO_PIKE_CLEANUP */       clear_markers();       free_type(string0_type_string);    string0_type_string = NULL;    free_type(string_type_string);    string_type_string = NULL;    free_type(int_type_string);    int_type_string = NULL;
pike.git/src/pike_types.c:8031:    free_type(mapping_type_string);    mapping_type_string = NULL;    free_type(type_type_string);    type_type_string = NULL;    free_type(mixed_type_string);    mixed_type_string = NULL;    free_type(void_type_string);    void_type_string = NULL;    free_type(zero_type_string);    zero_type_string = NULL; +  free_type(inheritable_type_string); +  inheritable_type_string = NULL; +  free_type(typeable_type_string); +  typeable_type_string = NULL; +  free_type(enumerable_type_string); +  enumerable_type_string = NULL;    free_type(any_type_string);    any_type_string = NULL;    free_type(weak_type_string);    weak_type_string = NULL;    free_type(sscanf_type_string);    sscanf_type_string = NULL; -  free_type(sscanf_76_type_string); -  sscanf_76_type_string = NULL; +  +  free_string(literal_string_string); literal_string_string = NULL; +  free_string(literal_int_string); literal_int_string = NULL; +  free_string(literal_float_string); literal_float_string = NULL; +  free_string(literal_function_string); literal_function_string = NULL; +  free_string(literal_object_string); literal_object_string = NULL; +  free_string(literal_program_string); literal_program_string = NULL; +  free_string(literal_array_string); literal_array_string = NULL; +  free_string(literal_multiset_string); literal_multiset_string = NULL; +  free_string(literal_mapping_string); literal_mapping_string = NULL; +  free_string(literal_type_string); literal_type_string = NULL; +  free_string(literal_mixed_string); literal_mixed_string = NULL; +    #ifdef PIKE_DEBUG    remove_callback(pike_type_gc_callback);   #endif   }      void cleanup_pike_type_table(void)   {    /* Free the hashtable here. */    if (pike_type_hash) {    free(pike_type_hash);
pike.git/src/pike_types.c:8062:    */    pike_type_hash = NULL;    }    /* Don't do this, it messes up stuff...    *    * It's needed for dmalloc to survive.    */    pike_type_hash_size = 0;      #ifdef DO_PIKE_CLEANUP -  free_all_pike_type_blocks(); +  ba_destroy(&type_allocator);   #endif /* DO_PIKE_CLEANUP */   }      PMOD_EXPORT void *find_type(struct pike_type *t,    void *(*cb)(struct pike_type *))   {    void *res;    if (!t) return NULL;       res = cb(t);
pike.git/src/pike_types.c:8127: Inside #if defined(PIKE_DEBUG)
   case T_OBJECT:    break;    default:    Pike_fatal("find_type: Unhandled type-node: %d\n", t->type);    break;   #endif /* PIKE_DEBUG */    }    return NULL;   }    - PMOD_EXPORT void visit_type (struct pike_type *t, int action) + PMOD_EXPORT void visit_type (struct pike_type *t, int action, void *extra)   { -  switch (action) { +  visit_enter(t, PIKE_T_TYPE, extra); +  switch (action & VISIT_MODE_MASK) {   #ifdef PIKE_DEBUG    default:    Pike_fatal ("Unknown visit action %d.\n", action);    case VISIT_NORMAL:    break;   #endif    case VISIT_COMPLEX_ONLY: -  +  visit_leave(t, PIKE_T_TYPE, extra);    return;    case VISIT_COUNT_BYTES:    mc_counted_bytes += sizeof (struct pike_type);    break;    }       switch (t->type) {    case T_FUNCTION:    case T_MANY:    case T_TUPLE:    case T_MAPPING:    case T_OR:    case T_AND:    case PIKE_T_RING: -  visit_type_ref (t->car, REF_TYPE_INTERNAL); +  visit_type_ref (t->car, REF_TYPE_INTERNAL, extra);    /* FALL_THROUGH */    case T_SCOPE:    case T_ASSIGN: -  visit_type_ref (t->cdr, REF_TYPE_INTERNAL); +  visit_type_ref (t->cdr, REF_TYPE_INTERNAL, extra);    break;    case T_ARRAY:    case T_MULTISET:    case T_NOT:    case T_TYPE:    case T_PROGRAM:    case T_STRING: -  visit_type_ref (t->car, REF_TYPE_INTERNAL); +  visit_type_ref (t->car, REF_TYPE_INTERNAL, extra);    break;    case PIKE_T_ATTRIBUTE:    case PIKE_T_NAME: -  visit_string_ref ((struct pike_string *) t->car, REF_TYPE_INTERNAL); -  visit_type_ref (t->cdr, REF_TYPE_INTERNAL); +  visit_string_ref ((struct pike_string *) t->car, REF_TYPE_INTERNAL, +  extra); +  visit_type_ref (t->cdr, REF_TYPE_INTERNAL, extra);    break;   #ifdef PIKE_DEBUG    case '0':    case '1':    case '2':    case '3':    case '4':    case '5':    case '6':    case '7':
pike.git/src/pike_types.c:8194: Inside #if defined(PIKE_DEBUG)
   case T_ZERO:    case PIKE_T_UNKNOWN:    case T_INT:    case T_OBJECT:    break;    default:    Pike_fatal("visit_type: Unhandled type-node: %d\n", t->type);    break;   #endif /* PIKE_DEBUG */    } +  visit_leave(t, PIKE_T_TYPE, extra);   }      #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP)      /* This is only enough gc stuff to detect leaking pike_type structs    * and to locate references to them. More is needed if types are    * extended to contain pointers to other memory objects or if they    * might contain cycles. */      void gc_mark_type_as_referenced(struct pike_type *t)
pike.git/src/pike_types.c:8236: Inside #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP)
   case PIKE_T_TYPE:    case PIKE_T_PROGRAM:    if (t->car) gc_mark_type_as_referenced(t->car);    break;    }    } GC_LEAVE;    }   }      #ifdef PIKE_DEBUG - static void gc_mark_external_types(struct callback *cb, void *a, void *b) + static void gc_mark_external_types(struct callback *UNUSED(cb), +  void *UNUSED(a), void *UNUSED(b))   {    unsigned int e;    for (e = 0; e < NELEM (a_markers); e++) {    if (a_markers[e])    gc_mark_external (a_markers[e], " in a_markers");    if (b_markers[e])    gc_mark_external (b_markers[e], " in b_markers");    }       if (string0_type_string)
pike.git/src/pike_types.c:8274: Inside #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) and #if defined(PIKE_DEBUG)
   if (mapping_type_string)    gc_mark_external(mapping_type_string, " as mapping_type_string");    if (function_type_string)    gc_mark_external(function_type_string, " as function_type_string");    if (type_type_string)    gc_mark_external(type_type_string, " as type_type_string");    if (void_type_string)    gc_mark_external(void_type_string, " as void_type_string");    if (zero_type_string)    gc_mark_external(zero_type_string, " as zero_type_string"); +  if (enumerable_type_string) +  gc_mark_external(enumerable_type_string, " as enumerable_type_string");    if (any_type_string)    gc_mark_external(any_type_string, " as any_type_string");    if (weak_type_string)    gc_mark_external(weak_type_string, " as weak_type_string");      #ifdef DO_PIKE_CLEANUP    {    struct pike_type_location *t = all_pike_type_locations;    while(t) {    gc_mark_external (t->t, " as constant type");
pike.git/src/pike_types.c:8352: Inside #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) and #if defined(PIKE_DEBUG)
   "Unhandled type-node: %d\n", t->type);    break;   #endif /* PIKE_DEBUG */    }    } GC_LEAVE;   }      void gc_check_all_types (void)   {    unsigned INT32 e; -  for(e=0;e<pike_type_hash_size;e++) +  for(e=0;e<=pike_type_hash_size;e++)    {    struct pike_type *t;    for(t = pike_type_hash[e]; t; t=t->next) gc_check_type (t);    }   }      #endif /* PIKE_DEBUG || DO_PIKE_CLEANUP */