Skip to content

Commit

Permalink
don't instantiate generic body type symbols in generic expressions (n…
Browse files Browse the repository at this point in the history
…im-lang#24092)

fixes nim-lang#24090

Generic body types are normally a sign of an uninstantiated type, and so
give errors when trying to instantiate them. However when instantiating
free user expressions like the nodes of `tyFromExpr`, generic default
params, static values etc, they can be used as arguments to macros or
templates etc (as in the issue). So, we don't try to instantiate generic
body type symbols at all in free expressions such as these (but not in
for example type nodes), and avoid the error.

In the future there should be a "concrete type" check for generic body
types different from the check in type instantiation to deal with things
like nim-lang#24091, if we do want to allow this use of them.
  • Loading branch information
metagn authored Sep 10, 2024
1 parent 2177176 commit baec195
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
5 changes: 5 additions & 0 deletions compiler/semtypinst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
checkMetaInvariants(cl, result)

proc prepareNode*(cl: var TReplTypeVars, n: PNode): PNode =
## instantiates a given generic expression, not a type node
if n.kind == nkSym and n.sym.kind == skType and
n.sym.typ != nil and n.sym.typ.kind == tyGenericBody:
# generic body types are allowed as user expressions, see #24090
return n
let t = replaceTypeVarsT(cl, n.typ)
if t != nil and t.kind == tyStatic and t.n != nil:
return if tfUnresolved in t.flags: prepareNode(cl, t.n)
Expand Down
26 changes: 26 additions & 0 deletions tests/generics/tuninstantiatedgenericcalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -409,3 +409,29 @@ block: # weird regression
# but expected: <T, U>
x
doAssert foo(Foo[int](1), Bar[int, int](2)).int == 1

block: # issue #24090
type M[V] = object
template y[V](N: type M, v: V): M[V] = default(M[V])
proc d(x: int | int, f: M[int] = M.y(0)) = discard
d(0, M.y(0))
type Foo[T] = object
x: typeof(M.y(default(T)))
var a: Foo[int]
doAssert a.x is M[int]
var b: Foo[float]
doAssert b.x is M[float]
doAssert not (compiles do:
type Bar[T] = object
x: typeof(M()) # actually fails here immediately
var bar: Bar[int])
doAssert not (compiles do:
type Bar[T] = object
x: typeof(default(M))
var bar: Bar[int]
# gives "undeclared identifier x" because of #24091,
# normally it should fail in the line above
echo bar.x)
proc foo[T: M](x: T = default(T)) = discard x
foo[M[int]]()
doAssert not compiles(foo())

0 comments on commit baec195

Please sign in to comment.