diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index 738b1c9e77d..54b91716eae 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -219,7 +219,7 @@ internal class Fir2IrVisitor( } } else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION) { // Trivial fake override case - val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverride(session, originalFunction, functionSymbol) + val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideFunction(session, originalFunction, functionSymbol) val fakeOverrideFunction = fakeOverrideSymbol.fir val irFunction = declarationStorage.getIrFunction( 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 6619747ba23..8f393317aa8 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 @@ -7,9 +7,8 @@ package org.jetbrains.kotlin.fir.scopes.impl import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirNamedFunction -import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl -import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl -import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.impl.* import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorWithJump @@ -31,14 +30,15 @@ class FirClassSubstitutionScope( substitution: Map ) : FirScope() { - private val fakeOverrides = mutableMapOf, FirFunctionSymbol<*>>() + private val fakeOverrideFunctions = mutableMapOf, FirFunctionSymbol<*>>() + private val fakeOverrideProperties = mutableMapOf() private val substitutor = substitutorByMap(substitution) override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction { useSiteScope.processFunctionsByName(name) process@{ original -> - val function = fakeOverrides.getOrPut(original) { createFakeOverride(original) } + val function = fakeOverrideFunctions.getOrPut(original) { createFakeOverrideFunction(original) } processor(function) } @@ -47,7 +47,14 @@ class FirClassSubstitutionScope( } override fun processPropertiesByName(name: Name, processor: (FirCallableSymbol<*>) -> ProcessorAction): ProcessorAction { - return useSiteScope.processPropertiesByName(name, processor) + return useSiteScope.processPropertiesByName(name) process@{ original -> + if (original is FirPropertySymbol) { + val property = fakeOverrideProperties.getOrPut(original) { createFakeOverrideProperty(original) } + processor(property) + } else { + processor(original) + } + } } private val typeCalculator by lazy { ReturnTypeCalculatorWithJump(session, scopeSession) } @@ -56,7 +63,7 @@ class FirClassSubstitutionScope( return substitutor.substituteOrNull(this) } - private fun createFakeOverride(original: FirFunctionSymbol<*>): FirFunctionSymbol<*> { + private fun createFakeOverrideFunction(original: FirFunctionSymbol<*>): FirFunctionSymbol<*> { val member = when (original) { is FirNamedFunctionSymbol -> original.fir is FirConstructorSymbol -> return original @@ -73,11 +80,23 @@ class FirClassSubstitutionScope( it.returnTypeRef.coneTypeUnsafe().substitute() } - return createFakeOverride(session, member, original, newReceiverType, newReturnType, newParameterTypes) + return createFakeOverrideFunction(session, member, original, newReceiverType, newReturnType, newParameterTypes) + } + + private fun createFakeOverrideProperty(original: FirPropertySymbol): FirPropertySymbol { + val member = original.fir + + val receiverType = member.receiverTypeRef?.coneTypeUnsafe() + val newReceiverType = receiverType?.substitute() + + val returnType = typeCalculator.tryCalculateReturnType(member).type + val newReturnType = returnType.substitute() + + return createFakeOverrideProperty(session, member, original, newReceiverType, newReturnType) } companion object { - fun createFakeOverride( + fun createFakeOverrideFunction( session: FirSession, baseFunction: FirNamedFunction, baseSymbol: FirNamedFunctionSymbol, @@ -113,6 +132,29 @@ class FirClassSubstitutionScope( } return symbol } + + fun createFakeOverrideProperty( + session: FirSession, + baseProperty: FirProperty, + baseSymbol: FirPropertySymbol, + newReceiverType: ConeKotlinType? = null, + newReturnType: ConeKotlinType? = null + ): FirPropertySymbol { + val symbol = FirPropertySymbol(baseSymbol.callableId, true, baseSymbol) + with(baseProperty) { + FirMemberPropertyImpl( + session, + psi, symbol, name, + baseProperty.receiverTypeRef?.withReplacedConeType(newReceiverType), + baseProperty.returnTypeRef.withReplacedConeType(newReturnType), + isVar, initializer = null, delegate = null + ).apply { + resolvePhase = baseProperty.resolvePhase + status = baseProperty.status as FirDeclarationStatusImpl + } + } + return symbol + } } } diff --git a/compiler/fir/resolve/testData/resolve/expresssions/genericPropertyAccess.kt b/compiler/fir/resolve/testData/resolve/expresssions/genericPropertyAccess.kt new file mode 100644 index 00000000000..9a1cfd6472b --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/genericPropertyAccess.kt @@ -0,0 +1,7 @@ +abstract class Base(val x: T) { + abstract fun foo(): T +} + +class Derived(x: T) : Base(x) { + override fun foo(): T = x +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/expresssions/genericPropertyAccess.txt b/compiler/fir/resolve/testData/resolve/expresssions/genericPropertyAccess.txt new file mode 100644 index 00000000000..f10c4bd12aa --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/genericPropertyAccess.txt @@ -0,0 +1,22 @@ +FILE: genericPropertyAccess.kt + public abstract class Base : R|kotlin/Any| { + public constructor(x: R|T|): R|Base| { + super() + } + + public final val x: R|T| = R|/x| + public get(): R|T| + + public abstract fun foo(): R|T| + + } + public final class Derived : R|Base| { + public constructor(x: R|T|): R|Derived| { + super|>(R|/x|) + } + + public final override fun foo(): R|T| { + ^foo this@R|/Base|.R|/Base.x| + } + + } diff --git a/compiler/fir/resolve/testData/resolve/stdlib/problems.txt b/compiler/fir/resolve/testData/resolve/stdlib/problems.txt index 7574a10cc11..9fcf50d1053 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/problems.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/problems.txt @@ -53,8 +53,8 @@ FILE: problems.kt } } - public final val xx: = R|/Derived.Derived|().R|/Base.x|.#(Int(1)) - public get(): + public final val xx: R|kotlin/Int| = R|/Derived.Derived|().R|/Base.x|.R|kotlin/Int.plus|(Int(1)) + public get(): R|kotlin/Int| public final val t: R|kotlin/Nothing| = throw R|java/lang/AssertionError.AssertionError|(String()) public get(): R|kotlin/Nothing| public abstract interface A : R|kotlin/Any| { diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java index 82d3c0900d7..c332a311b74 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java @@ -287,6 +287,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase { runTest("compiler/fir/resolve/testData/resolve/expresssions/dispatchReceiver.kt"); } + @TestMetadata("genericPropertyAccess.kt") + public void testGenericPropertyAccess() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/expresssions/genericPropertyAccess.kt"); + } + @TestMetadata("importedReceiver.kt") public void testImportedReceiver() throws Exception { runTest("compiler/fir/resolve/testData/resolve/expresssions/importedReceiver.kt"); diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirMemberPropertyImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirMemberPropertyImpl.kt index d303c89b02b..36a12606dde 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirMemberPropertyImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirMemberPropertyImpl.kt @@ -24,31 +24,73 @@ import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.name.Name -class FirMemberPropertyImpl( - session: FirSession, - psi: PsiElement?, - override val symbol: FirPropertySymbol, - name: Name, - visibility: Visibility, - modality: Modality?, - isExpect: Boolean, - isActual: Boolean, - isOverride: Boolean, - isConst: Boolean, - isLateInit: Boolean, - receiverTypeRef: FirTypeRef?, - returnTypeRef: FirTypeRef, - override val isVar: Boolean, - override var initializer: FirExpression?, +class FirMemberPropertyImpl : FirAbstractCallableMember, FirProperty, FirModifiableAccessorsOwner { + override val symbol: FirPropertySymbol + override val isVar: Boolean + override var initializer: FirExpression? override var delegate: FirExpression? -) : FirAbstractCallableMember( - session, psi, name, visibility, modality, isExpect, isActual, isOverride, receiverTypeRef, returnTypeRef -), FirProperty, FirModifiableAccessorsOwner { - // TODO: backing field may not exist - override val backingFieldSymbol = FirBackingFieldSymbol(symbol.callableId) - override val delegateFieldSymbol: FirDelegateFieldSymbol? = - delegate?.let { FirDelegateFieldSymbol(symbol.callableId) } + private fun bindSymbols(symbol: FirPropertySymbol) { + symbol.bind(this) + backingFieldSymbol.bind(this) + delegateFieldSymbol?.bind(this) + } + + constructor( + session: FirSession, + psi: PsiElement?, + symbol: FirPropertySymbol, + name: Name, + receiverTypeRef: FirTypeRef?, + returnTypeRef: FirTypeRef, + isVar: Boolean, + initializer: FirExpression?, + delegate: FirExpression? + ) : super(session, psi, name, receiverTypeRef, returnTypeRef) { + this.isVar = isVar + this.initializer = initializer + this.delegate = delegate + this.symbol = symbol + this.backingFieldSymbol = FirBackingFieldSymbol(symbol.callableId) + this.delegateFieldSymbol = delegate?.let { FirDelegateFieldSymbol(symbol.callableId) } + bindSymbols(symbol) + } + + constructor( + session: FirSession, + psi: PsiElement?, + symbol: FirPropertySymbol, + name: Name, + visibility: Visibility, + modality: Modality?, + isExpect: Boolean, + isActual: Boolean, + isOverride: Boolean, + isConst: Boolean, + isLateInit: Boolean, + receiverTypeRef: FirTypeRef?, + returnTypeRef: FirTypeRef, + isVar: Boolean, + initializer: FirExpression?, + delegate: FirExpression? + ) : super( + session, psi, name, visibility, modality, isExpect, isActual, isOverride, receiverTypeRef, returnTypeRef + ) { + this.isVar = isVar + this.initializer = initializer + this.delegate = delegate + status.isConst = isConst + status.isLateInit = isLateInit + this.symbol = symbol + this.backingFieldSymbol = FirBackingFieldSymbol(symbol.callableId) + this.delegateFieldSymbol = delegate?.let { FirDelegateFieldSymbol(symbol.callableId) } + bindSymbols(symbol) + } + + // TODO: backing field may not exist + override val backingFieldSymbol: FirBackingFieldSymbol + + override val delegateFieldSymbol: FirDelegateFieldSymbol? override var getter: FirPropertyAccessor? = null @@ -56,14 +98,6 @@ class FirMemberPropertyImpl( override var controlFlowGraphReference: FirControlFlowGraphReference = FirEmptyControlFlowGraphReference() - init { - symbol.bind(this) - backingFieldSymbol.bind(this) - delegateFieldSymbol?.bind(this) - status.isConst = isConst - status.isLateInit = isLateInit - } - override fun transformChildrenWithoutAccessors(transformer: FirTransformer, data: D) { initializer = initializer?.transformSingle(transformer, data) delegate = delegate?.transformSingle(transformer, data) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt index a84b9a33a48..8df35e7cfc4 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirVariableSymbol.kt @@ -20,7 +20,12 @@ open class FirVariableSymbol>(override val callableId: Callab constructor(name: Name) : this(CallableId(name)) // TODO? } -open class FirPropertySymbol(callableId: CallableId) : ConePropertySymbol, FirVariableSymbol(callableId) +open class FirPropertySymbol( + callableId: CallableId, + val isFakeOverride: Boolean = false, + // Actual for fake override only + val overriddenSymbol: FirPropertySymbol? = null +) : ConePropertySymbol, FirVariableSymbol(callableId) class FirBackingFieldSymbol(callableId: CallableId) : FirVariableSymbol(callableId) diff --git a/compiler/testData/ir/irText/expressions/thisOfGenericOuterClass.fir.txt b/compiler/testData/ir/irText/expressions/thisOfGenericOuterClass.fir.txt index efab0a74f09..1c124187ede 100644 --- a/compiler/testData/ir/irText/expressions/thisOfGenericOuterClass.fir.txt +++ b/compiler/testData/ir/irText/expressions/thisOfGenericOuterClass.fir.txt @@ -77,7 +77,7 @@ FILE fqName: fileName:/thisOfGenericOuterClass.kt PROPERTY name:xx visibility:public modality:FINAL [val] FIELD PROPERTY_BACKING_FIELD name:xx type:IrErrorType visibility:private [final] EXPRESSION_BODY - ERROR_CALL 'Unresolved reference: #' type=IrErrorType + ERROR_CALL 'Unresolved reference: #' type=IrErrorType ERROR_CALL 'Unresolved reference: #' type=IrErrorType FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:.test.) returnType:IrErrorType correspondingProperty: PROPERTY name:xx visibility:public modality:FINAL [val] diff --git a/compiler/testData/ir/irText/stubs/builtinMap.fir.txt b/compiler/testData/ir/irText/stubs/builtinMap.fir.txt index b14c20e7178..eab862aa02f 100644 --- a/compiler/testData/ir/irText/stubs/builtinMap.fir.txt +++ b/compiler/testData/ir/irText/stubs/builtinMap.fir.txt @@ -23,6 +23,7 @@ FILE fqName: fileName:/builtinMap.kt FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (it:java.util.LinkedHashMap.plus, V1 of .plus>) returnType:kotlin.Unit VALUE_PARAMETER name:it index:0 type:java.util.LinkedHashMap.plus, V1 of .plus> BLOCK_BODY - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - ERROR_CALL 'No getter found for R|kotlin/Pair.first|' type=A of kotlin.Pair - ERROR_CALL 'No getter found for R|kotlin/Pair.second|' type=B of kotlin.Pair + CALL 'public open fun put (: K1 of .plus, : V1 of .plus): V1 of .plus declared in java.util.HashMap' type=V1 of .plus origin=null + $this: GET_VAR ': java.util.HashMap declared in java.util.HashMap' type=java.util.HashMap<*, *> origin=null + : ERROR_CALL 'No getter found for R|kotlin/Pair.first|' type=K1 of .plus + : ERROR_CALL 'No getter found for R|kotlin/Pair.second|' type=V1 of .plus diff --git a/compiler/testData/ir/irText/types/localVariableOfIntersectionType_NI.fir.txt b/compiler/testData/ir/irText/types/localVariableOfIntersectionType_NI.fir.txt index 5c63635690f..fd5e226c237 100644 --- a/compiler/testData/ir/irText/types/localVariableOfIntersectionType_NI.fir.txt +++ b/compiler/testData/ir/irText/types/localVariableOfIntersectionType_NI.fir.txt @@ -94,14 +94,13 @@ FILE fqName: fileName:/localVariableOfIntersectionType_NI.kt VALUE_PARAMETER name:b index:1 type:.In<.IB> VALUE_PARAMETER name:z index:2 type:.Z BLOCK_BODY - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - VAR name:t type:T of .Inv [val] - CALL 'public abstract fun (): T of .Inv declared in .Inv' type=T of .Inv origin=null - $this: CALL 'public abstract fun create (x: .In.Z.create>, y: .In.Z.create>): .Inv.Z.create> declared in .Z' type=.Inv<.IA> origin=null - : - $this: GET_VAR 'z: .Z declared in .test' type=.Z origin=null - x: GET_VAR 'a: .In<.IA> declared in .test' type=.In<.IA> origin=null - y: GET_VAR 'b: .In<.IB> declared in .test' type=.In<.IB> origin=null - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - ERROR_CALL 'Unresolved reference: #' type=IrErrorType + CALL 'public abstract fun foo (): kotlin.Unit declared in .IA' type=kotlin.Unit origin=null + $this: ERROR_CALL 'No getter found for R|/Inv.t|' type=.IA + CALL 'public abstract fun bar (): kotlin.Unit declared in .IB' type=kotlin.Unit origin=null + $this: ERROR_CALL 'No getter found for R|/Inv.t|' type=.IA + VAR name:t type:.IA [val] + ERROR_CALL 'No getter found for R|/Inv.t|' type=.IA + CALL 'public abstract fun foo (): kotlin.Unit declared in .IA' type=kotlin.Unit origin=null + $this: GET_VAR 'val t: .IA [val] declared in .test' type=.IA origin=null + CALL 'public abstract fun bar (): kotlin.Unit declared in .IB' type=kotlin.Unit origin=null + $this: GET_VAR 'val t: .IA [val] declared in .test' type=.IA origin=null