Experimental support for delayed instantiation of generics

This postpones the semantic pass over the generic's body until
the generic is instantiated. There are several pros and cons for
this method and the capabilities that it enables may still be possible
in the old framework if we teach it a few new trick. Such an attempt
will follow in the next commits.

pros:
1) It allows macros to be expanded during generic instantiation that
will provide the body of the generic. See ``tmacrogenerics``.
2) The instantiation code is dramatically simplified. Dealing with unknown
types in the generic's body pre-pass requires a lot of hacky code and error
silencing in semTypeNode. See ``tgenericshardcases``.

cons:
1) There is a performance penalty of roughly 5% when bootstrapping.
2) Certain errors that used to be detected in the previous pre-pass won't
be detected with the new scheme until instantiation.
This commit is contained in:
Zahary Karadjov
2013-08-22 19:22:28 +03:00
parent a8c8a85135
commit fee2a7ecfa
12 changed files with 161 additions and 38 deletions

View File

@@ -0,0 +1,30 @@
discard """
file: "tgenericshardcases.nim"
output: "int\nfloat\nint\nstring"
"""
import typetraits
proc typeNameLen(x: typedesc): int {.compileTime.} =
result = x.name.len
macro selectType(a, b: typedesc): typedesc =
result = a
type
Foo[T] = object
data1: array[high(T), int]
data2: array[1..typeNameLen(T), selectType(float, string)]
MyEnum = enum A, B, C,D
var f1: Foo[MyEnum]
var f2: Foo[int8]
static:
assert high(f1.data1) == D
assert high(f1.data2) == 6 # length of MyEnum
assert high(f2.data1) == 127
assert high(f2.data2) == 4 # length of int8

View File

@@ -0,0 +1,39 @@
discard """
file: "tmacrogenerics.nim"
msg: '''
instantiation 1 with int and float
instantiation 2 with float and string
instantiation 3 with string and string
counter: 3
'''
output: "int\nfloat\nint\nstring"
"""
import typetraits, macros
var counter {.compileTime.} = 0
macro makeBar(A, B: typedesc): typedesc =
inc counter
echo "instantiation ", counter, " with ", A.name, " and ", B.name
result = A
type
Bar[T, U] = makeBar(T, U)
var bb1: Bar[int, float]
var bb2: Bar[float, string]
var bb3: Bar[int, float]
var bb4: Bar[string, string]
proc match(a: int) = echo "int"
proc match(a: string) = echo "string"
proc match(a: float) = echo "float"
match(bb1)
match(bb2)
match(bb3)
match(bb4)
static:
echo "counter: ", counter