From 6bc92806759b40126683c90bb36a68b2ba630090 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net>
Date: Fri, 10 Apr 1998 15:24:22 -0700
Subject: [PATCH] Stdio.FILE x; now means object that x is an object that
 inherits Stdio.FILE.

Rev: src/ChangeLog:1.145
Rev: src/interpret.c:1.76
Rev: src/language.yacc:1.72
Rev: src/lex.c:1.50
Rev: src/pike_memory.c:1.20
Rev: src/pike_types.c:1.38
Rev: src/program.c:1.76
Rev: src/program.h:1.39
Rev: src/testsuite.in:1.88
---
 src/ChangeLog     |   6 ++
 src/interpret.c   |   4 +-
 src/language.yacc | 108 ++++++++++++++++++++++++++++--------
 src/lex.c         |   8 ++-
 src/pike_memory.c |  47 ++++++++++++++--
 src/pike_types.c  | 138 +++++++++++++++++++++++++++++++++++-----------
 src/program.c     |  20 ++++---
 src/program.h     |   4 +-
 src/testsuite.in  |  14 ++++-
 9 files changed, 276 insertions(+), 73 deletions(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index bb0420236d..03348512c1 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+Fri Apr 10 15:05:11 1998  Fredrik Hubinette  <hubbe@cytocin.hubbe.net>
+
+	* language.yacc: it is now possible to use class names as types
+	  in most places.
+	* pike_types.c: object(foo) now means 'object that inherits foo'
+
 Thu Apr  9 15:11:07 1998  Fredrik Hubinette  <hubbe@cytocin.hubbe.net>
 
 	* Recursive module references now generates errors
diff --git a/src/interpret.c b/src/interpret.c
index 661f866ef4..5fcd7002e2 100644
--- a/src/interpret.c
+++ b/src/interpret.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: interpret.c,v 1.75 1998/04/10 18:06:05 grubba Exp $");
+RCSID("$Id: interpret.c,v 1.76 1998/04/10 22:24:19 hubbe Exp $");
 #include "interpret.h"
 #include "object.h"
 #include "program.h"
@@ -915,7 +915,7 @@ static int eval_instruction(unsigned char *pc)
       pop_n_elems(3);
       break;
 
-      CASE(F_GLOBAL_LVALUE)
+      CASE(F_GLOBAL_LVALUE);
       {
 	struct identifier *i;
 	INT32 tmp=GET_ARG() + fp->context.identifier_level;
diff --git a/src/language.yacc b/src/language.yacc
index 027cd24787..da11774490 100644
--- a/src/language.yacc
+++ b/src/language.yacc
@@ -107,6 +107,8 @@
 %token F_IMPORT
 %token F_INHERIT
 %token F_INLINE
+%token F_LOCAL_ID
+%token F_FINAL_ID
 %token F_INT_ID
 %token F_LAMBDA
 %token F_MULTISET_ID
@@ -169,7 +171,7 @@
 /* This is the grammar definition of Pike. */
 
 #include "global.h"
-RCSID("$Id: language.yacc,v 1.71 1998/04/10 04:35:19 hubbe Exp $");
+RCSID("$Id: language.yacc,v 1.72 1998/04/10 22:24:20 hubbe Exp $");
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
 #endif
@@ -290,6 +292,8 @@ int yylex(YYSTYPE *yylval);
 
 %type <n> cast
 %type <n> simple_type
+%type <n> simple_type2
+%type <n> simple_identifier_type
 %type <n> string_constant
 %type <n> string
 %type <n> F_STRING
@@ -328,6 +332,7 @@ int yylex(YYSTYPE *yylval);
 %type <n> idents
 %type <n> lambda
 %type <n> local_name_list
+%type <n> local_name_list2
 %type <n> low_idents
 %type <n> lvalue
 %type <n> lvalue_list
@@ -335,6 +340,7 @@ int yylex(YYSTYPE *yylval);
 %type <n> m_expr_list
 %type <n> m_expr_list2
 %type <n> new_local_name
+%type <n> new_local_name2
 %type <n> optional_else_part
 %type <n> return
 %type <n> sscanf
@@ -485,14 +491,7 @@ type_or_error: simple_type
     copy_shared_string(compiler_frame->current_type,$1->u.sval.u.string);
     free_node($1);
   }
-  | /* empty */
-  {
-    yyerror("Missing type.");
-    if(compiler_frame->current_type)
-      free_string(compiler_frame->current_type); 
-    copy_shared_string(compiler_frame->current_type,
-		       mixed_type_string);
-  }
+  ;
   
 
 def: modifiers type_or_error optional_stars F_IDENTIFIER 
@@ -599,7 +598,7 @@ optional_identifier: F_IDENTIFIER
   | /* empty */ { $$=0; }
   ;
 
-new_arg_name: type optional_dot_dot_dot optional_identifier
+new_arg_name: type7 optional_dot_dot_dot optional_identifier
   {
     if(varargs) yyerror("Can't define more arguments after ...");
 
@@ -641,8 +640,10 @@ arguments2: new_arg_name { $$ = 1; }
   ;
 
 modifier: F_NO_MASK    { $$ = ID_NOMASK; }
+  | F_FINAL_ID   { $$ = ID_NOMASK; }
   | F_STATIC     { $$ = ID_STATIC; }
-  | F_PRIVATE    { $$ = ID_PRIVATE; }
+  | F_PRIVATE    { $$ = ID_PRIVATE | ID_STATIC; }
+  | F_LOCAL_ID   { $$ = ID_INLINE; }
   | F_PUBLIC     { $$ = ID_PUBLIC; }
   | F_PROTECTED  { $$ = ID_PROTECTED; }
   | F_INLINE     { $$ = ID_INLINE; }
@@ -665,12 +666,34 @@ cast: '(' type ')'
       free_string(s);
     }
     ;
+
+type6: type | identifier_type ;
   
 type: type '*' { push_type(T_ARRAY); }
   | type2
   ;
 
-simple_type: type2
+type7: type7 '*' { push_type(T_ARRAY); }
+  | type4
+  ;
+
+simple_type: type4
+  {
+    struct pike_string *s=pop_type();
+    $$=mkstrnode(s);
+    free_string(s);
+  }
+  ;
+
+simple_type2: type2
+  {
+    struct pike_string *s=pop_type();
+    $$=mkstrnode(s);
+    free_string(s);
+  }
+  ;
+
+simple_identifier_type: identifier_type
   {
     struct pike_string *s=pop_type();
     $$=mkstrnode(s);
@@ -678,8 +701,27 @@ simple_type: type2
   }
   ;
 
+identifier_type: idents
+     { 
+       struct program *p;
+       resolv_program($1);
+       if((p=program_from_svalue(sp-1)))
+       {
+         push_type_int(sp[-1].u.program->id);
+       }else{
+         push_type_int(0);
+       }
+       push_type(0);
+       push_type(T_OBJECT);
+       pop_stack();
+       free_node($1);
+     }
+     ;
+
+type4: type2 | identifier_type
+
 type2: type2 '|' type3 { push_type(T_OR); }
-  | type3
+  | type3 
   ;
 
 type3: F_INT_ID      { push_type(T_INT); }
@@ -695,7 +737,7 @@ type3: F_INT_ID      { push_type(T_INT); }
   | F_FUNCTION_ID opt_function_type { push_type(T_FUNCTION); }
   ;
 
-opt_object_type:  /* Empty */ { push_type_int(0); }
+opt_object_type:  /* Empty */ { push_type_int(0); push_type(0); }
   | '(' program_ref ')'
   {
     struct program *p=program_from_svalue(sp-1);
@@ -707,6 +749,7 @@ opt_object_type:  /* Empty */ { push_type_int(0); }
       push_type_int(0);
     }
     pop_n_elems(2);
+    push_type(0);
   }
   ;
 
