From 79bece94a5708687a55e7c6b1d2f7ec6f3546b1c Mon Sep 17 00:00:00 2001 From: sergeych Date: Fri, 6 Feb 2026 13:46:38 +0300 Subject: [PATCH] Refine implicit receiver type resolution and enhance related tests. --- .../kotlin/net/sergeych/lyng/Compiler.kt | 32 ++++++++++++------- lynglib/src/commonTest/kotlin/TypesTest.kt | 20 +++++++++--- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index cb48802..a4b9bfc 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -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()) diff --git a/lynglib/src/commonTest/kotlin/TypesTest.kt b/lynglib/src/commonTest/kotlin/TypesTest.kt index 9916a6d..4531533 100644 --- a/lynglib/src/commonTest/kotlin/TypesTest.kt +++ b/lynglib/src/commonTest/kotlin/TypesTest.kt @@ -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) } } """)