From c0922ce1fed670f99cdffa79526ee2e4507b4a84 Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 25 Nov 2025 20:46:30 +0300 Subject: [PATCH 1/3] consider generic param type as typedesc in tuple type expressions fixes #25312 --- compiler/semexprs.nim | 4 ++-- tests/tuples/tgenericparamtypetuple.nim | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 tests/tuples/tgenericparamtypetuple.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 31b3770459d71..b74d1adc66efc 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -3064,10 +3064,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 = tupexp[0].typ.kind in {tyTypeDesc, tyGenericParam} # check if either everything or nothing is tyTypeDesc for i in 1.. Date: Tue, 25 Nov 2025 20:54:00 +0300 Subject: [PATCH 2/3] add more tests --- tests/tuples/tgenericparamtypetuple.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/tuples/tgenericparamtypetuple.nim b/tests/tuples/tgenericparamtypetuple.nim index 83705fd2dba55..93f1ff2d29a66 100644 --- a/tests/tuples/tgenericparamtypetuple.nim +++ b/tests/tuples/tgenericparamtypetuple.nim @@ -23,3 +23,12 @@ proc test5(test: HeapQueue[(float, ExampleObj)]) = # Works proc failingTest[T](test: HeapQueue[(float, T)]) = # (Compile) Error: Mixing types and values in tuples is not allowed. discard + +proc failingTest2[T](test: HeapQueue[(T, float)]) = # (Compile) Error: Mixing types and values in tuples is not allowed. + discard + +proc test6[T](test: HeapQueue[(T, T)]) = # works + discard + +proc test7[T, U](test: HeapQueue[(T, U)]) = # works + discard From e490b9aeabc696057bddd08f50c61f06c56d44b9 Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 25 Nov 2025 21:39:54 +0300 Subject: [PATCH 3/3] slightly better check but still not great --- compiler/semexprs.nim | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b74d1adc66efc..8384e514b0d34 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -3054,6 +3054,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: @@ -3064,10 +3071,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 in {tyTypeDesc, tyGenericParam} + isTupleType = isTypeTupleField(tupexp[0]) # check if either everything or nothing is tyTypeDesc for i in 1..