diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java index f643bba2892..f6adfc13620 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor; import org.jetbrains.kotlin.diagnostics.DiagnosticUtils; import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo; +import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus; import org.jetbrains.kotlin.psi.*; @@ -100,6 +101,8 @@ public class PackageCodegenImpl implements PackageCodegen { List classOrObjects = new ArrayList(); for (KtDeclaration declaration : file.getDeclarations()) { + if (declaration.hasModifier(KtTokens.PLATFORM_KEYWORD)) continue; + if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction || declaration instanceof KtTypeAlias) { generatePackagePart = true; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java index bfb7b65e731..2635c13509e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartCodegen.java @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor; import org.jetbrains.kotlin.descriptors.annotations.Annotated; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl; +import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; @@ -91,6 +92,8 @@ public class PackagePartCodegen extends MemberCodegen { @Override protected void generateBody() { for (KtDeclaration declaration : element.getDeclarations()) { + if (declaration.hasModifier(KtTokens.PLATFORM_KEYWORD)) continue; + if (declaration instanceof KtNamedFunction || declaration instanceof KtProperty || declaration instanceof KtTypeAlias) { genSimpleMember(declaration); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationResolver.kt index bff71caa8f5..1566b9c4302 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationResolver.kt @@ -20,11 +20,11 @@ import com.google.common.collect.HashMultimap import com.google.common.collect.Multimap import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors.REDECLARATION import org.jetbrains.kotlin.diagnostics.reportOnDeclaration -import org.jetbrains.kotlin.diagnostics.reportOnDeclarationOrFail import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.FqName @@ -78,14 +78,17 @@ class DeclarationResolver( for ((fqName, declarationsOrPackageDirectives) in topLevelFqNames.asMap()) { if (fqName.isRoot) continue - val descriptors = getTopLevelDescriptorsByFqName(topLevelDescriptorProvider, fqName, NoLookupLocation.WHEN_CHECK_REDECLARATIONS) + // TODO: report error on platform class and impl val, or vice versa + val (platform, impl) = + getTopLevelDescriptorsByFqName(topLevelDescriptorProvider, fqName, NoLookupLocation.WHEN_CHECK_REDECLARATIONS) + .partition { it is MemberDescriptor && it.isPlatform } - if (descriptors.size > 1) { - for (declarationOrPackageDirective in declarationsOrPackageDirectives) { - val reportAt = - if (declarationOrPackageDirective is KtPackageDirective) declarationOrPackageDirective.getNameIdentifier() - else declarationOrPackageDirective - trace.report(Errors.PACKAGE_OR_CLASSIFIER_REDECLARATION.on(reportAt!!, fqName.shortName().asString())) + for (descriptors in listOf(platform, impl)) { + if (descriptors.size > 1) { + for (directive in declarationsOrPackageDirectives) { + val reportAt = (directive as? KtPackageDirective)?.nameIdentifier ?: directive + trace.report(Errors.PACKAGE_OR_CLASSIFIER_REDECLARATION.on(reportAt, fqName.shortName().asString())) + } } } } diff --git a/compiler/testData/multiplatform/simple/common.kt b/compiler/testData/multiplatform/simple/common.kt new file mode 100644 index 00000000000..b79d7564b05 --- /dev/null +++ b/compiler/testData/multiplatform/simple/common.kt @@ -0,0 +1,8 @@ +platform class Printer { + fun print(message: String) +} + +fun main(args: Array) { + val printer = Printer() + printer.print("Hello, world!") +} diff --git a/compiler/testData/multiplatform/simple/js.kt b/compiler/testData/multiplatform/simple/js.kt new file mode 100644 index 00000000000..82382628b9b --- /dev/null +++ b/compiler/testData/multiplatform/simple/js.kt @@ -0,0 +1,5 @@ +impl class Printer { + fun print(message: String) { + println("JS says: " + message) + } +} diff --git a/compiler/testData/multiplatform/simple/jvm.kt b/compiler/testData/multiplatform/simple/jvm.kt new file mode 100644 index 00000000000..d219f769753 --- /dev/null +++ b/compiler/testData/multiplatform/simple/jvm.kt @@ -0,0 +1,5 @@ +impl class Printer { + fun print(message: String) { + println("JVM says: " + message) + } +} diff --git a/compiler/testData/multiplatform/simple/output.txt b/compiler/testData/multiplatform/simple/output.txt new file mode 100644 index 00000000000..ac1ad3921a5 --- /dev/null +++ b/compiler/testData/multiplatform/simple/output.txt @@ -0,0 +1,11 @@ +-- Common -- +Exit code: OK +Output: + +-- JVM -- +Exit code: OK +Output: + +-- JS -- +Exit code: OK +Output: diff --git a/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTest.kt b/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTest.kt new file mode 100644 index 00000000000..3c8e7dcb5a7 --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/multiplatform/MultiPlatformIntegrationTest.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.multiplatform + +import org.jetbrains.kotlin.cli.AbstractCliTest +import org.jetbrains.kotlin.cli.js.K2JSCompiler +import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler +import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase +import java.io.File + +class MultiPlatformIntegrationTest : KtUsefulTestCase() { + fun doTest(directoryPath: String) { + val root = File(KotlinTestUtils.getTestDataPathBase() + directoryPath) + val commonSrc = File(root, "common.kt") + val jsSrc = File(root, "js.kt") + val jvmSrc = File(root, "jvm.kt") + + val tmpdir = KotlinTestUtils.tmpDir(getTestName(true)) + + val commonDest = File(tmpdir, "common") + val jvmDest = File(tmpdir, "jvm") + val jsDest = File(File(tmpdir, "js"), "output.js") + + val result = buildString { + val (commonOutput, commonExitCode) = AbstractCliTest.executeCompilerGrabOutput(K2MetadataCompiler(), listOf( + commonSrc.absolutePath, "-d", commonDest.absolutePath + )) + appendln("-- Common --") + appendln("Exit code: $commonExitCode") + appendln("Output:") + appendln(commonOutput) + + val (jvmOutput, jvmExitCode) = AbstractCliTest.executeCompilerGrabOutput(K2JVMCompiler(), listOf( + jvmSrc.absolutePath, commonSrc.absolutePath, + "-d", jvmDest.absolutePath, + "-Xmulti-platform" + )) + appendln("-- JVM --") + appendln("Exit code: $jvmExitCode") + appendln("Output:") + appendln(jvmOutput) + + val (jsOutput, jsExitCode) = AbstractCliTest.executeCompilerGrabOutput(K2JSCompiler(), listOf( + jsSrc.absolutePath, commonSrc.absolutePath, + "-output", jsDest.absolutePath, + "-Xmulti-platform" + )) + appendln("-- JS --") + appendln("Exit code: $jsExitCode") + appendln("Output:") + append(jsOutput) + } + + KotlinTestUtils.assertEqualsToFile(File(root, "output.txt"), result) + } + + fun testSimple() { + doTest("/multiplatform/simple/") + } +} diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt index 2343a1f215d..00d38b3b4b2 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt @@ -55,7 +55,7 @@ class JsNameClashChecker : SimpleDeclarationChecker { val scope = getScope(suggested.scope) val name = suggested.names.last() val existing = scope[name] - if (existing != null && existing != suggested.descriptor) { + if (existing != null && existing != suggested.descriptor && !(existing is MemberDescriptor && existing.isPlatform)) { diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH.on(declaration, name, existing)) val existingDeclaration = existing.findPsi() if (clashedDescriptors.add(existing) && existingDeclaration is KtDeclaration && existingDeclaration != declaration) { diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/translate/utils/AnnotationsUtils.java b/js/js.frontend/src/org/jetbrains/kotlin/js/translate/utils/AnnotationsUtils.java index 76bd54befe5..cea133e8524 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/translate/utils/AnnotationsUtils.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/translate/utils/AnnotationsUtils.java @@ -18,10 +18,7 @@ package org.jetbrains.kotlin.js.translate.utils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.descriptors.ClassDescriptor; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor; -import org.jetbrains.kotlin.descriptors.PropertyDescriptor; +import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget; import org.jetbrains.kotlin.descriptors.annotations.Annotations; @@ -140,11 +137,14 @@ public final class AnnotationsUtils { } public static boolean isPredefinedObject(@NotNull DeclarationDescriptor descriptor) { + if (descriptor instanceof MemberDescriptor && ((MemberDescriptor) descriptor).isPlatform()) return true; + for (PredefinedAnnotation annotation : PredefinedAnnotation.values()) { if (hasAnnotationOrInsideAnnotatedClass(descriptor, annotation)) { return true; } } + return false; }