FIR: support varargs in resolve
This commit is contained in:
committed by
Mikhail Glukhikh
parent
fa135bbab0
commit
9dcf8f836a
@@ -13,6 +13,7 @@ object StandardClassIds {
|
||||
|
||||
private val BASE_KOTLIN_PACKAGE = FqName("kotlin")
|
||||
private fun String.baseId() = ClassId(BASE_KOTLIN_PACKAGE, Name.identifier(this))
|
||||
private fun Name.arrayId() = ClassId(Array.packageFqName, Name.identifier(identifier + Array.shortClassName.identifier))
|
||||
|
||||
val Nothing = "Nothing".baseId()
|
||||
val Unit = "Unit".baseId()
|
||||
@@ -25,14 +26,29 @@ object StandardClassIds {
|
||||
val Char = "Char".baseId()
|
||||
val Byte = "Byte".baseId()
|
||||
val Short = "Short".baseId()
|
||||
|
||||
val Int = "Int".baseId()
|
||||
val Long = "Long".baseId()
|
||||
|
||||
val String = "String".baseId()
|
||||
|
||||
val Float = "Float".baseId()
|
||||
val Double = "Double".baseId()
|
||||
|
||||
val String = "String".baseId()
|
||||
|
||||
fun byName(name: String) = name.baseId()
|
||||
|
||||
val primitiveArrayTypeByElementType: Map<ClassId, ClassId> = mutableMapOf<ClassId, ClassId>().apply {
|
||||
fun addPrimitive(id: ClassId) {
|
||||
put(id, id.shortClassName.arrayId())
|
||||
}
|
||||
|
||||
addPrimitive(Boolean)
|
||||
addPrimitive(Char)
|
||||
addPrimitive(Byte)
|
||||
addPrimitive(Short)
|
||||
addPrimitive(Int)
|
||||
addPrimitive(Long)
|
||||
addPrimitive(Float)
|
||||
addPrimitive(Double)
|
||||
}
|
||||
|
||||
val elementTypeByPrimitiveArrayType = primitiveArrayTypeByElementType.map { (k, v) -> v to k }.toMap()
|
||||
}
|
||||
@@ -5,9 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.withNullability
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
@@ -118,7 +120,7 @@ internal fun Candidate.resolveArgument(
|
||||
sink: CheckerSink
|
||||
) {
|
||||
|
||||
val expectedType = prepareExpectedType(argument, parameter)
|
||||
val expectedType = prepareExpectedType(sink.components.session, argument, parameter)
|
||||
resolveArgumentExpression(
|
||||
this.system.getBuilder(),
|
||||
argument,
|
||||
@@ -131,14 +133,26 @@ internal fun Candidate.resolveArgument(
|
||||
)
|
||||
}
|
||||
|
||||
private fun Candidate.prepareExpectedType(argument: FirExpression, parameter: FirValueParameter): ConeKotlinType {
|
||||
val expectedType = argument.getExpectedType(parameter/*, LanguageVersionSettings*/)
|
||||
private fun Candidate.prepareExpectedType(session: FirSession, argument: FirExpression, parameter: FirValueParameter): ConeKotlinType {
|
||||
val expectedType = argument.getExpectedType(session, parameter/*, LanguageVersionSettings*/)
|
||||
return this.substitutor.substituteOrSelf(expectedType)
|
||||
}
|
||||
|
||||
internal fun FirExpression.getExpectedType(parameter: FirValueParameter/*, languageVersionSettings: LanguageVersionSettings*/) =
|
||||
internal fun FirExpression.getExpectedType(
|
||||
session: FirSession,
|
||||
parameter: FirValueParameter/*, languageVersionSettings: LanguageVersionSettings*/
|
||||
) =
|
||||
// if (this.isSpread || this.isArrayAssignedAsNamedArgumentInAnnotation(parameter, languageVersionSettings)) {
|
||||
// parameter.type.unwrap()
|
||||
// } else {
|
||||
parameter.returnTypeRef.coneTypeUnsafe()//?.varargElementType?.unwrap() ?: parameter.type.unwrap()
|
||||
// }
|
||||
if (parameter.isVararg) {
|
||||
parameter.returnTypeRef.coneTypeUnsafe().varargElementType(session)
|
||||
} else {
|
||||
parameter.returnTypeRef.coneTypeUnsafe()
|
||||
}//?.varargElementType?.unwrap() ?: parameter.type.unwrap()
|
||||
// }
|
||||
|
||||
|
||||
private fun ConeKotlinType.varargElementType(session: FirSession): ConeKotlinType {
|
||||
return this.arrayElementType(session) ?: error("Failed to extract! ${this.render()}!")
|
||||
}
|
||||
@@ -47,10 +47,11 @@ class CallInfo(
|
||||
|
||||
interface CheckerSink {
|
||||
fun reportApplicability(new: CandidateApplicability)
|
||||
val components: InferenceComponents
|
||||
}
|
||||
|
||||
|
||||
class CheckerSinkImpl : CheckerSink {
|
||||
class CheckerSinkImpl(override val components: InferenceComponents) : CheckerSink {
|
||||
var current = CandidateApplicability.RESOLVED
|
||||
override fun reportApplicability(new: CandidateApplicability) {
|
||||
if (new < current) current = new
|
||||
@@ -452,12 +453,14 @@ class NoExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
|
||||
}
|
||||
|
||||
class CallResolver(val typeCalculator: ReturnTypeCalculator, val session: FirSession) {
|
||||
class CallResolver(val typeCalculator: ReturnTypeCalculator, val components: InferenceComponents) {
|
||||
|
||||
var callInfo: CallInfo? = null
|
||||
|
||||
var scopes: List<FirScope>? = null
|
||||
|
||||
val session: FirSession get() = components.session
|
||||
|
||||
private fun processImplicitReceiver(
|
||||
towerDataConsumer: TowerDataConsumer,
|
||||
implicitReceiverValue: ImplicitReceiverValue,
|
||||
@@ -471,7 +474,7 @@ class CallResolver(val typeCalculator: ReturnTypeCalculator, val session: FirSes
|
||||
}
|
||||
|
||||
fun runTowerResolver(towerDataConsumer: TowerDataConsumer, implicitReceiverValues: List<ImplicitReceiverValue>): CandidateCollector {
|
||||
val collector = CandidateCollector(callInfo!!)
|
||||
val collector = CandidateCollector(callInfo!!, components)
|
||||
|
||||
var group = 0
|
||||
|
||||
@@ -510,7 +513,7 @@ enum class CandidateApplicability {
|
||||
RESOLVED
|
||||
}
|
||||
|
||||
class CandidateCollector(val callInfo: CallInfo) {
|
||||
class CandidateCollector(val callInfo: CallInfo, val components: InferenceComponents) {
|
||||
|
||||
val groupNumbers = mutableListOf<Int>()
|
||||
val candidates = mutableListOf<Candidate>()
|
||||
@@ -530,7 +533,7 @@ class CandidateCollector(val callInfo: CallInfo) {
|
||||
candidate: Candidate
|
||||
): CandidateApplicability {
|
||||
|
||||
val sink = CheckerSinkImpl()
|
||||
val sink = CheckerSinkImpl(components)
|
||||
|
||||
|
||||
callInfo.callKind.sequence().forEach {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.symbols.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
@@ -44,7 +45,7 @@ open class ConeTypeVariable(name: String) : TypeVariableMarker {
|
||||
val defaultType = ConeTypeVariableType(ConeNullability.NOT_NULL, typeConstructor)
|
||||
}
|
||||
|
||||
class InferenceComponents(val ctx: TypeSystemInferenceExtensionContextDelegate) {
|
||||
class InferenceComponents(val ctx: TypeSystemInferenceExtensionContextDelegate, val session: FirSession) {
|
||||
private val approximator = object : AbstractTypeApproximator(ctx) {
|
||||
override fun createErrorType(message: String): SimpleTypeMarker {
|
||||
return ConeClassErrorType(message)
|
||||
|
||||
+3
-3
@@ -35,7 +35,7 @@ interface LambdaAnalyzer {
|
||||
class PostponedArgumentsAnalyzer(
|
||||
val lambdaAnalyzer: LambdaAnalyzer,
|
||||
val typeProvider: (FirExpression) -> FirTypeRef?,
|
||||
val session: FirSession
|
||||
val components: InferenceComponents
|
||||
) {
|
||||
|
||||
fun analyze(
|
||||
@@ -68,7 +68,7 @@ class PostponedArgumentsAnalyzer(
|
||||
lambda: ResolvedLambdaAtom//,
|
||||
//diagnosticHolder: KotlinDiagnosticsHolder
|
||||
) {
|
||||
val unitType = Unit(session.service()).constructType(emptyArray(), false)
|
||||
val unitType = Unit(components.session.service()).constructType(emptyArray(), false)
|
||||
val stubsForPostponedVariables = c.bindingStubsForPostponedVariables()
|
||||
val currentSubstitutor = c.buildCurrentSubstitutor(stubsForPostponedVariables.mapKeys { it.key.freshTypeConstructor(c) })
|
||||
|
||||
@@ -98,7 +98,7 @@ class PostponedArgumentsAnalyzer(
|
||||
|
||||
returnArguments.forEach { c.addSubsystemFromExpression(it) }
|
||||
|
||||
val checkerSink: CheckerSink = CheckerSinkImpl()
|
||||
val checkerSink: CheckerSink = CheckerSinkImpl(components)
|
||||
|
||||
val subResolvedKtPrimitives = returnArguments.map {
|
||||
var atom: PostponedResolvedAtomMarker? = null
|
||||
|
||||
+5
-5
@@ -192,7 +192,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
override fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker {
|
||||
return this
|
||||
}
|
||||
})
|
||||
}, session)
|
||||
|
||||
private fun <T : FirQualifiedAccess> transformCallee(qualifiedAccess: T): T {
|
||||
val callee = qualifiedAccess.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccess
|
||||
@@ -200,7 +200,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
val receiver = qualifiedAccess.explicitReceiver?.transformSingle(this, noExpectedType)
|
||||
|
||||
val info = CallInfo(CallKind.VariableAccess, receiver, emptyList(), emptyList()) { it.resultType }
|
||||
val resolver = CallResolver(jump, session)
|
||||
val resolver = CallResolver(jump, inferenceComponents)
|
||||
resolver.callInfo = info
|
||||
resolver.scopes = (scopes + localScopes).asReversed()
|
||||
|
||||
@@ -304,7 +304,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
val typeArguments = functionCall.typeArguments
|
||||
|
||||
val info = CallInfo(CallKind.Function, explicitReceiver, arguments, typeArguments) { it.resultType }
|
||||
val resolver = CallResolver(jump, session)
|
||||
val resolver = CallResolver(jump, inferenceComponents)
|
||||
resolver.callInfo = info
|
||||
resolver.scopes = (scopes + localScopes).asReversed()
|
||||
|
||||
@@ -416,7 +416,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
return listOfNotNull(newLambdaExpression.body?.statements?.lastOrNull() as? FirExpression) to InferenceSession.default
|
||||
}
|
||||
|
||||
}, { it.resultType }, session)
|
||||
}, { it.resultType }, inferenceComponents)
|
||||
|
||||
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(functionCall), initialType) {
|
||||
analyzer.analyze(
|
||||
@@ -813,7 +813,7 @@ private object StoreNameReference : FirTransformer<FirNamedReference>() {
|
||||
}
|
||||
}
|
||||
|
||||
private object StoreType : FirTransformer<FirResolvedTypeRef>() {
|
||||
internal object StoreType : FirTransformer<FirResolvedTypeRef>() {
|
||||
override fun <E : FirElement> transformElement(element: E, data: FirResolvedTypeRef): CompositeTransformResult<E> {
|
||||
return element.compose()
|
||||
}
|
||||
|
||||
+21
@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
||||
import org.jetbrains.kotlin.fir.types.createArrayOf
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
|
||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||
import org.jetbrains.kotlin.fir.visitors.compose
|
||||
@@ -87,4 +89,23 @@ open class FirTypeResolveTransformer : FirAbstractTreeTransformerWithSuperTypes(
|
||||
override fun transformTypeRef(typeRef: FirTypeRef, data: Nothing?): CompositeTransformResult<FirTypeRef> {
|
||||
return FirSpecificTypeResolverTransformer(towerScope, FirPosition.OTHER, session).transformTypeRef(typeRef, data)
|
||||
}
|
||||
|
||||
override fun transformValueParameter(valueParameter: FirValueParameter, data: Nothing?): CompositeTransformResult<FirDeclaration> {
|
||||
|
||||
val valueParameter = super.transformValueParameter(valueParameter, data).single as FirValueParameter
|
||||
|
||||
if (valueParameter.isVararg) {
|
||||
val returnTypeRef = valueParameter.returnTypeRef
|
||||
val returnType = returnTypeRef.coneTypeUnsafe()
|
||||
valueParameter.transformReturnTypeRef(
|
||||
StoreType,
|
||||
valueParameter.returnTypeRef.withReplacedConeType(
|
||||
session,
|
||||
returnType.createArrayOf(session)
|
||||
)
|
||||
)
|
||||
}
|
||||
return valueParameter.compose()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.types
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.constructType
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.symbols.invoke
|
||||
|
||||
|
||||
fun ConeKotlinType.createArrayOf(session: FirSession, nullable: Boolean = false): ConeKotlinType {
|
||||
val symbolProvider: FirSymbolProvider = session.service()
|
||||
if (this is ConeClassType) {
|
||||
val primitiveArrayId = StandardClassIds.primitiveArrayTypeByElementType[lookupTag.classId]
|
||||
if (primitiveArrayId != null) {
|
||||
return primitiveArrayId.invoke(symbolProvider).constructType(emptyArray(), nullable)
|
||||
}
|
||||
}
|
||||
|
||||
return StandardClassIds.Array.invoke(symbolProvider).constructType(arrayOf(this), nullable)
|
||||
}
|
||||
|
||||
|
||||
fun ConeKotlinType.arrayElementType(session: FirSession): ConeKotlinType? {
|
||||
if (this !is ConeClassType) return null
|
||||
val classId = this.lookupTag.classId
|
||||
if (classId == StandardClassIds.Array)
|
||||
return (typeArguments.first() as ConeTypedProjection).type
|
||||
val elementType = StandardClassIds.elementTypeByPrimitiveArrayType[classId]
|
||||
if (elementType != null) {
|
||||
return elementType.invoke(session.service()).constructType(emptyArray(), isNullable = false)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -3,7 +3,7 @@ FILE: default.kt
|
||||
}
|
||||
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 baz(x: R|kotlin/Int|, vararg y: R|kotlin/Array<kotlin/String>|, z: R|kotlin/Boolean| = Boolean(false)): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
R|/foo|(Int(1))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FILE: vararg.kt
|
||||
public final fun foo(x: R|kotlin/Int|, vararg y: R|kotlin/String|): R|kotlin/Unit| {
|
||||
public final fun foo(x: R|kotlin/Int|, vararg y: R|kotlin/Array<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 bar(x: R|kotlin/Int|, vararg y: R|kotlin/Array<kotlin/String>|, z: R|kotlin/Boolean|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
R|/foo|(Int(1))
|
||||
@@ -9,7 +9,7 @@ FILE: vararg.kt
|
||||
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)))
|
||||
R|/bar|(Int(1), z = Boolean(true), y = R|kotlin/arrayOf|<R|TypeVariable(T)|>(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))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fun foo(vararg x: String) {}
|
||||
|
||||
fun foo() {}
|
||||
|
||||
fun main() {
|
||||
foo()
|
||||
foo("!")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
FILE: vararg.kt
|
||||
public final fun foo(vararg x: R|kotlin/Array<kotlin/String>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun main(): R|kotlin/Unit| {
|
||||
R|/foo|()
|
||||
R|/foo|(String(!))
|
||||
}
|
||||
+5
@@ -257,6 +257,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/this.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("vararg.kt")
|
||||
public void testVararg() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/vararg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("when.kt")
|
||||
public void testWhen() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/when.kt");
|
||||
|
||||
Reference in New Issue
Block a user