From 635add48238fd0e530ea564db9bef5dbd421cbac Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 14 Nov 2019 13:48:51 +0300 Subject: [PATCH] FIR substitution: generate fake overrides for accessor symbols --- .../scopes/impl/FirClassSubstitutionScope.kt | 57 ++++++++++++++++-- .../resolve/expresssions/genericDescriptor.kt | 4 +- .../expresssions/genericDescriptor.txt | 4 +- .../resolve/expresssions/genericDiagnostic.kt | 58 +++++++++++++++++++ .../expresssions/genericDiagnostic.txt | 22 +++++++ .../expresssions/genericUsedInFunction.kt | 9 +++ .../expresssions/genericUsedInFunction.txt | 19 ++++++ .../fir/FirDiagnosticsTestGenerated.java | 10 ++++ 8 files changed, 173 insertions(+), 10 deletions(-) create mode 100644 compiler/fir/resolve/testData/resolve/expresssions/genericDiagnostic.kt create mode 100644 compiler/fir/resolve/testData/resolve/expresssions/genericDiagnostic.txt create mode 100644 compiler/fir/resolve/testData/resolve/expresssions/genericUsedInFunction.kt create mode 100644 compiler/fir/resolve/testData/resolve/expresssions/genericUsedInFunction.txt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt index c90cbed538c..7e0f35e6004 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt @@ -36,6 +36,7 @@ class FirClassSubstitutionScope( private val fakeOverrideFunctions = mutableMapOf, FirFunctionSymbol<*>>() private val fakeOverrideProperties = mutableMapOf() private val fakeOverrideFields = mutableMapOf() + private val fakeOverrideAccessors = mutableMapOf() private val substitutor = substitutorByMap(substitution) @@ -61,6 +62,10 @@ class FirClassSubstitutionScope( val field = fakeOverrideFields.getOrPut(original) { createFakeOverrideField(original) } processor(field) } + is FirAccessorSymbol -> { + val accessor = fakeOverrideAccessors.getOrPut(original) { createFakeOverrideAccessor(original) } + processor(accessor) + } else -> { processor(original) } @@ -127,17 +132,33 @@ class FirClassSubstitutionScope( return createFakeOverrideField(session, member, original, newReturnType) } + private fun createFakeOverrideAccessor(original: FirAccessorSymbol): FirAccessorSymbol { + val member = original.fir + + val returnType = typeCalculator.tryCalculateReturnType(member).type + val newReturnType = returnType.substitute() + + val newParameterTypes = member.valueParameters.map { + it.returnTypeRef.coneTypeUnsafe().substitute() + } + + if (newReturnType == null && newParameterTypes.all { it == null }) { + return original + } + + return createFakeOverrideAccessor(session, member, original, newReturnType, newParameterTypes) + } + companion object { - fun createFakeOverrideFunction( + private fun createFakeOverrideFunction( + fakeOverrideSymbol: FirFunctionSymbol, session: FirSession, baseFunction: FirSimpleFunction, - baseSymbol: FirNamedFunctionSymbol, newReceiverType: ConeKotlinType? = null, newReturnType: ConeKotlinType? = null, newParameterTypes: List? = null - ): FirNamedFunctionSymbol { - val symbol = FirNamedFunctionSymbol(baseSymbol.callableId, true, baseSymbol) - with(baseFunction) { + ): FirSimpleFunction { + return with(baseFunction) { // TODO: consider using here some light-weight functions instead of pseudo-real FirMemberFunctionImpl // As second alternative, we can invent some light-weight kind of FirRegularClass FirSimpleFunctionImpl( @@ -147,7 +168,7 @@ class FirClassSubstitutionScope( baseFunction.receiverTypeRef?.withReplacedConeType(newReceiverType), name, baseFunction.status, - symbol + fakeOverrideSymbol ).apply { resolvePhase = baseFunction.resolvePhase valueParameters += baseFunction.valueParameters.zip( @@ -169,6 +190,18 @@ class FirClassSubstitutionScope( } } } + } + + fun createFakeOverrideFunction( + session: FirSession, + baseFunction: FirSimpleFunction, + baseSymbol: FirNamedFunctionSymbol, + newReceiverType: ConeKotlinType? = null, + newReturnType: ConeKotlinType? = null, + newParameterTypes: List? = null + ): FirNamedFunctionSymbol { + val symbol = FirNamedFunctionSymbol(baseSymbol.callableId, true, baseSymbol) + createFakeOverrideFunction(symbol, session, baseFunction, newReceiverType, newReturnType, newParameterTypes) return symbol } @@ -218,6 +251,18 @@ class FirClassSubstitutionScope( } return symbol } + + fun createFakeOverrideAccessor( + session: FirSession, + baseFunction: FirSimpleFunction, + baseSymbol: FirAccessorSymbol, + newReturnType: ConeKotlinType? = null, + newParameterTypes: List? = null + ): FirAccessorSymbol { + val symbol = FirAccessorSymbol(baseSymbol.callableId, baseSymbol.accessorId) + createFakeOverrideFunction(symbol, session, baseFunction, null, newReturnType, newParameterTypes) + return symbol + } } } diff --git a/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.kt b/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.kt index aff396941c0..7557436a99f 100644 --- a/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.kt +++ b/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.kt @@ -20,8 +20,8 @@ interface Call { val resultingDescriptor: D } -fun test(call: Call, resolvedCall: ResolvedCall) { - call.resultingDescriptor.name +fun test(call: Call, resolvedCall: ResolvedCall) { + call.resultingDescriptor.name resolvedCall.resultingDescriptor.name } diff --git a/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.txt b/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.txt index 3533d72aef0..a442538c847 100644 --- a/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.txt +++ b/compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.txt @@ -6,8 +6,8 @@ FILE: test.kt public get(): R|D| } - public final fun test(call: R|Call|, resolvedCall: R|ResolvedCall|): R|kotlin/Unit| { - R|/call|.R|FakeOverride|.# + public final fun test(call: R|Call|, resolvedCall: R|ResolvedCall|): R|kotlin/Unit| { + R|/call|.R|FakeOverride|.R|/name| R|/resolvedCall|.R|/ResolvedCall.resultingDescriptor|.R|/name| } public final fun otherTest(call: R|Call<*>|, resolvedCall: R|ResolvedCall<*>|): R|kotlin/Unit| { diff --git a/compiler/fir/resolve/testData/resolve/expresssions/genericDiagnostic.kt b/compiler/fir/resolve/testData/resolve/expresssions/genericDiagnostic.kt new file mode 100644 index 00000000000..f7540c3e987 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/genericDiagnostic.kt @@ -0,0 +1,58 @@ +// FILE: Element.java +// FULL_JDK + +public interface Element {} + +// FILE: DerivedElement.java + +public interface DerivedElement extends Element {} + +// FILE: EmptyDiagnostic.java + +public class EmptyDiagnostic {} + +// FILE: Diagnostic.java + +import org.jetbrains.annotations.NotNull; + +public class Diagnostic extends EmptyDiagnostic { + @NotNull + public E getElement(); +} + +// FILE: DiagnosticFactory.java + +import org.jetbrains.annotations.NotNull; + +public class DiagnosticFactory { + @NotNull + public D cast(@NotNull EmptyDiagnostic diagnostic) { + return (D) diagnostic; + } +} + +// FILE: DiagnosticFactory0.java + +public class DiagnosticFactory0 extends DiagnosticFactory {} + +// FILE: test.kt + +class Fix(e: DerivedElement) + +fun create(d: Diagnostic) { + val element = d.element + Fix(element) +} + +fun createGeneric(d: Diagnostic) { + val element = d.element + Fix(element) +} + +private val DERIVED_FACTORY = DiagnosticFactory0() + +fun createViaFactory(d: EmptyDiagnostic) { + val casted = DERIVED_FACTORY.cast(d) + val element = casted.element + Fix(element) +} diff --git a/compiler/fir/resolve/testData/resolve/expresssions/genericDiagnostic.txt b/compiler/fir/resolve/testData/resolve/expresssions/genericDiagnostic.txt new file mode 100644 index 00000000000..730c3026601 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/genericDiagnostic.txt @@ -0,0 +1,22 @@ +FILE: test.kt + public final class Fix : R|kotlin/Any| { + public constructor(e: R|DerivedElement|): R|Fix| { + super() + } + + } + public final fun create(d: R|Diagnostic|): R|kotlin/Unit| { + lval element: R|DerivedElement!| = R|/d|.R|/Diagnostic.element| + R|/Fix.Fix|(R|/element|) + } + public final fun createGeneric(d: R|Diagnostic|): R|kotlin/Unit| { + lval element: R|DE!| = R|/d|.R|/Diagnostic.element| + R|/Fix.Fix|(R|/element|) + } + private final val DERIVED_FACTORY: R|DiagnosticFactory0| = R|/DiagnosticFactory0.DiagnosticFactory0|() + private get(): R|DiagnosticFactory0| + public final fun createViaFactory(d: R|EmptyDiagnostic|): R|kotlin/Unit| { + lval casted: R|Diagnostic<*>!| = R|/DERIVED_FACTORY|.R|FakeOverride!|>|(R|/d|) + lval element: R|E!| = R|/casted|.R|/Diagnostic.element| + #(R|/element|) + } diff --git a/compiler/fir/resolve/testData/resolve/expresssions/genericUsedInFunction.kt b/compiler/fir/resolve/testData/resolve/expresssions/genericUsedInFunction.kt new file mode 100644 index 00000000000..eac7488d220 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/genericUsedInFunction.kt @@ -0,0 +1,9 @@ +class Generic(val value: T) { + fun foo(): T = value +} + +fun test(arg: Generic) { + val value = arg.value + val foo = arg.foo() + val length = foo.length + value.length +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/expresssions/genericUsedInFunction.txt b/compiler/fir/resolve/testData/resolve/expresssions/genericUsedInFunction.txt new file mode 100644 index 00000000000..2929a1adacd --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/genericUsedInFunction.txt @@ -0,0 +1,19 @@ +FILE: genericUsedInFunction.kt + public final class Generic : R|kotlin/Any| { + public constructor(value: R|T|): R|Generic| { + super() + } + + public final val value: R|T| = R|/value| + public get(): R|T| + + public final fun foo(): R|T| { + ^foo this@R|/Generic|.R|FakeOverride| + } + + } + public final fun test(arg: R|Generic|): R|kotlin/Unit| { + lval value: R|kotlin/String| = R|/arg|.R|FakeOverride| + lval foo: R|kotlin/String| = R|/arg|.R|FakeOverride|() + lval length: R|kotlin/Int| = R|/foo|.R|kotlin/String.length|.R|kotlin/Int.plus|(R|/value|.R|kotlin/String.length|) + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index f4fcf85f1cb..c69a8d4fd95 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -379,11 +379,21 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/resolve/testData/resolve/expresssions/genericDescriptor.kt"); } + @TestMetadata("genericDiagnostic.kt") + public void testGenericDiagnostic() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/expresssions/genericDiagnostic.kt"); + } + @TestMetadata("genericPropertyAccess.kt") public void testGenericPropertyAccess() throws Exception { runTest("compiler/fir/resolve/testData/resolve/expresssions/genericPropertyAccess.kt"); } + @TestMetadata("genericUsedInFunction.kt") + public void testGenericUsedInFunction() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/expresssions/genericUsedInFunction.kt"); + } + @TestMetadata("importedReceiver.kt") public void testImportedReceiver() throws Exception { runTest("compiler/fir/resolve/testData/resolve/expresssions/importedReceiver.kt");