'result/return' triggers a void context
This commit is contained in:
parent
23bd3ccd8b
commit
6c0425d574
2 changed files with 60 additions and 23 deletions
|
|
@ -1799,8 +1799,18 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
|
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
|
||||||
nkCallStrLit:
|
nkCallStrLit:
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
if n.sons[0].kind == nkSym and n.sons[0].sym.magic != mNone:
|
let op = n.sons[0]
|
||||||
genMagicExpr(p, n, d, n.sons[0].sym.magic)
|
if n.typ.isNil:
|
||||||
|
# discard the value:
|
||||||
|
var a: TLoc
|
||||||
|
if op.kind == nkSym and op.sym.magic != mNone:
|
||||||
|
genMagicExpr(p, n, a, op.sym.magic)
|
||||||
|
else:
|
||||||
|
genCall(p, n, a)
|
||||||
|
else:
|
||||||
|
# load it into 'd':
|
||||||
|
if op.kind == nkSym and op.sym.magic != mNone:
|
||||||
|
genMagicExpr(p, n, d, op.sym.magic)
|
||||||
else:
|
else:
|
||||||
genCall(p, n, d)
|
genCall(p, n, d)
|
||||||
of nkCurly:
|
of nkCurly:
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
## this module does the semantic checking of statements
|
## this module does the semantic checking of statements
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
|
var EnforceVoidContext = PType(kind: tyStmt)
|
||||||
|
|
||||||
proc semCommand(c: PContext, n: PNode): PNode =
|
proc semCommand(c: PContext, n: PNode): PNode =
|
||||||
result = semExprNoType(c, n)
|
result = semExprNoType(c, n)
|
||||||
|
|
||||||
|
|
@ -56,6 +58,8 @@ proc semWhile(c: PContext, n: PNode): PNode =
|
||||||
n.sons[1] = semStmt(c, n.sons[1])
|
n.sons[1] = semStmt(c, n.sons[1])
|
||||||
dec(c.p.nestedLoopCounter)
|
dec(c.p.nestedLoopCounter)
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
|
if n.sons[1].typ == EnforceVoidContext:
|
||||||
|
result.typ = EnforceVoidContext
|
||||||
|
|
||||||
proc toCover(t: PType): biggestInt =
|
proc toCover(t: PType): biggestInt =
|
||||||
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
|
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
|
||||||
|
|
@ -121,19 +125,21 @@ proc fixNilType(n: PNode) =
|
||||||
if n.kind != nkNilLit and n.typ != nil:
|
if n.kind != nkNilLit and n.typ != nil:
|
||||||
localError(n.info, errDiscardValue)
|
localError(n.info, errDiscardValue)
|
||||||
elif n.kind in {nkStmtList, nkStmtListExpr}:
|
elif n.kind in {nkStmtList, nkStmtListExpr}:
|
||||||
|
n.kind = nkStmtList
|
||||||
for it in n: fixNilType(it)
|
for it in n: fixNilType(it)
|
||||||
n.typ = nil
|
n.typ = nil
|
||||||
|
|
||||||
var EnforceVoidContext = PType(kind: tyStmt)
|
|
||||||
|
|
||||||
proc discardCheck(result: PNode) =
|
proc discardCheck(result: PNode) =
|
||||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
|
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
|
||||||
if result.kind == nkNilLit:
|
if result.kind == nkNilLit:
|
||||||
# XXX too much work and fixing would break bootstrapping:
|
|
||||||
#Message(n.info, warnNilStatement)
|
|
||||||
result.typ = nil
|
result.typ = nil
|
||||||
elif not ImplicitlyDiscardable(result) and result.typ.kind != tyError and
|
elif ImplicitlyDiscardable(result):
|
||||||
gCmd != cmdInteractive:
|
var n = result
|
||||||
|
result.typ = nil
|
||||||
|
while n.kind == nkStmtListExpr:
|
||||||
|
n = n.lastSon
|
||||||
|
n.typ = nil
|
||||||
|
elif result.typ.kind != tyError and gCmd != cmdInteractive:
|
||||||
if result.typ.kind == tyNil:
|
if result.typ.kind == tyNil:
|
||||||
fixNilType(result)
|
fixNilType(result)
|
||||||
else:
|
else:
|
||||||
|
|
@ -157,15 +163,16 @@ proc semIf(c: PContext, n: PNode): PNode =
|
||||||
it.sons[0] = semExprBranchScope(c, it.sons[0])
|
it.sons[0] = semExprBranchScope(c, it.sons[0])
|
||||||
typ = commonType(typ, it.sons[0].typ)
|
typ = commonType(typ, it.sons[0].typ)
|
||||||
else: illFormedAst(it)
|
else: illFormedAst(it)
|
||||||
if isEmptyType(typ) or not hasElse:
|
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
|
||||||
for it in n: discardCheck(it.lastSon)
|
for it in n: discardCheck(it.lastSon)
|
||||||
result.kind = nkIfStmt
|
result.kind = nkIfStmt
|
||||||
|
# propagate any enforced VoidContext:
|
||||||
|
if typ == EnforceVoidContext: result.typ = EnforceVoidContext
|
||||||
else:
|
else:
|
||||||
for it in n:
|
for it in n:
|
||||||
let j = it.len-1
|
let j = it.len-1
|
||||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||||
result.kind = nkIfExpr
|
result.kind = nkIfExpr
|
||||||
# propagate any enforced VoidContext:
|
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
proc semCase(c: PContext, n: PNode): PNode =
|
proc semCase(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -211,17 +218,22 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
hasElse = true
|
hasElse = true
|
||||||
else:
|
else:
|
||||||
illFormedAst(x)
|
illFormedAst(x)
|
||||||
if chckCovered and (covered != toCover(n.sons[0].typ)):
|
if chckCovered:
|
||||||
|
if covered == toCover(n.sons[0].typ):
|
||||||
|
hasElse = true
|
||||||
|
else:
|
||||||
localError(n.info, errNotAllCasesCovered)
|
localError(n.info, errNotAllCasesCovered)
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
if isEmptyType(typ) or not hasElse:
|
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
|
||||||
for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
|
for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
|
||||||
|
# propagate any enforced VoidContext:
|
||||||
|
if typ == EnforceVoidContext:
|
||||||
|
result.typ = EnforceVoidContext
|
||||||
else:
|
else:
|
||||||
for i in 1..n.len-1:
|
for i in 1..n.len-1:
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
let j = it.len-1
|
let j = it.len-1
|
||||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||||
# propagate any enforced VoidContext:
|
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
proc semTry(c: PContext, n: PNode): PNode =
|
proc semTry(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -257,16 +269,17 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
|
a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
|
||||||
typ = commonType(typ, a.sons[length-1].typ)
|
typ = commonType(typ, a.sons[length-1].typ)
|
||||||
dec c.p.inTryStmt
|
dec c.p.inTryStmt
|
||||||
if isEmptyType(typ):
|
if isEmptyType(typ) or typ.kind == tyNil:
|
||||||
discardCheck(n.sons[0])
|
discardCheck(n.sons[0])
|
||||||
for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
|
for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
|
||||||
|
if typ == EnforceVoidContext:
|
||||||
|
result.typ = EnforceVoidContext
|
||||||
else:
|
else:
|
||||||
n.sons[0] = fitNode(c, typ, n.sons[0])
|
n.sons[0] = fitNode(c, typ, n.sons[0])
|
||||||
for i in 1..n.len-1:
|
for i in 1..n.len-1:
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
let j = it.len-1
|
let j = it.len-1
|
||||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||||
# propagate any enforced VoidContext:
|
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
|
proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
|
||||||
|
|
@ -627,7 +640,8 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
result = semForVars(c, n)
|
result = semForVars(c, n)
|
||||||
# propagate any enforced VoidContext:
|
# propagate any enforced VoidContext:
|
||||||
result.typ = n.sons[length-1].typ
|
if n.sons[length-1].typ == EnforceVoidContext:
|
||||||
|
result.typ = EnforceVoidContext
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
|
|
||||||
proc semRaise(c: PContext, n: PNode): PNode =
|
proc semRaise(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -1076,11 +1090,24 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||||
result = newNodeI(nkDiscardStmt, n.info, 1)
|
result = newNodeI(nkDiscardStmt, n.info, 1)
|
||||||
result.sons[0] = emptyNode
|
result.sons[0] = emptyNode
|
||||||
|
|
||||||
|
proc usesResult(n: PNode): bool =
|
||||||
|
# nkStmtList(expr) properly propagates the void context,
|
||||||
|
# so we don't need to process that all over again:
|
||||||
|
if n.kind notin {nkStmtList, nkStmtListExpr}:
|
||||||
|
if isAtom(n):
|
||||||
|
result = n.kind == nkSym and n.sym.kind == skResult
|
||||||
|
elif n.kind == nkReturnStmt:
|
||||||
|
result = true
|
||||||
|
else:
|
||||||
|
for c in n:
|
||||||
|
if usesResult(c): return true
|
||||||
|
|
||||||
proc semStmtList(c: PContext, n: PNode): PNode =
|
proc semStmtList(c: PContext, n: PNode): PNode =
|
||||||
# these must be last statements in a block:
|
# these must be last statements in a block:
|
||||||
const
|
const
|
||||||
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
|
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
|
||||||
result = n
|
result = n
|
||||||
|
result.kind = nkStmtList
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
var voidContext = false
|
var voidContext = false
|
||||||
var last = length-1
|
var last = length-1
|
||||||
|
|
@ -1113,7 +1140,7 @@ proc semStmtList(c: PContext, n: PNode): PNode =
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
n.sons[i] = semExpr(c, n.sons[i])
|
n.sons[i] = semExpr(c, n.sons[i])
|
||||||
if n.sons[i].typ == EnforceVoidContext:
|
if n.sons[i].typ == EnforceVoidContext or usesResult(n.sons[i]):
|
||||||
voidContext = true
|
voidContext = true
|
||||||
n.typ = EnforceVoidContext
|
n.typ = EnforceVoidContext
|
||||||
elif i != last or voidContext:
|
elif i != last or voidContext:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue