diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt index a5a04e94ee6..f0244a83773 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.types.DynamicTypesAllowed object JsPlatformConfigurator : PlatformConfigurator( DynamicTypesAllowed(), - additionalDeclarationCheckers = listOf(NativeInvokeChecker(), NativeGetterChecker(), NativeSetterChecker(), ClassDeclarationChecker()), + additionalDeclarationCheckers = listOf(NativeInvokeChecker(), NativeGetterChecker(), NativeSetterChecker()), additionalCallCheckers = listOf(), additionalTypeCheckers = listOf(), additionalSymbolUsageValidators = listOf(), diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/unsupportedFeatureCheckers.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/unsupportedFeatureCheckers.kt deleted file mode 100644 index 0185d5b6b6f..00000000000 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/unsupportedFeatureCheckers.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010-2015 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.js.resolve - -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility -import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.diagnostics.DiagnosticSink -import org.jetbrains.kotlin.diagnostics.rendering.renderKind -import org.jetbrains.kotlin.diagnostics.rendering.renderKindWithName -import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs -import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.DeclarationChecker -import org.jetbrains.kotlin.resolve.DescriptorUtils - -class ClassDeclarationChecker : DeclarationChecker { - override fun check( - declaration: KtDeclaration, - descriptor: DeclarationDescriptor, - diagnosticHolder: DiagnosticSink, - bindingContext: BindingContext - ) { - if (declaration !is KtClassOrObject || declaration is KtObjectDeclaration || declaration is KtEnumEntry) return - - // hack to avoid to get diagnostics when compile kotlin builtins - val fqNameUnsafe = DescriptorUtils.getFqName(descriptor) - if (fqNameUnsafe.asString().startsWith("kotlin.")) return - - if (!DescriptorUtils.isTopLevelDeclaration(descriptor) && !AnnotationsUtils.isNativeObject(descriptor)) { - diagnosticHolder.report(ErrorsJs.NON_TOPLEVEL_CLASS_DECLARATION.on(declaration, (descriptor as ClassDescriptor).renderKind())) - } - } -} diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java new file mode 100644 index 00000000000..278f65a6adf --- /dev/null +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java @@ -0,0 +1,33 @@ +/* + * 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.js.test.semantics; + +import org.jetbrains.kotlin.js.test.SingleFileTranslationTest; + +public class NestedTypesTest extends SingleFileTranslationTest { + public NestedTypesTest() { + super("nestedTypes/"); + } + + public void testNested() throws Exception { + checkFooBoxIsOk(); + } + + public void testInner() throws Exception { + checkFooBoxIsOk(); + } +} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt index ba4b41a2cf7..209eefc5a6a 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.js.PredefinedAnnotation import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.js.translate.general.Translation import org.jetbrains.kotlin.js.translate.operation.OperatorTable import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils @@ -32,6 +33,7 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.util.OperatorNameConventions import java.util.ArrayList @@ -209,13 +211,35 @@ object ConstructorCallCase : FunctionCallCase() { val functionRef = if (isNative()) fqName else context.aliasOrValue(callableDescriptor) { fqName } val constructorDescriptor = callableDescriptor as ConstructorDescriptor - if(constructorDescriptor.isPrimary || AnnotationsUtils.isNativeObject(constructorDescriptor)) { + if (constructorDescriptor.isPrimary || AnnotationsUtils.isNativeObject(constructorDescriptor)) { return JsNew(functionRef, argumentsInfo.translateArguments) } else { return JsInvocation(functionRef, argumentsInfo.translateArguments) } } + + override fun FunctionCallInfo.dispatchReceiver(): JsExpression { + val fqName = context.getQualifiedReference(callableDescriptor) + val functionRef = context.aliasOrValue(callableDescriptor) { fqName } + + val constructorDescriptor = callableDescriptor as ConstructorDescriptor + val receiver = this.resolvedCall.dispatchReceiver + var allArguments = when (receiver) { + is ExpressionReceiver -> { + val jsReceiver = Translation.translateAsExpression(receiver.expression, context) + (sequenceOf(jsReceiver) + argumentsInfo.translateArguments).toList() + } + else -> argumentsInfo.translateArguments + } + + if (constructorDescriptor.isPrimary || AnnotationsUtils.isNativeObject(constructorDescriptor)) { + return JsNew(functionRef, allArguments) + } + else { + return JsInvocation(functionRef, allArguments) + } + } } object SuperCallCase : FunctionCallCase() { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java index 0190dea9e8f..71a22e1a1ae 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java @@ -541,6 +541,27 @@ public final class StaticContext { return null; } }; + Rule nestedClassesHaveContainerQualifier = new Rule() { + @Nullable + @Override + public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { + if (isNativeObject(descriptor) || isBuiltin(descriptor)) { + return null; + } + if (!(descriptor instanceof ClassDescriptor)) { + return null; + } + ClassDescriptor cls = (ClassDescriptor) descriptor; + if (cls.getKind() == ClassKind.ENUM_ENTRY || cls.getKind() == ClassKind.OBJECT) { + return null; + } + DeclarationDescriptor container = descriptor.getContainingDeclaration(); + if (container == null) { + return null; + } + return getQualifiedReference(container); + } + }; addRule(libraryObjectsHaveKotlinQualifier); addRule(constructorOrCompanionObjectHasTheSameQualifierAsTheClass); @@ -548,6 +569,7 @@ public final class StaticContext { addRule(packageLevelDeclarationsHaveEnclosingPackagesNamesAsQualifier); addRule(nativeObjectsHaveNativePartOfFullQualifier); addRule(staticMembersHaveContainerQualifier); + addRule(nestedClassesHaveContainerQualifier); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index 1c461208e66..3b9dc1a9c9d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -21,10 +21,7 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.ReflectionTypes; -import org.jetbrains.kotlin.descriptors.CallableDescriptor; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.MemberDescriptor; -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor; +import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.js.config.Config; import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics; import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; @@ -32,6 +29,7 @@ import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingTrace; +import org.jetbrains.kotlin.resolve.DescriptorUtils; import java.util.HashMap; import java.util.Map; @@ -55,12 +53,16 @@ public class TranslationContext { private final TranslationContext parent; @Nullable private final DefinitionPlace definitionPlace; + @Nullable + private final DeclarationDescriptor declarationDescriptor; + @Nullable + private final ClassDescriptor classDescriptor; @NotNull public static TranslationContext rootContext(@NotNull StaticContext staticContext, JsFunction rootFunction) { DynamicContext rootDynamicContext = DynamicContext.rootContext(rootFunction.getScope(), rootFunction.getBody()); AliasingContext rootAliasingContext = AliasingContext.getCleanContext(); - return new TranslationContext(null, staticContext, rootDynamicContext, rootAliasingContext, null, null); + return new TranslationContext(null, staticContext, rootDynamicContext, rootAliasingContext, null, null, null); } private final Map expressionToTempConstVariableCache = new HashMap(); @@ -71,7 +73,8 @@ public class TranslationContext { @NotNull DynamicContext dynamicContext, @NotNull AliasingContext aliasingContext, @Nullable UsageTracker usageTracker, - @Nullable DefinitionPlace definitionPlace + @Nullable DefinitionPlace definitionPlace, + @Nullable DeclarationDescriptor declarationDescriptor ) { this.parent = parent; this.dynamicContext = dynamicContext; @@ -79,6 +82,14 @@ public class TranslationContext { this.aliasingContext = aliasingContext; this.usageTracker = usageTracker; this.definitionPlace = definitionPlace; + this.declarationDescriptor = declarationDescriptor; + if (declarationDescriptor instanceof ClassDescriptor + && !DescriptorUtils.isAnonymousObject(declarationDescriptor) + && !DescriptorUtils.isObject(declarationDescriptor)) { + this.classDescriptor = (ClassDescriptor) declarationDescriptor; + } else { + this.classDescriptor = parent != null ? parent.classDescriptor : null; + } } @Nullable @@ -103,19 +114,22 @@ public class TranslationContext { aliasingContext = this.aliasingContext.inner(); } - return new TranslationContext(this, this.staticContext, dynamicContext, aliasingContext, this.usageTracker, null); + return new TranslationContext(this, this.staticContext, dynamicContext, aliasingContext, this.usageTracker, null, + this.declarationDescriptor); } @NotNull public TranslationContext newFunctionBodyWithUsageTracker(@NotNull JsFunction fun, @NotNull MemberDescriptor descriptor) { DynamicContext dynamicContext = DynamicContext.newContext(fun.getScope(), fun.getBody()); UsageTracker usageTracker = new UsageTracker(this.usageTracker, descriptor, fun.getScope()); - return new TranslationContext(this, this.staticContext, dynamicContext, this.aliasingContext.inner(), usageTracker, this.definitionPlace); + return new TranslationContext(this, this.staticContext, dynamicContext, this.aliasingContext.inner(), usageTracker, this.definitionPlace, + this.declarationDescriptor); } @NotNull public TranslationContext innerBlock(@NotNull JsBlock block) { - return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker, null); + return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker, null, + this.declarationDescriptor); } @NotNull @@ -126,12 +140,14 @@ public class TranslationContext { @NotNull public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor, @Nullable DefinitionPlace place) { DynamicContext dynamicContext = DynamicContext.newContext(getScopeForDescriptor(descriptor), getBlockForDescriptor(descriptor)); - return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, place); + return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, place, + descriptor); } @NotNull private TranslationContext innerWithAliasingContext(AliasingContext aliasingContext) { - return new TranslationContext(this, this.staticContext, this.dynamicContext, aliasingContext, this.usageTracker, null); + return new TranslationContext(this, this.staticContext, this.dynamicContext, aliasingContext, this.usageTracker, null, + this.declarationDescriptor); } @NotNull @@ -319,7 +335,29 @@ public class TranslationContext { @NotNull public JsExpression getDispatchReceiver(@NotNull ReceiverParameterDescriptor descriptor) { JsExpression alias = getAliasForDescriptor(descriptor); - return alias == null ? JsLiteral.THIS : alias; + if (alias != null) { + return alias; + } + return getDispatchReceiverPath(getNearestClass(descriptor)); + } + + @NotNull + private JsExpression getDispatchReceiverPath(@Nullable ClassDescriptor cls) { + if (cls != null) { + JsExpression alias = getAliasForDescriptor(cls); + if (alias != null) { + return alias; + } + } + if (cls == classDescriptor || parent == null) { + return JsLiteral.THIS; + } + ClassDescriptor parentDescriptor = parent.classDescriptor; + if (classDescriptor != parentDescriptor) { + return new JsNameRef("$outer", parent.getDispatchReceiverPath(cls)); + } else { + return parent.getDispatchReceiverPath(cls); + } } @NotNull @@ -347,4 +385,17 @@ public class TranslationContext { return null; } + + private static ClassDescriptor getNearestClass(DeclarationDescriptor declaration) { + while (declaration != null) { + if (declaration instanceof ClassDescriptor) { + if (!DescriptorUtils.isAnonymousObject(declaration) + && !DescriptorUtils.isObject(declaration)) { + return (ClassDescriptor) declaration; + } + } + declaration = declaration.getContainingDeclaration(); + } + return null; + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java index 2280cde4ac6..02cff3705cf 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java @@ -67,7 +67,8 @@ public class DeclarationBodyVisitor extends TranslatorVisitor { } @Override - public Void visitClass(@NotNull KtClass expression, TranslationContext context) { + public Void visitClass(@NotNull KtClass declaration, TranslationContext context) { + staticResult.addAll(ClassTranslator.Companion.translate(declaration, context)); return null; } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/FileDeclaration.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/FileDeclaration.kt index 67fb9800812..9d313936e61 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/FileDeclaration.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/FileDeclaration.kt @@ -50,8 +50,8 @@ class FileDeclarationVisitor( } } - override fun visitClass(expression: KtClass, context: TranslationContext?): Void? { - result.addAll(ClassTranslator.translate(expression, context!!)) + override fun visitClass(declaration: KtClass, context: TranslationContext?): Void? { + result.addAll(ClassTranslator.translate(declaration, context!!)) return null } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java index df9c13ef6a2..580e38a836d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java @@ -84,6 +84,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator { @NotNull public JsFunction generateInitializeMethod(DelegationTranslator delegationTranslator) { ClassDescriptor classDescriptor = getClassDescriptor(bindingContext(), classDeclaration); + addOuterClassReference(classDescriptor); ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); if (primaryConstructor != null) { @@ -113,6 +114,22 @@ public final class ClassInitializerTranslator extends AbstractTranslator { return initFunction; } + private void addOuterClassReference(ClassDescriptor classDescriptor) { + DeclarationDescriptor container = classDescriptor.getContainingDeclaration(); + if (!(container instanceof ClassDescriptor) || !classDescriptor.isInner()) { + return; + } + + // TODO: avoid name clashing + JsName outerName = initFunction.getScope().declareName("$outer"); + initFunction.getParameters().add(0, new JsParameter(outerName)); + + JsExpression target = new JsNameRef(outerName, JsLiteral.THIS); + JsExpression paramRef = new JsNameRef(outerName); + JsExpression assignment = new JsBinaryOperation(JsBinaryOperator.ASG, target, paramRef); + initFunction.getBody().getStatements().add(new JsExpressionStatement(assignment)); + } + @NotNull public JsExpression generateEnumEntryInstanceCreation(@NotNull KotlinType enumClassType) { ResolvedCall superCall = getSuperCall(); diff --git a/js/js.translator/testData/kotlin_lib_ecma5.js b/js/js.translator/testData/kotlin_lib_ecma5.js index fd799ac5cd8..ce75f44f051 100644 --- a/js/js.translator/testData/kotlin_lib_ecma5.js +++ b/js/js.translator/testData/kotlin_lib_ecma5.js @@ -91,19 +91,22 @@ var Kotlin = {}; } } - function computeMetadata(bases, properties) { + function computeMetadata(bases, properties, staticProperties) { var metadata = {}; + var p, property; metadata.baseClasses = toArray(bases); metadata.baseClass = getClass(metadata.baseClasses); metadata.classIndex = Kotlin.newClassIndex(); metadata.functions = {}; metadata.properties = {}; + metadata.types = {}; + metadata.staticMembers = {}; if (!(properties == null)) { - for (var p in properties) { + for (p in properties) { if (properties.hasOwnProperty(p)) { - var property = properties[p]; + property = properties[p]; property.$classIndex$ = metadata.classIndex; if (typeof property === "function") { metadata.functions[p] = property; @@ -114,6 +117,19 @@ var Kotlin = {}; } } } + if (typeof staticProperties !== 'undefined') { + for (p in staticProperties) { + if (!staticProperties.hasOwnProperty(p)) { + continue; + } + property = staticProperties[p]; + if (typeof property === "function" && typeof property.type !== "undefined" && property.type === Kotlin.TYPE.INIT_FUN) { + metadata.types[p] = property; + } else { + metadata.staticMembers[p] = property; + } + } + } applyExtension(metadata.functions, metadata.baseClasses, function (it) { return it.$metadata$.functions }); @@ -146,10 +162,10 @@ var Kotlin = {}; if (constructor == null) { constructor = emptyFunction(); } - copyProperties(constructor, staticProperties); - var metadata = computeMetadata(bases, properties); + var metadata = computeMetadata(bases, properties, staticProperties); metadata.type = Kotlin.TYPE.CLASS; + copyProperties(constructor, metadata.staticMembers); var prototypeObj; if (metadata.baseClass !== null) { @@ -161,6 +177,14 @@ var Kotlin = {}; Object.defineProperties(prototypeObj, metadata.properties); copyProperties(prototypeObj, metadata.functions); prototypeObj.constructor = constructor; + for (var innerType in metadata.types) { + if (metadata.types.hasOwnProperty(innerType)) { + Object.defineProperty(constructor, innerType, { + get: metadata.types[innerType], + configurable: true + }); + } + } if (metadata.baseClass != null) { constructor.baseInitializer = metadata.baseClass; @@ -181,15 +205,25 @@ var Kotlin = {}; Kotlin.createTraitNow = function (bases, properties, staticProperties) { var obj = function () {}; - copyProperties(obj, staticProperties); - obj.$metadata$ = computeMetadata(bases, properties); + obj.$metadata$ = computeMetadata(bases, properties, staticProperties); obj.$metadata$.type = Kotlin.TYPE.TRAIT; + copyProperties(obj, obj.$metadata$.staticMembers); obj.prototype = {}; Object.defineProperties(obj.prototype, obj.$metadata$.properties); copyProperties(obj.prototype, obj.$metadata$.functions); Object.defineProperty(obj, "object", {get: class_object, configurable: true}); + + for (var innerType in obj.$metadata$.types) { + if (obj.$metadata$.types.hasOwnProperty(innerType)) { + Object.defineProperty(constructor, innerType, { + get: obj.$metadata$.types[innerType], + configurable: true + }); + } + } + return obj; }; diff --git a/js/js.translator/testData/nestedTypes/cases/inner.kt b/js/js.translator/testData/nestedTypes/cases/inner.kt new file mode 100644 index 00000000000..f6b40471caf --- /dev/null +++ b/js/js.translator/testData/nestedTypes/cases/inner.kt @@ -0,0 +1,14 @@ +package foo + +open class A(val x: Int, val y: Int) { + inner class B(val z: Int) { + fun foo() = x + y + z + } +} + +fun box(): String { + val a = A(2, 3) + val b = a.B(4) + return if (b.foo() == 9) "OK" else "failure" +} + diff --git a/js/js.translator/testData/nestedTypes/cases/nested.kt b/js/js.translator/testData/nestedTypes/cases/nested.kt new file mode 100644 index 00000000000..62c75ccbb13 --- /dev/null +++ b/js/js.translator/testData/nestedTypes/cases/nested.kt @@ -0,0 +1,10 @@ +package foo + +open class A(val x: Int) { + class B : A(5) +} + +fun box(): String { + return if (A(7).x + A.B().x == 12) "OK" else "failed" +} +