diff --git a/src/pike_types.c b/src/pike_types.c
index bd5bbdd10a5eb6e9ac989727ca5b85d30ec9e0e2..8f603ebfda19dc18b95afb61de04fc9e73019967 100644
--- a/src/pike_types.c
+++ b/src/pike_types.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: pike_types.c,v 1.69 1999/11/21 21:10:12 grubba Exp $");
+RCSID("$Id: pike_types.c,v 1.70 1999/11/23 22:35:44 grubba Exp $");
 #include <ctype.h>
 #include "svalue.h"
 #include "pike_types.h"
@@ -21,6 +21,7 @@ RCSID("$Id: pike_types.c,v 1.69 1999/11/21 21:10:12 grubba Exp $");
 #include "error.h"
 #include "las.h"
 #include "language.h"
+#include "lex.h"
 #include "pike_memory.h"
 #include "bignum.h"
 
@@ -28,6 +29,7 @@ int max_correct_args;
 
 static void internal_parse_type(char **s);
 static int type_length(char *t);
+static int low_pike_types_le(char *a, char *b);
 
 #define TWOT(X,Y) (((X) << 8)+(Y))
 #define EXTRACT_TWOT(X,Y) TWOT(EXTRACT_UCHAR(X), EXTRACT_UCHAR(Y))
@@ -53,6 +55,7 @@ static int type_length(char *t);
  *           ^
  *           0 means 'inherits'
  *           1 means 'is'
+ * Everything except T_VOID matches T_ZERO.
  */
 
 struct pike_string *string_type_string;
@@ -66,6 +69,7 @@ struct pike_string *multiset_type_string;
 struct pike_string *mapping_type_string;
 struct pike_string *mixed_type_string;
 struct pike_string *void_type_string;
+struct pike_string *zero_type_string;
 struct pike_string *any_type_string;
 
 static struct pike_string *a_markers[10],*b_markers[10];
@@ -115,6 +119,7 @@ void init_types(void)
   mapping_type_string=CONSTTYPE(tMapping);
   function_type_string=CONSTTYPE(tFunction);
   void_type_string=CONSTTYPE(tVoid);
+  zero_type_string=CONSTTYPE(tZero);
   any_type_string=CONSTTYPE(tOr(tVoid,tMix));
 }
 
@@ -163,6 +168,7 @@ one_more_type:
     case T_PROGRAM:
     case T_MIXED:
     case T_VOID:
+    case T_ZERO:
     case T_UNKNOWN:
       break;
 
@@ -719,6 +725,7 @@ void stupid_describe_type(char *a,INT32 len)
       case T_AND: printf("and"); break;
       case T_NOT: printf("not"); break;
       case T_VOID: printf("void"); break;
+      case T_ZERO: printf("zero"); break;
       case T_MIXED: printf("mixed"); break;
 	
       default: printf("%d",EXTRACT_UCHAR(a+e)); break;
@@ -751,6 +758,7 @@ char *low_describe_type(char *t)
       break;
       
     case T_VOID: my_strcat("void"); break;
+    case T_ZERO: my_strcat("zero"); break;
     case T_MIXED: my_strcat("mixed"); break;
     case T_UNKNOWN: my_strcat("unknown"); break;
     case T_INT:
@@ -898,6 +906,9 @@ static TYPE_T low_compile_type_to_runtime_type(char *t)
     default:
       return T_MIXED;
 
+  case T_ZERO:
+    return T_INT;
+
     case T_ARRAY:
     case T_MAPPING:
     case T_MULTISET:
@@ -956,10 +967,14 @@ static void low_or_pike_types(char *t1, char *t2)
     else
       push_unfinished_type(t2);
   }
-  else if(!t2)
+  else if((!t2) || (EXTRACT_UCHAR(t2) == T_ZERO))
   {
     push_unfinished_type(t1);
   }