@@ -728,7 +771,7 @@ opt_function_type: '('
     }
     type_stack_mark();
   }
-  type ')'
+  type7 ')'
   {
     type_stack_reverse();
     type_stack_reverse();
@@ -745,16 +788,16 @@ function_type_list: /* Empty */ optional_comma
   | function_type_list2 optional_comma
   ;
 
-function_type_list2: type 
+function_type_list2: type7 
   | function_type_list2 ','
   {
     type_stack_reverse();
     type_stack_mark();
   }
-  type
+  type7
   ;
 
-opt_array_type: '(' type ')'
+opt_array_type: '(' type7 ')'
   |  { push_type(T_MIXED); }
   ;
 
@@ -763,12 +806,12 @@ opt_mapping_type: '('
     type_stack_mark();
     type_stack_mark();
   }
-  type ':'
+  type7 ':'
   { 
     type_stack_reverse();
     type_stack_mark();
   }
-  type
+  type7
   { 
     type_stack_reverse();
     type_stack_reverse();
@@ -822,7 +865,7 @@ new_local_name: optional_stars F_IDENTIFIER
     push_finished_type($<n>0->u.sval.u.string);
     while($1--) push_type(T_ARRAY);
     add_local_name($2->u.sval.u.string, pop_type());
-    $$=mknode(F_ASSIGN,mkintnode(0), mklocalnode(islocal($2->u.sval.u.string)));
+    $$=mknode(F_ASSIGN,mkintnode(0),mklocalnode(islocal($2->u.sval.u.string)));
     free_node($2);
   }
   | optional_stars F_IDENTIFIER '=' expr0
