FIR substitution: generate fake overrides for accessor symbols
This commit is contained in:
+51
-6
@@ -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|)
|
||||
}
|
||||
+10
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user