From 527daced4609268dcc2c63ad4e6e8b3e2433dd78 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 20 Sep 2017 19:18:58 +0300 Subject: [PATCH] Optimize CFG for cases of simple variables Parameters/vals with an immediate initializer (which we assume is a rather common situation) do not require any kind of complicated CFA - Unused vals can be simply determined by linear traversal of the pseudocode - Definite assignment is a bit more complicated: a read-instruction of val can be considered as a safe if it's located *after* the first write in the pseudocode. It works almost always beside the case with do/while (see the test changed). This case will be fixed in the further commits The test for kt897.kt will also be fixed further, all other changes might be considered as minor as they mostly change diagnostics for already red code --- .../kotlin/cfg/PseudocodeVariablesData.kt | 340 +++++++++++++++--- .../tests/DefaultValuesCheckWithoutBody.kt | 2 +- .../tests/DefaultValuesTypechecking.kt | 6 +- .../diagnostics/tests/LValueAssignment.kt | 6 +- .../UninitializedOrReassignedVariables.kt | 10 +- .../controlFlowAnalysis/doWhileNotDefined.kt | 2 +- .../tests/controlFlowAnalysis/kt897.kt | 2 +- .../DataFlowInMultiDeclInFor.kt | 2 +- 8 files changed, 297 insertions(+), 73 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.kt index 16a570addb6..ead8c09633a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/PseudocodeVariablesData.kt @@ -26,16 +26,35 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.WriteValueInstructi import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction import org.jetbrains.kotlin.cfg.pseudocodeTraverser.Edges import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder +import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor -import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContextUtils.variableDescriptorForDeclaration -import java.util.* +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +private typealias ImmutableSet = javaslang.collection.Set +private typealias ImmutableHashSet = javaslang.collection.HashSet class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingContext: BindingContext) { private val pseudocodeVariableDataCollector = PseudocodeVariableDataCollector(bindingContext, pseudocode) - private val declaredVariablesForDeclaration = hashMapOf>() + private class VariablesForDeclaration( + val valsWithTrivialInitializer: Set, + val nonTrivialVariables: Set + ) { + val allVars = + if (nonTrivialVariables.isEmpty()) + valsWithTrivialInitializer + else + LinkedHashSet(valsWithTrivialInitializer).also { it.addAll(nonTrivialVariables) } + } + + private val declaredVariablesForDeclaration = hashMapOf() + private val rootVariables by lazy(LazyThreadSafetyMode.NONE) { + getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations = true) + } val variableInitializers: Map> by lazy { computeVariableInitializers() @@ -44,49 +63,87 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon val blockScopeVariableInfo: BlockScopeVariableInfo get() = pseudocodeVariableDataCollector.blockScopeVariableInfo - fun getDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): Set { + fun getDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): Set = + getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations).allVars + + private fun getAllDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): VariablesForDeclaration { if (!includeInsideLocalDeclarations) { return getUpperLevelDeclaredVariables(pseudocode) } - val declaredVariables = linkedSetOf() - declaredVariables.addAll(getUpperLevelDeclaredVariables(pseudocode)) + val nonTrivialVariables = linkedSetOf() + val valsWithTrivialInitializer = linkedSetOf() + addVariablesFromPseudocode(pseudocode, nonTrivialVariables, valsWithTrivialInitializer) for (localFunctionDeclarationInstruction in pseudocode.localDeclarations) { val localPseudocode = localFunctionDeclarationInstruction.body - declaredVariables.addAll(getUpperLevelDeclaredVariables(localPseudocode)) + addVariablesFromPseudocode(localPseudocode, nonTrivialVariables, valsWithTrivialInitializer) } - return declaredVariables + return VariablesForDeclaration(valsWithTrivialInitializer, nonTrivialVariables) } - private fun getUpperLevelDeclaredVariables(pseudocode: Pseudocode): Set { - var declaredVariables = declaredVariablesForDeclaration[pseudocode] - if (declaredVariables == null) { - declaredVariables = computeDeclaredVariablesForPseudocode(pseudocode) - declaredVariablesForDeclaration.put(pseudocode, declaredVariables) + private fun addVariablesFromPseudocode( + pseudocode: Pseudocode, + nonTrivialVariables: MutableSet, + valsWithTrivialInitializer: MutableSet + ) { + getUpperLevelDeclaredVariables(pseudocode).let { + nonTrivialVariables.addAll(it.nonTrivialVariables) + valsWithTrivialInitializer.addAll(it.valsWithTrivialInitializer) } - return declaredVariables } - private fun computeDeclaredVariablesForPseudocode(pseudocode: Pseudocode): Set { - val declaredVariables = linkedSetOf() + private fun getUpperLevelDeclaredVariables(pseudocode: Pseudocode) = declaredVariablesForDeclaration.getOrPut(pseudocode) { + computeDeclaredVariablesForPseudocode(pseudocode) + } + + private fun computeDeclaredVariablesForPseudocode(pseudocode: Pseudocode): VariablesForDeclaration { + val valsWithTrivialInitializer = linkedSetOf() + val nonTrivialVariables = linkedSetOf() for (instruction in pseudocode.instructions) { if (instruction is VariableDeclarationInstruction) { val variableDeclarationElement = instruction.variableDeclarationElement - val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement) - variableDescriptorForDeclaration(descriptor)?.let { - declaredVariables.add(it) + val descriptor = + variableDescriptorForDeclaration( + bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement) + ) ?: continue + + if (isValWithTrivialInitializer(variableDeclarationElement, descriptor)) { + valsWithTrivialInitializer.add(descriptor) + } + else { + nonTrivialVariables.add(descriptor) } } } - return Collections.unmodifiableSet(declaredVariables) + + return VariablesForDeclaration(valsWithTrivialInitializer, nonTrivialVariables) + } + + private fun isValWithTrivialInitializer(variableDeclarationElement: KtDeclaration, descriptor: VariableDescriptor) = + variableDeclarationElement is KtParameter || variableDeclarationElement is KtObjectDeclaration || + variableDeclarationElement.safeAs()?.isVariableWithTrivialInitializer(descriptor) == true + + private fun KtVariableDeclaration.isVariableWithTrivialInitializer(descriptor: VariableDescriptor): Boolean { + if (descriptor.isPropertyWithoutBackingField()) return true + if (isVar) return false + return initializer != null || safeAs()?.delegate != null || this is KtDestructuringDeclarationEntry + } + + private fun VariableDescriptor.isPropertyWithoutBackingField(): Boolean { + if (this !is PropertyDescriptor) return false + return bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, this) != true } // variable initializers - private fun computeVariableInitializers(): Map> { + private fun computeVariableInitializers(): Map> { val blockScopeVariableInfo = pseudocodeVariableDataCollector.blockScopeVariableInfo + val resultForValsWithTrivialInitializer = computeInitInfoForTrivialVals() + + if (rootVariables.nonTrivialVariables.isEmpty()) return resultForValsWithTrivialInitializer + return pseudocodeVariableDataCollector.collectData(TraversalOrder.FORWARD, InitControlFlowInfo()) { instruction: Instruction, incomingEdgesData: Collection -> @@ -94,6 +151,88 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon val exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny( instruction, enterInstructionData, blockScopeVariableInfo) Edges(enterInstructionData, exitInstructionData) + }.mapValues { + (instruction, edges) -> + val trivialEdges = resultForValsWithTrivialInitializer[instruction]!! + Edges(trivialEdges.incoming.replaceDelegate(edges.incoming), trivialEdges.outgoing.replaceDelegate(edges.outgoing)) + } + } + + private fun computeInitInfoForTrivialVals(): Map> { + val result = hashMapOf>() + var declaredSet = ImmutableHashSet.empty() + var initSet = ImmutableHashSet.empty() + pseudocode.traverse(TraversalOrder.FORWARD) { instruction -> + val enterState = ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, null) + when (instruction) { + is VariableDeclarationInstruction -> + extractValWithTrivialInitializer(instruction)?.let { + variableDescriptor -> + declaredSet = declaredSet.add(variableDescriptor) + } + is WriteValueInstruction -> { + val variableDescriptor = extractValWithTrivialInitializer(instruction) + if (variableDescriptor != null && instruction.isTrivialInitializer()) { + initSet = initSet.add(variableDescriptor) + } + } + } + + val afterState = ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, null) + + result[instruction] = Edges(enterState, afterState) + } + return result + } + + private fun WriteValueInstruction.isTrivialInitializer() = + element is KtVariableDeclaration || element is KtParameter + + private inner class ReadOnlyInitControlFlowInfoImpl( + val declaredSet: ImmutableSet, + val initSet: ImmutableSet, + private val delegate: ReadOnlyInitControlFlowInfo? + ) : ReadOnlyInitControlFlowInfo { + override fun getOrNull(variableDescriptor: VariableDescriptor): VariableControlFlowState? { + if (variableDescriptor in declaredSet) { + return VariableControlFlowState.create(isInitialized = variableDescriptor in initSet, isDeclared = true) + } + return delegate?.getOrNull(variableDescriptor) + } + + override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean = + delegate?.checkDefiniteInitializationInWhen(merge) ?: false + + fun replaceDelegate(newDelegate: ReadOnlyInitControlFlowInfo): ReadOnlyInitControlFlowInfo = + ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, newDelegate) + + override fun asMap(): ImmutableMap { + val initial = delegate?.asMap() ?: ImmutableHashMap.empty() + + return declaredSet.fold(initial) { + acc, variableDescriptor -> + acc.put(variableDescriptor, getOrNull(variableDescriptor)!!) + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ReadOnlyInitControlFlowInfoImpl + + if (declaredSet != other.declaredSet) return false + if (initSet != other.initSet) return false + if (delegate != other.delegate) return false + + return true + } + + override fun hashCode(): Int { + var result = declaredSet.hashCode() + result = 31 * result + initSet.hashCode() + result = 31 * result + (delegate?.hashCode() ?: 0) + return result } } @@ -115,7 +254,10 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon if (instruction !is WriteValueInstruction && instruction !is VariableDeclarationInstruction) { return enterInstructionData } - val variable = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext) ?: return enterInstructionData + val variable = + PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext) + ?.takeIf { it in rootVariables.nonTrivialVariables } + ?: return enterInstructionData var exitInstructionData = enterInstructionData if (instruction is WriteValueInstruction) { // if writing to already initialized object @@ -129,10 +271,10 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon } else { // instruction instanceof VariableDeclarationInstruction - var enterInitState: VariableControlFlowState? = enterInstructionData.getOrNull(variable) - if (enterInitState == null) { - enterInitState = getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo) - } + val enterInitState = + enterInstructionData.getOrNull(variable) + ?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo) + if (!enterInitState.mayBeInitialized() || !enterInitState.isDeclared) { val variableDeclarationInfo = VariableControlFlowState.create(enterInitState.initState, isDeclared = true) exitInstructionData = exitInstructionData.put(variable, variableDeclarationInfo, enterInitState) @@ -144,45 +286,127 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon // variable use val variableUseStatusData: Map> - get() = pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) { - instruction: Instruction, incomingEdgesData: Collection -> + get() { + val resultForTrivialVals = computeUseInfoForTrivialVals() + if (rootVariables.nonTrivialVariables.isEmpty()) return resultForTrivialVals - val enterResult: UseControlFlowInfo = if (incomingEdgesData.size == 1) { - incomingEdgesData.single() - } - else { - incomingEdgesData.fold(UseControlFlowInfo()) { result, edgeData -> - edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) -> - subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor))) + return pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) { instruction: Instruction, incomingEdgesData: Collection -> + + val enterResult: UseControlFlowInfo = if (incomingEdgesData.size == 1) { + incomingEdgesData.single() + } + else { + incomingEdgesData.fold(UseControlFlowInfo()) { result, edgeData -> + edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) -> + subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor))) + } } } - } - val variableDescriptor = PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext) - if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) { - Edges(enterResult, enterResult) - } - else { - val exitResult = - if (instruction is ReadValueInstruction) { - enterResult.put(variableDescriptor, VariableUseState.READ) - } - else { - var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor) - if (variableUseState == null) { - variableUseState = VariableUseState.UNUSED - } - when (variableUseState) { - VariableUseState.UNUSED, VariableUseState.ONLY_WRITTEN_NEVER_READ -> - enterResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ) - VariableUseState.WRITTEN_AFTER_READ, VariableUseState.READ -> - enterResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ) - } - } - Edges(enterResult, exitResult) + val variableDescriptor = + PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext) + ?.takeIf { it in rootVariables.nonTrivialVariables } + if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) { + Edges(enterResult, enterResult) + } + else { + val exitResult = + if (instruction is ReadValueInstruction) { + enterResult.put(variableDescriptor, VariableUseState.READ) + } + else { + var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor) + if (variableUseState == null) { + variableUseState = VariableUseState.UNUSED + } + when (variableUseState) { + VariableUseState.UNUSED, VariableUseState.ONLY_WRITTEN_NEVER_READ -> + enterResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ) + VariableUseState.WRITTEN_AFTER_READ, VariableUseState.READ -> + enterResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ) + } + } + Edges(enterResult, exitResult) + } + }.mapValues { + (instruction, edges) -> + val edgeForTrivialVals = resultForTrivialVals[instruction]!! + + Edges( + edgeForTrivialVals.incoming.replaceDelegate(edges.incoming), + edgeForTrivialVals.outgoing.replaceDelegate(edges.outgoing) + ) } } + private fun computeUseInfoForTrivialVals(): Map> { + val used = hashSetOf() + + pseudocode.traverse(TraversalOrder.FORWARD) { instruction -> + if (instruction is ReadValueInstruction) { + extractValWithTrivialInitializer(instruction)?.let { + used.add(it) + } + } + } + + val constantUseInfo = ReadOnlyUseControlFlowInfoImpl(used, null) + val constantEdges = Edges(constantUseInfo, constantUseInfo) + val result = hashMapOf>() + + pseudocode.traverse(TraversalOrder.FORWARD) { instruction -> + result[instruction] = constantEdges + } + return result + } + + private fun extractValWithTrivialInitializer(instruction: Instruction): VariableDescriptor? { + return PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)?.takeIf { + it in rootVariables.valsWithTrivialInitializer + } + } + + private inner class ReadOnlyUseControlFlowInfoImpl( + val used: Set, + val delegate: ReadOnlyUseControlFlowInfo? + ) : ReadOnlyUseControlFlowInfo { + override fun getOrNull(variableDescriptor: VariableDescriptor): VariableUseState? { + if (variableDescriptor in used) return VariableUseState.READ + return delegate?.getOrNull(variableDescriptor) + } + + fun replaceDelegate(newDelegate: ReadOnlyUseControlFlowInfo): ReadOnlyUseControlFlowInfo = + ReadOnlyUseControlFlowInfoImpl(used, newDelegate) + + override fun asMap(): ImmutableMap { + val initial = delegate?.asMap() ?: ImmutableHashMap.empty() + + return used.fold(initial) { + acc, variableDescriptor -> + acc.put(variableDescriptor, getOrNull(variableDescriptor)!!) + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ReadOnlyUseControlFlowInfoImpl + + if (used != other.used) return false + if (delegate != other.delegate) return false + + return true + } + + override fun hashCode(): Int { + var result = used.hashCode() + result = 31 * result + (delegate?.hashCode() ?: 0) + return result + } + + } + companion object { @JvmStatic diff --git a/compiler/testData/diagnostics/tests/DefaultValuesCheckWithoutBody.kt b/compiler/testData/diagnostics/tests/DefaultValuesCheckWithoutBody.kt index ac90467340b..217b1790e5d 100644 --- a/compiler/testData/diagnostics/tests/DefaultValuesCheckWithoutBody.kt +++ b/compiler/testData/diagnostics/tests/DefaultValuesCheckWithoutBody.kt @@ -6,4 +6,4 @@ abstract class Abst { abstract fun foo(x: Int = y, y: Int = x) } -fun extraDiagnostics(x: Int = y, y: Int) \ No newline at end of file +fun extraDiagnostics(x: Int = y, y: Int) diff --git a/compiler/testData/diagnostics/tests/DefaultValuesTypechecking.kt b/compiler/testData/diagnostics/tests/DefaultValuesTypechecking.kt index a6be46b2654..2ab8a0dbbbf 100644 --- a/compiler/testData/diagnostics/tests/DefaultValuesTypechecking.kt +++ b/compiler/testData/diagnostics/tests/DefaultValuesTypechecking.kt @@ -6,10 +6,10 @@ fun bar(x : Int = "", y : Int = x, z // KT-371 Resolve default parameters for constructors -class A(x : Int = y, y : Int = x) { // None of the references is resolved, no types checked - fun foo(bool: Boolean, a: Int = b, b: String = a) {} +class A(x : Int = y, y : Int = x) { // None of the references is resolved, no types checked + fun foo(bool: Boolean, a: Int = b, b: String = a) {} } val z = 3 -fun foo(x: Int = y, y: Int = x, i : Int = z): Int = x + y \ No newline at end of file +fun foo(x: Int = y, y: Int = x, i : Int = z): Int = x + y diff --git a/compiler/testData/diagnostics/tests/LValueAssignment.kt b/compiler/testData/diagnostics/tests/LValueAssignment.kt index 20f4baeea06..b98be9fd2e9 100644 --- a/compiler/testData/diagnostics/tests/LValueAssignment.kt +++ b/compiler/testData/diagnostics/tests/LValueAssignment.kt @@ -51,7 +51,7 @@ fun cannotBe() { 5 = 34 } -fun canBe(i0: Int, j: Int) { +fun canBe(i0: Int, j: Int) { var i = i0 (label@ i) = 34 @@ -61,7 +61,7 @@ fun canBe(i0: Int, j: Int) { (l@ a.a) = 3894 } -fun canBe2(j: Int) { +fun canBe2(j: Int) { (label@ j) = 34 } @@ -140,4 +140,4 @@ fun Array.checkThis() { abstract class Ab { abstract fun getArray() : Array -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/UninitializedOrReassignedVariables.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/UninitializedOrReassignedVariables.kt index 996e2b017c6..a0c29641d42 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/UninitializedOrReassignedVariables.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/UninitializedOrReassignedVariables.kt @@ -53,7 +53,7 @@ fun t2() { class A() {} -fun t4(a: A) { +fun t4(a: A) { a = A() } @@ -61,7 +61,7 @@ fun t4(a: A) { // reassigned vals fun t1() { - val a : Int = 1 + val a : Int = 1 a = 2 var b : Int = 1 @@ -83,7 +83,7 @@ enum class ProtocolState { fun t3() { val x: ProtocolState = ProtocolState.WAITING x = x.signal() - x = x.signal() //repeat for x + x = x.signal() //repeat for x } fun t4() { @@ -187,7 +187,7 @@ class AnonymousInitializers(var a: String, val b: String) { } } -fun reassignFunParams(a: Int) { +fun reassignFunParams(a: Int) { a = 1 } @@ -345,4 +345,4 @@ fun test(m : M) { fun test1(m : M) { m.x++ m.y-- -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/doWhileNotDefined.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/doWhileNotDefined.kt index e41bcd1a76e..92c4f436540 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/doWhileNotDefined.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/doWhileNotDefined.kt @@ -2,5 +2,5 @@ fun test(cond1: Boolean) { do { if (cond1) continue val cond2 = false - } while (cond2) // cond2 may be not defined here + } while (cond2) // cond2 may be not defined here } diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt897.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt897.kt index eb279e36d50..ee10f766706 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt897.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt897.kt @@ -4,7 +4,7 @@ package kt897 class A() { init { - i = 11 + i = 11 } val i : Int? = null // must be an error diff --git a/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt b/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt index 1feb317b1f0..0911d17433c 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/DataFlowInMultiDeclInFor.kt @@ -8,7 +8,7 @@ class A { } fun foo(list: List) { - for (var (c1, c2, c3) in list) { + for (var (c1, c2, c3) in list) { c1 = 1 c3 + 1 }