mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
sem generic proc param types like generic types + static instantiation fixes (#24005)
fixes #4228, fixes #4990, fixes #7006, fixes #7008, fixes #8406, fixes #8551, fixes #11112, fixes #20027, fixes #22647, refs #23854 and #23855 (remaining issue fixed), refs #8545 (works properly now with `cast[static[bool]]` changed to `cast[bool]`), refs #22342 and #22607 (disabled tests added), succeeds #23194 Parameter and return type nodes in generic procs now undergo the same `inGenericContext` treatment that nodes in generic type bodies do. This allows many of the fixes in #22029 and followups to also apply to generic proc signatures. Like #23983 however this needs some more compiler fixes, but this time mostly in `sigmatch` and type instantiations. 1. `tryReadingGenericParam` no longer treats `tyCompositeTypeClass` like a concrete type anymore, so expressions like `Foo.T` where `Foo` is a generic type don't look for a parameter of `Foo` in non-generic code anymore. It also doesn't generate `tyFromExpr` in non-generic code for any generic LHS. This is to handle a very specific case in `asyncmacro` which used `FutureVar.astToStr` where `FutureVar` is generic. 2. The `tryResolvingStaticExpr` call when matching `tyFromExpr` in sigmatch now doesn't consider call nodes in general unresolved, only nodes with `tyFromExpr` type, which is emitted on unresolved expressions by increasing `c.inGenericContext`. `c.inGenericContext == 0` is also now required to attempt instantiating `tyFromExpr`. So matching against `tyFromExpr` in proc signatures works in general now, but I'm speculating it depends on constant folding in `semExpr` for statics to match against it properly. 3. `paramTypesMatch` now doesn't try to change nodes with `tyFromExpr` type into `tyStatic` type when fitting to a static type, because it doesn't need to, they'll be handled the same way (this was a workaround in place of the static type instantiation changes, only one of the fields in the #22647 test doesn't work with it). 4. `tyStatic` matching now uses `inferStaticParam` instead of just range type matching, so `Foo[N div 2]` can infer `N` in the same way `array[N div 2, int]` can. `inferStaticParam` also disabled itself if the inferred static param type already had a node, but `makeStaticExpr` generates static types with unresolved nodes, so we only disable it if it also doesn't have a binding. This might not work very well but the static type instantiation changes should really lower the amount of cases where it's encountered. 5. Static types now undergo type instantiation. Previously the branch for `tyStatic` in `semtypinst` was a no-op, now it acts similarly to instantiating any other type with the following differences: - Other types only need instantiation if `containsGenericType` is true, static types also get instantiated if their value node isn't a literal node. Ideally any value node that is "already evaluated" should be ignored, but I'm not sure of a better way to check this, maybe if `evalConstExpr` emitted a flag. This is purely for optimization though. - After instantiation, `semConstExpr` is called on the value node if `not cl.allowMetaTypes` and the type isn't literally a `static` type. Then the type of the node is set to the base type of the static type to deal with `semConstExpr` stripping abstract types. We need to do this because calls like `foo(N)` where `N` is `static int` and `foo`'s first parameter is just `int` do not generate `tyFromExpr`, they are fully typed and so `makeStaticExpr` is called on them, giving a static type with an unresolved node.
This commit is contained in:
@@ -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)
|
||||
else:
|
||||
elif 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
|
||||
elif t.containsGenericType:
|
||||
if c.inGenericContext > 0:
|
||||
result = semGenericStmt(c, n)
|
||||
result.typ = makeTypeFromExpr(c, copyTree(result))
|
||||
else:
|
||||
result = nil
|
||||
else:
|
||||
result = nil
|
||||
|
||||
|
||||
@@ -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]
|
||||
@@ -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)):
|
||||
@@ -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):
|
||||
@@ -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
|
||||
|
||||
@@ -678,8 +678,31 @@ 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:
|
||||
result = t
|
||||
|
||||
of tyStatic:
|
||||
if cl.c.matchedConcept != nil:
|
||||
# allow concepts to not instantiate statics for now
|
||||
# they can't always infer them
|
||||
return
|
||||
if not containsGenericType(t) and (t.n == nil or t.n.kind in nkLiterals):
|
||||
# no need to instantiate
|
||||
return
|
||||
bailout()
|
||||
result = instCopyType(cl, t)
|
||||
cl.localCache[t.itemId] = result
|
||||
for i in FirstGenericParamAt..<result.kidsLen:
|
||||
var r = result[i]
|
||||
if r != nil:
|
||||
r = replaceTypeVarsT(cl, r)
|
||||
result[i] = r
|
||||
propagateToOwner(result, r)
|
||||
result.n = replaceTypeVarsN(cl, result.n)
|
||||
if not cl.allowMetaTypes and result.n != nil and
|
||||
result.base.kind != tyNone:
|
||||
result.n = cl.c.semConstExpr(cl.c, result.n)
|
||||
result.n.typ = result.base
|
||||
|
||||
of tyGenericInst, tyUserTypeClassInst:
|
||||
bailout()
|
||||
|
||||
@@ -885,6 +885,7 @@ proc maybeSkipDistinct(m: TCandidate; t: PType, callee: PSym): PType =
|
||||
|
||||
proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
|
||||
allowUnresolved = false,
|
||||
allowCalls = false,
|
||||
expectedType: PType = nil): PNode =
|
||||
# Consider this example:
|
||||
# type Value[N: static[int]] = object
|
||||
@@ -894,7 +895,7 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
|
||||
# This proc is used to evaluate such static expressions.
|
||||
let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil,
|
||||
allowMetaTypes = allowUnresolved)
|
||||
if instantiated.kind in nkCallKinds:
|
||||
if not allowCalls and instantiated.kind in nkCallKinds:
|
||||
return nil
|
||||
result = c.c.semExpr(c.c, instantiated)
|
||||
|
||||
@@ -966,7 +967,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 +1879,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`
|
||||
@@ -1963,23 +1969,29 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
of tyFromExpr:
|
||||
# fix the expression, so it contains the already instantiated types
|
||||
if f.n == nil or f.n.kind == nkEmpty: return isGeneric
|
||||
let reevaluated = tryResolvingStaticExpr(c, f.n)
|
||||
if reevaluated == nil:
|
||||
if c.c.inGenericContext > 0:
|
||||
# need to delay until instantiation
|
||||
# also prevent infinite recursion below
|
||||
return isNone
|
||||
inc c.c.inGenericContext # to generate tyFromExpr again if unresolved
|
||||
let reevaluated = tryResolvingStaticExpr(c, f.n, allowCalls = true).typ
|
||||
dec c.c.inGenericContext
|
||||
case reevaluated.kind
|
||||
of tyFromExpr:
|
||||
# not resolved
|
||||
result = isNone
|
||||
return
|
||||
case reevaluated.typ.kind
|
||||
of tyTypeDesc:
|
||||
result = typeRel(c, a, reevaluated.typ.base, flags)
|
||||
result = typeRel(c, a, reevaluated.base, flags)
|
||||
of tyStatic:
|
||||
result = typeRel(c, a, reevaluated.typ.base, flags)
|
||||
if result != isNone and reevaluated.typ.n != nil:
|
||||
if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
|
||||
result = typeRel(c, a, reevaluated.base, flags)
|
||||
if result != isNone and reevaluated.n != nil:
|
||||
if not exprStructuralEquivalent(aOrig.n, reevaluated.n):
|
||||
result = isNone
|
||||
else:
|
||||
# bug #14136: other types are just like 'tyStatic' here:
|
||||
result = typeRel(c, a, reevaluated.typ, flags)
|
||||
if result != isNone and reevaluated.typ.n != nil:
|
||||
if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
|
||||
result = typeRel(c, a, reevaluated, flags)
|
||||
if result != isNone and reevaluated.n != nil:
|
||||
if not exprStructuralEquivalent(aOrig.n, reevaluated.n):
|
||||
result = isNone
|
||||
of tyNone:
|
||||
if a.kind == tyNone: result = isEqual
|
||||
@@ -2188,7 +2200,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -239,3 +239,65 @@ 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()
|
||||
|
||||
when false: # issue #22342, type section version of #22607
|
||||
type GenAlias[isInt: static bool] = (
|
||||
when isInt:
|
||||
int
|
||||
else:
|
||||
float
|
||||
)
|
||||
|
||||
206
tests/proc/tstaticsignature.nim
Normal file
206
tests/proc/tstaticsignature.nim
Normal file
@@ -0,0 +1,206 @@
|
||||
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
|
||||
|
||||
block: # tyStatic and tyFromExpr instantiation mid-match
|
||||
proc bar(x: int): int = x * 3
|
||||
proc bar2(x: static int): int = x * 4
|
||||
type Foo[T: static int] = distinct array[T, int]
|
||||
proc foo[T: static int](x: Foo[T], y: Foo[bar(T)]) = discard
|
||||
proc foo2[T: static int](x: Foo[T], y: Foo[bar2(T)]) = discard
|
||||
foo(Foo[1]([1]), Foo[3]([1, 2, 3]))
|
||||
foo2(Foo[1]([1]), Foo[4]([1, 2, 3, 4]))
|
||||
|
||||
block: # issue #4990
|
||||
type Foo[I: static[int], A: static[array[I, int]]] = object
|
||||
curIndex: int
|
||||
|
||||
proc next[I: static[int], A: static[array[I, int]]](f: Foo[I, A]): string =
|
||||
discard
|
||||
const arr = [1, 2, 3]
|
||||
var f: Foo[arr.len, arr]
|
||||
discard next(f)
|
||||
|
||||
block: # issue #4990 comment
|
||||
type
|
||||
Foo[A: static[int], B: static[int], TokenType: enum, EofToken: static[TokenType]] = object
|
||||
curIndex: int
|
||||
MyEnum = enum
|
||||
meA, meB
|
||||
Bar = Foo[2, 3, MyEnum, meA]
|
||||
proc next[A: static[int], B: static[int], TokenType: enum,
|
||||
EofToken: static[TokenType]](f: Foo[A, B, TokenType, EofToken],
|
||||
a: static[(array[A, int], array[B, int])]): TokenType =
|
||||
TokenType(a[0][f.curIndex])
|
||||
const
|
||||
a = [1, 2]
|
||||
b = [3, 4, 5]
|
||||
template next(bar: Bar): MyEnum =
|
||||
next(Foo[2, 3, MyEnum, meA](bar), (a, b))
|
||||
let bar = Bar(curIndex: 0)
|
||||
doAssert bar.next() == meB
|
||||
|
||||
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[])
|
||||
Reference in New Issue
Block a user