From c8556ef5df29d0d3d0bb8839c7adcb237ab7bfb2 Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 9 Dec 2025 11:45:37 +0300 Subject: [PATCH] consider generic param type as typedesc in tuple type expressions (#25316) fixes #25312 Tuple expressions `(a, b, c)` can be either types or values depending on if their elements are typedescs or values, this is checked by checking if the type of the element is `tyTypeDesc`. However when an `skGenericParam` symbol is semchecked by `semSym` it is given its own `tyGenericParam` type rather than a `tyTypeDesc` type, this seems to be necessary for signatures to allow wildcard generic params passed to static constrained generic params (tested in #25315). The reason `semSym` is called is that `semGeneric` for generic invocations calls `matches` which sems its arguments like normal expressions. To deal with this, an expression of type `tyGenericParam` and with a `skGenericParam` sym is allowed as a type in the tuple expression. A problem is that this might consider a value with a wildcard generic param type as a type. But this is a very niche problem, and I'm not sure how to check for this. `skGenericParam` symbols stay as idents when semchecked so it can't be checked that the node is an `skGenericParam` symbol. It could be checked that it's an ident but I don't know how robust this is. And maybe there is another way to refer to a wildcard generic param type instead of just its symbol, i.e. another kind of node. This also makes #5647 finally work but a test case for that can be added after. (cherry picked from commit 44d2472b083b5f711b01505fc3199683ef8b3426) --- compiler/semexprs.nim | 11 ++++++-- tests/tuples/tgenericparamtypetuple.nim | 34 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 tests/tuples/tgenericparamtypetuple.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c1b49a19e9..78baa360ec 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -3053,6 +3053,13 @@ proc semExport(c: PContext, n: PNode): PNode = s = nextOverloadIter(o, c, a) +proc isTypeTupleField(n: PNode): bool {.inline.} = + result = n.typ.kind == tyTypeDesc or + (n.typ.kind == tyGenericParam and n.typ.sym.kind == skGenericParam) + # `skGenericParam` stays as `tyGenericParam` type rather than being wrapped in `tyTypeDesc` + # would check if `n` itself is an `skGenericParam` symbol, but these symbols semcheck to an ident + # maybe check if `n` is an ident to ensure this is not a value with the generic param type? + proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode = result = semTuplePositionsConstr(c, n, flags, expectedType) if result.typ.kind == tyFromExpr: @@ -3063,10 +3070,10 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp var isTupleType: bool = false if tupexp.len > 0: # don't interpret () as type internalAssert c.config, tupexp.kind == nkTupleConstr - isTupleType = tupexp[0].typ.kind == tyTypeDesc + isTupleType = isTypeTupleField(tupexp[0]) # check if either everything or nothing is tyTypeDesc for i in 1..