diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 8ff1dfe598b..e4b5135353a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -786,7 +786,7 @@ public interface Errors { DiagnosticFactory0 CAST_NEVER_SUCCEEDS = DiagnosticFactory0.create(WARNING); DiagnosticFactory0 DYNAMIC_NOT_ALLOWED = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 IS_ENUM_ENTRY = DiagnosticFactory0.create(ERROR); - DiagnosticFactory0 ENUM_ENTRY_AS_TYPE = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 ENUM_ENTRY_AS_TYPE = DiagnosticFactory0.create(ERROR); DiagnosticFactory2 IMPLICIT_CAST_TO_ANY = DiagnosticFactory2.create(WARNING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index bd08905fc5b..e16479a39f9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,35 +40,6 @@ import org.jetbrains.kotlin.types.typeUtil.* import org.jetbrains.kotlin.utils.addToStdlib.check import java.util.* -fun KtDeclaration.checkTypeReferences(trace: BindingTrace) { - if (this is KtCallableDeclaration) { - typeReference?.checkNotEnumEntry(trace) - receiverTypeReference?.checkNotEnumEntry(trace) - } - if (this is KtDeclarationWithBody) { - for (parameter in valueParameters) { - parameter.typeReference?.checkNotEnumEntry(trace) - } - } -} - -fun KtTypeReference.checkNotEnumEntry(trace: BindingTrace): Boolean { - var result = false - trace.bindingContext.get(TYPE, this)?.let { - val targetDescriptor = TypeUtils.getClassDescriptor(it) - if (targetDescriptor != null && DescriptorUtils.isEnumEntry(targetDescriptor)) { - trace.report(ENUM_ENTRY_AS_TYPE.on(this)) - result = true - } - } - typeElement?.let { - for (typeArgument in it.typeArgumentsAsTypes) { - typeArgument?.checkNotEnumEntry(trace) - } - } - return result -} - internal class DeclarationsCheckerBuilder( private val descriptorResolver: DescriptorResolver, private val originalModifiersChecker: ModifiersChecker, @@ -93,8 +64,6 @@ class DeclarationsChecker( private val exposedChecker = ExposedVisibilityChecker(trace) - fun KtDeclaration.checkTypeReferences() = checkTypeReferences(trace) - fun process(bodiesResolveContext: BodiesResolveContext) { for (file in bodiesResolveContext.files) { checkModifiersAndAnnotationsInPackageDirective(file) @@ -118,7 +87,6 @@ class DeclarationsChecker( checkPrimaryConstructor(classOrObject, classDescriptor) - classOrObject.checkTypeReferences() modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor) identifierChecker.checkDeclaration(classOrObject, trace) exposedChecker.checkClassHeader(classOrObject, classDescriptor) @@ -126,14 +94,12 @@ class DeclarationsChecker( for ((function, functionDescriptor) in bodiesResolveContext.functions.entries) { checkFunction(function, functionDescriptor) - function.checkTypeReferences() modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor) identifierChecker.checkDeclaration(function, trace) } for ((property, propertyDescriptor) in bodiesResolveContext.properties.entries) { checkProperty(property, propertyDescriptor) - property.checkTypeReferences() modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor) identifierChecker.checkDeclaration(property, trace) } @@ -259,7 +225,6 @@ class DeclarationsChecker( } private fun checkConstructorDeclaration(constructorDescriptor: ClassConstructorDescriptor, declaration: KtConstructor<*>) { - declaration.checkTypeReferences() modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor) identifierChecker.checkDeclaration(declaration, trace) checkVarargParameters(trace, constructorDescriptor) @@ -327,7 +292,6 @@ class DeclarationsChecker( for (delegationSpecifier in classOrObject.getSuperTypeListEntries()) { val typeReference = delegationSpecifier.typeReference ?: continue typeReference.type()?.let { DescriptorResolver.checkBounds(typeReference, it, trace) } - typeReference.checkNotEnumEntry(trace) } if (classOrObject !is KtClass) return @@ -841,7 +805,6 @@ class DeclarationsChecker( for (accessorDescriptor in propertyDescriptor.accessors) { val accessor = if (accessorDescriptor is PropertyGetterDescriptor) property.getter else property.setter if (accessor != null) { - accessor.checkTypeReferences() modifiersChecker.checkModifiersForDeclaration(accessor, accessorDescriptor) identifierChecker.checkDeclaration(accessor, trace) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 58d9be7fa5c..13e6e619e82 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -622,7 +622,6 @@ public class DescriptorResolver { @NotNull KotlinType upperBoundType, BindingTrace trace ) { - if (DeclarationsCheckerKt.checkNotEnumEntry(upperBound, trace)) return; if (!TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, upperBoundType)) { trace.report(FINAL_UPPER_BOUND.on(upperBound, upperBoundType)); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt index 5eac75691a9..65fe13a0163 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -120,7 +120,6 @@ class LocalVariableResolver( ExpressionTypingUtils.checkVariableShadowing(context.scope, context.trace, propertyDescriptor) - property.checkTypeReferences(context.trace) modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor) identifierChecker.checkDeclaration(property, context.trace) return Pair(typeInfo.replaceType(dataFlowAnalyzer.checkStatementType(property, context)), propertyDescriptor) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt index c7150cbf2e1..c74a624c82e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -68,9 +68,10 @@ class QualifiedExpressionResolver { ): TypeQualifierResolutionResult { val ownerDescriptor = if (!isDebuggerContext) scope.ownerDescriptor else null if (userType.qualifier == null) { - val descriptor = userType.referenceExpression?.let { - val classifier = scope.findClassifier(it.getReferencedNameAsName(), KotlinLookupLocation(it)) - storeResult(trace, it, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false) + val descriptor = userType.referenceExpression?.let { expression -> + val classifier = scope.findClassifier(expression.getReferencedNameAsName(), KotlinLookupLocation(expression)) + checkNotEnumEntry(classifier, trace, expression) + storeResult(trace, expression, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false) classifier } @@ -106,13 +107,23 @@ class QualifiedExpressionResolver { val lastPart = qualifierPartList.last() val classifier = when (qualifier) { is PackageViewDescriptor -> qualifier.memberScope.getContributedClassifier(lastPart.name, lastPart.location) - is ClassDescriptor -> qualifier.unsubstitutedInnerClassesScope.getContributedClassifier(lastPart.name, lastPart.location) + is ClassDescriptor -> { + val descriptor = qualifier.unsubstitutedInnerClassesScope.getContributedClassifier(lastPart.name, lastPart.location) + checkNotEnumEntry(descriptor, trace, lastPart.expression) + descriptor + } else -> null } storeResult(trace, lastPart.expression, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = isQualifier) return TypeQualifierResolutionResult(qualifierPartList, classifier) } + private fun checkNotEnumEntry(descriptor: DeclarationDescriptor?, trace: BindingTrace, expression: KtSimpleNameExpression) { + if (descriptor != null && DescriptorUtils.isEnumEntry(descriptor)) { + trace.report(Errors.ENUM_ENTRY_AS_TYPE.on(expression)) + } + } + fun resolveDescriptorForDoubleColonLHS( expression: KtExpression, scope: LexicalScope, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index 6ab5efd696a..67b295fa6d2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -353,8 +353,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ) { if (actualType == null || noExpectedType(targetType) || targetType.isError()) return; - DeclarationsCheckerKt.checkNotEnumEntry(expression.getRight(), context.trace); - if (DynamicTypesKt.isDynamic(targetType)) { KtTypeReference right = expression.getRight(); assert right != null : "We know target is dynamic, but RHS is missing"; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt index 48d4c1f9453..bb41238e93e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,8 +28,11 @@ import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries -import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext.EXPECTED_RETURN_TYPE +import org.jetbrains.kotlin.resolve.BindingContextUtils +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil import org.jetbrains.kotlin.resolve.checkers.UnderscoreChecker import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope @@ -109,7 +112,6 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre function.getValueParameters(), functionDescriptor.valueParameters, context.scope, context.dataFlowInfo, context.trace ) - function.checkTypeReferences(context.trace) components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(function, functionDescriptor) components.identifierChecker.checkDeclaration(function, context.trace) components.declarationsCheckerBuilder.withTrace(context.trace).checkFunction(function, functionDescriptor) diff --git a/compiler/testData/diagnostics/tests/EnumEntryAsType.kt b/compiler/testData/diagnostics/tests/EnumEntryAsType.kt index 386990c3e8c..f81d3a2969f 100644 --- a/compiler/testData/diagnostics/tests/EnumEntryAsType.kt +++ b/compiler/testData/diagnostics/tests/EnumEntryAsType.kt @@ -1,34 +1,54 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER -enum class Color { RED } +enum class Color { + RED { + fun RED> simpleName(): RED = null!! + } +} -class MyColor(val x: Color.RED, y: Color.RED) : Color.RED { +class MyColor(val x: Color.RED, y: Color.RED) : Color.RED { - var z: Color.RED = Color.RED - set(arg: Color.RED) { z = arg } + var z: Color.RED = Color.RED + set(arg: Color.RED) { z = arg } - fun foo(arg: Color.RED): Color.RED = arg + fun foo(arg: Color.RED): Color.RED = arg - fun bar(): Color.RED { - class Local : Color.RED - fun local(arg: Color.RED): Color.RED = arg - val temp: Color.RED = Color.RED - temp as? Color.RED - if (temp is Color.RED) { - return temp as Color.RED - } - val obj = object : Color.RED {} - if (obj is Color.RED) { - return obj - } + fun bar(): Color.RED { + class Local : Color.RED + fun local(arg: Color.RED): Color.RED = arg + val temp: Color.RED = Color.RED + temp as? Color.RED + if (temp is Color.RED) { + return temp as Color.RED + } + val obj = object : Color.RED {} + if (obj is Color.RED) { + return obj + } return Color.RED } } -fun create(): Array<Color.RED>? = null +fun create(): ArrayRED>? = null -interface YourColor.RED> +interface YourColor.RED> -class His : Your<Color.RED> +class His : YourRED> -fun Color.RED> otherCreate(): Array? = null \ No newline at end of file +fun Color.RED> otherCreate(): Array? = null + +typealias RedAlias = Color.RED + +typealias ArrayOfEnumEntry = ArrayRED> + +typealias ArrayOfEnumEntryAlias = Array + +fun bar(a: Any): T = a as T + +fun foo() { + fooRED>() + foo() + barRED>(Color.RED) +} + +fun ArrayRED>.foo(entries: ArrayRED>): ArrayRED> = null!! \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/EnumEntryAsType.txt b/compiler/testData/diagnostics/tests/EnumEntryAsType.txt index 53cf54e548a..ab536e19d29 100644 --- a/compiler/testData/diagnostics/tests/EnumEntryAsType.txt +++ b/compiler/testData/diagnostics/tests/EnumEntryAsType.txt @@ -1,7 +1,10 @@ package +public fun bar(/*0*/ a: kotlin.Any): T public fun create(): kotlin.Array? +public fun foo(): kotlin.Unit public fun otherCreate(): kotlin.Array? +public fun kotlin.Array.foo(/*0*/ entries: kotlin.Array): kotlin.Array public final enum class Color : kotlin.Enum { enum entry RED @@ -43,6 +46,7 @@ public final class MyColor : Color.RED { public final fun foo(/*0*/ arg: Color.RED): Color.RED public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun simpleName(): Color.RED public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -51,3 +55,6 @@ public interface Your { public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +public typealias ArrayOfEnumEntry = kotlin.Array +public typealias ArrayOfEnumEntryAlias = kotlin.Array +public typealias RedAlias = Color.RED diff --git a/compiler/testData/diagnostics/tests/enum/ifEnumEntry.kt b/compiler/testData/diagnostics/tests/enum/ifEnumEntry.kt index 83a69cd1f9b..1e5fa13b34d 100644 --- a/compiler/testData/diagnostics/tests/enum/ifEnumEntry.kt +++ b/compiler/testData/diagnostics/tests/enum/ifEnumEntry.kt @@ -3,4 +3,4 @@ enum class MyEnum { SECOND } -fun foo(me: MyEnum): Boolean = if (me is MyEnum.FIRST) true else false \ No newline at end of file +fun foo(me: MyEnum): Boolean = if (me is MyEnum.FIRST) true else false \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.kt b/compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.kt index f5634e0fe77..0c24077e5e0 100644 --- a/compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.kt +++ b/compiler/testData/diagnostics/tests/enum/inheritFromEnumEntry.kt @@ -2,4 +2,4 @@ enum class E { ENTRY } -class A : E.ENTRY +class A : E.ENTRY diff --git a/compiler/testData/diagnostics/tests/enum/isEnumEntry.kt b/compiler/testData/diagnostics/tests/enum/isEnumEntry.kt index 83603442a48..9ffdb1f5dac 100644 --- a/compiler/testData/diagnostics/tests/enum/isEnumEntry.kt +++ b/compiler/testData/diagnostics/tests/enum/isEnumEntry.kt @@ -3,4 +3,4 @@ enum class MyEnum { SECOND } -fun foo(me: MyEnum): Boolean = me is MyEnum.FIRST \ No newline at end of file +fun foo(me: MyEnum): Boolean = me is MyEnum.FIRST \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveEnumIs.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveEnumIs.kt index 4f695b0e3bd..0e5b31d342f 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveEnumIs.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveEnumIs.kt @@ -4,8 +4,8 @@ enum class MyEnum { fun foo(x: MyEnum): Int { return when (x) { - is MyEnum.A -> 1 - is MyEnum.B -> 2 - is MyEnum.C -> 3 + is MyEnum.A -> 1 + is MyEnum.B -> 2 + is MyEnum.C -> 3 } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/when/ExhaustiveEnumMixed.kt b/compiler/testData/diagnostics/tests/when/ExhaustiveEnumMixed.kt index a71d189a3a6..d962fadd7e4 100644 --- a/compiler/testData/diagnostics/tests/when/ExhaustiveEnumMixed.kt +++ b/compiler/testData/diagnostics/tests/when/ExhaustiveEnumMixed.kt @@ -5,7 +5,7 @@ enum class MyEnum { fun foo(x: MyEnum): Int { return when (x) { MyEnum.A -> 1 - is MyEnum.B -> 2 - is MyEnum.C -> 3 + is MyEnum.B -> 2 + is MyEnum.C -> 3 } } \ No newline at end of file