summary refs log tree commit diff stats
path: root/tests/generics/tuninstantiatedgenericcalls.nim
blob: f33fc8967c9bc15bd661765776d422fc4ba4b70f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
# Cases that used to only work due to weird workarounds in the compiler
# involving not instantiating calls in generic bodies which are removed
# due to breaking statics.
# The issue was that these calls are compiled as regular expressions at
# the generic declaration with unresolved generic parameter types,
# which are special cased in some places in the compiler, but sometimes
# treated like real types.

block:
  type Base10 = object

  func maxLen(T: typedesc[Base10], I: type): int8 =
    when I is uint8:
      3
    elif I is uint16:
      5
    elif I is uint32:
      10
    elif I is uint64:
      20
    else:
      when sizeof(uint) == 4:
        10
      else:
        20
  
  type
    Base10Buf[T: SomeUnsignedInt] = object
      data: array[maxLen(Base10, T), byte]
      len: int8

  var x: Base10Buf[uint32]
  doAssert x.data.len == 10
  var y: Base10Buf[uint16]
  doAssert y.data.len == 5

import typetraits

block thardcases:
  proc typeNameLen(x: typedesc): int {.compileTime.} =
    result = x.name.len
  macro selectType(a, b: typedesc): typedesc =
    result = a

  type
    Foo[T] = object
      data1: array[T.high, int]
      data2: array[typeNameLen(T), float]
      data3: array[0..T.typeNameLen, selectType(float, int)]
  
  type MyEnum = enum A, B, C, D

  var f1: Foo[MyEnum]
  var f2: Foo[int8]

  doAssert high(f1.data1) == 2 # (D = 3) - 1 == 2
  doAssert high(f1.data2) == 5 # (MyEnum.len = 6) - 1 == 5

  doAssert high(f2.data1) == 126 # 127 - 1 == 126
  doAssert high(f2.data2) == 3 # int8.len - 1 == 3

  static:
    doAssert high(f1.data1) == ord(C)
    doAssert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high

    doAssert high(f2.data1) == 126
    doAssert high(f2.data2) == 3

    doAssert high(f1.data3) == 6 # length of MyEnum
    doAssert high(f2.data3) == 4 # length of int8

    doAssert f2.data3[0] is float

import muninstantiatedgenericcalls

block:
  var x: Leb128Buf[uint32]
  doAssert x.data.len == 5
  var y: Leb128Buf[uint16]
  doAssert y.data.len == 3

import macros

block: # issue #12415
  macro isSomePointerImpl(t: typedesc): bool =
    var impl = t.getTypeInst[1].getTypeImpl
    if impl.kind == nnkDistinctTy:
      impl = impl[0].getTypeImpl
    if impl.kind in {nnkPtrTy,nnkRefTy}:
      result = newLit(true)
    elif impl.kind == nnkSym and impl.eqIdent("pointer"):
      result = newLit(true)
    else:
      result = newLit(false)

  proc isSomePointer[T](t: typedesc[T]): bool {.compileTime.} =
    isSomePointerImpl(t)

  type
    Option[T] = object
      ## An optional type that stores its value and state separately in a boolean.
      when isSomePointer(typedesc(T)):
        val: T
      else:
        val: T
        has: bool
  var x: Option[ref int]
  doAssert not compiles(x.has)
  var y: Option[int]
  doAssert compiles(y.has)

block: # issue #2002
  proc isNillable(T: typedesc): bool =
    when compiles((let v: T = nil)):
      return true
    else:
      return false

  type
    Foo[T] = object
      when isNillable(T):
        nillable: float
      else:
        notnillable: int

  var val1: Foo[ref int]
  doAssert compiles(val1.nillable)
  doAssert not compiles(val1.notnillable)
  var val2: Foo[int]
  doAssert not compiles(val2.nillable)
  doAssert compiles(val2.notnillable)

block: # issue #1771
  type
    Foo[X, T] = object
      bar: array[X.low..X.high, T]

  proc test[X, T](f: Foo[X, T]): T =
    f.bar[X.low]

  var a: Foo[range[0..2], float]
  doAssert test(a) == 0.0

block: # issue #23730
  proc test(M: static[int]): array[1 shl M, int] = discard
  doAssert len(test(3)) == 8
  doAssert len(test(5)) == 32

block: # issue #19819
  type
    Example[N: static int] = distinct int
    What[E: Example] = Example[E.N + E.N]

block: # issue #23339
  type
    A = object
    B = object
  template aToB(t: typedesc[A]): typedesc = B
  type
    Inner[I] = object
      innerField: I
    Outer[O] = object
      outerField: Inner[O.aToB]
  var x: Outer[A]
  doAssert typeof(x.outerField.innerField) is B

block: # deref syntax
  type
    Enqueueable = concept x
      x is ptr
    Foo[T: Enqueueable] = object
      x: typeof(default(T)[])

  proc p[T](f: Foo[T]) =
    var bar: Foo[T]
    discard
  var foo: Foo[ptr int]
  p(foo)
  doAssert foo.x is int
  foo.x = 123
  doAssert foo.x == 123
  inc foo.x
  doAssert foo.x == 124

