[FE] KT-51234 Check subtyping between context receivers

This commit is contained in:
Anastasia.Shadrina
2022-03-31 00:50:23 +07:00
committed by teamcity
parent a3fa2dc9bf
commit 292c0c4383
14 changed files with 714 additions and 22 deletions
@@ -1308,6 +1308,7 @@ public interface Errors {
DiagnosticFactory1<KtElement, String> MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<KtElement> AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement> UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement> SUBTYPING_BETWEEN_CONTEXT_RECEIVERS = DiagnosticFactory0.create(ERROR);
// Error sets
ImmutableSet<? extends DiagnosticFactory<?>> UNRESOLVED_REFERENCE_DIAGNOSTICS = ImmutableSet.of(
@@ -1120,6 +1120,7 @@ public class DefaultErrorMessages {
MAP.put(MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER, "Multiple arguments applicable for context receiver: {0}", TO_STRING);
MAP.put(AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER, "With implicit context receiver, call is ambiguous. Specify the receiver explicitly");
MAP.put(UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL, "To use contextual declarations, specify the `-Xcontext-receivers` compiler option");
MAP.put(SUBTYPING_BETWEEN_CONTEXT_RECEIVERS, "Subtyping relation between context receivers is prohibited");
MAP.setImmutable();
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.resolve
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtContextReceiverList
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.containsTypeParameter
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
import org.jetbrains.kotlin.types.typeUtil.supertypes
fun checkContextReceiversAreEnabled(
trace: BindingTrace,
languageVersionSettings: LanguageVersionSettings,
contextReceiverList: KtContextReceiverList
) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)) {
trace.report(
Errors.UNSUPPORTED_FEATURE.on(
contextReceiverList,
LanguageFeature.ContextReceivers to languageVersionSettings
)
)
}
}
fun checkSubtypingBetweenContextReceivers(
trace: BindingTrace,
contextReceiverList: KtContextReceiverList,
contextReceiverTypes: List<KotlinType>
) {
fun KotlinType.prepared(): KotlinType = when {
isTypeParameter() -> supertypes().first()
containsTypeParameter() -> replaceArgumentsWithStarProjections()
else -> this
}
for (i in 0 until contextReceiverTypes.lastIndex) {
val contextReceiverType = contextReceiverTypes[i].prepared()
for (j in (i + 1) until contextReceiverTypes.size) {
val anotherContextReceiverType = contextReceiverTypes[j].prepared()
if (NewKotlinTypeChecker.Default.isSubtypeOf(contextReceiverType, anotherContextReceiverType) ||
NewKotlinTypeChecker.Default.isSubtypeOf(anotherContextReceiverType, contextReceiverType)
) {
trace.report(Errors.SUBTYPING_BETWEEN_CONTEXT_RECEIVERS.on(contextReceiverList))
return
}
}
}
}
@@ -48,6 +48,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
SuspendFunctionAsSupertypeChecker,
EnumCompanionInEnumConstructorCallChecker,
ContextualDeclarationChecker,
SubtypingBetweenContextReceiversChecker,
ValueParameterUsageInDefaultArgumentChecker,
CyclicAnnotationsChecker,
)
@@ -368,10 +368,12 @@ class TypeResolver(
val contextReceiverList = type.contextReceiverList
val contextReceiversTypes = if (contextReceiverList != null) {
checkContextReceiversAreEnabled(contextReceiverList)
contextReceiverList.typeReferences().map { typeRef ->
checkContextReceiversAreEnabled(c.trace, languageVersionSettings, contextReceiverList)
val types = contextReceiverList.typeReferences().map { typeRef ->
resolveType(c.noBareTypes(), typeRef)
}
checkSubtypingBetweenContextReceivers(c.trace, contextReceiverList, types)
types
} else emptyList()
val parameterDescriptors = resolveParametersOfFunctionType(type.parameters)
@@ -454,7 +456,7 @@ class TypeResolver(
}
override fun visitContextReceiverList(contextReceiverList: KtContextReceiverList) {
checkContextReceiversAreEnabled(contextReceiverList)
checkContextReceiversAreEnabled(c.trace, languageVersionSettings, contextReceiverList)
}
override fun visitDynamicType(type: KtDynamicType) {
@@ -496,17 +498,6 @@ class TypeResolver(
c.trace.report(Errors.UNSUPPORTED.on(it, "val or var on parameter in function type"))
}
}
private fun checkContextReceiversAreEnabled(contextReceiverList: KtContextReceiverList) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)) {
c.trace.report(
UNSUPPORTED_FEATURE.on(
contextReceiverList,
LanguageFeature.ContextReceivers to languageVersionSettings
)
)
}
}
})
return result ?: type(ErrorUtils.createErrorType(ErrorTypeKind.NO_TYPE_SPECIFIED, typeElement?.getDebugText() ?: "unknown element"))
@@ -6,11 +6,14 @@
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.isContextualDeclaration
import org.jetbrains.kotlin.resolve.checkContextReceiversAreEnabled
import org.jetbrains.kotlin.resolve.checkSubtypingBetweenContextReceivers
object ContextualDeclarationChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
@@ -19,12 +22,23 @@ object ContextualDeclarationChecker : DeclarationChecker {
}
if (declaration.isContextualDeclaration()) {
val contextReceiverList = declaration.findDescendantOfType<KtContextReceiverList>() ?: return
context.trace.report(
Errors.UNSUPPORTED_FEATURE.on(
contextReceiverList, LanguageFeature.ContextReceivers to context.languageVersionSettings
)
)
checkContextReceiversAreEnabled(context.trace, context.languageVersionSettings, contextReceiverList)
return
}
}
}
object SubtypingBetweenContextReceiversChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers) || !declaration.isContextualDeclaration()) {
return
}
val contextReceivers = when (descriptor) {
is CallableDescriptor -> descriptor.contextReceiverParameters
is ClassDescriptor -> descriptor.contextReceivers
else -> return
}
val contextReceiverList = declaration.findDescendantOfType<KtContextReceiverList>() ?: return
checkSubtypingBetweenContextReceivers(context.trace, contextReceiverList, contextReceivers.map { it.type })
}
}