[FIR] Correctly build scopes for resolve of different parts of constructors
#KT-40409 Fixed
This commit is contained in:
@@ -13,11 +13,11 @@ FILE: delegatedSuperType.kt
|
||||
|
||||
}
|
||||
public final class C : R|A| {
|
||||
local final field $$delegate_0: R|A|
|
||||
local final field <$$delegate_0>: R|A|
|
||||
|
||||
public constructor(b: R|B|): R|C| {
|
||||
super<R|kotlin/Any|>()
|
||||
this@R|/C|.R|<local>/$$delegate_0| = R|<local>/b|
|
||||
this@R|/C|.R|<local>/<$$delegate_0>| = R|<local>/b|
|
||||
}
|
||||
|
||||
public final val b: R|B| = R|<local>/b|
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// ISSUE #KT-40409
|
||||
|
||||
interface A {
|
||||
var b: B
|
||||
}
|
||||
|
||||
interface B
|
||||
|
||||
fun A.test_1() {
|
||||
object : B by this.b {}
|
||||
}
|
||||
|
||||
fun A.test_2() {
|
||||
object : B by b {}
|
||||
}
|
||||
|
||||
class D(val x: String, val y: String = this.<!UNRESOLVED_REFERENCE!>x<!>) {}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
FILE: anonymousObjectByDelegate.kt
|
||||
public abstract interface A : R|kotlin/Any| {
|
||||
public abstract var b: R|B|
|
||||
public get(): R|B|
|
||||
public set(value: R|B|): R|kotlin/Unit|
|
||||
|
||||
}
|
||||
public abstract interface B : R|kotlin/Any| {
|
||||
}
|
||||
public final fun R|A|.test_1(): R|kotlin/Unit| {
|
||||
object : R|B| {
|
||||
local final field <$$delegate_0>: R|B|
|
||||
|
||||
private[local] constructor(): R|<anonymous>| {
|
||||
super<R|kotlin/Any|>()
|
||||
this@R|/<anonymous>|.R|<local>/<$$delegate_0>| = this@R|/test_1|.R|/A.b|
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public final fun R|A|.test_2(): R|kotlin/Unit| {
|
||||
object : R|B| {
|
||||
local final field <$$delegate_0>: R|B|
|
||||
|
||||
private[local] constructor(): R|<anonymous>| {
|
||||
super<R|kotlin/Any|>()
|
||||
this@R|/<anonymous>|.R|<local>/<$$delegate_0>| = this@R|/test_2|.R|/A.b|
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public final class D : R|kotlin/Any| {
|
||||
public constructor(x: R|kotlin/String|, y: R|kotlin/String| = this#.<Unresolved name: x>#): R|D| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val x: R|kotlin/String| = R|<local>/x|
|
||||
public get(): R|kotlin/String|
|
||||
|
||||
public final val y: R|kotlin/String| = R|<local>/y|
|
||||
public get(): R|kotlin/String|
|
||||
|
||||
}
|
||||
Generated
+5
@@ -896,6 +896,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousObjectByDelegate.kt")
|
||||
public void testAnonymousObjectByDelegate() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/anonymousObjectByDelegate.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("incompatibleModifiers.kt")
|
||||
public void testIncompatibleModifiers() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt");
|
||||
|
||||
+5
@@ -896,6 +896,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/annotationClassMember.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousObjectByDelegate.kt")
|
||||
public void testAnonymousObjectByDelegate() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/anonymousObjectByDelegate.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("incompatibleModifiers.kt")
|
||||
public void testIncompatibleModifiers() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt");
|
||||
|
||||
+53
-39
@@ -36,8 +36,11 @@ import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier
|
||||
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.TypeModifier
|
||||
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.TypeParameterModifier
|
||||
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.TypeProjectionModifier
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildImplicitThisReference
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
@@ -406,7 +409,7 @@ class DeclarationsConverter(
|
||||
val selfType = classNode.toDelegatedSelfType(this)
|
||||
|
||||
|
||||
val delegationSpecifiers = superTypeList?.let { convertDelegationSpecifiers(it) }
|
||||
val delegationSpecifiers = superTypeList?.let { convertDelegationSpecifiers(it, symbol, selfType) }
|
||||
var delegatedSuperTypeRef: FirTypeRef? = delegationSpecifiers?.delegatedSuperTypeRef
|
||||
val delegatedConstructorSource: FirLightSourceElement? = delegationSpecifiers?.delegatedConstructorSource
|
||||
delegationSpecifiers?.delegateFields?.map { declarations += it }
|
||||
@@ -502,37 +505,6 @@ class DeclarationsConverter(
|
||||
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitObjectLiteralExpression
|
||||
*/
|
||||
fun convertObjectLiteral(objectLiteral: LighterASTNode): FirElement {
|
||||
var modifiers = Modifier()
|
||||
var primaryConstructor: LighterASTNode? = null
|
||||
val superTypeRefs = mutableListOf<FirTypeRef>()
|
||||
val superTypeCallEntry = mutableListOf<FirExpression>()
|
||||
var delegatedSuperTypeRef: FirTypeRef? = null
|
||||
var classBody: LighterASTNode? = null
|
||||
var delegatedConstructorSource: FirLightSourceElement? = null
|
||||
var delegateFields: List<FirField>? = null
|
||||
var primaryConstructorBody: FirBlock? = null
|
||||
objectLiteral.getChildNodesByType(OBJECT_DECLARATION).first().forEachChildren {
|
||||
when (it.tokenType) {
|
||||
MODIFIER_LIST -> modifiers = convertModifierList(it)
|
||||
PRIMARY_CONSTRUCTOR -> primaryConstructor = it
|
||||
SUPER_TYPE_LIST -> convertDelegationSpecifiers(it).let {
|
||||
delegatedSuperTypeRef = it.delegatedSuperTypeRef
|
||||
superTypeRefs += it.superTypesRef
|
||||
superTypeCallEntry += it.delegatedConstructorArguments
|
||||
delegatedConstructorSource = it.delegatedConstructorSource
|
||||
delegateFields = it.delegateFields
|
||||
primaryConstructorBody = it.primaryConstructorBody
|
||||
}
|
||||
CLASS_BODY -> classBody = it
|
||||
}
|
||||
}
|
||||
|
||||
superTypeRefs.ifEmpty {
|
||||
superTypeRefs += implicitAnyType
|
||||
delegatedSuperTypeRef = implicitAnyType
|
||||
}
|
||||
val delegatedSuperType = delegatedSuperTypeRef ?: buildImplicitTypeRef()
|
||||
|
||||
return withChildClassName(ANONYMOUS_OBJECT_NAME) {
|
||||
buildAnonymousObject {
|
||||
source = objectLiteral.toFirSourceElement()
|
||||
@@ -541,8 +513,41 @@ class DeclarationsConverter(
|
||||
classKind = ClassKind.OBJECT
|
||||
scopeProvider = baseScopeProvider
|
||||
symbol = FirAnonymousObjectSymbol()
|
||||
typeParameters += context.capturedTypeParameters.map { buildOuterClassTypeParameterRef { symbol = it } }
|
||||
typeParameters += context.capturedTypeParameters.map { buildOuterClassTypeParameterRef { this.symbol = it } }
|
||||
val delegatedSelfType = objectLiteral.toDelegatedSelfType(this)
|
||||
|
||||
var modifiers = Modifier()
|
||||
var primaryConstructor: LighterASTNode? = null
|
||||
val superTypeRefs = mutableListOf<FirTypeRef>()
|
||||
val superTypeCallEntry = mutableListOf<FirExpression>()
|
||||
var delegatedSuperTypeRef: FirTypeRef? = null
|
||||
var classBody: LighterASTNode? = null
|
||||
var delegatedConstructorSource: FirLightSourceElement? = null
|
||||
var delegateFields: List<FirField>? = null
|
||||
var primaryConstructorBody: FirBlock? = null
|
||||
|
||||
objectLiteral.getChildNodesByType(OBJECT_DECLARATION).first().forEachChildren {
|
||||
when (it.tokenType) {
|
||||
MODIFIER_LIST -> modifiers = convertModifierList(it)
|
||||
PRIMARY_CONSTRUCTOR -> primaryConstructor = it
|
||||
SUPER_TYPE_LIST -> convertDelegationSpecifiers(it, symbol, delegatedSelfType).let {
|
||||
delegatedSuperTypeRef = it.delegatedSuperTypeRef
|
||||
superTypeRefs += it.superTypesRef
|
||||
superTypeCallEntry += it.delegatedConstructorArguments
|
||||
delegatedConstructorSource = it.delegatedConstructorSource
|
||||
delegateFields = it.delegateFields
|
||||
primaryConstructorBody = it.primaryConstructorBody
|
||||
}
|
||||
CLASS_BODY -> classBody = it
|
||||
}
|
||||
}
|
||||
|
||||
superTypeRefs.ifEmpty {
|
||||
superTypeRefs += implicitAnyType
|
||||
delegatedSuperTypeRef = implicitAnyType
|
||||
}
|
||||
val delegatedSuperType = delegatedSuperTypeRef ?: buildImplicitTypeRef()
|
||||
|
||||
annotations += modifiers.annotations
|
||||
this.superTypeRefs += superTypeRefs
|
||||
typeRef = delegatedSelfType
|
||||
@@ -1322,7 +1327,7 @@ class DeclarationsConverter(
|
||||
val primaryConstructorBody: FirBlock?
|
||||
)
|
||||
|
||||
private fun convertDelegationSpecifiers(delegationSpecifiers: LighterASTNode): DelegationSpecifiers {
|
||||
private fun convertDelegationSpecifiers(delegationSpecifiers: LighterASTNode, containerSymbol: AbstractFirBasedSymbol<*>, delegatedTypeRef: FirTypeRef): DelegationSpecifiers {
|
||||
val superTypeRefs = mutableListOf<FirTypeRef>()
|
||||
val superTypeCallEntry = mutableListOf<FirExpression>()
|
||||
var delegatedSuperTypeRef: FirTypeRef? = null
|
||||
@@ -1340,7 +1345,7 @@ class DeclarationsConverter(
|
||||
delegateConstructorSource = it.toFirSourceElement()
|
||||
}
|
||||
DELEGATED_SUPER_TYPE_ENTRY -> {
|
||||
superTypeRefs += convertExplicitDelegation(it, delegateNumber, delegateFields, initializeDelegateStatements)
|
||||
superTypeRefs += convertExplicitDelegation(it, delegateNumber, delegateFields, initializeDelegateStatements, containerSymbol, delegatedTypeRef)
|
||||
delegateNumber++
|
||||
}
|
||||
}
|
||||
@@ -1388,7 +1393,9 @@ class DeclarationsConverter(
|
||||
explicitDelegation: LighterASTNode,
|
||||
delegateNumber: Int,
|
||||
delegateFields: MutableList<FirField>,
|
||||
initializeDelegateStatements: MutableList<FirStatement>
|
||||
initializeDelegateStatements: MutableList<FirStatement>,
|
||||
containerSymbol: AbstractFirBasedSymbol<*>,
|
||||
delegatedSelfTypeRef: FirTypeRef
|
||||
): FirTypeRef {
|
||||
lateinit var firTypeRef: FirTypeRef
|
||||
var firExpression: FirExpression? = buildErrorExpression(
|
||||
@@ -1401,14 +1408,14 @@ class DeclarationsConverter(
|
||||
}
|
||||
}
|
||||
|
||||
val delegateName = Name.identifier("\$\$delegate_$delegateNumber")
|
||||
val delegateName = Name.special("<\$\$delegate_$delegateNumber>")
|
||||
delegateFields.add(
|
||||
buildField {
|
||||
source = firExpression!!.source
|
||||
session = baseSession
|
||||
origin = FirDeclarationOrigin.Synthetic
|
||||
name = delegateName
|
||||
returnTypeRef = firTypeRef!!
|
||||
returnTypeRef = firTypeRef
|
||||
symbol = FirFieldSymbol(CallableId(name))
|
||||
isVar = false
|
||||
status = FirDeclarationStatusImpl(Visibilities.LOCAL, Modality.FINAL)
|
||||
@@ -1418,10 +1425,17 @@ class DeclarationsConverter(
|
||||
buildVariableAssignment {
|
||||
source = firExpression!!.source
|
||||
calleeReference =
|
||||
buildSimpleNamedReference {
|
||||
buildResolvedNamedReference {
|
||||
name = delegateName
|
||||
resolvedSymbol = delegateFields[delegateNumber].symbol
|
||||
}
|
||||
rValue = firExpression!!
|
||||
dispatchReceiver = buildThisReceiverExpression {
|
||||
calleeReference = buildImplicitThisReference {
|
||||
boundSymbol = containerSymbol
|
||||
}
|
||||
typeRef = delegatedSelfTypeRef
|
||||
}
|
||||
}
|
||||
)
|
||||
return firTypeRef
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.builder.*
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
@@ -455,7 +456,8 @@ class RawFirBuilder(
|
||||
delegatedSelfTypeRef: FirTypeRef?,
|
||||
delegatedEnumSuperTypeRef: FirTypeRef?,
|
||||
classKind: ClassKind,
|
||||
containerTypeParameters: List<FirTypeParameterRef>
|
||||
containerTypeParameters: List<FirTypeParameterRef>,
|
||||
containerSymbol: AbstractFirBasedSymbol<*>
|
||||
): FirTypeRef {
|
||||
var superTypeCallEntry: KtSuperTypeCallEntry? = null
|
||||
var delegatedSuperTypeRef: FirTypeRef? = null
|
||||
@@ -475,7 +477,7 @@ class RawFirBuilder(
|
||||
val type = superTypeListEntry.typeReference.toFirOrErrorType()
|
||||
val delegateExpression = { superTypeListEntry.delegateExpression }.toFirExpression("Should have delegate")
|
||||
container.superTypeRefs += type
|
||||
val delegateName = Name.identifier("\$\$delegate_$delegateNumber")
|
||||
val delegateName = Name.special("<\$\$delegate_$delegateNumber>")
|
||||
val delegateSource = superTypeListEntry.delegateExpression?.toFirSourceElement()
|
||||
val delegateField = buildField {
|
||||
source = delegateSource
|
||||
@@ -491,10 +493,17 @@ class RawFirBuilder(
|
||||
buildVariableAssignment {
|
||||
source = delegateSource
|
||||
calleeReference =
|
||||
buildSimpleNamedReference {
|
||||
buildResolvedNamedReference {
|
||||
name = delegateName
|
||||
resolvedSymbol = delegateField.symbol
|
||||
}
|
||||
rValue = delegateExpression
|
||||
dispatchReceiver = buildThisReceiverExpression {
|
||||
calleeReference = buildImplicitThisReference {
|
||||
boundSymbol = containerSymbol
|
||||
}
|
||||
delegatedSelfTypeRef?.let { typeRef = it }
|
||||
}
|
||||
}
|
||||
)
|
||||
container.declarations.add(delegateField)
|
||||
@@ -747,8 +756,14 @@ class RawFirBuilder(
|
||||
addCapturedTypeParameters(typeParameters.take(classOrObject.typeParameters.size))
|
||||
|
||||
val delegatedSelfType = classOrObject.toDelegatedSelfType(this)
|
||||
val delegatedSuperType =
|
||||
classOrObject.extractSuperTypeListEntriesTo(this, delegatedSelfType, null, classKind, typeParameters)
|
||||
val delegatedSuperType = classOrObject.extractSuperTypeListEntriesTo(
|
||||
this,
|
||||
delegatedSelfType,
|
||||
null,
|
||||
classKind,
|
||||
typeParameters,
|
||||
symbol
|
||||
)
|
||||
|
||||
val primaryConstructor = classOrObject.primaryConstructor
|
||||
val firPrimaryConstructor = declarations.firstOrNull {it is FirConstructor} as? FirConstructor
|
||||
@@ -827,7 +842,8 @@ class RawFirBuilder(
|
||||
delegatedSelfType,
|
||||
null,
|
||||
ClassKind.CLASS,
|
||||
containerTypeParameters = emptyList()
|
||||
containerTypeParameters = emptyList(),
|
||||
symbol
|
||||
)
|
||||
typeRef = delegatedSelfType
|
||||
|
||||
|
||||
+67
-3
@@ -526,13 +526,73 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
if (constructor.isPrimary && containingClass?.classKind == ClassKind.ANNOTATION_CLASS) {
|
||||
return withFirArrayOfCallTransformer {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
transformFunction(constructor, data) as CompositeTransformResult<FirDeclaration>
|
||||
doTransformConstructor(constructor, data)
|
||||
}
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return transformFunction(constructor, data) as CompositeTransformResult<FirDeclaration>
|
||||
return doTransformConstructor(constructor, data)
|
||||
}
|
||||
|
||||
private fun doTransformConstructor(constructor: FirConstructor, data: ResolutionMode): CompositeTransformResult<FirConstructor> {
|
||||
return context.withContainer(constructor) {
|
||||
constructor.replaceResolvePhase(transformerPhase)
|
||||
dataFlowAnalyzer.enterFunction(constructor)
|
||||
|
||||
constructor.transformTypeParameters(transformer, data)
|
||||
.transformAnnotations(transformer, data)
|
||||
.transformReceiverTypeRef(transformer, data)
|
||||
.transformReturnTypeRef(transformer, data)
|
||||
|
||||
/*
|
||||
* Default values of constructor can't access members of constructing class
|
||||
*/
|
||||
context.withTowerDataContext(context.getTowerDataContextForConstructorResolution()) {
|
||||
withNewLocalScope {
|
||||
constructor.transformValueParameters(transformer, data)
|
||||
}
|
||||
}
|
||||
|
||||
val scopeWithValueParameters = if (constructor.isPrimary) {
|
||||
context.getPrimaryConstructorParametersScope()
|
||||
} else {
|
||||
constructor.scopeWithParameters()
|
||||
}
|
||||
|
||||
/*
|
||||
* Delegated constructor call is called before constructor body, so we need to
|
||||
* analyze it before body, so body can access smartcasts from that call
|
||||
*/
|
||||
context.withTowerDataCleanup {
|
||||
addLocalScope(scopeWithValueParameters)
|
||||
constructor.transformDelegatedConstructor(transformer, data)
|
||||
}
|
||||
|
||||
if (constructor.body != null) {
|
||||
if (constructor.isPrimary) {
|
||||
/*
|
||||
* Primary constructor may have body only if class delegates implementation to some property
|
||||
* In it's body we don't have this receiver for building class, so we need to use
|
||||
* special towerDataContext
|
||||
*/
|
||||
context.withTowerDataContext(context.getTowerDataContextForConstructorResolution()) {
|
||||
addLocalScope(scopeWithValueParameters)
|
||||
constructor.transformBody(transformer, data)
|
||||
}
|
||||
} else {
|
||||
withLocalScopeCleanup {
|
||||
addLocalScope(scopeWithValueParameters)
|
||||
constructor.transformBody(transformer, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val graph = dataFlowAnalyzer.exitFunction(constructor)
|
||||
constructor.transformControlFlowGraphReference(ControlFlowGraphReferenceTransformer, graph)
|
||||
constructor.compose()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun transformAnonymousInitializer(
|
||||
anonymousInitializer: FirAnonymousInitializer,
|
||||
data: ResolutionMode
|
||||
@@ -753,7 +813,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
val constructor = (owner as? FirRegularClass)?.declarations?.firstOrNull { it is FirConstructor } as? FirConstructor
|
||||
val primaryConstructorParametersScope =
|
||||
if (constructor?.isPrimary == true) {
|
||||
constructor.valueParameters.fold(FirLocalScope()) { acc, param -> acc.storeVariable(param) }
|
||||
constructor.scopeWithParameters()
|
||||
} else null
|
||||
|
||||
components.context.replaceTowerDataContext(forMembersResolution)
|
||||
@@ -770,6 +830,10 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirConstructor.scopeWithParameters(): FirLocalScope {
|
||||
return valueParameters.fold(FirLocalScope()) { acc, param -> acc.storeVariable(param) }
|
||||
}
|
||||
|
||||
protected inline fun <T> withLabelAndReceiverType(
|
||||
labelName: Name?,
|
||||
owner: FirCallableDeclaration<*>,
|
||||
|
||||
Reference in New Issue
Block a user