borrow checking (#15282)
* refactoring: move procs to typeallowed.nim * frontend preparations for first class openArray support * prepare the code generator for first class openArray * code generation for first class openArray; WIP * code generation for open arrays, progress * added isViewType proc * preparations for borrow checking * added borrow checking to the front end
This commit is contained in:
parent
c49b88163c
commit
10988d4840
18 changed files with 554 additions and 311 deletions
|
|
@ -141,6 +141,13 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||||
|
|
||||||
proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
|
proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
|
||||||
|
|
||||||
|
proc reifiedOpenArray(n: PNode): bool {.inline.} =
|
||||||
|
let x = trees.getRoot(n)
|
||||||
|
if x != nil and x.kind == skParam:
|
||||||
|
result = false
|
||||||
|
else:
|
||||||
|
result = true
|
||||||
|
|
||||||
proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
|
|
||||||
|
|
@ -174,7 +181,12 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||||
else:
|
else:
|
||||||
result = "($5*)($1)+(($2)-($4)), ($3)-($2)+1" %
|
result = "($5*)($1)+(($2)-($4)), ($3)-($2)+1" %
|
||||||
[rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first), dest]
|
[rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first), dest]
|
||||||
of tyOpenArray, tyVarargs, tyUncheckedArray, tyCString:
|
of tyOpenArray, tyVarargs:
|
||||||
|
if reifiedOpenArray(q[1]):
|
||||||
|
result = "($4*)($1.d)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
|
||||||
|
else:
|
||||||
|
result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
|
||||||
|
of tyUncheckedArray, tyCString:
|
||||||
result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
|
result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
let atyp = skipTypes(a.t, abstractInst)
|
let atyp = skipTypes(a.t, abstractInst)
|
||||||
|
|
@ -188,10 +200,13 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||||
else:
|
else:
|
||||||
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
|
||||||
else:
|
else:
|
||||||
initLocExpr(p, n, a)
|
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
|
||||||
case skipTypes(a.t, abstractVar).kind
|
case skipTypes(a.t, abstractVar).kind
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = "$1, $1Len_0" % [rdLoc(a)]
|
if reifiedOpenArray(n):
|
||||||
|
result = "$1.d, $1.l" % [rdLoc(a)]
|
||||||
|
else:
|
||||||
|
result = "$1, $1Len_0" % [rdLoc(a)]
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
let ntyp = skipTypes(n.typ, abstractInst)
|
let ntyp = skipTypes(n.typ, abstractInst)
|
||||||
if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and
|
if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,34 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
|
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
|
||||||
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)])
|
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)])
|
||||||
|
|
||||||
|
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
|
||||||
|
assert d.k != locNone
|
||||||
|
# getTemp(p, d.t, d)
|
||||||
|
|
||||||
|
case a.t.skipTypes(abstractVar).kind
|
||||||
|
of tyOpenArray, tyVarargs:
|
||||||
|
if reifiedOpenArray(a.lode):
|
||||||
|
linefmt(p, cpsStmts, "$1.d = $2.d; $1.l = $2.l;$n",
|
||||||
|
[rdLoc(d), a.rdLoc])
|
||||||
|
else:
|
||||||
|
linefmt(p, cpsStmts, "$1.d = $2; $1.l = $2Len_0;$n",
|
||||||
|
[rdLoc(d), a.rdLoc])
|
||||||
|
of tySequence:
|
||||||
|
linefmt(p, cpsStmts, "$1.d = $2$3; $1.l = $4;$n",
|
||||||
|
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)])
|
||||||
|
of tyArray:
|
||||||
|
linefmt(p, cpsStmts, "$1.d = $2; $1.l = $3;$n",
|
||||||
|
[rdLoc(d), rdLoc(a), rope(lengthOrd(p.config, a.t))])
|
||||||
|
of tyString:
|
||||||
|
let etyp = skipTypes(a.t, abstractInst)
|
||||||
|
if etyp.kind in {tyVar} and optSeqDestructors in p.config.globalOptions:
|
||||||
|
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||||
|
|
||||||
|
linefmt(p, cpsStmts, "$1.d = $2$3; $1.l = $4;$n",
|
||||||
|
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)])
|
||||||
|
else:
|
||||||
|
internalError(p.config, a.lode.info, "cannot handle " & $a.t.kind)
|
||||||
|
|
||||||
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
# This function replaces all other methods for generating
|
# This function replaces all other methods for generating
|
||||||
# the assignment operation in C.
|
# the assignment operation in C.
|
||||||
|
|
@ -349,7 +377,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
# open arrays are always on the stack - really? What if a sequence is
|
# open arrays are always on the stack - really? What if a sequence is
|
||||||
# passed to an open array?
|
# passed to an open array?
|
||||||
if containsGarbageCollectedRef(dest.t):
|
if reifiedOpenArray(dest.lode):
|
||||||
|
genOpenArrayConv(p, dest, src)
|
||||||
|
elif containsGarbageCollectedRef(dest.t):
|
||||||
linefmt(p, cpsStmts, # XXX: is this correct for arrays?
|
linefmt(p, cpsStmts, # XXX: is this correct for arrays?
|
||||||
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
|
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
|
||||||
[addrLoc(p.config, dest), addrLoc(p.config, src),
|
[addrLoc(p.config, dest), addrLoc(p.config, src),
|
||||||
|
|
@ -361,7 +391,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
"$1 = $2;$n",
|
"$1 = $2;$n",
|
||||||
[rdLoc(dest), rdLoc(src)])
|
[rdLoc(dest), rdLoc(src)])
|
||||||
of tySet:
|
of tySet:
|
||||||
if mapType(p.config, ty) == ctArray:
|
if mapSetType(p.config, ty) == ctArray:
|
||||||
linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n",
|
linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n",
|
||||||
[rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)])
|
[rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)])
|
||||||
else:
|
else:
|
||||||
|
|
@ -406,7 +436,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
|
||||||
[addrLoc(p.config, dest), addrLocOrTemp(src),
|
[addrLoc(p.config, dest), addrLocOrTemp(src),
|
||||||
genTypeInfo(p.module, dest.t, dest.lode.info)])
|
genTypeInfo(p.module, dest.t, dest.lode.info)])
|
||||||
of tySet:
|
of tySet:
|
||||||
if mapType(p.config, ty) == ctArray:
|
if mapSetType(p.config, ty) == ctArray:
|
||||||
linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n",
|
linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n",
|
||||||
[rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)])
|
[rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)])
|
||||||
else:
|
else:
|
||||||
|
|
@ -679,7 +709,7 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
|
||||||
tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags
|
tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags
|
||||||
|
|
||||||
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
||||||
let mt = mapType(p.config, e[0].typ)
|
let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]))
|
||||||
if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
|
if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
|
||||||
# XXX the amount of hacks for C's arrays is incredible, maybe we should
|
# XXX the amount of hacks for C's arrays is incredible, maybe we should
|
||||||
# simply wrap them in a struct? --> Losing auto vectorization then?
|
# simply wrap them in a struct? --> Losing auto vectorization then?
|
||||||
|
|
@ -747,7 +777,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
initLocExpr(p, e[0], a)
|
initLocExpr(p, e[0], a)
|
||||||
putIntoDest(p, d, e, "&" & a.r, a.storage)
|
putIntoDest(p, d, e, "&" & a.r, a.storage)
|
||||||
#Message(e.info, warnUser, "HERE NEW &")
|
#Message(e.info, warnUser, "HERE NEW &")
|
||||||
elif mapType(p.config, e[0].typ) == ctArray or isCppRef(p, e.typ):
|
elif mapType(p.config, e[0].typ, mapTypeChooser(e[0])) == ctArray or isCppRef(p, e.typ):
|
||||||
expr(p, e[0], d)
|
expr(p, e[0], d)
|
||||||
else:
|
else:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
|
|
@ -905,10 +935,16 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
|
||||||
let ty = skipTypes(arr.t, abstractVarRange)
|
let ty = skipTypes(arr.t, abstractVarRange)
|
||||||
case ty.kind
|
case ty.kind
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
linefmt(p, cpsStmts,
|
if reifiedOpenArray(arr.lode):
|
||||||
"if ($2-$1 != -1 && " &
|
linefmt(p, cpsStmts,
|
||||||
"((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n",
|
"if ($2-$1 != -1 && " &
|
||||||
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)])
|
"((NU)($1) >= (NU)($3.l) || (NU)($2) >= (NU)($3.l))){ #raiseIndexError(); $4}$n",
|
||||||
|
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)])
|
||||||
|
else:
|
||||||
|
linefmt(p, cpsStmts,
|
||||||
|
"if ($2-$1 != -1 && " &
|
||||||
|
"((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n",
|
||||||
|
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)])
|
||||||
of tyArray:
|
of tyArray:
|
||||||
let first = intLiteral(firstOrd(p.config, ty))
|
let first = intLiteral(firstOrd(p.config, ty))
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
|
|
@ -925,13 +961,22 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
|
||||||
proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
initLocExpr(p, x, a)
|
initLocExpr(p, x, a)
|
||||||
initLocExpr(p, y, b) # emit range check:
|
initLocExpr(p, y, b)
|
||||||
if optBoundsCheck in p.options:
|
if not reifiedOpenArray(x):
|
||||||
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n",
|
# emit range check:
|
||||||
[rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``!
|
if optBoundsCheck in p.options:
|
||||||
inheritLocation(d, a)
|
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n",
|
||||||
putIntoDest(p, d, n,
|
[rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``!
|
||||||
ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
|
inheritLocation(d, a)
|
||||||
|
putIntoDest(p, d, n,
|
||||||
|
ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
|
||||||
|
else:
|
||||||
|
if optBoundsCheck in p.options:
|
||||||
|
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2.l)){ #raiseIndexError2($1,$2.l-1); $3}$n",
|
||||||
|
[rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``!
|
||||||
|
inheritLocation(d, a)
|
||||||
|
putIntoDest(p, d, n,
|
||||||
|
ropecg(p.module, "$1.d[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
|
||||||
|
|
||||||
proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
|
|
@ -1675,8 +1720,12 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
else:
|
else:
|
||||||
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)]))
|
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)]))
|
||||||
else:
|
else:
|
||||||
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
|
if not reifiedOpenArray(a):
|
||||||
else: unaryExpr(p, e, d, "$1Len_0")
|
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
|
||||||
|
else: unaryExpr(p, e, d, "$1Len_0")
|
||||||
|
else:
|
||||||
|
if op == mHigh: unaryExpr(p, e, d, "($1.l-1)")
|
||||||
|
else: unaryExpr(p, e, d, "$1.l")
|
||||||
of tyCString:
|
of tyCString:
|
||||||
if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
|
if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
|
||||||
else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
|
else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
|
||||||
|
|
@ -2253,13 +2302,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t)])
|
putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t)])
|
||||||
of mOffsetOf:
|
of mOffsetOf:
|
||||||
var dotExpr: PNode
|
var dotExpr: PNode
|
||||||
block findDotExpr:
|
if e[1].kind == nkDotExpr:
|
||||||
if e[1].kind == nkDotExpr:
|
dotExpr = e[1]
|
||||||
dotExpr = e[1]
|
elif e[1].kind == nkCheckedFieldExpr:
|
||||||
elif e[1].kind == nkCheckedFieldExpr:
|
dotExpr = e[1][0]
|
||||||
dotExpr = e[1][0]
|
else:
|
||||||
else:
|
internalError(p.config, e.info, "unknown ast")
|
||||||
internalError(p.config, e.info, "unknown ast")
|
|
||||||
let t = dotExpr[0].typ.skipTypes({tyTypeDesc})
|
let t = dotExpr[0].typ.skipTypes({tyTypeDesc})
|
||||||
let tname = getTypeDesc(p.module, t)
|
let tname = getTypeDesc(p.module, t)
|
||||||
let member =
|
let member =
|
||||||
|
|
@ -2813,8 +2861,10 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
|
||||||
result.add getDefaultValue(p, t.sons[1], info)
|
result.add getDefaultValue(p, t.sons[1], info)
|
||||||
result.add "}"
|
result.add "}"
|
||||||
#result = rope"{}"
|
#result = rope"{}"
|
||||||
|
of tyOpenArray, tyVarargs:
|
||||||
|
result = rope"{NIM_NIL, 0}"
|
||||||
of tySet:
|
of tySet:
|
||||||
if mapType(p.config, t) == ctArray: result = rope"{}"
|
if mapSetType(p.config, t) == ctArray: result = rope"{}"
|
||||||
else: result = rope"0"
|
else: result = rope"0"
|
||||||
else:
|
else:
|
||||||
globalError(p.config, info, "cannot create null element for: " & $t.kind)
|
globalError(p.config, info, "cannot create null element for: " & $t.kind)
|
||||||
|
|
|
||||||
|
|
@ -1556,7 +1556,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||||
let le = e[0]
|
let le = e[0]
|
||||||
let ri = e[1]
|
let ri = e[1]
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs))
|
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar)
|
||||||
initLoc(a, locNone, le, OnUnknown)
|
initLoc(a, locNone, le, OnUnknown)
|
||||||
a.flags.incl(lfEnforceDeref)
|
a.flags.incl(lfEnforceDeref)
|
||||||
a.flags.incl(lfPrepareForMutation)
|
a.flags.incl(lfPrepareForMutation)
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
|
||||||
of 8: result = ctInt64
|
of 8: result = ctInt64
|
||||||
else: result = ctArray
|
else: result = ctArray
|
||||||
|
|
||||||
proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
|
proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind =
|
||||||
## Maps a Nim type to a C type
|
## Maps a Nim type to a C type
|
||||||
case typ.kind
|
case typ.kind
|
||||||
of tyNone, tyTyped: result = ctVoid
|
of tyNone, tyTyped: result = ctVoid
|
||||||
|
|
@ -157,14 +157,17 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
|
||||||
of tyChar: result = ctChar
|
of tyChar: result = ctChar
|
||||||
of tyNil: result = ctPtr
|
of tyNil: result = ctPtr
|
||||||
of tySet: result = mapSetType(conf, typ)
|
of tySet: result = mapSetType(conf, typ)
|
||||||
of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctArray
|
of tyOpenArray, tyVarargs:
|
||||||
|
if kind == skParam: result = ctArray
|
||||||
|
else: result = ctStruct
|
||||||
|
of tyArray, tyUncheckedArray: result = ctArray
|
||||||
of tyObject, tyTuple: result = ctStruct
|
of tyObject, tyTuple: result = ctStruct
|
||||||
of tyUserTypeClasses:
|
of tyUserTypeClasses:
|
||||||
doAssert typ.isResolvedUserTypeClass
|
doAssert typ.isResolvedUserTypeClass
|
||||||
return mapType(conf, typ.lastSon)
|
return mapType(conf, typ.lastSon, kind)
|
||||||
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
|
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
|
||||||
tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned:
|
tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned:
|
||||||
result = mapType(conf, lastSon(typ))
|
result = mapType(conf, lastSon(typ), kind)
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
if firstOrd(conf, typ) < 0:
|
if firstOrd(conf, typ) < 0:
|
||||||
result = ctInt32
|
result = ctInt32
|
||||||
|
|
@ -175,7 +178,7 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
|
||||||
of 4: result = ctInt32
|
of 4: result = ctInt32
|
||||||
of 8: result = ctInt64
|
of 8: result = ctInt64
|
||||||
else: result = ctInt32
|
else: result = ctInt32
|
||||||
of tyRange: result = mapType(conf, typ[0])
|
of tyRange: result = mapType(conf, typ[0], kind)
|
||||||
of tyPtr, tyVar, tyLent, tyRef:
|
of tyPtr, tyVar, tyLent, tyRef:
|
||||||
var base = skipTypes(typ.lastSon, typedescInst)
|
var base = skipTypes(typ.lastSon, typedescInst)
|
||||||
case base.kind
|
case base.kind
|
||||||
|
|
@ -192,14 +195,14 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind =
|
||||||
of tyInt..tyUInt64:
|
of tyInt..tyUInt64:
|
||||||
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
|
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
if typ.n != nil: result = mapType(conf, lastSon typ)
|
if typ.n != nil: result = mapType(conf, lastSon typ, kind)
|
||||||
else: doAssert(false, "mapType")
|
else: doAssert(false, "mapType")
|
||||||
else: doAssert(false, "mapType")
|
else: doAssert(false, "mapType")
|
||||||
|
|
||||||
proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind =
|
proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind =
|
||||||
#if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
#if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
||||||
#else:
|
#else:
|
||||||
result = mapType(conf, typ)
|
result = mapType(conf, typ, skResult)
|
||||||
|
|
||||||
proc isImportedType(t: PType): bool =
|
proc isImportedType(t: PType): bool =
|
||||||
result = t.sym != nil and sfImportc in t.sym.flags
|
result = t.sym != nil and sfImportc in t.sym.flags
|
||||||
|
|
@ -209,7 +212,7 @@ proc isImportedCppType(t: PType): bool =
|
||||||
result = (t.sym != nil and sfInfixCall in t.sym.flags) or
|
result = (t.sym != nil and sfInfixCall in t.sym.flags) or
|
||||||
(x.sym != nil and sfInfixCall in x.sym.flags)
|
(x.sym != nil and sfInfixCall in x.sym.flags)
|
||||||
|
|
||||||
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope
|
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope
|
||||||
|
|
||||||
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
||||||
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
||||||
|
|
@ -222,7 +225,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
|
||||||
# is necessary for proper code generation of assignments.
|
# is necessary for proper code generation of assignments.
|
||||||
if rettype == nil: result = true
|
if rettype == nil: result = true
|
||||||
else:
|
else:
|
||||||
case mapType(conf, rettype)
|
case mapType(conf, rettype, skResult)
|
||||||
of ctArray:
|
of ctArray:
|
||||||
result = not (skipTypes(rettype, typedescInst).kind in
|
result = not (skipTypes(rettype, typedescInst).kind in
|
||||||
{tyVar, tyLent, tyRef, tyPtr})
|
{tyVar, tyLent, tyRef, tyPtr})
|
||||||
|
|
@ -346,8 +349,8 @@ proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope =
|
||||||
if result == nil: result = cacheGetType(m.typeCache, sig)
|
if result == nil: result = cacheGetType(m.typeCache, sig)
|
||||||
|
|
||||||
proc structOrUnion(t: PType): Rope =
|
proc structOrUnion(t: PType): Rope =
|
||||||
let cachedUnion {.global.} = rope("union")
|
let cachedUnion = rope("union")
|
||||||
let cachedStruct {.global.} = rope("struct")
|
let cachedStruct = rope("struct")
|
||||||
let t = t.skipTypes({tyAlias, tySink})
|
let t = t.skipTypes({tyAlias, tySink})
|
||||||
if tfUnion in t.flags: cachedUnion
|
if tfUnion in t.flags: cachedUnion
|
||||||
else: cachedStruct
|
else: cachedStruct
|
||||||
|
|
@ -379,7 +382,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
|
||||||
doAssert m.forwTypeCache[sig] == result
|
doAssert m.forwTypeCache[sig] == result
|
||||||
else: internalError(m.config, "getTypeForward(" & $typ.kind & ')')
|
else: internalError(m.config, "getTypeForward(" & $typ.kind & ')')
|
||||||
|
|
||||||
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
|
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): Rope =
|
||||||
## like getTypeDescAux but creates only a *weak* dependency. In other words
|
## like getTypeDescAux but creates only a *weak* dependency. In other words
|
||||||
## we know we only need a pointer to it so we only generate a struct forward
|
## we know we only need a pointer to it so we only generate a struct forward
|
||||||
## declaration:
|
## declaration:
|
||||||
|
|
@ -387,7 +390,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
|
||||||
case etB.kind
|
case etB.kind
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
if isImportedCppType(etB) and t.kind == tyGenericInst:
|
if isImportedCppType(etB) and t.kind == tyGenericInst:
|
||||||
result = getTypeDescAux(m, t, check)
|
result = getTypeDescAux(m, t, check, kind)
|
||||||
else:
|
else:
|
||||||
result = getTypeForward(m, t, hashType(t))
|
result = getTypeForward(m, t, hashType(t))
|
||||||
pushType(m, t)
|
pushType(m, t)
|
||||||
|
|
@ -417,18 +420,18 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
|
||||||
result = getTypeForward(m, t, sig) & seqStar(m)
|
result = getTypeForward(m, t, sig) & seqStar(m)
|
||||||
pushType(m, t)
|
pushType(m, t)
|
||||||
else:
|
else:
|
||||||
result = getTypeDescAux(m, t, check)
|
result = getTypeDescAux(m, t, check, kind)
|
||||||
|
|
||||||
proc getSeqPayloadType(m: BModule; t: PType): Rope =
|
proc getSeqPayloadType(m: BModule; t: PType): Rope =
|
||||||
var check = initIntSet()
|
var check = initIntSet()
|
||||||
result = getTypeDescWeak(m, t, check) & "_Content"
|
result = getTypeDescWeak(m, t, check, skParam) & "_Content"
|
||||||
#result = getTypeForward(m, t, hashType(t)) & "_Content"
|
#result = getTypeForward(m, t, hashType(t)) & "_Content"
|
||||||
|
|
||||||
proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
|
proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
|
||||||
let sig = hashType(t)
|
let sig = hashType(t)
|
||||||
let result = cacheGetType(m.typeCache, sig)
|
let result = cacheGetType(m.typeCache, sig)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
discard getTypeDescAux(m, t, check)
|
discard getTypeDescAux(m, t, check, skVar)
|
||||||
else:
|
else:
|
||||||
# little hack for now to prevent multiple definitions of the same
|
# little hack for now to prevent multiple definitions of the same
|
||||||
# Seq_Content:
|
# Seq_Content:
|
||||||
|
|
@ -437,7 +440,7 @@ $3ifndef $2_Content_PP
|
||||||
$3define $2_Content_PP
|
$3define $2_Content_PP
|
||||||
struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];};
|
struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];};
|
||||||
$3endif$N
|
$3endif$N
|
||||||
""", [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"])
|
""", [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, skVar), result, rope"#"])
|
||||||
|
|
||||||
proc paramStorageLoc(param: PSym): TStorageLoc =
|
proc paramStorageLoc(param: PSym): TStorageLoc =
|
||||||
if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin {
|
if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin {
|
||||||
|
|
@ -453,7 +456,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||||
if t[0] == nil or isInvalidReturnType(m.config, t[0]):
|
if t[0] == nil or isInvalidReturnType(m.config, t[0]):
|
||||||
rettype = ~"void"
|
rettype = ~"void"
|
||||||
else:
|
else:
|
||||||
rettype = getTypeDescAux(m, t[0], check)
|
rettype = getTypeDescAux(m, t[0], check, skResult)
|
||||||
for i in 1..<t.n.len:
|
for i in 1..<t.n.len:
|
||||||
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
|
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
|
||||||
var param = t.n[i].sym
|
var param = t.n[i].sym
|
||||||
|
|
@ -462,14 +465,14 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||||
fillLoc(param.loc, locParam, t.n[i], mangleParamName(m, param),
|
fillLoc(param.loc, locParam, t.n[i], mangleParamName(m, param),
|
||||||
param.paramStorageLoc)
|
param.paramStorageLoc)
|
||||||
if ccgIntroducedPtr(m.config, param, t[0]):
|
if ccgIntroducedPtr(m.config, param, t[0]):
|
||||||
params.add(getTypeDescWeak(m, param.typ, check))
|
params.add(getTypeDescWeak(m, param.typ, check, skParam))
|
||||||
params.add(~"*")
|
params.add(~"*")
|
||||||
incl(param.loc.flags, lfIndirect)
|
incl(param.loc.flags, lfIndirect)
|
||||||
param.loc.storage = OnUnknown
|
param.loc.storage = OnUnknown
|
||||||
elif weakDep:
|
elif weakDep:
|
||||||
params.add(getTypeDescWeak(m, param.typ, check))
|
params.add(getTypeDescWeak(m, param.typ, check, skParam))
|
||||||
else:
|
else:
|
||||||
params.add(getTypeDescAux(m, param.typ, check))
|
params.add(getTypeDescAux(m, param.typ, check, skParam))
|
||||||
params.add(~" ")
|
params.add(~" ")
|
||||||
params.add(param.loc.r)
|
params.add(param.loc.r)
|
||||||
# declare the len field for open arrays:
|
# declare the len field for open arrays:
|
||||||
|
|
@ -487,10 +490,10 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||||
var arr = t[0]
|
var arr = t[0]
|
||||||
if params != nil: params.add(", ")
|
if params != nil: params.add(", ")
|
||||||
if mapReturnType(m.config, t[0]) != ctArray:
|
if mapReturnType(m.config, t[0]) != ctArray:
|
||||||
params.add(getTypeDescWeak(m, arr, check))
|
params.add(getTypeDescWeak(m, arr, check, skResult))
|
||||||
params.add("*")
|
params.add("*")
|
||||||
else:
|
else:
|
||||||
params.add(getTypeDescAux(m, arr, check))
|
params.add(getTypeDescAux(m, arr, check, skResult))
|
||||||
params.addf(" Result", [])
|
params.addf(" Result", [])
|
||||||
if t.callConv == ccClosure and declareEnvironment:
|
if t.callConv == ccClosure and declareEnvironment:
|
||||||
if params != nil: params.add(", ")
|
if params != nil: params.add(", ")
|
||||||
|
|
@ -562,16 +565,16 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
|
let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
|
||||||
if fieldType.kind == tyUncheckedArray:
|
if fieldType.kind == tyUncheckedArray:
|
||||||
result.addf("$1 $2[SEQ_DECL_SIZE];$n",
|
result.addf("$1 $2[SEQ_DECL_SIZE];$n",
|
||||||
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
[getTypeDescAux(m, fieldType.elemType, check, skField), sname])
|
||||||
elif fieldType.kind == tySequence:
|
elif fieldType.kind == tySequence:
|
||||||
# we need to use a weak dependency here for trecursive_table.
|
# we need to use a weak dependency here for trecursive_table.
|
||||||
result.addf("$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
|
result.addf("$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check, skField), sname])
|
||||||
elif field.bitsize != 0:
|
elif field.bitsize != 0:
|
||||||
result.addf("$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)])
|
result.addf("$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, rope($field.bitsize)])
|
||||||
else:
|
else:
|
||||||
# don't use fieldType here because we need the
|
# don't use fieldType here because we need the
|
||||||
# tyGenericInst for C++ template support
|
# tyGenericInst for C++ template support
|
||||||
result.addf("$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
|
result.addf("$1 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname])
|
||||||
else: internalError(m.config, n.info, "genRecordFieldsAux()")
|
else: internalError(m.config, n.info, "genRecordFieldsAux()")
|
||||||
|
|
||||||
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
|
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||||
|
|
@ -610,7 +613,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
||||||
hasField = true
|
hasField = true
|
||||||
elif m.compileToCpp:
|
elif m.compileToCpp:
|
||||||
appcg(m, result, " : public $1 {$n",
|
appcg(m, result, " : public $1 {$n",
|
||||||
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)])
|
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)])
|
||||||
if typ.isException and m.config.exc == excCpp:
|
if typ.isException and m.config.exc == excCpp:
|
||||||
when false:
|
when false:
|
||||||
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
|
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
|
||||||
|
|
@ -623,7 +626,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
||||||
hasField = true
|
hasField = true
|
||||||
else:
|
else:
|
||||||
appcg(m, result, " {$n $1 Sup;$n",
|
appcg(m, result, " {$n $1 Sup;$n",
|
||||||
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)])
|
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)])
|
||||||
hasField = true
|
hasField = true
|
||||||
else:
|
else:
|
||||||
result.addf(" {$n", [name])
|
result.addf(" {$n", [name])
|
||||||
|
|
@ -643,7 +646,7 @@ proc getTupleDesc(m: BModule, typ: PType, name: Rope,
|
||||||
var desc: Rope = nil
|
var desc: Rope = nil
|
||||||
for i in 0..<typ.len:
|
for i in 0..<typ.len:
|
||||||
desc.addf("$1 Field$2;$n",
|
desc.addf("$1 Field$2;$n",
|
||||||
[getTypeDescAux(m, typ[i], check), rope(i)])
|
[getTypeDescAux(m, typ[i], check, skField), rope(i)])
|
||||||
if desc == nil: result.add("char dummy;\L")
|
if desc == nil: result.add("char dummy;\L")
|
||||||
else: result.add(desc)
|
else: result.add(desc)
|
||||||
result.add("};\L")
|
result.add("};\L")
|
||||||
|
|
@ -677,7 +680,20 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
|
||||||
result = if result.kind == tyGenericInst: result[1]
|
result = if result.kind == tyGenericInst: result[1]
|
||||||
else: result.elemType
|
else: result.elemType
|
||||||
|
|
||||||
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind): Rope =
|
||||||
|
let sig = hashType(t)
|
||||||
|
if kind == skParam:
|
||||||
|
result = getTypeDescWeak(m, t[0], check, kind) & "*"
|
||||||
|
else:
|
||||||
|
result = cacheGetType(m.typeCache, sig)
|
||||||
|
if result == nil:
|
||||||
|
result = getTypeName(m, t, sig)
|
||||||
|
m.typeCache[sig] = result
|
||||||
|
let elemType = getTypeDescWeak(m, t[0], check, kind)
|
||||||
|
m.s[cfsTypes].addf("typedef struct {$n$2* d;$nNI l;$n} $1;$n",
|
||||||
|
[result, elemType])
|
||||||
|
|
||||||
|
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope =
|
||||||
# returns only the type's name
|
# returns only the type's name
|
||||||
|
|
||||||
var t = origTyp.skipTypes(irrelevantForBackend-{tyOwned})
|
var t = origTyp.skipTypes(irrelevantForBackend-{tyOwned})
|
||||||
|
|
@ -696,7 +712,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
addAbiCheck(m, t, result)
|
addAbiCheck(m, t, result)
|
||||||
|
|
||||||
result = getTypePre(m, t, sig)
|
result = getTypePre(m, t, sig)
|
||||||
if result != nil:
|
if result != nil and t.kind != tyOpenArray:
|
||||||
excl(check, t.id)
|
excl(check, t.id)
|
||||||
return
|
return
|
||||||
case t.kind
|
case t.kind
|
||||||
|
|
@ -705,7 +721,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
compileToCpp(m): "&" else: "*"
|
compileToCpp(m): "&" else: "*"
|
||||||
var et = origTyp.skipTypes(abstractInst).lastSon
|
var et = origTyp.skipTypes(abstractInst).lastSon
|
||||||
var etB = et.skipTypes(abstractInst)
|
var etB = et.skipTypes(abstractInst)
|
||||||
if mapType(m.config, t) == ctPtrToArray:
|
if mapType(m.config, t, kind) == ctPtrToArray:
|
||||||
if etB.kind == tySet:
|
if etB.kind == tySet:
|
||||||
et = getSysType(m.g.graph, unknownLineInfo, tyUInt8)
|
et = getSysType(m.g.graph, unknownLineInfo, tyUInt8)
|
||||||
else:
|
else:
|
||||||
|
|
@ -715,7 +731,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
case etB.kind
|
case etB.kind
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
if isImportedCppType(etB) and et.kind == tyGenericInst:
|
if isImportedCppType(etB) and et.kind == tyGenericInst:
|
||||||
result = getTypeDescAux(m, et, check) & star
|
result = getTypeDescAux(m, et, check, kind) & star
|
||||||
else:
|
else:
|
||||||
# no restriction! We have a forward declaration for structs
|
# no restriction! We have a forward declaration for structs
|
||||||
let name = getTypeForward(m, et, hashType et)
|
let name = getTypeForward(m, et, hashType et)
|
||||||
|
|
@ -723,7 +739,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
m.typeCache[sig] = result
|
m.typeCache[sig] = result
|
||||||
of tySequence:
|
of tySequence:
|
||||||
if optSeqDestructors in m.config.globalOptions:
|
if optSeqDestructors in m.config.globalOptions:
|
||||||
result = getTypeDescWeak(m, et, check) & star
|
result = getTypeDescWeak(m, et, check, kind) & star
|
||||||
m.typeCache[sig] = result
|
m.typeCache[sig] = result
|
||||||
else:
|
else:
|
||||||
# no restriction! We have a forward declaration for structs
|
# no restriction! We have a forward declaration for structs
|
||||||
|
|
@ -733,11 +749,10 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
pushType(m, et)
|
pushType(m, et)
|
||||||
else:
|
else:
|
||||||
# else we have a strong dependency :-(
|
# else we have a strong dependency :-(
|
||||||
result = getTypeDescAux(m, et, check) & star
|
result = getTypeDescAux(m, et, check, kind) & star
|
||||||
m.typeCache[sig] = result
|
m.typeCache[sig] = result
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = getTypeDescWeak(m, t[0], check) & "*"
|
result = getOpenArrayDesc(m, t, check, kind)
|
||||||
m.typeCache[sig] = result
|
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
result = cacheGetType(m.typeCache, sig)
|
result = cacheGetType(m.typeCache, sig)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
|
@ -783,7 +798,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
[result, rettype, desc])
|
[result, rettype, desc])
|
||||||
of tySequence:
|
of tySequence:
|
||||||
if optSeqDestructors in m.config.globalOptions:
|
if optSeqDestructors in m.config.globalOptions:
|
||||||
result = getTypeDescWeak(m, t, check)
|
result = getTypeDescWeak(m, t, check, kind)
|
||||||
else:
|
else:
|
||||||
# we cannot use getTypeForward here because then t would be associated
|
# we cannot use getTypeForward here because then t would be associated
|
||||||
# with the name of the struct, not with the pointer to the struct:
|
# with the name of the struct, not with the pointer to the struct:
|
||||||
|
|
@ -804,11 +819,11 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
if m.compileToCpp:
|
if m.compileToCpp:
|
||||||
appcg(m, m.s[cfsSeqTypes],
|
appcg(m, m.s[cfsSeqTypes],
|
||||||
cppSeq & " $1 data[SEQ_DECL_SIZE];$n" &
|
cppSeq & " $1 data[SEQ_DECL_SIZE];$n" &
|
||||||
"};$n", [getTypeDescAux(m, t[0], check), result])
|
"};$n", [getTypeDescAux(m, t[0], check, kind), result])
|
||||||
else:
|
else:
|
||||||
appcg(m, m.s[cfsSeqTypes],
|
appcg(m, m.s[cfsSeqTypes],
|
||||||
cSeq & " $1 data[SEQ_DECL_SIZE];$n" &
|
cSeq & " $1 data[SEQ_DECL_SIZE];$n" &
|
||||||
"};$n", [getTypeDescAux(m, t[0], check), result])
|
"};$n", [getTypeDescAux(m, t[0], check, kind), result])
|
||||||
else:
|
else:
|
||||||
result = rope("TGenericSeq")
|
result = rope("TGenericSeq")
|
||||||
result.add(seqStar(m))
|
result.add(seqStar(m))
|
||||||
|
|
@ -816,7 +831,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
result = getTypeName(m, origTyp, sig)
|
result = getTypeName(m, origTyp, sig)
|
||||||
m.typeCache[sig] = result
|
m.typeCache[sig] = result
|
||||||
if not isImportedType(t):
|
if not isImportedType(t):
|
||||||
let foo = getTypeDescAux(m, t[0], check)
|
let foo = getTypeDescAux(m, t[0], check, kind)
|
||||||
m.s[cfsTypes].addf("typedef $1 $2[1];$n", [foo, result])
|
m.s[cfsTypes].addf("typedef $1 $2[1];$n", [foo, result])
|
||||||
of tyArray:
|
of tyArray:
|
||||||
var n: BiggestInt = toInt64(lengthOrd(m.config, t))
|
var n: BiggestInt = toInt64(lengthOrd(m.config, t))
|
||||||
|
|
@ -824,7 +839,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
result = getTypeName(m, origTyp, sig)
|
result = getTypeName(m, origTyp, sig)
|
||||||
m.typeCache[sig] = result
|
m.typeCache[sig] = result
|
||||||
if not isImportedType(t):
|
if not isImportedType(t):
|
||||||
let foo = getTypeDescAux(m, t[1], check)
|
let foo = getTypeDescAux(m, t[1], check, kind)
|
||||||
m.s[cfsTypes].addf("typedef $1 $2[$3];$n",
|
m.s[cfsTypes].addf("typedef $1 $2[$3];$n",
|
||||||
[foo, result, rope(n)])
|
[foo, result, rope(n)])
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
|
|
@ -840,7 +855,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
internalAssert m.config, ty.n != nil
|
internalAssert m.config, ty.n != nil
|
||||||
result.add ty.n.renderTree
|
result.add ty.n.renderTree
|
||||||
else:
|
else:
|
||||||
result.add getTypeDescAux(m, ty, check)
|
result.add getTypeDescAux(m, ty, check, kind)
|
||||||
|
|
||||||
while i < cppName.data.len:
|
while i < cppName.data.len:
|
||||||
if cppName.data[i] == '\'':
|
if cppName.data[i] == '\'':
|
||||||
|
|
@ -901,16 +916,16 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
[result, rope(getSize(m.config, t))])
|
[result, rope(getSize(m.config, t))])
|
||||||
of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyOwned,
|
of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyOwned,
|
||||||
tyUserTypeClass, tyUserTypeClassInst, tyInferred:
|
tyUserTypeClass, tyUserTypeClassInst, tyInferred:
|
||||||
result = getTypeDescAux(m, lastSon(t), check)
|
result = getTypeDescAux(m, lastSon(t), check, kind)
|
||||||
else:
|
else:
|
||||||
internalError(m.config, "getTypeDescAux(" & $t.kind & ')')
|
internalError(m.config, "getTypeDescAux(" & $t.kind & ')')
|
||||||
result = nil
|
result = nil
|
||||||
# fixes bug #145:
|
# fixes bug #145:
|
||||||
excl(check, t.id)
|
excl(check, t.id)
|
||||||
|
|
||||||
proc getTypeDesc(m: BModule, typ: PType): Rope =
|
proc getTypeDesc(m: BModule, typ: PType; kind = skParam): Rope =
|
||||||
var check = initIntSet()
|
var check = initIntSet()
|
||||||
result = getTypeDescAux(m, typ, check)
|
result = getTypeDescAux(m, typ, check, kind)
|
||||||
|
|
||||||
type
|
type
|
||||||
TClosureTypeKind = enum ## In C closures are mapped to 3 different things.
|
TClosureTypeKind = enum ## In C closures are mapped to 3 different things.
|
||||||
|
|
@ -942,7 +957,7 @@ proc finishTypeDescriptions(m: BModule) =
|
||||||
if optSeqDestructors in m.config.globalOptions and t.skipTypes(abstractInst).kind == tySequence:
|
if optSeqDestructors in m.config.globalOptions and t.skipTypes(abstractInst).kind == tySequence:
|
||||||
seqV2ContentType(m, t, check)
|
seqV2ContentType(m, t, check)
|
||||||
else:
|
else:
|
||||||
discard getTypeDescAux(m, t, check)
|
discard getTypeDescAux(m, t, check, skParam)
|
||||||
inc(i)
|
inc(i)
|
||||||
m.typeStack.setLen 0
|
m.typeStack.setLen 0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -310,14 +310,19 @@ include ccgtypes
|
||||||
|
|
||||||
# ------------------------------ Manager of temporaries ------------------
|
# ------------------------------ Manager of temporaries ------------------
|
||||||
|
|
||||||
|
template mapTypeChooser(n: PNode): TSymKind =
|
||||||
|
(if n.kind == nkSym: n.sym.kind else: skVar)
|
||||||
|
|
||||||
|
template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
|
||||||
|
|
||||||
proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
|
proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
|
||||||
result = a.r
|
result = a.r
|
||||||
if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray:
|
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
|
||||||
result = "(&" & result & ")"
|
result = "(&" & result & ")"
|
||||||
|
|
||||||
proc byRefLoc(p: BProc; a: TLoc): Rope =
|
proc byRefLoc(p: BProc; a: TLoc): Rope =
|
||||||
result = a.r
|
result = a.r
|
||||||
if lfIndirect notin a.flags and mapType(p.config, a.t) != ctArray and not
|
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not
|
||||||
p.module.compileToCpp:
|
p.module.compileToCpp:
|
||||||
result = "(&" & result & ")"
|
result = "(&" & result & ")"
|
||||||
|
|
||||||
|
|
@ -364,7 +369,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
|
||||||
rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp)
|
rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp)
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n",
|
"#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n",
|
||||||
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType)])
|
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, mapTypeChooser(a))])
|
||||||
else:
|
else:
|
||||||
rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp)
|
rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp)
|
||||||
genAssignment(p, a, tmp, {})
|
genAssignment(p, a, tmp, {})
|
||||||
|
|
@ -387,7 +392,7 @@ proc genRefAssign(p: BProc, dest, src: TLoc)
|
||||||
|
|
||||||
proc isComplexValueType(t: PType): bool {.inline.} =
|
proc isComplexValueType(t: PType): bool {.inline.} =
|
||||||
let t = t.skipTypes(abstractInst + tyUserTypeClasses)
|
let t = t.skipTypes(abstractInst + tyUserTypeClasses)
|
||||||
result = t.kind in {tyArray, tySet, tyTuple, tyObject} or
|
result = t.kind in {tyArray, tySet, tyTuple, tyObject, tyOpenArray} or
|
||||||
(t.kind == tyProc and t.callConv == ccClosure)
|
(t.kind == tyProc and t.callConv == ccClosure)
|
||||||
|
|
||||||
include ccgreset
|
include ccgreset
|
||||||
|
|
@ -420,7 +425,8 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||||
# array passed as argument decayed into pointer, bug #7332
|
# array passed as argument decayed into pointer, bug #7332
|
||||||
# so we use getTypeDesc here rather than rdLoc(loc)
|
# so we use getTypeDesc here rather than rdLoc(loc)
|
||||||
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
||||||
[addrLoc(p.config, loc), getTypeDesc(p.module, loc.t)])
|
[addrLoc(p.config, loc),
|
||||||
|
getTypeDesc(p.module, loc.t, mapTypeChooser(loc))])
|
||||||
# XXX: We can be extra clever here and call memset only
|
# XXX: We can be extra clever here and call memset only
|
||||||
# on the bytes following the m_type field?
|
# on the bytes following the m_type field?
|
||||||
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
|
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
|
||||||
|
|
@ -431,14 +437,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
|
||||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
|
||||||
elif not isComplexValueType(typ):
|
elif not isComplexValueType(typ):
|
||||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
|
||||||
getTypeDesc(p.module, typ)])
|
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||||
else:
|
else:
|
||||||
if not isTemp or containsGarbageCollectedRef(loc.t):
|
if not isTemp or containsGarbageCollectedRef(loc.t):
|
||||||
# don't use nimZeroMem for temporary values for performance if we can
|
# don't use nimZeroMem for temporary values for performance if we can
|
||||||
# avoid it:
|
# avoid it:
|
||||||
if not isImportedCppType(typ):
|
if not isImportedCppType(typ):
|
||||||
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
||||||
[addrLoc(p.config, loc), getTypeDesc(p.module, typ)])
|
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))])
|
||||||
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
|
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
|
||||||
|
|
||||||
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||||
|
|
@ -456,7 +462,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
result.r = "T" & rope(p.labels) & "_"
|
result.r = "T" & rope(p.labels) & "_"
|
||||||
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t), result.r])
|
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r])
|
||||||
result.k = locTemp
|
result.k = locTemp
|
||||||
result.lode = lodeTyp t
|
result.lode = lodeTyp t
|
||||||
result.storage = OnStack
|
result.storage = OnStack
|
||||||
|
|
@ -466,7 +472,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||||
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
|
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
result.r = "T" & rope(p.labels) & "_"
|
result.r = "T" & rope(p.labels) & "_"
|
||||||
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t), result.r, value])
|
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value])
|
||||||
result.k = locTemp
|
result.k = locTemp
|
||||||
result.lode = lodeTyp t
|
result.lode = lodeTyp t
|
||||||
result.storage = OnStack
|
result.storage = OnStack
|
||||||
|
|
@ -488,7 +494,7 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
|
||||||
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
||||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||||
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
|
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
|
||||||
result.add getTypeDesc(p.module, s.typ)
|
result.add getTypeDesc(p.module, s.typ, skVar)
|
||||||
if s.constraint.isNil:
|
if s.constraint.isNil:
|
||||||
if sfRegister in s.flags: result.add(" register")
|
if sfRegister in s.flags: result.add(" register")
|
||||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||||
|
|
@ -541,7 +547,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
|
||||||
internalError(p.config, n.info, ".threadvar variables cannot have a value")
|
internalError(p.config, n.info, ".threadvar variables cannot have a value")
|
||||||
else:
|
else:
|
||||||
var decl: Rope = nil
|
var decl: Rope = nil
|
||||||
var td = getTypeDesc(p.module, s.loc.t)
|
var td = getTypeDesc(p.module, s.loc.t, skVar)
|
||||||
if s.constraint.isNil:
|
if s.constraint.isNil:
|
||||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||||
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
|
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
|
||||||
|
|
@ -687,7 +693,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||||
initLoc(dest, locTemp, lib.path, OnStack)
|
initLoc(dest, locTemp, lib.path, OnStack)
|
||||||
dest.r = getTempName(m)
|
dest.r = getTempName(m)
|
||||||
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
|
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
|
||||||
[getTypeDesc(m, lib.path.typ), rdLoc(dest)])
|
[getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)])
|
||||||
expr(p, lib.path, dest)
|
expr(p, lib.path, dest)
|
||||||
|
|
||||||
m.s[cfsVars].add(p.s(cpsLocals))
|
m.s[cfsVars].add(p.s(cpsLocals))
|
||||||
|
|
@ -727,7 +733,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||||
params.add(rdLoc(a))
|
params.add(rdLoc(a))
|
||||||
params.add(", ")
|
params.add(", ")
|
||||||
let load = "\t$1 = ($2) ($3$4));$n" %
|
let load = "\t$1 = ($2) ($3$4));$n" %
|
||||||
[tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
|
[tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)]
|
||||||
var last = lastSon(n)
|
var last = lastSon(n)
|
||||||
if last.kind == nkHiddenStdConv: last = last[1]
|
if last.kind == nkHiddenStdConv: last = last[1]
|
||||||
internalAssert(m.config, last.kind == nkStrLit)
|
internalAssert(m.config, last.kind == nkStrLit)
|
||||||
|
|
@ -741,8 +747,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||||
else:
|
else:
|
||||||
appcg(m, m.s[cfsDynLibInit],
|
appcg(m, m.s[cfsDynLibInit],
|
||||||
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
|
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
|
||||||
[tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
|
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
|
||||||
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
|
||||||
|
|
||||||
proc varInDynamicLib(m: BModule, sym: PSym) =
|
proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||||
var lib = sym.annex
|
var lib = sym.annex
|
||||||
|
|
@ -754,9 +760,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||||
inc(m.labels, 2)
|
inc(m.labels, 2)
|
||||||
appcg(m, m.s[cfsDynLibInit],
|
appcg(m, m.s[cfsDynLibInit],
|
||||||
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
|
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
|
||||||
[tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
|
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
|
||||||
m.s[cfsVars].addf("$2* $1;$n",
|
m.s[cfsVars].addf("$2* $1;$n",
|
||||||
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
[sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
|
||||||
|
|
||||||
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
|
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
|
||||||
sym.loc.r = mangleDynLibProc(sym)
|
sym.loc.r = mangleDynLibProc(sym)
|
||||||
|
|
@ -1187,7 +1193,7 @@ proc requestConstImpl(p: BProc, sym: PSym) =
|
||||||
[getTypeDesc(q, sym.typ), actualConstName, genBracedInit(q.initProc, sym.ast, isConst = true)])
|
[getTypeDesc(q, sym.typ), actualConstName, genBracedInit(q.initProc, sym.ast, isConst = true)])
|
||||||
if m.hcrOn:
|
if m.hcrOn:
|
||||||
# generate the global pointer with the real name
|
# generate the global pointer with the real name
|
||||||
q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t), sym.loc.r])
|
q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r])
|
||||||
# register it (but ignore the boolean result of hcrRegisterGlobal)
|
# register it (but ignore the boolean result of hcrRegisterGlobal)
|
||||||
q.initProc.procSec(cpsLocals).addf(
|
q.initProc.procSec(cpsLocals).addf(
|
||||||
"\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n",
|
"\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n",
|
||||||
|
|
@ -1201,13 +1207,13 @@ proc requestConstImpl(p: BProc, sym: PSym) =
|
||||||
if q != m and not containsOrIncl(m.declaredThings, sym.id):
|
if q != m and not containsOrIncl(m.declaredThings, sym.id):
|
||||||
assert(sym.loc.r != nil)
|
assert(sym.loc.r != nil)
|
||||||
if m.hcrOn:
|
if m.hcrOn:
|
||||||
m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t), sym.loc.r]);
|
m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]);
|
||||||
m.initProc.procSec(cpsLocals).addf(
|
m.initProc.procSec(cpsLocals).addf(
|
||||||
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
|
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
|
||||||
getTypeDesc(m, sym.loc.t), getModuleDllPath(q, sym)])
|
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(q, sym)])
|
||||||
else:
|
else:
|
||||||
let headerDecl = "extern NIM_CONST $1 $2;$n" %
|
let headerDecl = "extern NIM_CONST $1 $2;$n" %
|
||||||
[getTypeDesc(m, sym.loc.t), sym.loc.r]
|
[getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]
|
||||||
m.s[cfsData].add(headerDecl)
|
m.s[cfsData].add(headerDecl)
|
||||||
if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
|
if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
|
||||||
p.module.g.generatedHeader.s[cfsData].add(headerDecl)
|
p.module.g.generatedHeader.s[cfsData].add(headerDecl)
|
||||||
|
|
@ -1247,7 +1253,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
|
||||||
if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0:
|
if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0:
|
||||||
m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)]
|
m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)]
|
||||||
m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ")
|
m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ")
|
||||||
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t))
|
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar))
|
||||||
if m.hcrOn: m.s[cfsVars].add("*")
|
if m.hcrOn: m.s[cfsVars].add("*")
|
||||||
if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*")
|
if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*")
|
||||||
if sfRegister in sym.flags: m.s[cfsVars].add(" register")
|
if sfRegister in sym.flags: m.s[cfsVars].add(" register")
|
||||||
|
|
@ -1255,7 +1261,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
|
||||||
m.s[cfsVars].addf(" $1;$n", [sym.loc.r])
|
m.s[cfsVars].addf(" $1;$n", [sym.loc.r])
|
||||||
if m.hcrOn: m.initProc.procSec(cpsLocals).addf(
|
if m.hcrOn: m.initProc.procSec(cpsLocals).addf(
|
||||||
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
|
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
|
||||||
getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)])
|
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)])
|
||||||
|
|
||||||
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
|
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
|
||||||
result.addf("#define NIM_INTBITS $1\L", [
|
result.addf("#define NIM_INTBITS $1\L", [
|
||||||
|
|
@ -1613,10 +1619,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
|
||||||
prc.typ.sym = nil
|
prc.typ.sym = nil
|
||||||
|
|
||||||
if not containsOrIncl(m.declaredThings, prc.id):
|
if not containsOrIncl(m.declaredThings, prc.id):
|
||||||
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t)])
|
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)])
|
||||||
|
|
||||||
result = "\t$1 = ($2) $3($4, $5);$n" %
|
result = "\t$1 = ($2) $3($4, $5);$n" %
|
||||||
[tmp, getTypeDesc(m, prc.typ), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
|
[tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
|
||||||
|
|
||||||
proc genInitCode(m: BModule) =
|
proc genInitCode(m: BModule) =
|
||||||
## this function is called in cgenWriteModules after all modules are closed,
|
## this function is called in cgenWriteModules after all modules are closed,
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,8 @@ type
|
||||||
## which itself requires `nimble install libffi`, see #10150
|
## which itself requires `nimble install libffi`, see #10150
|
||||||
## Note: this feature can't be localized with {.push.}
|
## Note: this feature can't be localized with {.push.}
|
||||||
vmopsDanger,
|
vmopsDanger,
|
||||||
strictFuncs
|
strictFuncs,
|
||||||
|
views
|
||||||
|
|
||||||
LegacyFeature* = enum
|
LegacyFeature* = enum
|
||||||
allowSemcheckedAstModification,
|
allowSemcheckedAstModification,
|
||||||
|
|
|
||||||
|
|
@ -1035,7 +1035,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
gsub(g, n, 1)
|
gsub(g, n, 1)
|
||||||
of nkHiddenStdConv, nkHiddenSubConv:
|
of nkHiddenStdConv, nkHiddenSubConv:
|
||||||
if n.len >= 2:
|
if n.len >= 2:
|
||||||
gsub(g, n[1])
|
when false:
|
||||||
|
# if {renderIds, renderIr} * g.flags != {}:
|
||||||
|
put(g, tkSymbol, "(conv)")
|
||||||
|
put(g, tkParLe, "(")
|
||||||
|
gsub(g, n[1])
|
||||||
|
put(g, tkParRi, ")")
|
||||||
|
else:
|
||||||
|
gsub(g, n[1])
|
||||||
else:
|
else:
|
||||||
put(g, tkSymbol, "(wrong conv)")
|
put(g, tkSymbol, "(wrong conv)")
|
||||||
of nkHiddenCallConv:
|
of nkHiddenCallConv:
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import
|
||||||
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
||||||
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
|
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
|
||||||
lowerings, plugins/active, rod, lineinfos, strtabs, int128,
|
lowerings, plugins/active, rod, lineinfos, strtabs, int128,
|
||||||
isolation_check
|
isolation_check, typeallowed
|
||||||
|
|
||||||
from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
|
from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
|
||||||
|
|
||||||
|
|
@ -228,9 +228,9 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym
|
allowed: TSymFlags): PSym
|
||||||
|
|
||||||
proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind;
|
proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind;
|
||||||
flags: TTypeAllowedFlags = {}) =
|
flags: TTypeAllowedFlags = {}) =
|
||||||
let t = typeAllowed(typ, kind, flags)
|
let t = typeAllowed(typ, kind, c, flags)
|
||||||
if t != nil:
|
if t != nil:
|
||||||
var err: string
|
var err: string
|
||||||
if t == typ:
|
if t == typ:
|
||||||
|
|
@ -240,10 +240,10 @@ proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKi
|
||||||
else:
|
else:
|
||||||
err = "invalid type: '$1' in this context: '$2' for $3" % [typeToString(t),
|
err = "invalid type: '$1' in this context: '$2' for $3" % [typeToString(t),
|
||||||
typeToString(typ), toHumanStr(kind)]
|
typeToString(typ), toHumanStr(kind)]
|
||||||
localError(conf, info, err)
|
localError(c.config, info, err)
|
||||||
|
|
||||||
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
||||||
typeAllowedCheck(c.config, typ.n.info, typ, skProc)
|
typeAllowedCheck(c, typ.n.info, typ, skProc)
|
||||||
|
|
||||||
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
|
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
|
||||||
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
|
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc isCastable(conf: ConfigRef; dst, src: PType): bool =
|
proc isCastable(c: PContext; dst, src: PType): bool =
|
||||||
## Checks whether the source type can be cast to the destination type.
|
## Checks whether the source type can be cast to the destination type.
|
||||||
## Casting is very unrestrictive; casts are allowed as long as
|
## Casting is very unrestrictive; casts are allowed as long as
|
||||||
## castDest.size >= src.size, and typeAllowed(dst, skParam)
|
## castDest.size >= src.size, and typeAllowed(dst, skParam)
|
||||||
|
|
@ -193,6 +193,7 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool =
|
||||||
return false
|
return false
|
||||||
if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass:
|
if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass:
|
||||||
return false
|
return false
|
||||||
|
let conf = c.config
|
||||||
if conf.selectedGC in {gcArc, gcOrc}:
|
if conf.selectedGC in {gcArc, gcOrc}:
|
||||||
let d = skipTypes(dst, abstractInst)
|
let d = skipTypes(dst, abstractInst)
|
||||||
let s = skipTypes(src, abstractInst)
|
let s = skipTypes(src, abstractInst)
|
||||||
|
|
@ -210,7 +211,7 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool =
|
||||||
result = false
|
result = false
|
||||||
elif srcSize < 0:
|
elif srcSize < 0:
|
||||||
result = false
|
result = false
|
||||||
elif typeAllowed(dst, skParam) != nil:
|
elif typeAllowed(dst, skParam, c) != nil:
|
||||||
result = false
|
result = false
|
||||||
elif dst.kind == tyProc and dst.callConv == ccClosure:
|
elif dst.kind == tyProc and dst.callConv == ccClosure:
|
||||||
result = src.kind == tyProc and src.callConv == ccClosure
|
result = src.kind == tyProc and src.callConv == ccClosure
|
||||||
|
|
@ -338,7 +339,7 @@ proc semCast(c: PContext, n: PNode): PNode =
|
||||||
let castedExpr = semExprWithType(c, n[1])
|
let castedExpr = semExprWithType(c, n[1])
|
||||||
if tfHasMeta in targetType.flags:
|
if tfHasMeta in targetType.flags:
|
||||||
localError(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
|
localError(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
|
||||||
if not isCastable(c.config, targetType, castedExpr.typ):
|
if not isCastable(c, targetType, castedExpr.typ):
|
||||||
let tar = $targetType
|
let tar = $targetType
|
||||||
let alt = typeToString(targetType, preferDesc)
|
let alt = typeToString(targetType, preferDesc)
|
||||||
let msg = if tar != alt: tar & "=" & alt else: tar
|
let msg = if tar != alt: tar & "=" & alt else: tar
|
||||||
|
|
@ -794,7 +795,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||||
if callee.kind notin {skProc, skFunc, skConverter, skConst} or callee.isGenericRoutine:
|
if callee.kind notin {skProc, skFunc, skConverter, skConst} or callee.isGenericRoutine:
|
||||||
return
|
return
|
||||||
|
|
||||||
if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return
|
if n.typ != nil and typeAllowed(n.typ, skConst, c) != nil: return
|
||||||
|
|
||||||
var call = newNodeIT(nkCall, n.info, n.typ)
|
var call = newNodeIT(nkCall, n.info, n.typ)
|
||||||
call.add(n[0])
|
call.add(n[0])
|
||||||
|
|
@ -1600,7 +1601,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
|
||||||
proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
|
proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
|
||||||
if le.kind == nkHiddenDeref:
|
if le.kind == nkHiddenDeref:
|
||||||
var x = le[0]
|
var x = le[0]
|
||||||
if x.typ.kind in {tyVar, tyLent} and x.kind == nkSym and x.sym.kind == skResult:
|
if (x.typ.kind in {tyVar, tyLent} or isViewType(x.typ)) and x.kind == nkSym and x.sym.kind == skResult:
|
||||||
n[0] = x # 'result[]' --> 'result'
|
n[0] = x # 'result[]' --> 'result'
|
||||||
n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent)
|
n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent)
|
||||||
x.typ.flags.incl tfVarIsPtr
|
x.typ.flags.incl tfVarIsPtr
|
||||||
|
|
@ -1732,7 +1733,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||||
if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}:
|
if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}:
|
||||||
internalAssert c.config, c.p.resultSym != nil
|
internalAssert c.config, c.p.resultSym != nil
|
||||||
# Make sure the type is valid for the result variable
|
# Make sure the type is valid for the result variable
|
||||||
typeAllowedCheck(c.config, n.info, rhsTyp, skResult)
|
typeAllowedCheck(c, n.info, rhsTyp, skResult)
|
||||||
lhs.typ = rhsTyp
|
lhs.typ = rhsTyp
|
||||||
c.p.resultSym.typ = rhsTyp
|
c.p.resultSym.typ = rhsTyp
|
||||||
c.p.owner.typ[0] = rhsTyp
|
c.p.owner.typ[0] = rhsTyp
|
||||||
|
|
@ -1825,7 +1826,9 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
|
||||||
tupleConstr[i] = takeImplicitAddr(c, tupleConstr[i], e.kind == tyLent)
|
tupleConstr[i] = takeImplicitAddr(c, tupleConstr[i], e.kind == tyLent)
|
||||||
else:
|
else:
|
||||||
localError(c.config, n[0].info, errXExpected, "tuple constructor")
|
localError(c.config, n[0].info, errXExpected, "tuple constructor")
|
||||||
else: discard
|
else:
|
||||||
|
if isViewType(t):
|
||||||
|
n[0] = takeImplicitAddr(c, n[0], false)
|
||||||
|
|
||||||
proc semYield(c: PContext, n: PNode): PNode =
|
proc semYield(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -1243,8 +1243,11 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
|
||||||
effects[ensuresEffects] = ensuresSpec
|
effects[ensuresEffects] = ensuresSpec
|
||||||
|
|
||||||
var mutationInfo = MutationInfo()
|
var mutationInfo = MutationInfo()
|
||||||
if strictFuncs in c.features and not t.hasSideEffect and t.hasDangerousAssign:
|
if {strictFuncs, views} * c.features != {}:
|
||||||
t.hasSideEffect = mutatesNonVarParameters(s, body, mutationInfo)
|
var partitions = computeGraphPartitions(s, body)
|
||||||
|
if not t.hasSideEffect and t.hasDangerousAssign:
|
||||||
|
t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo)
|
||||||
|
checkBorrowedLocations(partitions, g.config)
|
||||||
|
|
||||||
if sfThread in s.flags and t.gcUnsafe:
|
if sfThread in s.flags and t.gcUnsafe:
|
||||||
if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions:
|
if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions:
|
||||||
|
|
|
||||||
|
|
@ -534,7 +534,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
|
|
||||||
if c.matchedConcept != nil:
|
if c.matchedConcept != nil:
|
||||||
typFlags.incl taConcept
|
typFlags.incl taConcept
|
||||||
typeAllowedCheck(c.config, a.info, typ, symkind, typFlags)
|
typeAllowedCheck(c, a.info, typ, symkind, typFlags)
|
||||||
|
|
||||||
when false: liftTypeBoundOps(c, typ, a.info)
|
when false: liftTypeBoundOps(c, typ, a.info)
|
||||||
instAllTypeBoundOp(c, a.info)
|
instAllTypeBoundOp(c, a.info)
|
||||||
|
|
@ -667,7 +667,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
if def.kind != nkNilLit:
|
if def.kind != nkNilLit:
|
||||||
if c.matchedConcept != nil:
|
if c.matchedConcept != nil:
|
||||||
typFlags.incl taConcept
|
typFlags.incl taConcept
|
||||||
typeAllowedCheck(c.config, a.info, typ, skConst, typFlags)
|
typeAllowedCheck(c, a.info, typ, skConst, typFlags)
|
||||||
|
|
||||||
var b: PNode
|
var b: PNode
|
||||||
if a.kind == nkVarTuple:
|
if a.kind == nkVarTuple:
|
||||||
|
|
|
||||||
|
|
@ -494,6 +494,7 @@ proc transformConv(c: PTransf, n: PNode): PNode =
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = transform(c, n[1])
|
result = transform(c, n[1])
|
||||||
|
#result = transformSons(c, n)
|
||||||
result.typ = takeType(n.typ, n[1].typ)
|
result.typ = takeType(n.typ, n[1].typ)
|
||||||
#echo n.info, " came here and produced ", typeToString(result.typ),
|
#echo n.info, " came here and produced ", typeToString(result.typ),
|
||||||
# " from ", typeToString(n.typ), " and ", typeToString(n[1].typ)
|
# " from ", typeToString(n.typ), " and ", typeToString(n[1].typ)
|
||||||
|
|
@ -1107,6 +1108,9 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode =
|
||||||
else:
|
else:
|
||||||
prc.transformedBody = nil
|
prc.transformedBody = nil
|
||||||
|
|
||||||
|
#if prc.name.s == "main":
|
||||||
|
# echo "transformed into ", renderTree(result, {renderIds})
|
||||||
|
|
||||||
proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
|
proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
|
||||||
if nfTransf in n.flags:
|
if nfTransf in n.flags:
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ proc getRoot*(n: PNode): PSym =
|
||||||
if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar, skParam}:
|
if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar, skParam}:
|
||||||
result = n.sym
|
result = n.sym
|
||||||
of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr,
|
of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr,
|
||||||
nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr, nkHiddenAddr, nkAddr:
|
||||||
result = getRoot(n[0])
|
result = getRoot(n[0])
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
result = getRoot(n[1])
|
result = getRoot(n[1])
|
||||||
|
|
|
||||||
228
compiler/typeallowed.nim
Normal file
228
compiler/typeallowed.nim
Normal file
|
|
@ -0,0 +1,228 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2020 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## This module contains 'typeAllowed' and friends which check
|
||||||
|
## for invalid types like 'openArray[var int]'.
|
||||||
|
|
||||||
|
import
|
||||||
|
intsets, ast, renderer, options, semdata, types
|
||||||
|
|
||||||
|
type
|
||||||
|
TTypeAllowedFlag* = enum
|
||||||
|
taField,
|
||||||
|
taHeap,
|
||||||
|
taConcept,
|
||||||
|
taIsOpenArray,
|
||||||
|
taNoUntyped
|
||||||
|
taIsTemplateOrMacro
|
||||||
|
taProcContextIsNotMacro
|
||||||
|
|
||||||
|
TTypeAllowedFlags* = set[TTypeAllowedFlag]
|
||||||
|
|
||||||
|
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind;
|
||||||
|
c: PContext; flags: TTypeAllowedFlags = {}): PType
|
||||||
|
|
||||||
|
proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
|
||||||
|
c: PContext; flags: TTypeAllowedFlags = {}): PType =
|
||||||
|
if n != nil:
|
||||||
|
result = typeAllowedAux(marker, n.typ, kind, c, flags)
|
||||||
|
if result == nil:
|
||||||
|
case n.kind
|
||||||
|
of nkNone..nkNilLit:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
#if n.kind == nkRecCase and kind in {skProc, skFunc, skConst}:
|
||||||
|
# return n[0].typ
|
||||||
|
for i in 0..<n.len:
|
||||||
|
let it = n[i]
|
||||||
|
result = typeAllowedNode(marker, it, kind, c, flags)
|
||||||
|
if result != nil: break
|
||||||
|
|
||||||
|
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
|
c: PContext; flags: TTypeAllowedFlags = {}): PType =
|
||||||
|
assert(kind in {skVar, skLet, skConst, skProc, skFunc, skParam, skResult})
|
||||||
|
# if we have already checked the type, return true, because we stop the
|
||||||
|
# evaluation if something is wrong:
|
||||||
|
result = nil
|
||||||
|
if typ == nil: return nil
|
||||||
|
if containsOrIncl(marker, typ.id): return nil
|
||||||
|
var t = skipTypes(typ, abstractInst-{tyTypeDesc})
|
||||||
|
case t.kind
|
||||||
|
of tyVar, tyLent:
|
||||||
|
if kind in {skProc, skFunc, skConst} and (views notin c.features):
|
||||||
|
result = t
|
||||||
|
elif t.kind == tyLent and kind != skResult:
|
||||||
|
result = t
|
||||||
|
else:
|
||||||
|
var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc})
|
||||||
|
case t2.kind
|
||||||
|
of tyVar, tyLent:
|
||||||
|
if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
|
||||||
|
of tyOpenArray:
|
||||||
|
if (kind != skParam and views notin c.features) or taIsOpenArray in flags: result = t
|
||||||
|
else: result = typeAllowedAux(marker, t2[0], kind, c, flags+{taIsOpenArray})
|
||||||
|
of tyUncheckedArray:
|
||||||
|
if kind != skParam: result = t
|
||||||
|
else: result = typeAllowedAux(marker, t2[0], kind, c, flags)
|
||||||
|
else:
|
||||||
|
if kind notin {skParam, skResult}: result = t
|
||||||
|
else: result = typeAllowedAux(marker, t2, kind, c, flags)
|
||||||
|
of tyProc:
|
||||||
|
if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags:
|
||||||
|
result = t
|
||||||
|
else:
|
||||||
|
if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}:
|
||||||
|
# only closure iterators may be assigned to anything.
|
||||||
|
result = t
|
||||||
|
let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags
|
||||||
|
for i in 1..<t.len:
|
||||||
|
if result != nil: break
|
||||||
|
result = typeAllowedAux(marker, t[i], skParam, c, f-{taIsOpenArray})
|
||||||
|
if result.isNil and t[0] != nil:
|
||||||
|
result = typeAllowedAux(marker, t[0], skResult, c, flags)
|
||||||
|
of tyTypeDesc:
|
||||||
|
if kind in {skVar, skLet, skConst} and taProcContextIsNotMacro in flags:
|
||||||
|
result = t
|
||||||
|
else:
|
||||||
|
# XXX: This is still a horrible idea...
|
||||||
|
result = nil
|
||||||
|
of tyUntyped, tyTyped:
|
||||||
|
if kind notin {skParam, skResult} or taNoUntyped in flags: result = t
|
||||||
|
of tyStatic:
|
||||||
|
if kind notin {skParam}: result = t
|
||||||
|
of tyVoid:
|
||||||
|
if taField notin flags: result = t
|
||||||
|
of tyTypeClasses:
|
||||||
|
if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
|
||||||
|
discard
|
||||||
|
elif t.isResolvedUserTypeClass:
|
||||||
|
result = typeAllowedAux(marker, t.lastSon, kind, c, flags)
|
||||||
|
elif kind notin {skParam, skResult}:
|
||||||
|
result = t
|
||||||
|
of tyGenericBody, tyGenericParam, tyGenericInvocation,
|
||||||
|
tyNone, tyForward, tyFromExpr:
|
||||||
|
result = t
|
||||||
|
of tyNil:
|
||||||
|
if kind != skConst and kind != skParam: result = t
|
||||||
|
of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer:
|
||||||
|
result = nil
|
||||||
|
of tyOrdinal:
|
||||||
|
if kind != skParam: result = t
|
||||||
|
of tyGenericInst, tyDistinct, tyAlias, tyInferred:
|
||||||
|
result = typeAllowedAux(marker, lastSon(t), kind, c, flags)
|
||||||
|
of tyRange:
|
||||||
|
if skipTypes(t[0], abstractInst-{tyTypeDesc}).kind notin
|
||||||
|
{tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64}: result = t
|
||||||
|
of tyOpenArray:
|
||||||
|
# you cannot nest openArrays/sinks/etc.
|
||||||
|
if (kind != skParam and views notin c.features) or taIsOpenArray in flags:
|
||||||
|
result = t
|
||||||
|
else:
|
||||||
|
result = typeAllowedAux(marker, t[0], kind, c, flags+{taIsOpenArray})
|
||||||
|
of tyVarargs, tySink:
|
||||||
|
# you cannot nest openArrays/sinks/etc.
|
||||||
|
if kind != skParam or taIsOpenArray in flags:
|
||||||
|
result = t
|
||||||
|
else:
|
||||||
|
result = typeAllowedAux(marker, t[0], kind, c, flags+{taIsOpenArray})
|
||||||
|
of tyUncheckedArray:
|
||||||
|
if kind != skParam and taHeap notin flags:
|
||||||
|
result = t
|
||||||
|
else:
|
||||||
|
result = typeAllowedAux(marker, lastSon(t), kind, c, flags-{taHeap})
|
||||||
|
of tySequence:
|
||||||
|
if t[0].kind != tyEmpty:
|
||||||
|
result = typeAllowedAux(marker, t[0], kind, c, flags+{taHeap})
|
||||||
|
elif kind in {skVar, skLet}:
|
||||||
|
result = t[0]
|
||||||
|
of tyArray:
|
||||||
|
if t[1].kind == tyTypeDesc:
|
||||||
|
result = t[1]
|
||||||
|
elif t[1].kind != tyEmpty:
|
||||||
|
result = typeAllowedAux(marker, t[1], kind, c, flags)
|
||||||
|
elif kind in {skVar, skLet}:
|
||||||
|
result = t[1]
|
||||||
|
of tyRef:
|
||||||
|
if kind == skConst: result = t
|
||||||
|
else: result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap})
|
||||||
|
of tyPtr:
|
||||||
|
result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap})
|
||||||
|
of tySet:
|
||||||
|
for i in 0..<t.len:
|
||||||
|
result = typeAllowedAux(marker, t[i], kind, c, flags)
|
||||||
|
if result != nil: break
|
||||||
|
of tyObject, tyTuple:
|
||||||
|
if kind in {skProc, skFunc, skConst} and
|
||||||
|
t.kind == tyObject and t[0] != nil:
|
||||||
|
result = t
|
||||||
|
else:
|
||||||
|
let flags = flags+{taField}
|
||||||
|
for i in 0..<t.len:
|
||||||
|
result = typeAllowedAux(marker, t[i], kind, c, flags)
|
||||||
|
if result != nil: break
|
||||||
|
if result.isNil and t.n != nil:
|
||||||
|
result = typeAllowedNode(marker, t.n, kind, c, flags)
|
||||||
|
of tyEmpty:
|
||||||
|
if kind in {skVar, skLet}: result = t
|
||||||
|
of tyProxy:
|
||||||
|
# for now same as error node; we say it's a valid type as it should
|
||||||
|
# prevent cascading errors:
|
||||||
|
result = nil
|
||||||
|
of tyOwned:
|
||||||
|
if t.len == 1 and t[0].skipTypes(abstractInst).kind in {tyRef, tyPtr, tyProc}:
|
||||||
|
result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap})
|
||||||
|
else:
|
||||||
|
result = t
|
||||||
|
of tyOptDeprecated: doAssert false
|
||||||
|
|
||||||
|
proc typeAllowed*(t: PType, kind: TSymKind; c: PContext; flags: TTypeAllowedFlags = {}): PType =
|
||||||
|
# returns 'nil' on success and otherwise the part of the type that is
|
||||||
|
# wrong!
|
||||||
|
var marker = initIntSet()
|
||||||
|
result = typeAllowedAux(marker, t, kind, c, flags)
|
||||||
|
|
||||||
|
proc isViewTypeAux(marker: var IntSet, t: PType): bool
|
||||||
|
|
||||||
|
proc isViewTypeNode(marker: var IntSet, n: PNode): bool =
|
||||||
|
case n.kind
|
||||||
|
of nkSym:
|
||||||
|
result = isViewTypeAux(marker, n.typ)
|
||||||
|
of nkOfBranch:
|
||||||
|
result = isViewTypeNode(marker, n.lastSon)
|
||||||
|
else:
|
||||||
|
for child in n:
|
||||||
|
result = isViewTypeNode(marker, child)
|
||||||
|
if result: break
|
||||||
|
|
||||||
|
proc isViewTypeAux(marker: var IntSet, t: PType): bool =
|
||||||
|
if containsOrIncl(marker, t.id): return false
|
||||||
|
case t.kind
|
||||||
|
of tyVar, tyLent, tyVarargs, tyOpenArray:
|
||||||
|
result = true
|
||||||
|
of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned,
|
||||||
|
tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic, tyFromExpr:
|
||||||
|
result = isViewTypeAux(marker, lastSon(t))
|
||||||
|
of tyTuple:
|
||||||
|
for i in 0..<t.len:
|
||||||
|
result = isViewTypeAux(marker, t[i])
|
||||||
|
if result: break
|
||||||
|
of tyObject:
|
||||||
|
result = false
|
||||||
|
if t.n != nil:
|
||||||
|
result = isViewTypeNode(marker, t.n)
|
||||||
|
if t[0] != nil:
|
||||||
|
result = result or isViewTypeAux(marker, t[0])
|
||||||
|
else:
|
||||||
|
# it doesn't matter what these types contain, 'ptr openArray' is not a
|
||||||
|
# view type!
|
||||||
|
result = false
|
||||||
|
|
||||||
|
proc isViewType*(t: PType): bool =
|
||||||
|
var marker = initIntSet()
|
||||||
|
result = isViewTypeAux(marker, t)
|
||||||
|
|
@ -329,7 +329,7 @@ proc containsTyRef*(typ: PType): bool =
|
||||||
result = searchTypeFor(typ, isTyRef)
|
result = searchTypeFor(typ, isTyRef)
|
||||||
|
|
||||||
proc isHiddenPointer(t: PType): bool =
|
proc isHiddenPointer(t: PType): bool =
|
||||||
result = t.kind in {tyString, tySequence}
|
result = t.kind in {tyString, tySequence, tyOpenArray, tyVarargs}
|
||||||
|
|
||||||
proc containsHiddenPointer*(typ: PType): bool =
|
proc containsHiddenPointer*(typ: PType): bool =
|
||||||
# returns true if typ contains a string, table or sequence (all the things
|
# returns true if typ contains a string, table or sequence (all the things
|
||||||
|
|
@ -1240,37 +1240,6 @@ proc commonSuperclass*(a, b: PType): PType =
|
||||||
return t
|
return t
|
||||||
y = y[0]
|
y = y[0]
|
||||||
|
|
||||||
type
|
|
||||||
TTypeAllowedFlag* = enum
|
|
||||||
taField,
|
|
||||||
taHeap,
|
|
||||||
taConcept,
|
|
||||||
taIsOpenArray,
|
|
||||||
taNoUntyped
|
|
||||||
taIsTemplateOrMacro
|
|
||||||
taProcContextIsNotMacro
|
|
||||||
|
|
||||||
TTypeAllowedFlags* = set[TTypeAllowedFlag]
|
|
||||||
|
|
||||||
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
|
||||||
flags: TTypeAllowedFlags = {}): PType
|
|
||||||
|
|
||||||
proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
|
|
||||||
flags: TTypeAllowedFlags = {}): PType =
|
|
||||||
if n != nil:
|
|
||||||
result = typeAllowedAux(marker, n.typ, kind, flags)
|
|
||||||
if result == nil:
|
|
||||||
case n.kind
|
|
||||||
of nkNone..nkNilLit:
|
|
||||||
discard
|
|
||||||
else:
|
|
||||||
#if n.kind == nkRecCase and kind in {skProc, skFunc, skConst}:
|
|
||||||
# return n[0].typ
|
|
||||||
for i in 0..<n.len:
|
|
||||||
let it = n[i]
|
|
||||||
result = typeAllowedNode(marker, it, kind, flags)
|
|
||||||
if result != nil: break
|
|
||||||
|
|
||||||
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
||||||
last: TTypeKind): bool =
|
last: TTypeKind): bool =
|
||||||
var a = a
|
var a = a
|
||||||
|
|
@ -1280,143 +1249,6 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
||||||
a = a[i]
|
a = a[i]
|
||||||
result = a.kind == last
|
result = a.kind == last
|
||||||
|
|
||||||
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
|
||||||
flags: TTypeAllowedFlags = {}): PType =
|
|
||||||
assert(kind in {skVar, skLet, skConst, skProc, skFunc, skParam, skResult})
|
|
||||||
# if we have already checked the type, return true, because we stop the
|
|
||||||
# evaluation if something is wrong:
|
|
||||||
result = nil
|
|
||||||
if typ == nil: return nil
|
|
||||||
if containsOrIncl(marker, typ.id): return nil
|
|
||||||
var t = skipTypes(typ, abstractInst-{tyTypeDesc})
|
|
||||||
case t.kind
|
|
||||||
of tyVar, tyLent:
|
|
||||||
if kind in {skProc, skFunc, skConst}:
|
|
||||||
result = t
|
|
||||||
elif t.kind == tyLent and kind != skResult:
|
|
||||||
result = t
|
|
||||||
else:
|
|
||||||
var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc})
|
|
||||||
case t2.kind
|
|
||||||
of tyVar, tyLent:
|
|
||||||
if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
|
|
||||||
of tyOpenArray:
|
|
||||||
if kind != skParam or taIsOpenArray in flags: result = t
|
|
||||||
else: result = typeAllowedAux(marker, t2[0], kind, flags+{taIsOpenArray})
|
|
||||||
of tyUncheckedArray:
|
|
||||||
if kind != skParam: result = t
|
|
||||||
else: result = typeAllowedAux(marker, t2[0], kind, flags)
|
|
||||||
else:
|
|
||||||
if kind notin {skParam, skResult}: result = t
|
|
||||||
else: result = typeAllowedAux(marker, t2, kind, flags)
|
|
||||||
of tyProc:
|
|
||||||
if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags:
|
|
||||||
result = t
|
|
||||||
else:
|
|
||||||
if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}:
|
|
||||||
# only closure iterators may be assigned to anything.
|
|
||||||
result = t
|
|
||||||
let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags
|
|
||||||
for i in 1..<t.len:
|
|
||||||
if result != nil: break
|
|
||||||
result = typeAllowedAux(marker, t[i], skParam, f-{taIsOpenArray})
|
|
||||||
if result.isNil and t[0] != nil:
|
|
||||||
result = typeAllowedAux(marker, t[0], skResult, flags)
|
|
||||||
of tyTypeDesc:
|
|
||||||
if kind in {skVar, skLet, skConst} and taProcContextIsNotMacro in flags:
|
|
||||||
result = t
|
|
||||||
else:
|
|
||||||
# XXX: This is still a horrible idea...
|
|
||||||
result = nil
|
|
||||||
of tyUntyped, tyTyped:
|
|
||||||
if kind notin {skParam, skResult} or taNoUntyped in flags: result = t
|
|
||||||
of tyStatic:
|
|
||||||
if kind notin {skParam}: result = t
|
|
||||||
of tyVoid:
|
|
||||||
if taField notin flags: result = t
|
|
||||||
of tyTypeClasses:
|
|
||||||
if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
|
|
||||||
discard
|
|
||||||
elif t.isResolvedUserTypeClass:
|
|
||||||
result = typeAllowedAux(marker, t.lastSon, kind, flags)
|
|
||||||
elif kind notin {skParam, skResult}:
|
|
||||||
result = t
|
|
||||||
of tyGenericBody, tyGenericParam, tyGenericInvocation,
|
|
||||||
tyNone, tyForward, tyFromExpr:
|
|
||||||
result = t
|
|
||||||
of tyNil:
|
|
||||||
if kind != skConst and kind != skParam: result = t
|
|
||||||
of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer:
|
|
||||||
result = nil
|
|
||||||
of tyOrdinal:
|
|
||||||
if kind != skParam: result = t
|
|
||||||
of tyGenericInst, tyDistinct, tyAlias, tyInferred:
|
|
||||||
result = typeAllowedAux(marker, lastSon(t), kind, flags)
|
|
||||||
of tyRange:
|
|
||||||
if skipTypes(t[0], abstractInst-{tyTypeDesc}).kind notin
|
|
||||||
{tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64}: result = t
|
|
||||||
of tyOpenArray, tyVarargs, tySink:
|
|
||||||
# you cannot nest openArrays/sinks/etc.
|
|
||||||
if kind != skParam or taIsOpenArray in flags:
|
|
||||||
result = t
|
|
||||||
else:
|
|
||||||
result = typeAllowedAux(marker, t[0], kind, flags+{taIsOpenArray})
|
|
||||||
of tyUncheckedArray:
|
|
||||||
if kind != skParam and taHeap notin flags:
|
|
||||||
result = t
|
|
||||||
else:
|
|
||||||
result = typeAllowedAux(marker, lastSon(t), kind, flags-{taHeap})
|
|
||||||
of tySequence:
|
|
||||||
if t[0].kind != tyEmpty:
|
|
||||||
result = typeAllowedAux(marker, t[0], kind, flags+{taHeap})
|
|
||||||
elif kind in {skVar, skLet}:
|
|
||||||
result = t[0]
|
|
||||||
of tyArray:
|
|
||||||
if t[1].kind == tyTypeDesc:
|
|
||||||
result = t[1]
|
|
||||||
elif t[1].kind != tyEmpty:
|
|
||||||
result = typeAllowedAux(marker, t[1], kind, flags)
|
|
||||||
elif kind in {skVar, skLet}:
|
|
||||||
result = t[1]
|
|
||||||
of tyRef:
|
|
||||||
if kind == skConst: result = t
|
|
||||||
else: result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap})
|
|
||||||
of tyPtr:
|
|
||||||
result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap})
|
|
||||||
of tySet:
|
|
||||||
for i in 0..<t.len:
|
|
||||||
result = typeAllowedAux(marker, t[i], kind, flags)
|
|
||||||
if result != nil: break
|
|
||||||
of tyObject, tyTuple:
|
|
||||||
if kind in {skProc, skFunc, skConst} and
|
|
||||||
t.kind == tyObject and t[0] != nil:
|
|
||||||
result = t
|
|
||||||
else:
|
|
||||||
let flags = flags+{taField}
|
|
||||||
for i in 0..<t.len:
|
|
||||||
result = typeAllowedAux(marker, t[i], kind, flags)
|
|
||||||
if result != nil: break
|
|
||||||
if result.isNil and t.n != nil:
|
|
||||||
result = typeAllowedNode(marker, t.n, kind, flags)
|
|
||||||
of tyEmpty:
|
|
||||||
if kind in {skVar, skLet}: result = t
|
|
||||||
of tyProxy:
|
|
||||||
# for now same as error node; we say it's a valid type as it should
|
|
||||||
# prevent cascading errors:
|
|
||||||
result = nil
|
|
||||||
of tyOwned:
|
|
||||||
if t.len == 1 and t[0].skipTypes(abstractInst).kind in {tyRef, tyPtr, tyProc}:
|
|
||||||
result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap})
|
|
||||||
else:
|
|
||||||
result = t
|
|
||||||
of tyOptDeprecated: doAssert false
|
|
||||||
|
|
||||||
proc typeAllowed*(t: PType, kind: TSymKind; flags: TTypeAllowedFlags = {}): PType =
|
|
||||||
# returns 'nil' on success and otherwise the part of the type that is
|
|
||||||
# wrong!
|
|
||||||
var marker = initIntSet()
|
|
||||||
result = typeAllowedAux(marker, t, kind, flags)
|
|
||||||
|
|
||||||
include sizealignoffsetimpl
|
include sizealignoffsetimpl
|
||||||
|
|
||||||
proc computeSize*(conf: ConfigRef; typ: PType): BiggestInt =
|
proc computeSize*(conf: ConfigRef; typ: PType): BiggestInt =
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import ast, types, lineinfos, options, msgs, renderer
|
||||||
from trees import getMagic, whichPragma
|
from trees import getMagic, whichPragma
|
||||||
from wordrecg import wNoSideEffect
|
from wordrecg import wNoSideEffect
|
||||||
from isolation_check import canAlias
|
from isolation_check import canAlias
|
||||||
|
from typeallowed import isViewType
|
||||||
|
|
||||||
type
|
type
|
||||||
SubgraphFlag = enum
|
SubgraphFlag = enum
|
||||||
|
|
@ -48,7 +49,7 @@ type
|
||||||
maxMutation, minConnection: int
|
maxMutation, minConnection: int
|
||||||
mutations: seq[int]
|
mutations: seq[int]
|
||||||
|
|
||||||
Partitions = object
|
Partitions* = object
|
||||||
abstractTime: int
|
abstractTime: int
|
||||||
s: seq[VarIndex]
|
s: seq[VarIndex]
|
||||||
graphs: seq[MutationInfo]
|
graphs: seq[MutationInfo]
|
||||||
|
|
@ -74,7 +75,7 @@ proc `$`*(config: ConfigRef; g: MutationInfo): string =
|
||||||
result.add config $ g.connectedVia
|
result.add config $ g.connectedVia
|
||||||
result.add " is the statement that connected the mutation to the parameter"
|
result.add " is the statement that connected the mutation to the parameter"
|
||||||
|
|
||||||
proc hasSideEffect(c: var Partitions; info: var MutationInfo): bool =
|
proc hasSideEffect*(c: var Partitions; info: var MutationInfo): bool =
|
||||||
for g in mitems c.graphs:
|
for g in mitems c.graphs:
|
||||||
if g.flags == {isMutated, connectsConstParam} and mutationAfterConnection(g):
|
if g.flags == {isMutated, connectsConstParam} and mutationAfterConnection(g):
|
||||||
info = g
|
info = g
|
||||||
|
|
@ -505,17 +506,16 @@ proc traverse(c: var Partitions; n: PNode) =
|
||||||
else:
|
else:
|
||||||
for child in n: traverse(c, child)
|
for child in n: traverse(c, child)
|
||||||
|
|
||||||
proc mutatesNonVarParameters*(s: PSym; n: PNode; info: var MutationInfo): bool =
|
proc computeGraphPartitions*(s: PSym; n: PNode; cursorInference = false): Partitions =
|
||||||
var par = Partitions(performCursorInference: false)
|
result = Partitions(performCursorInference: cursorInference)
|
||||||
if s.kind != skMacro:
|
if s.kind notin {skModule, skMacro}:
|
||||||
let params = s.typ.n
|
let params = s.typ.n
|
||||||
for i in 1..<params.len:
|
for i in 1..<params.len:
|
||||||
registerVariable(par, params[i])
|
registerVariable(result, params[i])
|
||||||
if resultPos < s.ast.safeLen:
|
if resultPos < s.ast.safeLen:
|
||||||
registerVariable(par, s.ast[resultPos])
|
registerVariable(result, s.ast[resultPos])
|
||||||
|
|
||||||
traverse(par, n)
|
traverse(result, n)
|
||||||
result = hasSideEffect(par, info)
|
|
||||||
|
|
||||||
proc dangerousMutation(g: MutationInfo; v: VarIndex): bool =
|
proc dangerousMutation(g: MutationInfo; v: VarIndex): bool =
|
||||||
if isMutated in g.flags:
|
if isMutated in g.flags:
|
||||||
|
|
@ -524,16 +524,16 @@ proc dangerousMutation(g: MutationInfo; v: VarIndex): bool =
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) =
|
proc checkBorrowedLocations*(par: var Partitions; config: ConfigRef) =
|
||||||
var par = Partitions(performCursorInference: true)
|
for i in 0 ..< par.s.len:
|
||||||
if s.kind notin {skMacro, skModule}:
|
let s = par.s[i].sym
|
||||||
let params = s.typ.n
|
if s.kind != skParam and isViewType(s.typ):
|
||||||
for i in 1..<params.len:
|
let rid = root(par, i)
|
||||||
registerVariable(par, params[i])
|
if par.s[rid].kind == isRootOf and dangerousMutation(par.graphs[par.s[rid].graphIndex], par.s[i]):
|
||||||
if resultPos < s.ast.safeLen:
|
localError(config, s.info, config $ par.graphs[par.s[rid].graphIndex])
|
||||||
registerVariable(par, s.ast[resultPos])
|
|
||||||
|
|
||||||
traverse(par, n)
|
proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) =
|
||||||
|
var par = computeGraphPartitions(s, n, true)
|
||||||
for i in 0 ..< par.s.len:
|
for i in 0 ..< par.s.len:
|
||||||
let v = addr(par.s[i])
|
let v = addr(par.s[i])
|
||||||
if v.flags == {} and v.sym.kind notin {skParam, skResult} and
|
if v.flags == {} and v.sym.kind notin {skParam, skResult} and
|
||||||
|
|
|
||||||
|
|
@ -1836,3 +1836,55 @@ For example:
|
||||||
|
|
||||||
|
|
||||||
The algorithm behind this analysis is currently not documented.
|
The algorithm behind this analysis is currently not documented.
|
||||||
|
|
||||||
|
|
||||||
|
View types
|
||||||
|
==========
|
||||||
|
|
||||||
|
A view type is a type that contains one of the following types:
|
||||||
|
|
||||||
|
- ``var T`` (mutable view into ``T``)
|
||||||
|
- ``lent T`` (immutable view into ``T``)
|
||||||
|
- ``openArray[T]`` (pair of (pointer to array of ``T``, size))
|
||||||
|
|
||||||
|
Since version 1.4 Nim allows view types to be used as local variables.
|
||||||
|
This feature needs to be enabled via ``{.experimental: "views".}``.
|
||||||
|
|
||||||
|
A local variable of a view type *borrows* from the locations and
|
||||||
|
it is statically enforced that the view does not outlive the location
|
||||||
|
it was borrowed from.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
{.experimental: "views".}
|
||||||
|
|
||||||
|
proc take(a: openArray[int]) =
|
||||||
|
echo a.len
|
||||||
|
|
||||||
|
proc main(s: seq[int]) =
|
||||||
|
var x: openArray[int] = s # 'x' is a view into 's'
|
||||||
|
# it is checked that 'x' does not outlive 's' and
|
||||||
|
# that 's' is not mutated.
|
||||||
|
for i in 0 .. high(x):
|
||||||
|
echo x[i]
|
||||||
|
take(x)
|
||||||
|
|
||||||
|
take(x.toOpenArray(0, 1)) # slicing remains possible
|
||||||
|
let y = x # create a view from a view
|
||||||
|
take y
|
||||||
|
# it is checked that 'y' does not outlive 'x' and
|
||||||
|
# that 'x' is not mutated as long as 'y' lives.
|
||||||
|
|
||||||
|
|
||||||
|
main(@[11, 22, 33])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
If a view type is used as a return type, the location must borrow from the
|
||||||
|
first parameter that is passed to the proc.
|
||||||
|
See https://nim-lang.org/docs/manual.html#procedures-var-return-type for
|
||||||
|
details about how this is done for ``var T``.
|
||||||
|
|
||||||
|
The algorithm behind this analysis is currently not documented.
|
||||||
|
|
|
||||||
27
tests/ccgbugs/tviews1.nim
Normal file
27
tests/ccgbugs/tviews1.nim
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
discard """
|
||||||
|
output: '''11
|
||||||
|
22
|
||||||
|
33
|
||||||
|
3
|
||||||
|
2
|
||||||
|
3'''
|
||||||
|
targets: "c cpp"
|
||||||
|
"""
|
||||||
|
|
||||||
|
{.experimental: "views".}
|
||||||
|
|
||||||
|
proc take(a: openArray[int]) =
|
||||||
|
echo a.len
|
||||||
|
|
||||||
|
proc main(s: seq[int]) =
|
||||||
|
var x: openArray[int] = s
|
||||||
|
for i in 0 .. high(x):
|
||||||
|
echo x[i]
|
||||||
|
take(x)
|
||||||
|
|
||||||
|
take(x.toOpenArray(0, 1))
|
||||||
|
let y = x
|
||||||
|
take y
|
||||||
|
|
||||||
|
|
||||||
|
main(@[11, 22, 33])
|
||||||
Loading…
Add table
Add a link
Reference in a new issue