definite assignment analysis for let (#21024)
* draft for let daa * patch * fixes bugs * errors for global let variable reassignments * checkpoint * out param accepts let * add more tests * add documentation * merge tests
This commit is contained in:
parent
6d8cf25bd7
commit
b2c7019006
9 changed files with 144 additions and 30 deletions
|
|
@ -736,7 +736,7 @@ proc hasUnresolvedArgs(c: PContext, n: PNode): bool =
|
|||
if hasUnresolvedArgs(c, n[i]): return true
|
||||
return false
|
||||
|
||||
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
|
||||
proc newHiddenAddrTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
|
||||
if n.kind == nkHiddenDeref and not (c.config.backend == backendCpp or
|
||||
sfCompileToCpp in c.module.flags):
|
||||
checkSonsLen(n, 1, c.config)
|
||||
|
|
@ -745,13 +745,17 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
|
|||
result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
|
||||
result.add n
|
||||
let aa = isAssignable(c, n)
|
||||
let sym = getRoot(n)
|
||||
if aa notin {arLValue, arLocalLValue}:
|
||||
if aa == arDiscriminant and c.inUncheckedAssignSection > 0:
|
||||
discard "allow access within a cast(unsafeAssign) section"
|
||||
elif strictDefs in c.features and aa == arAddressableConst and
|
||||
sym != nil and sym.kind == skLet and isOutParam:
|
||||
discard "allow let varaibles to be passed to out parameters"
|
||||
else:
|
||||
localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n))
|
||||
|
||||
proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
|
||||
proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
|
||||
result = n
|
||||
case n.kind
|
||||
of nkSym:
|
||||
|
|
@ -759,7 +763,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
|
|||
if n.sym.typ != nil and
|
||||
skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
|
||||
incl(n.sym.flags, sfAddrTaken)
|
||||
result = newHiddenAddrTaken(c, n)
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
of nkDotExpr:
|
||||
checkSonsLen(n, 2, c.config)
|
||||
if n[1].kind != nkSym:
|
||||
|
|
@ -767,14 +771,14 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
|
|||
return
|
||||
if skipTypes(n[1].sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
|
||||
incl(n[1].sym.flags, sfAddrTaken)
|
||||
result = newHiddenAddrTaken(c, n)
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
of nkBracketExpr:
|
||||
checkMinSonsLen(n, 1, c.config)
|
||||
if skipTypes(n[0].typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
|
||||
if n[0].kind == nkSym: incl(n[0].sym.flags, sfAddrTaken)
|
||||
result = newHiddenAddrTaken(c, n)
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
else:
|
||||
result = newHiddenAddrTaken(c, n)
|
||||
result = newHiddenAddrTaken(c, n, isOutParam)
|
||||
|
||||
proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
checkMinSonsLen(n, 1, c.config)
|
||||
|
|
@ -820,7 +824,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
|||
if i < t.len and
|
||||
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
|
||||
if n[i].kind != nkHiddenAddr:
|
||||
n[i] = analyseIfAddressTaken(c, n[i])
|
||||
n[i] = analyseIfAddressTaken(c, n[i], isOutParam(skipTypes(t[i], abstractInst-{tyTypeDesc})))
|
||||
|
||||
include semmagic
|
||||
|
||||
|
|
@ -1812,11 +1816,16 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
|||
# a = b # both are vars, means: a[] = b[]
|
||||
# a = b # b no 'var T' means: a = addr(b)
|
||||
var le = a.typ
|
||||
let assignable = isAssignable(c, a)
|
||||
let root = getRoot(a)
|
||||
let useStrictDefLet = root != nil and root.kind == skLet and
|
||||
assignable == arAddressableConst and
|
||||
strictDefs in c.features and isLocalSym(root)
|
||||
if le == nil:
|
||||
localError(c.config, a.info, "expression has no type")
|
||||
elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and
|
||||
isAssignable(c, a) in {arNone, arLentValue, arAddressableConst}) or (
|
||||
skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs} and views notin c.features):
|
||||
assignable in {arNone, arLentValue, arAddressableConst} and not useStrictDefLet
|
||||
) or (skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs} and views notin c.features):
|
||||
# Direct assignment to a discriminant is allowed!
|
||||
localError(c.config, a.info, errXCannotBeAssignedTo %
|
||||
renderTree(a, {renderNoComments}))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue