Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

treat generic proc param/return type like generic type body #23194

Closed
wants to merge 9 commits into from
20 changes: 14 additions & 6 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1482,20 +1482,28 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =

proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
case t.kind
of tyTypeParamsHolders:
of tyGenericInst:
result = readTypeParameter(c, t, i, n.info)
if result == c.graph.emptyNode:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
if c.inGenericContext > 0:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
else:
result = nil
of tyUserTypeClasses:
if t.isResolvedUserTypeClass:
result = readTypeParameter(c, t, i, n.info)
elif c.inGenericContext > 0:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, copyTree(result))
else:
result = nil
elif t.containsGenericType:
if c.inGenericContext > 0:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, copyTree(result))
of tyFromExpr, tyGenericParam, tyAnything:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, copyTree(result))
else:
result = nil
else:
result = nil

Expand Down
21 changes: 14 additions & 7 deletions compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1312,6 +1312,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
result = newProcType(c, n.info, prev)
var check = initIntSet()
var counter = 0
template isCurrentlyGeneric: bool =
# genericParams might update as implicit generic params are added
genericParams != nil and genericParams.len > 0

for i in 1..<n.len:
var a = n[i]
Expand All @@ -1332,7 +1335,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
hasDefault = a[^1].kind != nkEmpty

if hasType:
let isGeneric = isCurrentlyGeneric()
inc c.inGenericContext, ord(isGeneric)
typ = semParamType(c, a[^2], constraint)
dec c.inGenericContext, ord(isGeneric)
# TODO: Disallow typed/untyped in procs in the compiler/stdlib
if kind in {skProc, skFunc} and (typ.kind == tyTyped or typ.kind == tyUntyped):
if not isMagic(getCurrOwner(c)):
Expand All @@ -1353,7 +1359,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
message(c.config, a.info, warnImplicitDefaultValue, msg)
block determineType:
var defTyp = typ
if genericParams != nil and genericParams.len > 0:
if isCurrentlyGeneric():
defTyp = nil
def = semGenericStmt(c, def)
if hasUnresolvedArgs(c, def):
Expand Down Expand Up @@ -1432,11 +1438,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
onDef(a[j].info, arg)
a[j] = newSymNode(arg)

var r: PType =
if n[0].kind != nkEmpty:
semTypeNode(c, n[0], nil)
else:
nil
var r: PType = nil
if n[0].kind != nkEmpty:
let isGeneric = isCurrentlyGeneric()
inc c.inGenericContext, ord(isGeneric)
r = semTypeNode(c, n[0], nil)
dec c.inGenericContext, ord(isGeneric)

if r != nil and kind in {skMacro, skTemplate} and r.kind == tyTyped:
# XXX: To implement the proposed change in the warning, just
Expand Down Expand Up @@ -1489,7 +1496,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
result.flags.excl tfHasMeta
result.n.typ = r

if genericParams != nil and genericParams.len > 0:
if isCurrentlyGeneric():
for n in genericParams:
if {sfUsed, sfAnon} * n.sym.flags == {}:
result.flags.incl tfUnresolved
Expand Down
11 changes: 10 additions & 1 deletion compiler/semtypinst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
elif t.elementType.kind != tyNone:
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.elementType))

of tyUserTypeClass, tyStatic:
of tyUserTypeClass:#, tyStatic:
result = t

of tyGenericInst, tyUserTypeClassInst:
Expand All @@ -690,6 +690,9 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
propagateToOwner(result, result.last)

else:
if cl.c.matchedConcept != nil and t.kind == tyStatic:
# allow concepts to not instantiate statics for now
return
if containsGenericType(t):
#if not cl.allowMetaTypes:
bailout()
Expand Down Expand Up @@ -734,6 +737,12 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
of tyRange:
result.setIndexType result.indexType.skipTypes({tyStatic, tyDistinct})

of tyStatic:
if not cl.allowMetaTypes and result.n != nil and
result.base.kind != tyNone:
if result.n.kind notin nkLiterals:
result.n = cl.c.semConstExpr(cl.c, result.n)

