summary refs log tree commit diff stats
diff options
context:
space:
mode:
authormetagn <metagngn@gmail.com>2024-07-19 05:53:35 -0600
committerGitHub <noreply@github.com>2024-07-19 13:53:35 +0200
commit97f54745459b8651b7a38c174b3a8135224ebd09 (patch)
tree1eea8c52c77718571dd017eef8f69ebcada032de
parent24f5dfbed22322f63d1fc27a07d41f746212a7d3 (diff)
downloadNim-97f54745459b8651b7a38c174b3a8135224ebd09.tar.gz
fix generics treating symchoice symbols as uninstantiated (#23860)
fixes #23853

Since #22610 generics turns the `Name` in the `GT.Name` expression in
the test code into a sym choice. The problem is when the compiler tries
to instantiate `GT.Name` it also instantiates the sym choice symbols.
`Name` has type `template (E: type ExtensionField)` which contains the
unresolved generic type `ExtensionField`, which the compiler mistakes as
an uninstantiated node, when it's just part of the type of the template.
The compilation of the node itself and hence overloading will handle the
instantiation of the proc, so we avoid instantiating it in `semtypinst`,
similar to how the first nodes of call nodes aren't instantiated.
-rw-r--r--compiler/semtypinst.nim6
-rw-r--r--tests/generics/t23853.nim91
2 files changed, 96 insertions, 1 deletions
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index f0ce8d76f..e87a4939a 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -132,9 +132,13 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
       else:
         replaceTypeVarsS(cl, n.sym, replaceTypeVarsT(cl, n.sym.typ))
   let isCall = result.kind in nkCallKinds
+  # don't try to instantiate symchoice symbols, they can be
+  # generic procs which the compiler will think are uninstantiated
+  # because their type will contain uninstantiated params
+  let isSymChoice = result.kind in nkSymChoices
   for i in 0..<n.safeLen:
     # XXX HACK: ``f(a, b)``, avoid to instantiate `f`
-    if isCall and i == 0: result.add(n[i])
+    if isSymChoice or (isCall and i == 0): result.add(n[i])
     else: result.add(prepareNode(cl, n[i]))
 
 proc isTypeParam(n: PNode): bool =
diff --git a/tests/generics/t23853.nim b/tests/generics/t23853.nim
new file mode 100644
index 000000000..bc9514a53
--- /dev/null
+++ b/tests/generics/t23853.nim
@@ -0,0 +1,91 @@
+# issue #23853
+
+block simplified:
+  type QuadraticExt[F] = object
+    coords: array[2, F]
+  template Name(E: type QuadraticExt): int = 123
+  template getBigInt(Name: static int): untyped = int
+  type Foo[GT] = object
+    a: getBigInt(GT.Name)
+  var x: Foo[QuadraticExt[int]]
+  
+import std/macros
+
+type
+  Algebra* = enum
+    BN254_Snarks
+    BLS12_381
+
+  Fp*[Name: static Algebra] = object
+    limbs*: array[4, uint64]
+
+  QuadraticExt*[F] = object
+    ## Quadratic Extension field
+    coords*: array[2, F]
+
+  CubicExt*[F] = object
+    ## Cubic Extension field
+    coords*: array[3, F]
+
+  ExtensionField*[F] = QuadraticExt[F] or CubicExt[F]
+
+  Fp2*[Name: static Algebra] =
+    QuadraticExt[Fp[Name]]
+
+  Fp4*[Name: static Algebra] =
+    QuadraticExt[Fp2[Name]]
+
+  Fp6*[Name: static Algebra] =
+    CubicExt[Fp2[Name]]
+
+  Fp12*[Name: static Algebra] =
+    CubicExt[Fp4[Name]]
+    # QuadraticExt[Fp6[Name]]
+
+template Name*(E: type ExtensionField): Algebra =
+  E.F.Name
+
+const BLS12_381_Order = [uint64 0x1, 0x2, 0x3, 0x4]
+const BLS12_381_Modulus = [uint64 0x5, 0x6, 0x7, 0x8]
+
+
+{.experimental: "dynamicBindSym".}
+
+macro baseFieldModulus*(Name: static Algebra): untyped =
+  result = bindSym($Name & "_Modulus")
+
+macro scalarFieldModulus*(Name: static Algebra): untyped =
+  result = bindSym($Name & "_Order")
+
+type FieldKind* = enum
+  kBaseField
+  kScalarField
+
+template getBigInt*(Name: static Algebra, kind: static FieldKind): untyped =
+  # Workaround:
+  # in `ptr UncheckedArray[BigInt[EC.getScalarField().bits()]]
+  # EC.getScalarField is not accepted by the compiler
+  #
+  # and `ptr UncheckedArray[BigInt[Fr[EC.F.Name].bits]]` gets undeclared field: 'Name'
+  #
+  # but `ptr UncheckedArray[getBigInt(EC.getName(), kScalarField)]` works fine
+  when kind == kBaseField:
+    Name.baseFieldModulus().typeof()
+  else:
+    Name.scalarFieldModulus().typeof()
+
+# ------------------------------------------------------------------------------
+
+type BenchMultiexpContext*[GT] = object
+  elems: seq[GT]
+  exponents: seq[getBigInt(GT.Name, kScalarField)]
+
+proc createBenchMultiExpContext*(GT: typedesc, inputSizes: openArray[int]): BenchMultiexpContext[GT] =
+  discard
+
+# ------------------------------------------------------------------------------
+
+proc main() =
+  let ctx = createBenchMultiExpContext(Fp12[BLS12_381], [2, 4, 8, 16])
+
+main()