FIR: fix class / constructor type parameter duplication
This commit is contained in:
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.fir.scopes.impl.lazyNestedClassifierScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeNullability
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.toFirSourceElement
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
@@ -77,23 +76,33 @@ class JavaSymbolProvider(
|
||||
}
|
||||
}
|
||||
|
||||
private fun JavaTypeParameter.toFirTypeParameter(javaTypeParameterStack: JavaTypeParameterStack): FirTypeParameterBuilder {
|
||||
javaTypeParameterStack.getBuilder(this)?.let { return it }
|
||||
private fun JavaTypeParameter.toFirTypeParameterSymbol(
|
||||
javaTypeParameterStack: JavaTypeParameterStack
|
||||
): Pair<FirTypeParameterSymbol, Boolean> {
|
||||
val stored = javaTypeParameterStack.safeGet(this)
|
||||
if (stored != null) return stored to true
|
||||
val firSymbol = FirTypeParameterSymbol()
|
||||
javaTypeParameterStack.add(this, firSymbol)
|
||||
return firSymbol to false
|
||||
}
|
||||
|
||||
private fun JavaTypeParameter.toFirTypeParameter(
|
||||
firSymbol: FirTypeParameterSymbol,
|
||||
javaTypeParameterStack: JavaTypeParameterStack
|
||||
): FirTypeParameter {
|
||||
return FirTypeParameterBuilder().apply {
|
||||
session = this@JavaSymbolProvider.session
|
||||
name = this@toFirTypeParameter.name
|
||||
this.session = this@JavaSymbolProvider.session
|
||||
this.name = this@toFirTypeParameter.name
|
||||
symbol = firSymbol
|
||||
variance = INVARIANT
|
||||
isReified = false
|
||||
}.also {
|
||||
javaTypeParameterStack.add(this, it)
|
||||
}
|
||||
addBounds(this@toFirTypeParameter, javaTypeParameterStack)
|
||||
}.build()
|
||||
}
|
||||
|
||||
private fun FirTypeParameterBuilder.addBounds(
|
||||
javaTypeParameter: JavaTypeParameter,
|
||||
stack: JavaTypeParameterStack,
|
||||
stack: JavaTypeParameterStack
|
||||
) {
|
||||
for (upperBound in javaTypeParameter.upperBounds) {
|
||||
bounds += upperBound.toFirResolvedTypeRef(
|
||||
@@ -107,14 +116,12 @@ class JavaSymbolProvider(
|
||||
}
|
||||
|
||||
private fun List<JavaTypeParameter>.convertTypeParameters(stack: JavaTypeParameterStack): List<FirTypeParameter> {
|
||||
return this
|
||||
.map { it.toFirTypeParameter(stack) }
|
||||
.mapIndexed { index, typeParameterBuilder ->
|
||||
if (typeParameterBuilder.bounds.isEmpty()) {
|
||||
typeParameterBuilder.addBounds(this[index], stack)
|
||||
}
|
||||
typeParameterBuilder.build()
|
||||
}
|
||||
return map { it.toFirTypeParameterSymbol(stack) }.mapIndexed { index, (symbol, initialized) ->
|
||||
// This nasty logic is required, because type parameter bound can refer other type parameter from the list
|
||||
// So we have to create symbols first, and type parameters themselves after them
|
||||
if (initialized) symbol.fir
|
||||
else this[index].toFirTypeParameter(symbol, stack)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getClassLikeSymbolByFqName(classId: ClassId): FirRegularClassSymbol? {
|
||||
|
||||
@@ -5,16 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.java
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.FirTypeParameterBuilder
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
|
||||
|
||||
internal class JavaTypeParameterStack {
|
||||
|
||||
private val typeParameterMap = mutableMapOf<JavaTypeParameter, FirTypeParameterBuilder>()
|
||||
private val typeParameterMap = mutableMapOf<JavaTypeParameter, FirTypeParameterSymbol>()
|
||||
|
||||
fun add(javaTypeParameter: JavaTypeParameter, firTypeParameterBuilder: FirTypeParameterBuilder) {
|
||||
typeParameterMap[javaTypeParameter] = firTypeParameterBuilder
|
||||
fun add(javaTypeParameter: JavaTypeParameter, symbol: FirTypeParameterSymbol) {
|
||||
typeParameterMap[javaTypeParameter] = symbol
|
||||
}
|
||||
|
||||
fun addStack(javaTypeParameterStack: JavaTypeParameterStack) {
|
||||
@@ -30,9 +29,7 @@ internal class JavaTypeParameterStack {
|
||||
?: throw IllegalArgumentException("Cannot find Java type parameter $javaTypeParameter in stack")
|
||||
}
|
||||
|
||||
fun safeGet(javaTypeParameter: JavaTypeParameter) = typeParameterMap[javaTypeParameter]?.symbol
|
||||
|
||||
fun getBuilder(javaTypeParameter: JavaTypeParameter) = typeParameterMap[javaTypeParameter]
|
||||
fun safeGet(javaTypeParameter: JavaTypeParameter) = typeParameterMap[javaTypeParameter]
|
||||
|
||||
companion object {
|
||||
val EMPTY: JavaTypeParameterStack = JavaTypeParameterStack()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
operator fun ArrayList<String>.get(index1: Int, index2: Int) = this[index1 + index2]
|
||||
operator fun ArrayList<String>.set(index1: Int, index2: Int, elem: String) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
operator fun HashMap<String, Int?>.set(index: String, elem: Int?) {
|
||||
this.put(index, elem)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
operator fun <K, V> MutableMap<K, V>.set(k : K, v : V) = put(k, v)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
|
||||
var result = "Fail"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
import java.util.AbstractList
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// WITH_RUNTIME
|
||||
class ArrayWrapper<T>() {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
fun box(): String {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Boolean>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
fun box(): String {
|
||||
val l = ArrayList<Int>()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
@@ -2,21 +2,21 @@ FILE fqName:<root> fileName:/genericSamProjectedOut.kt
|
||||
FUN name:test visibility:public modality:FINAL <> (a:example.SomeJavaClass<out kotlin.String>) returnType:kotlin.Unit
|
||||
VALUE_PARAMETER name:a index:0 type:example.SomeJavaClass<out kotlin.String>
|
||||
BLOCK_BODY
|
||||
CALL 'public open fun someFunction (hello: example.Hello<kotlin.String?>?): kotlin.Unit declared in example.SomeJavaClass' type=kotlin.Unit origin=null
|
||||
CALL 'public open fun someFunction (hello: example.Hello<A of example.SomeJavaClass?>?): kotlin.Unit declared in example.SomeJavaClass' type=kotlin.Unit origin=null
|
||||
$this: GET_VAR 'a: example.SomeJavaClass<out kotlin.String> declared in <root>.test' type=example.SomeJavaClass<out kotlin.String> origin=null
|
||||
hello: FUN_EXPR type=kotlin.Function1<kotlin.String?, kotlin.Unit> origin=LAMBDA
|
||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.String?) returnType:kotlin.Unit
|
||||
VALUE_PARAMETER name:it index:0 type:kotlin.String?
|
||||
BLOCK_BODY
|
||||
GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
|
||||
CALL 'public open fun plus (hello: example.Hello<kotlin.String?>?): kotlin.Unit [operator] declared in example.SomeJavaClass' type=kotlin.Unit origin=null
|
||||
CALL 'public open fun plus (hello: example.Hello<A of example.SomeJavaClass?>?): kotlin.Unit [operator] declared in example.SomeJavaClass' type=kotlin.Unit origin=null
|
||||
$this: GET_VAR 'a: example.SomeJavaClass<out kotlin.String> declared in <root>.test' type=example.SomeJavaClass<out kotlin.String> origin=null
|
||||
hello: FUN_EXPR type=kotlin.Function1<kotlin.String?, kotlin.Unit> origin=LAMBDA
|
||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.String?) returnType:kotlin.Unit
|
||||
VALUE_PARAMETER name:it index:0 type:kotlin.String?
|
||||
BLOCK_BODY
|
||||
GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
|
||||
CALL 'public open fun get (hello: example.Hello<kotlin.String?>?): kotlin.Unit [operator] declared in example.SomeJavaClass' type=kotlin.Unit origin=null
|
||||
CALL 'public open fun get (hello: example.Hello<A of example.SomeJavaClass?>?): kotlin.Unit [operator] declared in example.SomeJavaClass' type=kotlin.Unit origin=null
|
||||
$this: GET_VAR 'a: example.SomeJavaClass<out kotlin.String> declared in <root>.test' type=example.SomeJavaClass<out kotlin.String> origin=null
|
||||
hello: FUN_EXPR type=kotlin.Function1<kotlin.String?, kotlin.Unit> origin=LAMBDA
|
||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.String?) returnType:kotlin.Unit
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ FILE fqName:<root> fileName:/samConversionInGenericConstructorCall.kt
|
||||
VALUE_PARAMETER name:f index:0 type:kotlin.Function1<kotlin.String, kotlin.String>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test1 (f: kotlin.Function1<kotlin.String, kotlin.String>): <root>.C<kotlin.String?> declared in <root>'
|
||||
CONSTRUCTOR_CALL 'public constructor <init> (jxx: <root>.J<X of <uninitialized parent>?, X of <uninitialized parent>?>?) declared in <root>.C' type=<root>.C<kotlin.String?> origin=null
|
||||
CONSTRUCTOR_CALL 'public constructor <init> (jxx: <root>.J<X of <root>.C?, X of <root>.C?>?) declared in <root>.C' type=<root>.C<kotlin.String?> origin=null
|
||||
<class: X>: kotlin.String?
|
||||
jxx: GET_VAR 'f: kotlin.Function1<kotlin.String, kotlin.String> declared in <root>.test1' type=kotlin.Function1<kotlin.String, kotlin.String> origin=null
|
||||
FUN name:test2 visibility:public modality:FINAL <> (x:kotlin.Any) returnType:kotlin.Unit
|
||||
@@ -11,7 +11,7 @@ FILE fqName:<root> fileName:/samConversionInGenericConstructorCall.kt
|
||||
BLOCK_BODY
|
||||
TYPE_OP type=kotlin.Function1<kotlin.String, kotlin.String> origin=CAST typeOperand=kotlin.Function1<kotlin.String, kotlin.String>
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test2' type=kotlin.Any origin=null
|
||||
CONSTRUCTOR_CALL 'public constructor <init> (jxx: <root>.J<X of <uninitialized parent>?, X of <uninitialized parent>?>?) declared in <root>.C' type=<root>.C<kotlin.String?> origin=null
|
||||
CONSTRUCTOR_CALL 'public constructor <init> (jxx: <root>.J<X of <root>.C?, X of <root>.C?>?) declared in <root>.C' type=<root>.C<kotlin.String?> origin=null
|
||||
<class: X>: kotlin.String?
|
||||
jxx: TYPE_OP type=kotlin.Function1<kotlin.String, kotlin.String> origin=IMPLICIT_CAST typeOperand=kotlin.Function1<kotlin.String, kotlin.String>
|
||||
GET_VAR 'x: kotlin.Any declared in <root>.test2' type=kotlin.Any origin=null
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@ FILE fqName:<root> fileName:/builtinMap.kt
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CALL 'public final fun apply <T> (block: kotlin.Function1<T of kotlin.apply, kotlin.Unit>): T of kotlin.apply [inline] declared in kotlin' type=java.util.LinkedHashMap<K1 of <root>.plus?, V1 of <root>.plus?> origin=null
|
||||
<T>: java.util.LinkedHashMap<K1 of <root>.plus?, V1 of <root>.plus?>
|
||||
$receiver: CONSTRUCTOR_CALL 'public constructor <init> (p0: kotlin.collections.Map<out K of <uninitialized parent>?, out V of <uninitialized parent>?>?) declared in java.util.LinkedHashMap' type=java.util.LinkedHashMap<K1 of <root>.plus?, V1 of <root>.plus?> origin=null
|
||||
$receiver: CONSTRUCTOR_CALL 'public constructor <init> (p0: kotlin.collections.Map<out K of java.util.LinkedHashMap?, out V of java.util.LinkedHashMap?>?) declared in java.util.LinkedHashMap' type=java.util.LinkedHashMap<K1 of <root>.plus?, V1 of <root>.plus?> origin=null
|
||||
<class: K>: K1 of <root>.plus?
|
||||
<class: V>: V1 of <root>.plus?
|
||||
p0: GET_VAR '<this>: kotlin.collections.Map<out K1 of <root>.plus, V1 of <root>.plus> declared in <root>.plus' type=kotlin.collections.Map<out K1 of <root>.plus, V1 of <root>.plus> origin=null
|
||||
@@ -27,9 +27,9 @@ FILE fqName:<root> fileName:/builtinMap.kt
|
||||
$receiver: VALUE_PARAMETER name:<this> type:java.util.LinkedHashMap<K1 of <root>.plus?, V1 of <root>.plus?>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): kotlin.Unit declared in <root>.plus'
|
||||
CALL 'public open fun put (p0: K1 of <root>.plus?, p1: V1 of <root>.plus?): V1 of <root>.plus? declared in java.util.LinkedHashMap' type=V1 of <root>.plus? origin=null
|
||||
CALL 'public open fun put (p0: K of java.util.LinkedHashMap?, p1: V of java.util.LinkedHashMap?): V of java.util.LinkedHashMap? declared in java.util.LinkedHashMap' type=V1 of <root>.plus? origin=null
|
||||
$this: GET_VAR '<this>: java.util.LinkedHashMap<K1 of <root>.plus?, V1 of <root>.plus?> declared in special.<anonymous>' type=java.util.LinkedHashMap<K1 of <root>.plus?, V1 of <root>.plus?> origin=null
|
||||
p0: CALL 'public final fun <get-first> (): K1 of <root>.plus declared in kotlin.Pair' type=K1 of <root>.plus origin=GET_PROPERTY
|
||||
p0: CALL 'public final fun <get-first> (): A of kotlin.Pair declared in kotlin.Pair' type=K1 of <root>.plus origin=GET_PROPERTY
|
||||
$this: GET_VAR 'pair: kotlin.Pair<K1 of <root>.plus, V1 of <root>.plus> declared in <root>.plus' type=kotlin.Pair<K1 of <root>.plus, V1 of <root>.plus> origin=null
|
||||
p1: CALL 'public final fun <get-second> (): V1 of <root>.plus declared in kotlin.Pair' type=V1 of <root>.plus origin=GET_PROPERTY
|
||||
p1: CALL 'public final fun <get-second> (): B of kotlin.Pair declared in kotlin.Pair' type=V1 of <root>.plus origin=GET_PROPERTY
|
||||
$this: GET_VAR 'pair: kotlin.Pair<K1 of <root>.plus, V1 of <root>.plus> declared in <root>.plus' type=kotlin.Pair<K1 of <root>.plus, V1 of <root>.plus> origin=null
|
||||
|
||||
Reference in New Issue
Block a user