From b73908a361b492a7bceafdd08c875bf8624a96ae Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 6 May 2026 02:21:37 +0800 Subject: [PATCH] fix #25789; improve handling of distinct types (#25791) fix #25789 This pull request addresses an issue with the `distinctBase` trait in the Nim compiler, ensuring it correctly handles types with generic parameters and static parameters. Additionally, it adds a new test to cover this scenario. The most important changes are: ### Compiler logic improvements * Updated the `evalTypeTrait` implementation for the `distinctBase` trait in `compiler/semmagic.nim` to properly skip all relevant type wrappers, including those with generic and static parameters, when unwrapping distinct types. This fixes incorrect handling of types like `distinct L[int, 100]`. ### Test coverage * Added a new test block for bug #25789 in `tests/metatype/ttypetraits.nim` that defines a distinct type over a generic type with a static parameter, verifies conversions, and checks that the `distinctBase` trait returns the correct type. --- compiler/semmagic.nim | 9 ++++++--- tests/metatype/ttypetraits.nim | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 88d7512373..397c08bf67 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -248,10 +248,13 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) assert operand.kind == tyTuple, $operand.kind result = newIntNodeT(toInt128(operand.len), traitCall, c.idgen, c.graph) of "distinctBase": - var arg = operand.skipTypes({tyGenericInst}) + var arg = operand.skipTypes(skippedTypes) let rec = semConstExpr(c, traitCall[2]).intVal != 0 - while arg.kind == tyDistinct: - arg = arg.base.skipTypes(skippedTypes + {tyGenericInst}) + while true: + let distinctArg = arg.skipTypes(skippedTypes + {tyGenericInst}) + if distinctArg.kind != tyDistinct: + break + arg = distinctArg.base.skipTypes(skippedTypes) if not rec: break result = getTypeDescNode(c, arg, operand.owner, traitCall.info) of "rangeBase": diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index 0107f6b049..46601c1070 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -434,3 +434,32 @@ block: # bug #24378 type Win222[T] = typeof("foobar") doAssert not supportsCopyMem((int, Win222[int])) doAssert not supportsCopyMem(tuple[a: int, b: Win222[int]]) + +block: # bug #25789 + type + L[T; N: static int] = distinct seq[T] + EPF = distinct L[int, 100] + + var e: EPF = EPF(L[int, 100](@[1, 2, 3])) + + template classifyGeneric[T](x: T): bool = + when typeof(x) is L: + true + else: + false + + template classifyConcrete[T](x: T): bool = + when typeof(x) is L[int, 100]: + true + else: + false + + let viaConv = L[int, 100](e) + doAssert $type(viaConv) == "L[system.int, 100]" + doAssert classifyGeneric(viaConv) + doAssert classifyConcrete(viaConv) + + let viaDB = distinctBase(e, recursive = false) + doAssert $type(viaDB) == "L[system.int, 100]" + doAssert classifyGeneric(viaDB) + doAssert classifyConcrete(viaDB)