diff --git a/compiler/ast.nim b/compiler/ast.nim index 6e5a17d99b..f4b1b84f58 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -353,7 +353,7 @@ type nfSem # node has been checked for semantics TNodeFlags* = set[TNodeFlag] - TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 19) + TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 23) tfVarargs, # procedure has C styled varargs tfNoSideEffect, # procedure type does not allow side effects tfFinal, # is the object final? @@ -380,7 +380,13 @@ type tfByRef, # pass object/tuple by reference (C backend) tfIterator, # type is really an iterator, not a tyProc tfShared, # type is 'shared' - tfNotNil # type cannot be 'nil' + tfNotNil, # type cannot be 'nil' + + tfNeedsInit, # type constains a "not nil" constraint somewhere or some + # other type so that it requires inititalization + tfHasShared, # type constains a "shared" constraint modifier somewhere + tfHasMeta, # type has "typedesc" or "expr" somewhere + tfHasGCedMem, # type contains GC'ed memory TTypeFlags* = set[TTypeFlag] @@ -1168,14 +1174,25 @@ proc newSons(father: PNode, length: int) = else: setlen(father.sons, length) -proc addSon*(father, son: PType) {.deprecated.} = - if isNil(father.sons): father.sons = @[] - add(father.sons, son) - #assert((father.kind != tyGenericInvokation) or (son.kind != tyGenericInst)) +proc propagateToOwner*(owner, elem: PType) = + owner.flags = owner.flags + (elem.flags * {tfNeedsInit, tfHasShared, + tfHasMeta, tfHasGCedMem}) + if tfNotNil in elem.flags: + owner.flags.incl tfNeedsInit + + if tfShared in elem.flags: + owner.flags.incl tfHasShared + + if elem.kind in {tyExpr, tyTypeDesc}: + owner.flags.incl tfHasMeta + elif elem.kind in {tyString, tyRef, tySequence} or + elem.kind == tyProc and elem.callConv == ccClosure: + owner.flags.incl tfHasGCedMem proc rawAddSon*(father, son: PType) = if isNil(father.sons): father.sons = @[] add(father.sons, son) + if not son.isNil: propagateToOwner(father, son) proc addSon(father, son: PNode) = assert son != nil diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 352b6ca043..1972dec989 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -43,6 +43,18 @@ proc getSysSym(name: string): PSym = result.typ = newType(tyError, systemModule) if result.kind == skStub: loadStub(result) +proc getSysMagic*(name: string, m: TMagic): PSym = + var ti: TIdentIter + let id = getIdent(name) + result = InitIdentIter(ti, systemModule.tab, id) + while result != nil: + if result.kind == skStub: loadStub(result) + if result.magic == m: return result + result = NextIdentIter(ti, systemModule.tab) + rawMessage(errSystemNeeds, name) + result = newSym(skError, id, systemModule, systemModule.info) + result.typ = newType(tyError, systemModule) + proc sysTypeFromName*(name: string): PType = result = getSysSym(name).typ @@ -111,7 +123,9 @@ proc skipIntLit*(t: PType): PType {.inline.} = proc AddSonSkipIntLit*(father, son: PType) = if isNil(father.sons): father.sons = @[] - add(father.sons, son.skipIntLit) + let s = son.skipIntLit + add(father.sons, s) + propagateToOwner(father, s) proc setIntLitType*(result: PNode) = let i = result.intVal diff --git a/compiler/msgs.nim b/compiler/msgs.nim index f75aec0d5e..302a7cfd88 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -106,7 +106,7 @@ type warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored, warnNilStatement, warnAnalysisLoophole, warnDifferentHeaps, warnWriteToForeignHeap, warnImplicitClosure, - warnEachIdentIsTuple, warnShadowIdent, warnUninit, warnUser, + warnEachIdentIsTuple, warnShadowIdent, warnProveInit, warnUninit, warnUser, hintSuccess, hintSuccessX, hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, @@ -355,7 +355,8 @@ const warnImplicitClosure: "implicit closure convention: '$1' [ImplicitClosure]", warnEachIdentIsTuple: "each identifier is a tuple [EachIdentIsTuple]", warnShadowIdent: "shadowed identifier: '$1' [ShadowIdent]", - warnUninit: "read from potentially uninitialized variable: '$1' [Uninit]", + warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future. [ProveInit]", + warnUninit: "'$1' might not have been initialized [Uninit]", warnUser: "$1 [User]", hintSuccess: "operation successful [Success]", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]", @@ -375,14 +376,14 @@ const hintUser: "$1 [User]"] const - WarningsToStr*: array[0..20, string] = ["CannotOpenFile", "OctalEscape", + WarningsToStr*: array[0..21, string] = ["CannotOpenFile", "OctalEscape", "XIsNeverRead", "XmightNotBeenInit", "Deprecated", "ConfigDeprecated", "SmallLshouldNotBeUsed", "UnknownMagic", "RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported", "CommentXIgnored", "NilStmt", "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap", - "ImplicitClosure", "EachIdentIsTuple", "ShadowIdent", "Uninit", + "ImplicitClosure", "EachIdentIsTuple", "ShadowIdent", "ProveInit", "Uninit", "User"] HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong", diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index de7bcaeee1..283f839062 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -50,6 +50,8 @@ proc add(code: var TPatternCode, op: TOpcode) {.inline.} = proc whichAlias*(p: PSym): TAliasRequest = if p.constraint != nil: result = TAliasRequest(p.constraint.strVal[0].ord) + else: + result = aqNone proc compileConstraints(p: PNode, result: var TPatternCode) = case p.kind diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index cc432aea85..cecec8e5ec 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -50,7 +50,7 @@ const typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow, wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef, - wInheritable, wGenSym, wInject} + wInheritable, wGenSym, wInject, wRequiresInit} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, wImportcpp, wImportobjc, wError} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, @@ -253,11 +253,11 @@ proc processNote(c: PContext, n: PNode) = of wHint: var x = findStr(msgs.HintsToStr, n.sons[0].sons[1].ident.s) if x >= 0: nk = TNoteKind(x + ord(hintMin)) - else: invalidPragma(n) + else: invalidPragma(n); return of wWarning: var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s) if x >= 0: nk = TNoteKind(x + ord(warnMin)) - else: InvalidPragma(n) + else: InvalidPragma(n); return else: invalidPragma(n) return @@ -695,6 +695,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, noVal(it) if sym.typ == nil: invalidPragma(it) else: incl(sym.typ.flags, tfIncompleteStruct) + of wRequiresInit: + noVal(it) + if sym.typ == nil: invalidPragma(it) + else: incl(sym.typ.flags, tfNeedsInit) of wByRef: noVal(it) if sym == nil or sym.typ == nil: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index fba028a462..cdab9b535b 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1601,6 +1601,25 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = addSonSkipIntLit(typ, n.sons[i].typ) result.typ = typ +proc checkInitialized(n: PNode, ids: TIntSet, info: TLineInfo) = + case n.kind + of nkRecList: + for i in countup(0, sonsLen(n) - 1): + checkInitialized(n.sons[i], ids, info) + of nkRecCase: + if (n.sons[0].kind != nkSym): InternalError(info, "checkInitialized") + checkInitialized(n.sons[0], ids, info) + when false: + # XXX we cannot check here, as we don't know the branch! + for i in countup(1, sonsLen(n) - 1): + case n.sons[i].kind + of nkOfBranch, nkElse: checkInitialized(lastSon(n.sons[i]), ids, info) + else: internalError(info, "checkInitialized") + of nkSym: + if tfNeedsInit in n.sym.typ.flags and n.sym.name.id notin ids: + Message(info, errGenerated, "field not initialized: " & n.sym.name.s) + else: internalError(info, "checkInitialized") + proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = var t = semTypeNode(c, n.sons[0], nil) result = n @@ -1611,6 +1630,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = if t.kind != tyObject: localError(n.info, errGenerated, "object constructor needs an object type") return + var objType = t var ids = initIntSet() for i in 1.. = toCover: tracked.init.add id # else we can't merge proc trackIf(tracked: PEffects, n: PNode) = track(tracked, n.sons[0].sons[0]) + let oldFacts = tracked.guards.len + addFact(tracked.guards, n.sons[0].sons[0]) let oldState = tracked.init.len var inter: TIntersection = @[] + var toCover = 0 track(tracked, n.sons[0].sons[1]) + if not breaksBlock(n.sons[0].sons[1]): inc toCover for i in oldState.. 1: + addFact(tracked.guards, branch.sons[0]) setLen(tracked.init, oldState) for i in 0 .. = toCover: tracked.init.add id # else we can't merge as it is not exhaustive + setLen(tracked.guards, oldFacts) proc trackBlock(tracked: PEffects, n: PNode) = if n.kind in {nkStmtList, nkStmtListExpr}: @@ -377,6 +415,9 @@ proc isTrue(n: PNode): bool = n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or n.kind == nkIntLit and n.intVal != 0 +proc paramType(op: PType, i: int): PType = + if op != nil and i < op.len: result = op.sons[i] + proc track(tracked: PEffects, n: PNode) = case n.kind of nkSym: @@ -404,11 +445,12 @@ proc track(tracked: PEffects, n: PNode) = else: mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) - for i in 1 .. 0 or n.sons[1].intVal < 0: + incl(result.flags, tfNeedsInit) + elif n.sons[0].floatVal > 0.0 or n.sons[1].floatVal < 0.0: + incl(result.flags, tfNeedsInit) else: LocalError(n.sons[0].info, errRangeExpected) result = newOrPrevType(tyError, prev, c) @@ -386,34 +396,34 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, swap(branch.sons[L-2], branch.sons[L-1]) checkForOverlap(c, t, i, branchIndex) -proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, - father: PNode, rectype: PSym) -proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int, - father: PNode, rectype: PSym) = +proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, + father: PNode, rectype: PType) +proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int, + father: PNode, rectype: PType) = var a = copyNode(n) checkMinSonsLen(n, 2) semRecordNodeAux(c, n.sons[0], check, pos, a, rectype) - if a.sons[0].kind != nkSym: + if a.sons[0].kind != nkSym: internalError("semRecordCase: discriminant is no symbol") return incl(a.sons[0].sym.flags, sfDiscriminant) var covered: biggestInt = 0 var typ = skipTypes(a.sons[0].Typ, abstractVar-{tyTypeDesc}) - if not isOrdinalType(typ): + if not isOrdinalType(typ): LocalError(n.info, errSelectorMustBeOrdinal) - elif firstOrd(typ) < 0: + elif firstOrd(typ) < 0: LocalError(n.info, errOrdXMustNotBeNegative, a.sons[0].sym.name.s) - elif lengthOrd(typ) > 0x00007FFF: + elif lengthOrd(typ) > 0x00007FFF: LocalError(n.info, errLenXinvalid, a.sons[0].sym.name.s) var chckCovered = true - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): var b = copyTree(n.sons[i]) addSon(a, b) case n.sons[i].kind - of nkOfBranch: + of nkOfBranch: checkMinSonsLen(b, 2) semCaseBranch(c, a, b, i, covered) - of nkElse: + of nkElse: chckCovered = false checkSonsLen(b, 1) else: illFormedAst(n) @@ -424,7 +434,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int, addSon(father, a) proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, - father: PNode, rectype: PSym) = + father: PNode, rectype: PType) = if n == nil: return case n.kind of nkRecWhen: @@ -463,7 +473,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, semRecordCase(c, n, check, pos, father, rectype) of nkNilLit: if father.kind != nkRecList: addSon(father, newNodeI(nkRecList, n.info)) - of nkRecList: + of nkRecList: # attempt to keep the nesting at a sane level: var a = if father.kind == nkRecList: father else: copyNode(n) for i in countup(0, sonsLen(n) - 1): @@ -473,7 +483,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, checkMinSonsLen(n, 3) var length = sonsLen(n) var a: PNode - if father.kind != nkRecList and length >= 4: a = newNodeI(nkRecList, n.info) + if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info) else: a = ast.emptyNode if n.sons[length-1].kind != nkEmpty: localError(n.sons[length-1].info, errInitHereNotAllowed) @@ -483,17 +493,19 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, typ = errorType(c) else: typ = semTypeNode(c, n.sons[length-2], nil) + propagateToOwner(rectype, typ) + let rec = rectype.sym for i in countup(0, sonsLen(n)-3): var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported}) suggestSym(n.sons[i], f) f.typ = typ f.position = pos - if (rectype != nil) and ({sfImportc, sfExportc} * rectype.flags != {}) and + if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and (f.loc.r == nil): f.loc.r = toRope(f.name.s) - f.flags = f.flags + ({sfImportc, sfExportc} * rectype.flags) + f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags) inc(pos) - if ContainsOrIncl(check, f.name.id): + if ContainsOrIncl(check, f.name.id): localError(n.sons[i].info, errAttemptToRedefine, f.name.s) if a.kind == nkEmpty: addSon(father, newSymNode(f)) else: addSon(a, newSymNode(f)) @@ -502,20 +514,20 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, else: illFormedAst(n) proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int, - n: PNode) = + n: PNode) = case n.kind - of nkRecCase: + of nkRecCase: if (n.sons[0].kind != nkSym): InternalError(n.info, "addInheritedFieldsAux") addInheritedFieldsAux(c, check, pos, n.sons[0]) - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): case n.sons[i].kind - of nkOfBranch, nkElse: + of nkOfBranch, nkElse: addInheritedFieldsAux(c, check, pos, lastSon(n.sons[i])) else: internalError(n.info, "addInheritedFieldsAux(record case branch)") - of nkRecList: - for i in countup(0, sonsLen(n) - 1): + of nkRecList: + for i in countup(0, sonsLen(n) - 1): addInheritedFieldsAux(c, check, pos, n.sons[i]) - of nkSym: + of nkSym: Incl(check, n.sym.name.id) inc(pos) else: InternalError(n.info, "addInheritedFieldsAux()") @@ -553,7 +565,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyObject, prev, c) rawAddSon(result, base) result.n = newNodeI(nkRecList, n.info) - semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym) + semRecordNodeAux(c, n.sons[2], check, pos, result.n, result) if n.sons[0].kind != nkEmpty: # dummy symbol for `pragma`: var s = newSymS(skType, newIdentNode(getIdent("dummy"), n.info), c) @@ -853,6 +865,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = if result.kind in NilableTypes and n.sons[2].kind == nkNilLit: result = freshType(result, prev) result.flags.incl(tfNotNil) + result.flags.incl(tfNeedsInit) else: LocalError(n.info, errGenerated, "invalid type") else: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 26341525cb..31fbc33e1e 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -152,6 +152,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = x = lookupTypeVar(cl, x) if header == nil: header = copyType(t, t.owner, false) header.sons[i] = x + propagateToOwner(header, x) #idTablePut(cl.typeMap, body.sons[i-1], x) if header != nil: # search again after first pass: @@ -170,6 +171,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = var x = replaceTypeVarsT(cl, t.sons[i]) assert x.kind != tyGenericInvokation header.sons[i] = x + propagateToOwner(header, x) idTablePut(cl.typeMap, body.sons[i-1], x) for i in countup(1, sonsLen(t) - 1): diff --git a/compiler/transf.nim b/compiler/transf.nim index 058143cdda..a35669e1d4 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -504,8 +504,8 @@ proc transformCase(c: PTransf, n: PNode): PTransNode = result.add(elseBranch) elif result.Pnode.lastSon.kind != nkElse and not ( skipTypes(n.sons[0].Typ, abstractVarRange).Kind in - {tyInt..tyInt64, tyChar, tyEnum}): - # fix a stupid code gen bug by normalizing: + {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32}): + # fix a stupid code gen bug by normalizing: var elseBranch = newTransNode(nkElse, n.info, 1) elseBranch[0] = newTransNode(nkNilLit, n.info, 0) add(result, elseBranch) @@ -704,7 +704,7 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = if nfTransf in n.flags or prc.kind in {skTemplate, skMacro}: result = n else: - when useEffectSystem: trackProc(prc, n) + #when useEffectSystem: trackProc(prc, n) var c = openTransf(module, "") result = processTransf(c, n) if prc.kind != skMacro: @@ -713,6 +713,7 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = if prc.kind == skIterator and prc.typ.callConv == ccClosure: result = lambdalifting.liftIterator(prc, result) incl(result.flags, nfTransf) + when useEffectSystem: trackProc(prc, result) proc transformStmt*(module: PSym, n: PNode): PNode = if nfTransf in n.flags: diff --git a/compiler/trees.nim b/compiler/trees.nim index f371cb0211..ab5c97a196 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -93,8 +93,7 @@ proc getOpSym*(op: PNode): PSym = proc getMagic*(op: PNode): TMagic = case op.kind - of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit, nkPrefix, nkPostfix, - nkInfix: + of nkCallKinds: case op.sons[0].Kind of nkSym: result = op.sons[0].sym.magic else: result = mNone diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 36d08c7182..2a8a02bd61 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -41,7 +41,7 @@ type wImmediate, wDestructor, wImportCpp, wImportObjC, wImportCompilerProc, - wImportc, wExportc, wIncompleteStruct, + wImportc, wExportc, wIncompleteStruct, wRequiresInit, wAlign, wNodecl, wPure, wSideeffect, wHeader, wNosideeffect, wNoreturn, wMerge, wLib, wDynlib, wCompilerproc, wProcVar, wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, @@ -122,7 +122,7 @@ const "immediate", "destructor", "importcpp", "importobjc", "importcompilerproc", "importc", "exportc", "incompletestruct", - "align", "nodecl", "pure", "sideeffect", + "requiresinit", "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", "compilerproc", "procvar", "fatal", "error", "warning", "hint", "line", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", diff --git a/doc/manual.txt b/doc/manual.txt index f163e0d5f3..7147eb6317 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -327,36 +327,36 @@ Numerical constants `Numerical constants`:idx: are of a single type and have the form:: - hexdigit ::= digit | 'A'..'F' | 'a'..'f' - octdigit ::= '0'..'7' - bindigit ::= '0'..'1' - HEX_LIT ::= '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )* - DEC_LIT ::= digit ( ['_'] digit )* - OCT_LIT ::= '0o' octdigit ( ['_'] octdigit )* - BIN_LIT ::= '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )* + hexdigit = digit | 'A'..'F' | 'a'..'f' + octdigit = '0'..'7' + bindigit = '0'..'1' + HEX_LIT = '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )* + DEC_LIT = digit ( ['_'] digit )* + OCT_LIT = '0o' octdigit ( ['_'] octdigit )* + BIN_LIT = '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )* - INT_LIT ::= HEX_LIT - | DEC_LIT - | OCT_LIT - | BIN_LIT + INT_LIT = HEX_LIT + | DEC_LIT + | OCT_LIT + | BIN_LIT - INT8_LIT ::= INT_LIT ['\''] ('i' | 'I') '8' - INT16_LIT ::= INT_LIT ['\''] ('i' | 'I') '16' - INT32_LIT ::= INT_LIT ['\''] ('i' | 'I') '32' - INT64_LIT ::= INT_LIT ['\''] ('i' | 'I') '64' + INT8_LIT = INT_LIT ['\''] ('i' | 'I') '8' + INT16_LIT = INT_LIT ['\''] ('i' | 'I') '16' + INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32' + INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64' - UINT8_LIT ::= INT_LIT ['\''] ('u' | 'U') - UINT8_LIT ::= INT_LIT ['\''] ('u' | 'U') '8' - UINT16_LIT ::= INT_LIT ['\''] ('u' | 'U') '16' - UINT32_LIT ::= INT_LIT ['\''] ('u' | 'U') '32' - UINT64_LIT ::= INT_LIT ['\''] ('u' | 'U') '64' + UINT8_LIT = INT_LIT ['\''] ('u' | 'U') + UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8' + UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16' + UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32' + UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64' - exponent ::= ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )* - FLOAT_LIT ::= digit (['_'] digit)* ('.' (['_'] digit)* [exponent] |exponent) - FLOAT32_LIT ::= HEX_LIT '\'' ('f'|'F') '32' - | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '32' - FLOAT64_LIT ::= HEX_LIT '\'' ('f'|'F') '64' - | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '64' + exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )* + FLOAT_LIT = digit (['_'] digit)* ('.' (['_'] digit)* [exponent] |exponent) + FLOAT32_LIT = HEX_LIT '\'' ('f'|'F') '32' + | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '32' + FLOAT64_LIT = HEX_LIT '\'' ('f'|'F') '64' + | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '64' As can be seen in the productions, numerical constants can contain underscores @@ -1818,6 +1818,24 @@ If a proc is annotated with the ``noinit`` pragma this refers to its implicit proc returnUndefinedValue: int {.noinit.} = nil +The implicit initialization can be also prevented by the `requiresInit`:idx: +type pragma. The compiler requires an explicit initialization then. However +it does a `control flow analysis`:idx: to prove the variable has been +initialized and does not rely on syntactic properties: + +.. code-block:: nimrod + type + TMyObject = object {.requiresInit.} + + proc p() = + # the following is valid: + var x: TMyObject + if someCondition(): + x = a() + else: + x = a() + use x + let statement ------------- diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt index 7f77a50d28..339cee3823 100644 --- a/doc/nimrodc.txt +++ b/doc/nimrodc.txt @@ -20,7 +20,7 @@ on the different supported platforms. It is not a definition of the Nimrod programming language (therefore is the `manual `_). Nimrod is free software; it is licensed under the -`GNU General Public License `_. +`MIT License `_. Compiler Usage diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 2eb8d692bc..86609c8e3a 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -338,24 +338,24 @@ when not defined(JS): const weekDays: array [0..6, TWeekDay] = [ dSun, dMon, dTue, dWed, dThu, dFri, dSat] - result.second = int(tm.second) - result.minute = int(tm.minute) - result.hour = int(tm.hour) - result.monthday = int(tm.monthday) - result.month = TMonth(tm.month) - result.year = tm.year + 1900'i32 - result.weekday = weekDays[int(tm.weekDay)] - result.yearday = int(tm.yearday) - result.isDST = tm.isDST > 0 - if local: - if result.isDST: - result.tzname = getTzname().DST - else: - result.tzname = getTzname().nonDST - else: - result.tzname = "UTC" - - result.timezone = if local: getTimezone() else: 0 + TTimeInfo(second: int(tm.second), + minute: int(tm.minute), + hour: int(tm.hour), + monthday: int(tm.monthday), + month: TMonth(tm.month), + year: tm.year + 1900'i32, + weekday: weekDays[int(tm.weekDay)], + yearday: int(tm.yearday), + isDST: tm.isDST > 0, + tzname: if local: + if tm.isDST > 0: + getTzname().DST + else: + getTzname().nonDST + else: + "UTC", + timezone: if local: getTimezone() else: 0 + ) proc timeInfoToTM(t: TTimeInfo): structTM = const diff --git a/tests/reject/tuninit1.nim b/tests/reject/tuninit1.nim new file mode 100644 index 0000000000..e51f9ce7c0 --- /dev/null +++ b/tests/reject/tuninit1.nim @@ -0,0 +1,36 @@ +discard """ + errormsg: "'y' might not have been initialized" + line:28 +""" + +import strutils + +{.warning[Uninit]:on.} + +proc p = + var x, y, z: int + if stdin.readLine == "true": + x = 34 + + while false: + y = 999 + break + + while true: + if x == 12: break + y = 9999 + + try: + z = parseInt("1233") + except E_Base: + case x + of 34: z = 123 + of 13: z = 34 + else: z = 8 + else: + y = 3444 + x = 3111 + z = 0 + echo x, y, z + +p() diff --git a/todo.txt b/todo.txt index 2aea8660fd..9a3377d1c3 100644 --- a/todo.txt +++ b/todo.txt @@ -2,7 +2,8 @@ version 0.9.4 ============= - make 'bind' default for templates and introduce 'mixin'; -- implement full 'not nil' checking; range[1..3] needs the same mechanism +- test 'not nil' checking more +- prove field accesses; prove array accesses - special rule for ``[]=`` - ``=`` should be overloadable; requires specialization for ``=``; general lift mechanism in the compiler is already implemented for 'fields' diff --git a/tools/niminst/debcreation.nim b/tools/niminst/debcreation.nim index 1e08e56533..982bfaf3d9 100644 --- a/tools/niminst/debcreation.nim +++ b/tools/niminst/debcreation.nim @@ -227,9 +227,9 @@ when isMainModule: #echo(createRules()) - prepDeb("nimrod", "0.8.14", "Dominik Picheta", "morfeusz8@gmail.com", + prepDeb("nimrod", "0.9.2", "Dominik Picheta", "morfeusz8@gmail.com", "The Nimrod compiler", "Compiler for the Nimrod programming language", - @[("bin/nimrod", "gpl2"), ("lib/*", "lgpl")], + @[("bin/nimrod", "MIT"), ("lib/*", "MIT")], @["bin/nimrod"], @["config/*"], @["doc/*"], @["lib/*"], "gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)") diff --git a/web/index.txt b/web/index.txt index 260d303c8c..e504b65c4f 100644 --- a/web/index.txt +++ b/web/index.txt @@ -89,7 +89,7 @@ Nimrod plays nice with others * **The Nimrod Compiler can also generate C++ or Objective C for easier interfacing.** * There are lots of bindings: for example, bindings to GTK2, the Windows API, - the POSIX API, OpenGL, SDL, Cario, Python, Lua, TCL, X11, libzip, PCRE, + the POSIX API, OpenGL, SDL, Cairo, Python, Lua, TCL, X11, libzip, PCRE, libcurl, mySQL and SQLite are included in the standard distribution. * A C to Nimrod conversion utility: New bindings to C libraries are easily generated by ``c2nim``. diff --git a/web/news.txt b/web/news.txt index 4f932bc05d..f5737ffa38 100644 --- a/web/news.txt +++ b/web/news.txt @@ -36,7 +36,7 @@ Language Additions - Arrays can now be declared with a single integer literal ``N`` instead of a range; the range is then ``0..N-1``. - +- Added ``requiresInit`` pragma to enforce explicit initialization. 2013-05-20 New website design!