system/src/sc/lang/java/ModelUtil.java
public static boolean isAssignableFrom(Object type1, Object type2, boolean assignmentSemantics, ITypeParamContext ctx, boolean allowUnbound, LayeredSystem sys) {
      if (type1 == type2)
         return true;

      if (type2 == NullLiteral.NULL_TYPE) {
         if (ModelUtil.isPrimitive(type1))
            return false;
         return true;
      }

      if (type1 instanceof TypeParameter) {
         // There java.lang.Void.class will match a type parameter
         //if (typeIsVoid(type2))
         //   return false;
         // Force primitive types to be their wrapper type so we find matches for Comparable and int
         return ((TypeParameter)type1).isAssignableFrom(wrapPrimitiveType(type2), ctx, allowUnbound);
      }
      if (type2 instanceof TypeParameter) {
         if (allowUnbound) {
            // TODO: enforce the extends type in the TypeParameter
            return true;
         }
         return ((TypeParameter)type2).isAssignableTo(type1, ctx, true /* allowUnbound */);
      }

      while (type1 instanceof TypeVariable) {
         type1 = ((TypeVariable) type1).getBounds()[0];
      }

      if (type2 instanceof TypeVariable) {
         do {
            type2 = ((TypeVariable) type2).getBounds()[0];
         }
         while (type2 instanceof TypeVariable);
         // If we have a type parameter that's not bound and are just matching for an incompatibility, only
         // reject the match if the bounds for the type is incompatible
         if (allowUnbound) {
            if (!ModelUtil.isAssignableFrom(type2, type1))
               return false;
            return true;
         }
      }

      boolean type1Num = isANumber(type1);
      boolean type2Num = isANumber(type2);
      if (type1Num && type2Num)
         // Note: switching the order here to "lhs" = "rhs"
         return numberTypesAssignableFrom(type1, type2, assignmentSemantics);

      if (isBoolean(type1) && isBoolean(type2))
         return true;

      boolean type1Char = isCharacter(type1);
      boolean type2Char = isCharacter(type2);
      if (type1Char && type2Char)
         return true;

      // Characters can be assigned to ints and vice versa during assignments only
      if (assignmentSemantics) {
         if ((type1Char && type2Num) || (type2Char && type1Num))
            return true;
      }
      else {
         // Method parameters - an integer can be assigned with a character argument
         if (isAnInteger(type1) && type2Char)
            return true;
      }

      while (type1 instanceof ParameterizedType)
         type1 = ((ParameterizedType) type1).getRawType();

      while (type2 instanceof ParameterizedType)
         type2 = ((ParameterizedType) type2).getRawType();

      if (type1 instanceof Class) {
         // Accepts double and other types assuming the unboxing rules in Java
         if (type1 == Object.class) {
            if (typeIsVoid(type2))
               return false;
            return true;
         }
         if (type2 instanceof ITypeDeclaration) {
            // In this case, we need to invert the direction of the test.  Let's see if our TypeDeclaration
            // implements a type with the same name.
            return ((ITypeDeclaration) type2).implementsType(((Class) type1).getName(), assignmentSemantics, allowUnbound);
         }
         else if (type2 instanceof Class) {
            Class cl1 = (Class) type1;
            Class cl2 = (Class) type2;
            boolean res = cl1.isAssignableFrom(cl2);

            // We only need this during the refreshBoundType after resetClassLoader.  Because we refresh references in any order
            // we might temporarily get incompatible class loaders during the refreshBoundTypes operation which prevent us from resolving types properly.
            // It seems like a better fix would be to just fix the order so we resolve things before we reference them?
            ClassLoader cl1Loader = cl1.getClassLoader();
            ClassLoader cl2Loader = cl2.getClassLoader();
            if (!res && cl1Loader != cl2Loader) {
               boolean deactivatedLoader = false;
               LayeredSystem sys1 = null, sys2 = null;
               if (cl1Loader instanceof TrackingClassLoader) {
                  TrackingClassLoader tcl1 = ((TrackingClassLoader) cl1Loader);
                  deactivatedLoader = tcl1.deactivated;
                  sys1 = tcl1.getSystem();
               }
               if (cl2Loader instanceof TrackingClassLoader) {
                  TrackingClassLoader tcl2 = ((TrackingClassLoader) cl2Loader);
                  deactivatedLoader |= tcl2.deactivated;
                  sys2 = tcl2.getSystem();
               }
               // It's possible we have the same class but different class loaders, either because one class loader was deactivated or we are dealing with two different layered systems - i.e.
               // finding an assignment across runtimes like java and js.  If so we need to convert the classes into the same class loader before doing the isAssignableFrom test.
               if (deactivatedLoader || sys1 != sys2) {
                  if (sys != null) {
                     Object ncl1, ncl2;
                     ncl1 = ModelUtil.refreshBoundClass(sys, cl1);
                     ncl2 = ModelUtil.refreshBoundClass(sys, cl2);
                     if (ncl1 != cl1 || ncl2 != cl2)
                        return ModelUtil.isAssignableFrom(ncl1, ncl2, assignmentSemantics, ctx, allowUnbound, sys);
                  }
                  if (ModelUtil.isAssignableByName(cl1, cl2)) {
                     return true;
                  }
               }
            }

            // Java will do a conversion from int to Integer so you can for example cast an int to Comparable and it will work.
            if (!res && cl2.isPrimitive()) {
               Class clWrapper = sc.type.Type.get(cl2).getObjectClass();
               res = isAssignableFrom(cl1, clWrapper);
            }

            return res;
         }
         else if (type2 == null)
            return false;
         else if (type2 instanceof BaseLambdaExpression.LambdaInferredType)
            return true;
         else
            throw new UnsupportedOperationException();
      }
      else if (type1 instanceof ITypeDeclaration) {
         ITypeDeclaration decl1 = (ITypeDeclaration) type1;
         if (type2 instanceof Class) {
            return decl1.isAssignableFromClass((Class) type2);
         }
         if (!(type2 instanceof ITypeDeclaration))
            System.out.println("*** Error - invalid type to isAssignable method");

         if (type2 instanceof BaseLambdaExpression.LambdaInferredType)
            return true;

         ITypeDeclaration decl2 = (ITypeDeclaration) type2;
         return decl1.isAssignableFrom(decl2, assignmentSemantics);
      }
      else if (type1 == null)
         return false;
      else
         throw new UnsupportedOperationException();
   }
