FIR substitution: generate fake overrides for accessor symbols

This commit is contained in:
Mikhail Glukhikh
2019-11-14 13:48:51 +03:00
parent bd70daa3d1
commit 635add4823
8 changed files with 173 additions and 10 deletions
@@ -36,6 +36,7 @@ class FirClassSubstitutionScope(
private val fakeOverrideFunctions = mutableMapOf<FirFunctionSymbol<*>, FirFunctionSymbol<*>>()
private val fakeOverrideProperties = mutableMapOf<FirPropertySymbol, FirPropertySymbol>()
private val fakeOverrideFields = mutableMapOf<FirFieldSymbol, FirFieldSymbol>()
private val fakeOverrideAccessors = mutableMapOf<FirAccessorSymbol, FirAccessorSymbol>()
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<ConeKotlinType>().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<FirSimpleFunction>,
session: FirSession,
baseFunction: FirSimpleFunction,
baseSymbol: FirNamedFunctionSymbol,
newReceiverType: ConeKotlinType? = null,
newReturnType: ConeKotlinType? = null,
newParameterTypes: List<ConeKotlinType?>? = 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<ConeKotlinType?>? = 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<ConeKotlinType?>? = null
): FirAccessorSymbol {
val symbol = FirAccessorSymbol(baseSymbol.callableId, baseSymbol.accessorId)
createFakeOverrideFunction(symbol, session, baseFunction, null, newReturnType, newParameterTypes)
return symbol
}
}
}
@@ -20,8 +20,8 @@ interface Call<D : Descriptor> {
val resultingDescriptor: D
}
fun <D> test(call: Call<D>, resolvedCall: ResolvedCall<D>) {
call.resultingDescriptor.<!INAPPLICABLE_CANDIDATE!>name<!>
fun <D : Descriptor> test(call: Call<D>, resolvedCall: ResolvedCall<D>) {
call.resultingDescriptor.name
resolvedCall.resultingDescriptor.name
}
@@ -6,8 +6,8 @@ FILE: test.kt
public get(): R|D|
}
public final fun <D> test(call: R|Call<D>|, resolvedCall: R|ResolvedCall<D>|): R|kotlin/Unit| {
R|<local>/call|.R|FakeOverride</Call.resultingDescriptor: R|D|>|.<Inapplicable(WRONG_RECEIVER): [/name]>#
public final fun <D : R|Descriptor|> test(call: R|Call<D>|, resolvedCall: R|ResolvedCall<D>|): R|kotlin/Unit| {
R|<local>/call|.R|FakeOverride</Call.resultingDescriptor: R|D|>|.R|/name|
R|<local>/resolvedCall|.R|/ResolvedCall.resultingDescriptor|.R|/name|
}
public final fun otherTest(call: R|Call<*>|, resolvedCall: R|ResolvedCall<*>|): R|kotlin/Unit| {
@@ -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<E extends Element> extends EmptyDiagnostic {
@NotNull
public E getElement();
}
// FILE: DiagnosticFactory.java
import org.jetbrains.annotations.NotNull;
public class DiagnosticFactory<D extends EmptyDiagnostic> {
@NotNull
public D cast(@NotNull EmptyDiagnostic diagnostic) {
return (D) diagnostic;
}
}
// FILE: DiagnosticFactory0.java
public class DiagnosticFactory0<E extends Element> extends DiagnosticFactory<Diagnostic> {}
// FILE: test.kt
class Fix(e: DerivedElement)
fun create(d: Diagnostic<DerivedElement>) {
val element = d.element
Fix(element)
}
fun <DE : DerivedElement> createGeneric(d: Diagnostic<DE>) {
val element = d.element
Fix(element)
}
private val DERIVED_FACTORY = DiagnosticFactory0<DerivedElement>()
fun createViaFactory(d: EmptyDiagnostic) {
val casted = DERIVED_FACTORY.cast(d)
val element = casted.element
<!INAPPLICABLE_CANDIDATE!>Fix<!>(element)
}
@@ -0,0 +1,22 @@
FILE: test.kt
public final class Fix : R|kotlin/Any| {
public constructor(e: R|DerivedElement|): R|Fix| {
super<R|kotlin/Any|>()
}
}
public final fun create(d: R|Diagnostic<DerivedElement>|): R|kotlin/Unit| {
lval element: R|DerivedElement!| = R|<local>/d|.R|/Diagnostic.element|
R|/Fix.Fix|(R|<local>/element|)
}
public final fun <DE : R|DerivedElement|> createGeneric(d: R|Diagnostic<DE>|): R|kotlin/Unit| {
lval element: R|DE!| = R|<local>/d|.R|/Diagnostic.element|
R|/Fix.Fix|(R|<local>/element|)
}
private final val DERIVED_FACTORY: R|DiagnosticFactory0<DerivedElement>| = R|/DiagnosticFactory0.DiagnosticFactory0|<R|DerivedElement|>()
private get(): R|DiagnosticFactory0<DerivedElement>|
public final fun createViaFactory(d: R|EmptyDiagnostic|): R|kotlin/Unit| {
lval casted: R|Diagnostic<*>!| = R|/DERIVED_FACTORY|.R|FakeOverride</DiagnosticFactory.cast: R|Diagnostic<*>!|>|(R|<local>/d|)
lval element: R|E!| = R|<local>/casted|.R|/Diagnostic.element|
<Inapplicable(INAPPLICABLE): [/Fix.Fix]>#(R|<local>/element|)
}
@@ -0,0 +1,9 @@
class Generic<T : CharSequence?>(val value: T) {
fun foo(): T = value
}
fun test(arg: Generic<String>) {
val value = arg.value
val foo = arg.foo()
val length = foo.length + value.length
}
@@ -0,0 +1,19 @@
FILE: genericUsedInFunction.kt
public final class Generic<T : R|kotlin/CharSequence?|> : R|kotlin/Any| {
public constructor<T : R|kotlin/CharSequence?|>(value: R|T|): R|Generic<T>| {
super<R|kotlin/Any|>()
}
public final val value: R|T| = R|<local>/value|
public get(): R|T|
public final fun foo(): R|T| {
^foo this@R|/Generic|.R|FakeOverride</Generic.value: R|T|>|
}
}
public final fun test(arg: R|Generic<kotlin/String>|): R|kotlin/Unit| {
lval value: R|kotlin/String| = R|<local>/arg|.R|FakeOverride</Generic.value: R|kotlin/String|>|
lval foo: R|kotlin/String| = R|<local>/arg|.R|FakeOverride</Generic.foo: R|kotlin/String|>|()
lval length: R|kotlin/Int| = R|<local>/foo|.R|kotlin/String.length|.R|kotlin/Int.plus|(R|<local>/value|.R|kotlin/String.length|)
}
@@ -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");