block:
  type Generic[T] = object
    field: T
  macro foo(x: typed): untyped = x
  macro bar[T](x: typedesc[Generic[T]]): untyped = x
  type
    Foo[T] = object
      field: Generic[int].foo()
    Foo2[T] = object
      field: Generic[T].foo()
    Bar[T] = object
      field: Generic[int].bar()
    Bar2[T] = object
      field: Generic[T].bar()
  var x: Foo[int]
  var x2: Foo2[int]
  var y: Bar[int]
  var y2: Bar2[int]

block:
  macro pick(x: static int): untyped =
    if x < 100:
      result = bindSym"int"
    else:
      result = bindSym"float"
  
  type Foo[T: static int] = object
    fixed1: pick(25)
    fixed2: pick(125)
    unknown: pick(T)
  
  var a: Foo[123]
  doAssert a.fixed1 is int
  doAssert a.fixed2 is float
  doAssert a.unknown is float
  var b: Foo[23]
  doAssert b.fixed1 is int
  doAssert b.fixed2 is float
  doAssert b.unknown is int

import std/sequtils

block: # version of #23432 with `typed`, don't delay instantiation
  type
    Future[T] = object
    InternalRaisesFuture[T, E] = object
  macro Raising[T](F: typedesc[Future[T]], E: varargs[typed]): untyped =
    let raises = nnkTupleConstr.newTree(E.mapIt(it))
    nnkBracketExpr.newTree(
      ident "InternalRaisesFuture",
      nnkDotExpr.newTree(F, ident"T"),
      raises
    )
  type X[E] = Future[void].Raising(E)
  proc f(x: X) = discard
  var v: Future[void].Raising([ValueError])
  f(v)

block: # issue #22647
  proc c0(n: static int): int = 8
  proc c1(n: static int): int = n div 2
  proc c2(n: static int): int = n * 2
  proc c3(n: static int, n2: int): int = n * n2
  proc `**`(n: static int, n2: int): int = n * n2
  proc c4(n: int, n2: int): int = n * n2

  type
    a[N: static int] = object
      f0 : array[N, int]

    b[N: static int] = object
      f0 : a[c0(N)]  # does not work
      f1 : a[c1(N)]  # does not work
      f2 : a[c2(N)]  # does not work
      f3 : a[N * 2]  # does not work
      f4 : a[N]      # works
      f5: a[c3(N, 2)]
      f6: a[N ** 2]
      f7: a[2 * N]
      f8: a[c4(N, 2)]

  proc p[N: static int](x : a[N]) = discard x.f0[0]
  template check(x, s: untyped) =
    p(x)
    doAssert x is a[s]
    doAssert x.N == s
    doAssert typeof(x).N == s
    doAssert x.f0 == default(array[s, int])
    doAssert x.f0.len == s
    proc p2[N: static int](y : a[N]) {.gensym.} =
      doAssert y is a[s]
      doAssert y.N == s
      doAssert typeof(y).N == s
      doAssert y.f0 == default(array[s, int])
      doAssert y.f0.len == s
    p2(x)
    proc p3(z: typeof(x)) {.gensym.} = discard
    p3(default(a[s]))
  proc p[N: static int](x : b[N]) =
    x.f0.check(8)
    x.f1.check(2)
    x.f2.check(8)
    x.f3.check(8)
    x.f4.check(4)
    x.f5.check(8)
    x.f6.check(8)
    x.f7.check(8)
    x.f8.check(8)

  var x: b[4]
  x.p()

block: # issue #1969
  type ZeroGenerator = object
  proc next(g: ZeroGenerator): int = 0
  # This compiles.
  type TripleOfInts = tuple
    a, b, c: typeof(new(ZeroGenerator)[].next)
  # This raises a compiler error before it's even instantiated.
  # The `new` proc can't be resolved because `Generator` is not defined.
  type TripleLike[Generator] = tuple
    a, b, c: typeof(new(Generator)[].next)

import std/atomics

block: # issue #12720
  const CacheLineSize = 128
  type
    Enqueueable = concept x, type T
      x is ptr
      x.next is Atomic[pointer]
    MyChannel[T: Enqueueable] = object
      pad: array[CacheLineSize - sizeof(default(T)[]), byte]
      dummy: typeof(default(T)[])

block: # issue #12714
  type
    Enqueueable = concept x, type T
      x is ptr
      x.next is Atomic[pointer]
    MyChannel[T: Enqueueable] = object
      dummy: type(default(T)[])

block: # issue #24044
  type ArrayBuf[N: static int, T = byte] = object
    buf: array[N, T]
  template maxLen(T: type): int =
    sizeof(T) * 2
  type MyBuf[I] = ArrayBuf[maxLen(I)]
  var v: MyBuf[int]