/** Note: the LayeredSystem is an optional parameter here for an edge case that allows us to detect mismatching Classes after we've reset the class loader and reload them rather than compare by name. */
the LayeredSystem is an optional parameter here for an edge case that allows us to detect mismatching Classes after we've reset the class loader and reload them rather than compare by name.
the LayeredSystem is an optional parameter here for an edge case that allows us to detect mismatching Classes after we ' ve reset the class loader and reload them rather than compare by name .
public static boolean isAssignableFrom(Object type1, Object type2, boolean assignmentSemantics, ITypeParamContext ctx, boolean allowUnbound, LayeredSystem sys) {
      if (type1 == type2)
         return true;
      if (type2 == NullLiteral.NULL_TYPE) {
         if (ModelUtil.isPrimitive(type1))
            return false;
         return true;
      }
      if (type1 instanceof TypeParameter) {
         return ((TypeParameter)type1).isAssignableFrom(wrapPrimitiveType(type2), ctx, allowUnbound);
      }
      if (type2 instanceof TypeParameter) {
         if (allowUnbound) {
            return true;
         }
         return ((TypeParameter)type2).isAssignableTo(type1, ctx, true /* allowUnbound */);
      }
      while (type1 instanceof TypeVariable) {
         type1 = ((TypeVariable) type1).getBounds()[0];
      }
      if (type2 instanceof TypeVariable) {
         do {
            type2 = ((TypeVariable) type2).getBounds()[0];
         }
         while (type2 instanceof TypeVariable);
         if (allowUnbound) {
            if (!ModelUtil.isAssignableFrom(type2, type1))
               return false;
            return true;
         }
      }
      boolean type1Num = isANumber(type1);
      boolean type2Num = isANumber(type2);
      if (type1Num && type2Num)
         return numberTypesAssignableFrom(type1, type2, assignmentSemantics);
      if (isBoolean(type1) && isBoolean(type2))
         return true;
      boolean type1Char = isCharacter(type1);
      boolean type2Char = isCharacter(type2);
      if (type1Char && type2Char)
         return true;
      if (assignmentSemantics) {
         if ((type1Char && type2Num) || (type2Char && type1Num))
            return true;
      }
      else {
         if (isAnInteger(type1) && type2Char)
            return true;
      }
      while (type1 instanceof ParameterizedType)
         type1 = ((ParameterizedType) type1).getRawType();
      while (type2 instanceof ParameterizedType)
         type2 = ((ParameterizedType) type2).getRawType();
      if (type1 instanceof Class) {
         if (type1 == Object.class) {
            if (typeIsVoid(type2))
               return false;
            return true;
         }
         if (type2 instanceof ITypeDeclaration) {
            return ((ITypeDeclaration) type2).implementsType(((Class) type1).getName(), assignmentSemantics, allowUnbound);
         }
         else if (type2 instanceof Class) {
            Class cl1 = (Class) type1;
            Class cl2 = (Class) type2;
            boolean res = cl1.isAssignableFrom(cl2);
            ClassLoader cl1Loader = cl1.getClassLoader();
            ClassLoader cl2Loader = cl2.getClassLoader();
            if (!res && cl1Loader != cl2Loader) {
               boolean deactivatedLoader = false;
               LayeredSystem sys1 = null, sys2 = null;
               if (cl1Loader instanceof TrackingClassLoader) {
                  TrackingClassLoader tcl1 = ((TrackingClassLoader) cl1Loader);
                  deactivatedLoader = tcl1.deactivated;
                  sys1 = tcl1.getSystem();
               }
               if (cl2Loader instanceof TrackingClassLoader) {
                  TrackingClassLoader tcl2 = ((TrackingClassLoader) cl2Loader);
                  deactivatedLoader |= tcl2.deactivated;
                  sys2 = tcl2.getSystem();
               }
               if (deactivatedLoader || sys1 != sys2) {
                  if (sys != null) {
                     Object ncl1, ncl2;
                     ncl1 = ModelUtil.refreshBoundClass(sys, cl1);
                     ncl2 = ModelUtil.refreshBoundClass(sys, cl2);
                     if (ncl1 != cl1 || ncl2 != cl2)
                        return ModelUtil.isAssignableFrom(ncl1, ncl2, assignmentSemantics, ctx, allowUnbound, sys);
                  }
                  if (ModelUtil.isAssignableByName(cl1, cl2)) {
                     return true;
                  }
               }
            }
            if (!res && cl2.isPrimitive()) {
               Class clWrapper = sc.type.Type.get(cl2).getObjectClass();
               res = isAssignableFrom(cl1, clWrapper);
            }
            return res;
         }
         else if (type2 == null)
            return false;
         else if (type2 instanceof BaseLambdaExpression.LambdaInferredType)
            return true;
         else
            throw new UnsupportedOperationException();
      }
      else if (type1 instanceof ITypeDeclaration) {
         ITypeDeclaration decl1 = (ITypeDeclaration) type1;
         if (type2 instanceof Class) {
            return decl1.isAssignableFromClass((Class) type2);
         }
         if (!(type2 instanceof ITypeDeclaration))
            System.out.println("*** Error - invalid type to isAssignable method");
         if (type2 instanceof BaseLambdaExpression.LambdaInferredType)
            return true;
         ITypeDeclaration decl2 = (ITypeDeclaration) type2;
         return decl1.isAssignableFrom(decl2, assignmentSemantics);
      }
      else if (type1 == null)
         return false;
      else
         throw new UnsupportedOperationException();
   }
