[KT-4124] Add support for simple nested classes
This commit is contained in:
@@ -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(),
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
+25
-1
@@ -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() {
|
||||
|
||||
@@ -541,6 +541,27 @@ public final class StaticContext {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Rule<JsExpression> nestedClassesHaveContainerQualifier = new Rule<JsExpression>() {
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+63
-12
@@ -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<JsExpression, TemporaryConstVariable> expressionToTempConstVariableCache = new HashMap<JsExpression, TemporaryConstVariable>();
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -67,7 +67,8 @@ public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+17
@@ -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<FunctionDescriptor> superCall = getSuperCall();
|
||||
|
||||
+41
-7
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user