diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/PossiblyBareType.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/PossiblyBareType.java new file mode 100644 index 00000000000..2b6d7b9bea1 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/PossiblyBareType.java @@ -0,0 +1,99 @@ +package org.jetbrains.jet.lang.resolve; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.types.*; + +/** + * Bare types are somewhat like raw types, but in Kotlin they are only allowed on the right-hand side of is/as. + * For example: + * + * fun foo(a: Any) { + * if (a is List) { + * // a is known to be List<*> here + * } + * } + * + * Another example: + * + * fun foo(a: Collection) { + * if (a is List) { + * // a is known to be List here + * } + * } + * + * One can call reconstruct(supertype) to get an actual type from a bare type + */ +public class PossiblyBareType { + + @NotNull + public static PossiblyBareType bare(@NotNull TypeConstructor bareTypeConstructor, boolean nullable) { + return new PossiblyBareType(null, bareTypeConstructor, nullable); + } + + @NotNull + public static PossiblyBareType type(@NotNull JetType actualType) { + return new PossiblyBareType(actualType, null, false); + } + + private final JetType actualType; + private final TypeConstructor bareTypeConstructor; + private final boolean nullable; + + private PossiblyBareType(@Nullable JetType actualType, @Nullable TypeConstructor bareTypeConstructor, boolean nullable) { + this.actualType = actualType; + this.bareTypeConstructor = bareTypeConstructor; + this.nullable = nullable; + } + + public boolean isBare() { + return actualType == null; + } + + @NotNull + public JetType getActualType() { + //noinspection ConstantConditions + return actualType; + } + + @NotNull + public TypeConstructor getBareTypeConstructor() { + //noinspection ConstantConditions + return bareTypeConstructor; + } + + private boolean isBareTypeNullable() { + return nullable; + } + + public boolean isNullable() { + if (isBare()) return isBareTypeNullable(); + return getActualType().isNullable(); + } + + public PossiblyBareType makeNullable() { + if (isBare()) { + return isBareTypeNullable() ? this : bare(getBareTypeConstructor(), true); + } + return type(TypeUtils.makeNullable(getActualType())); + } + + @NotNull + public JetType reconstruct(@NotNull JetType subjectType) { + if (!isBare()) return getActualType(); + + JetType type = CastDiagnosticsUtil.findStaticallyKnownSubtype( + TypeUtils.makeNotNullable(subjectType), + getBareTypeConstructor() + ); + // No need to make an absent type nullable + if (type == null) return type; + + return TypeUtils.makeNullableAsSpecified(type, isBareTypeNullable()); + } + + @Override + public String toString() { + return isBare() ? "bare " + bareTypeConstructor + (isBareTypeNullable() ? "?" : "") : getActualType().toString(); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolutionContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolutionContext.java index 49e6b76c0bf..caec48bd8ed 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolutionContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolutionContext.java @@ -7,10 +7,16 @@ public class TypeResolutionContext { public final JetScope scope; public final BindingTrace trace; public final boolean checkBounds; + public final boolean allowBareTypes; - public TypeResolutionContext(@NotNull JetScope scope, @NotNull BindingTrace trace, boolean checkBounds) { + public TypeResolutionContext(@NotNull JetScope scope, @NotNull BindingTrace trace, boolean checkBounds, boolean allowBareTypes) { this.scope = scope; this.trace = trace; this.checkBounds = checkBounds; + this.allowBareTypes = allowBareTypes; + } + + public TypeResolutionContext noBareTypes() { + return new TypeResolutionContext(scope, trace, checkBounds, false); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 47f81f3f6c6..70733620826 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -16,7 +16,6 @@ package org.jetbrains.jet.lang.resolve; -import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -35,6 +34,7 @@ import java.util.Collections; import java.util.List; import static org.jetbrains.jet.lang.diagnostics.Errors.*; +import static org.jetbrains.jet.lang.resolve.PossiblyBareType.type; import static org.jetbrains.jet.lang.types.Variance.*; public class TypeResolver { @@ -60,32 +60,41 @@ public class TypeResolver { @NotNull public JetType resolveType(@NotNull JetScope scope, @NotNull JetTypeReference typeReference, BindingTrace trace, boolean checkBounds) { - return resolveType(new TypeResolutionContext(scope, trace, checkBounds), typeReference); + // bare types are not allowed + return resolveType(new TypeResolutionContext(scope, trace, checkBounds, false), typeReference); } @NotNull public JetType resolveType(@NotNull TypeResolutionContext c, @NotNull JetTypeReference typeReference) { + assert !c.allowBareTypes : "Use resolvePossiblyBareType() when bare types are allowed"; + return resolvePossiblyBareType(c, typeReference).getActualType(); + } + + @NotNull + public PossiblyBareType resolvePossiblyBareType(@NotNull TypeResolutionContext c, @NotNull JetTypeReference typeReference) { JetType cachedType = c.trace.getBindingContext().get(BindingContext.TYPE, typeReference); - if (cachedType != null) return cachedType; + if (cachedType != null) return type(cachedType); List annotations = annotationResolver.getResolvedAnnotations(typeReference.getAnnotations(), c.trace); JetTypeElement typeElement = typeReference.getTypeElement(); - JetType type = resolveTypeElement(c, annotations, typeElement); - c.trace.record(BindingContext.TYPE, typeReference, type); + PossiblyBareType type = resolveTypeElement(c, annotations, typeElement); + if (!type.isBare()) { + c.trace.record(BindingContext.TYPE, typeReference, type.getActualType()); + } c.trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference, c.scope); return type; } @NotNull - private JetType resolveTypeElement( + private PossiblyBareType resolveTypeElement( final TypeResolutionContext c, final List annotations, JetTypeElement typeElement ) { - final JetType[] result = new JetType[1]; + final PossiblyBareType[] result = new PossiblyBareType[1]; if (typeElement != null) { typeElement.accept(new JetVisitorVoid() { @Override @@ -109,16 +118,16 @@ public class TypeResolver { JetScope scopeForTypeParameter = getScopeForTypeParameter(c, typeParameterDescriptor); if (scopeForTypeParameter instanceof ErrorUtils.ErrorScope) { - result[0] = ErrorUtils.createErrorType("?"); + result[0] = type(ErrorUtils.createErrorType("?")); } else { - result[0] = new JetTypeImpl( + result[0] = type(new JetTypeImpl( annotations, typeParameterDescriptor.getTypeConstructor(), TypeUtils.hasNullableLowerBound(typeParameterDescriptor), Collections.emptyList(), scopeForTypeParameter - ); + )); } resolveTypeProjections(c, ErrorUtils.createErrorType("No type").getConstructor(), type.getTypeArguments()); @@ -138,32 +147,33 @@ public class TypeResolver { int expectedArgumentCount = parameters.size(); int actualArgumentCount = arguments.size(); if (ErrorUtils.isError(typeConstructor)) { - result[0] = ErrorUtils.createErrorType("[Error type: " + typeConstructor + "]"); + result[0] = type(ErrorUtils.createErrorType("[Error type: " + typeConstructor + "]")); } else { if (actualArgumentCount != expectedArgumentCount) { if (actualArgumentCount == 0) { - if (rhsOfIsExpression(type) || rhsOfIsPattern(type)) { - c.trace.report(NO_TYPE_ARGUMENTS_ON_RHS_OF_IS_EXPRESSION.on(type, expectedArgumentCount, allStarProjectionsString(typeConstructor))); - } - else { - c.trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type, expectedArgumentCount)); + // See docs for PossiblyBareType + if (c.allowBareTypes) { + result[0] = PossiblyBareType.bare(typeConstructor, false); + return; } + c.trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type, expectedArgumentCount)); } else { c.trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type.getTypeArgumentList(), expectedArgumentCount)); } } else { - result[0] = new JetTypeImpl( + JetTypeImpl resultingType = new JetTypeImpl( annotations, typeConstructor, false, arguments, classDescriptor.getMemberScope(arguments) ); + result[0] = type(resultingType); if (c.checkBounds) { - TypeSubstitutor substitutor = TypeSubstitutor.create(result[0]); + TypeSubstitutor substitutor = TypeSubstitutor.create(resultingType); for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { TypeParameterDescriptor parameter = parameters.get(i); JetType argument = arguments.get(i).getType(); @@ -181,35 +191,35 @@ public class TypeResolver { @Override public void visitNullableType(JetNullableType nullableType) { - JetType baseType = resolveTypeElement(c, annotations, nullableType.getInnerType()); + PossiblyBareType baseType = resolveTypeElement(c, annotations, nullableType.getInnerType()); if (baseType.isNullable()) { c.trace.report(REDUNDANT_NULLABLE.on(nullableType)); } - else if (TypeUtils.hasNullableSuperType(baseType)) { - c.trace.report(BASE_WITH_NULLABLE_UPPER_BOUND.on(nullableType, baseType)); + else if (!baseType.isBare() && TypeUtils.hasNullableSuperType(baseType.getActualType())) { + c.trace.report(BASE_WITH_NULLABLE_UPPER_BOUND.on(nullableType, baseType.getActualType())); } - result[0] = TypeUtils.makeNullable(baseType); + result[0] = baseType.makeNullable(); } @Override public void visitFunctionType(JetFunctionType type) { JetTypeReference receiverTypeRef = type.getReceiverTypeRef(); - JetType receiverType = receiverTypeRef == null ? null : resolveType(c, receiverTypeRef); + JetType receiverType = receiverTypeRef == null ? null : resolveType(c.noBareTypes(), receiverTypeRef); List parameterTypes = new ArrayList(); for (JetParameter parameter : type.getParameters()) { - parameterTypes.add(resolveType(c, parameter.getTypeReference())); + parameterTypes.add(resolveType(c.noBareTypes(), parameter.getTypeReference())); } JetTypeReference returnTypeRef = type.getReturnTypeRef(); JetType returnType; if (returnTypeRef != null) { - returnType = resolveType(c, returnTypeRef); + returnType = resolveType(c.noBareTypes(), returnTypeRef); } else { returnType = KotlinBuiltIns.getInstance().getUnitType(); } - result[0] = KotlinBuiltIns.getInstance().getFunctionType(annotations, receiverType, parameterTypes, returnType); + result[0] = type(KotlinBuiltIns.getInstance().getFunctionType(annotations, receiverType, parameterTypes, returnType)); } @Override @@ -219,32 +229,11 @@ public class TypeResolver { }); } if (result[0] == null) { - return ErrorUtils.createErrorType(typeElement == null ? "No type element" : typeElement.getText()); + return type(ErrorUtils.createErrorType(typeElement == null ? "No type element" : typeElement.getText())); } return result[0]; } - private static boolean rhsOfIsExpression(@NotNull JetUserType type) { - // Look for the FIRST expression containing this type - JetExpression outerExpression = PsiTreeUtil.getParentOfType(type, JetExpression.class); - if (outerExpression instanceof JetIsExpression) { - JetIsExpression isExpression = (JetIsExpression) outerExpression; - // If this expression is JetIsExpression, and the type is the outermost on the RHS - if (type.getParent() == isExpression.getTypeRef()) { - return true; - } - } - return false; - } - - private static boolean rhsOfIsPattern(@NotNull JetUserType type) { - // Look for the is-pattern containing this type - JetWhenConditionIsPattern outerPattern = PsiTreeUtil.getParentOfType(type, JetWhenConditionIsPattern.class, false, JetExpression.class); - if (outerPattern == null) return false; - // We are interested only in the outermost type on the RHS - return type.getParent() == outerPattern.getTypeRef(); - } - private JetScope getScopeForTypeParameter(TypeResolutionContext c, final TypeParameterDescriptor typeParameterDescriptor) { if (c.checkBounds) { return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope(); @@ -283,7 +272,7 @@ public class TypeResolver { } else { // TODO : handle the Foo case - type = resolveType(c, argumentElement.getTypeReference()); + type = resolveType(c.noBareTypes(), argumentElement.getTypeReference()); Variance kind = resolveProjectionKind(projectionKind); if (constructor.getParameters().size() > i) { TypeParameterDescriptor parameterDescriptor = constructor.getParameters().get(i); @@ -333,15 +322,4 @@ public class TypeResolver { } return null; } - - @NotNull - private static String allStarProjectionsString(@NotNull TypeConstructor constructor) { - int size = constructor.getParameters().size(); - assert size != 0 : "No projections possible for a nilary type constructor" + constructor; - ClassifierDescriptor declarationDescriptor = constructor.getDeclarationDescriptor(); - assert declarationDescriptor != null : "No declaration descriptor for type constructor " + constructor; - String name = declarationDescriptor.getName().asString(); - - return TypeUtils.getTypeNameAndStarProjectionsString(name, size); - } } 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 1f37f9fae74..889a6b96717 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/CastDiagnosticsUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/CastDiagnosticsUtil.java @@ -112,11 +112,41 @@ public class CastDiagnosticsUtil { // NOTE: this does not account for 'as Array>' if (allParametersReified(subtype)) return false; + JetType staticallyKnownSubtype = findStaticallyKnownSubtype(supertype, subtype.getConstructor()); + + // 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); + } + + /** + * Remember that we are trying to cast something of type {@code supertype} to {@code subtype}. + * + * Since at runtime we can only check the class (type constructor), the rest of the subtype should be known statically, from supertype. + * This method reconstructs all static information that can be obtained from supertype. + * + * Example 1: + * supertype = Collection + * subtype = List<...> + * result = List + * + * Example 2: + * supertype = Any + * subtype = List<...> + * result = List<*> + */ + public static JetType findStaticallyKnownSubtype(@NotNull JetType supertype, @NotNull TypeConstructor subtypeConstructor) { + assert !supertype.isNullable() : "This method only makes sense for non-nullable types"; + // 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)); + ClassifierDescriptor descriptor = subtypeConstructor.getDeclarationDescriptor(); + assert descriptor != null : "Can't create default type for " + subtypeConstructor; + JetType subtypeWithVariables = descriptor.getDefaultType(); // Now, let's find a supertype of List that is a Collection of something, // in this case it will be Collection @@ -158,15 +188,7 @@ public class CastDiagnosticsUtil { // 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); + return TypeSubstitutor.create(substitution).substitute(subtypeWithVariables, Variance.INVARIANT); } private static boolean allParametersReified(JetType subtype) { 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 60b46010b4f..f7692084d69 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 @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.types.expressions; import com.google.common.collect.Lists; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; @@ -76,10 +77,13 @@ import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType; import static org.jetbrains.jet.lang.types.expressions.ControlStructureTypingUtils.createCallForSpecialConstruction; import static org.jetbrains.jet.lang.types.expressions.ControlStructureTypingUtils.resolveSpecialConstructionAsCall; import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.*; +import static org.jetbrains.jet.lexer.JetTokens.*; @SuppressWarnings("SuspiciousMethodCalls") public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { + private static final TokenSet BARE_TYPES_ALLOWED = TokenSet.create(AS_KEYWORD, AS_SAFE, IS_KEYWORD, NOT_IS); + private final PlatformToKotlinClassMap platformToKotlinClassMap; protected BasicExpressionTypingVisitor(@NotNull ExpressionTypingInternals facade, @NotNull PlatformToKotlinClassMap platformToKotlinClassMap) { @@ -167,10 +171,17 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return JetTypeInfo.create(null, leftTypeInfo.getDataFlowInfo()); } - JetType targetType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, right, context.trace, true); IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); + boolean allowBareTypes = BARE_TYPES_ALLOWED.contains(operationType); + TypeResolutionContext typeResolutionContext = new TypeResolutionContext(context.scope, context.trace, true, allowBareTypes); + PossiblyBareType possiblyBareTarget = context.expressionTypingServices.getTypeResolver().resolvePossiblyBareType(typeResolutionContext, right); + if (isTypeFlexible(left) || operationType == JetTokens.COLON) { + // We do not allow bare types on static assertions, because static assertions provide an expected type for their argument, + // thus causing a circularity in type dependencies + assert !possiblyBareTarget.isBare() : "Bare types should not be allowed for static assertions, because argument inference makes no sense there"; + JetType targetType = possiblyBareTarget.getActualType(); JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType.replaceExpectedType(targetType)); checkBinaryWithTypeRHS(expression, context, targetType, typeInfo.getType()); @@ -180,15 +191,24 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType); DataFlowInfo dataFlowInfo = context.dataFlowInfo; - if (typeInfo.getType() != null) { - checkBinaryWithTypeRHS(expression, contextWithNoExpectedType, targetType, typeInfo.getType()); + JetType subjectType = typeInfo.getType(); + JetType targetType; + if (subjectType != null) { + targetType = possiblyBareTarget.reconstruct(subjectType); + + checkBinaryWithTypeRHS(expression, contextWithNoExpectedType, targetType, subjectType); dataFlowInfo = typeInfo.getDataFlowInfo(); - if (operationType == JetTokens.AS_KEYWORD) { - DataFlowValue value = DataFlowValueFactory.INSTANCE.createDataFlowValue(left, typeInfo.getType(), context.trace.getBindingContext()); + if (operationType == AS_KEYWORD) { + DataFlowValue value = + DataFlowValueFactory.INSTANCE.createDataFlowValue(left, subjectType, context.trace.getBindingContext()); dataFlowInfo = dataFlowInfo.establishSubtyping(value, targetType); } } - JetType result = operationType == JetTokens.AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType; + else { + // Recovery: let's reconstruct as if we were casting from Any, to get some type there + targetType = possiblyBareTarget.reconstruct(KotlinBuiltIns.getInstance().getAnyType()); + } + JetType result = operationType == AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType; return DataFlowUtils.checkType(result, expression, context, dataFlowInfo); } 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 7b963e81d25..fa6c1d01e53 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 @@ -23,6 +23,8 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.PossiblyBareType; +import org.jetbrains.jet.lang.resolve.TypeResolutionContext; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory; @@ -279,8 +281,12 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { if (typeReferenceAfterIs == null) { return noChange(context); } - JetType type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReferenceAfterIs, context.trace, - true); + TypeResolutionContext typeResolutionContext = new TypeResolutionContext(context.scope, context.trace, true, /*allowBareTypes=*/ true); + PossiblyBareType possiblyBareTarget = context.expressionTypingServices.getTypeResolver().resolvePossiblyBareType(typeResolutionContext, typeReferenceAfterIs); + JetType type = possiblyBareTarget.reconstruct(subjectType); + if (possiblyBareTarget.isBare()) { + context.trace.record(BindingContext.TYPE, typeReferenceAfterIs, type); + } if (!subjectType.isNullable() && type.isNullable()) { JetTypeElement element = typeReferenceAfterIs.getTypeElement(); assert element instanceof JetNullableType : "element must be instance of " + JetNullableType.class.getName(); diff --git a/compiler/testData/diagnostics/tests/cast/bare/AsNestedBare.kt b/compiler/testData/diagnostics/tests/cast/bare/AsNestedBare.kt new file mode 100644 index 00000000000..c7f76721598 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/AsNestedBare.kt @@ -0,0 +1,10 @@ +trait Tr +trait G + +fun test(tr: Tr): Any { + return tr as G<G> +} + +fun test1(tr: Tr): Any { + return tr as G.(G) -> G +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/AsNullable.kt b/compiler/testData/diagnostics/tests/cast/bare/AsNullable.kt new file mode 100644 index 00000000000..5f4a50757e4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/AsNullable.kt @@ -0,0 +1,8 @@ +trait Tr +trait G : Tr + +fun test(tr: Tr) { + val v = tr as G? + // If v is not nullable, there will be a warning on this line: + v!!: G +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/EitherAs.kt b/compiler/testData/diagnostics/tests/cast/bare/EitherAs.kt new file mode 100644 index 00000000000..968faf96531 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/EitherAs.kt @@ -0,0 +1,16 @@ +trait Either +trait Left: Either +trait Right: Either + +class C1(val v1: Int) +class C2(val v2: Int) + +fun _as_left(e: Either): Any { + val v = e as Left + return v: Left +} + +fun _as_right(e: Either): Any { + val v = e as Right + return v: Right +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/EitherIs.kt b/compiler/testData/diagnostics/tests/cast/bare/EitherIs.kt new file mode 100644 index 00000000000..cde3454f2ca --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/EitherIs.kt @@ -0,0 +1,24 @@ +trait Either +trait Left: Either { + val value: A +} +trait Right: Either { + val value: B +} + +class C1(val v1: Int) +class C2(val v2: Int) + +fun _is_l(e: Either): Any { + if (e is Left) { + return e.value.v1 + } + return e +} + +fun _is_r(e: Either): Any { + if (e is Right) { + return e.value.v2 + } + return e +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/EitherNotIs.kt b/compiler/testData/diagnostics/tests/cast/bare/EitherNotIs.kt new file mode 100644 index 00000000000..54dfb3caa3c --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/EitherNotIs.kt @@ -0,0 +1,24 @@ +trait Either +trait Left: Either { + val value: A +} +trait Right: Either { + val value: B +} + +class C1(val v1: Int) +class C2(val v2: Int) + +fun _is_l(e: Either): Any { + if (e !is Left) { + return e + } + return e.value.v1 +} + +fun _is_r(e: Either): Any { + if (e !is Right) { + return e + } + return e.value.v2 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/EitherSafeAs.kt b/compiler/testData/diagnostics/tests/cast/bare/EitherSafeAs.kt new file mode 100644 index 00000000000..8424a6e003a --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/EitherSafeAs.kt @@ -0,0 +1,16 @@ +trait Either +trait Left: Either +trait Right: Either + +class C1(val v1: Int) +class C2(val v2: Int) + +fun _as_left(e: Either): Any? { + val v = e as? Left + return v: Left? +} + +fun _as_right(e: Either): Any? { + val v = e as? Right + return v: Right? +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/EitherWhen.kt b/compiler/testData/diagnostics/tests/cast/bare/EitherWhen.kt new file mode 100644 index 00000000000..c9800abd0fb --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/EitherWhen.kt @@ -0,0 +1,18 @@ +trait Either +trait Left: Either { + val value: A +} +trait Right: Either { + val value: B +} + +class C1(val v1: Int) +class C2(val v2: Int) + +fun _when(e: Either): Any { + return when (e) { + is Left -> e.value.v1 + is Right -> e.value.v2 + else -> e + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/ErrorsInSubstitution.kt b/compiler/testData/diagnostics/tests/cast/bare/ErrorsInSubstitution.kt new file mode 100644 index 00000000000..da98c968b35 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/ErrorsInSubstitution.kt @@ -0,0 +1,7 @@ +trait B +trait G: B + +fun f(p: B<Foo>): Any { + val v = p as G + return v: G<*> +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/NullableAs.kt b/compiler/testData/diagnostics/tests/cast/bare/NullableAs.kt new file mode 100644 index 00000000000..717bdc8627c --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/NullableAs.kt @@ -0,0 +1,7 @@ +trait Tr +trait G : Tr + +fun test(tr: Tr?) { + val v = tr as G + v: G +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/RedundantNullable.kt b/compiler/testData/diagnostics/tests/cast/bare/RedundantNullable.kt new file mode 100644 index 00000000000..77933e0545a --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/RedundantNullable.kt @@ -0,0 +1,4 @@ +trait B +class G: B + +fun f(b: B?) = b is G?? \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/ToErrorType.kt b/compiler/testData/diagnostics/tests/cast/bare/ToErrorType.kt new file mode 100644 index 00000000000..ee8ce3bdb93 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/ToErrorType.kt @@ -0,0 +1,6 @@ +class P + +fun foo(p: P): Any { + val v = p as G + return v +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/UnrelatedAs.kt b/compiler/testData/diagnostics/tests/cast/bare/UnrelatedAs.kt new file mode 100644 index 00000000000..f3731d6a5b0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/UnrelatedAs.kt @@ -0,0 +1,7 @@ +trait Tr +trait G + +fun test(tr: Tr) { + val v = tr as G + v: G<*> +} diff --git a/compiler/testData/diagnostics/tests/cast/bare/UnrelatedColon.kt b/compiler/testData/diagnostics/tests/cast/bare/UnrelatedColon.kt new file mode 100644 index 00000000000..521d280cb1d --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/UnrelatedColon.kt @@ -0,0 +1,4 @@ +trait Tr +trait G + +fun test(tr: Tr) = tr: G \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/UnrelatedIs.kt b/compiler/testData/diagnostics/tests/cast/bare/UnrelatedIs.kt new file mode 100644 index 00000000000..20ceb0b1998 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/bare/UnrelatedIs.kt @@ -0,0 +1,4 @@ +trait Tr +trait G + +fun test(tr: Tr) = tr is G diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 7ebfa281de4..12e9726a0a2 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -964,7 +964,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage } @TestMetadata("compiler/testData/diagnostics/tests/cast") - @InnerTestClasses({Cast.NeverSucceeds.class}) + @InnerTestClasses({Cast.Bare.class, Cast.NeverSucceeds.class}) public static class Cast extends AbstractDiagnosticsTestWithEagerResolve { public void testAllFilesPresentInCast() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/cast"), Pattern.compile("^(.+)\\.kt$"), true); @@ -1185,6 +1185,84 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/cast/WhenWithExpression.kt"); } + @TestMetadata("compiler/testData/diagnostics/tests/cast/bare") + public static class Bare extends AbstractDiagnosticsTestWithEagerResolve { + public void testAllFilesPresentInBare() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/cast/bare"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("AsNestedBare.kt") + public void testAsNestedBare() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/AsNestedBare.kt"); + } + + @TestMetadata("AsNullable.kt") + public void testAsNullable() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/AsNullable.kt"); + } + + @TestMetadata("EitherAs.kt") + public void testEitherAs() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/EitherAs.kt"); + } + + @TestMetadata("EitherIs.kt") + public void testEitherIs() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/EitherIs.kt"); + } + + @TestMetadata("EitherNotIs.kt") + public void testEitherNotIs() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/EitherNotIs.kt"); + } + + @TestMetadata("EitherSafeAs.kt") + public void testEitherSafeAs() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/EitherSafeAs.kt"); + } + + @TestMetadata("EitherWhen.kt") + public void testEitherWhen() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/EitherWhen.kt"); + } + + @TestMetadata("ErrorsInSubstitution.kt") + public void testErrorsInSubstitution() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/ErrorsInSubstitution.kt"); + } + + @TestMetadata("NullableAs.kt") + public void testNullableAs() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/NullableAs.kt"); + } + + @TestMetadata("RedundantNullable.kt") + public void testRedundantNullable() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/RedundantNullable.kt"); + } + + @TestMetadata("ToErrorType.kt") + public void testToErrorType() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/ToErrorType.kt"); + } + + @TestMetadata("UnrelatedAs.kt") + public void testUnrelatedAs() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/UnrelatedAs.kt"); + } + + @TestMetadata("UnrelatedColon.kt") + public void testUnrelatedColon() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/UnrelatedColon.kt"); + } + + @TestMetadata("UnrelatedIs.kt") + public void testUnrelatedIs() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/bare/UnrelatedIs.kt"); + } + + } + @TestMetadata("compiler/testData/diagnostics/tests/cast/neverSucceeds") public static class NeverSucceeds extends AbstractDiagnosticsTestWithEagerResolve { public void testAllFilesPresentInNeverSucceeds() throws Exception { @@ -1216,6 +1294,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage public static Test innerSuite() { TestSuite suite = new TestSuite("Cast"); suite.addTestSuite(Cast.class); + suite.addTestSuite(Bare.class); suite.addTestSuite(NeverSucceeds.class); return suite; }