[FIR] KT-59368 context receiver subtyping checker
This commit is contained in:
+6
@@ -2105,6 +2105,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.SUBTYPING_BETWEEN_CONTEXT_RECEIVERS) { firDiagnostic ->
|
||||||
|
SubtypingBetweenContextReceiversImpl(
|
||||||
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.RECURSION_IN_IMPLICIT_TYPES) { firDiagnostic ->
|
add(FirErrors.RECURSION_IN_IMPLICIT_TYPES) { firDiagnostic ->
|
||||||
RecursionInImplicitTypesImpl(
|
RecursionInImplicitTypesImpl(
|
||||||
firDiagnostic as KtPsiDiagnostic,
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
|||||||
+4
@@ -1500,6 +1500,10 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = UnsupportedContextualDeclarationCall::class
|
override val diagnosticClass get() = UnsupportedContextualDeclarationCall::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SubtypingBetweenContextReceivers : KtFirDiagnostic<KtElement> {
|
||||||
|
override val diagnosticClass get() = SubtypingBetweenContextReceivers::class
|
||||||
|
}
|
||||||
|
|
||||||
interface RecursionInImplicitTypes : KtFirDiagnostic<PsiElement> {
|
interface RecursionInImplicitTypes : KtFirDiagnostic<PsiElement> {
|
||||||
override val diagnosticClass get() = RecursionInImplicitTypes::class
|
override val diagnosticClass get() = RecursionInImplicitTypes::class
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -1800,6 +1800,11 @@ internal class UnsupportedContextualDeclarationCallImpl(
|
|||||||
token: KtLifetimeToken,
|
token: KtLifetimeToken,
|
||||||
) : KtAbstractFirDiagnostic<KtElement>(firDiagnostic, token), KtFirDiagnostic.UnsupportedContextualDeclarationCall
|
) : KtAbstractFirDiagnostic<KtElement>(firDiagnostic, token), KtFirDiagnostic.UnsupportedContextualDeclarationCall
|
||||||
|
|
||||||
|
internal class SubtypingBetweenContextReceiversImpl(
|
||||||
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
|
token: KtLifetimeToken,
|
||||||
|
) : KtAbstractFirDiagnostic<KtElement>(firDiagnostic, token), KtFirDiagnostic.SubtypingBetweenContextReceivers
|
||||||
|
|
||||||
internal class RecursionInImplicitTypesImpl(
|
internal class RecursionInImplicitTypesImpl(
|
||||||
firDiagnostic: KtPsiDiagnostic,
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
token: KtLifetimeToken,
|
token: KtLifetimeToken,
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
FILE: contextReceiversSubtyping.kt
|
||||||
|
public abstract interface D : R|D1|, R|D2| {
|
||||||
|
}
|
||||||
|
public abstract interface D1 : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
public abstract interface D2 : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
context(R|T|, R|D2|)
|
||||||
|
public final fun <T : R|D1|, R|D2|> foo(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public abstract interface Cov<out T> : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
public final class A : R|kotlin/Any| {
|
||||||
|
public constructor(): R|A| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class B : R|kotlin/Any| {
|
||||||
|
public constructor(): R|B| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
context(R|Cov<T>|, R|Cov<B>|)
|
||||||
|
public final fun <T : R|A|> foo(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// !LANGUAGE: +ContextReceivers
|
||||||
|
|
||||||
|
interface D: D1, D2 {}
|
||||||
|
interface D1 {}
|
||||||
|
interface D2 {}
|
||||||
|
|
||||||
|
<!SUBTYPING_BETWEEN_CONTEXT_RECEIVERS!>context(T, D2)<!>
|
||||||
|
fun <T> foo() where T: D1, T: D2 {}
|
||||||
|
|
||||||
|
interface Cov<out T> {}
|
||||||
|
class A {}
|
||||||
|
class B {}
|
||||||
|
|
||||||
|
// This sholdn't be an error since the type parameter is predetermined to be `A`,
|
||||||
|
// which causes that there can't be subtyping between the context receivers.
|
||||||
|
// However, the cheking is simplified because it is time-consuming process.
|
||||||
|
<!SUBTYPING_BETWEEN_CONTEXT_RECEIVERS!>context(Cov<T>, Cov<B>)<!>
|
||||||
|
fun <T: <!FINAL_UPPER_BOUND!>A<!>> foo() {}
|
||||||
+6
@@ -1503,6 +1503,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/checkers/complexConflictingProjections.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/checkers/complexConflictingProjections.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("contextReceiversSubtyping.kt")
|
||||||
|
public void testContextReceiversSubtyping() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/checkers/contextReceiversSubtyping.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("importAnnotationWithRequiresOptIn.kt")
|
@TestMetadata("importAnnotationWithRequiresOptIn.kt")
|
||||||
public void testImportAnnotationWithRequiresOptIn() throws Exception {
|
public void testImportAnnotationWithRequiresOptIn() throws Exception {
|
||||||
|
|||||||
+6
@@ -1503,6 +1503,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/checkers/complexConflictingProjections.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/checkers/complexConflictingProjections.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("contextReceiversSubtyping.kt")
|
||||||
|
public void testContextReceiversSubtyping() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/checkers/contextReceiversSubtyping.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("importAnnotationWithRequiresOptIn.kt")
|
@TestMetadata("importAnnotationWithRequiresOptIn.kt")
|
||||||
public void testImportAnnotationWithRequiresOptIn() throws Exception {
|
public void testImportAnnotationWithRequiresOptIn() throws Exception {
|
||||||
|
|||||||
+1
@@ -676,6 +676,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
}
|
}
|
||||||
val AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED)
|
val AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED)
|
||||||
val UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL by error<KtElement>(PositioningStrategy.NAME_IDENTIFIER)
|
val UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL by error<KtElement>(PositioningStrategy.NAME_IDENTIFIER)
|
||||||
|
val SUBTYPING_BETWEEN_CONTEXT_RECEIVERS by error<KtElement>(PositioningStrategy.DEFAULT)
|
||||||
}
|
}
|
||||||
|
|
||||||
val TYPES_AND_TYPE_PARAMETERS by object : DiagnosticGroup("Types & type parameters") {
|
val TYPES_AND_TYPE_PARAMETERS by object : DiagnosticGroup("Types & type parameters") {
|
||||||
|
|||||||
@@ -415,6 +415,7 @@ object FirErrors {
|
|||||||
val MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER by error1<KtElement, ConeKotlinType>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER by error1<KtElement, ConeKotlinType>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
val AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER by error0<KtElement>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER by error0<KtElement>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
val UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL by error0<KtElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
|
val UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL by error0<KtElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
|
||||||
|
val SUBTYPING_BETWEEN_CONTEXT_RECEIVERS by error0<KtElement>()
|
||||||
|
|
||||||
// Types & type parameters
|
// Types & type parameters
|
||||||
val RECURSION_IN_IMPLICIT_TYPES by error0<PsiElement>()
|
val RECURSION_IN_IMPLICIT_TYPES by error0<PsiElement>()
|
||||||
|
|||||||
+1
@@ -263,6 +263,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
|
|||||||
"MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER",
|
"MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER",
|
||||||
"AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER",
|
"AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER",
|
||||||
"UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL",
|
"UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL",
|
||||||
|
"SUBTYPING_BETWEEN_CONTEXT_RECEIVERS",
|
||||||
"RECURSION_IN_IMPLICIT_TYPES",
|
"RECURSION_IN_IMPLICIT_TYPES",
|
||||||
"INFERENCE_ERROR",
|
"INFERENCE_ERROR",
|
||||||
"PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT",
|
"PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT",
|
||||||
|
|||||||
@@ -5,10 +5,19 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.checkers
|
package org.jetbrains.kotlin.fir.analysis.checkers
|
||||||
|
|
||||||
|
import com.intellij.lang.LighterASTNode
|
||||||
|
import org.jetbrains.kotlin.KtLightSourceElement
|
||||||
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
|
import org.jetbrains.kotlin.diagnostics.findChildByType
|
||||||
|
import org.jetbrains.kotlin.diagnostics.findDescendantByType
|
||||||
|
import org.jetbrains.kotlin.diagnostics.traverseDescendants
|
||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.toKtLightSourceElement
|
||||||
|
import org.jetbrains.kotlin.util.getChildren
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,3 +32,17 @@ fun KtModifierKeywordToken.toVisibilityOrNull(): Visibility? {
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locates first [CONTEXT_RECEIVER_LIST] and returns position in source.
|
||||||
|
*/
|
||||||
|
fun KtSourceElement.findContextReceiverListSource(): KtLightSourceElement? {
|
||||||
|
if (this.lighterASTNode.tokenType == KtNodeTypes.CONTEXT_RECEIVER_LIST)
|
||||||
|
return this.lighterASTNode.toKtLightSourceElement(treeStructure)
|
||||||
|
|
||||||
|
return treeStructure.findDescendantByType(
|
||||||
|
lighterASTNode,
|
||||||
|
KtNodeTypes.CONTEXT_RECEIVER_LIST,
|
||||||
|
false
|
||||||
|
)?.toKtLightSourceElement(treeStructure)
|
||||||
|
}
|
||||||
|
|||||||
+52
-34
@@ -5,27 +5,34 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||||
|
|
||||||
import com.intellij.lang.LighterASTNode
|
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.KtLightSourceElement
|
|
||||||
import org.jetbrains.kotlin.KtNodeTypes.CONTEXT_RECEIVER_LIST
|
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.findContextReceiverListSource
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.toKtLightSourceElement
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.util.getChildren
|
|
||||||
|
|
||||||
object FirContextReceiversDeclarationChecker : FirBasicDeclarationChecker() {
|
object FirContextReceiversDeclarationChecker : FirBasicDeclarationChecker() {
|
||||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)) return
|
|
||||||
if (declaration.source?.kind is KtFakeSourceElementKind) return
|
if (declaration.source?.kind is KtFakeSourceElementKind) return
|
||||||
if (!declaration.hasContextReceiver()) return
|
val contextReceivers = declaration.getContextReceiver()
|
||||||
|
if (contextReceivers.isEmpty()) return
|
||||||
val source = declaration.source?.findContextReceiverListSource() ?: return
|
val source = declaration.source?.findContextReceiverListSource() ?: return
|
||||||
|
|
||||||
|
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)) {
|
||||||
|
if (checkSubTypes(contextReceivers.map { it.typeRef.coneType }, context)) {
|
||||||
|
reporter.reportOn(
|
||||||
|
source,
|
||||||
|
FirErrors.SUBTYPING_BETWEEN_CONTEXT_RECEIVERS,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
reporter.reportOn(
|
reporter.reportOn(
|
||||||
source,
|
source,
|
||||||
FirErrors.UNSUPPORTED_FEATURE,
|
FirErrors.UNSUPPORTED_FEATURE,
|
||||||
@@ -34,36 +41,47 @@ object FirContextReceiversDeclarationChecker : FirBasicDeclarationChecker() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirDeclaration.hasContextReceiver(): Boolean {
|
private fun FirDeclaration.getContextReceiver(): List<FirContextReceiver> {
|
||||||
val contextReceivers = when (this) {
|
return when (this) {
|
||||||
is FirCallableDeclaration -> contextReceivers
|
is FirCallableDeclaration -> contextReceivers
|
||||||
is FirRegularClass -> contextReceivers
|
is FirRegularClass -> contextReceivers
|
||||||
is FirScript -> contextReceivers
|
is FirScript -> contextReceivers
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
return contextReceivers.isNotEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun KtSourceElement.findContextReceiverListSource(): KtLightSourceElement? {
|
|
||||||
var contextReceiverList: LighterASTNode? = null
|
|
||||||
var contextReceiverListOffset = startOffset
|
|
||||||
|
|
||||||
val nodes = lighterASTNode.getChildren(treeStructure)
|
|
||||||
for (node in nodes) {
|
|
||||||
if (node.tokenType == CONTEXT_RECEIVER_LIST) {
|
|
||||||
contextReceiverList = node
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
contextReceiverListOffset += node.endOffset - node.startOffset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (contextReceiverList == null) return null
|
|
||||||
|
|
||||||
return contextReceiverList.toKtLightSourceElement(
|
|
||||||
treeStructure,
|
|
||||||
startOffset = contextReceiverListOffset,
|
|
||||||
endOffset = contextReceiverListOffset + contextReceiverList.textLength,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplified checking of subtype relation used in context receiver checkers.
|
||||||
|
* It converts type parameters to star projections and top level type parameters to its supertypes. Then it checks the relation.
|
||||||
|
*/
|
||||||
|
fun checkSubTypes(types: List<ConeKotlinType>, context: CheckerContext): Boolean {
|
||||||
|
fun replaceTypeParametersByStarProjections(type: ConeClassLikeType): ConeClassLikeType {
|
||||||
|
return type.withArguments(type.typeArguments.map {
|
||||||
|
when {
|
||||||
|
it.isStarProjection -> it
|
||||||
|
it.type!! is ConeTypeParameterType -> ConeStarProjection
|
||||||
|
it.type!! is ConeClassLikeType -> replaceTypeParametersByStarProjections(it.type as ConeClassLikeType)
|
||||||
|
else -> it
|
||||||
|
}
|
||||||
|
}.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
val replacedTypeParameters = types.flatMap { r ->
|
||||||
|
when (r) {
|
||||||
|
is ConeTypeParameterType -> r.lookupTag.typeParameterSymbol.resolvedBounds.map { it.type }
|
||||||
|
is ConeClassLikeType -> listOf(replaceTypeParametersByStarProjections(r))
|
||||||
|
else -> listOf(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in replacedTypeParameters.indices)
|
||||||
|
for (j in i + 1..<replacedTypeParameters.size) {
|
||||||
|
if (replacedTypeParameters[i].isSubtypeOf(replacedTypeParameters[j], context.session)
|
||||||
|
|| replacedTypeParameters[j].isSubtypeOf(replacedTypeParameters[i], context.session)
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
+22
-11
@@ -5,29 +5,40 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.checkers.type
|
package org.jetbrains.kotlin.fir.analysis.checkers.type
|
||||||
|
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.*
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.checkSubTypes
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.findContextReceiverListSource
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
|
||||||
object FirContextReceiversTypeChecker : FirTypeRefChecker() {
|
object FirContextReceiversTypeChecker : FirTypeRefChecker() {
|
||||||
override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)) return
|
|
||||||
if (typeRef !is FirResolvedTypeRef) return
|
if (typeRef !is FirResolvedTypeRef) return
|
||||||
val source = typeRef.source ?: return
|
if (typeRef.source?.kind is KtFakeSourceElementKind) return
|
||||||
if (source.kind is KtFakeSourceElementKind) return
|
if (!typeRef.coneType.hasContextReceivers) return
|
||||||
|
val source = typeRef.source?.findContextReceiverListSource() ?: return
|
||||||
|
|
||||||
if (typeRef.coneType.hasContextReceivers) {
|
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)) {
|
||||||
reporter.reportOn(
|
if (checkSubTypes(typeRef.coneType.contextReceiversTypes(context.session), context)) {
|
||||||
source,
|
reporter.reportOn(
|
||||||
FirErrors.UNSUPPORTED_FEATURE,
|
source,
|
||||||
LanguageFeature.ContextReceivers to context.languageVersionSettings,
|
FirErrors.SUBTYPING_BETWEEN_CONTEXT_RECEIVERS,
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reporter.reportOn(
|
||||||
|
source,
|
||||||
|
FirErrors.UNSUPPORTED_FEATURE,
|
||||||
|
LanguageFeature.ContextReceivers to context.languageVersionSettings,
|
||||||
|
context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
@@ -581,6 +581,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SINGLE_ANONYMOUS_
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SMARTCAST_IMPOSSIBLE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SMARTCAST_IMPOSSIBLE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SPREAD_OF_NULLABLE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SPREAD_OF_NULLABLE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUBCLASS_OPT_IN_INAPPLICABLE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUBCLASS_OPT_IN_INAPPLICABLE
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUBTYPING_BETWEEN_CONTEXT_RECEIVERS
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPES_FOR_ANNOTATION_CLASS
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPES_FOR_ANNOTATION_CLASS
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_APPEARS_TWICE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_APPEARS_TWICE
|
||||||
@@ -1276,6 +1277,10 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
|||||||
UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL,
|
UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL,
|
||||||
"To use contextual declarations, specify the '-Xcontext-receivers' compiler option."
|
"To use contextual declarations, specify the '-Xcontext-receivers' compiler option."
|
||||||
)
|
)
|
||||||
|
map.put(
|
||||||
|
SUBTYPING_BETWEEN_CONTEXT_RECEIVERS,
|
||||||
|
"Subtyping relation between context receivers is prohibited."
|
||||||
|
)
|
||||||
|
|
||||||
// Ambiguity
|
// Ambiguity
|
||||||
map.put(OVERLOAD_RESOLUTION_AMBIGUITY, "Overload resolution ambiguity between candidates: {0}", SYMBOLS)
|
map.put(OVERLOAD_RESOLUTION_AMBIGUITY, "Overload resolution ambiguity between candidates: {0}", SYMBOLS)
|
||||||
|
|||||||
-221
@@ -1,221 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNCHECKED_CAST
|
|
||||||
// !LANGUAGE: +ContextReceivers
|
|
||||||
|
|
||||||
interface A
|
|
||||||
interface B : A
|
|
||||||
typealias C = B
|
|
||||||
|
|
||||||
interface Inv<T>
|
|
||||||
interface Cov<out T>
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
|
|
||||||
context(A, A)
|
|
||||||
fun f1() {}
|
|
||||||
|
|
||||||
context(A, B)
|
|
||||||
fun f2() {}
|
|
||||||
|
|
||||||
context(A, C)
|
|
||||||
fun f3() {}
|
|
||||||
|
|
||||||
context(B, C)
|
|
||||||
fun f4() {}
|
|
||||||
|
|
||||||
context(C, C)
|
|
||||||
fun f5() {}
|
|
||||||
|
|
||||||
context(A, A, A)
|
|
||||||
fun f6() {}
|
|
||||||
|
|
||||||
context(Inv<A>, Inv<B>)
|
|
||||||
fun f7() {}
|
|
||||||
|
|
||||||
context(Inv<A>, Inv<A>)
|
|
||||||
fun f8() {}
|
|
||||||
|
|
||||||
context(Inv<T>, Inv<A>)
|
|
||||||
fun <T> f9() {}
|
|
||||||
|
|
||||||
context(Cov<A>, Cov<B>)
|
|
||||||
fun f10() {}
|
|
||||||
|
|
||||||
context(Cov<T>, Cov<A>)
|
|
||||||
fun <T> f11() {}
|
|
||||||
|
|
||||||
context(T, A)
|
|
||||||
fun <T> f12() {}
|
|
||||||
|
|
||||||
// Classes
|
|
||||||
|
|
||||||
context(A, A)
|
|
||||||
class C1 {
|
|
||||||
context(A, A)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(A, A)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(A, B)
|
|
||||||
class C2 {
|
|
||||||
context(A, B)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(A, B)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(A, C)
|
|
||||||
class C3 {
|
|
||||||
context(A, C)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(A, C)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(B, C)
|
|
||||||
class C4 {
|
|
||||||
context(B, C)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(B, C)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(C, C)
|
|
||||||
class C5 {
|
|
||||||
context(C, C)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(C, C)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(A, A, A)
|
|
||||||
class C6 {
|
|
||||||
context(A, A, A)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(A, A, A)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(Inv<A>, Inv<B>)
|
|
||||||
class C7 {
|
|
||||||
context(Inv<A>, Inv<B>)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(Inv<A>, Inv<B>)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(Inv<A>, Inv<A>)
|
|
||||||
class C8 {
|
|
||||||
context(Inv<A>, Inv<A>)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(Inv<A>, Inv<A>)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(Inv<T>, Inv<A>)
|
|
||||||
class C9<T> {
|
|
||||||
context(Inv<T>, Inv<A>)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(Inv<T>, Inv<A>)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(Cov<A>, Cov<B>)
|
|
||||||
class C10 {
|
|
||||||
context(Cov<A>, Cov<B>)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(Cov<A>, Cov<B>)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(Cov<T>, Cov<A>)
|
|
||||||
class C11<T> {
|
|
||||||
context(Cov<T>, Cov<A>)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(Cov<T>, Cov<A>)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(T, A)
|
|
||||||
class C12<T> {
|
|
||||||
context(T, A)
|
|
||||||
val p: Any get() = 42
|
|
||||||
|
|
||||||
context(T, A)
|
|
||||||
fun m() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Properties
|
|
||||||
|
|
||||||
context(A, A)
|
|
||||||
val p1: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(A, B)
|
|
||||||
val p2: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(A, C)
|
|
||||||
val p3: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(B, C)
|
|
||||||
val p4: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(C, C)
|
|
||||||
val p5: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(A, A, A)
|
|
||||||
val p6: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(Inv<A>, Inv<B>)
|
|
||||||
val p7: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(Inv<A>, Inv<A>)
|
|
||||||
val p8: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(Inv<T>, Inv<A>)
|
|
||||||
val <T> p9: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(Cov<A>, Cov<B>)
|
|
||||||
val p10: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(Cov<T>, Cov<A>)
|
|
||||||
val <T> p11: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
context(T, A)
|
|
||||||
val <T> p12: Any?
|
|
||||||
get() { return null }
|
|
||||||
|
|
||||||
// Function types
|
|
||||||
|
|
||||||
// Function types are processed with the same function that is used for checking contextual declarations
|
|
||||||
// So we check here only one simple case: `context(A, B)`
|
|
||||||
|
|
||||||
context(A, B)
|
|
||||||
fun f(g: context(A, B) () -> Unit, value: Any): context(A, B) () -> Unit {
|
|
||||||
return value as (context(A, B) () -> Unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
val lf: context(A, B) () -> Unit = { }
|
|
||||||
}
|
|
||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNCHECKED_CAST
|
// !DIAGNOSTICS: -UNCHECKED_CAST
|
||||||
// !LANGUAGE: +ContextReceivers
|
// !LANGUAGE: +ContextReceivers
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
// !DIAGNOSTICS: -UNCHECKED_CAST
|
// !DIAGNOSTICS: -UNCHECKED_CAST
|
||||||
|
|
||||||
<!UNSUPPORTED_FEATURE!>context(Any)<!>
|
<!UNSUPPORTED_FEATURE!>context(Any)<!>
|
||||||
fun f(g: <!UNSUPPORTED_FEATURE!>context(Any) () -> Unit<!>, value: Any): <!UNSUPPORTED_FEATURE!>context(A) () -> Unit<!> {
|
fun f(g: <!UNSUPPORTED_FEATURE!>context(Any)<!> () -> Unit, value: Any): <!UNSUPPORTED_FEATURE!>context(A)<!> () -> Unit {
|
||||||
return value as <!UNSUPPORTED_FEATURE!>(context(A) () -> Unit)<!>
|
return value as (<!UNSUPPORTED_FEATURE!>context(A)<!> () -> Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun f(g: () -> Unit, value: Any) : () -> Unit {
|
fun f(g: () -> Unit, value: Any) : () -> Unit {
|
||||||
|
|||||||
Reference in New Issue
Block a user