@@ -835,6 +878,20 @@ new_local_name: optional_stars F_IDENTIFIER
   }
   ;
 
+new_local_name2: F_IDENTIFIER
+  {
+    add_local_name($1->u.sval.u.string, $<n>0->u.sval.u.string);
+    $$=mknode(F_ASSIGN,mkintnode(0),mklocalnode(islocal($1->u.sval.u.string)));
+    free_node($1);
+  }
+  | F_IDENTIFIER '=' expr0
+  {
+    add_local_name($1->u.sval.u.string, $<n>0->u.sval.u.string);
+    $$=mknode(F_ASSIGN,$3, mklocalnode(islocal($1->u.sval.u.string)));
+    free_node($1);
+  }
+  ;
+
 
 block:'{'
   {
@@ -856,6 +913,10 @@ local_name_list: new_local_name
   | local_name_list ',' { $<n>$=$<n>0; } new_local_name { $$=mknode(F_ARG_LIST,$1,$4); }
   ;
 
+local_name_list2: new_local_name2
+  | local_name_list2 ',' { $<n>$=$<n>0; } new_local_name { $$=mknode(F_ARG_LIST,$1,$4); }
+  ;
+
 statements: { $$=0; }
   | statements statement
   {
@@ -1136,7 +1197,8 @@ optional_comma_expr: { $$=0; }
   ;
 
 comma_expr: comma_expr2
-  | simple_type local_name_list { $$=$2; free_node($1); }
+  | simple_type2 local_name_list { $$=$2; free_node($1); }
+  | simple_identifier_type local_name_list2 { $$=$2; free_node($1); }
   ;
           
 
@@ -1452,7 +1514,7 @@ sscanf: F_SSCANF '(' expr0 ',' expr0 lvalue_list ')'
 
 lvalue: expr4
   | '[' low_lvalue_list ']' { $$=mknode(F_ARRAY_LVALUE, $2,0); }
-  | type F_IDENTIFIER
+  | type6 F_IDENTIFIER
   {
     add_local_name($2->u.sval.u.string,pop_type());
     $$=mklocalnode(islocal($2->u.sval.u.string));
diff --git a/src/lex.c b/src/lex.c
index 51882968f7..681ab6dad1 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: lex.c,v 1.49 1998/04/06 20:36:20 hubbe Exp $");
+RCSID("$Id: lex.c,v 1.50 1998/04/10 22:24:20 hubbe Exp $");
 #include "language.h"
 #include "array.h"
 #include "lex.h"
@@ -814,6 +814,9 @@ static int yylex2(YYSTYPE *yylval)
 	  case TWO_CHAR('e','l'):
 	    if(ISWORD("else")) return F_ELSE;
 	  break;
+	  case TWO_CHAR('f','i'):
+	    if(ISWORD("final")) return F_FINAL_ID;
+	  break;
 	  case TWO_CHAR('f','l'):
 	    if(ISWORD("float")) return F_FLOAT_ID;
 	  break;
@@ -841,6 +844,9 @@ static int yylex2(YYSTYPE *yylval)
 	  case TWO_CHAR('l','a'):
 	    if(ISWORD("lambda")) return F_LAMBDA;
 	  break;
+	  case TWO_CHAR('l','o'):
+	    if(ISWORD("local")) return F_LOCAL_ID;
+	  break;
 	  case TWO_CHAR('m','a'):
 	    if(ISWORD("mapping")) return F_MAPPING_ID;
 	  break;
diff --git a/src/pike_memory.c b/src/pike_memory.c
index cba84ca1c6..67d1fa5d31 100644
--- a/src/pike_memory.c
+++ b/src/pike_memory.c
@@ -9,7 +9,7 @@
 #include "pike_macros.h"
 #include "gc.h"
 
-RCSID("$Id: pike_memory.c,v 1.19 1998/04/06 04:29:27 hubbe Exp $");
+RCSID("$Id: pike_memory.c,v 1.20 1998/04/10 22:24:20 hubbe Exp $");
 
 /* strdup() is used by several modules, so let's provide it */
 #ifndef HAVE_STRDUP
@@ -466,6 +466,10 @@ int verbose_debug_exit = 1;
 #define LHSIZE 1109891
 #define FLSIZE 8803
 #define DEBUG_MALLOC_PAD 8
+#define FREE_DELAY 256
+
+static void *blocks_to_free[FREE_DELAY];
+static unsigned int blocks_to_free_ptr=0;
 
 struct fileloc
 {
@@ -490,7 +494,7 @@ BLOCK_ALLOC(memloc, 16382)
 struct memhdr
 {
   struct memhdr *next;
-  size_t size;
+  long size;
   void *data;
   struct memloc *locations;
 };
@@ -526,7 +530,14 @@ void check_pad(struct memhdr *mh)
 {
   long q,e;
   char *mem=mh->data;
-  size_t size=mh->size;
+  size_t size;
+  if(mh->size < 0)
+  {
+    fprintf(stderr,"Freeing block %p twice (size %ld)!\n",mem, ~mh->size);
+    dump_memhdr_locations(mh, 0);
+    abort();
+  }
+  size=mh->size;
   q= (((long)mem) ^ 0x555555) + (size * 9248339);
 
 /*  fprintf(stderr,"Checking %p(%d) %ld\n",mem, size, q);  */
@@ -745,6 +756,7 @@ static int remove_memhdr(void *p, int already_gone)
   {
     if(mh->data==p)
     {
+      if(mh->size < 0) mh->size=~mh->size;
       if(!already_gone) check_pad(mh);
 
       *prev=mh->next;
@@ -814,11 +826,25 @@ void *debug_realloc(void *p, size_t s, const char *fn, int line)
 
 void debug_free(void *p, const char *fn, int line)
 {
+  struct memhdr *mh;
+  if(!p) return;
   mt_lock(&debug_malloc_mutex);
-  if(remove_memhdr(p,0))  p=((char *)p) - DEBUG_MALLOC_PAD;
-  free(p);
   if(verbose_debug_malloc)
     fprintf(stderr, "free(%p) (%s:%d)\n", p, fn,line);
+  if((mh=find_memhdr(p)))
+  {
+    void *p2;
+    add_location(mh, location_number(fn,line));
+    MEMSET(p, 0x55, mh->size);
+    mh->size = ~mh->size;
+    blocks_to_free_ptr++;
+    blocks_to_free_ptr%=FREE_DELAY;
+    p2=blocks_to_free[blocks_to_free_ptr];
+    blocks_to_free[blocks_to_free_ptr]=p;
+    p=p2;
+  }
+  if(remove_memhdr(p,0))  p=((char *)p) - DEBUG_MALLOC_PAD;
+  free(p);
   mt_unlock(&debug_malloc_mutex);
 }
 
@@ -862,6 +888,15 @@ void cleanup_memhdrs()
 {
   unsigned long h;
   mt_lock(&debug_malloc_mutex);
+  for(h=0;h<FREE_DELAY;h++)
+  {
+    void *p;
+    if((p=blocks_to_free[h]))
+    {
+      if(remove_memhdr(p,0))  p=((char *)p) - DEBUG_MALLOC_PAD;
+      free(p);
+    }
+  }
   if(verbose_debug_exit)
   {
     int first=1;
@@ -878,7 +913,7 @@ void cleanup_memhdrs()
 	}
 
 	
-	fprintf(stderr, "LEAK: (%p) %d bytes\n",m->data, m->size);
+	fprintf(stderr, "LEAK: (%p) %ld bytes\n",m->data, m->size);
 #ifdef DEBUG
 	describe_something(m->data, attempt_to_identify(m->data),0);
 #endif
diff --git a/src/pike_types.c b/src/pike_types.c
index 53511ee460..5c16993dad 100644
--- a/src/pike_types.c
+++ b/src/pike_types.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: pike_types.c,v 1.37 1998/04/09 02:47:47 hubbe Exp $");
+RCSID("$Id: pike_types.c,v 1.38 1998/04/10 22:24:21 hubbe Exp $");
 #include <ctype.h>
 #include "svalue.h"
 #include "pike_types.h"
@@ -46,6 +46,11 @@ static int type_length(char *t);
  * note that the type after T_MANY can be T_VOID
  * T_MIXED matches anything except T_VOID
  * T_UNKNOWN only matches T_MIXED and T_UNKNOWN
+ * objects are coded thus:
+ * T_OBJECT <0/1> <program_id>
+ *           ^
+ *           0 means 'inherits'
+ *           1 means 'is'
  */
 
 struct pike_string *string_type_string;
@@ -90,7 +95,7 @@ static void CHECK_TYPE(struct pike_string *s)
   if(type_length(s->str) != s->len)
   {
     stupid_describe_type(s->str,s->len);
-    fatal("Length of type is wrong.\n");
+    fatal("Length of type is wrong. (should be %d, is %d)\n",type_length(s->str),s->len);
   }
 }
 #else
@@ -164,6 +169,7 @@ static int type_length(char *t)
       break;
       
     case T_OBJECT:
+      t++;
       t+=sizeof(INT32);
       break;
   }
@@ -271,6 +277,7 @@ static void push_unfinished_type_with_markers(char *s, struct pike_string **am)
 	push_type(EXTRACT_UCHAR(s+ ++e));
 	push_type(EXTRACT_UCHAR(s+ ++e));
 	push_type(EXTRACT_UCHAR(s+ ++e));
+	push_type(EXTRACT_UCHAR(s+ ++e));
 	break;
 	
       default:
@@ -339,6 +346,7 @@ static void internal_parse_typeA(char **_s)
   else if(!strcmp(buf,"object"))
   {
     push_type_int(0);
+    push_type(0);
     push_type(T_OBJECT);
   }
   else if(!strcmp(buf,"program")) push_type(T_PROGRAM);
@@ -583,8 +591,10 @@ void stupid_describe_type(char *a,INT32 len)
       case T_STRING: printf("string"); break;
       case T_PROGRAM: printf("program"); break;
       case T_OBJECT:
-	printf("object(%ld)",(long)EXTRACT_INT(a+e+1));
-	e+=sizeof(INT32);
+	printf("object(%s %ld)",
+	       EXTRACT_UCHAR(a+e+1)?"inherits":"clone of",
+	       (long)EXTRACT_INT(a+e+2));
+	e+=sizeof(INT32)+1;
 	break;
       case T_FUNCTION: printf("function"); break;
       case T_ARRAY: printf("array"); break;
@@ -636,7 +646,7 @@ char *low_describe_type(char *t)
     case T_PROGRAM: my_strcat("program"); break;
     case T_OBJECT:
       my_strcat("object");
-      t+=4;
+      t+=sizeof(INT32)+1;
       /* Prog id */
       break;
     case T_STRING: my_strcat("string"); break;
@@ -837,6 +847,38 @@ static struct pike_string *or_pike_types(struct pike_string *a,
   return pop_unfinished_type();
 }
 
+static struct pike_string *low_object_fun_type(char *t,
+					       struct pike_string *tmp)
+{
+  struct program *p;
+  int i;
+  p=id_to_program(EXTRACT_INT(t+2));
+  if(!p) return 0;
+  i=FIND_LFUN(p, LFUN_CALL);
+
+  if(EXTRACT_UCHAR(t+1) ||
+     (p->identifier_references[i].id_flags & ID_NOMASK) ||
+    (ID_FROM_INT(p, i)->identifier_flags & IDENTIFIER_PROTOTYPED))
+    return ID_FROM_INT(p, i)->type;
+
+  return 0;
+}
+
+static struct pike_string *low_object_lfun_type(char *t, short lfun)
+{
+  struct program *p;
+  int i;
+  p=id_to_program(EXTRACT_INT(t+2));
+  if(!p) return 0;
+  i=FIND_LFUN(p, LFUN_CALL);
+
+  if(EXTRACT_UCHAR(t+1) ||
+     (p->identifier_references[i].id_flags & ID_NOMASK) ||
+    (ID_FROM_INT(p, i)->identifier_flags & IDENTIFIER_PROTOTYPED))
+    return ID_FROM_INT(p, i)->type;
+
+  return 0;
+}
 
 #define A_EXACT 1
 #define B_EXACT 2
@@ -952,25 +994,17 @@ static char *low_match_types(char *a,char *b, int flags)
     return a;
   case TWOT(T_OBJECT, T_FUNCTION):
   {
-    struct program *p;
-    if((p=id_to_program(EXTRACT_INT(a+1))))
-    {
-      int i=FIND_LFUN(p,LFUN_CALL);
-      if(i == -1) return 0;
-      return low_match_types(ID_FROM_INT(p, i)->type->str, b, flags);
-    }
+    struct pike_string *s;
+    if((s=low_object_lfun_type(a, LFUN_CALL)))
+       return low_match_types(s->str,b,flags);
     return a;
   }
 
   case TWOT(T_FUNCTION, T_OBJECT):
   {
-    struct program *p;
-    if((p=id_to_program(EXTRACT_INT(b+1))))
-    {
-      int i=FIND_LFUN(p,LFUN_CALL);
-      if(i == -1) return 0;
-      return low_match_types(a, ID_FROM_INT(p, i)->type->str, flags);
-    }
+    struct pike_string *s;
+    if((s=low_object_lfun_type(b, LFUN_CALL)))
+       return low_match_types(a,s->str,flags);
     return a;
   }
   }
@@ -1030,10 +1064,40 @@ static char *low_match_types(char *a,char *b, int flags)
     break;
 
   case T_OBJECT:
-    a++;
-    b++;
-    if(!EXTRACT_INT(a) || !EXTRACT_INT(b)) break;
-    if(EXTRACT_INT(a) != EXTRACT_INT(b)) return 0;
+    /* object(* 0) matches any object */
+    if(!EXTRACT_INT(a+2) || !EXTRACT_INT(b+2)) break;
+
+    /* object(x *) =? object(x *) */
+    if(EXTRACT_UCHAR(a+1) == EXTRACT_UCHAR(b+1))
+    {
+      /* x? */
+      if(EXTRACT_UCHAR(a+1))
+      {
+	/* object(1 x) =? object(1 x) */
+	if(EXTRACT_INT(a+2) != EXTRACT_INT(b+2)) return 0;
+      }else{
+	/* object(0 *) =? object(0 *) */
+	break;
+      }
+    }
+
+    {
+      struct program *ap,*bp;
+      ap=id_to_program(EXTRACT_UCHAR(a+2));
+      bp=id_to_program(EXTRACT_UCHAR(b+2));
+
+      if(!ap || !bp) break;
+      
+      if(EXTRACT_UCHAR(a+1))
+      {
+	if(low_get_storage(bp,ap)==-1)
+	  return 0;
+      }else{
+	if(low_get_storage(ap,bp)==-1)
+	  return 0;
+      }
+    }
+    
     break;
 
   case T_MULTISET:
@@ -1121,6 +1185,7 @@ static int low_get_return_type(char *a,char *b)
 
     case T_PROGRAM:
       push_type_int(0);
+      push_type(0);
       push_type(T_OBJECT);
       return 1;
 
@@ -1155,7 +1220,7 @@ static struct pike_string *debug_low_index_type(char *t, node *n)
   {
   case T_OBJECT:
   {
-    struct program *p=id_to_program(EXTRACT_INT(t));
+    struct program *p=id_to_program(EXTRACT_INT(t+1));
     if(p && n)
     {
       if(n->token == F_ARROW)
@@ -1181,8 +1246,16 @@ static struct pike_string *debug_low_index_type(char *t, node *n)
 	  reference_shared_string(int_type_string);
 	  return int_type_string;
 	}else{
-	  reference_shared_string(ID_FROM_INT(p, i)->type);
-	  return ID_FROM_INT(p, i)->type;
+	  if(EXTRACT_UCHAR(t) ||
+	     (p->identifier_references[i].id_flags & ID_NOMASK) ||
+	    (ID_FROM_INT(p, i)->identifier_flags & IDENTIFIER_PROTOTYPED))
+	  {
+	    reference_shared_string(ID_FROM_INT(p, i)->type);
+	    return ID_FROM_INT(p, i)->type;
+	  }else{
+	    reference_shared_string(mixed_type_string);
+	    return mixed_type_string;
+	  }
 	}	   
       }
     }
@@ -1276,16 +1349,16 @@ static int low_check_indexing(char *type, char *index_type, node *n)
 
   case T_OBJECT:
   {
-    struct program *p=id_to_program(EXTRACT_INT(type));
+    struct program *p=id_to_program(EXTRACT_INT(type+1));
     if(p)
     {
       if(n->token == F_ARROW)
       {
-	if(FIND_LFUN(p,LFUN_ARROW) != -1 || FIND_LFUN(p,LFUN_ASSIGN_ARROW) != -1)
-	return 1;
+	if(FIND_LFUN(p,LFUN_ARROW)!=-1 || FIND_LFUN(p,LFUN_ASSIGN_ARROW)!=-1)
+	  return 1;
       }else{
-	if(FIND_LFUN(p,LFUN_INDEX) != -1 || FIND_LFUN(p,LFUN_ASSIGN_INDEX) != -1)
-	return 1;
+	if(FIND_LFUN(p,LFUN_INDEX)!=-1 || FIND_LFUN(p,LFUN_ASSIGN_INDEX)!=-1)
+	  return 1;
       }
       return !!low_match_types(string_type_string->str, index_type,0);
     }else{
@@ -1440,8 +1513,10 @@ struct pike_string *get_type_of_svalue(struct svalue *s)
     if(s->u.object->prog)
     {
       push_type_int(s->u.object->prog->id);
+      push_type(1);
     }else{
       push_type_int(0);
+      push_type(0);
     }
     push_type(T_OBJECT);
     return pop_unfinished_type();
@@ -1470,6 +1545,7 @@ struct pike_string *get_type_of_svalue(struct svalue *s)
     {
       type_stack_mark();
       push_type_int(s->u.program->id);
+      push_type(1);
       push_type(T_OBJECT);
       
       type_stack_mark();
diff --git a/src/program.c b/src/program.c
index 5bbb7d645a..268b268b39 100644
--- a/src/program.c
+++ b/src/program.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: program.c,v 1.75 1998/04/10 18:38:15 grubba Exp $");
+RCSID("$Id: program.c,v 1.76 1998/04/10 22:24:21 hubbe Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -2287,12 +2287,12 @@ static struct get_storage_cache
   INT32 oid, pid, offset;
 } get_storage_cache[GET_STORAGE_CACHE_SIZE];
 
-char *get_storage(struct object *o, struct program *p)
+int low_get_storage(struct program *o, struct program *p)
 {
   INT32 oid,pid, offset;
   unsigned INT32 hval;
-  if(!o->prog) return 0;
-  oid=o->prog->id;
+  if(!o) return 0;
+  oid=o->id;
   pid=p->id;
   hval=oid*9248339 + pid;
   hval%=GET_STORAGE_CACHE_SIZE;
@@ -2307,11 +2307,11 @@ char *get_storage(struct object *o, struct program *p)
   }else{
     INT32 e;
     offset=-1;
-    for(e=0;e<o->prog->num_inherits;e++)
+    for(e=0;e<o->num_inherits;e++)
     {
-      if(o->prog->inherits[e].prog==p)
+      if(o->inherits[e].prog==p)
       {
-	offset=o->prog->inherits[e].storage_offset;
+	offset=o->inherits[e].storage_offset;
 	break;
       }
     }
@@ -2321,6 +2321,12 @@ char *get_storage(struct object *o, struct program *p)
     get_storage_cache[hval].offset=offset;
   }
 
+  return offset;
+}
+
+char *get_storage(struct object *o, struct program *p)
+{
+  int offset= low_get_storage(o->prog, p);
   if(offset == -1) return 0;
   return o->storage + offset;
 }
diff --git a/src/program.h b/src/program.h
index eb3be4ccd2..28cc725110 100644
--- a/src/program.h
+++ b/src/program.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: program.h,v 1.38 1998/04/09 02:49:48 hubbe Exp $
+ * $Id: program.h,v 1.39 1998/04/10 22:24:22 hubbe Exp $
  */
 #ifndef PROGRAM_H
 #define PROGRAM_H
@@ -108,6 +108,7 @@ union idptr
 #define IDENTIFIER_FUNCTION 3
 #define IDENTIFIER_CONSTANT 4
 #define IDENTIFIER_VARARGS 8
+#define IDENTIFIER_PROTOTYPED 16
 
 #define IDENTIFIER_IS_FUNCTION(X) ((X) & IDENTIFIER_FUNCTION)
 #define IDENTIFIER_IS_CONSTANT(X) ((X) & IDENTIFIER_CONSTANT)
@@ -350,6 +351,7 @@ void count_memory_in_programs(INT32 *num_, INT32 *size_);
 void push_compiler_frame(void);
 void pop_local_variables(int level);
 void pop_compiler_frame(void);
+int low_get_storage(struct program *o, struct program *p);
 char *get_storage(struct object *o, struct program *p);
 struct program *low_program_from_function(struct program *p,
 					  INT32 i);
diff --git a/src/testsuite.in b/src/testsuite.in
index 50f4989717..30ea496b47 100644
--- a/src/testsuite.in
+++ b/src/testsuite.in
@@ -1,4 +1,4 @@
-test_true([["$Id: testsuite.in,v 1.87 1998/04/10 04:49:55 hubbe Exp $"]])
+test_true([["$Id: testsuite.in,v 1.88 1998/04/10 22:24:22 hubbe Exp $"]])
 test_eq(1e1,10.0)
 test_eq(1E1,10.0)
 test_eq(1e+1,10.0)
@@ -13,6 +13,13 @@ bar"]],[["foo\nbar"]])
 test_true([[stringp(#string "Makefile")]])
 test_any([[class Bar { array(int) foo = ({}); }; class Foo { inherit Bar; array(int) foo = ({1}); }; return sizeof(Foo()->foo);]],1)
 
+test_compile([[Stdio.File foo=Stdio.File();]])
+test_compile([[class { Stdio.File foo=Stdio.File(); }]])
+test_compile_any([[void foo(Stdio.FILE f) {}]])
+test_compile_any([[void foo(array(Stdio.FILE) f) {}]])
+test_compile_any([[void foo(array(Stdio.FILE) f) {}]])
+test_compile_any([[Stdio.File foo(array(Stdio.FILE) f) { return f[0]; }]])
+test_compile([[Stdio.File foo=Stdio.FILE();]])
 
 test_any([[object(Stdio.File) f; f=Stdio.File(); return 1]],1)
 test_compile([[int t=gauge { string foo; };]])
@@ -171,7 +178,10 @@ test_program(inherit test;)
 test_program(inherit test; int a() { return foo; } )
 test_define_program(test,[[class TEST { int a() { return 1; } }]])
 test_program(inherit test; inherit TEST; )
-test_compile_error(class c { object(Stdio.File) foo; object(Regexp) bar=foo; })
+
+dnl This test cannot be performed without a way to tell the
+dnl compiler that foo *is* an Stdio.File, not inherits an Stdio.File
+dnl test_compile_error(class c { object(Stdio.File) foo; object(Regexp) bar=foo; })
 test_do(class c { object foo; object(Regexp) bar=foo; })
 test_do(class c { object(Stdio.File) foo; object bar=foo; })
 test_any(if(int i=1) return i; return 0;,1)
-- 
GitLab