Enable delegation by interface for inline classes in old FE

#KT-27435
This commit is contained in:
Ilmir Usmanov
2021-11-29 14:50:16 +01:00
parent 3002829acf
commit bb53ba4a2e
20 changed files with 371 additions and 5 deletions
@@ -16867,6 +16867,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/inlineClasses/identityComparisonWithInlineClasses.kt");
}
@Test
@TestMetadata("inlineClassCanImplementInterfaceByDelegation.kt")
public void testInlineClassCanImplementInterfaceByDelegation() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassCanImplementInterfaceByDelegation.kt");
}
@Test
@TestMetadata("inlineClassCanOnlyImplementInterfaces.kt")
public void testInlineClassCanOnlyImplementInterfaces() throws Exception {
@@ -16867,6 +16867,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/inlineClasses/identityComparisonWithInlineClasses.kt");
}
@Test
@TestMetadata("inlineClassCanImplementInterfaceByDelegation.kt")
public void testInlineClassCanImplementInterfaceByDelegation() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassCanImplementInterfaceByDelegation.kt");
}
@Test
@TestMetadata("inlineClassCanOnlyImplementInterfaces.kt")
public void testInlineClassCanOnlyImplementInterfaces() throws Exception {
@@ -16867,6 +16867,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/inlineClasses/identityComparisonWithInlineClasses.kt");
}
@Test
@TestMetadata("inlineClassCanImplementInterfaceByDelegation.kt")
public void testInlineClassCanImplementInterfaceByDelegation() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassCanImplementInterfaceByDelegation.kt");
}
@Test
@TestMetadata("inlineClassCanOnlyImplementInterfaces.kt")
public void testInlineClassCanOnlyImplementInterfaces() throws Exception {
@@ -21098,6 +21098,34 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType")
@TestDataPath("$PROJECT_ROOT")
public class DelegationByUnderlyingType {
@Test
public void testAllFilesPresentInDelegationByUnderlyingType() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("default.kt")
public void testDefault() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/default.kt");
}
@Test
@TestMetadata("defaultArgument.kt")
public void testDefaultArgument() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/defaultArgument.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/simple.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/funInterface")
@TestDataPath("$PROJECT_ROOT")
@@ -757,7 +757,7 @@ public class DefaultErrorMessages {
MAP.put(PROPERTY_WITH_BACKING_FIELD_INSIDE_VALUE_CLASS, "Value class cannot have properties with backing fields");
MAP.put(DELEGATED_PROPERTY_INSIDE_VALUE_CLASS, "Value class cannot have delegated properties");
MAP.put(VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE, "Value class cannot have value parameter of type ''{0}''", RENDER_TYPE);
MAP.put(VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION, "Value class cannot implement an interface by delegation");
MAP.put(VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION, "Value class cannot implement an interface by delegation if expression is not a parameter");
MAP.put(VALUE_CLASS_CANNOT_EXTEND_CLASSES, "Value class cannot extend classes");
MAP.put(VALUE_CLASS_CANNOT_BE_RECURSIVE, "Value class cannot be recursive");
MAP.put(RESERVED_MEMBER_INSIDE_VALUE_CLASS, "Member with the name ''{0}'' is reserved for future releases", STRING);
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.contracts.parsing.isEqualsDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
@@ -15,9 +16,12 @@ import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.modalityModifier
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.isUnit
@@ -104,12 +108,18 @@ object InlineClassDeclarationChecker : DeclarationChecker {
}
for (supertypeEntry in declaration.superTypeListEntries) {
val typeReference = supertypeEntry.typeReference ?: continue
val type = trace[BindingContext.TYPE, typeReference] ?: continue
if (supertypeEntry is KtDelegatedSuperTypeEntry) {
trace.report(Errors.VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION.on(supertypeEntry))
return
val resolvedCall = supertypeEntry.delegateExpression.getResolvedCall(trace.bindingContext) ?: continue
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.InlineClassImplementationByDelegation) ||
resolvedCall.resultingDescriptor !is ValueParameterDescriptor ||
resolvedCall.resultingDescriptor.containingDeclaration != trace.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, primaryConstructor]
) {
trace.report(Errors.VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION.on(supertypeEntry))
return
}
} else {
val typeReference = supertypeEntry.typeReference ?: continue
val type = trace[BindingContext.TYPE, typeReference] ?: continue
val typeDescriptor = type.constructor.declarationDescriptor ?: continue
if (!DescriptorUtils.isInterface(typeDescriptor)) {
trace.report(Errors.VALUE_CLASS_CANNOT_EXTEND_CLASSES.on(typeReference))
@@ -0,0 +1,20 @@
// WITH_STDLIB
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// LANGUAGE: +InlineClassImplementationByDelegation
interface I {
fun ok(): String = "OK"
}
inline class IC(val i: I): I by i
fun box(): String {
val i = object : I {}
var res = IC(i).ok()
if (res != "OK") return "FAIL: $res"
val ic: I = IC(i)
res = ic.ok()
return res
}
@@ -0,0 +1,28 @@
// WITH_STDLIB
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// LANGUAGE: +InlineClassImplementationByDelegation
interface I {
fun o(k: String = "K"): String = "O$k"
}
inline class IC(val i: I): I by i
fun box(): String {
val i = object : I {}
val ic1 = IC(i)
var res = ic1.o()
if (res != "OK") return "FAIL 1: $res"
res = ic1.o("KK")
if (res != "OKK") return "FAIL 2: $res"
val ic2: I = IC(i)
res = ic2.o()
if (res != "OK") return "FAIL 3: $res"
res = ic2.o("KK")
if (res != "OKK") return "FAIL 4: $res"
return "OK"
}
@@ -0,0 +1,22 @@
// WITH_STDLIB
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// LANGUAGE: +InlineClassImplementationByDelegation
interface I {
fun ok(): String
}
inline class IC(val i: I): I by i
fun box(): String {
val i = object : I {
override fun ok(): String = "OK"
}
var res = IC(i).ok()
if (res != "OK") return "FAIL: $res"
val ic: I = IC(i)
res = ic.ok()
return res
}
@@ -0,0 +1,18 @@
// !LANGUAGE: +InlineClasses, -JvmInlineValueClasses, +InlineClassImplementationByDelegation
// SKIP_TXT
interface IFoo
object FooImpl : IFoo
class CFoo : IFoo
val c = CFoo()
inline class Test1(val x: Any) : <!VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION!>IFoo by FooImpl<!>
inline class Test2(val x: IFoo) : <!VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION!>IFoo by x<!>
inline class Test3(val x: IFoo) : <!VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION!>IFoo by CFoo()<!>
inline class Test4(val x: IFoo) : <!VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION!>IFoo by c<!>
@@ -0,0 +1,18 @@
// !LANGUAGE: +InlineClasses, -JvmInlineValueClasses, +InlineClassImplementationByDelegation
// SKIP_TXT
interface IFoo
object FooImpl : IFoo
class CFoo : IFoo
val c = CFoo()
inline class Test1(val x: Any) : <!VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION!>IFoo by FooImpl<!>
inline class Test2(val x: IFoo) : IFoo by x
inline class Test3(val x: IFoo) : <!VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION!>IFoo by CFoo()<!>
inline class Test4(val x: IFoo) : <!VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION!>IFoo by c<!>
@@ -16873,6 +16873,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/inlineClasses/identityComparisonWithInlineClasses.kt");
}
@Test
@TestMetadata("inlineClassCanImplementInterfaceByDelegation.kt")
public void testInlineClassCanImplementInterfaceByDelegation() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassCanImplementInterfaceByDelegation.kt");
}
@Test
@TestMetadata("inlineClassCanOnlyImplementInterfaces.kt")
public void testInlineClassCanOnlyImplementInterfaces() throws Exception {
@@ -20720,6 +20720,34 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType")
@TestDataPath("$PROJECT_ROOT")
public class DelegationByUnderlyingType {
@Test
public void testAllFilesPresentInDelegationByUnderlyingType() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@Test
@TestMetadata("default.kt")
public void testDefault() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/default.kt");
}
@Test
@TestMetadata("defaultArgument.kt")
public void testDefaultArgument() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/defaultArgument.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/simple.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/funInterface")
@TestDataPath("$PROJECT_ROOT")
@@ -21098,6 +21098,34 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType")
@TestDataPath("$PROJECT_ROOT")
public class DelegationByUnderlyingType {
@Test
public void testAllFilesPresentInDelegationByUnderlyingType() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("default.kt")
public void testDefault() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/default.kt");
}
@Test
@TestMetadata("defaultArgument.kt")
public void testDefaultArgument() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/defaultArgument.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/simple.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/funInterface")
@TestDataPath("$PROJECT_ROOT")
@@ -17260,6 +17260,34 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DelegationByUnderlyingType extends AbstractLightAnalysisModeTest {
@TestMetadata("default.kt")
public void ignoreDefault() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/default.kt");
}
@TestMetadata("defaultArgument.kt")
public void ignoreDefaultArgument() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/defaultArgument.kt");
}
@TestMetadata("simple.kt")
public void ignoreSimple() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/simple.kt");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInDelegationByUnderlyingType() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/funInterface")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -243,6 +243,7 @@ enum class LanguageFeature(
EliminateAmbiguitiesOnInheritedSamInterfaces(KOTLIN_1_7),
ConsiderExtensionReceiverFromConstrainsInLambda(KOTLIN_1_7, kind = BUG_FIX), // KT-49832
ProperInternalVisibilityCheckInImportingScope(KOTLIN_1_7, kind = BUG_FIX),
InlineClassImplementationByDelegation(KOTLIN_1_7),
// 1.8
@@ -16450,6 +16450,34 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType")
@TestDataPath("$PROJECT_ROOT")
public class DelegationByUnderlyingType {
@Test
public void testAllFilesPresentInDelegationByUnderlyingType() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("default.kt")
public void testDefault() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/default.kt");
}
@Test
@TestMetadata("defaultArgument.kt")
public void testDefaultArgument() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/defaultArgument.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/simple.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/funInterface")
@TestDataPath("$PROJECT_ROOT")
@@ -16414,6 +16414,34 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType")
@TestDataPath("$PROJECT_ROOT")
public class DelegationByUnderlyingType {
@Test
public void testAllFilesPresentInDelegationByUnderlyingType() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("default.kt")
public void testDefault() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/default.kt");
}
@Test
@TestMetadata("defaultArgument.kt")
public void testDefaultArgument() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/defaultArgument.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/simple.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/funInterface")
@TestDataPath("$PROJECT_ROOT")
@@ -13847,6 +13847,34 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DelegationByUnderlyingType extends AbstractIrCodegenBoxWasmTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
}
public void testAllFilesPresentInDelegationByUnderlyingType() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
@TestMetadata("default.kt")
public void testDefault() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/default.kt");
}
@TestMetadata("defaultArgument.kt")
public void testDefaultArgument() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/defaultArgument.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/simple.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/funInterface")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -17316,6 +17316,35 @@ public class NativeExtBlackBoxTestGenerated extends AbstractNativeBlackBoxTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType")
@TestDataPath("$PROJECT_ROOT")
@NativeBlackBoxTestCaseGroupProvider(ExtTestCaseGroupProvider.class)
public class DelegationByUnderlyingType {
@Test
public void testAllFilesPresentInDelegationByUnderlyingType() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("default.kt")
public void testDefault() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/default.kt");
}
@Test
@TestMetadata("defaultArgument.kt")
public void testDefaultArgument() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/defaultArgument.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/delegationByUnderlyingType/simple.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/inlineClasses/funInterface")
@TestDataPath("$PROJECT_ROOT")