From fa7bd3dd2e5b230c5ec7cc763bbfe2c4ca374721 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 27 Nov 2019 15:24:43 +0300 Subject: [PATCH] FIR: Support SAM constructors for type aliases --- .../resolve/calls/ConstructorProcessing.kt | 112 ++++++++++++------ ...Comparator.kt => kotlinComparatorAlias.kt} | 2 +- ...mparator.txt => kotlinComparatorAlias.txt} | 4 +- ...FirDiagnosticsWithStdlibTestGenerated.java | 10 +- .../expressions/sam/samConstructors.fir.txt | 20 ++-- 5 files changed, 94 insertions(+), 54 deletions(-) rename compiler/fir/resolve/testData/resolve/stdlib/{problems/unresolvedComparator.kt => kotlinComparatorAlias.kt} (70%) rename compiler/fir/resolve/testData/resolve/stdlib/{problems/unresolvedComparator.txt => kotlinComparatorAlias.txt} (64%) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt index 368d370b7ee..5c16dc19403 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt @@ -14,9 +14,12 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.ProcessorAction +import org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope +import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType import org.jetbrains.kotlin.fir.symbols.impl.* -import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl +import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.coneTypeUnsafe import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -79,12 +82,48 @@ private fun processSyntheticConstructors( processor: (FirFunctionSymbol<*>) -> ProcessorAction, bodyResolveComponents: BodyResolveComponents ): ProcessorAction { - if (matchedSymbol == null) return ProcessorAction.NEXT - if (matchedSymbol !is FirRegularClassSymbol) return ProcessorAction.NEXT + val samConstructor = matchedSymbol.findSAMConstructor(bodyResolveComponents) + if (samConstructor != null) return processor(samConstructor.symbol) - val function = bodyResolveComponents.samResolver.getSamConstructor(matchedSymbol.fir) ?: return ProcessorAction.NEXT + return ProcessorAction.NEXT +} - return processor(function.symbol) +private fun FirClassLikeSymbol<*>?.findSAMConstructor( + bodyResolveComponents: BodyResolveComponents +): FirSimpleFunction? { + return when (this) { + is FirRegularClassSymbol -> bodyResolveComponents.samResolver.getSamConstructor(fir) + is FirTypeAliasSymbol -> findSAMConstructorForTypeAlias(bodyResolveComponents) + is FirAnonymousObjectSymbol, null -> null + } +} + +private fun FirTypeAliasSymbol.findSAMConstructorForTypeAlias( + bodyResolveComponents: BodyResolveComponents +): FirSimpleFunction? { + val session = bodyResolveComponents.session + val type = + fir.expandedTypeRef.coneTypeUnsafe().fullyExpandedType(session) + + val expansionRegularClass = type.lookupTag.toSymbol(session)?.fir as? FirRegularClass ?: return null + val samConstructorForClass = bodyResolveComponents.samResolver.getSamConstructor(expansionRegularClass) ?: return null + + if (type.typeArguments.isEmpty()) return samConstructorForClass + + val namedSymbol = samConstructorForClass.symbol as? FirNamedFunctionSymbol ?: return null + + val substitutor = prepareSubstitutorForTypeAliasConstructors( + this, + type, + session + ) { newReturnType, newParameterTypes, newTypeParameters -> + FirClassSubstitutionScope.createFakeOverrideFunction( + session, this, namedSymbol, null, + newReturnType, newParameterTypes, newTypeParameters + ).fir + } ?: return null + + return substitutor.substitute(samConstructorForClass) } private fun processConstructors( @@ -147,7 +186,8 @@ private class TypeAliasConstructorsSubstitutingScope( } } -private typealias ConstructorCopyFactory = F.(FirTypeRef, List, List) -> F +private typealias ConstructorCopyFactory = + F.(newReturnType: ConeKotlinType?, newValueParameterTypes: List, newTypeParameters: List) -> F private class TypeAliasConstructorsSubstitutor>( private val typeAliasSymbol: FirTypeAliasSymbol, @@ -156,33 +196,17 @@ private class TypeAliasConstructorsSubstitutor>( ) { fun substitute(baseFunction: F): F { val typeParameters = typeAliasSymbol.fir.typeParameters - val newReturnTypeRef = baseFunction.returnTypeRef.substitute(substitutor) + val newReturnType = baseFunction.returnTypeRef.coneTypeUnsafe().let(substitutor::substituteOrNull) - val newParameterTypeRefs = baseFunction.valueParameters.map { valueParameter -> - valueParameter.returnTypeRef.substitute(substitutor) + val newParameterTypes = baseFunction.valueParameters.map { valueParameter -> + valueParameter.returnTypeRef.coneTypeUnsafe().let(substitutor::substituteOrNull) } - if (newReturnTypeRef == null && newParameterTypeRefs.all { it == null }) return baseFunction + if (newReturnType == null && newParameterTypes.all { it == null }) return baseFunction return baseFunction.copyFactory( - newReturnTypeRef ?: baseFunction.returnTypeRef, - baseFunction.valueParameters.zip( - newParameterTypeRefs - ) { valueParameter, newTypeRef -> - with(valueParameter) { - FirValueParameterImpl( - source, - session, - newTypeRef ?: returnTypeRef, - name, - FirVariableSymbol(valueParameter.symbol.callableId), - defaultValue, - isCrossinline, - isNoinline, - isVararg - ) - } - }, + newReturnType, + newParameterTypes, typeParameters ) } @@ -199,13 +223,32 @@ private fun prepareSubstitutingScopeForTypeAliasConstructors( typeAliasSymbol, expandedType, session - ) factory@{ newReturnTypeRef, newValueParameters, newTypeParameters -> + ) factory@{ newReturnType, newParameterTypes, newTypeParameters -> FirConstructorImpl( - source, session, newReturnTypeRef, receiverTypeRef, status, + source, session, + returnTypeRef.withReplacedConeType(newReturnType), + receiverTypeRef, status, FirConstructorSymbol(symbol.callableId, overriddenSymbol = symbol) ).apply { resolvePhase = this@factory.resolvePhase - valueParameters += newValueParameters + valueParameters += + this@factory.valueParameters.zip( + newParameterTypes + ) { valueParameter, newParameterType -> + with(valueParameter) { + FirValueParameterImpl( + source, + session, + returnTypeRef.withReplacedConeType(newParameterType), + name, + FirVariableSymbol(valueParameter.symbol.callableId), + defaultValue, + isCrossinline, + isNoinline, + isVararg + ) + } + } this.typeParameters += newTypeParameters } } ?: return null @@ -236,8 +279,3 @@ private fun > prepareSubstitutorForTypeAliasConstructor return TypeAliasConstructorsSubstitutor(typeAliasSymbol, substitutor, copyFactory) } - -private fun FirTypeRef.substitute(substitutor: ConeSubstitutor): FirResolvedTypeRef? = - coneTypeUnsafe() - .let(substitutor::substituteOrNull) - ?.let { FirResolvedTypeRefImpl(source, it) } diff --git a/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.kt b/compiler/fir/resolve/testData/resolve/stdlib/kotlinComparatorAlias.kt similarity index 70% rename from compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.kt rename to compiler/fir/resolve/testData/resolve/stdlib/kotlinComparatorAlias.kt index 53a1806444b..ea7c051bc54 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.kt +++ b/compiler/fir/resolve/testData/resolve/stdlib/kotlinComparatorAlias.kt @@ -1,5 +1,5 @@ fun test_1() { - val comp = Comparator { x, y -> 1 } + val comp = Comparator { x, y -> 1 } } fun test_3(comparator: java.util.Comparator) { diff --git a/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.txt b/compiler/fir/resolve/testData/resolve/stdlib/kotlinComparatorAlias.txt similarity index 64% rename from compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.txt rename to compiler/fir/resolve/testData/resolve/stdlib/kotlinComparatorAlias.txt index e47af829aea..cce904a6f30 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/kotlinComparatorAlias.txt @@ -1,6 +1,6 @@ -FILE: unresolvedComparator.kt +FILE: kotlinComparatorAlias.kt public final fun test_1(): R|kotlin/Unit| { - lval comp: = #( = Comparator@fun (x: R|class error: No type for parameter|, y: R|class error: No type for parameter|): R|kotlin/Int| { + lval comp: R|java/util/Comparator| = R|java/util/Comparator|( = Comparator@fun (x: R|kotlin/Int|, y: R|kotlin/Int|): R|kotlin/Int| { Int(1) } ) diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java index 134a8d340d1..1c67c81d22e 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java @@ -123,6 +123,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic runTest("compiler/fir/resolve/testData/resolve/stdlib/javaLangComparator.kt"); } + @TestMetadata("kotlinComparatorAlias.kt") + public void testKotlinComparatorAlias() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/stdlib/kotlinComparatorAlias.kt"); + } + @TestMetadata("listPlusAssign.kt") public void testListPlusAssign() throws Exception { runTest("compiler/fir/resolve/testData/resolve/stdlib/listPlusAssign.kt"); @@ -571,10 +576,5 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic public void testCloneArray() throws Exception { runTest("compiler/fir/resolve/testData/resolve/stdlib/problems/cloneArray.kt"); } - - @TestMetadata("unresolvedComparator.kt") - public void testUnresolvedComparator() throws Exception { - runTest("compiler/fir/resolve/testData/resolve/stdlib/problems/unresolvedComparator.kt"); - } } } diff --git a/compiler/testData/ir/irText/expressions/sam/samConstructors.fir.txt b/compiler/testData/ir/irText/expressions/sam/samConstructors.fir.txt index 47ad7028b2a..7ccd6b56c20 100644 --- a/compiler/testData/ir/irText/expressions/sam/samConstructors.fir.txt +++ b/compiler/testData/ir/irText/expressions/sam/samConstructors.fir.txt @@ -20,14 +20,16 @@ FILE fqName: fileName:/samConstructors.kt RETURN type=kotlin.Nothing from='public final fun test3 (): java.lang.Runnable declared in ' CALL 'public final fun Runnable (block: kotlin.Function0): java.lang.Runnable declared in java.lang' type=java.lang.Runnable origin=null block: FUNCTION_REFERENCE 'public final fun foo (): kotlin.Unit declared in ' type=kotlin.Function0 origin=null - FUN name:test4 visibility:public modality:FINAL <> () returnType:IrErrorType + FUN name:test4 visibility:public modality:FINAL <> () returnType:java.util.Comparator BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun test4 (): IrErrorType declared in ' - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - FUN_EXPR type=kotlin.Function2 origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (a:IrErrorType, b:IrErrorType) returnType:IrErrorType - VALUE_PARAMETER name:a index:0 type:IrErrorType - VALUE_PARAMETER name:b index:1 type:IrErrorType + RETURN type=kotlin.Nothing from='public final fun test4 (): java.util.Comparator declared in ' + CALL 'public final fun Comparator (block: kotlin.Function2): java.util.Comparator declared in java.util' type=java.util.Comparator origin=null + : kotlin.Int + block: FUN_EXPR type=kotlin.Function2 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Int + VALUE_PARAMETER name:a index:0 type:kotlin.Int + VALUE_PARAMETER name:b index:1 type:kotlin.Int BLOCK_BODY - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - GET_VAR 'b: IrErrorType declared in .test4.' type=IrErrorType origin=null + CALL 'public final fun minus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null + $this: GET_VAR 'a: kotlin.Int declared in .test4.' type=kotlin.Int origin=null + other: GET_VAR 'b: kotlin.Int declared in .test4.' type=kotlin.Int origin=null