-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Closed
Description
template generics don't bind generic params on instantiation; causing wrong runtime values or crashes
Example
when true:
template getTypStr[T](a: T): string = $T
echo(getTypStr(1)) # 170141183460469231731687303715884105727; should be: int
# echo(getTypStr(true)) # true ; should be: bool
# echo(getTypStr(1.0)) # Error: unhandled exception: cannot extract number from invalid AST node
# echo(getTypStr(1u8)) # Error: internal error: expr(skType); unknown symbolCurrent Output
170141183460469231731687303715884105727
Expected Output
int
other example: default
template isDefault[T](a: T): bool = a == default(T) # BUG
doAssert isDefault(0.0)gives: Error: type mismatch: got <int> but expected one of: proc default(T: typedesc): T:type
workarounds are not good
use type(a) instead of T works in example above but won't work in more general cases eg:
type Foo[M, P] = object
template getTypStr[T1, T2](a: Foo[T1, T2]): untyped =
# $T1 # doesn't work because of this issue
$type(a).M # bad: you have to "know" that `T1` corresponds to `M`
let a = Foo[int8, bool]()
let b=getTypStr(a)
echo (b, $type(b))but then (despite being bad), that doesn't even work with special cases like seq[T], giving Error: undeclared field: 'T'
template getTypStr[X](a: seq[X]): untyped =
$type(a).T # doesnt' work for seq[T] even though it's declared like seq[T] !
var a: seq[int]
let b=getTypStr(a)
echo (b, $type(b))
So you're forced to use the newly introduced typetraits.genericParams (see #13433), which seems overkill for these specific cases.
note
interestingly, static[T] generic params do seem to bind correctly, unlike non-static generic params eg:
type Foo[N: static float, T: Ordinal] = object
template getTypStr[N, T](a: Foo[N, T]): auto = N
let a = Foo[3.1, bool]()
doAssert getTypStr(a) == 3.1root cause for:
Additional Information
- 1056f9e devel
- related but different from:
pmetras, n0bra1n3r and shirleyquirk