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.

(cherry picked from commit 97f5474545)
This commit is contained in:
metagn
2024-07-19 05:53:35 -06:00
committed by narimiran
parent f09b612f64
commit baa8af92af
2 changed files with 96 additions and 1 deletions

View File

@@ -136,9 +136,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 =

91
tests/generics/t23853.nim Normal file
View File

@@ -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()