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.
This commit is contained in:
ringabout
2026-05-06 02:21:37 +08:00
committed by GitHub
parent cbe02aa9de
commit b73908a361
2 changed files with 35 additions and 3 deletions

View File

@@ -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":

View File

@@ -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)