Perform nil checks during object construction and within compiles()
Close https://github.com/nim-lang/Nim/issues/6494
This commit is contained in:
parent
7b7e42be54
commit
4f3d309fb0
4 changed files with 10 additions and 7 deletions
|
|
@ -584,7 +584,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||||
result = buildEchoStmt(c, result)
|
result = buildEchoStmt(c, result)
|
||||||
if c.config.cmd == cmdIdeTools:
|
if c.config.cmd == cmdIdeTools:
|
||||||
appendToModule(c.module, result)
|
appendToModule(c.module, result)
|
||||||
trackTopLevelStmt(c, c.module, result)
|
trackStmt(c, c.module, result, isTopLevel = true)
|
||||||
|
|
||||||
proc recoverContext(c: PContext) =
|
proc recoverContext(c: PContext) =
|
||||||
# clean up in case of a semantic error: We clean up the stacks, etc. This is
|
# clean up in case of a semantic error: We clean up the stacks, etc. This is
|
||||||
|
|
|
||||||
|
|
@ -2082,7 +2082,10 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
var err: string
|
var err: string
|
||||||
try:
|
try:
|
||||||
result = semExpr(c, n, flags)
|
result = semExpr(c, n, flags)
|
||||||
if c.config.errorCounter != oldErrorCount: result = nil
|
if result != nil:
|
||||||
|
trackStmt(c, c.module, result, isTopLevel = false)
|
||||||
|
if c.config.errorCounter != oldErrorCount:
|
||||||
|
result = nil
|
||||||
except ERecoverableError:
|
except ERecoverableError:
|
||||||
discard
|
discard
|
||||||
# undo symbol table changes (as far as it's possible):
|
# undo symbol table changes (as far as it's possible):
|
||||||
|
|
|
||||||
|
|
@ -996,6 +996,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
createTypeBoundOps(tracked, x[1].typ, n.info)
|
createTypeBoundOps(tracked, x[1].typ, n.info)
|
||||||
|
|
||||||
if x.kind == nkExprColonExpr:
|
if x.kind == nkExprColonExpr:
|
||||||
|
notNilCheck(tracked, x[1], x[0].sym.typ)
|
||||||
checkForSink(tracked.config, tracked.owner, x[1])
|
checkForSink(tracked.config, tracked.owner, x[1])
|
||||||
else:
|
else:
|
||||||
checkForSink(tracked.config, tracked.owner, x)
|
checkForSink(tracked.config, tracked.owner, x)
|
||||||
|
|
@ -1260,7 +1261,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
|
||||||
dataflowAnalysis(s, body)
|
dataflowAnalysis(s, body)
|
||||||
when false: trackWrites(s, body)
|
when false: trackWrites(s, body)
|
||||||
|
|
||||||
proc trackTopLevelStmt*(c: PContext; module: PSym; n: PNode) =
|
proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) =
|
||||||
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
|
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
|
||||||
nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
|
nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
|
||||||
return
|
return
|
||||||
|
|
@ -1268,5 +1269,5 @@ proc trackTopLevelStmt*(c: PContext; module: PSym; n: PNode) =
|
||||||
var effects = newNode(nkEffectList, n.info)
|
var effects = newNode(nkEffectList, n.info)
|
||||||
var t: TEffects
|
var t: TEffects
|
||||||
initEffects(g, effects, module, t, c)
|
initEffects(g, effects, module, t, c)
|
||||||
t.isTopLevel = true
|
t.isTopLevel = isTopLevel
|
||||||
track(t, n)
|
track(t, n)
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ type
|
||||||
|
|
||||||
var x = D
|
var x = D
|
||||||
var nilRef: TRefObj
|
var nilRef: TRefObj
|
||||||
var notNilRef = TRefObj(x: 20)
|
let notNilRef = TRefObjNotNil(x: 20)
|
||||||
|
|
||||||
proc makeHasNotNils: ref THasNotNils =
|
proc makeHasNotNils: ref THasNotNils =
|
||||||
(ref THasNotNils)(a: TRefObj(x: 10),
|
(ref THasNotNils)(a: TRefObj(x: 10),
|
||||||
|
|
@ -102,8 +102,7 @@ reject TObj(a: 10, f: "") # conflicting fields
|
||||||
accept TObj(choice: E, e1: TRefObj(x: 10), e2: 10)
|
accept TObj(choice: E, e1: TRefObj(x: 10), e2: 10)
|
||||||
|
|
||||||
accept THasNotNils(a: notNilRef, b: notNilRef, c: nilRef)
|
accept THasNotNils(a: notNilRef, b: notNilRef, c: nilRef)
|
||||||
# XXX: the "not nil" logic in the compiler is not strong enough to catch this one yet:
|
reject THasNotNils(a: notNilRef, b: nilRef, c: nilRef) # `b` shouldn't be nil
|
||||||
# reject THasNotNils(a: notNilRef, b: nilRef, c: nilRef)
|
|
||||||
reject THasNotNils(b: notNilRef, c: notNilRef) # there is a missing not nil field
|
reject THasNotNils(b: notNilRef, c: notNilRef) # there is a missing not nil field
|
||||||
reject THasNotNils() # again, missing fields
|
reject THasNotNils() # again, missing fields
|
||||||
accept THasNotNils(a: notNilRef, b: notNilRef) # it's OK to omit a non-mandatory field
|
accept THasNotNils(a: notNilRef, b: notNilRef) # it's OK to omit a non-mandatory field
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue