diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java index e460c94f3d1..aa4a32e9156 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java @@ -39,10 +39,7 @@ import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.BindingContextUtils; -import org.jetbrains.kotlin.resolve.BindingTrace; -import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils; +import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.calls.model.*; import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; @@ -80,7 +77,7 @@ public class JetControlFlowProcessor { private Pseudocode generate(@NotNull JetElement subroutine) { builder.enterSubroutine(subroutine); CFPVisitor cfpVisitor = new CFPVisitor(builder); - if (subroutine instanceof JetDeclarationWithBody) { + if (subroutine instanceof JetDeclarationWithBody && !(subroutine instanceof JetSecondaryConstructor)) { JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) subroutine; List valueParameters = declarationWithBody.getValueParameters(); for (JetParameter valueParameter : valueParameters) { @@ -1358,7 +1355,9 @@ public class JetControlFlowProcessor { @Override public void visitObjectDeclaration(@NotNull JetObjectDeclaration objectDeclaration) { - visitClassOrObject(objectDeclaration); + generateHeaderDelegationSpecifiers(objectDeclaration); + generateClassOrObjectInitializers(objectDeclaration); + generateDeclarationForLocalClassOrObjectIfNeeded(objectDeclaration); } @Override @@ -1386,19 +1385,14 @@ public class JetControlFlowProcessor { generateInstructions(classInitializer.getBody()); } - private void visitClassOrObject(JetClassOrObject classOrObject) { + private void generateHeaderDelegationSpecifiers(@NotNull JetClassOrObject classOrObject) { for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) { generateInstructions(specifier); } - List declarations = classOrObject.getDeclarations(); - if (classOrObject.isLocal()) { - for (JetDeclaration declaration : declarations) { - generateInstructions(declaration); - } - return; - } - //For top-level and inner classes and objects functions are collected and checked separately. - for (JetDeclaration declaration : declarations) { + } + + private void generateClassOrObjectInitializers(@NotNull JetClassOrObject classOrObject) { + for (JetDeclaration declaration : classOrObject.getDeclarations()) { if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) { generateInstructions(declaration); } @@ -1407,15 +1401,61 @@ public class JetControlFlowProcessor { @Override public void visitClass(@NotNull JetClass klass) { - List parameters = klass.getPrimaryConstructorParameters(); + if (klass.hasPrimaryConstructor()) { + processParameters(klass.getPrimaryConstructorParameters()); + + // delegation specifiers of primary constructor, anonymous class and property initializers + generateHeaderDelegationSpecifiers(klass); + generateClassOrObjectInitializers(klass); + } + + generateDeclarationForLocalClassOrObjectIfNeeded(klass); + } + + private void generateDeclarationForLocalClassOrObjectIfNeeded(@NotNull JetClassOrObject classOrObject) { + if (classOrObject.isLocal()) { + for (JetDeclaration declaration : classOrObject.getDeclarations()) { + if (declaration instanceof JetSecondaryConstructor || + declaration instanceof JetProperty || + declaration instanceof JetClassInitializer) { + continue; + } + generateInstructions(declaration); + } + } + } + + private void processParameters(@NotNull List parameters) { for (JetParameter parameter : parameters) { generateInstructions(parameter); } - visitClassOrObject(klass); + } + + @Override + public void visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor) { + JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(constructor, JetClassOrObject.class); + assert classOrObject != null : "Guaranteed by parsing contract"; + + processParameters(constructor.getValueParameters()); + generateCallOrMarkUnresolved(constructor.getDelegationCall()); + + if (constructor.getDelegationCall() != null && + constructor.getDelegationCall().getCalleeExpression() != null && + !constructor.getDelegationCall().getCalleeExpression().isThis() + ) { + generateClassOrObjectInitializers(classOrObject); + } + + generateInstructions(constructor.getBodyExpression()); } @Override public void visitDelegationToSuperCallSpecifier(@NotNull JetDelegatorToSuperCall call) { + generateCallOrMarkUnresolved(call); + } + + private void generateCallOrMarkUnresolved(@Nullable JetCallElement call) { + if (call == null) return; if (!generateCall(call)) { List arguments = KotlinPackage.map( call.getValueArguments(), diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java index 53543cda1b1..b9a1d8dc753 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java @@ -577,8 +577,8 @@ public class JetFlowInformationProvider { for (VariableDescriptor variable : declaredVariables) { if (variable instanceof PropertyDescriptor) { PseudocodeVariablesData.VariableInitState variableInitState = initializers.getIncoming().get(variable); - if (variableInitState == null) return; - trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, variableInitState.isInitialized); + if (variableInitState != null && variableInitState.isInitialized) continue; + trace.record(BindingContext.IS_UNINITIALIZED, (PropertyDescriptor) variable); } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetConstructorDelegationCall.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetConstructorDelegationCall.java index ead090e3274..dc4d1873e1d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetConstructorDelegationCall.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetConstructorDelegationCall.java @@ -70,7 +70,7 @@ public class JetConstructorDelegationCall extends JetElementImplStub"; + } + @Nullable @Override public JetTypeParameterList getTypeParameterList() { @@ -139,7 +145,7 @@ public class JetSecondaryConstructor extends JetDeclarationStub"); + return Name.special(getName()); } @Nullable diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index f91d60fb6de..f5481733e79 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -185,7 +185,7 @@ public interface BindingContext { return backingFieldRequired; } }; - WritableSlice IS_INITIALIZED = Slices.createSimpleSetSlice(); + WritableSlice IS_UNINITIALIZED = Slices.createSimpleSetSlice(); WritableSlice BLOCK = new Slices.SetSlice(DO_NOTHING) { @Override diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ControlFlowAnalyzer.java index 3a0a37c4f70..a3fdc05ab2a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ControlFlowAnalyzer.java @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.cfg.JetFlowInformationProvider; import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor; import org.jetbrains.kotlin.descriptors.PropertyDescriptor; @@ -45,6 +46,9 @@ public class ControlFlowAnalyzer { for (JetClassOrObject aClass : c.getDeclaredClasses().keySet()) { checkDeclarationContainer(c, aClass); } + for (JetSecondaryConstructor constructor : c.getSecondaryConstructors().keySet()) { + checkSecondaryConstructor(constructor); + } for (Map.Entry entry : c.getFunctions().entrySet()) { JetNamedFunction function = entry.getKey(); SimpleFunctionDescriptor functionDescriptor = entry.getValue(); @@ -60,6 +64,12 @@ public class ControlFlowAnalyzer { } } + private void checkSecondaryConstructor(@NotNull JetSecondaryConstructor constructor) { + JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider(constructor, trace); + flowInformationProvider.checkDeclaration(); + flowInformationProvider.checkFunction(KotlinBuiltIns.getInstance().getUnitType()); + } + private void checkDeclarationContainer(@NotNull BodiesResolveContext c, JetDeclarationContainer declarationContainer) { // A pseudocode of class/object initialization corresponds to a class/object // or initialization of properties corresponds to a package declared in a file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java index 47440bd99a8..36b56d992fb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java @@ -456,7 +456,7 @@ public class DeclarationsChecker { if (initializer == null && delegate == null) { boolean error = false; if (backingFieldRequired && !inTrait && - Boolean.FALSE.equals(trace.getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor))) { + Boolean.TRUE.equals(trace.getBindingContext().get(BindingContext.IS_UNINITIALIZED, propertyDescriptor))) { if (!(containingDeclaration instanceof ClassDescriptor) || hasAccessorImplementation) { error = true; trace.report(MUST_BE_INITIALIZED.on(property)); diff --git a/compiler/testData/cfg/secondaryConstructors/withPrimary.instructions b/compiler/testData/cfg/secondaryConstructors/withPrimary.instructions new file mode 100644 index 00000000000..653b7357fe3 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withPrimary.instructions @@ -0,0 +1,115 @@ +== A == +class A(val w: Char) { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor(): this('a') { + y = 2 + } + + // anonymous + init { + x = w + z = 8 + } + + constructor(a: Int, b: Int = 3): this(b.toChar()) { + y = x + } + + // anonymous + init { + y = 9 + } +} +--------------------- +L0: + 1 + v(val w: Char) + magic[FAKE_INITIALIZER](val w: Char) -> + w(w|) + v(val x: Int) + v(var y: Int) + v(val z: Int) + v(val v = -1) + r(1) -> + mark(-1) + call(-1, minus|) -> + w(v|) + 2 mark({ x = w z = 8 }) + magic[IMPLICIT_RECEIVER](x) -> + magic[IMPLICIT_RECEIVER](w) -> + r(w|) -> + w(x|, ) + magic[IMPLICIT_RECEIVER](z) -> + r(8) -> + w(z|, ) + mark({ y = 9 }) + magic[IMPLICIT_RECEIVER](y) -> + r(9) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(): this('a') { + y = 2 + } +--------------------- +L0: + 1 + r('a') -> + mark(this('a')) + call(this('a'), |) -> + 2 mark({ y = 2 }) + magic[IMPLICIT_RECEIVER](y) -> + r(2) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(a: Int, b: Int = 3): this(b.toChar()) { + y = x + } +--------------------- +L0: + 1 + v(a: Int) + magic[FAKE_INITIALIZER](a: Int) -> + w(a|) + v(b: Int = 3) + jmp?(L2) NEXT:[magic[FAKE_INITIALIZER](b: Int = 3) -> , r(3) -> ] + r(3) -> +L2 [after default value for parameter b]: + magic[FAKE_INITIALIZER](b: Int = 3) -> PREV:[jmp?(L2), r(3) -> ] + merge(b: Int = 3|, ) -> + w(b|) + mark(b.toChar()) + r(b) -> + mark(toChar()) + call(toChar(), toChar|) -> + mark(this(b.toChar())) + call(this(b.toChar()), |) -> + 2 mark({ y = x }) + magic[IMPLICIT_RECEIVER](y) -> + magic[IMPLICIT_RECEIVER](x) -> + r(x|) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/secondaryConstructors/withPrimary.kt b/compiler/testData/cfg/secondaryConstructors/withPrimary.kt new file mode 100644 index 00000000000..d9cf8555e8d --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withPrimary.kt @@ -0,0 +1,25 @@ +class A(val w: Char) { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor(): this('a') { + y = 2 + } + + // anonymous + init { + x = w + z = 8 + } + + constructor(a: Int, b: Int = 3): this(b.toChar()) { + y = x + } + + // anonymous + init { + y = 9 + } +} \ No newline at end of file diff --git a/compiler/testData/cfg/secondaryConstructors/withPrimary.values b/compiler/testData/cfg/secondaryConstructors/withPrimary.values new file mode 100644 index 00000000000..d896a9b3fe8 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withPrimary.values @@ -0,0 +1,73 @@ +== A == +class A(val w: Char) { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor(): this('a') { + y = 2 + } + + // anonymous + init { + x = w + z = 8 + } + + constructor(a: Int, b: Int = 3): this(b.toChar()) { + y = x + } + + // anonymous + init { + y = 9 + } +} +--------------------- + : Char NEW: magic[FAKE_INITIALIZER](val w: Char) -> + : A NEW: magic[IMPLICIT_RECEIVER](x) -> + : A NEW: magic[IMPLICIT_RECEIVER](w) -> + : A NEW: magic[IMPLICIT_RECEIVER](z) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> +1 : Int NEW: r(1) -> +-1 : Int NEW: call(-1, minus|) -> +w : Int NEW: r(w|) -> +8 : Int NEW: r(8) -> +z = 8 !: * +{ x = w z = 8 } !: * COPY +9 : Int NEW: r(9) -> +y = 9 !: * +{ y = 9 } !: * COPY +===================== +== == +constructor(): this('a') { + y = 2 + } +--------------------- + : A NEW: magic[IMPLICIT_RECEIVER](y) -> +'a' : Char NEW: r('a') -> +this('a') : * NEW: call(this('a'), |) -> +2 : Int NEW: r(2) -> +y = 2 !: * +{ y = 2 } !: * COPY +===================== +== == +constructor(a: Int, b: Int = 3): this(b.toChar()) { + y = x + } +--------------------- + : Int NEW: magic[FAKE_INITIALIZER](a: Int) -> + : Int NEW: magic[FAKE_INITIALIZER](b: Int = 3) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> + : A NEW: magic[IMPLICIT_RECEIVER](x) -> +3 : Int NEW: r(3) -> +b: Int = 3 : Int NEW: merge(b: Int = 3|, ) -> +b : {<: Number} NEW: r(b) -> +toChar() : Char NEW: call(toChar(), toChar|) -> +b.toChar() : Char COPY +this(b.toChar()) : * NEW: call(this(b.toChar()), |) -> +x : Int NEW: r(x|) -> +y = x !: * +{ y = x } !: * COPY +===================== diff --git a/compiler/testData/cfg/secondaryConstructors/withPrimarySuper.instructions b/compiler/testData/cfg/secondaryConstructors/withPrimarySuper.instructions new file mode 100644 index 00000000000..259cc99fbe1 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withPrimarySuper.instructions @@ -0,0 +1,146 @@ +== B == +open class B(x: Int) +--------------------- +L0: + 1 + v(x: Int) + magic[FAKE_INITIALIZER](x: Int) -> + w(x|) +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== A == +class A(val w: Char, u: Int = 2) : B(w.toInt() + u) { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor(): this('a') { + y = 2 + } + + // anonymous + init { + x = w + z = 8 + } + + constructor(a: Int, b: Int = 3): this(b.toChar()) { + y = x + } + + // anonymous + init { + y = 9 + } +} +--------------------- +L0: + 1 + v(val w: Char) + magic[FAKE_INITIALIZER](val w: Char) -> + w(w|) + v(u: Int = 2) + jmp?(L2) NEXT:[magic[FAKE_INITIALIZER](u: Int = 2) -> , r(2) -> ] + r(2) -> +L2 [after default value for parameter u]: + magic[FAKE_INITIALIZER](u: Int = 2) -> PREV:[jmp?(L2), r(2) -> ] + merge(u: Int = 2|, ) -> + w(u|) + mark(w.toInt()) + r(w) -> + mark(toInt()) + call(toInt(), toInt|) -> + r(u) -> + mark(w.toInt() + u) + call(w.toInt() + u, plus|, ) -> + mark(B(w.toInt() + u)) + call(B(w.toInt() + u), |) -> + v(val x: Int) + v(var y: Int) + v(val z: Int) + v(val v = -1) + r(1) -> + mark(-1) + call(-1, minus|) -> + w(v|) + 2 mark({ x = w z = 8 }) + magic[IMPLICIT_RECEIVER](x) -> + magic[IMPLICIT_RECEIVER](w) -> + r(w|) -> + w(x|, ) + magic[IMPLICIT_RECEIVER](z) -> + r(8) -> + w(z|, ) + mark({ y = 9 }) + magic[IMPLICIT_RECEIVER](y) -> + r(9) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(): this('a') { + y = 2 + } +--------------------- +L0: + 1 + r('a') -> + mark(this('a')) + call(this('a'), |) -> + 2 mark({ y = 2 }) + magic[IMPLICIT_RECEIVER](y) -> + r(2) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(a: Int, b: Int = 3): this(b.toChar()) { + y = x + } +--------------------- +L0: + 1 + v(a: Int) + magic[FAKE_INITIALIZER](a: Int) -> + w(a|) + v(b: Int = 3) + jmp?(L2) NEXT:[magic[FAKE_INITIALIZER](b: Int = 3) -> , r(3) -> ] + r(3) -> +L2 [after default value for parameter b]: + magic[FAKE_INITIALIZER](b: Int = 3) -> PREV:[jmp?(L2), r(3) -> ] + merge(b: Int = 3|, ) -> + w(b|) + mark(b.toChar()) + r(b) -> + mark(toChar()) + call(toChar(), toChar|) -> + mark(this(b.toChar())) + call(this(b.toChar()), |) -> + 2 mark({ y = x }) + magic[IMPLICIT_RECEIVER](y) -> + magic[IMPLICIT_RECEIVER](x) -> + r(x|) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/secondaryConstructors/withPrimarySuper.kt b/compiler/testData/cfg/secondaryConstructors/withPrimarySuper.kt new file mode 100644 index 00000000000..0b44918ec5b --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withPrimarySuper.kt @@ -0,0 +1,26 @@ +open class B(x: Int) +class A(val w: Char, u: Int = 2) : B(w.toInt() + u) { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor(): this('a') { + y = 2 + } + + // anonymous + init { + x = w + z = 8 + } + + constructor(a: Int, b: Int = 3): this(b.toChar()) { + y = x + } + + // anonymous + init { + y = 9 + } +} diff --git a/compiler/testData/cfg/secondaryConstructors/withPrimarySuper.values b/compiler/testData/cfg/secondaryConstructors/withPrimarySuper.values new file mode 100644 index 00000000000..b85d7106f53 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withPrimarySuper.values @@ -0,0 +1,87 @@ +== B == +open class B(x: Int) +--------------------- + : Int NEW: magic[FAKE_INITIALIZER](x: Int) -> +===================== +== A == +class A(val w: Char, u: Int = 2) : B(w.toInt() + u) { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor(): this('a') { + y = 2 + } + + // anonymous + init { + x = w + z = 8 + } + + constructor(a: Int, b: Int = 3): this(b.toChar()) { + y = x + } + + // anonymous + init { + y = 9 + } +} +--------------------- + : Char NEW: magic[FAKE_INITIALIZER](val w: Char) -> + : A NEW: magic[IMPLICIT_RECEIVER](x) -> + : A NEW: magic[IMPLICIT_RECEIVER](w) -> + : A NEW: magic[IMPLICIT_RECEIVER](z) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> + : Int NEW: magic[FAKE_INITIALIZER](u: Int = 2) -> +2 : Int NEW: r(2) -> +u: Int = 2 : Int NEW: merge(u: Int = 2|, ) -> +w : Char NEW: r(w) -> +toInt() : Int NEW: call(toInt(), toInt|) -> +w.toInt() : Int COPY +u : Int NEW: r(u) -> +w.toInt() + u : Int NEW: call(w.toInt() + u, plus|, ) -> +B(w.toInt() + u) : * NEW: call(B(w.toInt() + u), |) -> +1 : Int NEW: r(1) -> +-1 : Int NEW: call(-1, minus|) -> +w : Int NEW: r(w|) -> +8 : Int NEW: r(8) -> +z = 8 !: * +{ x = w z = 8 } !: * COPY +9 : Int NEW: r(9) -> +y = 9 !: * +{ y = 9 } !: * COPY +===================== +== == +constructor(): this('a') { + y = 2 + } +--------------------- + : A NEW: magic[IMPLICIT_RECEIVER](y) -> +'a' : Char NEW: r('a') -> +this('a') : * NEW: call(this('a'), |) -> +2 : Int NEW: r(2) -> +y = 2 !: * +{ y = 2 } !: * COPY +===================== +== == +constructor(a: Int, b: Int = 3): this(b.toChar()) { + y = x + } +--------------------- + : Int NEW: magic[FAKE_INITIALIZER](a: Int) -> + : Int NEW: magic[FAKE_INITIALIZER](b: Int = 3) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> + : A NEW: magic[IMPLICIT_RECEIVER](x) -> +3 : Int NEW: r(3) -> +b: Int = 3 : Int NEW: merge(b: Int = 3|, ) -> +b : {<: Number} NEW: r(b) -> +toChar() : Char NEW: call(toChar(), toChar|) -> +b.toChar() : Char COPY +this(b.toChar()) : * NEW: call(this(b.toChar()), |) -> +x : Int NEW: r(x|) -> +y = x !: * +{ y = x } !: * COPY +===================== diff --git a/compiler/testData/cfg/secondaryConstructors/withReturn.instructions b/compiler/testData/cfg/secondaryConstructors/withReturn.instructions new file mode 100644 index 00000000000..9c75852c260 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withReturn.instructions @@ -0,0 +1,61 @@ +== A == +class A { + val x: Int + constructor() { + if (1 == 1) { + return + } + else null!! + x = 1 + } +} +--------------------- +L0: + 1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor() { + if (1 == 1) { + return + } + else null!! + x = 1 + } +--------------------- +L0: + 1 + mark() + call(, ) -> + v(val x: Int) + 2 mark({ if (1 == 1) { return } else null!! x = 1 }) + mark(if (1 == 1) { return } else null!!) + r(1) -> + r(1) -> + mark(1 == 1) + call(1 == 1, equals|, ) -> + jf(L2|) NEXT:[r(null) -> , mark({ return })] + 3 mark({ return }) + ret L1 NEXT:[] +- 2 jmp(L3) NEXT:[merge(if (1 == 1) { return } else null!!|!, ) -> ] PREV:[] +L2 [else branch]: + r(null) -> PREV:[jf(L2|)] + magic[NOT_NULL_ASSERTION](null!!|) -> + jmp(error) NEXT:[] +L3 ['if' expression result]: +- merge(if (1 == 1) { return } else null!!|!, ) -> PREV:[] +- magic[IMPLICIT_RECEIVER](x) -> PREV:[] +- r(1) -> PREV:[] +- w(x|, ) PREV:[] +L1: + 1 NEXT:[] PREV:[ret L1] +error: + PREV:[jmp(error)] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/secondaryConstructors/withReturn.kt b/compiler/testData/cfg/secondaryConstructors/withReturn.kt new file mode 100644 index 00000000000..c677ead6785 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withReturn.kt @@ -0,0 +1,10 @@ +class A { + val x: Int + constructor() { + if (1 == 1) { + return + } + else null!! + x = 1 + } +} \ No newline at end of file diff --git a/compiler/testData/cfg/secondaryConstructors/withReturn.values b/compiler/testData/cfg/secondaryConstructors/withReturn.values new file mode 100644 index 00000000000..8cfaa16d773 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withReturn.values @@ -0,0 +1,35 @@ +== A == +class A { + val x: Int + constructor() { + if (1 == 1) { + return + } + else null!! + x = 1 + } +} +--------------------- +===================== +== == +constructor() { + if (1 == 1) { + return + } + else null!! + x = 1 + } +--------------------- + : * NEW: call(, ) -> +1 : OR{*, *} NEW: r(1) -> +1 : * NEW: r(1) -> +1 == 1 : Boolean NEW: call(1 == 1, equals|, ) -> +return !: * +{ return } !: * COPY +null : * NEW: r(null) -> +null!! : * NEW: magic[NOT_NULL_ASSERTION](null!!|) -> +if (1 == 1) { return } else null!! : * NEW: merge(if (1 == 1) { return } else null!!|!, ) -> +1 : Int NEW: r(1) -> +x = 1 !: * +{ if (1 == 1) { return } else null!! x = 1 } !: * COPY +===================== diff --git a/compiler/testData/cfg/secondaryConstructors/withoutPrimary.instructions b/compiler/testData/cfg/secondaryConstructors/withoutPrimary.instructions new file mode 100644 index 00000000000..9de2f406acf --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withoutPrimary.instructions @@ -0,0 +1,198 @@ +== A == +class A { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor() { + x = 1 + y = 2 + } + constructor(a: Int, b: Int = 3) { + x = a + y = x + } + + //anonymous + init { + z = 8 + } + + constructor(a: String, b: Int = 4): this() { + y = 5 + } + constructor(a: Double, b: Int = 6): this(a.toInt()) { + y = 7 + } + + // anonymous + init { + y = 9 + } +} +--------------------- +L0: + 1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor() { + x = 1 + y = 2 + } +--------------------- +L0: + 1 + mark() + call(, ) -> + v(val x: Int) + v(var y: Int) + v(val z: Int) + v(val v = -1) + r(1) -> + mark(-1) + call(-1, minus|) -> + w(v|) + 2 mark({ z = 8 }) + magic[IMPLICIT_RECEIVER](z) -> + r(8) -> + w(z|, ) + mark({ y = 9 }) + magic[IMPLICIT_RECEIVER](y) -> + r(9) -> + w(y|, ) + mark({ x = 1 y = 2 }) + magic[IMPLICIT_RECEIVER](x) -> + r(1) -> + w(x|, ) + magic[IMPLICIT_RECEIVER](y) -> + r(2) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(a: Int, b: Int = 3) { + x = a + y = x + } +--------------------- +L0: + 1 + v(a: Int) + magic[FAKE_INITIALIZER](a: Int) -> + w(a|) + v(b: Int = 3) + jmp?(L2) NEXT:[magic[FAKE_INITIALIZER](b: Int = 3) -> , r(3) -> ] + r(3) -> +L2 [after default value for parameter b]: + magic[FAKE_INITIALIZER](b: Int = 3) -> PREV:[jmp?(L2), r(3) -> ] + merge(b: Int = 3|, ) -> + w(b|) + mark() + call(, ) -> + v(val x: Int) + v(var y: Int) + v(val z: Int) + v(val v = -1) + r(1) -> + mark(-1) + call(-1, minus|) -> + w(v|) + 2 mark({ z = 8 }) + magic[IMPLICIT_RECEIVER](z) -> + r(8) -> + w(z|, ) + mark({ y = 9 }) + magic[IMPLICIT_RECEIVER](y) -> + r(9) -> + w(y|, ) + mark({ x = a y = x }) + magic[IMPLICIT_RECEIVER](x) -> + r(a) -> + w(x|, ) + magic[IMPLICIT_RECEIVER](y) -> + magic[IMPLICIT_RECEIVER](x) -> + r(x|) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(a: String, b: Int = 4): this() { + y = 5 + } +--------------------- +L0: + 1 + v(a: String) + magic[FAKE_INITIALIZER](a: String) -> + w(a|) + v(b: Int = 4) + jmp?(L2) NEXT:[magic[FAKE_INITIALIZER](b: Int = 4) -> , r(4) -> ] + r(4) -> +L2 [after default value for parameter b]: + magic[FAKE_INITIALIZER](b: Int = 4) -> PREV:[jmp?(L2), r(4) -> ] + merge(b: Int = 4|, ) -> + w(b|) + mark(this()) + call(this(), ) -> + 2 mark({ y = 5 }) + magic[IMPLICIT_RECEIVER](y) -> + r(5) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(a: Double, b: Int = 6): this(a.toInt()) { + y = 7 + } +--------------------- +L0: + 1 + v(a: Double) + magic[FAKE_INITIALIZER](a: Double) -> + w(a|) + v(b: Int = 6) + jmp?(L2) NEXT:[magic[FAKE_INITIALIZER](b: Int = 6) -> , r(6) -> ] + r(6) -> +L2 [after default value for parameter b]: + magic[FAKE_INITIALIZER](b: Int = 6) -> PREV:[jmp?(L2), r(6) -> ] + merge(b: Int = 6|, ) -> + w(b|) + mark(a.toInt()) + r(a) -> + mark(toInt()) + call(toInt(), toInt|) -> + mark(this(a.toInt())) + call(this(a.toInt()), |) -> + 2 mark({ y = 7 }) + magic[IMPLICIT_RECEIVER](y) -> + r(7) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/secondaryConstructors/withoutPrimary.kt b/compiler/testData/cfg/secondaryConstructors/withoutPrimary.kt new file mode 100644 index 00000000000..f5ea08fa3c9 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withoutPrimary.kt @@ -0,0 +1,32 @@ +class A { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor() { + x = 1 + y = 2 + } + constructor(a: Int, b: Int = 3) { + x = a + y = x + } + + //anonymous + init { + z = 8 + } + + constructor(a: String, b: Int = 4): this() { + y = 5 + } + constructor(a: Double, b: Int = 6): this(a.toInt()) { + y = 7 + } + + // anonymous + init { + y = 9 + } +} diff --git a/compiler/testData/cfg/secondaryConstructors/withoutPrimary.values b/compiler/testData/cfg/secondaryConstructors/withoutPrimary.values new file mode 100644 index 00000000000..64d62056c11 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withoutPrimary.values @@ -0,0 +1,105 @@ +== A == +class A { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor() { + x = 1 + y = 2 + } + constructor(a: Int, b: Int = 3) { + x = a + y = x + } + + //anonymous + init { + z = 8 + } + + constructor(a: String, b: Int = 4): this() { + y = 5 + } + constructor(a: Double, b: Int = 6): this(a.toInt()) { + y = 7 + } + + // anonymous + init { + y = 9 + } +} +--------------------- +===================== +== == +constructor() { + x = 1 + y = 2 + } +--------------------- + : A NEW: magic[IMPLICIT_RECEIVER](y) -> + : A NEW: magic[IMPLICIT_RECEIVER](z) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> + : A NEW: magic[IMPLICIT_RECEIVER](x) -> + : * NEW: call(, ) -> +1 : Int NEW: r(1) -> +2 : Int NEW: r(2) -> +y = 2 !: * +{ x = 1 y = 2 } !: * COPY +===================== +== == +constructor(a: Int, b: Int = 3) { + x = a + y = x + } +--------------------- + : Int NEW: magic[FAKE_INITIALIZER](a: Int) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> + : A NEW: magic[IMPLICIT_RECEIVER](x) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> + : A NEW: magic[IMPLICIT_RECEIVER](x) -> + : Int NEW: magic[FAKE_INITIALIZER](b: Int = 3) -> + : A NEW: magic[IMPLICIT_RECEIVER](z) -> +3 : Int NEW: r(3) -> +b: Int = 3 : Int NEW: merge(b: Int = 3|, ) -> + : * NEW: call(, ) -> +a : Int NEW: r(a) -> +x : Int NEW: r(x|) -> +y = x !: * +{ x = a y = x } !: * COPY +===================== +== == +constructor(a: String, b: Int = 4): this() { + y = 5 + } +--------------------- + : String NEW: magic[FAKE_INITIALIZER](a: String) -> + : Int NEW: magic[FAKE_INITIALIZER](b: Int = 4) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> +4 : Int NEW: r(4) -> +b: Int = 4 : Int NEW: merge(b: Int = 4|, ) -> +this() : * NEW: call(this(), ) -> +5 : Int NEW: r(5) -> +y = 5 !: * +{ y = 5 } !: * COPY +===================== +== == +constructor(a: Double, b: Int = 6): this(a.toInt()) { + y = 7 + } +--------------------- + : Double NEW: magic[FAKE_INITIALIZER](a: Double) -> + : Int NEW: magic[FAKE_INITIALIZER](b: Int = 6) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> +6 : Int NEW: r(6) -> +b: Int = 6 : Int NEW: merge(b: Int = 6|, ) -> +a : {<: Number} NEW: r(a) -> +toInt() : Int NEW: call(toInt(), toInt|) -> +a.toInt() : Int COPY +this(a.toInt()) : * NEW: call(this(a.toInt()), |) -> +7 : Int NEW: r(7) -> +y = 7 !: * +{ y = 7 } !: * COPY +===================== diff --git a/compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.instructions b/compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.instructions new file mode 100644 index 00000000000..6ea73f7a14f --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.instructions @@ -0,0 +1,215 @@ +== B == +open class B(x: Int) +--------------------- +L0: + 1 + v(x: Int) + magic[FAKE_INITIALIZER](x: Int) -> + w(x|) +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== A == +class A : B { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor(): super(11) { + x = 1 + y = 2 + } + constructor(a: Int, b: Int = 3): super(b) { + x = a + y = x + } + + // anonymous + init { + z = 8 + } + + constructor(a: String, b: Int = 4): this() { + y = 5 + } + constructor(a: Double, b: Int = 6): this(a.toInt()) { + y = 7 + } + + // anonymous + init { + y = 9 + } +} +--------------------- +L0: + 1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(): super(11) { + x = 1 + y = 2 + } +--------------------- +L0: + 1 + r(11) -> + mark(super(11)) + call(super(11), |) -> + v(val x: Int) + v(var y: Int) + v(val z: Int) + v(val v = -1) + r(1) -> + mark(-1) + call(-1, minus|) -> + w(v|) + 2 mark({ z = 8 }) + magic[IMPLICIT_RECEIVER](z) -> + r(8) -> + w(z|, ) + mark({ y = 9 }) + magic[IMPLICIT_RECEIVER](y) -> + r(9) -> + w(y|, ) + mark({ x = 1 y = 2 }) + magic[IMPLICIT_RECEIVER](x) -> + r(1) -> + w(x|, ) + magic[IMPLICIT_RECEIVER](y) -> + r(2) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(a: Int, b: Int = 3): super(b) { + x = a + y = x + } +--------------------- +L0: + 1 + v(a: Int) + magic[FAKE_INITIALIZER](a: Int) -> + w(a|) + v(b: Int = 3) + jmp?(L2) NEXT:[magic[FAKE_INITIALIZER](b: Int = 3) -> , r(3) -> ] + r(3) -> +L2 [after default value for parameter b]: + magic[FAKE_INITIALIZER](b: Int = 3) -> PREV:[jmp?(L2), r(3) -> ] + merge(b: Int = 3|, ) -> + w(b|) + r(b) -> + mark(super(b)) + call(super(b), |) -> + v(val x: Int) + v(var y: Int) + v(val z: Int) + v(val v = -1) + r(1) -> + mark(-1) + call(-1, minus|) -> + w(v|) + 2 mark({ z = 8 }) + magic[IMPLICIT_RECEIVER](z) -> + r(8) -> + w(z|, ) + mark({ y = 9 }) + magic[IMPLICIT_RECEIVER](y) -> + r(9) -> + w(y|, ) + mark({ x = a y = x }) + magic[IMPLICIT_RECEIVER](x) -> + r(a) -> + w(x|, ) + magic[IMPLICIT_RECEIVER](y) -> + magic[IMPLICIT_RECEIVER](x) -> + r(x|) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(a: String, b: Int = 4): this() { + y = 5 + } +--------------------- +L0: + 1 + v(a: String) + magic[FAKE_INITIALIZER](a: String) -> + w(a|) + v(b: Int = 4) + jmp?(L2) NEXT:[magic[FAKE_INITIALIZER](b: Int = 4) -> , r(4) -> ] + r(4) -> +L2 [after default value for parameter b]: + magic[FAKE_INITIALIZER](b: Int = 4) -> PREV:[jmp?(L2), r(4) -> ] + merge(b: Int = 4|, ) -> + w(b|) + mark(this()) + call(this(), ) -> + 2 mark({ y = 5 }) + magic[IMPLICIT_RECEIVER](y) -> + r(5) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== == +constructor(a: Double, b: Int = 6): this(a.toInt()) { + y = 7 + } +--------------------- +L0: + 1 + v(a: Double) + magic[FAKE_INITIALIZER](a: Double) -> + w(a|) + v(b: Int = 6) + jmp?(L2) NEXT:[magic[FAKE_INITIALIZER](b: Int = 6) -> , r(6) -> ] + r(6) -> +L2 [after default value for parameter b]: + magic[FAKE_INITIALIZER](b: Int = 6) -> PREV:[jmp?(L2), r(6) -> ] + merge(b: Int = 6|, ) -> + w(b|) + mark(a.toInt()) + r(a) -> + mark(toInt()) + call(toInt(), toInt|) -> + mark(this(a.toInt())) + call(this(a.toInt()), |) -> + 2 mark({ y = 7 }) + magic[IMPLICIT_RECEIVER](y) -> + r(7) -> + w(y|, ) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.kt b/compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.kt new file mode 100644 index 00000000000..2f487590b81 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.kt @@ -0,0 +1,33 @@ +open class B(x: Int) +class A : B { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor(): super(11) { + x = 1 + y = 2 + } + constructor(a: Int, b: Int = 3): super(b) { + x = a + y = x + } + + // anonymous + init { + z = 8 + } + + constructor(a: String, b: Int = 4): this() { + y = 5 + } + constructor(a: Double, b: Int = 6): this(a.toInt()) { + y = 7 + } + + // anonymous + init { + y = 9 + } +} diff --git a/compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.values b/compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.values new file mode 100644 index 00000000000..9b6c848d075 --- /dev/null +++ b/compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.values @@ -0,0 +1,112 @@ +== B == +open class B(x: Int) +--------------------- + : Int NEW: magic[FAKE_INITIALIZER](x: Int) -> +===================== +== A == +class A : B { + val x: Int + var y: Int + val z: Int + val v = -1 + + constructor(): super(11) { + x = 1 + y = 2 + } + constructor(a: Int, b: Int = 3): super(b) { + x = a + y = x + } + + // anonymous + init { + z = 8 + } + + constructor(a: String, b: Int = 4): this() { + y = 5 + } + constructor(a: Double, b: Int = 6): this(a.toInt()) { + y = 7 + } + + // anonymous + init { + y = 9 + } +} +--------------------- +===================== +== == +constructor(): super(11) { + x = 1 + y = 2 + } +--------------------- + : A NEW: magic[IMPLICIT_RECEIVER](x) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> + : A NEW: magic[IMPLICIT_RECEIVER](z) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> +11 : Int NEW: r(11) -> +super(11) : * NEW: call(super(11), |) -> +1 : Int NEW: r(1) -> +2 : Int NEW: r(2) -> +y = 2 !: * +{ x = 1 y = 2 } !: * COPY +===================== +== == +constructor(a: Int, b: Int = 3): super(b) { + x = a + y = x + } +--------------------- + : Int NEW: magic[FAKE_INITIALIZER](a: Int) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> + : A NEW: magic[IMPLICIT_RECEIVER](x) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> + : A NEW: magic[IMPLICIT_RECEIVER](x) -> + : Int NEW: magic[FAKE_INITIALIZER](b: Int = 3) -> + : A NEW: magic[IMPLICIT_RECEIVER](z) -> +3 : Int NEW: r(3) -> +b: Int = 3 : Int NEW: merge(b: Int = 3|, ) -> +b : Int NEW: r(b) -> +super(b) : * NEW: call(super(b), |) -> +a : Int NEW: r(a) -> +x : Int NEW: r(x|) -> +y = x !: * +{ x = a y = x } !: * COPY +===================== +== == +constructor(a: String, b: Int = 4): this() { + y = 5 + } +--------------------- + : String NEW: magic[FAKE_INITIALIZER](a: String) -> + : Int NEW: magic[FAKE_INITIALIZER](b: Int = 4) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> +4 : Int NEW: r(4) -> +b: Int = 4 : Int NEW: merge(b: Int = 4|, ) -> +this() : * NEW: call(this(), ) -> +5 : Int NEW: r(5) -> +y = 5 !: * +{ y = 5 } !: * COPY +===================== +== == +constructor(a: Double, b: Int = 6): this(a.toInt()) { + y = 7 + } +--------------------- + : Double NEW: magic[FAKE_INITIALIZER](a: Double) -> + : Int NEW: magic[FAKE_INITIALIZER](b: Int = 6) -> + : A NEW: magic[IMPLICIT_RECEIVER](y) -> +6 : Int NEW: r(6) -> +b: Int = 6 : Int NEW: merge(b: Int = 6|, ) -> +a : {<: Number} NEW: r(a) -> +toInt() : Int NEW: call(toInt(), toInt|) -> +a.toInt() : Int COPY +this(a.toInt()) : * NEW: call(this(a.toInt()), |) -> +7 : Int NEW: r(7) -> +y = 7 !: * +{ y = 7 } !: * COPY +===================== diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/membersInitializationWithPrimary.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/membersInitializationWithPrimary.txt new file mode 100644 index 00000000000..b0b6416fa16 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/membersInitializationWithPrimary.txt @@ -0,0 +1,19 @@ +package + +internal final class A { + public constructor A() + public constructor A(/*0*/ w: kotlin.Char) + public constructor A(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int = ...) + internal final val overinitialized: kotlin.Int + internal final val uninitialized: kotlin.Int + internal final val useInitialized: kotlin.Int + internal final val useUnitialized: kotlin.Int + internal final val v: kotlin.Int = -1 + internal final val w: kotlin.Char + internal final val x: kotlin.Int + internal final var y: kotlin.Int + internal final val z: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/membersInitializationWithoutPrimary.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/membersInitializationWithoutPrimary.txt new file mode 100644 index 00000000000..610ca35deae --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/membersInitializationWithoutPrimary.txt @@ -0,0 +1,20 @@ +package + +internal final class A { + public constructor A() + public constructor A(/*0*/ a: kotlin.Double, /*1*/ b: kotlin.Int = ...) + public constructor A(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int = ...) + public constructor A(/*0*/ x: kotlin.String) + public constructor A(/*0*/ a: kotlin.String, /*1*/ b: kotlin.Int = ...) + internal final val overinitialized: kotlin.Int + internal final val uninitialized: kotlin.Int + internal final val useInitialized: kotlin.Int + internal final val useUnitialized: kotlin.Int + internal final val v: kotlin.Int = -1 + internal final val x: kotlin.Int + internal final var y: kotlin.Int + internal final val z: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.kt new file mode 100644 index 00000000000..3c9f5a6cfcc --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.kt @@ -0,0 +1,33 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +class A(val w: Char) { + val x: Int + var y: Int + val z: Int + val v = -1 + + val uninitialized: Int + val overinitialized: Int + + constructor(): this('a') { + y = 1 + + overinitialized = 2 + uninitialized = 3 + } + + // anonymous + init { + x = 4 + z = 5 + overinitialized = 6 + } + + constructor(a: Int): this('b') { + y = 7 + } + + // anonymous + init { + y = 8 + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.txt new file mode 100644 index 00000000000..9331f996333 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.txt @@ -0,0 +1,17 @@ +package + +internal final class A { + public constructor A() + public constructor A(/*0*/ w: kotlin.Char) + public constructor A(/*0*/ a: kotlin.Int) + internal final val overinitialized: kotlin.Int + internal final val uninitialized: kotlin.Int + internal final val v: kotlin.Int = -1 + internal final val w: kotlin.Char + internal final val x: kotlin.Int + internal final var y: kotlin.Int + internal final val z: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.kt new file mode 100644 index 00000000000..35f31915e4f --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.kt @@ -0,0 +1,39 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +class A { + val x: Int + var y: Int + val z: Int + val v = -1 + + val uninitialized: Int + val overinitialized: Int + + constructor() { + x = 1 + y = 2 + + overinitialized = 3 + uninitialized = 4 + } + + constructor(a: Int): super() { + x = 5 + y = 6 + } + + constructor(x: String): this() { + y = 7 + uninitialized = 8 + } + + //anonymous + init { + z = 9 + overinitialized = 10 + } + + // anonymous + init { + y = 12 + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.txt new file mode 100644 index 00000000000..749adae33ed --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.txt @@ -0,0 +1,16 @@ +package + +internal final class A { + public constructor A() + public constructor A(/*0*/ a: kotlin.Int) + public constructor A(/*0*/ x: kotlin.String) + internal final val overinitialized: kotlin.Int + internal final val uninitialized: kotlin.Int + internal final val v: kotlin.Int = -1 + internal final val x: kotlin.Int + internal final var y: kotlin.Int + internal final val z: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/return.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/return.kt index 71181bbfe91..835274867be 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/return.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/return.kt @@ -1,17 +1,16 @@ - class A { init { return - return 1 + return 1 } - constructor() { + constructor() { if (1 == 1) { return return 1 } return return foo() - } + } fun foo(): Int = 1 } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.kt new file mode 100644 index 00000000000..017c1629ce5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.kt @@ -0,0 +1,38 @@ +class A0 { + val x: Int + constructor() { + if (1 == 1) { + return + } + x = 1 + } + constructor(arg: Int) { + x = arg + } +} + +class A1 { + val x: Int + constructor() { + if (1 == 1) { + return + } else null!! + x = 1 + } +} + +class A2 { + val x: Int + constructor() { + if (1 == 1) { + x = 1 + return + } + else { + x = 2 + } + } + constructor(arg: Int) { + x = arg + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.txt new file mode 100644 index 00000000000..e6e961c6fff --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.txt @@ -0,0 +1,27 @@ +package + +internal final class A0 { + public constructor A0() + public constructor A0(/*0*/ arg: kotlin.Int) + internal final val x: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal final class A1 { + public constructor A1() + internal final val x: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal final class A2 { + public constructor A2() + public constructor A2(/*0*/ arg: kotlin.Int) + internal final val x: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.kt new file mode 100644 index 00000000000..18b3c8d4382 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.kt @@ -0,0 +1,30 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +class A(val w: Int) { + val x: Int + val useUnitialized = x + + y + + v + var y: Int + val v = -1 + val useInitialized = useUnitialized + v + w + + val uninitialized: Int + + constructor(): this(1) { + x + y + v + uninitialized + w + } + + // anonymous + init { + x + y + v + uninitialized + w + x = 1 + x + y + v + uninitialized + w + } + + // anonymous + init { + x + y + v + uninitialized + w + y = 7 + x + y + v + uninitialized + w + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.txt new file mode 100644 index 00000000000..fa386228132 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.txt @@ -0,0 +1,16 @@ +package + +internal final class A { + public constructor A() + public constructor A(/*0*/ w: kotlin.Int) + internal final val uninitialized: kotlin.Int + internal final val useInitialized: kotlin.Int + internal final val useUnitialized: kotlin.Int + internal final val v: kotlin.Int = -1 + internal final val w: kotlin.Int + internal final val x: kotlin.Int + internal final var y: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.kt new file mode 100644 index 00000000000..ea2b64d48a1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.kt @@ -0,0 +1,46 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +class A { + val x: Int + val useUnitialized = x + // reported on each secondary constructor + y + + v + var y: Int + val v = -1 + + val useInitialized = useUnitialized + v + + val uninitialized: Int + + constructor() { + x = 1 + y = 2 + + x + y + v + uninitialized + + uninitialized = 3 + + x + y + v + uninitialized + } + + constructor(a: Int): super() { + x + y + v + uninitialized + x = 4 + y = 5 + + x + y + v + uninitialized + } + + constructor(x: String): this() { + x + y + v + uninitialized + } + + //anonymous + init { + y + } + + // anonymous + init { + y = 9 + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.txt new file mode 100644 index 00000000000..db39ce1d758 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.txt @@ -0,0 +1,16 @@ +package + +internal final class A { + public constructor A() + public constructor A(/*0*/ a: kotlin.Int) + public constructor A(/*0*/ x: kotlin.String) + internal final val uninitialized: kotlin.Int + internal final val useInitialized: kotlin.Int + internal final val useUnitialized: kotlin.Int + internal final val v: kotlin.Int = -1 + internal final val x: kotlin.Int + internal final var y: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/cfg/AbstractPseudocodeTest.java b/compiler/tests/org/jetbrains/kotlin/cfg/AbstractPseudocodeTest.java index 7ab8a455388..bfa5c4e33ed 100644 --- a/compiler/tests/org/jetbrains/kotlin/cfg/AbstractPseudocodeTest.java +++ b/compiler/tests/org/jetbrains/kotlin/cfg/AbstractPseudocodeTest.java @@ -63,7 +63,7 @@ public abstract class AbstractPseudocodeTest extends KotlinTestWithEnvironment { if (declaration instanceof JetDeclarationContainer) { for (JetDeclaration member : ((JetDeclarationContainer) declaration).getDeclarations()) { // Properties and initializers are processed elsewhere - if (member instanceof JetNamedFunction) { + if (member instanceof JetNamedFunction || member instanceof JetSecondaryConstructor) { addDeclaration(data, bindingContext, member); } } diff --git a/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java index e6efd38fe08..8107c01dce2 100644 --- a/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java @@ -40,6 +40,7 @@ import java.util.regex.Pattern; ControlFlowTestGenerated.Declarations.class, ControlFlowTestGenerated.Expressions.class, ControlFlowTestGenerated.Functions.class, + ControlFlowTestGenerated.SecondaryConstructors.class, ControlFlowTestGenerated.TailCalls.class, }) @RunWith(JUnit3RunnerWithInners.class) @@ -611,6 +612,45 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { } } + @TestMetadata("compiler/testData/cfg/secondaryConstructors") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SecondaryConstructors extends AbstractControlFlowTest { + public void testAllFilesPresentInSecondaryConstructors() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/cfg/secondaryConstructors"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("withPrimary.kt") + public void testWithPrimary() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cfg/secondaryConstructors/withPrimary.kt"); + doTest(fileName); + } + + @TestMetadata("withPrimarySuper.kt") + public void testWithPrimarySuper() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cfg/secondaryConstructors/withPrimarySuper.kt"); + doTest(fileName); + } + + @TestMetadata("withReturn.kt") + public void testWithReturn() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cfg/secondaryConstructors/withReturn.kt"); + doTest(fileName); + } + + @TestMetadata("withoutPrimary.kt") + public void testWithoutPrimary() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cfg/secondaryConstructors/withoutPrimary.kt"); + doTest(fileName); + } + + @TestMetadata("withoutPrimarySuper.kt") + public void testWithoutPrimarySuper() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/cfg/tailCalls") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java index 016bcbc0787..889e304aa41 100644 --- a/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java @@ -46,6 +46,7 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest { Cfg.Declarations.class, Cfg.Expressions.class, Cfg.Functions.class, + Cfg.SecondaryConstructors.class, Cfg.TailCalls.class, }) @RunWith(JUnit3RunnerWithInners.class) @@ -617,6 +618,45 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest { } } + @TestMetadata("compiler/testData/cfg/secondaryConstructors") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SecondaryConstructors extends AbstractPseudoValueTest { + public void testAllFilesPresentInSecondaryConstructors() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/cfg/secondaryConstructors"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("withPrimary.kt") + public void testWithPrimary() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cfg/secondaryConstructors/withPrimary.kt"); + doTest(fileName); + } + + @TestMetadata("withPrimarySuper.kt") + public void testWithPrimarySuper() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cfg/secondaryConstructors/withPrimarySuper.kt"); + doTest(fileName); + } + + @TestMetadata("withReturn.kt") + public void testWithReturn() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cfg/secondaryConstructors/withReturn.kt"); + doTest(fileName); + } + + @TestMetadata("withoutPrimary.kt") + public void testWithoutPrimary() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cfg/secondaryConstructors/withoutPrimary.kt"); + doTest(fileName); + } + + @TestMetadata("withoutPrimarySuper.kt") + public void testWithoutPrimarySuper() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/cfg/secondaryConstructors/withoutPrimarySuper.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/cfg/tailCalls") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 8cf6400d741..1789a198b98 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -10439,6 +10439,18 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("propertyInitializationWithPrimary.kt") + public void testPropertyInitializationWithPrimary() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithPrimary.kt"); + doTest(fileName); + } + + @TestMetadata("propertyInitializationWithoutPrimary.kt") + public void testPropertyInitializationWithoutPrimary() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/propertyInitializationWithoutPrimary.kt"); + doTest(fileName); + } + @TestMetadata("return.kt") public void testReturn() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/return.kt"); @@ -10463,6 +10475,24 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("unreachableCode.kt") + public void testUnreachableCode() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/unreachableCode.kt"); + doTest(fileName); + } + + @TestMetadata("useOfPropertiesWithPrimary.kt") + public void testUseOfPropertiesWithPrimary() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithPrimary.kt"); + doTest(fileName); + } + + @TestMetadata("useOfPropertiesWithoutPrimary.kt") + public void testUseOfPropertiesWithoutPrimary() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/useOfPropertiesWithoutPrimary.kt"); + doTest(fileName); + } + @TestMetadata("varargsInDelegationCallToPrimary.kt") public void testVarargsInDelegationCallToPrimary() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/varargsInDelegationCallToPrimary.kt");