fix #1789 (binding to static params during generic proc sigmatch)
This commit is contained in:
parent
bf8f6a3000
commit
da36a847a7
6 changed files with 116 additions and 46 deletions
|
|
@ -60,6 +60,12 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||||
else:
|
else:
|
||||||
result = symChoice(c, n, s, scOpen)
|
result = symChoice(c, n, s, scOpen)
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
|
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)
|
result = newSymNodeTypeDesc(s, n.info)
|
||||||
styleCheckUse(n.info, s)
|
styleCheckUse(n.info, s)
|
||||||
of skParam:
|
of skParam:
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
var q = a.sym
|
var q = a.sym
|
||||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
|
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
|
||||||
continue
|
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}
|
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
||||||
var t = PType(idTableGet(pt, q.typ))
|
var t = PType(idTableGet(pt, q.typ))
|
||||||
if t == nil:
|
if t == nil:
|
||||||
|
|
@ -40,6 +41,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
t = generateTypeInstance(c, pt, a, t)
|
t = generateTypeInstance(c, pt, a, t)
|
||||||
#t = ReplaceTypeVarsT(cl, t)
|
#t = ReplaceTypeVarsT(cl, t)
|
||||||
s.typ = t
|
s.typ = t
|
||||||
|
if t.kind == tyStatic: s.ast = t.n
|
||||||
addDecl(c, s)
|
addDecl(c, s)
|
||||||
entry.concreteTypes[i] = t
|
entry.concreteTypes[i] = t
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,25 +214,22 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
|
||||||
localError(n.info, errXExpectsOneTypeParam, "range")
|
localError(n.info, errXExpectsOneTypeParam, "range")
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
|
|
||||||
proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
proc semArrayIndex(c: PContext, n: PNode): PType =
|
||||||
var indx, base: PType
|
if isRange(n): result = semRangeAux(c, n, nil)
|
||||||
result = newOrPrevType(tyArray, prev, c)
|
|
||||||
if sonsLen(n) == 3:
|
|
||||||
# 3 = length(array indx base)
|
|
||||||
if isRange(n[1]): indx = semRangeAux(c, n[1], nil)
|
|
||||||
else:
|
else:
|
||||||
let e = semExprWithType(c, n.sons[1], {efDetermineType})
|
let e = semExprWithType(c, n, {efDetermineType})
|
||||||
if e.typ.kind == tyFromExpr:
|
if e.typ.kind == tyFromExpr:
|
||||||
indx = makeRangeWithStaticExpr(c, e.typ.n)
|
result = makeRangeWithStaticExpr(c, e.typ.n)
|
||||||
elif e.kind in {nkIntLit..nkUInt64Lit}:
|
elif e.kind in {nkIntLit..nkUInt64Lit}:
|
||||||
indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
|
result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
|
||||||
elif e.kind == nkSym and e.typ.kind == tyStatic:
|
elif e.kind == nkSym and e.typ.kind == tyStatic:
|
||||||
if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
|
if e.sym.ast != nil:
|
||||||
|
return semArrayIndex(c, e.sym.ast)
|
||||||
internalAssert c.inGenericContext > 0
|
internalAssert c.inGenericContext > 0
|
||||||
if not isOrdinalType(e.typ.lastSon):
|
if not isOrdinalType(e.typ.lastSon):
|
||||||
localError(n[1].info, errOrdinalTypeExpected)
|
localError(n[1].info, errOrdinalTypeExpected)
|
||||||
indx = makeRangeWithStaticExpr(c, e)
|
result = makeRangeWithStaticExpr(c, e)
|
||||||
indx.flags.incl tfUnresolved
|
result.flags.incl tfUnresolved
|
||||||
elif e.kind in nkCallKinds and hasGenericArguments(e):
|
elif e.kind in nkCallKinds and hasGenericArguments(e):
|
||||||
if not isOrdinalType(e.typ):
|
if not isOrdinalType(e.typ):
|
||||||
localError(n[1].info, errOrdinalTypeExpected)
|
localError(n[1].info, errOrdinalTypeExpected)
|
||||||
|
|
@ -241,17 +238,24 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||||
# We are going to construct a range type that will be
|
# We are going to construct a range type that will be
|
||||||
# properly filled-out in semtypinst (see how tyStaticExpr
|
# properly filled-out in semtypinst (see how tyStaticExpr
|
||||||
# is handled there).
|
# is handled there).
|
||||||
indx = makeRangeWithStaticExpr(c, e)
|
result = makeRangeWithStaticExpr(c, e)
|
||||||
elif e.kind == nkIdent:
|
elif e.kind == nkIdent:
|
||||||
indx = e.typ.skipTypes({tyTypeDesc})
|
result = e.typ.skipTypes({tyTypeDesc})
|
||||||
else:
|
else:
|
||||||
let x = semConstExpr(c, e)
|
let x = semConstExpr(c, e)
|
||||||
if x.kind in {nkIntLit..nkUInt64Lit}:
|
if x.kind in {nkIntLit..nkUInt64Lit}:
|
||||||
indx = makeRangeType(c, 0, x.intVal-1, n.info,
|
result = makeRangeType(c, 0, x.intVal-1, n.info,
|
||||||
x.typ.skipTypes({tyTypeDesc}))
|
x.typ.skipTypes({tyTypeDesc}))
|
||||||
else:
|
else:
|
||||||
indx = x.typ.skipTypes({tyTypeDesc})
|
result = x.typ.skipTypes({tyTypeDesc})
|
||||||
#localError(n[1].info, errConstExprExpected)
|
#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)
|
addSonSkipIntLit(result, indx)
|
||||||
if indx.kind == tyGenericInst: indx = lastSon(indx)
|
if indx.kind == tyGenericInst: indx = lastSon(indx)
|
||||||
if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
|
if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
|
||||||
|
|
|
||||||
|
|
@ -517,6 +517,16 @@ proc maybeSkipDistinct(t: PType, callee: PSym): PType =
|
||||||
else:
|
else:
|
||||||
result = t
|
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 =
|
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# typeRel can be used to establish various relationships between types:
|
# 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
|
# bugfix: accept integer conversions here
|
||||||
#if result < isGeneric: result = isNone
|
#if result < isGeneric: result = isNone
|
||||||
if result notin {isNone, isGeneric}:
|
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)
|
result = typeRangeRel(f, a)
|
||||||
else:
|
else:
|
||||||
if skipTypes(f, {tyRange}).kind == a.kind:
|
if skipTypes(f, {tyRange}).kind == a.kind:
|
||||||
|
|
@ -1006,15 +1021,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
of tyFromExpr:
|
of tyFromExpr:
|
||||||
# fix the expression, so it contains the already instantiated types
|
# fix the expression, so it contains the already instantiated types
|
||||||
let instantiated = replaceTypesInBody(c.c, c.bindings, f.n)
|
let reevaluated = tryResolvingStaticExpr(c, f.n)
|
||||||
let reevaluted = c.c.semExpr(c.c, instantiated)
|
case reevaluated.typ.kind
|
||||||
case reevaluted.typ.kind
|
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
result = typeRel(c, a, reevaluted.typ.base)
|
result = typeRel(c, a, reevaluated.typ.base)
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
result = typeRel(c, a, reevaluted.typ.base)
|
result = typeRel(c, a, reevaluated.typ.base)
|
||||||
if result != isNone and reevaluted.typ.n != nil:
|
if result != isNone and reevaluated.typ.n != nil:
|
||||||
if not exprStructuralEquivalent(aOrig.n, reevaluted.typ.n):
|
if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
localError(f.n.info, errTypeExpected)
|
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]
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue