diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index bac00bbee1300..46de230f23a5d 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -725,7 +725,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp # nkBracket nodes can also be produced by the VM as seq constant nodes # in which case, we cannot produce a new array type for the node, # as this might lose type info even when the node has array type - let constructType = n.typ.isNil + let constructType = n.typ.isNil or n.typ.kind == tyFromExpr var expectedElementType, expectedIndexType: PType = nil var expectedBase: PType = nil if constructType: @@ -797,17 +797,26 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp localError(c.config, x.info, "invalid order in array constructor") x = x[1] - let xx = semExprWithType(c, x, {efTypeAllowed}, expectedElementType) - result.add xx - if constructType: - typ = commonType(c, typ, xx.typ) + if typ.kind == tyFromExpr and c.inGenericContext > 0: + result.add semGenericStmt(c, x) + else: + let xx = semExprWithType(c, x, {efTypeAllowed}, expectedElementType) + result.add xx + if constructType: + typ = commonType(c, typ, xx.typ) #n[i] = semExprWithType(c, x, {}) #result.add fitNode(c, typ, n[i]) inc(lastIndex) - if constructType: - addSonSkipIntLit(result.typ, typ, c.idgen) - for i in 0.. 0: + if constructType: + result.typ() = nil # current result.typ is invalid, index type is nil + result.typ() = makeTypeFromExpr(c, result.copyTree) + return + else: + if constructType: + addSonSkipIntLit(result.typ, typ, c.idgen) + for i in 0.. 0: + n[i] = semGenericStmt(c, n[i]) + elif isRange(n[i]): checkSonsLen(n[i], 3, c.config) n[i][1] = semExprWithType(c, n[i][1], {efTypeAllowed}, expectedElementType) n[i][2] = semExprWithType(c, n[i][2], {efTypeAllowed}, expectedElementType) @@ -2811,7 +2822,10 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode = if doSetType: typ = skipTypes(n[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink}) if doSetType: - if not isOrdinalType(typ, allowEnumWithHoles=true): + if typ.kind == tyFromExpr and c.inGenericContext > 0: + # propagate it as set element type + discard + elif not isOrdinalType(typ, allowEnumWithHoles=true): localError(c.config, n.info, errOrdinalTypeExpected % typeToString(typ, preferDesc)) typ = makeRangeType(c, 0, MaxSetElements-1, n.info) elif isIntLit(typ): @@ -2825,11 +2839,16 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode = typ = makeRangeType(c, 0, MaxSetElements-1, n.info) if expectedElementType == nil: expectedElementType = typ - addSonSkipIntLit(result.typ, typ, c.idgen) + if typ.kind == tyFromExpr and c.inGenericContext > 0: + result.typ() = makeTypeFromExpr(c, result.copyTree) + else: + addSonSkipIntLit(result.typ, typ, c.idgen) for i in 0.. 0: + m = n[i] + elif isRange(n[i]): m = newNodeI(nkRange, info) m.add fitNode(c, typ, n[i][1], info) m.add fitNode(c, typ, n[i][2], info) @@ -2937,14 +2956,20 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedT var typ = newTypeS(tyTuple, c) # leave typ.n nil! for i in 0.. 0: + typ = makeTypeFromExpr(c, n.copyTree) + else: + if expectedElemType != nil and + (expectedElemType.kind != tyNil and not hasEmpty(expectedElemType)): + # hasEmpty/nil check is to not break existing code like + # `const foo = [(1, {}), (2, {false})]`, + # `const foo = if true: (0, nil) else: (1, new(int))` + n[i] = fitNode(c, expectedElemType, n[i], n[i].info) + addSonSkipIntLit(typ, n[i].typ.skipTypes({tySink}), c.idgen) result.typ() = typ include semobjconstr @@ -3035,6 +3060,10 @@ proc semExport(c: PContext, n: PNode): PNode = proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode = var tupexp = semTuplePositionsConstr(c, n, flags, expectedType) + # convert `tupexp` to typedesc if necessary: + if tupexp.typ.kind == tyFromExpr: + # tyFromExpr is already ambivalent between types and values + return tupexp var isTupleType: bool = false if tupexp.len > 0: # don't interpret () as type isTupleType = tupexp[0].typ.kind == tyTypeDesc diff --git a/tests/proc/tgenericdefaultparam.nim b/tests/proc/tgenericdefaultparam.nim index 7bce591ce5ee2..04f0774308f93 100644 --- a/tests/proc/tgenericdefaultparam.nim +++ b/tests/proc/tgenericdefaultparam.nim @@ -96,3 +96,35 @@ block: # issue #24121 proc baz[T: FooBar](x: T, y = foo(x)): string = y doAssert baz(Foo(123)) == "b" doAssert baz(Bar(123)) == "c" + +block: # issue #24484 + type E = enum A + proc foo[T](t: set[T] = {T.A}) = + discard + foo[E]() + + proc bar[T](t: set[T] = {T(0), 5}) = + doAssert t == {0, 5} + bar[uint8]() + doAssert not compiles(bar[string]()) + +block: # issue #24484, array version + type E = enum A + proc foo[T](t: openArray[T] = [T.A]) = + discard + foo[E]() + + proc bar[T](t: openArray[T] = [T(0), 5]) = + doAssert t == [T(0), 5] + bar[uint8]() + +block: # issue #24484, tuple version + type E = enum A + proc foo[T](t = (T.A,)) = + discard + foo[E]() + + proc bar[T](t: (T, int) = (T(0), 5)) = + doAssert t == (T(0), 5) + bar[uint8]() +