+  else if (EXTRACT_UCHAR(t1) == T_ZERO)
+  {
+    push_unfinished_type(t2);
+  }
   else if(EXTRACT_UCHAR(t1)==T_MIXED || EXTRACT_UCHAR(t2)==T_MIXED)
   {
     push_type(T_MIXED);
@@ -1056,8 +1071,10 @@ static int lower_and_pike_types(char *t1, char *t2)
     t1 += type_length(t1);
   }
   switch(EXTRACT_UCHAR(t1)) {
+  case T_ZERO:
   case T_VOID:
     break;
+  case T_PROGRAM:
   case T_STRING:
   case T_FLOAT:
   case T_INT:
@@ -1088,6 +1105,8 @@ static int low_and_push_complex_pike_type(char *type)
   }
   switch(EXTRACT_UCHAR(type)) {
   case T_VOID:
+  case T_ZERO:
+  case T_PROGRAM:
   case T_STRING:
   case T_FLOAT:
   case T_INT:
@@ -1105,16 +1124,15 @@ static int low_and_push_complex_pike_type(char *type)
 
 static void low_and_pike_types(char *t1, char *t2)
 {
-  if(!t1)
+  if(!t1 || EXTRACT_UCHAR(t1) == T_VOID ||
+     !t2 || EXTRACT_UCHAR(t2) == T_VOID)
   {
-    if(!t2)
-      push_type(T_VOID);
-    else
-      push_unfinished_type(t2);
+    push_type(T_VOID);
   }
-  else if(!t2)
+  else if(EXTRACT_UCHAR(t1) == T_ZERO ||
+	  EXTRACT_UCHAR(t2) == T_ZERO)
   {
-    push_unfinished_type(t1);
+    push_type(T_ZERO);
   }
   else if(EXTRACT_UCHAR(t1)==T_MIXED)
   {
@@ -1124,10 +1142,6 @@ static void low_and_pike_types(char *t1, char *t2)
   {
     push_unfinished_type(t1);
   }
-  else if(EXTRACT_UCHAR(t1)==T_VOID || EXTRACT_UCHAR(t2)==T_VOID)
-  {
-    push_type(T_VOID);
-  }
   else if(EXTRACT_UCHAR(t1)==T_INT && EXTRACT_UCHAR(t2)==T_INT)
   {
     INT32 i1,i2;
@@ -1151,13 +1165,22 @@ static void low_and_pike_types(char *t1, char *t2)
     }
   }
   else if((EXTRACT_UCHAR(t1)==T_STRING && EXTRACT_UCHAR(t2)==T_STRING) ||
-	  (EXTRACT_UCHAR(t1)==T_FLOAT && EXTRACT_UCHAR(t2)==T_FLOAT))
+	  (EXTRACT_UCHAR(t1)==T_FLOAT && EXTRACT_UCHAR(t2)==T_FLOAT) ||
+	  (EXTRACT_UCHAR(t1)==T_PROGRAM && EXTRACT_UCHAR(t2)==T_PROGRAM))
   {
     push_unfinished_type(t1);
   }
+  else if(low_pike_types_le(t1, t2))
+  {
+    push_unfinished_type(t1);
+  }
+  else if(low_pike_types_le(t2, t1))
+  {
+    push_unfinished_type(t2);
+  }
   else
   {
-    push_type(T_VOID);
+    push_type(T_ZERO);
 
     if (lower_and_pike_types(t1, t2)) {
       /* t1 contains complex types. */
@@ -1314,8 +1337,13 @@ static char *low_match_types(char *a,char *b, int flags)
   }
 
   /* 'mixed' matches anything */
-  if(EXTRACT_UCHAR(a) == T_MIXED && !(flags & A_EXACT)) return a;
   if(EXTRACT_UCHAR(b) == T_MIXED && !(flags & B_EXACT)) return a;
+  if(EXTRACT_UCHAR(a) == T_ZERO && !(flags & A_EXACT) &&
+     EXTRACT_UCHAR(b) != T_VOID) return a;
+  if(EXTRACT_UCHAR(a) == T_MIXED && !(flags & A_EXACT)) return a;
+  if(EXTRACT_UCHAR(b) == T_ZERO && !(flags & B_EXACT) &&
+     EXTRACT_UCHAR(a) != T_VOID) return a;
+
 
   /* Special cases (tm) */
   switch(EXTRACT_TWOT(a,b))
@@ -1461,6 +1489,296 @@ static char *low_match_types(char *a,char *b, int flags)
   case T_FLOAT:
   case T_STRING:
   case T_PROGRAM:
+  case T_ZERO:
+  case T_VOID:
+  case T_MIXED:
+    break;
+
+  default:
+    fatal("error in type string.\n");
+  }
+  return ret;
+}
+
+/*
+ * Check the partial ordering relation.
+ *
+ *                 mixed
+ *
+ * int float string program function object
+ *
+ *                 zero
+ *
+ *                 void
+ */
+static int low_pike_types_le(char *a,char *b)
+{
+  int ret;
+  if(a == b) return 1;
+
+  switch(EXTRACT_UCHAR(a))
+  {
+  case T_AND:
+    /* OK if either of the parts is a subset. */
+    /* FIXME: What if b also contains an AND? */
+    a++;
+    ret = low_pike_types_le(a,b);
+    if(ret) return ret;
+    a += type_length(a);
+    return low_pike_types_le(a,b);
+
+  case T_OR:
+    /* OK, if both of the parts are a subset */
+    a++;
+    ret=low_pike_types_le(a,b);
+    if (!ret) return 0;
+    a+=type_length(a);
+    return low_pike_types_le(a,b);
+
+  case T_NOT:
+    return !low_pike_types_le(a+1,b);
+
+  case T_ASSIGN:
+    ret=low_pike_types_le(a+2,b);
+    if(ret && EXTRACT_UCHAR(b)!=T_VOID)
+    {
+      int m=EXTRACT_UCHAR(a+1)-'0';
+      type_stack_mark();
+      low_or_pike_types(a_markers[m] ? a_markers[m]->str : 0,b);
+      if(a_markers[m]) free_string(a_markers[m]);
+      a_markers[m]=pop_unfinished_type();
+    }
+    return ret;
+
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+    {
+      int m=EXTRACT_UCHAR(a)-'0';
+      if(a_markers[m])
+	return low_pike_types_le(a_markers[m]->str, b);
+      else
+	return low_pike_types_le(mixed_type_string->str, b);
+    }
+  }
+
+  switch(EXTRACT_UCHAR(b))
+  {
+  case T_AND:
+    /* OK, if a is a subset of both parts. */
+    b++;
+    ret = low_pike_types_le(a,b);
+    if(!ret) return 0;
+    b+=type_length(b);
+    return low_pike_types_le(a,b);
+
+  case T_OR:
+    /* OK if a is a subset of either of the parts. */
+    b++;
+    ret=low_pike_types_le(a,b);
+    if (ret) return ret;
+    b+=type_length(b);
+    return low_pike_types_le(a,b);
+
+  case T_NOT:
+    return !low_pike_types_le(a,b+1);
+
+  case T_ASSIGN:
+    ret=low_pike_types_le(a,b+2);
+    if(ret && EXTRACT_UCHAR(a)!=T_VOID)
+    {
+      int m=EXTRACT_UCHAR(b+1)-'0';
+      type_stack_mark();
+      low_or_pike_types(b_markers[m] ? b_markers[m]->str : 0,a);
+      if(b_markers[m]) free_string(b_markers[m]);
+      b_markers[m]=pop_unfinished_type();
+    }
+    return ret;
+
+  case '0': case '1': case '2': case '3': case '4':
+  case '5': case '6': case '7': case '8': case '9':
+    {
+      int m=EXTRACT_UCHAR(b)-'0';
+      if(b_markers[m])
+	return low_pike_types_le(a, b_markers[m]->str);
+      else
+	return low_pike_types_le(a, mixed_type_string->str);
+    }
+
+  case T_MIXED:
+    /* any_type <= 'mixed' */
+    return 1;
+  }
+
+  if (EXTRACT_UCHAR(a) == T_MIXED) {
+    return 0;
+  }
+
+  if (EXTRACT_UCHAR(a) == T_VOID) {
+    /* void <= any_type */
+    return 1;
+  }
+
+  if (EXTRACT_UCHAR(b) == T_VOID) {
+    return 0;
+  }
+
+  if (EXTRACT_UCHAR(a) == T_ZERO) {
+    /* void <= zero <= any_type */
+    return 1;
+  }
+
+  if (EXTRACT_UCHAR(b) == T_ZERO) {
+    return 0;
+  }
+
+  /* Special cases (tm) */
+  switch(EXTRACT_TWOT(a,b))
+  {
+  case TWOT(T_PROGRAM, T_FUNCTION):
+  case TWOT(T_FUNCTION, T_PROGRAM):
+    /* FIXME: Not really... Should check the return value. */
+    return 1;
+
+  case TWOT(T_OBJECT, T_FUNCTION):
+    {
+      struct pike_string *s;
+      if((s=low_object_lfun_type(a, LFUN_CALL)))
+	return low_pike_types_le(s->str,b);
+      return 1;
+    }
+
+  case TWOT(T_FUNCTION, T_OBJECT):
+    {
+      struct pike_string *s;
+      if((s=low_object_lfun_type(b, LFUN_CALL)))
+	return low_pike_types_le(a,s->str);
+      return 1;
+    }
+  }
+
+  if(EXTRACT_UCHAR(a) != EXTRACT_UCHAR(b)) return 0;
+
+  ret=1;
+  switch(EXTRACT_UCHAR(a))
+  {
+  case T_FUNCTION:
+    a++;
+    b++;
+    while(EXTRACT_UCHAR(a)!=T_MANY || EXTRACT_UCHAR(b)!=T_MANY)
+    {
+      char *a_tmp,*b_tmp;
+      if(EXTRACT_UCHAR(a)==T_MANY)
+      {
+	a_tmp=a+1;
+      }else{
+	a_tmp=a;
+	a+=type_length(a);
+      }
+
+      if(EXTRACT_UCHAR(b)==T_MANY)
+      {
+	b_tmp=b+1;
+      }else{
+	b_tmp=b;
+	b+=type_length(b);
+      }
+
+      if(!low_pike_types_le(a_tmp, b_tmp)) return 0;
+    }
+    /* check the 'many' type */
+    a++;
+    b++;
+    if (!low_pike_types_le(a, b))
+      return 0;
+
+    a+=type_length(a);
+    b+=type_length(b);
+
+    /* check the returntype */
+    /* NOTE: The order between a & b is switched. */
+    if(!low_pike_types_le(b,a)) return 0;
+    break;
+
+  case T_MAPPING:
+    /*
+     *  mapping(A:B) <= mapping(C:D)   iff C <= A && B <= D.
+     */
+    if(!low_pike_types_le(++b,++a)) return 0;
+    return low_pike_types_le(a+type_length(a),b+type_length(b));
+
+  case T_OBJECT:
+#if 0
+    if(extract_type_int(a+2) || extract_type_int(b+2))
+    {
+      fprintf(stderr,"Type match1: ");
+      stupid_describe_type(a,type_length(a));
+      fprintf(stderr,"Type match2: ");
+      stupid_describe_type(b,type_length(b));
+    }
+#endif
+
+    /* object(* 0) matches any object */
+    if(!extract_type_int(b+2))
+      return 1;
+
+    if(!extract_type_int(a+2))
+      return 0;
+    
+
+    /* 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_type_int(a+2) != extract_type_int(b+2)) return 0;
+      }else{
+	/* object(0 *) =? object(0 *) */
+	break;
+      }
+    }
+
+    {
+      struct program *ap,*bp;
+      ap=id_to_program(extract_type_int(a+2));
+      bp=id_to_program(extract_type_int(b+2));
+
+      if(!ap || !bp) break;
+
+      if(EXTRACT_UCHAR(a+1))
+      {
+	if(!implements(ap,bp))
+	  return 0;
+      }else{
+	if(!implements(bp,ap))
+	  return 0;
+      }
+    }
+    
+    break;
+
+  case T_INT:
+  {
+    INT32 amin=extract_type_int(a+1);
+    INT32 amax=extract_type_int(a+1+sizeof(INT32));
+
+    INT32 bmin=extract_type_int(b+1);
+    INT32 bmax=extract_type_int(b+1+sizeof(INT32));
+    
+    if(amin < bmin || amax > bmax) return 0;
+    break;
+  }
+    
+
+  case T_MULTISET:
+  case T_ARRAY:
+    if(!low_pike_types_le(++a,++b)) return 0;
+
+  case T_FLOAT:
+  case T_STRING:
+  case T_PROGRAM:
+  case T_ZERO:
   case T_VOID:
   case T_MIXED:
     break;
