mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-18 21:40:32 +00:00
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
(cherry picked from commit 83a2515af7)
This commit is contained in:
@@ -1297,75 +1297,89 @@ template isIndirect(x: PSym): bool =
|
||||
v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
|
||||
skConst, skTemp, skLet})
|
||||
|
||||
proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
case n[0].kind
|
||||
of nkSym:
|
||||
let s = n[0].sym
|
||||
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
|
||||
case s.kind
|
||||
of skParam:
|
||||
r.res = s.loc.r
|
||||
r.address = nil
|
||||
r.typ = etyNone
|
||||
of skVar, skLet, skResult:
|
||||
r.kind = resExpr
|
||||
let jsType = mapType(p, 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")
|
||||
proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
|
||||
let s = n.sym
|
||||
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
|
||||
case s.kind
|
||||
of skParam:
|
||||
r.res = s.loc.r
|
||||
r.address = nil
|
||||
r.typ = etyNone
|
||||
of skVar, skLet, skResult:
|
||||
r.kind = resExpr
|
||||
let jsType = mapType(p):
|
||||
if typ.isNil:
|
||||
n.typ
|
||||
else:
|
||||
# 'var openArray' for instance produces an 'addr' but this is harmless:
|
||||
gen(p, n[0], r)
|
||||
#internalError(p.config, n.info, "genAddr: 4 " & renderTree(n))
|
||||
else: internalError(p.config, n.info, $("genAddr: 2", s.kind))
|
||||
of nkCheckedFieldExpr:
|
||||
genCheckedFieldOp(p, n[0], n.typ, r)
|
||||
of nkDotExpr:
|
||||
if mapType(p, n.typ) == etyBaseIndex:
|
||||
genFieldAddr(p, n[0], r)
|
||||
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:
|
||||
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:
|
||||
# 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)
|
||||
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:
|
||||
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) =
|
||||
p.g.code.add(content)
|
||||
|
||||
@@ -1121,15 +1121,15 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
case c.cmp
|
||||
of dcEq: return false
|
||||
of dcEqIgnoreDistinct:
|
||||
while a.kind == tyDistinct: a = a[0]
|
||||
while b.kind == tyDistinct: b = b[0]
|
||||
a = a.skipTypes({tyDistinct, tyGenericInst})
|
||||
b = b.skipTypes({tyDistinct, tyGenericInst})
|
||||
if a.kind != b.kind: return false
|
||||
of dcEqOrDistinctOf:
|
||||
while a.kind == tyDistinct: a = a[0]
|
||||
a = a.skipTypes({tyDistinct, tyGenericInst})
|
||||
if a.kind != b.kind: return false
|
||||
|
||||
# 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
|
||||
lhs = x.skipGenericAlias
|
||||
rhs = y.skipGenericAlias
|
||||
|
||||
@@ -11,3 +11,9 @@ converter toInt(s: string): int =
|
||||
|
||||
let x = (int)"234"
|
||||
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
|
||||
Foo
|
||||
foo
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -140,6 +141,22 @@ block tRequiresInit:
|
||||
let 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
|
||||
|
||||
template main() =
|
||||
|
||||
Reference in New Issue
Block a user