unwrap typedesc in semSet to enable stuff like set[T.distinctBase] (#25924)

`distinctBase` results in typedesc, so `set[T.distinctBase]` received
`typedesc[range[...]]` as its element type, which `isOrdinalType`
rejects. Strip the wrapper in `semSet` before storing the element type
and checking ordinality.

Also add `tyFromExpr` to the deferred-check set so the error doesn't
fire prematurely inside generic bodies - same pattern already used by
`semArray`.
This commit is contained in:
Ryan McConnell
2026-07-26 12:08:44 -04:00
committed by GitHub
parent 0021205854
commit 2d81149294
2 changed files with 41 additions and 1 deletions

View File

@@ -219,9 +219,10 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
result = newOrPrevType(tySet, prev, c)
if n.len == 2 and n[1].kind != nkEmpty:
var base = semTypeNode(c, n[1], nil)
if base.kind == tyTypeDesc: base = base.base # unwrap from type traits like distinctBase
addSonSkipIntLit(result, base, c.idgen)
if base.kind in {tyGenericInst, tyAlias, tySink}: base = skipModifier(base)
if base.kind notin {tyGenericParam, tyGenericInvocation}:
if base.kind notin {tyGenericParam, tyGenericInvocation, tyFromExpr}:
if base.kind == tyForward:
c.forwardTypeUpdates.add (getCurrOwner(c), result, n)
elif not isOrdinalType(base, allowEnumWithHoles = true):

View File

@@ -0,0 +1,39 @@
# Test that set[] accepts range types via typedesc[R], and set[typedesc[R]]
# must unwrap the typedesc wrapper before checking ordinality.
import std/typetraits
type
TestDistinctRange = distinct range[0 .. 63]
block: # explicit range type as set base
type S = set[range[0 .. 63]]
var s: S = {0, 1}
doAssert 0 in s
block: # distinctBase result as set base (non-generic)
type S = set[TestDistinctRange.distinctBase]
var s: S = {0, 1}
doAssert 0 in s
block: # range alias as set base
type RangeAlias = range[0 .. 63]
type S = set[RangeAlias]
var s: S = {0, 1}
doAssert 0 in s
block: # set[T.distinctBase] in generic body type position
proc test[T: TestDistinctRange]() =
var s: set[T.distinctBase]
s = {0, 1}
doAssert 0 in s
test[TestDistinctRange]()
block: # passing set[T.distinctBase] to a proc expecting set[0..63]
proc accept(x: typedesc[set[0 .. 63]]) = discard
proc pass[T: TestDistinctRange](p: typedesc[set[T]]) =
accept(set[T.distinctBase])
pass(set[TestDistinctRange])