@@ -1559,6 +1877,14 @@ int match_types(struct pike_string *a,struct pike_string *b)
   return 0!=low_match_types(a->str, b->str,0);
 }
 
+int pike_types_le(struct pike_string *a,struct pike_string *b)
+{
+  check_type_string(a);
+  check_type_string(b);
+  clear_markers();
+  return low_pike_types_le(a->str, b->str);
+}
+
 
 #ifdef DEBUG_MALLOC
 #define low_index_type(X,Y) ((struct pike_string *)debug_malloc_touch(debug_low_index_type((X),(Y))))
@@ -1629,6 +1955,7 @@ static struct pike_string *debug_low_index_type(char *t, node *n)
       p=get_auto_bignum_program_or_zero();
       goto comefrom_int_index;
 #endif
+    case T_ZERO:
     case T_VOID:
     case T_FLOAT:
       return 0;
@@ -1732,6 +2059,7 @@ static struct pike_string *debug_low_key_type(char *t, node *n)
     return mixed_type_string;
 
     case T_VOID:
+    case T_ZERO:
     case T_FLOAT:
     case T_INT:
       return 0;
@@ -2100,7 +2428,7 @@ struct pike_string *get_type_of_svalue(struct svalue *s)
       push_type(T_INT);
       return pop_unfinished_type();
     }else{
-      ret=mixed_type_string;
+      ret=zero_type_string;
     }
     reference_shared_string(ret);
     return ret;
@@ -2141,6 +2469,7 @@ char *get_name_of_type(int t)
     case T_OBJECT: return "object";
     case T_PROGRAM: return "program";
     case T_STRING: return "string";
+    case T_ZERO: return "zero";
     case T_VOID: return "void";
     default: return "unknown";
   }
@@ -2159,6 +2488,7 @@ void cleanup_pike_types(void)
   free_string(mapping_type_string);
   free_string(mixed_type_string);
   free_string(void_type_string);
+  free_string(zero_type_string);
   free_string(any_type_string);
 }