block: # issue #15959
  proc my[T](a: T): typeof(a[0]) = discard
  proc my2[T](a: T): array[sizeof(a[0]), T] = discard
  proc byLent2[T](a: T): lent type(a[0]) = a[0] # Error: type mismatch: got <T, int literal(0)>
  proc byLent3[T](a: T): lent typeof(a[0]) = a[0] # ditto
  proc byLent4[T](a: T): lent[type(a[0])] = a[0] # Error: no generic parameters allowed for lent
  var x = @[1, 2, 3]
  doAssert my(x) is int
  doAssert my2(x) is array[sizeof(int), seq[int]]
  doAssert byLent2(x) == 1
  doAssert byLent2(x) is lent int
  doAssert byLent3(x) == 1
  doAssert byLent3(x) is lent int
  doAssert byLent4(x) == 1
  doAssert byLent4(x) is lent int
  proc fn[U](a: U): auto = a
  proc my3[T](a: T, b: typeof(fn(a))) = discard
  my3(x, x)
  doAssert not compiles(my3(x, x[0]))

block: # issue #22342, type section version of #22607
  type GenAlias[isInt: static bool] = (
    when isInt:
      int
    else:
      float
  )
  doAssert GenAlias[true] is int
  doAssert GenAlias[false] is float
  proc foo(T: static bool): GenAlias[T] = discard
  doAssert foo(true) is int
  doAssert foo(false) is float
  proc foo[T: static bool](v: var GenAlias[T]) =
    v += 1
  var x: int
  foo[true](x)
  doAssert not compiles(foo[false](x))
  foo[true](x)
  doAssert x == 2
  var y: float
  foo[false](y)
  doAssert not compiles(foo[true](y))
  foo[false](y)
  doAssert y == 2

block: # `when`, test no constant semchecks
  type Foo[T] = (
    when false:
      {.error: "bad".}
    elif defined(neverDefined):
      {.error: "bad 2".}
    else:
      T
  )
  var x: Foo[int]
  type Bar[T] = (
    when true:
      T
    elif defined(js):
      {.error: "bad".}
    else:
      {.error: "bad 2".}
  )
  var y: Bar[int]

block: # weird regression
  type
    Foo[T] = distinct int
    Bar[T, U] = distinct int
  proc foo[T, U](x: static Foo[T], y: static Bar[T, U]): Foo[T] =
    # signature gives:
    # Error: cannot instantiate Bar
    # got: <typedesc[T], U>
    # 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())

block: # above but encountered by sigmatch using replaceTypeVarsN
  type Opt[T] = object
    x: T
  proc none[T](x: type Opt, y: typedesc[T]): Opt[T] = discard
  proc foo[T](x: T, a = Opt.none(int)) = discard
  foo(1, a = Opt.none(int))
  foo(1)

block: # real version of above
  type Opt[T] = object
    x: T
  template none(x: type Opt, T: type): Opt[T] = Opt[T]()
  proc foo[T](x: T, a = Opt.none(int)) = discard
  foo(1, a = Opt.none(int))
  foo(1)

block: # issue #20880
  type
    Child[n: static int] = object
      data: array[n, int]
    Parent[n: static int] = object
      child: Child[3*n]
  const n = 3
  doAssert $(typeof Parent[n*3]()) == "Parent[9]"
  doAssert $(typeof Parent[1]().child) == "Child[3]"
  doAssert Parent[1]().child.data.len == 3

{.experimental: "dynamicBindSym".}
block: # issue #16774
  type SecretWord = distinct uint64
  const WordBitWidth = 8 * sizeof(uint64)
  func wordsRequired(bits: int): int {.compileTime.} =
    ## Compute the number of limbs required
    # from the **announced** bit length
    (bits + WordBitWidth - 1) div WordBitWidth
  type
    Curve = enum BLS12_381
    BigInt[bits: static int] = object
      limbs: array[bits.wordsRequired, SecretWord]
  const BLS12_381_Modulus = default(BigInt[381])
  macro Mod(C: static Curve): untyped =
    ## Get the Modulus associated to a curve
    result = bindSym($C & "_Modulus")
  macro getCurveBitwidth(C: static Curve): untyped =
    result = nnkDotExpr.newTree(
      getAST(Mod(C)),
      ident"bits"
    )
  type Fp[C: static Curve] = object
    ## Finite Fields / Modular arithmetic
    ## modulo the curve modulus
    mres: BigInt[getCurveBitwidth(C)]
  var x: Fp[BLS12_381]
  doAssert x.mres.limbs.len == wordsRequired(getCurveBitWidth(BLS12_381))
  # minimized, as if we haven't tested it already:
  macro makeIntLit(c: static int): untyped =
    result = newLit(c)
  type Test[T: static int] = object
    myArray: array[makeIntLit(T), int]
  var y: Test[2]
  doAssert y.myArray.len == 2
  var z: Test[4]
  doAssert z.myArray.len == 4

block: # issue #16175
  type
    Thing[D: static uint] = object
      when D == 0:
        kid: char
      else:
        kid: Thing[D-1]
  var t2 = Thing[3]()
  doAssert t2.kid is Thing[2.uint]
  doAssert t2.kid.kid is Thing[1.uint]
  doAssert t2.kid.kid.kid is Thing[0.uint]
  doAssert t2.kid.kid.kid.kid is char
  var s = Thing[1]()
  doAssert s.kid is Thing[0.uint]
  doAssert s.kid.kid is char