Allow bare types on the right-hand side of as/as?/is/!is

This commit is contained in:
Andrey Breslav
2013-09-06 17:33:28 +04:00
parent e9e23c0069
commit 5c86a5bd7c
21 changed files with 447 additions and 82 deletions
@@ -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<String>) {
* if (a is List) {
* // a is known to be List<String> 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();
}
}
@@ -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);
}
}
@@ -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<AnnotationDescriptor> 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<AnnotationDescriptor> 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.<TypeProjection>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<JetType> parameterTypes = new ArrayList<JetType>();
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<in *> 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);
}
}
@@ -112,11 +112,41 @@ public class CastDiagnosticsUtil {
// NOTE: this does not account for 'as Array<List<T>>'
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 Foo>
// 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<String>
* subtype = List<...>
* result = List<String>
*
* 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<Foo> to List<Bar>
// First, let's make List<T>, 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<T> that is a Collection of something,
// in this case it will be Collection<T>
@@ -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<T> -> List<Foo>
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 Foo>
// 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) {
@@ -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);
}
@@ -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();
@@ -0,0 +1,10 @@
trait Tr
trait G<T>
fun test(tr: Tr): Any {
return tr as G<<!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>G<!>>
}
fun test1(tr: Tr): Any {
return tr as <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>G<!>.(<!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>G<!>) -> <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>G<!>
}
@@ -0,0 +1,8 @@
trait Tr<T>
trait G<T> : Tr<T>
fun test(tr: Tr<String>) {
val v = tr as G?
// If v is not nullable, there will be a warning on this line:
v!!: G<String>
}
@@ -0,0 +1,16 @@
trait Either<out A, out B>
trait Left<out A>: Either<A, Nothing>
trait Right<out B>: Either<Nothing, B>
class C1(val v1: Int)
class C2(val v2: Int)
fun _as_left(e: Either<C1, C2>): Any {
val v = e as Left
return v: Left<C1>
}
fun _as_right(e: Either<C1, C2>): Any {
val v = e as Right
return v: Right<C2>
}
@@ -0,0 +1,24 @@
trait Either<out A, out B>
trait Left<out A>: Either<A, Nothing> {
val value: A
}
trait Right<out B>: Either<Nothing, B> {
val value: B
}
class C1(val v1: Int)
class C2(val v2: Int)
fun _is_l(e: Either<C1, C2>): Any {
if (e is Left) {
return e.value.v1
}
return e
}
fun _is_r(e: Either<C1, C2>): Any {
if (e is Right) {
return e.value.v2
}
return e
}
@@ -0,0 +1,24 @@
trait Either<out A, out B>
trait Left<out A>: Either<A, Nothing> {
val value: A
}
trait Right<out B>: Either<Nothing, B> {
val value: B
}
class C1(val v1: Int)
class C2(val v2: Int)
fun _is_l(e: Either<C1, C2>): Any {
if (e !is Left) {
return e
}
return e.value.v1
}
fun _is_r(e: Either<C1, C2>): Any {
if (e !is Right) {
return e
}
return e.value.v2
}
@@ -0,0 +1,16 @@
trait Either<out A, out B>
trait Left<out A>: Either<A, Nothing>
trait Right<out B>: Either<Nothing, B>
class C1(val v1: Int)
class C2(val v2: Int)
fun _as_left(e: Either<C1, C2>): Any? {
val v = e as? Left
return v: Left<C1>?
}
fun _as_right(e: Either<C1, C2>): Any? {
val v = e as? Right
return v: Right<C2>?
}
@@ -0,0 +1,18 @@
trait Either<out A, out B>
trait Left<out A>: Either<A, Nothing> {
val value: A
}
trait Right<out B>: Either<Nothing, B> {
val value: B
}
class C1(val v1: Int)
class C2(val v2: Int)
fun _when(e: Either<C1, C2>): Any {
return when (e) {
is Left -> e.value.v1
is Right -> e.value.v2
else -> e
}
}
@@ -0,0 +1,7 @@
trait B<T>
trait G<T>: B<T>
fun f(p: B<<!UNRESOLVED_REFERENCE!>Foo<!>>): Any {
val v = <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>p<!> as G
return <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>v<!>: G<*>
}
@@ -0,0 +1,7 @@
trait Tr<T>
trait G<T> : Tr<T>
fun test(tr: Tr<String>?) {
val v = tr as G
v: G<String>
}
@@ -0,0 +1,4 @@
trait B<T>
class G<T>: B<T>
fun f(b: B<String>?) = b is G?<!REDUNDANT_NULLABLE!>?<!>
@@ -0,0 +1,6 @@
class P
fun foo(p: P): Any {
val v = p <!USELESS_CAST!>as<!> <!UNRESOLVED_REFERENCE!>G<!>
return <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>v<!>
}
@@ -0,0 +1,7 @@
trait Tr
trait G<T>
fun test(tr: Tr) {
val v = tr as G
v: G<*>
}
@@ -0,0 +1,4 @@
trait Tr
trait G<T>
fun test(tr: Tr) = tr: <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>G<!>
@@ -0,0 +1,4 @@
trait Tr
trait G<T>
fun test(tr: Tr) = tr is G
@@ -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;
}