mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-14 23:33:28 +00:00
fix #1789 (binding to static params during generic proc sigmatch)
This commit is contained in:
@@ -219,7 +219,7 @@ proc maybeLiftType(t: var PType, c: PContext, info: TLineInfo) =
|
||||
# gnrc. params, then it won't be necessary to open a new scope here
|
||||
openScope(c)
|
||||
var lifted = liftParamType(c, skType, newNodeI(nkArgList, info),
|
||||
t, ":anon", info)
|
||||
t, ":anon", info)
|
||||
closeScope(c)
|
||||
if lifted != nil: t = lifted
|
||||
|
||||
|
||||
@@ -60,7 +60,13 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skGenericParam:
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
if s.typ != nil and s.typ.kind == tyStatic:
|
||||
if s.typ.n != nil:
|
||||
result = s.typ.n
|
||||
else:
|
||||
result = n
|
||||
else:
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
of skParam:
|
||||
result = n
|
||||
|
||||
@@ -21,7 +21,8 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
var q = a.sym
|
||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
|
||||
continue
|
||||
var s = newSym(skType, q.name, getCurrOwner(), q.info)
|
||||
let symKind = if q.typ.kind == tyStatic: skConst else: skType
|
||||
var s = newSym(symKind, q.name, getCurrOwner(), q.info)
|
||||
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
||||
var t = PType(idTableGet(pt, q.typ))
|
||||
if t == nil:
|
||||
@@ -40,6 +41,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
t = generateTypeInstance(c, pt, a, t)
|
||||
#t = ReplaceTypeVarsT(cl, t)
|
||||
s.typ = t
|
||||
if t.kind == tyStatic: s.ast = t.n
|
||||
addDecl(c, s)
|
||||
entry.concreteTypes[i] = t
|
||||
|
||||
|
||||
@@ -214,44 +214,48 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
|
||||
localError(n.info, errXExpectsOneTypeParam, "range")
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
|
||||
proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||
var indx, base: PType
|
||||
result = newOrPrevType(tyArray, prev, c)
|
||||
if sonsLen(n) == 3:
|
||||
# 3 = length(array indx base)
|
||||
if isRange(n[1]): indx = semRangeAux(c, n[1], nil)
|
||||
proc semArrayIndex(c: PContext, n: PNode): PType =
|
||||
if isRange(n): result = semRangeAux(c, n, nil)
|
||||
else:
|
||||
let e = semExprWithType(c, n, {efDetermineType})
|
||||
if e.typ.kind == tyFromExpr:
|
||||
result = makeRangeWithStaticExpr(c, e.typ.n)
|
||||
elif e.kind in {nkIntLit..nkUInt64Lit}:
|
||||
result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
|
||||
elif e.kind == nkSym and e.typ.kind == tyStatic:
|
||||
if e.sym.ast != nil:
|
||||
return semArrayIndex(c, e.sym.ast)
|
||||
internalAssert c.inGenericContext > 0
|
||||
if not isOrdinalType(e.typ.lastSon):
|
||||
localError(n[1].info, errOrdinalTypeExpected)
|
||||
result = makeRangeWithStaticExpr(c, e)
|
||||
result.flags.incl tfUnresolved
|
||||
elif e.kind in nkCallKinds and hasGenericArguments(e):
|
||||
if not isOrdinalType(e.typ):
|
||||
localError(n[1].info, errOrdinalTypeExpected)
|
||||
# This is an int returning call, depending on an
|
||||
# yet unknown generic param (see tgenericshardcases).
|
||||
# We are going to construct a range type that will be
|
||||
# properly filled-out in semtypinst (see how tyStaticExpr
|
||||
# is handled there).
|
||||
result = makeRangeWithStaticExpr(c, e)
|
||||
elif e.kind == nkIdent:
|
||||
result = e.typ.skipTypes({tyTypeDesc})
|
||||
else:
|
||||
let e = semExprWithType(c, n.sons[1], {efDetermineType})
|
||||
if e.typ.kind == tyFromExpr:
|
||||
indx = makeRangeWithStaticExpr(c, e.typ.n)
|
||||
elif e.kind in {nkIntLit..nkUInt64Lit}:
|
||||
indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
|
||||
elif e.kind == nkSym and e.typ.kind == tyStatic:
|
||||
if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
|
||||
internalAssert c.inGenericContext > 0
|
||||
if not isOrdinalType(e.typ.lastSon):
|
||||
localError(n[1].info, errOrdinalTypeExpected)
|
||||
indx = makeRangeWithStaticExpr(c, e)
|
||||
indx.flags.incl tfUnresolved
|
||||
elif e.kind in nkCallKinds and hasGenericArguments(e):
|
||||
if not isOrdinalType(e.typ):
|
||||
localError(n[1].info, errOrdinalTypeExpected)
|
||||
# This is an int returning call, depending on an
|
||||
# yet unknown generic param (see tgenericshardcases).
|
||||
# We are going to construct a range type that will be
|
||||
# properly filled-out in semtypinst (see how tyStaticExpr
|
||||
# is handled there).
|
||||
indx = makeRangeWithStaticExpr(c, e)
|
||||
elif e.kind == nkIdent:
|
||||
indx = e.typ.skipTypes({tyTypeDesc})
|
||||
let x = semConstExpr(c, e)
|
||||
if x.kind in {nkIntLit..nkUInt64Lit}:
|
||||
result = makeRangeType(c, 0, x.intVal-1, n.info,
|
||||
x.typ.skipTypes({tyTypeDesc}))
|
||||
else:
|
||||
let x = semConstExpr(c, e)
|
||||
if x.kind in {nkIntLit..nkUInt64Lit}:
|
||||
indx = makeRangeType(c, 0, x.intVal-1, n.info,
|
||||
x.typ.skipTypes({tyTypeDesc}))
|
||||
else:
|
||||
indx = x.typ.skipTypes({tyTypeDesc})
|
||||
#localError(n[1].info, errConstExprExpected)
|
||||
result = x.typ.skipTypes({tyTypeDesc})
|
||||
#localError(n[1].info, errConstExprExpected)
|
||||
|
||||
proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||
var base: PType
|
||||
result = newOrPrevType(tyArray, prev, c)
|
||||
if sonsLen(n) == 3:
|
||||
# 3 = length(array indx base)
|
||||
var indx = semArrayIndex(c, n[1])
|
||||
addSonSkipIntLit(result, indx)
|
||||
if indx.kind == tyGenericInst: indx = lastSon(indx)
|
||||
if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
|
||||
|
||||
@@ -517,6 +517,16 @@ proc maybeSkipDistinct(t: PType, callee: PSym): PType =
|
||||
else:
|
||||
result = t
|
||||
|
||||
proc tryResolvingStaticExpr(c: var TCandidate, n: PNode): PNode =
|
||||
# Consider this example:
|
||||
# type Value[N: static[int]] = object
|
||||
# proc foo[N](a: Value[N], r: range[0..(N-1)])
|
||||
# Here, N-1 will be initially nkStaticExpr that can be evaluated only after
|
||||
# N is bound to a concrete value during the matching of the first param.
|
||||
# This proc is used to evaluate such static expressions.
|
||||
let instantiated = replaceTypesInBody(c.c, c.bindings, n)
|
||||
result = c.c.semExpr(c.c, instantiated)
|
||||
|
||||
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
# typeRel can be used to establish various relationships between types:
|
||||
#
|
||||
@@ -620,6 +630,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
# bugfix: accept integer conversions here
|
||||
#if result < isGeneric: result = isNone
|
||||
if result notin {isNone, isGeneric}:
|
||||
# resolve any late-bound static expressions
|
||||
# that may appear in the range:
|
||||
for i in 0..1:
|
||||
if f.n[i].kind == nkStaticExpr:
|
||||
f.n.sons[i] = tryResolvingStaticExpr(c, f.n[i])
|
||||
result = typeRangeRel(f, a)
|
||||
else:
|
||||
if skipTypes(f, {tyRange}).kind == a.kind:
|
||||
@@ -1006,15 +1021,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
|
||||
of tyFromExpr:
|
||||
# fix the expression, so it contains the already instantiated types
|
||||
let instantiated = replaceTypesInBody(c.c, c.bindings, f.n)
|
||||
let reevaluted = c.c.semExpr(c.c, instantiated)
|
||||
case reevaluted.typ.kind
|
||||
let reevaluated = tryResolvingStaticExpr(c, f.n)
|
||||
case reevaluated.typ.kind
|
||||
of tyTypeDesc:
|
||||
result = typeRel(c, a, reevaluted.typ.base)
|
||||
result = typeRel(c, a, reevaluated.typ.base)
|
||||
of tyStatic:
|
||||
result = typeRel(c, a, reevaluted.typ.base)
|
||||
if result != isNone and reevaluted.typ.n != nil:
|
||||
if not exprStructuralEquivalent(aOrig.n, reevaluted.typ.n):
|
||||
result = typeRel(c, a, reevaluated.typ.base)
|
||||
if result != isNone and reevaluated.typ.n != nil:
|
||||
if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
|
||||
result = isNone
|
||||
else:
|
||||
localError(f.n.info, errTypeExpected)
|
||||
|
||||
44
tests/generics/t1789.nim
Normal file
44
tests/generics/t1789.nim
Normal file
@@ -0,0 +1,44 @@
|
||||
discard """
|
||||
output: "3\n0"
|
||||
"""
|
||||
|
||||
# https://github.com/Araq/Nim/issues/1789
|
||||
|
||||
type
|
||||
Foo[N: static[int]] = object
|
||||
|
||||
proc bindStaticN[N](foo: Foo[N]) =
|
||||
var ar0: array[3, int]
|
||||
var ar1: array[N, int]
|
||||
var ar2: array[1..N, int]
|
||||
var ar3: array[0..(N+10), float]
|
||||
echo N
|
||||
|
||||
var f: Foo[3]
|
||||
f.bindStaticN
|
||||
|
||||
# case 2
|
||||
|
||||
type
|
||||
ObjectWithStatic[X, Y: static[int], T] = object
|
||||
bar: array[X * Y, T] # this one works
|
||||
|
||||
AliasWithStatic[X, Y: static[int], T] = array[X * Y, T]
|
||||
|
||||
var
|
||||
x: ObjectWithStatic[1, 2, int]
|
||||
y: AliasWithStatic[2, 3, int]
|
||||
|
||||
# case 3
|
||||
|
||||
type
|
||||
Bar[N: static[int], T] = object
|
||||
bar: array[N, T]
|
||||
|
||||
proc `[]`*[N, T](f: Bar[N, T], n: range[0..(N - 1)]): T =
|
||||
assert high(n) == N-1
|
||||
result = f.bar[n]
|
||||
|
||||
var b: Bar[3, int]
|
||||
echo b[2]
|
||||
|
||||
Reference in New Issue
Block a user