From bbafb7c013597401519e34db7955a5556b425808 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 22 Nov 2016 18:18:13 +0300 Subject: [PATCH] Check platform<->impl compatibility for class members When matching platform and impl classifiers, ensure that each declaration from the platform class scope is present in the impl class scope. Note that the presence of the 'impl' modifier is not checked yet --- ...atformIncompatibilityDiagnosticRenderer.kt | 44 +++++-- .../PlatformImplDeclarationChecker.kt | 114 +++++++++++++++--- .../constructorIncorrectSignature/common.kt | 3 + .../constructorIncorrectSignature/jvm.kt | 3 + .../constructorIncorrectSignature/output.txt | 25 ++++ .../functionIncorrectSignature/common.kt | 3 + .../functionIncorrectSignature/jvm.kt | 3 + .../functionIncorrectSignature/output.txt | 25 ++++ .../classScopes/missingConstructor/common.kt | 3 + .../classScopes/missingConstructor/jvm.kt | 1 + .../classScopes/missingConstructor/output.txt | 22 ++++ .../classScopes/missingFunction/common.kt | 3 + .../classScopes/missingFunction/jvm.kt | 1 + .../classScopes/missingFunction/output.txt | 19 +++ .../classScopes/simple/common.kt | 5 + .../multiplatform/classScopes/simple/jvm.kt | 5 + .../classScopes/simple/output.txt | 8 ++ .../incorrectImplInClass/common.kt | 1 + .../multiplatform/incorrectImplInClass/jvm.kt | 10 ++ .../incorrectImplInClass/output.txt | 17 +++ ...MultiPlatformIntegrationTestGenerated.java | 6 + 21 files changed, 294 insertions(+), 27 deletions(-) create mode 100644 compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/common.kt create mode 100644 compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/jvm.kt create mode 100644 compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/output.txt create mode 100644 compiler/testData/multiplatform/classScopes/functionIncorrectSignature/common.kt create mode 100644 compiler/testData/multiplatform/classScopes/functionIncorrectSignature/jvm.kt create mode 100644 compiler/testData/multiplatform/classScopes/functionIncorrectSignature/output.txt create mode 100644 compiler/testData/multiplatform/classScopes/missingConstructor/common.kt create mode 100644 compiler/testData/multiplatform/classScopes/missingConstructor/jvm.kt create mode 100644 compiler/testData/multiplatform/classScopes/missingConstructor/output.txt create mode 100644 compiler/testData/multiplatform/classScopes/missingFunction/common.kt create mode 100644 compiler/testData/multiplatform/classScopes/missingFunction/jvm.kt create mode 100644 compiler/testData/multiplatform/classScopes/missingFunction/output.txt create mode 100644 compiler/testData/multiplatform/classScopes/simple/common.kt create mode 100644 compiler/testData/multiplatform/classScopes/simple/jvm.kt create mode 100644 compiler/testData/multiplatform/classScopes/simple/output.txt create mode 100644 compiler/testData/multiplatform/incorrectImplInClass/common.kt create mode 100644 compiler/testData/multiplatform/incorrectImplInClass/jvm.kt create mode 100644 compiler/testData/multiplatform/incorrectImplInClass/output.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/PlatformIncompatibilityDiagnosticRenderer.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/PlatformIncompatibilityDiagnosticRenderer.kt index faabc9c6798..b434b3b05e7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/PlatformIncompatibilityDiagnosticRenderer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/PlatformIncompatibilityDiagnosticRenderer.kt @@ -16,28 +16,58 @@ package org.jetbrains.kotlin.diagnostics.rendering +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.resolve.checkers.PlatformImplDeclarationChecker object PlatformIncompatibilityDiagnosticRenderer : DiagnosticParameterRenderer>> { + private val INDENTATION_UNIT = " " + override fun render( obj: Map>, renderingContext: RenderingContext ): String { if (obj.isEmpty()) return "" + val renderDescriptor: (DeclarationDescriptor) -> String = { Renderers.COMPACT_WITH_MODIFIERS.render(it, renderingContext) } + return buildString { appendln() - for ((incompatibility, descriptors) in obj) { - append("The following declaration") - if (descriptors.size == 1) append(" is") else append("s are") - append(" incompatible") - incompatibility.reason?.let { append(" because $it") } + render(obj, "", renderDescriptor) + } + } + + private fun StringBuilder.render( + map: Map>, + indent: String, + renderDescriptor: (DeclarationDescriptor) -> String + ) { + for ((incompatibility, descriptors) in map) { + append(indent) + append("The following declaration") + if (descriptors.size == 1) append(" is") else append("s are") + append(" incompatible") + incompatibility.reason?.let { append(" because $it") } + + incompatibility.unimplemented?.let { unimplemented -> + appendln(".") + append(indent) + appendln("No implementations are found for members listed below:") + for ((descriptor, mapping) in unimplemented) { + appendln() + append(indent + " ") + appendln(renderDescriptor(descriptor)) + if (mapping.isNotEmpty()) { + appendln() + } + render(mapping, indent + INDENTATION_UNIT, renderDescriptor) + } + } ?: run { appendln(":") for (descriptor in descriptors) { - append(" ") - appendln(Renderers.COMPACT_WITH_MODIFIERS.render(descriptor, renderingContext)) + append(indent + " ") + appendln(renderDescriptor(descriptor)) } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PlatformImplDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PlatformImplDeclarationChecker.kt index 95fb5755840..19db63ff4df 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PlatformImplDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PlatformImplDeclarationChecker.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.BindingContext @@ -33,11 +34,13 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeConstructorSubstitution import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.typeUtil.asTypeProjection +import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.keysToMap class PlatformImplDeclarationChecker : DeclarationChecker { @@ -95,17 +98,28 @@ class PlatformImplDeclarationChecker : DeclarationChecker { private fun checkImplementationHasPlatformDeclaration( reportOn: KtDeclaration, descriptor: MemberDescriptor, diagnosticHolder: DiagnosticSink ) { + fun ClassifierDescriptor.findDeclarationForClass(): ClassDescriptor? = + findClassifiersFromTheSameModule().firstOrNull { declaration -> + this != declaration && + declaration is ClassDescriptor && declaration.isPlatform && + areCompatibleClassifiers(declaration, this) == Compatible + } as? ClassDescriptor + val hasDeclaration = when (descriptor) { - is CallableMemberDescriptor -> descriptor.findNamesakesFromTheSameModule().any { declaration -> - descriptor != declaration && - declaration.isPlatform && - areCompatibleCallables(declaration, descriptor) == Compatible - } - is ClassifierDescriptor -> descriptor.findClassifiersFromTheSameModule().any { declaration -> - descriptor != declaration && - declaration is ClassDescriptor && declaration.isPlatform && - areCompatibleClassifiers(declaration, descriptor) == Compatible + is CallableMemberDescriptor -> { + val container = descriptor.containingDeclaration + val candidates = when (container) { + is ClassDescriptor -> container.findDeclarationForClass()?.getMembers(descriptor.name).orEmpty() + is PackageFragmentDescriptor -> descriptor.findNamesakesFromTheSameModule() + else -> return // do not report anything for incorrect code, e.g. 'impl' local function + } + candidates.any { declaration -> + descriptor != declaration && + declaration.isPlatform && + areCompatibleCallables(declaration, descriptor) == Compatible + } } + is ClassifierDescriptor -> descriptor.findDeclarationForClass() != null else -> false } @@ -138,7 +152,10 @@ class PlatformImplDeclarationChecker : DeclarationChecker { sealed class Compatibility { // Note that the reason is used in the diagnostic output, see PlatformIncompatibilityDiagnosticRenderer - sealed class Incompatible(val reason: String?) : Compatibility() { + sealed class Incompatible( + val reason: String?, + val unimplemented: List>>>? = null + ) : Compatibility() { // Callables object ParameterShape : Incompatible("parameter shapes are different (extension vs non-extension)") @@ -172,6 +189,10 @@ class PlatformImplDeclarationChecker : DeclarationChecker { object Supertypes : Incompatible("some supertypes are missing in the implementation") + class ClassScopes( + unimplemented: List>>> + ) : Incompatible("some members are not implemented", unimplemented) + // Common object Modality : Incompatible("modality is different") @@ -188,7 +209,7 @@ class PlatformImplDeclarationChecker : DeclarationChecker { } // a is the declaration in common code, b is the definition in the platform-specific code - private fun areCompatibleCallables(a: CallableMemberDescriptor, b: CallableMemberDescriptor): Compatibility { + private fun areCompatibleCallables(a: CallableMemberDescriptor, b: CallableMemberDescriptor, parentSubstitutor: Substitutor? = null): Compatibility { assert(a.name == b.name) { "This function should be invoked only for declarations with the same name: $a, $b" } assert(a.containingDeclaration is ClassDescriptor == b.containingDeclaration is ClassDescriptor) { "This function should be invoked only for declarations in the same kind of container (both members or both top level): $a, $b" @@ -206,7 +227,7 @@ class PlatformImplDeclarationChecker : DeclarationChecker { val bTypeParams = b.typeParameters if (aTypeParams.size != bTypeParams.size) return Incompatible.TypeParameterCount - val substitutor = Substitutor(aTypeParams, bTypeParams) + val substitutor = Substitutor(aTypeParams, bTypeParams, parentSubstitutor) if (aParams.map { substitutor(it.type) } != bParams.map { it.type } || aExtensionReceiver?.type?.let(substitutor) != bExtensionReceiver?.type) return Incompatible.ParameterTypes @@ -260,9 +281,22 @@ class PlatformImplDeclarationChecker : DeclarationChecker { private fun areCompatibleClassifiers(a: ClassDescriptor, other: ClassifierDescriptor): Compatibility { assert(a.fqNameUnsafe == other.fqNameUnsafe) { "This function should be invoked only for declarations with the same name: $a, $other" } + var parentSubstitutor: Substitutor? = null + val b = when (other) { is ClassDescriptor -> other - is TypeAliasDescriptor -> other.classDescriptor ?: return Incompatible.Unknown + is TypeAliasDescriptor -> { + val classDescriptor = other.classDescriptor ?: return Compatible // do not report extra error on erroneous typealias + // If a platform class test.C is implemented by a typealias test.C = test.CImpl, we must now state that any occurrence + // of the type "test.C" in the platform class scope should be replaced with "test.CImpl". + // Otherwise the types would not be equal and e.g. test.C's constructor is not going to be found in test.CImpl's scope. + // For this, we construct an additional substitutor with a single mapping test.C -> test.CImpl + // TODO: this looks like a dirty hack + parentSubstitutor = Substitutor(null, TypeSubstitutor.create(TypeConstructorSubstitution.createByConstructorsMap( + mapOf(a.typeConstructor to classDescriptor.defaultType.asTypeProjection()) + ))) + classDescriptor + } else -> throw AssertionError("Incorrect impl classifier for $a: $other") } @@ -272,7 +306,7 @@ class PlatformImplDeclarationChecker : DeclarationChecker { val bTypeParams = b.declaredTypeParameters if (aTypeParams.size != bTypeParams.size) return Incompatible.TypeParameterCount - val substitutor = Substitutor(aTypeParams, bTypeParams) + val substitutor = Substitutor(aTypeParams, bTypeParams, parentSubstitutor) if (a.modality != b.modality) return Incompatible.Modality if (a.visibility != b.visibility) return Incompatible.Visibility @@ -283,12 +317,46 @@ class PlatformImplDeclarationChecker : DeclarationChecker { if (!b.typeConstructor.supertypes.containsAll(a.typeConstructor.supertypes.map(substitutor))) return Incompatible.Supertypes - // TODO: check scopes + areCompatibleClassScopes(a, b, substitutor).let { if (it != Compatible) return it } + // TODO: check 'impl' modifier return Compatible } + private fun areCompatibleClassScopes(a: ClassDescriptor, b: ClassDescriptor, substitutor: Substitutor): Compatibility { + val unimplemented = arrayListOf>>>() + + val bMembersByName = b.getMembers().groupBy { it.name } + + outer@ for (aMember in a.getMembers()) { + val mapping = bMembersByName[aMember.name].orEmpty().keysToMap { bMember -> areCompatibleCallables(aMember, bMember, substitutor) } + if (mapping.values.any { it == Compatible }) continue + + val incompatibilityMap = mutableMapOf>() + for ((descriptor, compatibility) in mapping) { + when (compatibility) { + Compatible -> continue@outer + is Incompatible -> incompatibilityMap.getOrPut(compatibility) { SmartList() }.add(descriptor) + } + } + + unimplemented.add(aMember to incompatibilityMap) + } + + // TODO: check static scope, enum entries + + if (unimplemented.isEmpty()) return Compatible + + return Incompatible.ClassScopes(unimplemented) + } + + private fun ClassDescriptor.getMembers(name: Name? = null): Collection { + val nameFilter = if (name != null) { it -> it == name } else MemberScope.ALL_NAME_FILTER + return defaultType.memberScope.getDescriptorsFiltered(nameFilter = nameFilter).filterIsInstance() + + constructors.filter { nameFilter(it.name) } + } + private inline fun equalBy(first: T, second: T, selector: (T) -> K): Boolean = selector(first) == selector(second) @@ -302,14 +370,20 @@ class PlatformImplDeclarationChecker : DeclarationChecker { // This substitutor takes the type from A's signature and returns the type that should be in that place in B's signature private class Substitutor( - aTypeParams: List, - bTypeParams: List + private val parent: Substitutor?, + private val typeSubstitutor: TypeSubstitutor ) : (KotlinType?) -> KotlinType? { - val typeSubstitutor = TypeSubstitutor.create(TypeConstructorSubstitution.createByParametersMap( - aTypeParams.keysToMap { bTypeParams[it.index].defaultType.asTypeProjection() } + constructor( + aTypeParams: List, + bTypeParams: List, + parent: Substitutor? = null + ) : this(parent, TypeSubstitutor.create( + TypeConstructorSubstitution.createByParametersMap(aTypeParams.keysToMap { + bTypeParams[it.index].defaultType.asTypeProjection() + }) )) override fun invoke(type: KotlinType?): KotlinType? = - type?.asTypeProjection()?.let(typeSubstitutor::substitute)?.type + (parent?.invoke(type) ?: type)?.asTypeProjection()?.let(typeSubstitutor::substitute)?.type } } diff --git a/compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/common.kt b/compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/common.kt new file mode 100644 index 00000000000..0ff7d1151e4 --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/common.kt @@ -0,0 +1,3 @@ +platform class Foo { + constructor(s: String) +} diff --git a/compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/jvm.kt b/compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/jvm.kt new file mode 100644 index 00000000000..09cce011363 --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/jvm.kt @@ -0,0 +1,3 @@ +impl class Foo { + impl constructor(s: Array) +} diff --git a/compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/output.txt b/compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/output.txt new file mode 100644 index 00000000000..a4ad3c3a915 --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/output.txt @@ -0,0 +1,25 @@ +-- Common -- +Exit code: OK +Output: + +-- JVM -- +Exit code: COMPILATION_ERROR +Output: +compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/common.kt:1:16: error: no definition is found for platform declaration 'Foo' +The following declaration is incompatible because some members are not implemented. +No implementations are found for members listed below: + + public constructor Foo(s: String) + + The following declaration is incompatible because parameter types are different: + public constructor Foo(s: Array) + +platform class Foo { + ^ +compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/jvm.kt:1:1: error: modifier 'impl' is only applicable to members that are initially declared in platform-independent code +impl class Foo { +^ +compiler/testData/multiplatform/classScopes/constructorIncorrectSignature/jvm.kt:2:5: error: modifier 'impl' is only applicable to members that are initially declared in platform-independent code + impl constructor(s: Array) + ^ + diff --git a/compiler/testData/multiplatform/classScopes/functionIncorrectSignature/common.kt b/compiler/testData/multiplatform/classScopes/functionIncorrectSignature/common.kt new file mode 100644 index 00000000000..383c122682b --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/functionIncorrectSignature/common.kt @@ -0,0 +1,3 @@ +platform class Foo { + fun function(b: ByteArray): Int +} diff --git a/compiler/testData/multiplatform/classScopes/functionIncorrectSignature/jvm.kt b/compiler/testData/multiplatform/classScopes/functionIncorrectSignature/jvm.kt new file mode 100644 index 00000000000..c27957cabc8 --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/functionIncorrectSignature/jvm.kt @@ -0,0 +1,3 @@ +impl class Foo { + impl fun function(b: ByteArray): Long = b.size.toLong() +} diff --git a/compiler/testData/multiplatform/classScopes/functionIncorrectSignature/output.txt b/compiler/testData/multiplatform/classScopes/functionIncorrectSignature/output.txt new file mode 100644 index 00000000000..2d731e465b7 --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/functionIncorrectSignature/output.txt @@ -0,0 +1,25 @@ +-- Common -- +Exit code: OK +Output: + +-- JVM -- +Exit code: COMPILATION_ERROR +Output: +compiler/testData/multiplatform/classScopes/functionIncorrectSignature/common.kt:1:16: error: no definition is found for platform declaration 'Foo' +The following declaration is incompatible because some members are not implemented. +No implementations are found for members listed below: + + public final platform fun function(b: ByteArray): Int + + The following declaration is incompatible because return type is different: + public final impl fun function(b: ByteArray): Long + +platform class Foo { + ^ +compiler/testData/multiplatform/classScopes/functionIncorrectSignature/jvm.kt:1:1: error: modifier 'impl' is only applicable to members that are initially declared in platform-independent code +impl class Foo { +^ +compiler/testData/multiplatform/classScopes/functionIncorrectSignature/jvm.kt:2:5: error: modifier 'impl' is only applicable to members that are initially declared in platform-independent code + impl fun function(b: ByteArray): Long = b.size.toLong() + ^ + diff --git a/compiler/testData/multiplatform/classScopes/missingConstructor/common.kt b/compiler/testData/multiplatform/classScopes/missingConstructor/common.kt new file mode 100644 index 00000000000..0ff7d1151e4 --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/missingConstructor/common.kt @@ -0,0 +1,3 @@ +platform class Foo { + constructor(s: String) +} diff --git a/compiler/testData/multiplatform/classScopes/missingConstructor/jvm.kt b/compiler/testData/multiplatform/classScopes/missingConstructor/jvm.kt new file mode 100644 index 00000000000..0a749a23b04 --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/missingConstructor/jvm.kt @@ -0,0 +1 @@ +impl class Foo diff --git a/compiler/testData/multiplatform/classScopes/missingConstructor/output.txt b/compiler/testData/multiplatform/classScopes/missingConstructor/output.txt new file mode 100644 index 00000000000..4f92c0eeb8b --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/missingConstructor/output.txt @@ -0,0 +1,22 @@ +-- Common -- +Exit code: OK +Output: + +-- JVM -- +Exit code: COMPILATION_ERROR +Output: +compiler/testData/multiplatform/classScopes/missingConstructor/common.kt:1:16: error: no definition is found for platform declaration 'Foo' +The following declaration is incompatible because some members are not implemented. +No implementations are found for members listed below: + + public constructor Foo(s: String) + + The following declaration is incompatible because number of value parameters is different: + public constructor Foo() + +platform class Foo { + ^ +compiler/testData/multiplatform/classScopes/missingConstructor/jvm.kt:1:1: error: modifier 'impl' is only applicable to members that are initially declared in platform-independent code +impl class Foo +^ + diff --git a/compiler/testData/multiplatform/classScopes/missingFunction/common.kt b/compiler/testData/multiplatform/classScopes/missingFunction/common.kt new file mode 100644 index 00000000000..f2d8816ecd2 --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/missingFunction/common.kt @@ -0,0 +1,3 @@ +platform class Foo { + fun function(s: String) +} diff --git a/compiler/testData/multiplatform/classScopes/missingFunction/jvm.kt b/compiler/testData/multiplatform/classScopes/missingFunction/jvm.kt new file mode 100644 index 00000000000..0a749a23b04 --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/missingFunction/jvm.kt @@ -0,0 +1 @@ +impl class Foo diff --git a/compiler/testData/multiplatform/classScopes/missingFunction/output.txt b/compiler/testData/multiplatform/classScopes/missingFunction/output.txt new file mode 100644 index 00000000000..62c0680d85f --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/missingFunction/output.txt @@ -0,0 +1,19 @@ +-- Common -- +Exit code: OK +Output: + +-- JVM -- +Exit code: COMPILATION_ERROR +Output: +compiler/testData/multiplatform/classScopes/missingFunction/common.kt:1:16: error: no definition is found for platform declaration 'Foo' +The following declaration is incompatible because some members are not implemented. +No implementations are found for members listed below: + + public final platform fun function(s: String): Unit + +platform class Foo { + ^ +compiler/testData/multiplatform/classScopes/missingFunction/jvm.kt:1:1: error: modifier 'impl' is only applicable to members that are initially declared in platform-independent code +impl class Foo +^ + diff --git a/compiler/testData/multiplatform/classScopes/simple/common.kt b/compiler/testData/multiplatform/classScopes/simple/common.kt new file mode 100644 index 00000000000..ff5d0be3e5d --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/simple/common.kt @@ -0,0 +1,5 @@ +platform class Foo(param: String) { + var property: Int + + fun function(p: List): T +} diff --git a/compiler/testData/multiplatform/classScopes/simple/jvm.kt b/compiler/testData/multiplatform/classScopes/simple/jvm.kt new file mode 100644 index 00000000000..2113636a60c --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/simple/jvm.kt @@ -0,0 +1,5 @@ +impl class Foo impl constructor(param: String) { + impl var property: Int = param.length + + impl fun function(p: List): T = p.first() +} diff --git a/compiler/testData/multiplatform/classScopes/simple/output.txt b/compiler/testData/multiplatform/classScopes/simple/output.txt new file mode 100644 index 00000000000..ce9e219309f --- /dev/null +++ b/compiler/testData/multiplatform/classScopes/simple/output.txt @@ -0,0 +1,8 @@ +-- Common -- +Exit code: OK +Output: + +-- JVM -- +Exit code: OK +Output: + diff --git a/compiler/testData/multiplatform/incorrectImplInClass/common.kt b/compiler/testData/multiplatform/incorrectImplInClass/common.kt new file mode 100644 index 00000000000..84d5a6e54da --- /dev/null +++ b/compiler/testData/multiplatform/incorrectImplInClass/common.kt @@ -0,0 +1 @@ +platform class Foo diff --git a/compiler/testData/multiplatform/incorrectImplInClass/jvm.kt b/compiler/testData/multiplatform/incorrectImplInClass/jvm.kt new file mode 100644 index 00000000000..229461d8624 --- /dev/null +++ b/compiler/testData/multiplatform/incorrectImplInClass/jvm.kt @@ -0,0 +1,10 @@ +impl class Foo impl constructor() { + impl constructor(s: String) : this() + + impl fun nonPlatformFun() {} + + impl val nonPlatformVal = "" + + private fun nonImplFun() {} + private val nonImplVal = "" +} diff --git a/compiler/testData/multiplatform/incorrectImplInClass/output.txt b/compiler/testData/multiplatform/incorrectImplInClass/output.txt new file mode 100644 index 00000000000..45dc765f6fb --- /dev/null +++ b/compiler/testData/multiplatform/incorrectImplInClass/output.txt @@ -0,0 +1,17 @@ +-- Common -- +Exit code: OK +Output: + +-- JVM -- +Exit code: COMPILATION_ERROR +Output: +compiler/testData/multiplatform/incorrectImplInClass/jvm.kt:2:5: error: modifier 'impl' is only applicable to members that are initially declared in platform-independent code + impl constructor(s: String) : this() + ^ +compiler/testData/multiplatform/incorrectImplInClass/jvm.kt:4:5: error: modifier 'impl' is only applicable to members that are initially declared in platform-independent code + impl fun nonPlatformFun() {} + ^ +compiler/testData/multiplatform/incorrectImplInClass/jvm.kt:6:5: error: modifier 'impl' is only applicable to members that are initially declared in platform-independent code + impl val nonPlatformVal = "" + ^ + diff --git a/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTestGenerated.java index f259e884f8e..dbcad671508 100644 --- a/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTestGenerated.java @@ -72,6 +72,12 @@ public class MultiPlatformIntegrationTestGenerated extends AbstractMultiPlatform doTest(fileName); } + @TestMetadata("incorrectImplInClass") + public void testIncorrectImplInClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/multiplatform/incorrectImplInClass/"); + doTest(fileName); + } + @TestMetadata("simple") public void testSimple() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/multiplatform/simple/");