Skip to content

Commit

Permalink
Fixed generic distinct conversions for 'var' (#18837)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
beef331 authored Oct 26, 2021
1 parent 3ecb369 commit 83a2515
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 66 deletions.
138 changes: 76 additions & 62 deletions compiler/jsgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1288,75 +1288,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
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:
typ
if jsType == etyObject:
# make addr() a no-op:
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")
if isIndirect(s):
r.res = s.loc.r & "[0]"
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)
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)
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:
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)
Expand Down
8 changes: 4 additions & 4 deletions compiler/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions tests/converter/texplicit_conversion.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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))
17 changes: 17 additions & 0 deletions tests/distinct/tdistinct.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ false
false
false
Foo
foo
'''
"""

Expand Down Expand Up @@ -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() =
Expand Down

0 comments on commit 83a2515

Please sign in to comment.