diff --git a/src/main/java/com/laytonsmith/core/compiler/analysis/StaticAnalysis.java b/src/main/java/com/laytonsmith/core/compiler/analysis/StaticAnalysis.java index 79b9951dc..8bbd74617 100644 --- a/src/main/java/com/laytonsmith/core/compiler/analysis/StaticAnalysis.java +++ b/src/main/java/com/laytonsmith/core/compiler/analysis/StaticAnalysis.java @@ -7,9 +7,7 @@ import com.laytonsmith.core.constructs.CFunction; import com.laytonsmith.core.constructs.CKeyword; import com.laytonsmith.core.constructs.CLabel; -import com.laytonsmith.core.constructs.CNull; import com.laytonsmith.core.constructs.CString; -import com.laytonsmith.core.constructs.CVoid; import com.laytonsmith.core.constructs.IVariable; import com.laytonsmith.core.constructs.InstanceofUtil; import com.laytonsmith.core.constructs.Target; @@ -430,18 +428,8 @@ public CClassType typecheck(ParseTree ast, Environment env, Set exceptions) { - // Handle types that cause exceptions in the InstanceofUtil isInstanceof check. - if(type.equals(expected) || type == CClassType.AUTO || type == CNull.TYPE) { - return; - } - if(type == CVoid.TYPE || expected == CVoid.TYPE || expected == CNull.TYPE) { - exceptions.add(new ConfigCompileException("Expected type " + expected.getSimpleName() - + ", but received type " + type.getSimpleName() + " instead.", t)); - return; - } - - // Handle 'normal' types. - if(!InstanceofUtil.isInstanceof(type, expected, env)) { + // Generate an exception if the given type is not instanceof the expected type. + if(!InstanceofUtil.isInstanceof(type, expected, null, env)) { exceptions.add(new ConfigCompileException("Expected type " + expected.getSimpleName() + ", but received type " + type.getSimpleName() + " instead.", t)); } @@ -461,9 +449,7 @@ public static void requireAnyType(CClassType type, CClassType[] expected, // Return if the type is instanceof any expected type. for(CClassType exp : expected) { - if(type.equals(exp) || type == CClassType.AUTO || type == CNull.TYPE - || (type != CVoid.TYPE && exp != CVoid.TYPE && exp != CNull.TYPE) - || InstanceofUtil.isInstanceof(type, exp, env)) { + if(InstanceofUtil.isInstanceof(type, exp, null, env)) { return; } } diff --git a/src/main/java/com/laytonsmith/core/constructs/InstanceofUtil.java b/src/main/java/com/laytonsmith/core/constructs/InstanceofUtil.java index 1778c287c..0af0bcc20 100644 --- a/src/main/java/com/laytonsmith/core/constructs/InstanceofUtil.java +++ b/src/main/java/com/laytonsmith/core/constructs/InstanceofUtil.java @@ -3,7 +3,6 @@ import com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery; import com.laytonsmith.annotations.typeof; import com.laytonsmith.core.FullyQualifiedClassName; -import com.laytonsmith.core.Static; import com.laytonsmith.core.constructs.generics.LeftHandGenericUse; import com.laytonsmith.core.environments.Environment; import com.laytonsmith.core.natives.interfaces.Mixed; @@ -150,20 +149,41 @@ public static boolean isInstanceof(Mixed value, CClassType instanceofThis, LeftH /** * Returns whether or not a given MethodScript type is an instance of the specified MethodScript type. - * - * @param type The type to check for - * @param instanceofThis The CClassType to check. This may not be null. - * @param generics The LHS generics definition\ + * The following rules apply in the given order: + * + * @param type - The type to check for. + * Java {@code null} can be used to indicate no type (e.g. from control flow breaking statements). + * @param instanceofThis - The {@link CClassType} to check against. + * Java {@code null} can be used to indicate that anything is allowed to match this + * (i.e. making this method return {@code true}). + * @param instanceofThisGenerics * @param env - * @return + * @return {@code true} if type is instance of instanceofThis. */ - public static boolean isInstanceof(CClassType type, CClassType instanceofThis, LeftHandGenericUse generics, Environment env) { - Static.AssertNonNull(instanceofThis, "instanceofThis may not be null"); - instanceofThis = CClassType.getNakedClassType(instanceofThis.getFQCN()); - // Return true for AUTO, as everything can be used as AUTO. - if(instanceofThis == CClassType.AUTO) { + public static boolean isInstanceof( + CClassType type, CClassType instanceofThis, LeftHandGenericUse instanceofThisGenerics, Environment env) { + instanceofThis = (instanceofThis != null ? CClassType.getNakedClassType(instanceofThis.getFQCN()) : null); + + // Handle special cases. + if(instanceofThis == null || (instanceofThis.equals(type) && (instanceofThis.getGenericDeclaration() == null + || type.getGenericParameters().isInstanceof(instanceofThisGenerics))) || CClassType.AUTO.equals(type) + || CNull.TYPE.equals(type) || CClassType.AUTO.equals(instanceofThis)) { return true; } + if(type == null || CVoid.TYPE.equals(type) + || CVoid.TYPE.equals(instanceofThis) || CNull.TYPE.equals(instanceofThis)) { + return false; + } // Get cached result or compute and cache result. Set castableClasses = ISINSTANCEOF_CACHE.get(type); @@ -173,15 +193,8 @@ public static boolean isInstanceof(CClassType type, CClassType instanceofThis, L } // Return the result. - if(!castableClasses.contains(instanceofThis)) { - return false; - } - - if(instanceofThis.getGenericDeclaration() != null ) { - return type.getGenericParameters().isInstanceof(generics, env); - } else { - return true; - } + return castableClasses.contains(instanceofThis) && (instanceofThis.getGenericDeclaration() == null + || type.getGenericParameters().isInstanceof(instanceofThisGenerics)); } private static FullyQualifiedClassName typeof(Class c) {