KT-28456 generate index arguments per expression
In the desugaring for compound assignment to a collection element,
argument expression 'i' is mapped to value parameters 'iG' and 'iS' of
corresponding 'get' and 'set' operators.
In general, these value parameters can have different indices.
This requires extra machinery in argument generation - that is, to be
able to generate a particular expression argument using an arbitrary
callback. In the vast majority of the cases this callback will just use
the corresponding StatementGenerator to generate IR subtree for the
provided expression. In case of 'get' and 'set' operator calls for an
augmented assignment expression this will map corresponding argument
expressions to pregenerated temporary variables.
Thus, in the following context:
```
class A
operator fun A.get(vararg xs: Int) = 0
operator fun A.set(i: Int, j: Int, v: Int) {}
```
statement `a[1, 2] += 3` will be desugared as (in a really pseudo
Kotlin):
```
{
val tmp_array = a
val tmp_index0 = 1
val tmp_index1 = 2
tmp_array.set(
i = tmp_index0,
j = tmp_index1,
v = tmp_array.get(xs = [tmp_index0, tmp_index1]).plus(3)
)
}
```
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
class A
|
||||
|
||||
operator fun A.get(vararg xs: Int) = 0
|
||||
|
||||
operator fun A.set(i: Int, j: Int, v: Int) {}
|
||||
|
||||
fun testSimpleAssignment(a: A) {
|
||||
a[1, 2] = 0
|
||||
}
|
||||
|
||||
fun testPostfixIncrement(a: A) = a[1, 2]++
|
||||
|
||||
fun testCompoundAssignment(a: A) {
|
||||
a[1, 2] += 10
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
FILE fqName:<root> fileName:/kt28456.kt
|
||||
CLASS CLASS name:A modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:A flags:
|
||||
CONSTRUCTOR visibility:public <> () returnType:A flags:primary
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='A'
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any? flags:
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN name:get visibility:public modality:FINAL <> ($receiver:A, xs:kotlin.IntArray) returnType:kotlin.Int flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:A flags:
|
||||
VALUE_PARAMETER name:xs index:0 type:kotlin.IntArray varargElementType:kotlin.Int flags:vararg
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='get(vararg Int) on A: Int'
|
||||
CONST Int type=kotlin.Int value=0
|
||||
FUN name:set visibility:public modality:FINAL <> ($receiver:A, i:kotlin.Int, j:kotlin.Int, v:kotlin.Int) returnType:kotlin.Unit flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:A flags:
|
||||
VALUE_PARAMETER name:i index:0 type:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:j index:1 type:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:v index:2 type:kotlin.Int flags:
|
||||
BLOCK_BODY
|
||||
FUN name:testSimpleAssignment visibility:public modality:FINAL <> (a:A) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
CALL 'set(Int, Int, Int) on A: Unit' type=kotlin.Unit origin=EQ
|
||||
$receiver: GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
i: CONST Int type=kotlin.Int value=1
|
||||
j: CONST Int type=kotlin.Int value=2
|
||||
v: CONST Int type=kotlin.Int value=0
|
||||
FUN name:testPostfixIncrement visibility:public modality:FINAL <> (a:A) returnType:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='testPostfixIncrement(A): Int'
|
||||
BLOCK type=kotlin.Int origin=POSTFIX_INCR
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_array type:A flags:val
|
||||
GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp1_index0 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=1
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp2_index1 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=2
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp3 type:kotlin.Int flags:val
|
||||
CALL 'get(vararg Int) on A: Int' type=kotlin.Int origin=POSTFIX_INCR
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int
|
||||
GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
GET_VAR 'tmp2_index1: Int' type=kotlin.Int origin=null
|
||||
CALL 'set(Int, Int, Int) on A: Unit' type=kotlin.Unit origin=POSTFIX_INCR
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
j: GET_VAR 'tmp2_index1: Int' type=kotlin.Int origin=null
|
||||
v: CALL 'inc(): Int' type=kotlin.Int origin=POSTFIX_INCR
|
||||
$this: GET_VAR 'tmp3: Int' type=kotlin.Int origin=null
|
||||
GET_VAR 'tmp3: Int' type=kotlin.Int origin=null
|
||||
FUN name:testCompoundAssignment visibility:public modality:FINAL <> (a:A) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
BLOCK type=kotlin.Unit origin=PLUSEQ
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_array type:A flags:val
|
||||
GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp1_index0 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=1
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp2_index1 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=2
|
||||
CALL 'set(Int, Int, Int) on A: Unit' type=kotlin.Unit origin=PLUSEQ
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
j: GET_VAR 'tmp2_index1: Int' type=kotlin.Int origin=null
|
||||
v: CALL 'plus(Int): Int' type=kotlin.Int origin=PLUSEQ
|
||||
$this: CALL 'get(vararg Int) on A: Int' type=kotlin.Int origin=PLUSEQ
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int
|
||||
GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
GET_VAR 'tmp2_index1: Int' type=kotlin.Int origin=null
|
||||
other: CONST Int type=kotlin.Int value=10
|
||||
@@ -0,0 +1,7 @@
|
||||
class A
|
||||
|
||||
operator fun A.set(vararg i: Int, v: Int) {}
|
||||
|
||||
fun testSimpleAssignment(a: A) {
|
||||
a[1, 2, 3] = 0
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
FILE fqName:<root> fileName:/kt28456a.kt
|
||||
CLASS CLASS name:A modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:A flags:
|
||||
CONSTRUCTOR visibility:public <> () returnType:A flags:primary
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='A'
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any? flags:
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN name:set visibility:public modality:FINAL <> ($receiver:A, i:kotlin.IntArray, v:kotlin.Int) returnType:kotlin.Unit flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:A flags:
|
||||
VALUE_PARAMETER name:i index:0 type:kotlin.IntArray varargElementType:kotlin.Int flags:vararg
|
||||
VALUE_PARAMETER name:v index:1 type:kotlin.Int flags:
|
||||
BLOCK_BODY
|
||||
FUN name:testSimpleAssignment visibility:public modality:FINAL <> (a:A) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
CALL 'set(vararg Int, Int) on A: Unit' type=kotlin.Unit origin=EQ
|
||||
$receiver: GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
i: VARARG type=kotlin.IntArray varargElementType=kotlin.Int
|
||||
CONST Int type=kotlin.Int value=1
|
||||
CONST Int type=kotlin.Int value=2
|
||||
CONST Int type=kotlin.Int value=3
|
||||
v: CONST Int type=kotlin.Int value=0
|
||||
@@ -0,0 +1,15 @@
|
||||
class A
|
||||
|
||||
operator fun A.get(i: Int, a: Int = 1, b: Int = 2, c: Int = 3, d: Int = 4) = 0
|
||||
|
||||
operator fun A.set(i: Int, j: Int = 42, v: Int) {}
|
||||
|
||||
fun testSimpleAssignment(a: A) {
|
||||
a[1] = 0
|
||||
}
|
||||
|
||||
fun testPostfixIncrement(a: A) = a[1]++
|
||||
|
||||
fun testCompoundAssignment(a: A) {
|
||||
a[1] += 10
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
FILE fqName:<root> fileName:/kt28456b.kt
|
||||
CLASS CLASS name:A modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:A flags:
|
||||
CONSTRUCTOR visibility:public <> () returnType:A flags:primary
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='A'
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any? flags:
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN name:get visibility:public modality:FINAL <> ($receiver:A, i:kotlin.Int, a:kotlin.Int, b:kotlin.Int, c:kotlin.Int, d:kotlin.Int) returnType:kotlin.Int flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:A flags:
|
||||
VALUE_PARAMETER name:i index:0 type:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:a index:1 type:kotlin.Int flags:
|
||||
EXPRESSION_BODY
|
||||
CONST Int type=kotlin.Int value=1
|
||||
VALUE_PARAMETER name:b index:2 type:kotlin.Int flags:
|
||||
EXPRESSION_BODY
|
||||
CONST Int type=kotlin.Int value=2
|
||||
VALUE_PARAMETER name:c index:3 type:kotlin.Int flags:
|
||||
EXPRESSION_BODY
|
||||
CONST Int type=kotlin.Int value=3
|
||||
VALUE_PARAMETER name:d index:4 type:kotlin.Int flags:
|
||||
EXPRESSION_BODY
|
||||
CONST Int type=kotlin.Int value=4
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='get(Int, Int = ..., Int = ..., Int = ..., Int = ...) on A: Int'
|
||||
CONST Int type=kotlin.Int value=0
|
||||
FUN name:set visibility:public modality:FINAL <> ($receiver:A, i:kotlin.Int, j:kotlin.Int, v:kotlin.Int) returnType:kotlin.Unit flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:A flags:
|
||||
VALUE_PARAMETER name:i index:0 type:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:j index:1 type:kotlin.Int flags:
|
||||
EXPRESSION_BODY
|
||||
CONST Int type=kotlin.Int value=42
|
||||
VALUE_PARAMETER name:v index:2 type:kotlin.Int flags:
|
||||
BLOCK_BODY
|
||||
FUN name:testSimpleAssignment visibility:public modality:FINAL <> (a:A) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
CALL 'set(Int, Int = ..., Int) on A: Unit' type=kotlin.Unit origin=EQ
|
||||
$receiver: GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
i: CONST Int type=kotlin.Int value=1
|
||||
v: CONST Int type=kotlin.Int value=0
|
||||
FUN name:testPostfixIncrement visibility:public modality:FINAL <> (a:A) returnType:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='testPostfixIncrement(A): Int'
|
||||
BLOCK type=kotlin.Int origin=POSTFIX_INCR
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_array type:A flags:val
|
||||
GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp1_index0 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=1
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp2 type:kotlin.Int flags:val
|
||||
CALL 'get(Int, Int = ..., Int = ..., Int = ..., Int = ...) on A: Int' type=kotlin.Int origin=POSTFIX_INCR
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
CALL 'set(Int, Int = ..., Int) on A: Unit' type=kotlin.Unit origin=POSTFIX_INCR
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
v: CALL 'inc(): Int' type=kotlin.Int origin=POSTFIX_INCR
|
||||
$this: GET_VAR 'tmp2: Int' type=kotlin.Int origin=null
|
||||
GET_VAR 'tmp2: Int' type=kotlin.Int origin=null
|
||||
FUN name:testCompoundAssignment visibility:public modality:FINAL <> (a:A) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
BLOCK type=kotlin.Unit origin=PLUSEQ
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_array type:A flags:val
|
||||
GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp1_index0 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=1
|
||||
CALL 'set(Int, Int = ..., Int) on A: Unit' type=kotlin.Unit origin=PLUSEQ
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
v: CALL 'plus(Int): Int' type=kotlin.Int origin=PLUSEQ
|
||||
$this: CALL 'get(Int, Int = ..., Int = ..., Int = ..., Int = ...) on A: Int' type=kotlin.Int origin=PLUSEQ
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
other: CONST Int type=kotlin.Int value=10
|
||||
Reference in New Issue
Block a user