[PSI, FE] Support functional types

This commit is contained in:
Anastasiya Shadrina
2021-08-12 01:15:58 +07:00
committed by TeamCityServer
parent e53cee77a3
commit e3f987459c
45 changed files with 507 additions and 40 deletions
@@ -10588,6 +10588,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/dp.kt"); runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/dp.kt");
} }
@Test
@TestMetadata("functionalType.kt")
public void testFunctionalType() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/functionalType.kt");
}
@Test @Test
@TestMetadata("genericOuterClass.kt") @TestMetadata("genericOuterClass.kt")
public void testGenericOuterClass() throws Exception { public void testGenericOuterClass() throws Exception {
@@ -10719,6 +10725,28 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
public void testWithExplicitReceiverError() throws Exception { public void testWithExplicitReceiverError() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/withExplicitReceiverError.kt"); runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/withExplicitReceiverError.kt");
} }
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP")
@TestDataPath("$PROJECT_ROOT")
public class FromKEEP {
@Test
public void testAllFilesPresentInFromKEEP() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("clickHandler.kt")
public void testClickHandler() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/clickHandler.kt");
}
@Test
@TestMetadata("functionalType.kt")
public void testFunctionalType() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/functionalType.kt");
}
}
} }
} }
@@ -100,6 +100,7 @@ class JvmRuntimeTypes(
descriptor.builtIns, descriptor.builtIns,
Annotations.EMPTY, Annotations.EMPTY,
actualFunctionDescriptor.extensionReceiverParameter?.type, actualFunctionDescriptor.extensionReceiverParameter?.type,
actualFunctionDescriptor.contextReceiverParameters.map { it.type },
actualFunctionDescriptor.valueParameters.map { it.type }, actualFunctionDescriptor.valueParameters.map { it.type },
null, null,
actualFunctionDescriptor.returnType!! actualFunctionDescriptor.returnType!!
@@ -146,6 +147,7 @@ class JvmRuntimeTypes(
Annotations.EMPTY, Annotations.EMPTY,
if (isBound) null else referencedFunction.extensionReceiverParameter?.type if (isBound) null else referencedFunction.extensionReceiverParameter?.type
?: referencedFunction.dispatchReceiverParameter?.type, ?: referencedFunction.dispatchReceiverParameter?.type,
referencedFunction.contextReceiverParameters.map { it.type },
anonymousFunctionDescriptor.valueParameters.drop(receivers).map { it.type }, anonymousFunctionDescriptor.valueParameters.drop(receivers).map { it.type },
null, null,
anonymousFunctionDescriptor.returnType!!, anonymousFunctionDescriptor.returnType!!,
@@ -94,7 +94,8 @@ fun InstructionAdapter.generateClosureFieldsInitializationFromParameters(
} }
fun computeExpectedNumberOfReceivers(referencedFunction: FunctionDescriptor, isBound: Boolean): Int { fun computeExpectedNumberOfReceivers(referencedFunction: FunctionDescriptor, isBound: Boolean): Int {
val receivers = (if (referencedFunction.dispatchReceiverParameter != null) 1 else 0) + val receivers = referencedFunction.contextReceiverParameters.size +
(if (referencedFunction.dispatchReceiverParameter != null) 1 else 0) +
(if (referencedFunction.extensionReceiverParameter != null) 1 else 0) - (if (referencedFunction.extensionReceiverParameter != null) 1 else 0) -
(if (isBound) 1 else 0) (if (isBound) 1 else 0)
@@ -339,6 +339,14 @@ public abstract interface Comparable<in T> : R|kotlin/Any| {
} }
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.TYPE|())) @R|kotlin/annotation/MustBeDocumented|() public final annotation class ContextFunctionTypeParams : R|kotlin/Annotation| {
public final val count: R|kotlin/Int|
public get(): R|kotlin/Int|
public constructor(count: R|kotlin/Int|): R|kotlin/ContextFunctionTypeParams|
}
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.CLASS|(), R|kotlin/annotation/AnnotationTarget.FUNCTION|(), R|kotlin/annotation/AnnotationTarget.PROPERTY|(), R|kotlin/annotation/AnnotationTarget.ANNOTATION_CLASS|(), R|kotlin/annotation/AnnotationTarget.CONSTRUCTOR|(), R|kotlin/annotation/AnnotationTarget.PROPERTY_SETTER|(), R|kotlin/annotation/AnnotationTarget.PROPERTY_GETTER|(), R|kotlin/annotation/AnnotationTarget.TYPEALIAS|())) @R|kotlin/annotation/MustBeDocumented|() public final annotation class Deprecated : R|kotlin/Annotation| { @R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(R|kotlin/annotation/AnnotationTarget.CLASS|(), R|kotlin/annotation/AnnotationTarget.FUNCTION|(), R|kotlin/annotation/AnnotationTarget.PROPERTY|(), R|kotlin/annotation/AnnotationTarget.ANNOTATION_CLASS|(), R|kotlin/annotation/AnnotationTarget.CONSTRUCTOR|(), R|kotlin/annotation/AnnotationTarget.PROPERTY_SETTER|(), R|kotlin/annotation/AnnotationTarget.PROPERTY_GETTER|(), R|kotlin/annotation/AnnotationTarget.TYPEALIAS|())) @R|kotlin/annotation/MustBeDocumented|() public final annotation class Deprecated : R|kotlin/Annotation| {
public final val level: R|kotlin/DeprecationLevel| public final val level: R|kotlin/DeprecationLevel|
public get(): R|kotlin/DeprecationLevel| public get(): R|kotlin/DeprecationLevel|
@@ -10588,6 +10588,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/dp.kt"); runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/dp.kt");
} }
@Test
@TestMetadata("functionalType.kt")
public void testFunctionalType() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/functionalType.kt");
}
@Test @Test
@TestMetadata("genericOuterClass.kt") @TestMetadata("genericOuterClass.kt")
public void testGenericOuterClass() throws Exception { public void testGenericOuterClass() throws Exception {
@@ -10719,6 +10725,28 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
public void testWithExplicitReceiverError() throws Exception { public void testWithExplicitReceiverError() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/withExplicitReceiverError.kt"); runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/withExplicitReceiverError.kt");
} }
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP")
@TestDataPath("$PROJECT_ROOT")
public class FromKEEP {
@Test
public void testAllFilesPresentInFromKEEP() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("clickHandler.kt")
public void testClickHandler() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/clickHandler.kt");
}
@Test
@TestMetadata("functionalType.kt")
public void testFunctionalType() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/functionalType.kt");
}
}
} }
} }
@@ -10588,6 +10588,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/dp.kt"); runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/dp.kt");
} }
@Test
@TestMetadata("functionalType.kt")
public void testFunctionalType() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/functionalType.kt");
}
@Test @Test
@TestMetadata("genericOuterClass.kt") @TestMetadata("genericOuterClass.kt")
public void testGenericOuterClass() throws Exception { public void testGenericOuterClass() throws Exception {
@@ -10719,6 +10725,28 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
public void testWithExplicitReceiverError() throws Exception { public void testWithExplicitReceiverError() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/withExplicitReceiverError.kt"); runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/withExplicitReceiverError.kt");
} }
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP")
@TestDataPath("$PROJECT_ROOT")
public class FromKEEP {
@Test
public void testAllFilesPresentInFromKEEP() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("clickHandler.kt")
public void testClickHandler() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/clickHandler.kt");
}
@Test
@TestMetadata("functionalType.kt")
public void testFunctionalType() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/functionalType.kt");
}
}
} }
} }
@@ -346,7 +346,12 @@ class TypeResolver(
override fun visitFunctionType(type: KtFunctionType) { override fun visitFunctionType(type: KtFunctionType) {
val receiverTypeRef = type.receiverTypeReference val receiverTypeRef = type.receiverTypeReference
val receiverType = if (receiverTypeRef == null) null else resolveType(c.noBareTypes(), receiverTypeRef) val receiverType = if (receiverTypeRef?.typeElement == null) null else resolveType(c.noBareTypes(), receiverTypeRef)
val contextReceiversTypeRefs = type.contextReceiversTypeReferences
val contextReceiversTypes = contextReceiversTypeRefs?.mapNotNull {
resolveType(c.noBareTypes(), it)
} ?: emptyList()
val parameterDescriptors = resolveParametersOfFunctionType(type.parameters) val parameterDescriptors = resolveParametersOfFunctionType(type.parameters)
checkParametersOfFunctionType(parameterDescriptors) checkParametersOfFunctionType(parameterDescriptors)
@@ -362,7 +367,7 @@ class TypeResolver(
result = type( result = type(
createFunctionType( createFunctionType(
moduleDescriptor.builtIns, annotations, receiverType, moduleDescriptor.builtIns, annotations, receiverType, contextReceiversTypes,
parameterDescriptors.map { it.type }, parameterDescriptors.map { it.type },
parameterDescriptors.map { it.name }, parameterDescriptors.map { it.name },
returnType, returnType,
@@ -44,6 +44,7 @@ import javax.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import static org.jetbrains.kotlin.psi.KtPsiUtil.getLastElementDeparenthesized; import static org.jetbrains.kotlin.psi.KtPsiUtil.getLastElementDeparenthesized;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getRecordedTypeInfo; import static org.jetbrains.kotlin.resolve.BindingContextUtils.getRecordedTypeInfo;
@@ -334,7 +335,7 @@ public class ArgumentTypeResolver {
} }
return FunctionTypesKt.createFunctionType( return FunctionTypesKt.createFunctionType(
builtIns, Annotations.Companion.getEMPTY(), null, Collections.emptyList(), null, TypeUtils.DONT_CARE builtIns, Annotations.Companion.getEMPTY(), null, Collections.emptyList(), Collections.emptyList(), null, TypeUtils.DONT_CARE
); );
} }
@@ -372,7 +373,7 @@ public class ArgumentTypeResolver {
return expectedTypeIsUnknown return expectedTypeIsUnknown
? functionPlaceholders.createFunctionPlaceholderType(Collections.emptyList(), /* hasDeclaredArguments = */ false) ? functionPlaceholders.createFunctionPlaceholderType(Collections.emptyList(), /* hasDeclaredArguments = */ false)
: FunctionTypesKt.createFunctionType( : FunctionTypesKt.createFunctionType(
builtIns, Annotations.Companion.getEMPTY(), null, Collections.emptyList(), null, DONT_CARE builtIns, Annotations.Companion.getEMPTY(), null, Collections.emptyList(), Collections.emptyList(), null, DONT_CARE
); );
} }
List<KtParameter> valueParameters = function.getValueParameters(); List<KtParameter> valueParameters = function.getValueParameters();
@@ -391,11 +392,14 @@ public class ArgumentTypeResolver {
KotlinType returnType = resolveTypeRefWithDefault(function.getTypeReference(), scope, temporaryTrace, DONT_CARE); KotlinType returnType = resolveTypeRefWithDefault(function.getTypeReference(), scope, temporaryTrace, DONT_CARE);
assert returnType != null; assert returnType != null;
KotlinType receiverType = resolveTypeRefWithDefault(function.getReceiverTypeReference(), scope, temporaryTrace, null); KotlinType receiverType = resolveTypeRefWithDefault(function.getReceiverTypeReference(), scope, temporaryTrace, null);
List<KotlinType> contextReceiversTypes = function.getContextReceivers().stream().map(contextReceiver ->
resolveTypeRefWithDefault(contextReceiver.typeReference(), scope, temporaryTrace, null)
).collect(Collectors.toList());
return expectedTypeIsUnknown && isFunctionLiteral return expectedTypeIsUnknown && isFunctionLiteral
? functionPlaceholders.createFunctionPlaceholderType(parameterTypes, /* hasDeclaredArguments = */ true) ? functionPlaceholders.createFunctionPlaceholderType(parameterTypes, /* hasDeclaredArguments = */ true)
: FunctionTypesKt.createFunctionType( : FunctionTypesKt.createFunctionType(
builtIns, Annotations.Companion.getEMPTY(), receiverType, parameterTypes, parameterNames, returnType, suspendFunctionTypeExpected builtIns, Annotations.Companion.getEMPTY(), receiverType, contextReceiversTypes, parameterTypes, parameterNames, returnType, suspendFunctionTypeExpected
); );
} }
@@ -357,7 +357,7 @@ public class CallResolver {
parameterTypes.add(NO_EXPECTED_TYPE); parameterTypes.add(NO_EXPECTED_TYPE);
} }
expectedType = FunctionTypesKt.createFunctionType( expectedType = FunctionTypesKt.createFunctionType(
builtIns, Annotations.Companion.getEMPTY(), null, parameterTypes, null, context.expectedType builtIns, Annotations.Companion.getEMPTY(), null, Collections.emptyList(), parameterTypes, null, context.expectedType
); );
} }
KotlinType calleeType = expressionTypingServices.safeGetType( KotlinType calleeType = expressionTypingServices.safeGetType(
@@ -177,7 +177,7 @@ class BuilderInferenceSupport(
approximationSubstitutor.buildSubstitutor().substitute(lambdaExpectedType, Variance.IN_VARIANCE) ?: return approximationSubstitutor.buildSubstitutor().substitute(lambdaExpectedType, Variance.IN_VARIANCE) ?: return
val newExpectedType = createFunctionType( val newExpectedType = createFunctionType(
newReceiverType.builtIns, approximatedLambdaType.annotations, newReceiverType, newReceiverType.builtIns, approximatedLambdaType.annotations, newReceiverType, emptyList(), // TODO: Context receivers?
approximatedLambdaType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType), approximatedLambdaType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType),
parameterNames = null, // TODO: parameterNames parameterNames = null, // TODO: parameterNames
returnType = approximatedLambdaType.getReturnTypeFromFunctionType(), returnType = approximatedLambdaType.getReturnTypeFromFunctionType(),
@@ -16,9 +16,7 @@
package org.jetbrains.kotlin.resolve.calls.inference package org.jetbrains.kotlin.resolve.calls.inference
import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.builtins.*
import org.jetbrains.kotlin.builtins.isBuiltinExtensionFunctionalType
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl.ConstraintKind.EQUAL import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl.ConstraintKind.EQUAL
@@ -471,8 +469,9 @@ internal fun createTypeForFunctionPlaceholder(
functionPlaceholderTypeConstructor.argumentTypes functionPlaceholderTypeConstructor.argumentTypes
} }
val receiverType = if (isExtension) DONT_CARE else null val receiverType = if (isExtension) DONT_CARE else null
val contextReceiverTypes = (0 until expectedType.contextFunctionTypeParamsCount()).map { DONT_CARE }
return createFunctionType( return createFunctionType(
functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, newArgumentTypes, null, DONT_CARE, functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, contextReceiverTypes, newArgumentTypes, null, DONT_CARE,
suspendFunction = expectedType.isSuspendFunctionType suspendFunction = expectedType.isSuspendFunctionType
) )
} }
@@ -186,9 +186,11 @@ class DynamicCallableDescriptors(private val storageManager: StorageManager, bui
val funLiteral = funLiteralExpr.functionLiteral val funLiteral = funLiteralExpr.functionLiteral
val receiverType = funLiteral.receiverTypeReference?.let { dynamicType } val receiverType = funLiteral.receiverTypeReference?.let { dynamicType }
val contextReceiversTypes = funLiteral.contextReceivers.map { dynamicType }
val parameterTypes = funLiteral.valueParameters.map { dynamicType } val parameterTypes = funLiteral.valueParameters.map { dynamicType }
return createFunctionType(owner.builtIns, Annotations.EMPTY, receiverType, parameterTypes, null, dynamicType) return createFunctionType(owner.builtIns, Annotations.EMPTY, receiverType, contextReceiversTypes, parameterTypes, null, dynamicType)
} }
for (arg in call.valueArguments) { for (arg in call.valueArguments) {
@@ -171,8 +171,9 @@ class KotlinResolutionCallbacksImpl(
@OptIn(TypeRefinement::class) callComponents.kotlinTypeChecker.kotlinTypeRefiner.refineType(it) @OptIn(TypeRefinement::class) callComponents.kotlinTypeChecker.kotlinTypeRefiner.refineType(it)
} }
// TODO: Context receivers?
val expectedType = createFunctionType( val expectedType = createFunctionType(
builtIns, annotations, refinedReceiverType, parameters, null, builtIns, annotations, refinedReceiverType, emptyList(), parameters, null,
lambdaInfo.expectedType, isSuspend lambdaInfo.expectedType, isSuspend
) )
@@ -334,6 +334,7 @@ class ResolvedAtomCompleter(
builtIns, builtIns,
existingLambdaType.annotations, existingLambdaType.annotations,
substitutedLambdaTypes.receiverType?.substitutedType, substitutedLambdaTypes.receiverType?.substitutedType,
emptyList(),
substitutedLambdaTypes.parameterTypes.map { it.substitutedType }, substitutedLambdaTypes.parameterTypes.map { it.substitutedType },
null, // parameter names transforms to special annotations, so they are already taken from parameter types null, // parameter names transforms to special annotations, so they are already taken from parameter types
substitutedLambdaTypes.returnType.substitutedType, substitutedLambdaTypes.returnType.substitutedType,
@@ -830,6 +830,9 @@ class DoubleColonExpressionResolver(
} }
companion object { companion object {
private fun contextReceiverTypesFor(descriptor: CallableDescriptor): List<KotlinType> =
descriptor.contextReceiverParameters.map { it.type }
private fun receiverTypeFor(descriptor: CallableDescriptor, lhs: DoubleColonLHS?): KotlinType? = private fun receiverTypeFor(descriptor: CallableDescriptor, lhs: DoubleColonLHS?): KotlinType? =
(descriptor.extensionReceiverParameter ?: descriptor.dispatchReceiverParameter)?.let { (lhs as? DoubleColonLHS.Type)?.type } (descriptor.extensionReceiverParameter ?: descriptor.dispatchReceiverParameter)?.let { (lhs as? DoubleColonLHS.Type)?.type }
@@ -849,6 +852,7 @@ class DoubleColonExpressionResolver(
reflectionTypes: ReflectionTypes, reflectionTypes: ReflectionTypes,
scopeOwnerDescriptor: DeclarationDescriptor scopeOwnerDescriptor: DeclarationDescriptor
): KotlinType? { ): KotlinType? {
val contextReceiverTypes = contextReceiverTypesFor(descriptor)
val receiverType = receiverTypeFor(descriptor, lhs) val receiverType = receiverTypeFor(descriptor, lhs)
return when (descriptor) { return when (descriptor) {
is FunctionDescriptor -> { is FunctionDescriptor -> {
@@ -857,7 +861,7 @@ class DoubleColonExpressionResolver(
val parametersNames = descriptor.valueParameters.map { it.name } val parametersNames = descriptor.valueParameters.map { it.name }
return reflectionTypes.getKFunctionType( return reflectionTypes.getKFunctionType(
Annotations.EMPTY, receiverType, Annotations.EMPTY, receiverType,
parametersTypes, parametersNames, returnType, descriptor.builtIns, descriptor.isSuspend contextReceiverTypes, parametersTypes, parametersNames, returnType, descriptor.builtIns, descriptor.isSuspend
) )
} }
is PropertyDescriptor -> { is PropertyDescriptor -> {
@@ -397,6 +397,7 @@ fun SimpleFunctionDescriptor.createFunctionType(
builtIns, builtIns,
Annotations.EMPTY, Annotations.EMPTY,
extensionReceiverParameter?.type, extensionReceiverParameter?.type,
contextReceiverParameters.map { it.type },
if (shouldUseVarargType) valueParameters.map { it.varargElementType ?: it.type } else valueParameters.map { it.type }, if (shouldUseVarargType) valueParameters.map { it.varargElementType ?: it.type } else valueParameters.map { it.type },
null, null,
returnType ?: return null, returnType ?: return null,
@@ -540,6 +540,7 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
(statementGenerator.context.irBuiltIns as IrBuiltInsOverDescriptors).builtIns, (statementGenerator.context.irBuiltIns as IrBuiltInsOverDescriptors).builtIns,
annotations, annotations,
null, null,
emptyList(),
arguments.dropLast(1).map { it.type }, arguments.dropLast(1).map { it.type },
null, null,
arguments.last().type, arguments.last().type,
@@ -2172,6 +2172,12 @@ public class KotlinParsing extends AbstractKotlinParsing {
IElementType lookahead = lookahead(1); IElementType lookahead = lookahead(1);
IElementType lookahead2 = lookahead(2); IElementType lookahead2 = lookahead(2);
boolean typeBeforeDot = true; boolean typeBeforeDot = true;
boolean withContextReceiver = at(CONTEXT_KEYWORD) && lookahead == LPAR;
if (withContextReceiver) {
parseContextReceiverList();
}
if (at(IDENTIFIER) && !(lookahead == DOT && lookahead2 == IDENTIFIER) && lookahead != LT && at(DYNAMIC_KEYWORD)) { if (at(IDENTIFIER) && !(lookahead == DOT && lookahead2 == IDENTIFIER) && lookahead != LT && at(DYNAMIC_KEYWORD)) {
PsiBuilder.Marker dynamicType = mark(); PsiBuilder.Marker dynamicType = mark();
advance(); // DYNAMIC_KEYWORD advance(); // DYNAMIC_KEYWORD
@@ -2180,7 +2186,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
else if (at(IDENTIFIER) || at(PACKAGE_KEYWORD) || atParenthesizedMutableForPlatformTypes(0)) { else if (at(IDENTIFIER) || at(PACKAGE_KEYWORD) || atParenthesizedMutableForPlatformTypes(0)) {
parseUserType(allowSimpleIntersectionTypes); parseUserType(allowSimpleIntersectionTypes);
} }
else if (at(LPAR)) { else if (at(LPAR) && !withContextReceiver) {
PsiBuilder.Marker functionOrParenthesizedType = mark(); PsiBuilder.Marker functionOrParenthesizedType = mark();
// This may be a function parameter list or just a parenthesized type // This may be a function parameter list or just a parenthesized type
@@ -2211,7 +2217,7 @@ public class KotlinParsing extends AbstractKotlinParsing {
} }
} }
else { else if (!withContextReceiver) {
errorWithRecovery("Type expected", errorWithRecovery("Type expected",
TokenSet.orSet(TOP_LEVEL_DECLARATION_FIRST, TokenSet.orSet(TOP_LEVEL_DECLARATION_FIRST,
TokenSet.create(EQ, COMMA, GT, RBRACKET, DOT, RPAR, RBRACE, LBRACE, SEMICOLON), TokenSet.create(EQ, COMMA, GT, RBRACKET, DOT, RPAR, RBRACE, LBRACE, SEMICOLON),
@@ -2240,8 +2246,10 @@ public class KotlinParsing extends AbstractKotlinParsing {
intersectionType.done(INTERSECTION_TYPE); intersectionType.done(INTERSECTION_TYPE);
wasIntersection = true; wasIntersection = true;
} }
boolean withExtensionReceiver = typeBeforeDot && at(DOT);
if (typeBeforeDot && !wasIntersection && at(DOT)) {
if (withExtensionReceiver && !wasIntersection || withContextReceiver) {
// This is a receiver for a function type // This is a receiver for a function type
// A.(B) -> C // A.(B) -> C
// ^ // ^
@@ -2253,7 +2261,9 @@ public class KotlinParsing extends AbstractKotlinParsing {
receiverTypeRef.done(TYPE_REFERENCE); receiverTypeRef.done(TYPE_REFERENCE);
receiverType.done(FUNCTION_TYPE_RECEIVER); receiverType.done(FUNCTION_TYPE_RECEIVER);
advance(); // DOT if (withExtensionReceiver) {
advance(); // DOT
}
if (at(LPAR)) { if (at(LPAR)) {
parseFunctionTypeContents().drop(); parseFunctionTypeContents().drop();
@@ -45,6 +45,10 @@ public class KtFunctionType extends KtElementImplStub<KotlinPlaceHolderStub<KtFu
@Override @Override
public List<KtTypeReference> getTypeArgumentsAsTypes() { public List<KtTypeReference> getTypeArgumentsAsTypes() {
ArrayList<KtTypeReference> result = Lists.newArrayList(); ArrayList<KtTypeReference> result = Lists.newArrayList();
List<KtTypeReference> contextReceiversTypeRefs = getContextReceiversTypeReferences();
if (contextReceiversTypeRefs != null) {
result.addAll(contextReceiversTypeRefs);
}
KtTypeReference receiverTypeRef = getReceiverTypeReference(); KtTypeReference receiverTypeRef = getReceiverTypeReference();
if (receiverTypeRef != null) { if (receiverTypeRef != null) {
result.add(receiverTypeRef); result.add(receiverTypeRef);
@@ -89,6 +93,20 @@ public class KtFunctionType extends KtElementImplStub<KotlinPlaceHolderStub<KtFu
return receiverDeclaration.getTypeReference(); return receiverDeclaration.getTypeReference();
} }
public List<KtTypeReference> getContextReceiversTypeReferences() {
KtFunctionTypeReceiver receiverDeclaration = getReceiver();
if (receiverDeclaration == null) {
return null;
}
KtTypeReference receiverTypeRef = receiverDeclaration.getTypeReference();
KtContextReceiverList contextReceiverList = receiverTypeRef.getStubOrPsiChild(KtStubElementTypes.CONTEXT_RECEIVER_LIST);
if (contextReceiverList != null) {
return contextReceiverList.typeReferences();
} else {
return Collections.emptyList();
}
}
@Nullable @Nullable
public KtTypeReference getReturnTypeReference() { public KtTypeReference getReturnTypeReference() {
return getStubOrPsiChild(KtStubElementTypes.TYPE_REFERENCE); return getStubOrPsiChild(KtStubElementTypes.TYPE_REFERENCE);
@@ -86,7 +86,7 @@ private fun preprocessLambdaArgument(
if (expectedType != null) { if (expectedType != null) {
val lambdaType = createFunctionType( val lambdaType = createFunctionType(
csBuilder.builtIns, Annotations.EMPTY, resolvedArgument.receiver, csBuilder.builtIns, Annotations.EMPTY, resolvedArgument.receiver, emptyList(), // TODO: Context receivers?
resolvedArgument.parameters, null, resolvedArgument.returnType, resolvedArgument.isSuspend resolvedArgument.parameters, null, resolvedArgument.returnType, resolvedArgument.isSuspend
) )
csBuilder.addSubtypeConstraint(lambdaType, expectedType, ArgumentConstraintPositionImpl(argument)) csBuilder.addSubtypeConstraint(lambdaType, expectedType, ArgumentConstraintPositionImpl(argument))
@@ -43,6 +43,7 @@ object SuspendTypeConversions : ParameterTypeConversion {
candidate.callComponents.builtIns, candidate.callComponents.builtIns,
expectedParameterType.annotations, expectedParameterType.annotations,
expectedParameterType.getReceiverTypeFromFunctionType(), expectedParameterType.getReceiverTypeFromFunctionType(),
expectedParameterType.getContextReceiverTypesFromFunctionType(),
expectedParameterType.getValueParameterTypesFromFunctionType().map { it.type }, expectedParameterType.getValueParameterTypesFromFunctionType().map { it.type },
parameterNames = null, parameterNames = null,
expectedParameterType.getReturnTypeFromFunctionType(), expectedParameterType.getReturnTypeFromFunctionType(),
@@ -78,6 +78,7 @@ object UnitTypeConversions : ParameterTypeConversion {
candidate.callComponents.builtIns, candidate.callComponents.builtIns,
expectedParameterType.annotations, expectedParameterType.annotations,
expectedParameterType.getReceiverTypeFromFunctionType(), expectedParameterType.getReceiverTypeFromFunctionType(),
expectedParameterType.getContextReceiverTypesFromFunctionType(),
expectedParameterType.getValueParameterTypesFromFunctionType().map { it.type }, expectedParameterType.getValueParameterTypesFromFunctionType().map { it.type },
parameterNames = null, parameterNames = null,
candidate.callComponents.builtIns.nullableAnyType, candidate.callComponents.builtIns.nullableAnyType,
+6
View File
@@ -195,6 +195,12 @@ public interface Comparable</*0*/ in T> {
public abstract operator fun compareTo(/*0*/ other: T): kotlin.Int public abstract operator fun compareTo(/*0*/ other: T): kotlin.Int
} }
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.MustBeDocumented public final annotation class ContextFunctionTypeParams : kotlin.Annotation {
/*primary*/ public constructor ContextFunctionTypeParams(/*0*/ count: kotlin.Int)
public final val count: kotlin.Int
public final fun <get-count>(): kotlin.Int
}
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.MustBeDocumented public final annotation class Deprecated : kotlin.Annotation { @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.MustBeDocumented public final annotation class Deprecated : kotlin.Annotation {
/*primary*/ public constructor Deprecated(/*0*/ message: kotlin.String, /*1*/ replaceWith: kotlin.ReplaceWith = ..., /*2*/ level: kotlin.DeprecationLevel = ...) /*primary*/ public constructor Deprecated(/*0*/ message: kotlin.String, /*1*/ replaceWith: kotlin.ReplaceWith = ..., /*2*/ level: kotlin.DeprecationLevel = ...)
public final val level: kotlin.DeprecationLevel public final val level: kotlin.DeprecationLevel
+6
View File
@@ -203,6 +203,12 @@ public interface Comparable</*0*/ in T> {
public abstract operator fun compareTo(/*0*/ other: T): kotlin.Int public abstract operator fun compareTo(/*0*/ other: T): kotlin.Int
} }
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.MustBeDocumented public final annotation class ContextFunctionTypeParams : kotlin.Annotation {
/*primary*/ public constructor ContextFunctionTypeParams(/*0*/ count: kotlin.Int)
public final val count: kotlin.Int
public final fun <get-count>(): kotlin.Int
}
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.MustBeDocumented public final annotation class Deprecated : kotlin.Annotation { @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.MustBeDocumented public final annotation class Deprecated : kotlin.Annotation {
/*primary*/ public constructor Deprecated(/*0*/ message: kotlin.String, /*1*/ replaceWith: kotlin.ReplaceWith = ..., /*2*/ level: kotlin.DeprecationLevel = ...) /*primary*/ public constructor Deprecated(/*0*/ message: kotlin.String, /*1*/ replaceWith: kotlin.ReplaceWith = ..., /*2*/ level: kotlin.DeprecationLevel = ...)
public final val level: kotlin.DeprecationLevel public final val level: kotlin.DeprecationLevel
+6
View File
@@ -205,6 +205,12 @@ public interface Comparable</*0*/ in T> {
public abstract operator fun compareTo(/*0*/ other: T): kotlin.Int public abstract operator fun compareTo(/*0*/ other: T): kotlin.Int
} }
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.MustBeDocumented public final annotation class ContextFunctionTypeParams : kotlin.Annotation {
/*primary*/ public constructor ContextFunctionTypeParams(/*0*/ count: kotlin.Int)
public final val count: kotlin.Int
public final fun <get-count>(): kotlin.Int
}
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.MustBeDocumented public final annotation class Deprecated : kotlin.Annotation { @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.MustBeDocumented public final annotation class Deprecated : kotlin.Annotation {
/*primary*/ public constructor Deprecated(/*0*/ message: kotlin.String, /*1*/ replaceWith: kotlin.ReplaceWith = ..., /*2*/ level: kotlin.DeprecationLevel = ...) /*primary*/ public constructor Deprecated(/*0*/ message: kotlin.String, /*1*/ replaceWith: kotlin.ReplaceWith = ..., /*2*/ level: kotlin.DeprecationLevel = ...)
public final val level: kotlin.DeprecationLevel public final val level: kotlin.DeprecationLevel
@@ -203,6 +203,12 @@ public interface Comparable</*0*/ in T> {
public abstract operator fun compareTo(/*0*/ other: T): kotlin.Int public abstract operator fun compareTo(/*0*/ other: T): kotlin.Int
} }
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.MustBeDocumented public final annotation class ContextFunctionTypeParams : kotlin.Annotation {
/*primary*/ public constructor ContextFunctionTypeParams(/*0*/ count: kotlin.Int)
public final val count: kotlin.Int
public final fun <get-count>(): kotlin.Int
}
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.MustBeDocumented public final annotation class Deprecated : kotlin.Annotation { @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.TYPEALIAS}) @kotlin.annotation.MustBeDocumented public final annotation class Deprecated : kotlin.Annotation {
/*primary*/ public constructor Deprecated(/*0*/ message: kotlin.String, /*1*/ replaceWith: kotlin.ReplaceWith = ..., /*2*/ level: kotlin.DeprecationLevel = ...) /*primary*/ public constructor Deprecated(/*0*/ message: kotlin.String, /*1*/ replaceWith: kotlin.ReplaceWith = ..., /*2*/ level: kotlin.DeprecationLevel = ...)
public final val level: kotlin.DeprecationLevel public final val level: kotlin.DeprecationLevel
@@ -0,0 +1,10 @@
// FIR_IDENTICAL
class Button
class ClickEvent
typealias ClickHandler = context(Button) (ClickEvent) -> Unit
fun handleClick(clickHandler: ClickHandler) {
clickHandler(Button(), ClickEvent())
}
@@ -0,0 +1,18 @@
package
public fun handleClick(/*0*/ clickHandler: ClickHandler /* = @kotlin.ContextFunctionTypeParams(count = 1) (ClickEvent) -> kotlin.Unit */): kotlin.Unit
public final class Button {
public constructor Button()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class ClickEvent {
public constructor ClickEvent()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public typealias ClickHandler = @kotlin.ContextFunctionTypeParams(count = 1) (ClickEvent) -> kotlin.Unit
@@ -0,0 +1,21 @@
// !LANGUAGE: +ContextReceivers
// !DIAGNOSTICS: -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE
class Context
class Receiver
class Param
fun foo(context: Context, receiver: Receiver, p: Param) {}
context(Context)
fun bar(receiver: Receiver, p: Param) {}
context(Context)
fun Receiver.baz(p: Param) {}
fun main() {
var g: context(Context) Receiver.(Param) -> Unit
g = ::<!UNRESOLVED_REFERENCE!>foo<!> // OK
g = ::bar // OK
g = Receiver::baz // OK
}
@@ -0,0 +1,20 @@
// !DIAGNOSTICS: -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE
class Context
class Receiver
class Param
fun foo(context: Context, receiver: Receiver, p: Param) {}
context(Context)
fun bar(receiver: Receiver, p: Param) {}
context(Context)
fun Receiver.baz(p: Param) {}
fun main() {
var g: context(Context) Receiver.(Param) -> Unit
g = ::foo // OK
g = ::bar // OK
g = Receiver::baz // OK
}
@@ -0,0 +1,27 @@
package
public fun bar(/*0*/ receiver: Receiver, /*1*/ p: Param): kotlin.Unit
public fun foo(/*0*/ context: Context, /*1*/ receiver: Receiver, /*2*/ p: Param): kotlin.Unit
public fun main(): kotlin.Unit
public fun Receiver.baz(/*0*/ p: Param): kotlin.Unit
public final class Context {
public constructor Context()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Param {
public constructor Param()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Receiver {
public constructor Receiver()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,39 @@
class Param
class C
class R
context(C)
fun R.f1(g: context(C) R.(Param) -> Unit) {
g(this@C, this@R, Param())
}
context(C)
fun f2(g: context(C) (Param) -> Unit) {
g(this@C, Param())
}
context(C)
fun R.f3(g: context(C) R.() -> Unit) {
g(this@C, this@R)
}
context(C)
fun f4(g: context(C) () -> Unit) {
g(this@C)
}
fun test() {
val lf1: context(C) R.(Param) -> Unit = { _ -> }
val lf2: context(C) (Param) -> Unit = { _ -> }
val lf3: context(C) R.() -> Unit = { }
val lf4: context(C) () -> Unit = { }
with(C()) {
with(R()) {
f1(lf1)
f2(lf2)
f3(lf3)
f4(lf4)
}
}
}
@@ -0,0 +1,39 @@
class Param
class C
class R
context(C)
fun R.f1(g: context(C) R.(Param) -> Unit) {
g(this@C, this@R, Param())
}
context(C)
fun f2(g: context(C) (Param) -> Unit) {
g(this@C, Param())
}
context(C)
fun R.f3(g: context(C) R.() -> Unit) {
g(this@C, this@R)
}
context(C)
fun f4(g: context(C) () -> Unit) {
g(this@C)
}
fun test() {
val lf1: context(C) R.(Param) -> Unit = { _ -> }
val lf2: context(C) (Param) -> Unit = { _ -> }
val lf3: context(C) R.() -> Unit = { }
val lf4: context(C) () -> Unit = { }
with(C()) {
with(R()) {
f1(lf1)
f2(lf2)
f3(lf3)
f4(lf4)
}
}
}
@@ -0,0 +1,28 @@
package
public fun f2(/*0*/ g: @kotlin.ContextFunctionTypeParams(count = 1) (Param) -> kotlin.Unit): kotlin.Unit
public fun f4(/*0*/ g: @kotlin.ContextFunctionTypeParams(count = 1) () -> kotlin.Unit): kotlin.Unit
public fun test(): kotlin.Unit
public fun R.f1(/*0*/ g: @kotlin.ContextFunctionTypeParams(count = 1) (R.(Param) -> kotlin.Unit)): kotlin.Unit
public fun R.f3(/*0*/ g: @kotlin.ContextFunctionTypeParams(count = 1) (R.() -> kotlin.Unit)): kotlin.Unit
public final class C {
public constructor C()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Param {
public constructor Param()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class R {
public constructor R()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -10594,6 +10594,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/dp.kt"); runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/dp.kt");
} }
@Test
@TestMetadata("functionalType.kt")
public void testFunctionalType() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/functionalType.kt");
}
@Test @Test
@TestMetadata("genericOuterClass.kt") @TestMetadata("genericOuterClass.kt")
public void testGenericOuterClass() throws Exception { public void testGenericOuterClass() throws Exception {
@@ -10725,6 +10731,28 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
public void testWithExplicitReceiverError() throws Exception { public void testWithExplicitReceiverError() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/withExplicitReceiverError.kt"); runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/withExplicitReceiverError.kt");
} }
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP")
@TestDataPath("$PROJECT_ROOT")
public class FromKEEP {
@Test
public void testAllFilesPresentInFromKEEP() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("clickHandler.kt")
public void testClickHandler() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/clickHandler.kt");
}
@Test
@TestMetadata("functionalType.kt")
public void testFunctionalType() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/functionalType.kt");
}
}
} }
} }
+5
View File
@@ -97,6 +97,11 @@ public enum class DeprecationLevel {
@MustBeDocumented @MustBeDocumented
public annotation class ExtensionFunctionType public annotation class ExtensionFunctionType
// TODO: How to make it require opt-in? @RequiresOptIn doesn't support TYPE target
@Target(TYPE)
@MustBeDocumented
public annotation class ContextFunctionTypeParams(val count: Int)
/** /**
* Annotates type arguments of functional type and holds corresponding parameter name specified by the user in type declaration (if any). * Annotates type arguments of functional type and holds corresponding parameter name specified by the user in type declaration (if any).
*/ */
@@ -114,6 +114,7 @@ object StandardNames {
@JvmField val deprecationLevel: FqName = fqName("DeprecationLevel") @JvmField val deprecationLevel: FqName = fqName("DeprecationLevel")
@JvmField val replaceWith: FqName = fqName("ReplaceWith") @JvmField val replaceWith: FqName = fqName("ReplaceWith")
@JvmField val extensionFunctionType: FqName = fqName("ExtensionFunctionType") @JvmField val extensionFunctionType: FqName = fqName("ExtensionFunctionType")
@JvmField val contextFunctionTypeParams: FqName = fqName("ContextFunctionTypeParams")
@JvmField val parameterName: FqName = fqName("ParameterName") @JvmField val parameterName: FqName = fqName("ParameterName")
@JvmField val parameterNameClassId: ClassId = ClassId.topLevel(parameterName) @JvmField val parameterNameClassId: ClassId = ClassId.topLevel(parameterName)
@JvmField val annotation: FqName = fqName("Annotation") @JvmField val annotation: FqName = fqName("Annotation")
@@ -58,13 +58,15 @@ class ReflectionTypes(module: ModuleDescriptor, private val notFoundClasses: Not
fun getKFunctionType( fun getKFunctionType(
annotations: Annotations, annotations: Annotations,
receiverType: KotlinType?, receiverType: KotlinType?,
contextReceiverTypes: List<KotlinType>,
parameterTypes: List<KotlinType>, parameterTypes: List<KotlinType>,
parameterNames: List<Name>?, parameterNames: List<Name>?,
returnType: KotlinType, returnType: KotlinType,
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
isSuspend: Boolean isSuspend: Boolean
): SimpleType { ): SimpleType {
val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns) val arguments =
getFunctionTypeArgumentProjections(receiverType, contextReceiverTypes, parameterTypes, parameterNames, returnType, builtIns)
val classDescriptor = val classDescriptor =
if (isSuspend) getKSuspendFunction(arguments.size - 1 /* return type */) else getKFunction(arguments.size - 1 /* return type */) if (isSuspend) getKSuspendFunction(arguments.size - 1 /* return type */) else getKFunction(arguments.size - 1 /* return type */)
return KotlinTypeFactory.simpleNotNullType(annotations, classDescriptor, arguments) return KotlinTypeFactory.simpleNotNullType(annotations, classDescriptor, arguments)
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.builtins package org.jetbrains.kotlin.builtins
import org.jetbrains.kotlin.builtins.StandardNames.BUILT_INS_PACKAGE_NAME import org.jetbrains.kotlin.builtins.StandardNames.BUILT_INS_PACKAGE_NAME
import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -16,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.IntValue
import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
@@ -128,10 +128,29 @@ private fun FqNameUnsafe.getFunctionalClassKind(): FunctionClassKind? {
return FunctionClassKind.getFunctionalClassKind(shortName().asString(), toSafe().parent()) return FunctionClassKind.getFunctionalClassKind(shortName().asString(), toSafe().parent())
} }
fun KotlinType.contextFunctionTypeParamsCount(): Int {
val annotationDescriptor = annotations.findAnnotation(StandardNames.FqNames.contextFunctionTypeParams) ?: return 0
val constantValue = annotationDescriptor.allValueArguments.getValue(Name.identifier("count"))
return (constantValue as IntValue).value
}
fun KotlinType.getReceiverTypeFromFunctionType(): KotlinType? { fun KotlinType.getReceiverTypeFromFunctionType(): KotlinType? {
assert(isBuiltinFunctionalType) { "Not a function type: $this" } assert(isBuiltinFunctionalType) { "Not a function type: $this" }
return if (isTypeAnnotatedWithExtensionFunctionType) arguments.first().type else null if (!isTypeAnnotatedWithExtensionFunctionType) {
return null
}
val index = contextFunctionTypeParamsCount()
return arguments[index].type
}
fun KotlinType.getContextReceiverTypesFromFunctionType(): List<KotlinType> {
assert(isBuiltinFunctionalType) { "Not a function type: $this" }
val contextReceiversCount = contextFunctionTypeParamsCount()
return if (contextReceiversCount == 0) {
emptyList()
} else {
arguments.subList(0, contextReceiversCount).map { it.type }
}
} }
fun KotlinType.getReturnTypeFromFunctionType(): KotlinType { fun KotlinType.getReturnTypeFromFunctionType(): KotlinType {
@@ -148,7 +167,7 @@ fun KotlinType.replaceReturnType(newReturnType: KotlinType): KotlinType {
fun KotlinType.getValueParameterTypesFromFunctionType(): List<TypeProjection> { fun KotlinType.getValueParameterTypesFromFunctionType(): List<TypeProjection> {
assert(isBuiltinFunctionalType) { "Not a function type: $this" } assert(isBuiltinFunctionalType) { "Not a function type: $this" }
val arguments = arguments val arguments = arguments
val first = if (isBuiltinExtensionFunctionalType) 1 else 0 val first = contextFunctionTypeParamsCount() + if (isBuiltinExtensionFunctionalType) 1 else 0
val last = arguments.size - 1 val last = arguments.size - 1
assert(first <= last) { "Not an exact function type: $this" } assert(first <= last) { "Not an exact function type: $this" }
return arguments.subList(first, last) return arguments.subList(first, last)
@@ -183,14 +202,16 @@ fun KotlinType.extractParameterNameFromFunctionTypeArgument(): Name? {
} }
fun getFunctionTypeArgumentProjections( fun getFunctionTypeArgumentProjections(
receiverType: KotlinType?, receiverType: KotlinType?,
parameterTypes: List<KotlinType>, contextReceiverTypes: List<KotlinType>,
parameterNames: List<Name>?, parameterTypes: List<KotlinType>,
returnType: KotlinType, parameterNames: List<Name>?,
builtIns: KotlinBuiltIns returnType: KotlinType,
builtIns: KotlinBuiltIns
): List<TypeProjection> { ): List<TypeProjection> {
val arguments = ArrayList<TypeProjection>(parameterTypes.size + (if (receiverType != null) 1 else 0) + 1) val arguments = ArrayList<TypeProjection>(parameterTypes.size + contextReceiverTypes.size + (if (receiverType != null) 1 else 0) + 1)
arguments.addAll(contextReceiverTypes.map { it.asTypeProjection() })
arguments.addIfNotNull(receiverType?.asTypeProjection()) arguments.addIfNotNull(receiverType?.asTypeProjection())
parameterTypes.mapIndexedTo(arguments) { index, type -> parameterTypes.mapIndexedTo(arguments) { index, type ->
@@ -219,17 +240,22 @@ fun createFunctionType(
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
annotations: Annotations, annotations: Annotations,
receiverType: KotlinType?, receiverType: KotlinType?,
contextReceiverTypes: List<KotlinType>,
parameterTypes: List<KotlinType>, parameterTypes: List<KotlinType>,
parameterNames: List<Name>?, parameterNames: List<Name>?,
returnType: KotlinType, returnType: KotlinType,
suspendFunction: Boolean = false suspendFunction: Boolean = false
): SimpleType { ): SimpleType {
val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns) val arguments =
val parameterCount = if (receiverType == null) parameterTypes.size else parameterTypes.size + 1 getFunctionTypeArgumentProjections(receiverType, contextReceiverTypes, parameterTypes, parameterNames, returnType, builtIns)
val parameterCount = parameterTypes.size + contextReceiverTypes.size + if (receiverType == null) 0 else 1
val classDescriptor = getFunctionDescriptor(builtIns, parameterCount, suspendFunction) val classDescriptor = getFunctionDescriptor(builtIns, parameterCount, suspendFunction)
// TODO: preserve laziness of given annotations // TODO: preserve laziness of given annotations
val typeAnnotations = if (receiverType != null) annotations.withExtensionFunctionAnnotation(builtIns) else annotations var typeAnnotations = annotations
if (receiverType != null) typeAnnotations = typeAnnotations.withExtensionFunctionAnnotation(builtIns)
if (contextReceiverTypes.isNotEmpty()) typeAnnotations =
typeAnnotations.withContextReceiversFunctionAnnotation(builtIns, contextReceiverTypes.size)
return KotlinTypeFactory.simpleNotNullType(typeAnnotations, classDescriptor, arguments) return KotlinTypeFactory.simpleNotNullType(typeAnnotations, classDescriptor, arguments)
} }
@@ -246,6 +272,19 @@ fun Annotations.withExtensionFunctionAnnotation(builtIns: KotlinBuiltIns) =
Annotations.create(this + BuiltInAnnotationDescriptor(builtIns, StandardNames.FqNames.extensionFunctionType, emptyMap())) Annotations.create(this + BuiltInAnnotationDescriptor(builtIns, StandardNames.FqNames.extensionFunctionType, emptyMap()))
} }
fun Annotations.withContextReceiversFunctionAnnotation(builtIns: KotlinBuiltIns, contextReceiversCount: Int) =
if (hasAnnotation(StandardNames.FqNames.contextFunctionTypeParams)) {
this
} else {
Annotations.create(
this + BuiltInAnnotationDescriptor(
builtIns, StandardNames.FqNames.contextFunctionTypeParams, mapOf(
Name.identifier("count") to IntValue(contextReceiversCount)
)
)
)
}
fun getFunctionDescriptor(builtIns: KotlinBuiltIns, parameterCount: Int, isSuspendFunction: Boolean) = fun getFunctionDescriptor(builtIns: KotlinBuiltIns, parameterCount: Int, isSuspendFunction: Boolean) =
if (isSuspendFunction) builtIns.getSuspendFunction(parameterCount) else builtIns.getFunction(parameterCount) if (isSuspendFunction) builtIns.getSuspendFunction(parameterCount) else builtIns.getFunction(parameterCount)
@@ -43,10 +43,11 @@ fun transformSuspendFunctionToRuntimeFunctionType(suspendFunType: KotlinType): S
} }
return createFunctionType( return createFunctionType(
suspendFunType.builtIns, suspendFunType.builtIns,
suspendFunType.annotations, suspendFunType.annotations,
suspendFunType.getReceiverTypeFromFunctionType(), suspendFunType.getReceiverTypeFromFunctionType(),
suspendFunType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType) + suspendFunType.getContextReceiverTypesFromFunctionType(),
suspendFunType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType) +
KotlinTypeFactory.simpleType( KotlinTypeFactory.simpleType(
Annotations.EMPTY, Annotations.EMPTY,
// Continuation interface is not a part of built-ins anymore, it has been moved to stdlib. // Continuation interface is not a part of built-ins anymore, it has been moved to stdlib.
@@ -76,14 +76,15 @@ fun getFunctionTypeForAbstractMethod(
val parameterTypes = ArrayList<KotlinType>(valueParameters.size) val parameterTypes = ArrayList<KotlinType>(valueParameters.size)
val parameterNames = ArrayList<Name>(valueParameters.size) val parameterNames = ArrayList<Name>(valueParameters.size)
var startIndex = 0 val contextReceiversTypes = function.contextReceiverParameters.map { it.type }
var startIndex = contextReceiversTypes.size
var receiverType: KotlinType? = null var receiverType: KotlinType? = null
val extensionReceiver = function.extensionReceiverParameter val extensionReceiver = function.extensionReceiverParameter
if (extensionReceiver != null) { if (extensionReceiver != null) {
receiverType = extensionReceiver.type receiverType = extensionReceiver.type
} else if (shouldConvertFirstParameterToDescriptor && function.valueParameters.isNotEmpty()) { } else if (shouldConvertFirstParameterToDescriptor && function.valueParameters.isNotEmpty()) {
receiverType = valueParameters[0].type receiverType = valueParameters[0].type
startIndex = 1 startIndex += 1
} }
for (i in startIndex until valueParameters.size) { for (i in startIndex until valueParameters.size) {
@@ -93,7 +94,7 @@ fun getFunctionTypeForAbstractMethod(
} }
return createFunctionType( return createFunctionType(
function.builtIns, EMPTY, receiverType, parameterTypes, function.builtIns, EMPTY, receiverType, contextReceiversTypes, parameterTypes,
parameterNames, returnType, function.isSuspend parameterNames, returnType, function.isSuspend
) )
} }
@@ -226,6 +226,7 @@ class TypeDeserializer(
funType.builtIns, funType.builtIns,
funType.annotations, funType.annotations,
funType.getReceiverTypeFromFunctionType(), funType.getReceiverTypeFromFunctionType(),
funType.getContextReceiverTypesFromFunctionType(),
funType.getValueParameterTypesFromFunctionType().dropLast(1).map(TypeProjection::getType), funType.getValueParameterTypesFromFunctionType().dropLast(1).map(TypeProjection::getType),
// TODO: names // TODO: names
null, null,
+8
View File
@@ -1187,6 +1187,14 @@ public open class ConcurrentModificationException : kotlin.RuntimeException {
public constructor ConcurrentModificationException(cause: kotlin.Throwable?) public constructor ConcurrentModificationException(cause: kotlin.Throwable?)
} }
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE})
@kotlin.annotation.MustBeDocumented
public final annotation class ContextFunctionTypeParams : kotlin.Annotation {
public constructor ContextFunctionTypeParams(count: kotlin.Int)
public final val count: kotlin.Int { get; }
}
@kotlin.SinceKotlin(version = "1.4") @kotlin.SinceKotlin(version = "1.4")
@kotlin.ExperimentalStdlibApi @kotlin.ExperimentalStdlibApi
public final class DeepRecursiveFunction<T, R> { public final class DeepRecursiveFunction<T, R> {
+8
View File
@@ -1158,6 +1158,14 @@ public open class ConcurrentModificationException : kotlin.RuntimeException {
public constructor ConcurrentModificationException(cause: kotlin.Throwable?) public constructor ConcurrentModificationException(cause: kotlin.Throwable?)
} }
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE})
@kotlin.annotation.MustBeDocumented
public final annotation class ContextFunctionTypeParams : kotlin.Annotation {
public constructor ContextFunctionTypeParams(count: kotlin.Int)
public final val count: kotlin.Int { get; }
}
@kotlin.SinceKotlin(version = "1.4") @kotlin.SinceKotlin(version = "1.4")
@kotlin.ExperimentalStdlibApi @kotlin.ExperimentalStdlibApi
public final class DeepRecursiveFunction<T, R> { public final class DeepRecursiveFunction<T, R> {
@@ -1,6 +1,10 @@
public abstract interface annotation class kotlin/BuilderInference : java/lang/annotation/Annotation { public abstract interface annotation class kotlin/BuilderInference : java/lang/annotation/Annotation {
} }
public abstract interface annotation class kotlin/ContextFunctionTypeParams : java/lang/annotation/Annotation {
public abstract fun count ()I
}
public final class kotlin/DeepRecursiveFunction { public final class kotlin/DeepRecursiveFunction {
public fun <init> (Lkotlin/jvm/functions/Function3;)V public fun <init> (Lkotlin/jvm/functions/Function3;)V
} }