Plug another hole: default(T) forbidden for objects requiring initialization
This commit is contained in:
parent
05a0ec4adb
commit
8ae48292ff
5 changed files with 31 additions and 19 deletions
|
|
@ -46,6 +46,7 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
||||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
proc activate(c: PContext, n: PNode)
|
proc activate(c: PContext, n: PNode)
|
||||||
|
proc checkDefaultConstruction(c: PContext, typ: PType, info: TLineInfo)
|
||||||
proc semQuoteAst(c: PContext, n: PNode): PNode
|
proc semQuoteAst(c: PContext, n: PNode): PNode
|
||||||
proc finishMethod(c: PContext, s: PSym)
|
proc finishMethod(c: PContext, s: PSym)
|
||||||
proc evalAtCompileTime(c: PContext, n: PNode): PNode
|
proc evalAtCompileTime(c: PContext, n: PNode): PNode
|
||||||
|
|
@ -58,24 +59,6 @@ proc isArrayConstr(n: PNode): bool {.inline.} =
|
||||||
result = n.kind == nkBracket and
|
result = n.kind == nkBracket and
|
||||||
n.typ.skipTypes(abstractInst).kind == tyArray
|
n.typ.skipTypes(abstractInst).kind == tyArray
|
||||||
|
|
||||||
type
|
|
||||||
ObjConstrContext = object
|
|
||||||
typ: PType # The constructed type
|
|
||||||
initExpr: PNode # The init expression (nkObjConstr)
|
|
||||||
requiresFullInit: bool # A `requiresInit` derived type will
|
|
||||||
# set this to true while visiting
|
|
||||||
# parent types.
|
|
||||||
|
|
||||||
InitStatus = enum # This indicates the result of object construction
|
|
||||||
initUnknown
|
|
||||||
initFull # All of the fields have been initialized
|
|
||||||
initPartial # Some of the fields have been initialized
|
|
||||||
initNone # None of the fields have been initialized
|
|
||||||
initConflict # Fields from different branches have been initialized
|
|
||||||
|
|
||||||
proc semConstructType(c: PContext, initExpr: PNode,
|
|
||||||
t: PType, flags: TExprFlags): InitStatus
|
|
||||||
|
|
||||||
template semIdeForTemplateOrGenericCheck(conf, n, requiresCheck) =
|
template semIdeForTemplateOrGenericCheck(conf, n, requiresCheck) =
|
||||||
# we check quickly if the node is where the cursor is
|
# we check quickly if the node is where the cursor is
|
||||||
when defined(nimsuggest):
|
when defined(nimsuggest):
|
||||||
|
|
|
||||||
|
|
@ -2264,6 +2264,12 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
of mSizeOf:
|
of mSizeOf:
|
||||||
markUsed(c, n.info, s)
|
markUsed(c, n.info, s)
|
||||||
result = semSizeof(c, setMs(n, s))
|
result = semSizeof(c, setMs(n, s))
|
||||||
|
of mDefault:
|
||||||
|
result = semDirectOp(c, n, flags)
|
||||||
|
c.config.internalAssert result[1].typ.kind == tyTypeDesc
|
||||||
|
let typ = result[1].typ.base
|
||||||
|
if typ.kind in {tyObject, tyTuple}:
|
||||||
|
checkDefaultConstruction(c, typ, n.info)
|
||||||
else:
|
else:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,21 @@
|
||||||
|
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
|
type
|
||||||
|
ObjConstrContext = object
|
||||||
|
typ: PType # The constructed type
|
||||||
|
initExpr: PNode # The init expression (nkObjConstr)
|
||||||
|
requiresFullInit: bool # A `requiresInit` derived type will
|
||||||
|
# set this to true while visiting
|
||||||
|
# parent types.
|
||||||
|
|
||||||
|
InitStatus = enum # This indicates the result of object construction
|
||||||
|
initUnknown
|
||||||
|
initFull # All of the fields have been initialized
|
||||||
|
initPartial # Some of the fields have been initialized
|
||||||
|
initNone # None of the fields have been initialized
|
||||||
|
initConflict # Fields from different branches have been initialized
|
||||||
|
|
||||||
proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) =
|
proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) =
|
||||||
case newStatus
|
case newStatus
|
||||||
of initConflict:
|
of initConflict:
|
||||||
|
|
@ -336,6 +351,9 @@ proc semConstructType(c: PContext, initExpr: PNode,
|
||||||
constrCtx.requiresFullInit = constrCtx.requiresFullInit or
|
constrCtx.requiresFullInit = constrCtx.requiresFullInit or
|
||||||
tfRequiresInit in t.flags
|
tfRequiresInit in t.flags
|
||||||
|
|
||||||
|
proc checkDefaultConstruction(c: PContext, typ: PType, info: TLineInfo) =
|
||||||
|
discard semConstructType(c, newNodeI(nkObjConstr, info), typ, {})
|
||||||
|
|
||||||
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
var t = semTypeNode(c, n[0], nil)
|
var t = semTypeNode(c, n[0], nil)
|
||||||
result = newNodeIT(nkObjConstr, n.info, t)
|
result = newNodeIT(nkObjConstr, n.info, t)
|
||||||
|
|
|
||||||
|
|
@ -616,7 +616,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
b[j] = newSymNode(v)
|
b[j] = newSymNode(v)
|
||||||
if def.kind == nkEmpty:
|
if def.kind == nkEmpty:
|
||||||
if v.typ.kind in {tyObject, tyTuple}:
|
if v.typ.kind in {tyObject, tyTuple}:
|
||||||
discard semConstructType(c, newNodeI(nkObjConstr, v.info), v.typ, {})
|
checkDefaultConstruction(c, v.typ, v.info)
|
||||||
else:
|
else:
|
||||||
checkNilable(c, v)
|
checkNilable(c, v)
|
||||||
if sfCompileTime in v.flags:
|
if sfCompileTime in v.flags:
|
||||||
|
|
|
||||||
|
|
@ -125,12 +125,15 @@ accept PartialRequiresInit(a: 10, b: "x")
|
||||||
accept PartialRequiresInit(a: 20)
|
accept PartialRequiresInit(a: 20)
|
||||||
reject PartialRequiresInit(b: "x")
|
reject PartialRequiresInit(b: "x")
|
||||||
reject PartialRequiresInit()
|
reject PartialRequiresInit()
|
||||||
|
reject default(PartialRequiresInit)
|
||||||
reject:
|
reject:
|
||||||
var obj: PartialRequiresInit
|
var obj: PartialRequiresInit
|
||||||
|
|
||||||
accept FullRequiresInit(a: 10, b: 20)
|
accept FullRequiresInit(a: 10, b: 20)
|
||||||
reject FullRequiresInit(a: 10)
|
reject FullRequiresInit(a: 10)
|
||||||
reject FullRequiresInit(b: 20)
|
reject FullRequiresInit(b: 20)
|
||||||
|
reject FullRequiresInit()
|
||||||
|
reject default(FullRequiresInit)
|
||||||
reject:
|
reject:
|
||||||
var obj: FullRequiresInit
|
var obj: FullRequiresInit
|
||||||
|
|
||||||
|
|
@ -140,11 +143,13 @@ reject FullRequiresInitWithParent(a: notNilRef, b: nil, c: nil, e: 10, d: 20) #
|
||||||
reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, e: 10, d: 20) # c should not be missing
|
reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, e: 10, d: 20) # c should not be missing
|
||||||
reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: nil, e: 10) # d should not be missing
|
reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: nil, e: 10) # d should not be missing
|
||||||
reject FullRequiresInitWithParent()
|
reject FullRequiresInitWithParent()
|
||||||
|
reject default(FullRequiresInitWithParent)
|
||||||
reject:
|
reject:
|
||||||
var obj: FullRequiresInitWithParent
|
var obj: FullRequiresInitWithParent
|
||||||
|
|
||||||
# this will be accepted, because the false outer branch will be taken and the inner A branch
|
# this will be accepted, because the false outer branch will be taken and the inner A branch
|
||||||
accept TNestedChoices()
|
accept TNestedChoices()
|
||||||
|
accept default(TNestedChoices)
|
||||||
accept:
|
accept:
|
||||||
var obj: TNestedChoices
|
var obj: TNestedChoices
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue