diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 9293f8497b150..7e61c60708f8c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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 diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index bdf8fb8ca686b..2a5b6c75170c8 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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.. 0: + if isCurrentlyGeneric(): defTyp = nil def = semGenericStmt(c, def) if hasUnresolvedArgs(c, def): @@ -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 @@ -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 diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 428d897ecf081..9fdc1cbc2b2fe 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -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: @@ -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() @@ -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 diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index af9b29718f4d7..e440d27857f09 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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) @@ -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` @@ -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 diff --git a/tests/generics/t23854.nim b/tests/generics/t23854.nim index 675f9d121a6d7..f1175c8b2183f 100644 --- a/tests/generics/t23854.nim +++ b/tests/generics/t23854.nim @@ -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) diff --git a/tests/generics/t23855.nim b/tests/generics/t23855.nim index 5ae927a94eb3f..da8135a982054 100644 --- a/tests/generics/t23855.nim +++ b/tests/generics/t23855.nim @@ -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() diff --git a/tests/generics/tuninstantiatedgenericcalls.nim b/tests/generics/tuninstantiatedgenericcalls.nim index 172a00bd44163..d75d24fa10fb2 100644 --- a/tests/generics/tuninstantiatedgenericcalls.nim +++ b/tests/generics/tuninstantiatedgenericcalls.nim @@ -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() diff --git a/tests/misc/t8545.nim b/tests/misc/t8545.nim index 48b886cb89a47..0d22ab1c17f3b 100644 --- a/tests/misc/t8545.nim +++ b/tests/misc/t8545.nim @@ -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 @@ -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 diff --git a/tests/proc/tstaticsignature.nim b/tests/proc/tstaticsignature.nim new file mode 100644 index 0000000000000..ea1844745f4f8 --- /dev/null +++ b/tests/proc/tstaticsignature.nim @@ -0,0 +1,168 @@ +when false: # issue #22607, needs nkWhenStmt to be handled like nkRecWhen + proc test[x: static bool]( + t: ( + when x: + int + else: + float + ) + ) = discard + test[true](1.int) + test[false](1.0) + doAssert not compiles(test[]) + +block: # issue #4228 + template seqType(t: typedesc): typedesc = + when t is int: + seq[int] + else: + seq[string] + + proc mkSeq[T: int|string](v: T): seqType(T) = + result = newSeq[T](1) + result[0] = v + + doAssert mkSeq("a") == @["a"] + doAssert mkSeq(1) == @[1] + +block: # expanded version of t8545 + template bar(a: static[bool]): untyped = + when a: + int + else: + float + + proc main() = + proc foo1(a: static[bool]): auto = 1 + doAssert foo1(true) == 1 + + proc foo2(a: static[bool]): bar(a) = 1 + doAssert foo2(true) == 1 + doAssert foo2(true) is int + doAssert foo2(false) == 1.0 + doAssert foo2(false) is float + + proc foo3(a: static[bool]): bar(cast[bool](a)) = 1 + doAssert foo3(true) == 1 + doAssert foo3(true) is int + doAssert foo3(false) == 1.0 + doAssert foo3(false) is float + + proc foo4(a: static[bool]): bar(static(a)) = 1 + doAssert foo4(true) == 1 + doAssert foo4(true) is int + doAssert foo4(false) == 1.0 + doAssert foo4(false) is float + + static: main() + main() + +block: # issue #8406 + macro f(x: static[int]): untyped = discard + proc g[X: static[int]](v: f(X)) = discard + +import macros + +block: # issue #8551 + macro distinctBase2(T: typedesc): untyped = + let typeNode = getTypeImpl(T) + expectKind(typeNode, nnkBracketExpr) + if typeNode[0].typeKind != ntyTypeDesc: + error "expected typeDesc, got " & $typeNode[0] + var typeSym = typeNode[1] + + typeSym = getTypeImpl(typeSym) + + if typeSym.typeKind != ntyDistinct: + error "type is not distinct: " & $typeSym.typeKind + + typeSym = typeSym[0] + typeSym + + func distinctBase[T](a: T): distinctBase2(T) = distinctBase2(T)(a) + + type T = distinct int + doAssert distinctBase(T(0)) is int + +block: + type Foo[T] = object + x: T + + proc foo(x: Foo): Foo[x.T] = + doAssert typeof(result) is typeof(x) + + var a: Foo[int] + let b: Foo[int] = foo(a) + doAssert b.x is int + +block: + type Foo[T: static int] = object + x: array[T, int] + + proc double(x: int): int = x * 2 + + proc foo[T: static int](x: Foo[T]): Foo[T.double] = + doAssert typeof(result).T == double(typeof(x).T) + + var a: Foo[3] + let b: Foo[6] = foo(a) + doAssert $typeof(foo(a)) == "Foo[6]" + +block: + type Foo[T: static int] = object + x: array[T, int] + + proc foo(x: Foo): Foo[x.T] = + doAssert typeof(result).T == typeof(x).T + doAssert typeof(result) is typeof(x) + + var a: Foo[3] + let b: Foo[3] = foo(a) + doAssert $typeof(foo(a)) == "Foo[3]" + +block: # issue #7006 + type + Node[T] = object + val: T + next: ref Node[T] + HHSet[T, Key] = object + data: seq[Node[T]] + proc rawGet(hhs:HHSet; key: hhs.Key): ptr Node[hhs.T] = + return nil # body doesn't matter + var hhs: HHSet[string, cstring] + discard hhs.rawGet("hello".cstring) + +block: # issue #7008 + type Node[T] = object + val: T + # Compiles fine + proc concreteProc(s: Node[cstring]; key: s.T) = discard + # Also fine + proc implicitGenericProc1(s: Node; key: s.T) = discard + # still fine + proc explicitGenericProc1[T](s: Node[T]; key: T) = discard + # Internal Compiler Error! + proc explicitGenericProc2[T](s: Node[T]; key: s.T) = discard + let n = Node[int](val: 5) + implicitGenericProc1(n, 5) # works + explicitGenericProc1(n, 5) # works + explicitGenericProc2(n, 5) # doesn't + +block: # issue #20027 + block: + type Test[T] = object + proc run(self: Test): self.T = discard + discard run(Test[int]()) + block: + type Test[T] = object + proc run[T](self: Test[T]): self.T = discard + discard run(Test[int]()) + block: + type Test[T] = object + proc run(self: Test[auto]): self.T = discard + discard run(Test[int]()) + +block: # issue #11112 + proc foo[A, B]: type(A.default + B.default) = + discard + doAssert foo[int, int]() is int