public static boolean isAssignableFrom ( Object type1 , Object type2 , boolean assignmentSemantics , ITypeParamContext ctx , boolean allowUnbound , LayeredSystem sys ) { if ( type1 == type2 ) return true ; if ( type2 == NullLiteral . NULL_TYPE ) { if ( ModelUtil . isPrimitive ( type1 ) ) return false ; return true ; } if ( type1 instanceof TypeParameter ) { return ( ( TypeParameter ) type1 ) . isAssignableFrom ( wrapPrimitiveType ( type2 ) , ctx , allowUnbound ) ; } if ( type2 instanceof TypeParameter ) { if ( allowUnbound ) { return true ; } return ( ( TypeParameter ) type2 ) . isAssignableTo ( type1 , ctx , true /* allowUnbound */ ) ; } while ( type1 instanceof TypeVariable ) { type1 = ( ( TypeVariable ) type1 ) . getBounds ( ) [ 0 ] ; } if ( type2 instanceof TypeVariable ) { do { type2 = ( ( TypeVariable ) type2 ) . getBounds ( ) [ 0 ] ; } while ( type2 instanceof TypeVariable ) ; if ( allowUnbound ) { if ( ! ModelUtil . isAssignableFrom ( type2 , type1 ) ) return false ; return true ; } } boolean type1Num = isANumber ( type1 ) ; boolean type2Num = isANumber ( type2 ) ; if ( type1Num && type2Num ) return numberTypesAssignableFrom ( type1 , type2 , assignmentSemantics ) ; if ( isBoolean ( type1 ) && isBoolean ( type2 ) ) return true ; boolean type1Char = isCharacter ( type1 ) ; boolean type2Char = isCharacter ( type2 ) ; if ( type1Char && type2Char ) return true ; if ( assignmentSemantics ) { if ( ( type1Char && type2Num ) || ( type2Char && type1Num ) ) return true ; } else { if ( isAnInteger ( type1 ) && type2Char ) return true ; } while ( type1 instanceof ParameterizedType ) type1 = ( ( ParameterizedType ) type1 ) . getRawType ( ) ; while ( type2 instanceof ParameterizedType ) type2 = ( ( ParameterizedType ) type2 ) . getRawType ( ) ; if ( type1 instanceof Class ) { if ( type1 == Object . class ) { if ( typeIsVoid ( type2 ) ) return false ; return true ; } if ( type2 instanceof ITypeDeclaration ) { return ( ( ITypeDeclaration ) type2 ) . implementsType ( ( ( Class ) type1 ) . getName ( ) , assignmentSemantics , allowUnbound ) ; } else if ( type2 instanceof Class ) { Class cl1 = ( Class ) type1 ; Class cl2 = ( Class ) type2 ; boolean res = cl1 . isAssignableFrom ( cl2 ) ; ClassLoader cl1Loader = cl1 . getClassLoader ( ) ; ClassLoader cl2Loader = cl2 . getClassLoader ( ) ; if ( ! res && cl1Loader != cl2Loader ) { boolean deactivatedLoader = false ; LayeredSystem sys1 = null , sys2 = null ; if ( cl1Loader instanceof TrackingClassLoader ) { TrackingClassLoader tcl1 = ( ( TrackingClassLoader ) cl1Loader ) ; deactivatedLoader = tcl1 . deactivated ; sys1 = tcl1 . getSystem ( ) ; } if ( cl2Loader instanceof TrackingClassLoader ) { TrackingClassLoader tcl2 = ( ( TrackingClassLoader ) cl2Loader ) ; deactivatedLoader |= tcl2 . deactivated ; sys2 = tcl2 . getSystem ( ) ; } if ( deactivatedLoader || sys1 != sys2 ) { if ( sys != null ) { Object ncl1 , ncl2 ; ncl1 = ModelUtil . refreshBoundClass ( sys , cl1 ) ; ncl2 = ModelUtil . refreshBoundClass ( sys , cl2 ) ; if ( ncl1 != cl1 || ncl2 != cl2 ) return ModelUtil . isAssignableFrom ( ncl1 , ncl2 , assignmentSemantics , ctx , allowUnbound , sys ) ; } if ( ModelUtil . isAssignableByName ( cl1 , cl2 ) ) { return true ; } } } if ( ! res && cl2 . isPrimitive ( ) ) { Class clWrapper = sc . type . Type . get ( cl2 ) . getObjectClass ( ) ; res = isAssignableFrom ( cl1 , clWrapper ) ; } return res ; } else if ( type2 == null ) return false ; else if ( type2 instanceof BaseLambdaExpression . LambdaInferredType ) return true ; else throw new UnsupportedOperationException ( ) ; } else if ( type1 instanceof ITypeDeclaration ) { ITypeDeclaration decl1 = ( ITypeDeclaration ) type1 ; if ( type2 instanceof Class ) { return decl1 . isAssignableFromClass ( ( Class ) type2 ) ; } if ( ! ( type2 instanceof ITypeDeclaration ) ) System . out . println ( "*** Error - invalid type to isAssignable method" ) ; if ( type2 instanceof BaseLambdaExpression . LambdaInferredType ) return true ; ITypeDeclaration decl2 = ( ITypeDeclaration ) type2 ; return decl1 . isAssignableFrom ( decl2 , assignmentSemantics ) ; } else if ( type1 == null ) return false ; else throw new UnsupportedOperationException ( ) ; }
Note: the LayeredSystem is an optional parameter here for an edge case that allows us to detect mismatching Classes after we've reset the class loader and reload them rather than compare by name.
Note : the LayeredSystem is an optional parameter here for an edge case that allows us to detect mismatching Classes after we ' ve reset the class loader and reload them rather than compare by name .
// There java.lang.Void.class will match a type parameter //if (typeIsVoid(type2)) //   return false; // Force primitive types to be their wrapper type so we find matches for Comparable and int // TODO: enforce the extends type in the TypeParameter // If we have a type parameter that's not bound and are just matching for an incompatibility, only // reject the match if the bounds for the type is incompatible // Note: switching the order here to "lhs" = "rhs" // Characters can be assigned to ints and vice versa during assignments only // Method parameters - an integer can be assigned with a character argument // Accepts double and other types assuming the unboxing rules in Java // In this case, we need to invert the direction of the test.  Let's see if our TypeDeclaration // implements a type with the same name. // We only need this during the refreshBoundType after resetClassLoader.  Because we refresh references in any order // we might temporarily get incompatible class loaders during the refreshBoundTypes operation which prevent us from resolving types properly. // It seems like a better fix would be to just fix the order so we resolve things before we reference them? // It's possible we have the same class but different class loaders, either because one class loader was deactivated or we are dealing with two different layered systems - i.e. // finding an assignment across runtimes like java and js.  If so we need to convert the classes into the same class loader before doing the isAssignableFrom test. // Java will do a conversion from int to Integer so you can for example cast an int to Comparable and it will work.