From e3079ac667dbf255ab355019c47b13fef4f30a83 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 3 Sep 2013 19:54:27 +0400 Subject: [PATCH] Erased casts supported --- .../jet/lang/types/CastDiagnosticsUtil.java | 88 ++++++++++- .../jetbrains/jet/lang/types/TypeUtils.java | 13 +- .../BasicExpressionTypingVisitor.java | 147 +----------------- .../PatternMatchingTypingVisitor.java | 2 +- .../diagnostics/tests/cast/DowncastMap.kt | 10 ++ .../diagnostics/tests/cast/IsArray.kt | 1 + ...ivedWithOneSubstitutedAndOneSameGeneric.kt | 5 + .../IsErasedAllowForExactSupertypeCheck.kt | 5 + ...AllowForOverridenVarianceWithProjection.kt | 8 + ...AllowForSupertypeCheckWithContrvariance.kt | 8 + ...sedAllowForSupertypeCheckWithCovariance.kt | 8 + ...IsErasedAllowForTypeWithIrrelevantMixin.kt | 9 ++ ...llowForTypeWithTwoSameTypeSubstitutions.kt | 6 + ...sErasedAllowForTypeWithoutTypeArguments.kt | 5 + .../IsErasedDisallowForOverridenVariance.kt | 8 + .../IsErasedDisallowForTypeWithConstraints.kt | 6 + ...ubtypeMappedToTwoParamsWithFirstInvalid.kt | 8 + ...btypeMappedToTwoParamsWithSecondInvalid.kt | 8 + .../tests/cast/IsErasedNonGeneric.kt | 3 + .../tests/cast/IsErasedNullableTasT.kt | 1 + .../diagnostics/tests/cast/IsErasedTasT.kt | 1 + .../tests/cast/IsErasedToErrorType.kt | 1 + .../tests/cast/IsRecursionSustainable.kt | 6 + .../tests/generics/RawTypeInIsExpression.kt | 2 +- .../tests/generics/RawTypeInIsPattern.kt | 2 +- .../checkers/JetDiagnosticsTestGenerated.java | 95 +++++++++++ 26 files changed, 298 insertions(+), 158 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/cast/DowncastMap.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsArray.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedAllowForExactSupertypeCheck.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedAllowForOverridenVarianceWithProjection.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedAllowForSupertypeCheckWithContrvariance.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedAllowForSupertypeCheckWithCovariance.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithIrrelevantMixin.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithTwoSameTypeSubstitutions.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithoutTypeArguments.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedDisallowForOverridenVariance.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedDisallowForTypeWithConstraints.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedDissallowForSubtypeMappedToTwoParamsWithFirstInvalid.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedDissallowForSubtypeMappedToTwoParamsWithSecondInvalid.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedNonGeneric.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedNullableTasT.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedTasT.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedToErrorType.kt create mode 100644 compiler/testData/diagnostics/tests/cast/IsRecursionSustainable.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/CastDiagnosticsUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/CastDiagnosticsUtil.java index bb3b0ae2376..b7869524c77 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/CastDiagnosticsUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/CastDiagnosticsUtil.java @@ -1,6 +1,8 @@ package org.jetbrains.jet.lang.types; +import com.google.common.base.Predicate; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.PlatformToKotlinClassMap; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; @@ -8,10 +10,12 @@ import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; +import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; public class CastDiagnosticsUtil { @@ -44,11 +48,8 @@ public class CastDiagnosticsUtil { List aTypes = mapToPlatformIndependentTypes(a, platformToKotlinClassMap); List bTypes = mapToPlatformIndependentTypes(b, platformToKotlinClassMap); - for (int i = 0; i < aTypes.size(); i++) { - JetType aType = aTypes.get(i); - for (int j = 0; j < bTypes.size(); j++) { - JetType bType = bTypes.get(j); - + for (JetType aType : aTypes) { + for (JetType bType : bTypes) { if (JetTypeChecker.INSTANCE.isSubtypeOf(aType, bType)) return true; if (JetTypeChecker.INSTANCE.isSubtypeOf(bType, aType)) return true; } @@ -91,5 +92,82 @@ public class CastDiagnosticsUtil { return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.TRAIT; } + /** + * Check if cast from supertype to subtype is erased. + * It is an error in "is" statement and warning in "as". + */ + public static boolean isCastErased(@NotNull JetType supertype, @NotNull JetType subtype, @NotNull JetTypeChecker typeChecker) { + // cast between T and T? is always OK + if (supertype.isNullable() || subtype.isNullable()) { + return isCastErased(TypeUtils.makeNotNullable(supertype), TypeUtils.makeNotNullable(subtype), typeChecker); + } + + // if it is a upcast, it's never erased + if (typeChecker.isSubtypeOf(supertype, subtype)) return false; + + // downcasting to a type parameter is always erased + if (isTypeParameter(subtype)) return true; + + // Check that we are actually casting to a generic type + // NOTE: this does not account for 'as Array>' + if (allParametersReified(subtype)) return false; + + // Assume we are casting an expression of type Collection to List + // First, let's make List, where T is a type variable + JetType subtypeWithVariables = TypeUtils.makeUnsubstitutedType( + subtype.getConstructor(), + ErrorUtils.createErrorScope("Scope for intermediate type. This type shouldn't be used outside isCastErased()", true)); + + // Now, let's find a supertype of List that is a Collection of something, + // in this case it will be Collection + JetType supertypeWithVariables = TypeCheckingProcedure.findCorrespondingSupertype(subtypeWithVariables, supertype); + if (supertypeWithVariables == null) return true; + + // Now, let's try to unify Collection and Collection + // solution is a map from T to Foo + final List variables = subtypeWithVariables.getConstructor().getParameters(); + TypeUnifier.UnificationResult solution = TypeUnifier.unify( + new TypeProjection(supertype), new TypeProjection(supertypeWithVariables), + new Predicate() { + @Override + public boolean apply(TypeConstructor typeConstructor) { + ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor(); + return descriptor instanceof TypeParameterDescriptor && variables.contains(descriptor); + } + }); + + // If some of the parameters are not determined by unification, it means that these parameters are lost, + // let's put stars instead, so that we can only cast to something like List<*>, e.g. (a: Any) as List<*> + Map substitution = Maps.newHashMap(solution.getSubstitution()); + for (TypeParameterDescriptor variable : variables) { + TypeProjection value = substitution.get(variable.getTypeConstructor()); + if (value == null) { + substitution.put( + variable.getTypeConstructor(), + SubstitutionUtils.makeStarProjection(variable) + ); + } + } + + // At this point we have values for all type parameters of List + // Let's make a type by substituting them: List -> List + JetType staticallyKnownSubtype = TypeSubstitutor.create(substitution).substitute(subtypeWithVariables, Variance.INVARIANT); + + // If the substitution failed, it means that the result is an impossible type, e.g. something like Out + // In this case, we can't guarantee anything, so the cast is considered to be erased + if (staticallyKnownSubtype == null) return true; + + // If the type we calculated is a subtype of the cast target, it's OK to use the cast target instead. + // If not, it's wrong to use it + return !typeChecker.isSubtypeOf(staticallyKnownSubtype, subtype); + } + + private static boolean allParametersReified(JetType subtype) { + for (TypeParameterDescriptor parameterDescriptor : subtype.getConstructor().getParameters()) { + if (!parameterDescriptor.isReified()) return false; + } + return true; + } + private CastDiagnosticsUtil() {} } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java index f2a4057d31a..30859c6bb8d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -353,13 +353,18 @@ public class TypeUtils { @NotNull public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor, JetScope unsubstitutedMemberScope) { - if (ErrorUtils.isError(classDescriptor)) { - return ErrorUtils.createErrorType("Unsubstituted type for " + classDescriptor); + return makeUnsubstitutedType(classDescriptor.getTypeConstructor(), unsubstitutedMemberScope); + } + + @NotNull + public static JetType makeUnsubstitutedType(TypeConstructor typeConstructor, JetScope unsubstitutedMemberScope) { + if (ErrorUtils.isError(typeConstructor)) { + return ErrorUtils.createErrorType("Unsubstituted type for " + typeConstructor); } - List arguments = getDefaultTypeProjections(classDescriptor.getTypeConstructor().getParameters()); + List arguments = getDefaultTypeProjections(typeConstructor.getParameters()); return new JetTypeImpl( Collections.emptyList(), - classDescriptor.getTypeConstructor(), + typeConstructor, false, arguments, unsubstitutedMemberScope diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 5220e82410c..4f6aca72695 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.lang.types.expressions; import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; @@ -57,7 +56,6 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; -import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.utils.ThrowingList; @@ -235,156 +233,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { context.trace.report(USELESS_CAST.on(expression.getOperationReference())); } else { - if (isCastErased(actualType, targetType, typeChecker)) { + if (CastDiagnosticsUtil.isCastErased(actualType, targetType, typeChecker)) { context.trace.report(Errors.UNCHECKED_CAST.on(expression, actualType, targetType)); } } } } - /** - * Check if assignment from supertype to subtype is erased. - * It is an error in "is" statement and warning in "as". - */ - public static boolean isCastErased(@NotNull JetType supertype, @NotNull JetType subtype, @NotNull JetTypeChecker typeChecker) { - if (!(subtype.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor)) { - // TODO: what if it is TypeParameterDescriptor? - return false; - } - - // do not crash on error types - if (ErrorUtils.isErrorType(supertype) || ErrorUtils.isErrorType(subtype)) { - return false; - } - - return hasDowncastsInTypeArguments(supertype, subtype, typeChecker) || hasErasedTypeArguments(supertype, subtype); - } - - /* - Check if type arguments are downcasted, which cannot be checked at run-time. - - Examples: - 1. a: MutableList is MutableList - true, because 'String' is more specific - 2. a: Collection is List - false, because 'Any' is less specific, and it is guaranteed by static checker - 3. a: MutableCollection is MutableList - false, because these types have empty intersection (type parameter is invariant) - */ - private static boolean hasDowncastsInTypeArguments( - @NotNull JetType supertype, - @NotNull JetType subtype, - @NotNull JetTypeChecker typeChecker - ) { - List superParameters = supertype.getConstructor().getParameters(); - - // This map holds arguments for type parameters of all superclasses of a type (see method comment for sample) - Multimap subtypeSubstitutionMap = SubstitutionUtils.buildDeepSubstitutionMultimap(subtype); - - for (int i = 0; i < superParameters.size(); i++) { - TypeProjection superArgument = supertype.getArguments().get(i); - TypeParameterDescriptor parameter = superParameters.get(i); - - if (parameter.isReified()) { - continue; - } - - Collection substituted = subtypeSubstitutionMap.get(parameter.getTypeConstructor()); - for (TypeProjection substitutedArgument : substituted) { - // For sample #2 (a: Collection is List): - // parameter = E declared in Collection - // superArgument = String - // substitutedArgument = Any, because Collection is the supertype of List - - // 1. Any..Nothing - // 2. String..Nothing - // 3. String..String - JetType superOut = TypeCheckingProcedure.getOutType(parameter, superArgument); - JetType superIn = TypeCheckingProcedure.getInType(parameter, superArgument); - - // 1. String..String - // 2. Any..Nothing - // 3. Any..Any - JetType subOut = TypeCheckingProcedure.getOutType(parameter, substitutedArgument); - JetType subIn = TypeCheckingProcedure.getInType(parameter, substitutedArgument); - - // super type range must be a subset of sub type range - if (typeChecker.isSubtypeOf(superOut, subOut) && typeChecker.isSubtypeOf(subIn, superIn)) { - // continue - } - else { - return true; - } - } - } - - return false; - } - - /* - Check if type arguments are erased, that is they are not mapped to type parameters of supertype's class - - Examples (MyMap is defined like this: trait MyMap: Map): - 1. a: Any is List - true - 2. a: Collection is List - false - 3. a: Map is MyMap - false - */ - private static boolean hasErasedTypeArguments( - @NotNull JetType supertype, - @NotNull JetType subtype - ) { - // Erase all type arguments, replacing them with unsubstituted versions: - // 1. List - // 2. List - // 3. MyMap - JetType subtypeCleared = TypeUtils.makeUnsubstitutedType( - (ClassDescriptor) subtype.getConstructor().getDeclarationDescriptor(), null); - - // This map holds arguments for type parameters of all superclasses of a type (see method comment for sample) - // For all "E" declared in Collection, Iterable, etc., value will be type "E", where the latter E is declared in List - Multimap clearTypeSubstitutionMap = - SubstitutionUtils.buildDeepSubstitutionMultimap(subtypeCleared); - - - // This set will contain all arguments for type parameters of superclass which are mapped from type parameters of subtype's class - // 1. empty - // 2. [E declared in List] - // 3. [T declared in MyMap] - Set clearSubstituted = new HashSet(); - - List superParameters = supertype.getConstructor().getParameters(); - for (TypeParameterDescriptor superParameter : superParameters) { - Collection substituted = clearTypeSubstitutionMap.get(superParameter.getTypeConstructor()); - for (TypeProjection substitutedProjection : substituted) { - clearSubstituted.add(substitutedProjection.getType()); - } - } - - // For each type parameter of subtype's class, we check that it is mapped to type parameters of supertype, - // that is its type is present in clearSubstituted set - List subParameters = subtype.getConstructor().getParameters(); - for (int i = 0; i < subParameters.size(); i++) { - TypeParameterDescriptor parameter = subParameters.get(i); - TypeProjection argument = subtype.getArguments().get(i); - - if (parameter.isReified()) { - continue; - } - - // "is List<*>", no check for type argument, actually - if (argument.equals(SubstitutionUtils.makeStarProjection(parameter))) { - continue; - } - - // if parameter is mapped to nothing then it is erased - // 1. return from here - // 2. contains = true, don't return - // 3. contains = true, don't return - if (!clearSubstituted.contains(parameter.getDefaultType())) { - return true; - } - } - - return false; - } - @Override public JetTypeInfo visitThisExpression(JetThisExpression expression, ExpressionTypingContext context) { JetType result = null; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java index 1d37e1a616e..4db11b2cda7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java @@ -285,7 +285,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { context.trace.report(Errors.USELESS_NULLABLE_CHECK.on(nullableType)); } checkTypeCompatibility(context, type, subjectType, typeReferenceAfterIs); - if (BasicExpressionTypingVisitor.isCastErased(subjectType, type, JetTypeChecker.INSTANCE)) { + if (CastDiagnosticsUtil.isCastErased(subjectType, type, JetTypeChecker.INSTANCE)) { context.trace.report(Errors.CANNOT_CHECK_FOR_ERASED.on(typeReferenceAfterIs, type)); } return new DataFlowInfos(context.dataFlowInfo.establishSubtyping(subjectDataFlowValue, type), context.dataFlowInfo); diff --git a/compiler/testData/diagnostics/tests/cast/DowncastMap.kt b/compiler/testData/diagnostics/tests/cast/DowncastMap.kt new file mode 100644 index 00000000000..3b2e1bb7fda --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/DowncastMap.kt @@ -0,0 +1,10 @@ +trait Map +trait MutableMap: Map { + fun set(k: K, v: V) +} + +fun p(p: Map) { + if (p is MutableMap) { + p[""] = 1 + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsArray.kt b/compiler/testData/diagnostics/tests/cast/IsArray.kt new file mode 100644 index 00000000000..f5329d82748 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsArray.kt @@ -0,0 +1 @@ +fun f(a: Array) = a is Array diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt new file mode 100644 index 00000000000..5df28bb45fd --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt @@ -0,0 +1,5 @@ +open class BaseTwo +open class DerivedWithOne: BaseTwo() + +// a is BaseTwo => if (a is DerivedWithOne) a is DerivedWithOne +fun testing(a: BaseTwo) = a is DerivedWithOne diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowForExactSupertypeCheck.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForExactSupertypeCheck.kt new file mode 100644 index 00000000000..51c6eab4642 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForExactSupertypeCheck.kt @@ -0,0 +1,5 @@ +open class Base +class Some: Base() + +// a is Some => a is Base +fun f(a: Some) = a is Base \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowForOverridenVarianceWithProjection.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForOverridenVarianceWithProjection.kt new file mode 100644 index 00000000000..09d7b2f6792 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForOverridenVarianceWithProjection.kt @@ -0,0 +1,8 @@ +open class A +open class B: A() + +open class Base +open class SubBase : Base() + +// l is Base<+B> => if (l is SubBase) l is SubBase<+B> => l is SubBase<+A> +fun ff(l: Base) = l is SubBase diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowForSupertypeCheckWithContrvariance.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForSupertypeCheckWithContrvariance.kt new file mode 100644 index 00000000000..db875931272 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForSupertypeCheckWithContrvariance.kt @@ -0,0 +1,8 @@ +open class A +open class B: A() + +open class Base +class SubBase: Base() + +// f is SubBase => f is Base => (Base, B <: A) f is Base +fun test(f: SubBase) = f is Base \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowForSupertypeCheckWithCovariance.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForSupertypeCheckWithCovariance.kt new file mode 100644 index 00000000000..a7ca5876259 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForSupertypeCheckWithCovariance.kt @@ -0,0 +1,8 @@ +open class A +open class B: A() + +open class Base +class SubBase: Base() + +// f is SubBase => (SubBase <: Base) f is Base => (B <: A, Base => SubBase <: Base) f is Base +fun test(f: SubBase) = f is Base \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithIrrelevantMixin.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithIrrelevantMixin.kt new file mode 100644 index 00000000000..15c61f24a53 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithIrrelevantMixin.kt @@ -0,0 +1,9 @@ +trait A +trait B: A +trait D + +trait BaseSuper +trait BaseImpl: BaseSuper +trait DerivedSuper: BaseSuper, BaseImpl + +fun test(t: BaseSuper) = t is DerivedSuper \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithTwoSameTypeSubstitutions.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithTwoSameTypeSubstitutions.kt new file mode 100644 index 00000000000..41baa2a3676 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithTwoSameTypeSubstitutions.kt @@ -0,0 +1,6 @@ +open class BaseMulti +class SomeMultiDerived: BaseMulti() + +// t is BaseMulti<+String, String> => if (t is SomeMultiDerived) => t is SomeMultiDerived<+String> => +// => (String <: Any, SomeMultiDerived) t is SomeMultiDerived<+Any> +fun someDerived(t: BaseMulti) = t is SomeMultiDerived diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithoutTypeArguments.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithoutTypeArguments.kt new file mode 100644 index 00000000000..a481246aaad --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithoutTypeArguments.kt @@ -0,0 +1,5 @@ +open class Base +class Some: Base() + +// No erased types in check +fun f(a: Base) = a is Some diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedDisallowForOverridenVariance.kt b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowForOverridenVariance.kt new file mode 100644 index 00000000000..c7eb75aebb4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowForOverridenVariance.kt @@ -0,0 +1,8 @@ +open class A +open class B: A() + +open class Base +open class SubBase : Base() + + +fun ff(l: Base) = l is SubBase diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedDisallowForTypeWithConstraints.kt b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowForTypeWithConstraints.kt new file mode 100644 index 00000000000..be45dbe7036 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowForTypeWithConstraints.kt @@ -0,0 +1,6 @@ +trait A +trait B: A + +trait Base + +fun test(a: Base) where T: Base = a is T \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedDissallowForSubtypeMappedToTwoParamsWithFirstInvalid.kt b/compiler/testData/diagnostics/tests/cast/IsErasedDissallowForSubtypeMappedToTwoParamsWithFirstInvalid.kt new file mode 100644 index 00000000000..74370d950ae --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedDissallowForSubtypeMappedToTwoParamsWithFirstInvalid.kt @@ -0,0 +1,8 @@ +open class A +open class B: A() +open class D + +open class Base +open class Derived: Base() + +fun test(a: Base) = a is Derived \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedDissallowForSubtypeMappedToTwoParamsWithSecondInvalid.kt b/compiler/testData/diagnostics/tests/cast/IsErasedDissallowForSubtypeMappedToTwoParamsWithSecondInvalid.kt new file mode 100644 index 00000000000..8b0c5de4329 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedDissallowForSubtypeMappedToTwoParamsWithSecondInvalid.kt @@ -0,0 +1,8 @@ +open class A +open class B: A() +open class D + +open class Base +open class Derived: Base() + +fun test(a: Base) = a is Derived \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedNonGeneric.kt b/compiler/testData/diagnostics/tests/cast/IsErasedNonGeneric.kt new file mode 100644 index 00000000000..97387f2bdef --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedNonGeneric.kt @@ -0,0 +1,3 @@ +trait A +trait B +fun testing(a: A) = a as B diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedNullableTasT.kt b/compiler/testData/diagnostics/tests/cast/IsErasedNullableTasT.kt new file mode 100644 index 00000000000..0a32f3a862f --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedNullableTasT.kt @@ -0,0 +1 @@ +fun testing(a: T?) = a is T diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedTasT.kt b/compiler/testData/diagnostics/tests/cast/IsErasedTasT.kt new file mode 100644 index 00000000000..ae1fa33c9f8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedTasT.kt @@ -0,0 +1 @@ +fun testing(a: T) = a is T diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedToErrorType.kt b/compiler/testData/diagnostics/tests/cast/IsErasedToErrorType.kt new file mode 100644 index 00000000000..f88613e0aeb --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedToErrorType.kt @@ -0,0 +1 @@ +fun testing(a: Any) = a is UnresolvedType diff --git a/compiler/testData/diagnostics/tests/cast/IsRecursionSustainable.kt b/compiler/testData/diagnostics/tests/cast/IsRecursionSustainable.kt new file mode 100644 index 00000000000..f194a077389 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsRecursionSustainable.kt @@ -0,0 +1,6 @@ +open class RecA: RecB() +open class RecB: RecA() +open class SelfR: SelfR() + +fun test(f: SelfR) = f is RecA +fun test(f: RecB) = f is RecA \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/RawTypeInIsExpression.kt b/compiler/testData/diagnostics/tests/generics/RawTypeInIsExpression.kt index 49e5c7e3d88..a404383ccb2 100644 --- a/compiler/testData/diagnostics/tests/generics/RawTypeInIsExpression.kt +++ b/compiler/testData/diagnostics/tests/generics/RawTypeInIsExpression.kt @@ -6,7 +6,7 @@ public fun foo(a: Any) { a is Map a is Map<*, *> a is Map<> - a is List<Map> + a is List<Map> a is List a is Int diff --git a/compiler/testData/diagnostics/tests/generics/RawTypeInIsPattern.kt b/compiler/testData/diagnostics/tests/generics/RawTypeInIsPattern.kt index bd67f5d6967..b1f7a4564c0 100644 --- a/compiler/testData/diagnostics/tests/generics/RawTypeInIsPattern.kt +++ b/compiler/testData/diagnostics/tests/generics/RawTypeInIsPattern.kt @@ -5,7 +5,7 @@ public fun foo(a: Any, b: -> {} is Map<*, *> -> {} is Map<> -> {} - is List<Map> -> {} + is List<Map> -> {} is List -> {} is Int -> {} else -> {} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 634079ffe53..ede5e61efcc 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -980,6 +980,56 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/cast/AsErasedWarning.kt"); } + @TestMetadata("DowncastMap.kt") + public void testDowncastMap() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/DowncastMap.kt"); + } + + @TestMetadata("IsArray.kt") + public void testIsArray() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsArray.kt"); + } + + @TestMetadata("IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt") + public void testIsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt"); + } + + @TestMetadata("IsErasedAllowForExactSupertypeCheck.kt") + public void testIsErasedAllowForExactSupertypeCheck() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowForExactSupertypeCheck.kt"); + } + + @TestMetadata("IsErasedAllowForOverridenVarianceWithProjection.kt") + public void testIsErasedAllowForOverridenVarianceWithProjection() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowForOverridenVarianceWithProjection.kt"); + } + + @TestMetadata("IsErasedAllowForSupertypeCheckWithContrvariance.kt") + public void testIsErasedAllowForSupertypeCheckWithContrvariance() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowForSupertypeCheckWithContrvariance.kt"); + } + + @TestMetadata("IsErasedAllowForSupertypeCheckWithCovariance.kt") + public void testIsErasedAllowForSupertypeCheckWithCovariance() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowForSupertypeCheckWithCovariance.kt"); + } + + @TestMetadata("IsErasedAllowForTypeWithIrrelevantMixin.kt") + public void testIsErasedAllowForTypeWithIrrelevantMixin() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithIrrelevantMixin.kt"); + } + + @TestMetadata("IsErasedAllowForTypeWithTwoSameTypeSubstitutions.kt") + public void testIsErasedAllowForTypeWithTwoSameTypeSubstitutions() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithTwoSameTypeSubstitutions.kt"); + } + + @TestMetadata("IsErasedAllowForTypeWithoutTypeArguments.kt") + public void testIsErasedAllowForTypeWithoutTypeArguments() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowForTypeWithoutTypeArguments.kt"); + } + @TestMetadata("IsErasedAllowFromOut.kt") public void testIsErasedAllowFromOut() throws Exception { doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOut.kt"); @@ -1015,6 +1065,16 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowDifferentArgInvariantPosition.kt"); } + @TestMetadata("IsErasedDisallowForOverridenVariance.kt") + public void testIsErasedDisallowForOverridenVariance() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowForOverridenVariance.kt"); + } + + @TestMetadata("IsErasedDisallowForTypeWithConstraints.kt") + public void testIsErasedDisallowForTypeWithConstraints() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowForTypeWithConstraints.kt"); + } + @TestMetadata("IsErasedDisallowFromAny.kt") public void testIsErasedDisallowFromAny() throws Exception { doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromAny.kt"); @@ -1035,11 +1095,46 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOutAtClass.kt"); } + @TestMetadata("IsErasedDissallowForSubtypeMappedToTwoParamsWithFirstInvalid.kt") + public void testIsErasedDissallowForSubtypeMappedToTwoParamsWithFirstInvalid() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedDissallowForSubtypeMappedToTwoParamsWithFirstInvalid.kt"); + } + + @TestMetadata("IsErasedDissallowForSubtypeMappedToTwoParamsWithSecondInvalid.kt") + public void testIsErasedDissallowForSubtypeMappedToTwoParamsWithSecondInvalid() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedDissallowForSubtypeMappedToTwoParamsWithSecondInvalid.kt"); + } + + @TestMetadata("IsErasedNonGeneric.kt") + public void testIsErasedNonGeneric() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedNonGeneric.kt"); + } + + @TestMetadata("IsErasedNullableTasT.kt") + public void testIsErasedNullableTasT() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedNullableTasT.kt"); + } + @TestMetadata("IsErasedStar.kt") public void testIsErasedStar() throws Exception { doTest("compiler/testData/diagnostics/tests/cast/IsErasedStar.kt"); } + @TestMetadata("IsErasedTasT.kt") + public void testIsErasedTasT() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedTasT.kt"); + } + + @TestMetadata("IsErasedToErrorType.kt") + public void testIsErasedToErrorType() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedToErrorType.kt"); + } + + @TestMetadata("IsRecursionSustainable.kt") + public void testIsRecursionSustainable() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsRecursionSustainable.kt"); + } + @TestMetadata("IsReified.kt") public void testIsReified() throws Exception { doTest("compiler/testData/diagnostics/tests/cast/IsReified.kt");