Fixed generic distinct conversions for 'var' (#18837)
* SameTypeAux now properly traverses generic distincts * Smarter traversal of distincts * Removed redundant check * Fixed nkConv for jsgen * Added test for non distinct nkConv * using skiptypes for distinct now * Fixed genaddr for nkconv
This commit is contained in:
parent
3ecb369ca1
commit
83a2515af7
4 changed files with 104 additions and 67 deletions
|
|
@ -1288,75 +1288,89 @@ template isIndirect(x: PSym): bool =
|
||||||
v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
|
v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
|
||||||
skConst, skTemp, skLet})
|
skConst, skTemp, skLet})
|
||||||
|
|
||||||
proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
|
||||||
case n[0].kind
|
let s = n.sym
|
||||||
of nkSym:
|
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
|
||||||
let s = n[0].sym
|
case s.kind
|
||||||
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
|
of skParam:
|
||||||
case s.kind
|
r.res = s.loc.r
|
||||||
of skParam:
|
r.address = nil
|
||||||
r.res = s.loc.r
|
r.typ = etyNone
|
||||||
r.address = nil
|
of skVar, skLet, skResult:
|
||||||
r.typ = etyNone
|
r.kind = resExpr
|
||||||
of skVar, skLet, skResult:
|
let jsType = mapType(p):
|
||||||
r.kind = resExpr
|
if typ.isNil:
|
||||||
let jsType = mapType(p, n.typ)
|
n.typ
|
||||||
if jsType == etyObject:
|
|
||||||
# make addr() a no-op:
|
|
||||||
r.typ = etyNone
|
|
||||||
if isIndirect(s):
|
|
||||||
r.res = s.loc.r & "[0]"
|
|
||||||
else:
|
|
||||||
r.res = s.loc.r
|
|
||||||
r.address = nil
|
|
||||||
elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
|
|
||||||
# for ease of code generation, we do not distinguish between
|
|
||||||
# sfAddrTaken and sfGlobal.
|
|
||||||
r.typ = etyBaseIndex
|
|
||||||
r.address = s.loc.r
|
|
||||||
r.res = rope("0")
|
|
||||||
else:
|
else:
|
||||||
# 'var openArray' for instance produces an 'addr' but this is harmless:
|
typ
|
||||||
gen(p, n[0], r)
|
if jsType == etyObject:
|
||||||
#internalError(p.config, n.info, "genAddr: 4 " & renderTree(n))
|
# make addr() a no-op:
|
||||||
else: internalError(p.config, n.info, $("genAddr: 2", s.kind))
|
r.typ = etyNone
|
||||||
of nkCheckedFieldExpr:
|
if isIndirect(s):
|
||||||
genCheckedFieldOp(p, n[0], n.typ, r)
|
r.res = s.loc.r & "[0]"
|
||||||
of nkDotExpr:
|
else:
|
||||||
if mapType(p, n.typ) == etyBaseIndex:
|
r.res = s.loc.r
|
||||||
genFieldAddr(p, n[0], r)
|
r.address = nil
|
||||||
|
elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
|
||||||
|
# for ease of code generation, we do not distinguish between
|
||||||
|
# sfAddrTaken and sfGlobal.
|
||||||
|
r.typ = etyBaseIndex
|
||||||
|
r.address = s.loc.r
|
||||||
|
r.res = rope("0")
|
||||||
else:
|
else:
|
||||||
genFieldAccess(p, n[0], r)
|
|
||||||
of nkBracketExpr:
|
|
||||||
var ty = skipTypes(n[0].typ, abstractVarRange)
|
|
||||||
if ty.kind in MappedToObject:
|
|
||||||
gen(p, n[0], r)
|
|
||||||
else:
|
|
||||||
let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind
|
|
||||||
case kindOfIndexedExpr
|
|
||||||
of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs:
|
|
||||||
genArrayAddr(p, n[0], r)
|
|
||||||
of tyTuple:
|
|
||||||
genFieldAddr(p, n[0], r)
|
|
||||||
else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
|
|
||||||
of nkObjDownConv:
|
|
||||||
gen(p, n[0], r)
|
|
||||||
of nkHiddenDeref:
|
|
||||||
gen(p, n[0], r)
|
|
||||||
of nkHiddenAddr:
|
|
||||||
gen(p, n[0], r)
|
|
||||||
of nkStmtListExpr:
|
|
||||||
if n.len == 1: gen(p, n[0], r)
|
|
||||||
else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr")
|
|
||||||
of nkCallKinds:
|
|
||||||
if n[0].typ.kind == tyOpenArray:
|
|
||||||
# 'var openArray' for instance produces an 'addr' but this is harmless:
|
# 'var openArray' for instance produces an 'addr' but this is harmless:
|
||||||
# namely toOpenArray(a, 1, 3)
|
gen(p, n, r)
|
||||||
|
#internalError(p.config, n.info, "genAddr: 4 " & renderTree(n))
|
||||||
|
else: internalError(p.config, n.info, $("genAddr: 2", s.kind))
|
||||||
|
|
||||||
|
proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
|
if n.kind == nkSym:
|
||||||
|
genSymAddr(p, n, nil, r)
|
||||||
|
else:
|
||||||
|
case n[0].kind
|
||||||
|
of nkSym:
|
||||||
|
genSymAddr(p, n[0], n.typ, r)
|
||||||
|
of nkCheckedFieldExpr:
|
||||||
|
genCheckedFieldOp(p, n[0], n.typ, r)
|
||||||
|
of nkDotExpr:
|
||||||
|
if mapType(p, n.typ) == etyBaseIndex:
|
||||||
|
genFieldAddr(p, n[0], r)
|
||||||
|
else:
|
||||||
|
genFieldAccess(p, n[0], r)
|
||||||
|
of nkBracketExpr:
|
||||||
|
var ty = skipTypes(n[0].typ, abstractVarRange)
|
||||||
|
if ty.kind in MappedToObject:
|
||||||
|
gen(p, n[0], r)
|
||||||
|
else:
|
||||||
|
let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind
|
||||||
|
case kindOfIndexedExpr
|
||||||
|
of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs:
|
||||||
|
genArrayAddr(p, n[0], r)
|
||||||
|
of tyTuple:
|
||||||
|
genFieldAddr(p, n[0], r)
|
||||||
|
of tyGenericBody:
|
||||||
|
genAddr(p, n[^1], r)
|
||||||
|
else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
|
||||||
|
of nkObjDownConv:
|
||||||
gen(p, n[0], r)
|
gen(p, n[0], r)
|
||||||
|
of nkHiddenDeref:
|
||||||
|
gen(p, n[0], r)
|
||||||
|
of nkHiddenAddr:
|
||||||
|
gen(p, n[0], r)
|
||||||
|
of nkConv:
|
||||||
|
genAddr(p, n[0], r)
|
||||||
|
of nkStmtListExpr:
|
||||||
|
if n.len == 1: gen(p, n[0], r)
|
||||||
|
else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr")
|
||||||
|
of nkCallKinds:
|
||||||
|
if n[0].typ.kind == tyOpenArray:
|
||||||
|
# 'var openArray' for instance produces an 'addr' but this is harmless:
|
||||||
|
# namely toOpenArray(a, 1, 3)
|
||||||
|
gen(p, n[0], r)
|
||||||
|
else:
|
||||||
|
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
|
||||||
else:
|
else:
|
||||||
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
|
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
|
||||||
else:
|
|
||||||
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
|
|
||||||
|
|
||||||
proc attachProc(p: PProc; content: Rope; s: PSym) =
|
proc attachProc(p: PProc; content: Rope; s: PSym) =
|
||||||
p.g.code.add(content)
|
p.g.code.add(content)
|
||||||
|
|
|
||||||
|
|
@ -1121,15 +1121,15 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
case c.cmp
|
case c.cmp
|
||||||
of dcEq: return false
|
of dcEq: return false
|
||||||
of dcEqIgnoreDistinct:
|
of dcEqIgnoreDistinct:
|
||||||
while a.kind == tyDistinct: a = a[0]
|
a = a.skipTypes({tyDistinct, tyGenericInst})
|
||||||
while b.kind == tyDistinct: b = b[0]
|
b = b.skipTypes({tyDistinct, tyGenericInst})
|
||||||
if a.kind != b.kind: return false
|
if a.kind != b.kind: return false
|
||||||
of dcEqOrDistinctOf:
|
of dcEqOrDistinctOf:
|
||||||
while a.kind == tyDistinct: a = a[0]
|
a = a.skipTypes({tyDistinct, tyGenericInst})
|
||||||
if a.kind != b.kind: return false
|
if a.kind != b.kind: return false
|
||||||
|
|
||||||
# this is required by tunique_type but makes no sense really:
|
# this is required by tunique_type but makes no sense really:
|
||||||
if x.kind == tyGenericInst and IgnoreTupleFields notin c.flags:
|
if tyDistinct notin {x.kind, y.kind} and x.kind == tyGenericInst and IgnoreTupleFields notin c.flags:
|
||||||
let
|
let
|
||||||
lhs = x.skipGenericAlias
|
lhs = x.skipGenericAlias
|
||||||
rhs = y.skipGenericAlias
|
rhs = y.skipGenericAlias
|
||||||
|
|
|
||||||
|
|
@ -11,3 +11,9 @@ converter toInt(s: string): int =
|
||||||
|
|
||||||
let x = (int)"234"
|
let x = (int)"234"
|
||||||
echo x
|
echo x
|
||||||
|
|
||||||
|
block: # Test for nkconv
|
||||||
|
proc foo(o: var int) =
|
||||||
|
assert o == 0
|
||||||
|
var a = 0
|
||||||
|
foo(int(a))
|
||||||
|
|
@ -8,6 +8,7 @@ false
|
||||||
false
|
false
|
||||||
false
|
false
|
||||||
Foo
|
Foo
|
||||||
|
foo
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -140,6 +141,22 @@ block tRequiresInit:
|
||||||
let s = "test"
|
let s = "test"
|
||||||
doAssert s == "test"
|
doAssert s == "test"
|
||||||
|
|
||||||
|
block: #17322
|
||||||
|
type
|
||||||
|
A[T] = distinct string
|
||||||
|
|
||||||
|
proc foo(a: var A) =
|
||||||
|
a.string.add "foo"
|
||||||
|
|
||||||
|
type
|
||||||
|
B = distinct A[int]
|
||||||
|
|
||||||
|
var b: B
|
||||||
|
foo(A[int](b))
|
||||||
|
echo A[int](b).string
|
||||||
|
b.string.add "bar"
|
||||||
|
assert b.string == "foobar"
|
||||||
|
|
||||||
type Foo = distinct string
|
type Foo = distinct string
|
||||||
|
|
||||||
template main() =
|
template main() =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue