Refine implicit receiver type resolution and enhance related tests.

This commit is contained in:
Sergey Chernov 2026-02-06 13:46:38 +03:00
parent 3b290116b8
commit 79bece94a5
2 changed files with 36 additions and 16 deletions

View File

@ -599,6 +599,16 @@ class Compiler(
return null
}
private fun implicitReceiverTypeForMember(name: String): String? {
for (ctx in codeContexts.asReversed()) {
val fn = ctx as? CodeContext.Function ?: continue
if (!fn.implicitThisMembers) continue
val typeName = fn.implicitThisTypeName ?: continue
if (hasImplicitThisMember(name, typeName)) return typeName
}
return null
}
private fun currentEnclosingClassName(): String? {
val ctx = codeContexts.asReversed().firstOrNull { it is CodeContext.ClassBody } as? CodeContext.ClassBody
return ctx?.name
@ -836,14 +846,12 @@ class Compiler(
if (hasImplicitThisMember(name, implicitType)) {
resolutionSink?.referenceMember(name, pos, implicitType)
val ids = resolveImplicitThisMemberIds(name, pos, implicitType)
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, implicitType)
val preferredType = if (currentImplicitThisTypeName() == null) null else implicitType
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, preferredType)
}
}
val implicitThisMembers = codeContexts.any { ctx ->
(ctx as? CodeContext.Function)?.implicitThisMembers == true
}
val implicitType = if (implicitThisMembers) currentImplicitThisTypeName() else null
if (implicitType != null && hasImplicitThisMember(name, implicitType)) {
val implicitType = implicitReceiverTypeForMember(name)
if (implicitType != null) {
resolutionSink?.referenceMember(name, pos, implicitType)
val ids = resolveImplicitThisMemberIds(name, pos, implicitType)
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, implicitType)
@ -4456,7 +4464,7 @@ class Compiler(
detectedBlockArgument,
isOptional,
left.atPos,
implicitThisTypeName
left.preferredThisTypeName() ?: implicitThisTypeName
)
}
is LocalVarRef -> {
@ -4465,7 +4473,8 @@ class Compiler(
(ctx as? CodeContext.Function)?.implicitThisMembers == true
}
if ((classContext || implicitThis) && extensionNames.contains(left.name)) {
val ids = resolveImplicitThisMemberIds(left.name, left.pos(), implicitThisTypeName)
val receiverTypeName = implicitReceiverTypeForMember(left.name) ?: implicitThisTypeName
val ids = resolveImplicitThisMemberIds(left.name, left.pos(), receiverTypeName)
ImplicitThisMethodCallRef(
left.name,
ids.methodId,
@ -4473,7 +4482,7 @@ class Compiler(
detectedBlockArgument,
isOptional,
left.pos(),
implicitThisTypeName
receiverTypeName
)
} else {
checkGenericBoundsAtCall(left.name, args, left.pos())
@ -4486,7 +4495,8 @@ class Compiler(
(ctx as? CodeContext.Function)?.implicitThisMembers == true
}
if ((classContext || implicitThis) && extensionNames.contains(left.name)) {
val ids = resolveImplicitThisMemberIds(left.name, left.pos(), implicitThisTypeName)
val receiverTypeName = implicitReceiverTypeForMember(left.name) ?: implicitThisTypeName
val ids = resolveImplicitThisMemberIds(left.name, left.pos(), receiverTypeName)
ImplicitThisMethodCallRef(
left.name,
ids.methodId,
@ -4494,7 +4504,7 @@ class Compiler(
detectedBlockArgument,
isOptional,
left.pos(),
implicitThisTypeName
receiverTypeName
)
} else {
checkGenericBoundsAtCall(left.name, args, left.pos())

View File

@ -266,7 +266,7 @@ class TypesTest {
}
@Test
fun multipleReceivers() = runTest {
fun testMultipleReceivers() = runTest {
eval("""
class R1(shared,r1="r1")
class R2(shared,r2="r2")
@ -278,10 +278,20 @@ class TypesTest {
assertEquals("r2", r2)
assertEquals("t", shared)
assertEquals("s", this@R1.shared)
// actually we have now this of union type R1 & R2!
// println(this::class)
assert( this@R2 is R2 )
// assert( this@R1 is R1 )
assertEquals("r1", this@R1.r1)
assertEquals("r2", this@R2.r2)
assertEquals("r1", r1)
}
}
with(R1("s")) {
assertEquals("r1", r1)
assertEquals("s", shared)
with(R2("t")) {
assertEquals("r2", r2)
assertEquals("t", shared)
assertEquals("s", this@R1.shared)
assertEquals("r1", this@R1.r1)
assertEquals("r1", r1)
}
}
""")