From 65c21561a4402a9f722011436a34d705fca050f5 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 15 Jul 2014 18:11:26 +0400 Subject: [PATCH] Fix super constructor calls of anonymous objects and local classes If a class inherits from another class which captures something (outer class instance, receiver parameter, local variables, etc.), the constructor of the former class should contain all the parameters of the super constructor as its own parameters, so that it could make a proper super call. All such parameters are now replicated in the derived constructor with kind = SUPER_CALL_PARAM, except an instance of the outer class (kind = OUTER), which can be taken from the derived's own OUTER when it has one, to prevent multiple passing of the same argument. Previously it worked only when inheriting from inner classes via a special hack (ConstructorFrameMap). Also reuse recently introduced ArgumentGenerator to automatically take care of default and vararg arguments of super constructor #KT-3581 Fixed #KT-5342 Fixed #KT-5343 Fixed --- .../jet/codegen/ExpressionCodegen.java | 41 +++++- .../jet/codegen/FunctionCodegen.java | 2 +- .../codegen/ImplementationBodyCodegen.java | 139 ++++++++++++------ .../jet/codegen/state/JetTypeMapper.java | 49 +++++- .../jvmSignature/JvmMethodParameterKind.java | 2 +- .../deepInnerHierarchy.kt | 13 ++ .../deepLocalHierarchy.kt | 17 +++ .../superConstructorCall/innerExtendsOuter.kt | 14 ++ .../localExtendsLocalWithClosure.kt | 11 ++ ...localWithClosureExtendsLocalWithClosure.kt | 16 ++ .../objectExtendsClassDefaultArgument.kt | 9 ++ .../objectExtendsClassVararg.kt | 8 + .../objectExtendsInner.kt | 12 ++ .../objectExtendsInnerDefaultArgument.kt | 12 ++ ...jectExtendsInnerOfLocalVarargAndDefault.kt | 17 +++ .../objectExtendsInnerOfLocalWithCapture.kt | 15 ++ .../objectExtendsLocalCaptureInSuperCall.kt | 11 ++ .../objectExtendsLocalWithClosure.kt | 14 ++ .../BlackBoxCodegenTestGenerated.java | 76 +++++++++- 19 files changed, 417 insertions(+), 61 deletions(-) create mode 100644 compiler/testData/codegen/box/superConstructorCall/deepInnerHierarchy.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/deepLocalHierarchy.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/innerExtendsOuter.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/localExtendsLocalWithClosure.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/localWithClosureExtendsLocalWithClosure.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/objectExtendsClassDefaultArgument.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/objectExtendsClassVararg.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/objectExtendsInner.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerDefaultArgument.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerOfLocalVarargAndDefault.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/objectExtendsLocalCaptureInSuperCall.kt create mode 100644 compiler/testData/codegen/box/superConstructorCall/objectExtendsLocalWithClosure.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 71e39a3e737..72b187d39b2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1328,7 +1328,7 @@ public class ExpressionCodegen extends JetVisitor implem ConstructorDescriptor constructorDescriptor = bindingContext.get(CONSTRUCTOR, expression.getObjectDeclaration()); assert constructorDescriptor != null : "Unresolved constructor: " + expression.getText(); - CallableMethod constructor = typeMapper.mapToCallableMethod(constructorDescriptor); + JvmMethodSignature constructor = typeMapper.mapSignature(constructorDescriptor); Type type = typeMapper.mapType(constructorDescriptor.getContainingDeclaration()); @@ -1339,12 +1339,27 @@ public class ExpressionCodegen extends JetVisitor implem ResolvedCall superCall = closure.getSuperCall(); if (superCall != null) { + // For an anonymous object, we should also generate all non-default arguments that it captures for its super call ConstructorDescriptor superConstructor = superCall.getResultingDescriptor(); - List valueArguments = superCall.getValueArgumentsByIndex(); - assert valueArguments != null : "Failed to arrange value arguments by index: " + superConstructor; - ArgumentGenerator argumentGenerator = - new CallBasedArgumentGenerator(this, defaultCallGenerator, superConstructor.getValueParameters(), - typeMapper.mapToCallableMethod(superConstructor).getValueParameterTypes()); + List superValueParameters = superConstructor.getValueParameters(); + int params = superValueParameters.size(); + List superMappedTypes = typeMapper.mapToCallableMethod(superConstructor).getValueParameterTypes(); + assert superMappedTypes.size() >= params : String.format("Incorrect number of mapped parameters vs arguments: %d < %d for %s", + superMappedTypes.size(), params, constructorDescriptor); + + List valueArguments = new ArrayList(params); + List valueParameters = new ArrayList(params); + List mappedTypes = new ArrayList(params); + for (ValueParameterDescriptor parameter : superValueParameters) { + ResolvedValueArgument argument = superCall.getValueArguments().get(parameter); + if (!(argument instanceof DefaultValueArgument)) { + valueArguments.add(argument); + valueParameters.add(parameter); + mappedTypes.add(superMappedTypes.get(parameter.getIndex())); + } + } + ArgumentGenerator argumentGenerator = new CallBasedArgumentGenerator(this, defaultCallGenerator, valueParameters, mappedTypes); + argumentGenerator.generate(valueArguments); } @@ -1352,7 +1367,11 @@ public class ExpressionCodegen extends JetVisitor implem return StackValue.onStack(type); } - public void pushClosureOnStack(@Nullable CalculatedClosure closure, boolean ignoreThisAndReceiver, @NotNull CallGenerator callGenerator) { + public void pushClosureOnStack( + @Nullable CalculatedClosure closure, + boolean ignoreThisAndReceiver, + @NotNull CallGenerator callGenerator + ) { if (closure == null) return; int paramIndex = 0; @@ -1381,6 +1400,12 @@ public class ExpressionCodegen extends JetVisitor implem StackValue capturedVar = entry.getValue().getOuterValue(this); callGenerator.putCapturedValueOnStack(capturedVar, sharedVarType, paramIndex++); } + + ResolvedCall superCall = closure.getSuperCall(); + if (superCall != null) { + MutableClosure superClosure = bindingContext.get(CLOSURE, superCall.getResultingDescriptor().getContainingDeclaration()); + pushClosureOnStack(superClosure, ignoreThisAndReceiver, callGenerator); + } } private StackValue generateBlock(List statements, boolean lastStatementIsExpression) { @@ -2133,7 +2158,7 @@ public class ExpressionCodegen extends JetVisitor implem invokeMethodWithArguments(callableMethod, resolvedCall, receiver, callGenerator, argumentGenerator); } - private void invokeMethodWithArguments( + public void invokeMethodWithArguments( @NotNull CallableMethod callableMethod, @NotNull ResolvedCall resolvedCall, @NotNull StackValue receiver, diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 0f370098435..ad590649820 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -393,7 +393,7 @@ public class FunctionCodegen extends ParentCodegenAware { private static boolean needIndexForVar(JvmMethodParameterKind kind) { return kind == JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE || kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL || - kind == JvmMethodParameterKind.SUPER_OF_ANONYMOUS_CALL_PARAM; + kind == JvmMethodParameterKind.SUPER_CALL_PARAM; } public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 4dfde28cf1d..c074f56ee9b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -26,7 +26,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.backend.common.CodegenUtil; import org.jetbrains.jet.backend.common.DataClassMethodGenerator; -import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.binding.CodegenBinding; import org.jetbrains.jet.codegen.binding.MutableClosure; import org.jetbrains.jet.codegen.bridges.BridgesPackage; @@ -47,7 +46,10 @@ import org.jetbrains.jet.lang.resolve.DeclarationResolver; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage; import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil; +import org.jetbrains.jet.lang.resolve.calls.model.DefaultValueArgument; +import org.jetbrains.jet.lang.resolve.calls.model.ExpressionValueArgument; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.model.VarargValueArgument; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames; @@ -73,6 +75,7 @@ import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver; import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; +import static org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage.getResolvedCallWithAssert; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.DelegationToTraitImpl; @@ -1446,20 +1449,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { - if (specifier != superCall) { - if (specifier instanceof JetDelegatorByExpressionSpecifier) { - JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression(); - assert delegateExpression != null; - delegateExpression.accept(visitor); - } + if (specifier instanceof JetDelegatorByExpressionSpecifier) { + JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression(); + assert delegateExpression != null; + delegateExpression.accept(visitor); } - else { - if (superCall instanceof JetDelegatorToSuperCall) { - JetValueArgumentList argumentList = ((JetDelegatorToSuperCall) superCall).getValueArgumentList(); - if (argumentList != null) { - argumentList.accept(visitor); - } - } + } + + if (superCall instanceof JetDelegatorToSuperCall && !isAnonymousObject(descriptor)) { + JetValueArgumentList argumentList = ((JetDelegatorToSuperCall) superCall).getValueArgumentList(); + if (argumentList != null) { + argumentList.accept(visitor); } } } @@ -1550,51 +1550,96 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void generateDelegatorToConstructorCall( - InstructionAdapter iv, ExpressionCodegen codegen, - ConstructorDescriptor constructorDescriptor + @NotNull InstructionAdapter iv, + @NotNull ExpressionCodegen codegen, + @NotNull ConstructorDescriptor constructorDescriptor ) { - ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration(); - iv.load(0, OBJECT_TYPE); - if (classDecl.getKind() == ClassKind.ENUM_CLASS || classDecl.getKind() == ClassKind.ENUM_ENTRY) { - iv.load(1, OBJECT_TYPE); - iv.load(2, Type.INT_TYPE); - } - - ResolvedCall resolvedCall = BindingContextUtilPackage.getResolvedCallWithAssert(superCall, bindingContext); + ResolvedCall resolvedCall = getResolvedCallWithAssert(superCall, bindingContext); ConstructorDescriptor superConstructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor(); - //noinspection SuspiciousMethodCalls - CalculatedClosure closureForSuper = bindingContext.get(CLOSURE, superConstructor.getContainingDeclaration()); - if (closureForSuper != null && closureForSuper.getCaptureThis() != null) { - iv.load(((ConstructorFrameMap) codegen.myFrameMap).getOuterThisIndex(), OBJECT_TYPE); + CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor); + CallableMethod callable = typeMapper.mapToCallableMethod(constructorDescriptor); + + List superParameters = superCallable.getValueParameters(); + List parameters = callable.getValueParameters(); + + int offset = 1; + int superIndex = 0; + + // Here we match all the super constructor parameters except those with kind VALUE to the derived constructor parameters, push + // them all onto the stack and update "offset" variable so that in the end it points to the slot of the first VALUE argument + for (JvmMethodParameterSignature parameter : parameters) { + if (superIndex >= superParameters.size()) break; + + JvmMethodParameterKind kind = parameter.getKind(); + Type type = parameter.getAsmType(); + + // Stop when we reach the actual value parameters present in the code; they will be generated via ResolvedCall below + if (superParameters.get(superIndex).getKind() == JvmMethodParameterKind.VALUE && + kind == JvmMethodParameterKind.SUPER_CALL_PARAM) { + break; + } + + if (kind == JvmMethodParameterKind.SUPER_CALL_PARAM || kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL || + (kind == JvmMethodParameterKind.OUTER && superConstructor.getContainingDeclaration().isInner())) { + iv.load(offset, type); + superIndex++; + } + + offset += type.getSize(); } - CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor); - + ArgumentGenerator argumentGenerator; if (isAnonymousObject(descriptor) && superCall instanceof JetDelegatorToSuperCall) { - int nextVar = findFirstSuperArgument(typeMapper.mapToCallableMethod(constructorDescriptor)); - for (Type t : superCallable.getAsmMethod().getArgumentTypes()) { - iv.load(nextVar, t); - nextVar += t.getSize(); - } - superCallable.invokeWithNotNullAssertion(codegen.v, state, resolvedCall); + List superValues = superParameters.subList(superIndex, superParameters.size()); + argumentGenerator = new ObjectSuperCallArgumentGenerator(superValues, iv, offset); } else { - codegen.invokeMethodWithArguments(superCallable, resolvedCall, StackValue.none()); + argumentGenerator = + new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, superConstructor.getValueParameters(), + superCallable.getValueParameterTypes()); } + + codegen.invokeMethodWithArguments(superCallable, resolvedCall, StackValue.none(), codegen.defaultCallGenerator, argumentGenerator); } - private static int findFirstSuperArgument(@NotNull CallableMethod method) { - int i = 0; - for (JvmMethodParameterSignature type : method.getValueParameters()) { - if (type.getKind() == JvmMethodParameterKind.SUPER_OF_ANONYMOUS_CALL_PARAM) { - return i + 1; // because of this - } - i += type.getAsmType().getSize(); + private static class ObjectSuperCallArgumentGenerator extends ArgumentGenerator { + private final List parameters; + private final InstructionAdapter iv; + private int offset; + + public ObjectSuperCallArgumentGenerator( + @NotNull List superParameters, + @NotNull InstructionAdapter iv, + int firstValueParamOffset + ) { + this.parameters = superParameters; + this.iv = iv; + this.offset = firstValueParamOffset; + } + + @Override + public void generateExpression(int i, @NotNull ExpressionValueArgument argument) { + generateSuperCallArgument(i); + } + + @Override + public void generateDefault(int i, @NotNull DefaultValueArgument argument) { + pushDefaultValueOnStack(parameters.get(i).getAsmType(), iv); + } + + @Override + public void generateVararg(int i, @NotNull VarargValueArgument argument) { + generateSuperCallArgument(i); + } + + private void generateSuperCallArgument(int i) { + Type type = parameters.get(i).getAsmType(); + iv.load(offset, type); + offset += type.getSize(); } - return -1; } @Override @@ -1602,7 +1647,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { if (declaration instanceof JetEnumEntry) { String name = declaration.getName(); assert name != null : "Enum entry has no name: " + declaration.getText(); - String desc = "L" + classAsmType.getInternalName() + ";"; + String desc = classAsmType.getDescriptor(); ClassDescriptor entryDescriptor = bindingContext.get(BindingContext.CLASS, declaration); v.newField(OtherOrigin(declaration, entryDescriptor), ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL, name, desc, null, null); myEnumConstants.add((JetEnumEntry) declaration); @@ -1663,7 +1708,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { throw new UnsupportedOperationException("unsupported type of enum constant initializer: " + specifier); } - ResolvedCall resolvedCall = BindingContextUtilPackage.getResolvedCallWithAssert(specifier, bindingContext); + ResolvedCall resolvedCall = getResolvedCallWithAssert(specifier, bindingContext); CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) resolvedCall.getResultingDescriptor()); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java index 1b1b52da899..6d52e05603b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java @@ -34,7 +34,9 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.OverrideResolver; +import org.jetbrains.jet.lang.resolve.calls.model.DefaultValueArgument; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.StringValue; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; @@ -784,9 +786,50 @@ public class JetTypeMapper { } ResolvedCall superCall = closure.getSuperCall(); - if (superCall != null && isAnonymousObject(descriptor.getContainingDeclaration())) { - for (JvmMethodParameterSignature parameter : mapSignature(superCall.getResultingDescriptor()).getValueParameters()) { - writeParameter(sw, JvmMethodParameterKind.SUPER_OF_ANONYMOUS_CALL_PARAM, parameter.getAsmType()); + // We may generate a slightly wrong signature for a local class / anonymous object in light classes mode but we don't care, + // because such classes are not accessible from the outside world + if (superCall != null && classBuilderMode == ClassBuilderMode.FULL) { + writeSuperConstructorCallParameters(sw, descriptor, superCall, captureThis != null); + } + } + + private void writeSuperConstructorCallParameters( + @NotNull BothSignatureWriter sw, + @NotNull ConstructorDescriptor descriptor, + @NotNull ResolvedCall superCall, + boolean hasOuter + ) { + ConstructorDescriptor superDescriptor = superCall.getResultingDescriptor(); + List valueArguments = superCall.getValueArgumentsByIndex(); + assert valueArguments != null : "Failed to arrange value arguments by index: " + superDescriptor; + + List parameters = mapSignature(superDescriptor).getValueParameters(); + + int params = parameters.size(); + int args = valueArguments.size(); + + // Mapped parameters should consist of captured values plus all of valueArguments + assert params >= args : + String.format("Incorrect number of mapped parameters vs arguments: %d < %d for %s", params, args, descriptor); + + // Include all captured values, i.e. those parameters for which there are no resolved value arguments + for (int i = 0; i < params - args; i++) { + JvmMethodParameterSignature parameter = parameters.get(i); + JvmMethodParameterKind kind = parameter.getKind(); + if (kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL) continue; + if (hasOuter && kind == JvmMethodParameterKind.OUTER) continue; + + writeParameter(sw, JvmMethodParameterKind.SUPER_CALL_PARAM, parameter.getAsmType()); + } + + if (isAnonymousObject(descriptor.getContainingDeclaration())) { + // For anonymous objects, also add all real non-default value arguments passed to the super constructor + for (int i = 0; i < args; i++) { + ResolvedValueArgument valueArgument = valueArguments.get(i); + JvmMethodParameterSignature parameter = parameters.get(params - args + i); + if (!(valueArgument instanceof DefaultValueArgument)) { + writeParameter(sw, JvmMethodParameterKind.SUPER_CALL_PARAM, parameter.getAsmType()); + } } } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/jvmSignature/JvmMethodParameterKind.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/jvmSignature/JvmMethodParameterKind.java index 7e8408ab18f..530b9302109 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/jvmSignature/JvmMethodParameterKind.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/jvmSignature/JvmMethodParameterKind.java @@ -23,7 +23,7 @@ public enum JvmMethodParameterKind { RECEIVER, CAPTURED_LOCAL_VARIABLE, ENUM_NAME_OR_ORDINAL, - SUPER_OF_ANONYMOUS_CALL_PARAM; + SUPER_CALL_PARAM; public boolean isSkippedInGenericSignature() { return this == OUTER || this == ENUM_NAME_OR_ORDINAL; diff --git a/compiler/testData/codegen/box/superConstructorCall/deepInnerHierarchy.kt b/compiler/testData/codegen/box/superConstructorCall/deepInnerHierarchy.kt new file mode 100644 index 00000000000..08efa14a7ff --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/deepInnerHierarchy.kt @@ -0,0 +1,13 @@ +open class A(val s: String) { + open inner class B(s: String): A(s) + + open inner class C(s: String, additional: Double): B(s) + + open inner class D(other: Int, another: Long, s: String) : C(s, another.toDouble()) + + open inner class E : D(0, 42L, "OK") + + inner class F : E() +} + +fun box(): String = A("Fail").F().s diff --git a/compiler/testData/codegen/box/superConstructorCall/deepLocalHierarchy.kt b/compiler/testData/codegen/box/superConstructorCall/deepLocalHierarchy.kt new file mode 100644 index 00000000000..51a059cb0a3 --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/deepLocalHierarchy.kt @@ -0,0 +1,17 @@ +fun box(): String { + open trait L1 { + fun foo(): String + } + + open class L2(val s: String) : L1 { + override fun foo() = s + } + + open class L3(unused: Double, value: String = "OK") : L2(value) + + open class L4(i: Int, j: Long, z: Boolean, l: L3) : L3(3.14) + + class L5 : L4(0, 0L, false, L3(2.71, "Fail")) + + return L5().foo() +} diff --git a/compiler/testData/codegen/box/superConstructorCall/innerExtendsOuter.kt b/compiler/testData/codegen/box/superConstructorCall/innerExtendsOuter.kt new file mode 100644 index 00000000000..e90ccb30a21 --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/innerExtendsOuter.kt @@ -0,0 +1,14 @@ +// When inner class extends its outer, there are two instances of the outer present in the inner: +// the enclosing one and the one in the super call. +// Here we test that symbols are resolved to the instance created via the super call. +// This differs from Java, so this test may change when we revisit code generation of inner classes + +open class Outer(vararg val chars: Char) { + open inner class Inner(val s: String): Outer(s[0], s[1]) { + fun concat() = java.lang.String.valueOf(chars) + } + + fun value() = Inner("OK").concat() +} + +fun box() = Outer('F', 'a', 'i', 'l').value() diff --git a/compiler/testData/codegen/box/superConstructorCall/localExtendsLocalWithClosure.kt b/compiler/testData/codegen/box/superConstructorCall/localExtendsLocalWithClosure.kt new file mode 100644 index 00000000000..f24ed933d5c --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/localExtendsLocalWithClosure.kt @@ -0,0 +1,11 @@ +fun box(): String { + val result = "OK" + + open class Local(val ok: Boolean) { + fun result() = if (ok) result else "Fail" + } + + class Derived : Local(true) + + return Derived().result() +} diff --git a/compiler/testData/codegen/box/superConstructorCall/localWithClosureExtendsLocalWithClosure.kt b/compiler/testData/codegen/box/superConstructorCall/localWithClosureExtendsLocalWithClosure.kt new file mode 100644 index 00000000000..b2bb6dbd67a --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/localWithClosureExtendsLocalWithClosure.kt @@ -0,0 +1,16 @@ +fun box(): String { + val three = 3 + + open class Local(val one: Int) { + open fun value() = "$three$one" + } + + val four = 4 + + class Derived(val two: Int) : Local(1) { + override fun value() = super.value() + "$four$two" + } + + val result = Derived(2).value() + return if (result == "3142") "OK" else "Fail: $result" +} diff --git a/compiler/testData/codegen/box/superConstructorCall/objectExtendsClassDefaultArgument.kt b/compiler/testData/codegen/box/superConstructorCall/objectExtendsClassDefaultArgument.kt new file mode 100644 index 00000000000..298b0ec9162 --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/objectExtendsClassDefaultArgument.kt @@ -0,0 +1,9 @@ +// KT-3581 + +open class A(val result: String = "OK") { +} + +fun box(): String { + val a = object : A() {} + return a.result +} diff --git a/compiler/testData/codegen/box/superConstructorCall/objectExtendsClassVararg.kt b/compiler/testData/codegen/box/superConstructorCall/objectExtendsClassVararg.kt new file mode 100644 index 00000000000..b0bb4aed5d1 --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/objectExtendsClassVararg.kt @@ -0,0 +1,8 @@ +open class SomeClass(val some: Double, val other: Int, vararg val args: String) { + fun result() = args[1] +} + +fun box(): String { + return object : SomeClass(3.14, 42, "No", "OK", "Yes") { + }.result() +} diff --git a/compiler/testData/codegen/box/superConstructorCall/objectExtendsInner.kt b/compiler/testData/codegen/box/superConstructorCall/objectExtendsInner.kt new file mode 100644 index 00000000000..f02f1d4edc1 --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/objectExtendsInner.kt @@ -0,0 +1,12 @@ +class A { + open inner class Inner(val result: String) + + fun box(): String { + val o = object : Inner("OK") { + fun ok() = result + } + return o.ok() + } +} + +fun box() = A().box() diff --git a/compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerDefaultArgument.kt b/compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerDefaultArgument.kt new file mode 100644 index 00000000000..c94d6ab49ca --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerDefaultArgument.kt @@ -0,0 +1,12 @@ +class A { + open inner class Inner(val result: String = "OK", val int: Int) + + fun box(): String { + val o = object : Inner(int = 0) { + fun ok() = result + } + return o.ok() + } +} + +fun box() = A().box() diff --git a/compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerOfLocalVarargAndDefault.kt b/compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerOfLocalVarargAndDefault.kt new file mode 100644 index 00000000000..eef3131ae2b --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerOfLocalVarargAndDefault.kt @@ -0,0 +1,17 @@ +fun box(): String { + val capture = "oh" + + class Local { + val captured = capture + + open inner class Inner(val d: Double = -1.0, val s: String, vararg val y: Int) { + open fun result() = "Fail" + } + + val obj = object : Inner(s = "OK") { + override fun result() = s + } + } + + return Local().obj.result() +} diff --git a/compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt b/compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt new file mode 100644 index 00000000000..b4fb7a47cee --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt @@ -0,0 +1,15 @@ +fun box(): String { + class Local { + open inner class Inner(val s: String) { + open fun result() = "Fail" + } + + val realResult = "OK" + + val obj = object : Inner(realResult) { + override fun result() = s + } + } + + return Local().obj.result() +} diff --git a/compiler/testData/codegen/box/superConstructorCall/objectExtendsLocalCaptureInSuperCall.kt b/compiler/testData/codegen/box/superConstructorCall/objectExtendsLocalCaptureInSuperCall.kt new file mode 100644 index 00000000000..35bb545eb82 --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/objectExtendsLocalCaptureInSuperCall.kt @@ -0,0 +1,11 @@ +open class A(val s: String) + +fun box(): String { + class B { + val result = "OK" + + val f = object : A(result) {}.s + } + + return B().f +} diff --git a/compiler/testData/codegen/box/superConstructorCall/objectExtendsLocalWithClosure.kt b/compiler/testData/codegen/box/superConstructorCall/objectExtendsLocalWithClosure.kt new file mode 100644 index 00000000000..834b1e5d824 --- /dev/null +++ b/compiler/testData/codegen/box/superConstructorCall/objectExtendsLocalWithClosure.kt @@ -0,0 +1,14 @@ +fun box(): String { + val d = 42.0 + val c = 'C' + + open class Local(val l: Long) { + fun foo(): Boolean = d == 42.0 && c == 'C' && l == 239L + } + + if (object : Local(239L) { + fun bar(): Boolean = foo() + }.bar()) return "OK" + + return "Fail" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index a6864d1e91f..683c65b6b78 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.codegen.generated.AbstractBlackBoxCodegenTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("compiler/testData/codegen/box") -@InnerTestClasses({BlackBoxCodegenTestGenerated.Arrays.class, BlackBoxCodegenTestGenerated.BinaryOp.class, BlackBoxCodegenTestGenerated.Bridges.class, BlackBoxCodegenTestGenerated.BuiltinStubMethods.class, BlackBoxCodegenTestGenerated.Casts.class, BlackBoxCodegenTestGenerated.Classes.class, BlackBoxCodegenTestGenerated.Closures.class, BlackBoxCodegenTestGenerated.Constants.class, BlackBoxCodegenTestGenerated.ControlStructures.class, BlackBoxCodegenTestGenerated.DefaultArguments.class, BlackBoxCodegenTestGenerated.DelegatedProperty.class, BlackBoxCodegenTestGenerated.Elvis.class, BlackBoxCodegenTestGenerated.Enum.class, BlackBoxCodegenTestGenerated.ExclExcl.class, BlackBoxCodegenTestGenerated.ExtensionFunctions.class, BlackBoxCodegenTestGenerated.ExtensionProperties.class, BlackBoxCodegenTestGenerated.FakeOverride.class, BlackBoxCodegenTestGenerated.FieldRename.class, BlackBoxCodegenTestGenerated.Finally.class, BlackBoxCodegenTestGenerated.Functions.class, BlackBoxCodegenTestGenerated.InnerNested.class, BlackBoxCodegenTestGenerated.Instructions.class, BlackBoxCodegenTestGenerated.Intrinsics.class, BlackBoxCodegenTestGenerated.Labels.class, BlackBoxCodegenTestGenerated.LocalClasses.class, BlackBoxCodegenTestGenerated.MultiDecl.class, BlackBoxCodegenTestGenerated.Objects.class, BlackBoxCodegenTestGenerated.OperatorConventions.class, BlackBoxCodegenTestGenerated.Package.class, BlackBoxCodegenTestGenerated.PrimitiveTypes.class, BlackBoxCodegenTestGenerated.Properties.class, BlackBoxCodegenTestGenerated.Reflection.class, BlackBoxCodegenTestGenerated.Regressions.class, BlackBoxCodegenTestGenerated.SafeCall.class, BlackBoxCodegenTestGenerated.SamConstructors.class, BlackBoxCodegenTestGenerated.Strings.class, BlackBoxCodegenTestGenerated.Super.class, BlackBoxCodegenTestGenerated.ToArray.class, BlackBoxCodegenTestGenerated.Traits.class, BlackBoxCodegenTestGenerated.TypeInfo.class, BlackBoxCodegenTestGenerated.TypeMapping.class, BlackBoxCodegenTestGenerated.UnaryOp.class, BlackBoxCodegenTestGenerated.Unit.class, BlackBoxCodegenTestGenerated.Vararg.class, BlackBoxCodegenTestGenerated.When.class}) +@InnerTestClasses({BlackBoxCodegenTestGenerated.Arrays.class, BlackBoxCodegenTestGenerated.BinaryOp.class, BlackBoxCodegenTestGenerated.Bridges.class, BlackBoxCodegenTestGenerated.BuiltinStubMethods.class, BlackBoxCodegenTestGenerated.Casts.class, BlackBoxCodegenTestGenerated.Classes.class, BlackBoxCodegenTestGenerated.Closures.class, BlackBoxCodegenTestGenerated.Constants.class, BlackBoxCodegenTestGenerated.ControlStructures.class, BlackBoxCodegenTestGenerated.DefaultArguments.class, BlackBoxCodegenTestGenerated.DelegatedProperty.class, BlackBoxCodegenTestGenerated.Elvis.class, BlackBoxCodegenTestGenerated.Enum.class, BlackBoxCodegenTestGenerated.ExclExcl.class, BlackBoxCodegenTestGenerated.ExtensionFunctions.class, BlackBoxCodegenTestGenerated.ExtensionProperties.class, BlackBoxCodegenTestGenerated.FakeOverride.class, BlackBoxCodegenTestGenerated.FieldRename.class, BlackBoxCodegenTestGenerated.Finally.class, BlackBoxCodegenTestGenerated.Functions.class, BlackBoxCodegenTestGenerated.InnerNested.class, BlackBoxCodegenTestGenerated.Instructions.class, BlackBoxCodegenTestGenerated.Intrinsics.class, BlackBoxCodegenTestGenerated.Labels.class, BlackBoxCodegenTestGenerated.LocalClasses.class, BlackBoxCodegenTestGenerated.MultiDecl.class, BlackBoxCodegenTestGenerated.Objects.class, BlackBoxCodegenTestGenerated.OperatorConventions.class, BlackBoxCodegenTestGenerated.Package.class, BlackBoxCodegenTestGenerated.PrimitiveTypes.class, BlackBoxCodegenTestGenerated.Properties.class, BlackBoxCodegenTestGenerated.Reflection.class, BlackBoxCodegenTestGenerated.Regressions.class, BlackBoxCodegenTestGenerated.SafeCall.class, BlackBoxCodegenTestGenerated.SamConstructors.class, BlackBoxCodegenTestGenerated.Strings.class, BlackBoxCodegenTestGenerated.Super.class, BlackBoxCodegenTestGenerated.SuperConstructorCall.class, BlackBoxCodegenTestGenerated.ToArray.class, BlackBoxCodegenTestGenerated.Traits.class, BlackBoxCodegenTestGenerated.TypeInfo.class, BlackBoxCodegenTestGenerated.TypeMapping.class, BlackBoxCodegenTestGenerated.UnaryOp.class, BlackBoxCodegenTestGenerated.Unit.class, BlackBoxCodegenTestGenerated.Vararg.class, BlackBoxCodegenTestGenerated.When.class}) public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInBox() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/box"), Pattern.compile("^(.+)\\.kt$"), true); @@ -4826,6 +4826,79 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } + @TestMetadata("compiler/testData/codegen/box/superConstructorCall") + public static class SuperConstructorCall extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInSuperConstructorCall() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/box/superConstructorCall"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("deepInnerHierarchy.kt") + public void testDeepInnerHierarchy() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/deepInnerHierarchy.kt"); + } + + @TestMetadata("deepLocalHierarchy.kt") + public void testDeepLocalHierarchy() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/deepLocalHierarchy.kt"); + } + + @TestMetadata("innerExtendsOuter.kt") + public void testInnerExtendsOuter() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/innerExtendsOuter.kt"); + } + + @TestMetadata("localExtendsLocalWithClosure.kt") + public void testLocalExtendsLocalWithClosure() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/localExtendsLocalWithClosure.kt"); + } + + @TestMetadata("localWithClosureExtendsLocalWithClosure.kt") + public void testLocalWithClosureExtendsLocalWithClosure() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/localWithClosureExtendsLocalWithClosure.kt"); + } + + @TestMetadata("objectExtendsClassDefaultArgument.kt") + public void testObjectExtendsClassDefaultArgument() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/objectExtendsClassDefaultArgument.kt"); + } + + @TestMetadata("objectExtendsClassVararg.kt") + public void testObjectExtendsClassVararg() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/objectExtendsClassVararg.kt"); + } + + @TestMetadata("objectExtendsInner.kt") + public void testObjectExtendsInner() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/objectExtendsInner.kt"); + } + + @TestMetadata("objectExtendsInnerDefaultArgument.kt") + public void testObjectExtendsInnerDefaultArgument() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerDefaultArgument.kt"); + } + + @TestMetadata("objectExtendsInnerOfLocalVarargAndDefault.kt") + public void testObjectExtendsInnerOfLocalVarargAndDefault() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerOfLocalVarargAndDefault.kt"); + } + + @TestMetadata("objectExtendsInnerOfLocalWithCapture.kt") + public void testObjectExtendsInnerOfLocalWithCapture() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/objectExtendsInnerOfLocalWithCapture.kt"); + } + + @TestMetadata("objectExtendsLocalCaptureInSuperCall.kt") + public void testObjectExtendsLocalCaptureInSuperCall() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/objectExtendsLocalCaptureInSuperCall.kt"); + } + + @TestMetadata("objectExtendsLocalWithClosure.kt") + public void testObjectExtendsLocalWithClosure() throws Exception { + doTest("compiler/testData/codegen/box/superConstructorCall/objectExtendsLocalWithClosure.kt"); + } + + } + @TestMetadata("compiler/testData/codegen/box/toArray") public static class ToArray extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInToArray() throws Exception { @@ -5335,6 +5408,7 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { suite.addTestSuite(SamConstructors.class); suite.addTestSuite(Strings.class); suite.addTestSuite(Super.class); + suite.addTestSuite(SuperConstructorCall.class); suite.addTestSuite(ToArray.class); suite.addTest(Traits.innerSuite()); suite.addTestSuite(TypeInfo.class);