[NI] Prototype for SAM-conversion.

Supported:
- conversion in resolution parts. Also sam-with-receiver is supported automatically
- separate flag for kotlin function with java SAM as parameters

TODO:
- fix overload conflict error when function type is the same byte origin types is ordered
- consider case when parameter type is T, T <:> Runnable
- support vararg of Runnable

[NI] Turn off synthetic scope with SAM adapter functions if NI enabled
This commit is contained in:
Stanislav Erokhin
2018-05-01 23:46:15 +03:00
parent 4b8e95c243
commit 8f0b073c08
48 changed files with 889 additions and 26 deletions
@@ -49,4 +49,15 @@ interface KotlinResolutionCallbacks {
fun isCompileTimeConstant(resolvedAtom: ResolvedCallAtom, expectedType: UnwrappedType): Boolean
val inferenceSession: InferenceSession
}
interface SamConversionTransformer {
fun getFunctionTypeForPossibleSamType(possibleSamType: UnwrappedType): UnwrappedType?
fun shouldRunSamConversionForFunction(candidate: CallableDescriptor): Boolean
object Empty : SamConversionTransformer {
override fun getFunctionTypeForPossibleSamType(possibleSamType: UnwrappedType): UnwrappedType? = null
override fun shouldRunSamConversionForFunction(candidate: CallableDescriptor): Boolean = false
}
}
@@ -61,7 +61,7 @@ class NewOverloadingConflictResolver(
} else {
val originalValueParameter = originalValueParameters[valueParameter.index]
for (valueArgument in resolvedValueArgument.arguments) {
valueArgumentToParameterType[valueArgument] =
valueArgumentToParameterType[valueArgument] = candidate.resolvedCall.argumentsWithConversion[valueArgument]?.convertedTypeByOriginParameter ?:
valueArgument.getExpectedType(originalValueParameter, candidate.callComponents.languageVersionSettings)
}
}
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
@@ -21,6 +23,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.anySuperTypeConstructor
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal object CheckInstantiationOfAbstractClass : ResolutionPart() {
@@ -28,7 +31,8 @@ internal object CheckInstantiationOfAbstractClass : ResolutionPart() {
val candidateDescriptor = resolvedCall.candidateDescriptor
if (candidateDescriptor is ConstructorDescriptor &&
!callComponents.statelessCallbacks.isSuperOrDelegatingConstructorCall(resolvedCall.atom)) {
!callComponents.statelessCallbacks.isSuperOrDelegatingConstructorCall(resolvedCall.atom)
) {
if (candidateDescriptor.constructedClass.modality == Modality.ABSTRACT) {
addDiagnostic(InstantiationOfAbstractClass)
}
@@ -244,11 +248,48 @@ private fun KotlinResolutionCandidate.prepareExpectedType(
argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor
): UnwrappedType {
val argumentType = argument.getExpectedType(candidateParameter, callComponents.languageVersionSettings)
val argumentType = getExpectedTypeWithSAMConversion(argument, candidateParameter) ?: argument.getExpectedType(
candidateParameter,
callComponents.languageVersionSettings
)
val resultType = knownTypeParametersResultingSubstitutor?.substitute(argumentType) ?: argumentType
return resolvedCall.substitutor.substituteKeepAnnotations(resultType)
}
private fun KotlinResolutionCandidate.getExpectedTypeWithSAMConversion(
argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor
): UnwrappedType? {
if (!callComponents.samConversionTransformer.shouldRunSamConversionForFunction(resolvedCall.candidateDescriptor)) return null
val argumentIsFunctional = when (argument) {
is SimpleKotlinCallArgument -> argument.receiver.stableType.isSubtypeOfFunctionType()
is LambdaKotlinCallArgument, is CallableReferenceKotlinCallArgument -> true
else -> false
}
if (!argumentIsFunctional) return null
val originalExpectedType = argument.getExpectedType(candidateParameter.original, callComponents.languageVersionSettings)
val convertedTypeByOriginal = callComponents.samConversionTransformer.getFunctionTypeForPossibleSamType(originalExpectedType) ?: return null
val candidateExpectedType = argument.getExpectedType(candidateParameter, callComponents.languageVersionSettings)
val convertedTypeByCandidate = callComponents.samConversionTransformer.getFunctionTypeForPossibleSamType(candidateExpectedType)
assert(candidateExpectedType.constructor == originalExpectedType.constructor && convertedTypeByCandidate != null) {
"If original type is SAM type, then candidate should have same type constructor and corresponding function type\n" +
"originalExpectType: $originalExpectedType, candidateExpectType: $candidateExpectedType\n" +
"functionTypeByOriginal: $convertedTypeByOriginal, functionTypeByCandidate: $convertedTypeByCandidate"
}
resolvedCall.registerArgumentWithSamConversion(argument, SamConversionDescription(convertedTypeByOriginal, convertedTypeByCandidate!!))
return convertedTypeByCandidate
}
private fun UnwrappedType.isSubtypeOfFunctionType() = anySuperTypeConstructor {
it.declarationDescriptor?.getFunctionalClassKind() == FunctionClassDescriptor.Kind.Function
}
internal object CheckReceivers : ResolutionPart() {
private fun KotlinResolutionCandidate.checkReceiver(
receiverArgument: SimpleKotlinCallArgument?,
@@ -42,7 +42,8 @@ class KotlinCallComponents(
val constraintInjector: ConstraintInjector,
val reflectionTypes: ReflectionTypes,
val builtIns: KotlinBuiltIns,
val languageVersionSettings: LanguageVersionSettings
val languageVersionSettings: LanguageVersionSettings,
val samConversionTransformer: SamConversionTransformer
)
class SimpleCandidateFactory(
@@ -61,8 +61,15 @@ abstract class ResolvedCallAtom : ResolvedAtom() {
abstract val typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
abstract val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
abstract val substitutor: FreshVariableNewTypeSubstitutor
abstract val argumentsWithConversion: Map<KotlinCallArgument, SamConversionDescription>
}
class SamConversionDescription(
val convertedTypeByOriginParameter: UnwrappedType,
val convertedTypeByCandidateParameter: UnwrappedType // expected type for corresponding argument
)
class ResolvedExpressionAtom(override val atom: ExpressionKotlinCallArgument) : ResolvedAtom() {
init {
setAnalyzedResults(listOf())
@@ -24,10 +24,10 @@ import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableFromCallableDescriptor
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.UnwrappedType
abstract class ResolutionPart {
@@ -176,6 +176,17 @@ class MutableResolvedCallAtom(
override lateinit var argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
override lateinit var substitutor: FreshVariableNewTypeSubstitutor
lateinit var argumentToCandidateParameter: Map<KotlinCallArgument, ValueParameterDescriptor>
private var samAdapterMap: HashMap<KotlinCallArgument, SamConversionDescription>? = null
override val argumentsWithConversion: Map<KotlinCallArgument, SamConversionDescription>
get() = samAdapterMap ?: emptyMap()
fun registerArgumentWithSamConversion(argument: KotlinCallArgument, samConversionDescription: SamConversionDescription) {
if (samAdapterMap == null)
samAdapterMap = hashMapOf()
samAdapterMap!![argument] = samConversionDescription
}
override public fun setAnalyzedResults(subResolvedAtoms: List<ResolvedAtom>) {
super.setAnalyzedResults(subResolvedAtoms)