diff --git a/compiler/ast.nim b/compiler/ast.nim index f4b1b84f58..e4f7f6d985 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1175,10 +1175,18 @@ proc newSons(father: PNode, length: int) = setlen(father.sons, length) proc propagateToOwner*(owner, elem: PType) = - owner.flags = owner.flags + (elem.flags * {tfNeedsInit, tfHasShared, - tfHasMeta, tfHasGCedMem}) + const HaveTheirOwnEmpty = {tySequence, tySet} + owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta, + tfHasGCedMem}) if tfNotNil in elem.flags: - owner.flags.incl tfNeedsInit + if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}: + owner.flags.incl tfNotNil + elif owner.kind notin HaveTheirOwnEmpty: + owner.flags.incl tfNeedsInit + + if tfNeedsInit in elem.flags: + if owner.kind in HaveTheirOwnEmpty: nil + else: owner.flags.incl tfNeedsInit if tfShared in elem.flags: owner.flags.incl tfHasShared diff --git a/compiler/guards.nim b/compiler/guards.nim index d4cb34f362..aece63b194 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -532,6 +532,13 @@ proc buildElse(n: PNode): PNode = result.sons[1] = s result.sons[2] = n.sons[0] +proc addDiscriminantFact*(m: var TModel, n: PNode) = + var fact = newNodeI(nkCall, n.info, 3) + fact.sons[0] = newSymNode(getSysMagic("==", mEqI)) + fact.sons[1] = n.sons[0] + fact.sons[2] = n.sons[1] + m.add fact + proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) = let branch = n.sons[i] if branch.kind == nkOfBranch: diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 50286d399d..2c87c3b2c1 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -74,7 +74,6 @@ type bottom: int owner: PSym init: seq[int] # list of initialized variables - # coming soon: "guard" tracking for 'let' variables guards: TModel # nested guards PEffects = var TEffects @@ -89,11 +88,19 @@ proc initVar(a: PEffects, n: PNode) = if x == s.id: return a.init.add s.id +proc initVarViaNew(a: PEffects, n: PNode) = + if n.kind != nkSym: return + let s = n.sym + if {tfNeedsInit, tfNotNil} * s.typ.flags == {tfNotNil}: + # 'x' is not nil, but that doesn't mean it's not nil children + # are initialized: + initVarViaNew(a, n) + proc useVar(a: PEffects, n: PNode) = let s = n.sym if isLocalVar(a, s): if s.id notin a.init: - if tfNeedsInit in s.typ.flags: + if {tfNeedsInit, tfNotNil} * s.typ.flags != {}: when true: Message(n.info, warnProveInit, s.name.s) else: @@ -298,6 +305,18 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = let tagSpec = effectSpec(pragma, wTags) mergeTags(tracked, tagSpec, n) +proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = + let n = n.skipConv + if paramType != nil and tfNotNil in paramType.flags and + n.typ != nil and tfNotNil notin n.typ.flags: + case impliesNotNil(tracked.guards, n) + of impUnknown: + Message(n.info, errGenerated, + "cannot prove '$1' is not nil" % n.renderTree) + of impNo: + Message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree) + of impYes: discard + proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = let op = n.typ if op != nil and op.kind == tyProc and n.kind != nkNilLit: @@ -315,15 +334,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = else: mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) - if paramType != nil: - if tfNotNil in paramType.flags and op != nil and tfNotNil notin op.flags: - case impliesNotNil(tracked.guards, n) - of impUnknown: - Message(n.info, errGenerated, - "cannot prove '$1' is not nil" % n.renderTree) - of impNo: - Message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree) - of impYes: discard + notNilCheck(tracked, n, paramType) proc breaksBlock(n: PNode): bool = case n.kind @@ -456,8 +467,7 @@ proc track(tracked: PEffects, n: PNode) = if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq, mShallowCopy}: # may not look like an assignment, but it is: - initVar(tracked, n.sons[1]) - # XXX new(objWithNotNil) is not initialized properly! + initVarViaNew(tracked, n.sons[1]) for i in 0 ..