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
This commit is contained in:
Denis Zharkov
2017-09-20 19:18:58 +03:00
parent 4b79269cec
commit 527daced46
8 changed files with 297 additions and 73 deletions
@@ -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<T> = javaslang.collection.Set<T>
private typealias ImmutableHashSet<T> = javaslang.collection.HashSet<T>
class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingContext: BindingContext) {
private val pseudocodeVariableDataCollector = PseudocodeVariableDataCollector(bindingContext, pseudocode)
private val declaredVariablesForDeclaration = hashMapOf<Pseudocode, Set<VariableDescriptor>>()
private class VariablesForDeclaration(
val valsWithTrivialInitializer: Set<VariableDescriptor>,
val nonTrivialVariables: Set<VariableDescriptor>
) {
val allVars =
if (nonTrivialVariables.isEmpty())
valsWithTrivialInitializer
else
LinkedHashSet(valsWithTrivialInitializer).also { it.addAll(nonTrivialVariables) }
}
private val declaredVariablesForDeclaration = hashMapOf<Pseudocode, VariablesForDeclaration>()
private val rootVariables by lazy(LazyThreadSafetyMode.NONE) {
getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations = true)
}
val variableInitializers: Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>> 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<VariableDescriptor> {
fun getDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): Set<VariableDescriptor> =
getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations).allVars
private fun getAllDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): VariablesForDeclaration {
if (!includeInsideLocalDeclarations) {
return getUpperLevelDeclaredVariables(pseudocode)
}
val declaredVariables = linkedSetOf<VariableDescriptor>()
declaredVariables.addAll(getUpperLevelDeclaredVariables(pseudocode))
val nonTrivialVariables = linkedSetOf<VariableDescriptor>()
val valsWithTrivialInitializer = linkedSetOf<VariableDescriptor>()
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<VariableDescriptor> {
var declaredVariables = declaredVariablesForDeclaration[pseudocode]
if (declaredVariables == null) {
declaredVariables = computeDeclaredVariablesForPseudocode(pseudocode)
declaredVariablesForDeclaration.put(pseudocode, declaredVariables)
private fun addVariablesFromPseudocode(
pseudocode: Pseudocode,
nonTrivialVariables: MutableSet<VariableDescriptor>,
valsWithTrivialInitializer: MutableSet<VariableDescriptor>
) {
getUpperLevelDeclaredVariables(pseudocode).let {
nonTrivialVariables.addAll(it.nonTrivialVariables)
valsWithTrivialInitializer.addAll(it.valsWithTrivialInitializer)
}
return declaredVariables
}
private fun computeDeclaredVariablesForPseudocode(pseudocode: Pseudocode): Set<VariableDescriptor> {
val declaredVariables = linkedSetOf<VariableDescriptor>()
private fun getUpperLevelDeclaredVariables(pseudocode: Pseudocode) = declaredVariablesForDeclaration.getOrPut(pseudocode) {
computeDeclaredVariablesForPseudocode(pseudocode)
}
private fun computeDeclaredVariablesForPseudocode(pseudocode: Pseudocode): VariablesForDeclaration {
val valsWithTrivialInitializer = linkedSetOf<VariableDescriptor>()
val nonTrivialVariables = linkedSetOf<VariableDescriptor>()
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<KtVariableDeclaration>()?.isVariableWithTrivialInitializer(descriptor) == true
private fun KtVariableDeclaration.isVariableWithTrivialInitializer(descriptor: VariableDescriptor): Boolean {
if (descriptor.isPropertyWithoutBackingField()) return true
if (isVar) return false
return initializer != null || safeAs<KtProperty>()?.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<Instruction, Edges<InitControlFlowInfo>> {
private fun computeVariableInitializers(): Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>> {
val blockScopeVariableInfo = pseudocodeVariableDataCollector.blockScopeVariableInfo
val resultForValsWithTrivialInitializer = computeInitInfoForTrivialVals()
if (rootVariables.nonTrivialVariables.isEmpty()) return resultForValsWithTrivialInitializer
return pseudocodeVariableDataCollector.collectData(TraversalOrder.FORWARD, InitControlFlowInfo()) {
instruction: Instruction, incomingEdgesData: Collection<InitControlFlowInfo> ->
@@ -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<Instruction, Edges<ReadOnlyInitControlFlowInfoImpl>> {
val result = hashMapOf<Instruction, Edges<ReadOnlyInitControlFlowInfoImpl>>()
var declaredSet = ImmutableHashSet.empty<VariableDescriptor>()
var initSet = ImmutableHashSet.empty<VariableDescriptor>()
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<VariableDescriptor>,
val initSet: ImmutableSet<VariableDescriptor>,
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<VariableDescriptor, VariableControlFlowState> {
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<Instruction, Edges<ReadOnlyUseControlFlowInfo>>
get() = pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) {
instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> ->
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<UseControlFlowInfo> ->
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<Instruction, Edges<ReadOnlyUseControlFlowInfoImpl>> {
val used = hashSetOf<VariableDescriptor>()
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<Instruction, Edges<ReadOnlyUseControlFlowInfoImpl>>()
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<VariableDescriptor>,
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<VariableDescriptor, VariableUseState> {
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
@@ -6,4 +6,4 @@ abstract class Abst {
abstract fun foo(x: Int = <!UNINITIALIZED_PARAMETER!>y<!>, y: Int = x)
}
<!NON_MEMBER_FUNCTION_NO_BODY!>fun extraDiagnostics(<!UNUSED_PARAMETER!>x<!>: Int = <!UNINITIALIZED_PARAMETER!>y<!>, <!UNUSED_PARAMETER!>y<!>: Int)<!>
<!NON_MEMBER_FUNCTION_NO_BODY!>fun extraDiagnostics(<!UNUSED_PARAMETER!>x<!>: Int = <!UNINITIALIZED_PARAMETER!>y<!>, y: Int)<!>
@@ -6,10 +6,10 @@ fun bar(x : Int = <!TYPE_MISMATCH!>""<!>, y : Int = x, <!UNUSED_PARAMETER!>z<!>
// KT-371 Resolve default parameters for constructors
class A(x : Int = <!UNINITIALIZED_PARAMETER!>y<!>, <!UNUSED_PARAMETER!>y<!> : Int = x) { // None of the references is resolved, no types checked
fun foo(<!UNUSED_PARAMETER!>bool<!>: Boolean, a: Int = <!TYPE_MISMATCH, UNINITIALIZED_PARAMETER!>b<!>, <!UNUSED_PARAMETER!>b<!>: String = <!TYPE_MISMATCH!>a<!>) {}
class A(x : Int = <!UNINITIALIZED_PARAMETER!>y<!>, y : Int = x) { // None of the references is resolved, no types checked
fun foo(<!UNUSED_PARAMETER!>bool<!>: Boolean, a: Int = <!TYPE_MISMATCH, UNINITIALIZED_PARAMETER!>b<!>, b: String = <!TYPE_MISMATCH!>a<!>) {}
}
val z = 3
fun foo(x: Int = <!UNINITIALIZED_PARAMETER!>y<!>, y: Int = x, <!UNUSED_PARAMETER!>i<!> : Int = z): Int = x + y
fun foo(x: Int = <!UNINITIALIZED_PARAMETER!>y<!>, y: Int = x, <!UNUSED_PARAMETER!>i<!> : Int = z): Int = x + y
+3 -3
View File
@@ -51,7 +51,7 @@ fun cannotBe() {
<!VARIABLE_EXPECTED!>5<!> = 34
}
fun canBe(i0: Int, j: Int) {
fun canBe(i0: Int, <!UNUSED_PARAMETER!>j<!>: Int) {
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>i<!> = i0
<!UNUSED_VALUE!>(label@ i) =<!> 34
@@ -61,7 +61,7 @@ fun canBe(i0: Int, j: Int) {
(l@ a.a) = 3894
}
fun canBe2(j: Int) {
fun canBe2(<!UNUSED_PARAMETER!>j<!>: Int) {
<!UNUSED_VALUE!>(label@ <!VAL_REASSIGNMENT!>j<!>) =<!> 34
}
@@ -140,4 +140,4 @@ fun Array<Int>.checkThis() {
abstract class Ab {
abstract fun getArray() : Array<Int>
}
}
@@ -53,7 +53,7 @@ fun t2() {
class A() {}
fun t4(a: A) {
fun t4(<!UNUSED_PARAMETER!>a<!>: A) {
<!UNUSED_VALUE!><!VAL_REASSIGNMENT!>a<!> =<!> A()
}
@@ -61,7 +61,7 @@ fun t4(a: A) {
// reassigned vals
fun t1() {
val <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>a<!> : Int = 1
val <!UNUSED_VARIABLE!>a<!> : Int = 1
<!UNUSED_VALUE!><!VAL_REASSIGNMENT!>a<!> =<!> 2
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>b<!> : Int = 1
@@ -83,7 +83,7 @@ enum class ProtocolState {
fun t3() {
val x: ProtocolState = ProtocolState.WAITING
<!VAL_REASSIGNMENT!>x<!> = x.signal()
<!UNUSED_VALUE!>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(<!UNUSED_PARAMETER!>a<!>: Int) {
<!UNUSED_VALUE!><!VAL_REASSIGNMENT!>a<!> =<!> 1
}
@@ -345,4 +345,4 @@ fun test(m : M) {
fun test1(m : M) {
<!VAL_REASSIGNMENT!>m.x<!>++
m.y--
}
}
@@ -2,5 +2,5 @@ fun test(cond1: Boolean) {
do {
if (cond1) continue
val cond2 = false
} while (<!UNINITIALIZED_VARIABLE!>cond2<!>) // cond2 may be not defined here
} while (cond2) // cond2 may be not defined here
}
@@ -4,7 +4,7 @@ package kt897
class A() {
init {
<!INITIALIZATION_BEFORE_DECLARATION!>i<!> = 11
i = 11
}
val i : Int? = null // must be an error
@@ -8,7 +8,7 @@ class A {
}
fun foo(list: List<A>) {
for (<!VAL_OR_VAR_ON_LOOP_PARAMETER!>var<!> (<!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>c1<!>, <!UNUSED_VARIABLE!>c2<!>, c3) in list) {
for (<!VAL_OR_VAR_ON_LOOP_PARAMETER!>var<!> (<!UNUSED_VARIABLE!>c1<!>, <!UNUSED_VARIABLE!>c2<!>, c3) in list) {
<!UNUSED_VALUE!><!VAL_REASSIGNMENT!>c1<!> =<!> 1
c3 + 1
}