FIR resolve: introduce argument mapper
This commit is contained in:
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.renderWithType
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
@@ -41,7 +42,7 @@ class CallInfo(
|
||||
|
||||
val typeProvider: (FirExpression) -> FirTypeRef?
|
||||
) {
|
||||
|
||||
val argumentCount get() = arguments.size
|
||||
}
|
||||
|
||||
interface CheckerSink {
|
||||
@@ -69,6 +70,8 @@ class Candidate(
|
||||
system
|
||||
}
|
||||
lateinit var substitutor: ConeSubstitutor
|
||||
|
||||
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
|
||||
}
|
||||
|
||||
sealed class CallKind {
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirLambdaArgumentExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
|
||||
class FirCallArgumentsProcessor(
|
||||
private val function: FirFunction,
|
||||
private val arguments: List<FirExpression>
|
||||
) {
|
||||
class Result(val argumentMapping: Map<FirExpression, FirValueParameter>, val isSuccess: Boolean)
|
||||
|
||||
fun process(): Result {
|
||||
var currentState: State = State.PositionalOnly(function.valueParameters)
|
||||
for (argument in arguments) {
|
||||
if (argument is FirWrappedArgumentExpression) {
|
||||
currentState = State.PositionalThenNamed(
|
||||
function.valueParameters,
|
||||
currentState.argumentMap,
|
||||
currentState.usedParameters
|
||||
)
|
||||
}
|
||||
val status = currentState.processArgument(argument)
|
||||
if (status != MappingStatus.SUCCESS) {
|
||||
// unmapped argument
|
||||
return Result(currentState.argumentMap, isSuccess = false)
|
||||
}
|
||||
}
|
||||
|
||||
for (valueParameter in function.valueParameters) {
|
||||
if (valueParameter !in currentState.usedParameters && !valueParameter.isVararg && valueParameter.defaultValue == null) {
|
||||
// unmapped parameter
|
||||
return Result(currentState.argumentMap, isSuccess = false)
|
||||
}
|
||||
}
|
||||
return Result(currentState.argumentMap, isSuccess = currentState.argumentMap.size == arguments.size)
|
||||
}
|
||||
|
||||
private enum class MappingStatus {
|
||||
SUCCESS,
|
||||
ERROR
|
||||
}
|
||||
|
||||
private sealed class State(
|
||||
val valueParameters: List<FirValueParameter>,
|
||||
val argumentMap: MutableMap<FirExpression, FirValueParameter> = mutableMapOf(),
|
||||
val usedParameters: MutableSet<FirValueParameter> = mutableSetOf()
|
||||
) {
|
||||
abstract fun processArgument(argument: FirExpression): MappingStatus
|
||||
|
||||
class PositionalOnly(valueParameters: List<FirValueParameter>) : State(valueParameters) {
|
||||
var currentParameterIndex: Int = 0
|
||||
|
||||
val currentParameter get() = valueParameters.getOrNull(currentParameterIndex)
|
||||
|
||||
fun nextParameter() {
|
||||
val currentParameter = currentParameter ?: return
|
||||
if (currentParameter.isVararg) return
|
||||
usedParameters += currentParameter
|
||||
currentParameterIndex++
|
||||
}
|
||||
|
||||
override fun processArgument(argument: FirExpression): MappingStatus {
|
||||
require(argument !is FirNamedArgumentExpression) {
|
||||
"Positional-only argument processor state should not receiver ${argument.render()}"
|
||||
}
|
||||
|
||||
val currentParameter = currentParameter ?: return MappingStatus.ERROR
|
||||
argumentMap[argument] = currentParameter
|
||||
nextParameter()
|
||||
|
||||
return MappingStatus.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
class PositionalThenNamed(
|
||||
valueParameters: List<FirValueParameter>,
|
||||
argumentMap: MutableMap<FirExpression, FirValueParameter>,
|
||||
usedParameters: MutableSet<FirValueParameter>
|
||||
) : State(valueParameters, argumentMap, usedParameters) {
|
||||
val nameToParameter = valueParameters.associateBy { it.name }
|
||||
|
||||
private fun map(parameter: FirValueParameter, argument: FirExpression): MappingStatus {
|
||||
if (parameter in usedParameters) return MappingStatus.ERROR
|
||||
argumentMap[argument] = parameter
|
||||
usedParameters += parameter
|
||||
return MappingStatus.SUCCESS
|
||||
}
|
||||
|
||||
override fun processArgument(argument: FirExpression): MappingStatus {
|
||||
when (argument) {
|
||||
is FirNamedArgumentExpression -> {
|
||||
val name = argument.name
|
||||
val parameter = nameToParameter[name] ?: return MappingStatus.ERROR
|
||||
return map(parameter, argument)
|
||||
}
|
||||
is FirLambdaArgumentExpression -> {
|
||||
val lastParameter = valueParameters.lastOrNull() ?: return MappingStatus.ERROR
|
||||
return map(lastParameter, argument)
|
||||
}
|
||||
else -> {
|
||||
return MappingStatus.ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.calls
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
|
||||
abstract class ResolutionStage {
|
||||
@@ -19,7 +20,11 @@ abstract class CheckerStage : ResolutionStage()
|
||||
internal object MapArguments : ResolutionStage() {
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val symbol = candidate.symbol as? FirFunctionSymbol ?: return sink.reportApplicability(CandidateApplicability.HIDDEN)
|
||||
if (symbol.firUnsafe<FirFunction>().valueParameters.size != callInfo.arguments.size) {
|
||||
val function = symbol.firUnsafe<FirFunction>()
|
||||
val processor = FirCallArgumentsProcessor(function, callInfo.arguments)
|
||||
val mappingResult = processor.process()
|
||||
candidate.argumentMapping = mappingResult.argumentMapping
|
||||
if (!mappingResult.isSuccess) {
|
||||
return sink.reportApplicability(CandidateApplicability.PARAMETER_MAPPING_ERROR)
|
||||
}
|
||||
}
|
||||
@@ -28,10 +33,9 @@ internal object MapArguments : ResolutionStage() {
|
||||
|
||||
internal object CheckArguments : CheckerStage() {
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val symbol = candidate.symbol as? FirFunctionSymbol ?: error("Can't check arguments for non function")
|
||||
val declaration = symbol.fir as FirFunction
|
||||
for ((parameter, argument) in declaration.valueParameters.zip(callInfo.arguments)) {
|
||||
|
||||
val argumentMapping =
|
||||
candidate.argumentMapping ?: throw IllegalStateException("Argument should be already mapped while checking arguments!")
|
||||
for ((argument, parameter) in argumentMapping) {
|
||||
candidate.resolveArgument(argument, parameter, isReceiver = false, typeProvider = callInfo.typeProvider, sink = sink)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
fun foo(first: Int, second: Double = 3.14, third: Boolean = false) {}
|
||||
fun bar(first: Int, second: Double = 2.71, third: Boolean, fourth: String = "") {}
|
||||
fun baz(x: Int, vararg y: String, z: Boolean = false) {}
|
||||
|
||||
fun test() {
|
||||
foo(1)
|
||||
foo(1, 2.0)
|
||||
foo(1, 2.0, true)
|
||||
foo(1, third = true)
|
||||
|
||||
foo()
|
||||
foo(0, 0.0, false, "")
|
||||
|
||||
bar(1, third = true)
|
||||
bar(1, 2.0, true)
|
||||
bar(1, 2.0, true, "my")
|
||||
|
||||
bar(1, true)
|
||||
|
||||
baz(1)
|
||||
baz(1, "my", "yours")
|
||||
baz(1, z = true)
|
||||
|
||||
baz(0, "", false)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
FILE: default.kt
|
||||
public final fun foo(first: R|kotlin/Int|, second: R|kotlin/Double| = Double(3.14), third: R|kotlin/Boolean| = Boolean(false)): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun bar(first: R|kotlin/Int|, second: R|kotlin/Double| = Double(2.71), third: R|kotlin/Boolean|, fourth: R|kotlin/String| = String()): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun baz(x: R|kotlin/Int|, vararg y: R|kotlin/String|, z: R|kotlin/Boolean| = Boolean(false)): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
R|/foo|(Int(1))
|
||||
R|/foo|(Int(1), Double(2.0))
|
||||
R|/foo|(Int(1), Double(2.0), Boolean(true))
|
||||
R|/foo|(Int(1), third = Boolean(true))
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#()
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(Int(0), Double(0.0), Boolean(false), String())
|
||||
R|/bar|(Int(1), third = Boolean(true))
|
||||
R|/bar|(Int(1), Double(2.0), Boolean(true))
|
||||
R|/bar|(Int(1), Double(2.0), Boolean(true), String(my))
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(Int(1), Boolean(true))
|
||||
R|/baz|(Int(1))
|
||||
R|/baz|(Int(1), String(my), String(yours))
|
||||
R|/baz|(Int(1), z = Boolean(true))
|
||||
<Inapplicable(INAPPLICABLE): [/baz]>#(Int(0), String(), Boolean(false))
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
fun foo(f: () -> Unit) {}
|
||||
fun bar(x: Int, f: () -> Unit) {}
|
||||
fun baz(f: () -> Unit, other: Boolean = true) {}
|
||||
|
||||
|
||||
fun test() {
|
||||
foo {}
|
||||
foo() {}
|
||||
foo({})
|
||||
|
||||
foo(1) {}
|
||||
foo(f = {}) {}
|
||||
|
||||
bar(1) {}
|
||||
bar(x = 1) {}
|
||||
bar(1, {})
|
||||
bar(x = 1, f = {})
|
||||
|
||||
bar {}
|
||||
bar({})
|
||||
|
||||
baz(other = false, f = {})
|
||||
baz({}, false)
|
||||
|
||||
baz {}
|
||||
baz() {}
|
||||
baz(other = false) {}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
FILE: lambda.kt
|
||||
public final fun foo(f: R|kotlin/Function0|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun bar(x: R|kotlin/Int|, f: R|kotlin/Function0|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun baz(f: R|kotlin/Function0|, other: R|kotlin/Boolean| = Boolean(true)): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
R|/foo|(<L> = foo@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/foo|(<L> = foo@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/foo|(foo@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(Int(1), <L> = foo@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(f = foo@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
, <L> = foo@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/bar|(Int(1), <L> = bar@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/bar|(x = Int(1), <L> = bar@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/bar|(Int(1), bar@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/bar|(x = Int(1), f = bar@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(<L> = bar@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(bar@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/baz|(other = Boolean(false), f = baz@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/baz|(baz@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
, Boolean(false))
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/baz]>#(<L> = baz@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/baz]>#(<L> = baz@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/baz]>#(other = Boolean(false), <L> = baz@fun <implicit>.<anonymous>(): <implicit> {
|
||||
^ {
|
||||
Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
fun foo(first: Int, second: Double, third: Boolean, fourth: String) {}
|
||||
|
||||
fun test() {
|
||||
foo(1, 2.0, true, "")
|
||||
foo(1, 2.0, true, fourth = "!")
|
||||
foo(1, 2.0, fourth = "???", third = false)
|
||||
foo(1, second = 3.14, third = false, fourth = "!?")
|
||||
foo(third = false, second = 2.71, fourth = "?!", first = 0)
|
||||
|
||||
foo()
|
||||
foo(0.0, false, 0, "")
|
||||
foo(1, 2.0, third = true, "")
|
||||
foo(second = 0.0, first = 0, fourth = "")
|
||||
foo(first = 0.0, second = 0, third = "", fourth = false)
|
||||
foo(first = 0, second = 0.0, third = false, fourth = "", first = 1)
|
||||
foo(0, 0.0, false, foth = "")
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
FILE: simple.kt
|
||||
public final fun foo(first: R|kotlin/Int|, second: R|kotlin/Double|, third: R|kotlin/Boolean|, fourth: R|kotlin/String|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
R|/foo|(Int(1), Double(2.0), Boolean(true), String())
|
||||
R|/foo|(Int(1), Double(2.0), Boolean(true), fourth = String(!))
|
||||
R|/foo|(Int(1), Double(2.0), fourth = String(???), third = Boolean(false))
|
||||
R|/foo|(Int(1), second = Double(3.14), third = Boolean(false), fourth = String(!?))
|
||||
R|/foo|(third = Boolean(false), second = Double(2.71), fourth = String(?!), first = Int(0))
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#()
|
||||
<Inapplicable(INAPPLICABLE): [/foo]>#(Double(0.0), Boolean(false), Int(0), String())
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(Int(1), Double(2.0), third = Boolean(true), String())
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(second = Double(0.0), first = Int(0), fourth = String())
|
||||
<Inapplicable(INAPPLICABLE): [/foo]>#(first = Double(0.0), second = Int(0), third = String(), fourth = Boolean(false))
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(first = Int(0), second = Double(0.0), third = Boolean(false), fourth = String(), first = Int(1))
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(Int(0), Double(0.0), Boolean(false), foth = String())
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
fun foo(x: Int, vararg y: String) {}
|
||||
fun bar(x: Int, vararg y: String, z: Boolean) {}
|
||||
|
||||
fun test() {
|
||||
foo(1)
|
||||
foo(1, "")
|
||||
foo(1, "my", "yours")
|
||||
|
||||
foo("")
|
||||
foo(1, 2)
|
||||
|
||||
bar(1, z = true, y = *arrayOf("my", "yours"))
|
||||
|
||||
bar(0, z = false, y = "", y = "other")
|
||||
bar(0, "", true)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
FILE: vararg.kt
|
||||
public final fun foo(x: R|kotlin/Int|, vararg y: R|kotlin/String|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun bar(x: R|kotlin/Int|, vararg y: R|kotlin/String|, z: R|kotlin/Boolean|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
R|/foo|(Int(1))
|
||||
R|/foo|(Int(1), String())
|
||||
R|/foo|(Int(1), String(my), String(yours))
|
||||
<Inapplicable(INAPPLICABLE): [/foo]>#(String())
|
||||
<Inapplicable(INAPPLICABLE): [/foo]>#(Int(1), Int(2))
|
||||
R|/bar|(Int(1), z = Boolean(true), y = <Inapplicable(INAPPLICABLE): [kotlin/arrayOf]>#(String(my), String(yours)))
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(Int(0), z = Boolean(false), y = String(), y = String(other))
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(Int(0), String(), Boolean(true))
|
||||
}
|
||||
@@ -37,7 +37,7 @@ FILE: simple.kt
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
R|/B.foo|()
|
||||
R|/B.bar|()
|
||||
<Ambiguity: buz, [/B.buz, /A.buz]>#()
|
||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/B.buz, /A.buz]>#()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+33
@@ -124,6 +124,39 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
||||
runTest("compiler/fir/resolve/testData/resolve/typeParameterVsNested.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/fir/resolve/testData/resolve/arguments")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Arguments extends AbstractFirResolveTestCase {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInArguments() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve/arguments"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("default.kt")
|
||||
public void testDefault() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/arguments/default.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lambda.kt")
|
||||
public void testLambda() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/arguments/lambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/arguments/simple.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("vararg.kt")
|
||||
public void testVararg() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/arguments/vararg.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/fir/resolve/testData/resolve/builtins")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user