else: discard
else:
# If this type doesn't refer to a generic type we may still want to run it
Expand Down
15 changes: 12 additions & 3 deletions compiler/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,8 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =

else: discard

elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil:
elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and
(lhs.typ.n == nil or idTableGet(c.bindings, lhs.typ) == nil):
var inferred = newTypeS(tyStatic, c.c, lhs.typ.elementType)
inferred.n = newIntNode(nkIntLit, rhs)
put(c, lhs.typ, inferred)
Expand Down Expand Up @@ -1877,7 +1878,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
elif f.base.kind notin {tyNone, tyGenericParam}:
result = typeRel(c, f.base, a, flags)
if result != isNone and f.n != nil:
if not exprStructuralEquivalent(f.n, aOrig.n):
var r = tryResolvingStaticExpr(c, f.n)
if r == nil: r = f.n
if not exprStructuralEquivalent(r, aOrig.n) and
not (aOrig.n.kind == nkIntLit and
inferStaticParam(c, r, aOrig.n.intVal)):
result = isNone
elif f.base.kind == tyGenericParam:
# Handling things like `type A[T; Y: static T] = object`
Expand Down Expand Up @@ -2188,7 +2193,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
a = typ
else:
if m.callee.kind == tyGenericBody:
if f.kind == tyStatic and typeRel(m, f.base, a) != isNone:
# we can't use `makeStaticExpr` if `arg` has a generic type
# because it generates `tyStatic`, which semtypinst doesn't touch
# not sure if checking for `tyFromExpr` is enough
if f.kind == tyStatic and typeRel(m, f.base, a) != isNone and
a.kind != tyFromExpr:
result = makeStaticExpr(m.c, arg)
result.typ.flags.incl tfUnresolved
result.typ.n = arg
Expand Down
3 changes: 2 additions & 1 deletion tests/generics/t23854.nim
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ template getBits[bits: static int](x: ptr UncheckedArray[BigInt[bits]]): int = b

proc main() =
let ctx = ECFFT_Descriptor[EC_ShortW_Aff[Fp[BLS12_381]]].new()
when false: echo getBits(ctx.rootsOfUnity2) # doesn't work yet?
doAssert getBits(ctx.rootsOfUnity1) == 255
doAssert getBits(ctx.rootsOfUnity2) == 255
doAssert ctx.rootsOfUnity1[0].limbs.len == wordsRequired(255)
doAssert ctx.rootsOfUnity2[0].limbs.len == wordsRequired(255)

Expand Down
2 changes: 1 addition & 1 deletion tests/generics/t23855.nim
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ template getBits[bits: static int](x: ptr UncheckedArray[BigInt[bits]]): int = b

proc main() =
let ctx = ECFFT_Descriptor[EC_ShortW_Aff[Fp[BLS12_381]]].new()
when false: echo getBits(ctx.rootsOfUnity) # doesn't work yet?
doAssert getBits(ctx.rootsOfUnity) == 255
doAssert ctx.rootsOfUnity[0].limbs.len == wordsRequired(255)

main()
54 changes: 54 additions & 0 deletions tests/generics/tuninstantiatedgenericcalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,57 @@ block: # version of #23432 with `typed`, don't delay instantiation
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()
7 changes: 1 addition & 6 deletions tests/misc/t8545.nim
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
discard """
# just tests that this doesn't crash the compiler
errormsg: "cannot instantiate: 'a:type'"
"""

# bug #8545

template bar(a: static[bool]): untyped = int
Expand All @@ -14,7 +9,7 @@ proc main() =
proc foo2(a: static[bool]): bar(a) = 1
doAssert foo2(true) == 1

proc foo3(a: static[bool]): bar(cast[static[bool]](a)) = 1
proc foo3(a: static[bool]): bar(cast[bool](a)) = 1
doAssert foo3(true) == 1

proc foo4(a: static[bool]): bar(static(a)) = 1
Expand Down
Loading
Loading