diff options
-rwxr-xr-x | compiler/ast.nim | 6 | ||||
-rwxr-xr-x | compiler/ccgexprs.nim | 8 | ||||
-rwxr-xr-x | compiler/ccgtypes.nim | 4 | ||||
-rwxr-xr-x | compiler/cgen.nim | 2 | ||||
-rwxr-xr-x | compiler/docgen.nim | 2 | ||||
-rwxr-xr-x | compiler/ecmasgen.nim | 4 | ||||
-rwxr-xr-x | compiler/evals.nim | 5 | ||||
-rwxr-xr-x | compiler/llvmgen.nim | 2 | ||||
-rwxr-xr-x | compiler/msgs.nim | 4 | ||||
-rwxr-xr-x | compiler/sem.nim | 4 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 88 | ||||
-rwxr-xr-x | compiler/seminst.nim | 1 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 9 | ||||
-rwxr-xr-x | compiler/semthreads.nim | 6 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 8 | ||||
-rwxr-xr-x | compiler/transf.nim | 4 | ||||
-rwxr-xr-x | compiler/types.nim | 20 | ||||
-rwxr-xr-x | lib/pure/smtp.nim | 12 | ||||
-rwxr-xr-x | lib/pure/streams.nim | 2 | ||||
-rwxr-xr-x | lib/pure/strtabs.nim | 10 | ||||
-rwxr-xr-x | lib/wrappers/gtk/glib2.nim | 2 | ||||
-rw-r--r-- | tests/accept/run/teventemitter.nim | 23 | ||||
-rw-r--r-- | tests/accept/run/tvarres1.nim | 15 | ||||
-rw-r--r-- | tests/accept/run/tvarres2.nim | 20 | ||||
-rw-r--r-- | tests/reject/tvarres1.nim | 17 | ||||
-rw-r--r-- | tests/reject/tvarres2.nim | 16 | ||||
-rwxr-xr-x | todo.txt | 8 |
27 files changed, 234 insertions, 68 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index fe601759d..f176f6eb1 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -186,8 +186,8 @@ type nkReturnToken # token used for interpretation TNodeKinds* = set[TNodeKind] -type - TSymFlag* = enum # already 30 flags! +type + TSymFlag* = enum # already 29 flags! sfUsed, # read access of sym (for warnings) or simply used sfStar, # symbol has * visibility sfMinus, # symbol has - visibility @@ -204,7 +204,6 @@ type sfRegister, # variable should be placed in a register sfPure, # object is "pure" that means it has no type-information - sfResult, # variable is 'result' in proc sfNoSideEffect, # proc has no side effects sfSideEffect, # proc may have side effects; cannot prove it has none sfMainModule, # module is the main module @@ -293,6 +292,7 @@ type skType, # a type skConst, # a constant skVar, # a variable + skResult, # special 'result' variable skProc, # a proc skMethod, # a method skIterator, # an iterator diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index d9ad0573a..e92673909 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -136,7 +136,7 @@ proc getStorageLoc(n: PNode): TStorageLoc = case n.sym.kind of skParam, skForVar, skTemp: result = OnStack - of skVar: + of skVar, skResult: if sfGlobal in n.sym.flags: result = OnHeap else: result = OnStack of skConst: @@ -206,6 +206,10 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # This function replaces all other methods for generating # the assignment operation in C. + if src.t != nil and src.t.kind == tyPtr: + # little HACK to suppor the new 'var T' as return type: + appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + return var ty = skipTypes(dest.t, abstractVarRange) case ty.kind of tyRef: @@ -1648,7 +1652,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) = genComplexConst(p, sym, d) of skEnumField: putIntoDest(p, d, e.typ, toRope(sym.position)) - of skVar: + of skVar, skResult: if sfGlobal in sym.flags: genVarPrototype(p.module, sym) if ((sym.loc.r == nil) or (sym.loc.t == nil)): InternalError(e.info, "expr: var not init " & sym.name.s) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index a1f772379..ddaeed729 100755 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -37,7 +37,7 @@ proc mangleName(s: PSym): PRope = case s.kind of skProc, skMethod, skConverter, skConst: result = toRope("@") - of skVar: + of skVar, skResult: if sfGlobal in s.flags: result = toRope("@") else: result = toRope("%") of skForVar, skTemp, skParam, skType, skEnumField, skModule: @@ -153,7 +153,7 @@ proc getGlobalTempName(): PRope = proc ccgIntroducedPtr(s: PSym): bool = var pt = s.typ - assert(not (sfResult in s.flags)) + assert skResult != s.kind case pt.Kind of tyObject: # XXX quick hack floatSize*2 for the pegs module under 64bit diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 68e377f8b..b89d2d7fc 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -534,7 +534,7 @@ proc cgsym(m: BModule, name: string): PRope = if sym != nil: case sym.kind of skProc, skMethod, skConverter: genProc(m, sym) - of skVar: genVarPrototype(m, sym) + of skVar, skResult: genVarPrototype(m, sym) of skType: discard getTypeDesc(m, sym.typ) else: InternalError("cgsym: " & name) else: diff --git a/compiler/docgen.nim b/compiler/docgen.nim index fc019790a..0c5d41b47 100755 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -810,7 +810,7 @@ proc generateDoc(d: PDoc, n: PNode) = proc genSection(d: PDoc, kind: TSymKind) = const sectionNames: array[skModule..skTemplate, string] = [ - "Imports", "Types", "Consts", "Vars", "Procs", "Methods", + "Imports", "Types", "Consts", "Vars", "Vars", "Procs", "Methods", "Iterators", "Converters", "Macros", "Templates" ] if d.section[kind] == nil: return diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index 592a24043..2e66f61c9 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -832,7 +832,7 @@ proc genAddr(p: var TProc, n: PNode, r: var TCompRes) = s = n.sons[0].sym if s.loc.r == nil: InternalError(n.info, "genAddr: 3") case s.kind - of skVar: + of skVar, skResult: if mapType(n.typ) == etyObject: # make addr() a no-op: r.kind = etyNone @@ -863,7 +863,7 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) = if s.loc.r == nil: InternalError(n.info, "symbol has no generated name: " & s.name.s) case s.kind - of skVar, skParam, skTemp: + of skVar, skParam, skTemp, skResult: var k = mapType(s.typ) if k == etyBaseIndex: r.kind = etyBaseIndex diff --git a/compiler/evals.nim b/compiler/evals.nim index 4372e3179..9aa67de3e 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -293,7 +293,7 @@ proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode = # which can be modified. var x = c while x != nil: - if sfResult in sym.flags: + if sym.kind == skResult: result = x.params[0] if result == nil: result = emptyNode return @@ -425,7 +425,8 @@ proc evalSwap(c: PEvalContext, n: PNode): PNode = proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = case n.sym.kind of skProc, skConverter, skMacro: result = n.sym.ast.sons[codePos] - of skVar, skForVar, skTemp: result = evalVariable(c.tos, n.sym, flags) + of skVar, skForVar, skTemp, skResult: + result = evalVariable(c.tos, n.sym, flags) of skParam: # XXX what about LValue? result = c.tos.params[n.sym.position + 1] diff --git a/compiler/llvmgen.nim b/compiler/llvmgen.nim index f8acb624a..b45f37e14 100755 --- a/compiler/llvmgen.nim +++ b/compiler/llvmgen.nim @@ -393,7 +393,7 @@ proc UseMagic(m: BModule, name: string) = if sym != nil: case sym.kind of skProc, skMethod, skConverter: genProc(m, sym) - of skVar: genVarPrototype(m, sym) + of skVar, skResult: genVarPrototype(m, sym) of skType: discard getTypeDesc(m, sym.typ) else: InternalError("useMagic: " & name) elif not (sfSystemModule in m.module.flags): diff --git a/compiler/msgs.nim b/compiler/msgs.nim index b2ead1d9e..27b5c7f67 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -56,7 +56,8 @@ type errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig, errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects, errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX, - errCannotInstantiateX, errExprHasNoAddress, errVarForOutParamNeeded, + errCannotInstantiateX, errExprHasNoAddress, errXStackEscape, + errVarForOutParamNeeded, errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX, errAmbiguousCallXYZ, errWrongNumberOfArguments, errXCannotBePassedToProcVar, errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, @@ -227,6 +228,7 @@ const errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'", errCannotInstantiateX: "cannot instantiate: \'$1\'", errExprHasNoAddress: "expression has no address", + errXStackEscape: "address of '$1' may not escape its stack frame", errVarForOutParamNeeded: "for a \'var\' type a variable needs to be passed", errPureTypeMismatch: "type mismatch", errTypeMismatch: "type mismatch: got (", diff --git a/compiler/sem.nim b/compiler/sem.nim index c2fbfff72..5d2e1069f 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -50,6 +50,10 @@ proc addResult(c: PContext, t: PType, info: TLineInfo) proc addResultNode(c: PContext, n: PNode) proc instGenericContainer(c: PContext, n: PNode, header: PType): PType +proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} = + if not typeAllowed(typ, skConst): + GlobalError(typ.n.info, errXisNoType, typeToString(typ)) + proc semConstExpr(c: PContext, n: PNode): PNode = result = semExprWithType(c, n) if result == nil: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 879a42d81..959a48267 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -21,20 +21,31 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode +proc newDeref(n: PNode): PNode {.inline.} = + result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0]) + addSon(result, n) + proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExpr(c, n, flags) if result.kind == nkEmpty: # do not produce another redundant error message: raiseRecoverableError() if result.typ != nil: - if result.typ.kind == tyVar: - var d = newNodeIT(nkHiddenDeref, result.info, result.typ.sons[0]) - addSon(d, result) - result = d + if result.typ.kind == tyVar: result = newDeref(result) else: GlobalError(n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) +proc semExprWithTypeNoDeref(c: PContext, n: PNode, + flags: TExprFlags = {}): PNode = + result = semExpr(c, n, flags) + if result.kind == nkEmpty: + # do not produce another redundant error message: + raiseRecoverableError() + if result.typ == nil: + GlobalError(n.info, errExprXHasNoType, + renderTree(result, {renderNoComments})) + proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = result = symChoice(c, n, s) @@ -67,7 +78,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = newSymNode(s, n.info) of skMacro: result = semMacroExpr(c, n, s) of skTemplate: result = semTemplateExpr(c, n, s) - of skVar: + of skVar, skResult: markUsed(n, s) # if a proc accesses a global variable, it is not side effect free: if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect) @@ -330,33 +341,37 @@ type TAssignableResult = enum arNone, # no l-value and no discriminant arLValue, # is an l-value + arLocalLValue, # is an l-value, but local var; must not escape + # its stack frame! arDiscriminant # is a discriminant -proc isAssignable(n: PNode): TAssignableResult = +proc isAssignable(c: PContext, n: PNode): TAssignableResult = result = arNone case n.kind - of nkSym: - if n.sym.kind in {skVar, skTemp}: result = arLValue + of nkSym: + if n.sym.kind in {skVar, skResult, skTemp}: + if c.p.owner.id == n.sym.owner.id: result = arLocalLValue + else: result = arLValue of nkDotExpr: if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: result = arLValue else: - result = isAssignable(n.sons[0]) - if result == arLValue and sfDiscriminant in n.sons[1].sym.flags: + result = isAssignable(c, n.sons[0]) + if result != arNone and sfDiscriminant in n.sons[1].sym.flags: result = arDiscriminant of nkBracketExpr: if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: result = arLValue - else: - result = isAssignable(n.sons[0]) + else: + result = isAssignable(c, n.sons[0]) of nkHiddenStdConv, nkHiddenSubConv, nkConv: # Object and tuple conversions are still addressable, so we skip them if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}: - result = isAssignable(n.sons[1]) + result = isAssignable(c, n.sons[1]) of nkHiddenDeref, nkDerefExpr: result = arLValue of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: - result = isAssignable(n.sons[0]) + result = isAssignable(c, n.sons[0]) else: nil @@ -367,7 +382,7 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = else: result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ)) addSon(result, n) - if isAssignable(n) != arLValue: + if isAssignable(c, n) notin {arLValue, arLocalLValue}: localError(n.info, errVarForOutParamNeeded) proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = @@ -403,7 +418,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = for i in countup(1, sonsLen(n) - 1): if i < sonsLen(t) and t.sons[i] != nil and skipTypes(t.sons[i], abstractInst).kind == tyVar: - if isAssignable(n.sons[i]) != arLValue: + if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}: LocalError(n.sons[i].info, errVarForOutParamNeeded) return for i in countup(1, sonsLen(n) - 1): @@ -751,7 +766,30 @@ proc propertyWriteAccess(c: PContext, n, a: PNode): PNode = else: globalError(n.Info, errUndeclaredFieldX, id.s) -proc semAsgn(c: PContext, n: PNode): PNode = +proc takeImplicitAddr(c: PContext, n: PNode): PNode = + case n.kind + of nkHiddenAddr, nkAddr: return n + of nkHiddenDeref, nkDerefExpr: return n.sons[0] + of nkBracketExpr: + if len(n) == 1: return n.sons[0] + else: nil + var valid = isAssignable(c, n) + if valid != arLValue: + if valid == arLocalLValue: + GlobalError(n.info, errXStackEscape, renderTree(n, {renderNoComments})) + else: + GlobalError(n.info, errExprHasNoAddress) + result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ)) + result.add(n) + +proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = + if le.kind == nkHiddenDeref: + var x = le.sons[0] + if x.typ.kind == tyVar and x.kind == nkSym and x.sym.kind == skResult: + n.sons[0] = x # 'result[]' --> 'result' + n.sons[1] = takeImplicitAddr(c, ri) + +proc semAsgn(c: PContext, n: PNode): PNode = checkSonsLen(n, 2) var a = n.sons[0] case a.kind @@ -762,8 +800,8 @@ proc semAsgn(c: PContext, n: PNode): PNode = if a == nil: return propertyWriteAccess(c, n, n[0]) of nkBracketExpr: - # a[i..j] = x - # --> `[..]=`(a, i, j, x) + # a[i] = x + # --> `[]=`(a, i, x) a = semSubscript(c, a, {efLValue}) if a == nil: result = buildOverloadedSubscripts(n.sons[0], inAsgn=true) @@ -772,15 +810,19 @@ proc semAsgn(c: PContext, n: PNode): PNode = else: a = semExprWithType(c, a, {efLValue}) n.sons[0] = a - n.sons[1] = semExprWithType(c, n.sons[1]) + # a = b # both are vars, means: a[] = b[] + # a = b # b no 'var T' means: a = addr(b) var le = a.typ - if skipTypes(le, {tyGenericInst}).kind != tyVar and IsAssignable(a) == arNone: + if skipTypes(le, {tyGenericInst}).kind != tyVar and + IsAssignable(c, a) == arNone: # Direct assignment to a discriminant is allowed! localError(a.info, errXCannotBeAssignedTo, renderTree(a, {renderNoComments})) - else: + else: + n.sons[1] = semExprWithType(c, n.sons[1]) n.sons[1] = fitNode(c, le, n.sons[1]) fixAbstractType(c, n) + asgnToResultVar(c, n, n.sons[0], n.sons[1]) result = n proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym = @@ -1144,7 +1186,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = n checkSonsLen(n, 1) n.sons[0] = semExprWithType(c, n.sons[0]) - if isAssignable(n.sons[0]) != arLValue: + if isAssignable(c, n.sons[0]) notin {arLValue, arLocalLValue}: GlobalError(n.info, errExprHasNoAddress) n.typ = makePtrType(c, n.sons[0].typ) of nkHiddenAddr, nkHiddenDeref: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 6cb325290..a73a0d9bf 100755 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -100,6 +100,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, result.typ = newTypeS(tyProc, c) addSon(result.typ, nil) result.typ.callConv = fn.typ.callConv + ParamsTypeCheck(c, result.typ) var oldPrc = GenericCacheGet(c, entry) if oldPrc == nil: # add it here, so that recursive generic procs are possible: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a341ce64d..3444ccfca 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -164,7 +164,7 @@ proc SemReturn(c: PContext, n: PNode): PNode = addSon(a, n.sons[0]) n.sons[0] = semAsgn(c, a) # optimize away ``result = result``: - if n[0][1].kind == nkSym and sfResult in n[0][1].sym.flags: + if n[0][1].kind == nkSym and n[0][1].sym.kind == skResult: n.sons[0] = ast.emptyNode proc SemYield(c: PContext, n: PNode): PNode = @@ -544,10 +544,9 @@ proc sideEffectsCheck(c: PContext, s: PSym) = proc addResult(c: PContext, t: PType, info: TLineInfo) = if t != nil: - var s = newSym(skVar, getIdent"result", getCurrOwner()) + var s = newSym(skResult, getIdent"result", getCurrOwner()) s.info = info s.typ = t - incl(s.flags, sfResult) incl(s.flags, sfUsed) addDecl(c, s) c.p.resultSym = s @@ -569,7 +568,8 @@ proc semLambda(c: PContext, n: PNode): PNode = if n.sons[paramsPos].kind != nkEmpty: semParamList(c, n.sons[ParamsPos], nil, s) addParams(c, s.typ.n) - else: + ParamsTypeCheck(c, s.typ) + else: s.typ = newTypeS(tyProc, c) addSon(s.typ, nil) s.typ.callConv = ccClosure @@ -664,6 +664,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if sfBorrow in s.flags: LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s) if n.sons[genericParamsPos].kind == nkEmpty: + ParamsTypeCheck(c, s.typ) pushProcCon(c, s) if (s.typ.sons[0] != nil) and (kind != skIterator): addResult(c, s.typ.sons[0], n.info) diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim index 7355c3bfc..60c54b43e 100755 --- a/compiler/semthreads.nim +++ b/compiler/semthreads.nim @@ -107,7 +107,7 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner = result = c.mapping[v.id] if result != toUndefined: return case v.kind - of skVar: + of skVar, skResult: result = toNil if sfGlobal in v.flags: if sfThreadVar in v.flags: @@ -192,9 +192,13 @@ proc analyseCall(c: PProcCtx, n: PNode): TThreadOwner = if prc.ast.sons[codePos].kind == nkEmpty and {sfNoSideEffect, sfThread, sfImportc} * prc.flags == {}: Message(n.info, warnAnalysisLoophole, renderTree(n)) + if result == toUndefined: result = toNil if prc.typ.sons[0] != nil: if prc.ast.len > resultPos: result = newCtx.mapping[prc.ast.sons[resultPos].sym.id] + # if the proc body does not set 'result', nor 'return's something + # explicitely, it returns a binary zero, so 'toNil' is correct: + if result == toUndefined: result = toNil else: result = toNil else: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 44d264c1c..fb7f46007 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -480,8 +480,8 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = # n.sons[0] contains the pragmas (if any). We process these later... checkSonsLen(n, 3) if n.sons[1].kind != nkEmpty: - base = semTypeNode(c, n.sons[1].sons[0], nil) - var concreteBase = skipGenericInvokation(skipTypes(base, skipPtrs)) + base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs) + var concreteBase = skipGenericInvokation(base) if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: addInheritedFields(c, check, pos, concreteBase) else: @@ -528,10 +528,10 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode, proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType = result = semTypeNode(c, n, nil) - if (genericParams != nil) and (sonsLen(genericParams) == 0): + if genericParams != nil and sonsLen(genericParams) == 0: result = addTypeVarsOfGenericBody(c, result, genericParams, cl) #if result.kind == tyGenericInvokation: debug(result) - + proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType = var diff --git a/compiler/transf.nim b/compiler/transf.nim index 93b69a597..78814edd8 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -526,12 +526,12 @@ proc gatherVars(c: PTransf, n: PNode, marked: var TIntSet, owner: PSym, container: PNode) = # gather used vars for closure generation case n.kind - of nkSym: + of nkSym: var s = n.sym var found = false case s.kind of skVar: found = sfGlobal notin s.flags - of skTemp, skForVar, skParam: found = true + of skTemp, skForVar, skParam, skResult: found = true else: nil if found and owner.id != s.owner.id and not ContainsOrIncl(marked, s.id): incl(s.flags, sfInClosure) diff --git a/compiler/types.nim b/compiler/types.nim index 83426bed7..2e4262ecc 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -758,8 +758,8 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool = result = typeAllowedNode(marker, n.sons[i], kind) if not result: return -proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = - assert(kind in {skVar, skConst, skParam}) +proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = + assert(kind in {skVar, skConst, skParam, skResult}) # if we have already checked the type, return true, because we stop the # evaluation if something is wrong: result = true @@ -773,13 +773,14 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = of tyVar: result = false # ``var var`` is always an invalid type: of tyOpenArray: - result = (kind == skParam) and typeAllowedAux(marker, t2, kind) - else: result = (kind != skConst) and typeAllowedAux(marker, t2, kind) + result = kind == skParam and typeAllowedAux(marker, t2, kind) + else: + result = kind in {skParam, skResult} and typeAllowedAux(marker, t2, kind) of tyProc: for i in countup(1, sonsLen(t) - 1): result = typeAllowedAux(marker, t.sons[i], skParam) if not result: return - if t.sons[0] != nil: result = typeAllowedAux(marker, t.sons[0], skVar) + if t.sons[0] != nil: result = typeAllowedAux(marker, t.sons[0], skResult) of tyExpr, tyStmt, tyTypeDesc: result = true of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation: @@ -799,10 +800,11 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar) of tySequence: result = (kind != skConst) and typeAllowedAux(marker, t.sons[0], skVar) or - (t.sons[0].kind == tyEmpty) - of tyArray: - result = typeAllowedAux(marker, t.sons[1], skVar) - of tyPtr, tyRef: + t.sons[0].kind == tyEmpty + of tyArray: + result = typeAllowedAux(marker, t.sons[1], skVar) or + t.sons[1].kind == tyEmpty + of tyPtr, tyRef: result = typeAllowedAux(marker, t.sons[0], skVar) of tyArrayConstr, tyTuple, tySet: for i in countup(0, sonsLen(t) - 1): diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index bddcdfb04..0dd9f3eca 100755 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2010 Dominik Picheta +# (c) Copyright 2011 Dominik Picheta # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -87,7 +87,7 @@ proc checkReply(smtp: TSMTP, reply: string) = proc connect*(address: string, port = 25, ssl = false, debug = false): TSMTP = ## Establishes a connection with a SMTP server. - ## May fail with EInvalidReply or with a socket errors. + ## May fail with EInvalidReply or with a socket error. if not ssl: result.sock = socket() @@ -125,7 +125,6 @@ proc sendmail*(smtp: TSMTP, fromaddr: string, ## Sends `msg` from `fromaddr` to `toaddr`. ## Messages may be formed using ``createMessage`` by converting the ## TMessage into a string. - ## This function sends the QUIT command when finished. smtp.debugSend("MAIL FROM:<" & fromaddr & ">\c\L") smtp.checkReply("250") @@ -139,8 +138,9 @@ proc sendmail*(smtp: TSMTP, fromaddr: string, smtp.debugSend(msg & "\c\L") smtp.debugSend(".\c\L") smtp.checkReply("250") - - # quit + +proc close*(smtp: TSMTP) = + ## Disconnects from the SMTP server and closes the socket. smtp.debugSend("QUIT\c\L") if not smtp.ssl: smtp.sock.close() @@ -201,6 +201,6 @@ when isMainModule: smtp.auth("someone", "password") smtp.sendmail("someone@gmail.com", @["someone@yahoo.com", "someone@gmail.com"], $msg) - + smtp.close() diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 242e40d83..62cb385d4 100755 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2009 Andreas Rumpf +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 2028daa50..584282fbc 100755 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -92,6 +92,14 @@ proc `[]`*(t: PStringTable, key: string): string {.rtl, extern: "nstGet".} = if index >= 0: result = t.data[index].val else: result = "" +proc modGet*(t: PStringTable, key: string): var string {. + rtl, extern: "nstTake".} = + ## retrieves the location at ``t[key]``. If `key` is not in `t`, the + ## ``EInvalidValue`` exception is raised. + var index = RawGet(t, key) + if index >= 0: result = t.data[index].val + else: raise newException(EInvalidValue, "key does not exist: " & key) + proc hasKey*(t: PStringTable, key: string): bool {.rtl, extern: "nst$1".} = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 @@ -213,4 +221,6 @@ when isMainModule: assert x["k"] == "v" assert x["11"] == "22" assert x["565"] == "67" + x.modGet("11") = "23" + assert x["11"] == "23" diff --git a/lib/wrappers/gtk/glib2.nim b/lib/wrappers/gtk/glib2.nim index acb85c194..9947e2a4b 100755 --- a/lib/wrappers/gtk/glib2.nim +++ b/lib/wrappers/gtk/glib2.nim @@ -4505,3 +4505,5 @@ proc G_TYPE_GSTRING*(): GType = proc g_thread_init*(vtable: pointer) {. cdecl, dynlib: gobjectlib, importc: "g_thread_init".} +proc g_timeout_add*(interval: guint, function, data: gpointer): guint {. + cdecl, dynlib: gliblib, importc: "g_timeout_add".} diff --git a/tests/accept/run/teventemitter.nim b/tests/accept/run/teventemitter.nim new file mode 100644 index 000000000..6ebe994b1 --- /dev/null +++ b/tests/accept/run/teventemitter.nim @@ -0,0 +1,23 @@ +import tables +import lists +type + TEventArgs = object of TObject +type + TEventEmitter = object of TObject + events*: TTable[string, TDoublyLinkedList[proc(e : TEventArgs)]] +proc on*(emitter : var TEventEmitter, event : string, func : proc(e : TEventArgs)) = + if hasKey(emitter.events, event) == false: + var list: TDoublyLinkedList[proc(e : TEventArgs)] + add(emitter.events,event,list) #if not, add it. + append(emitter.events[event], func) #adds the function to the event's list. I get a error here too. + +proc emit*(emitter : TEventEmitter, event : string, args : TEventArgs) = + for func in items(emitter.events[event]): + func(args) #call function with args. +proc initEmitter(emitter : TEventEmitter) = + emitter.events = initTable[string, TSinglyLinkedList[TObject]]() + +var ee : TEventEmitter +ee.on("print", proc(e : TEventArgs) = echo("pie")) +ee.emit("print") + diff --git a/tests/accept/run/tvarres1.nim b/tests/accept/run/tvarres1.nim new file mode 100644 index 000000000..a48c961df --- /dev/null +++ b/tests/accept/run/tvarres1.nim @@ -0,0 +1,15 @@ +discard """ + output: "45" +""" + +var + g = 5 + +proc p(): var int = + var bla = addr(g) #: array [0..7, int] + result = bla[] + +p() = 45 + +echo g + diff --git a/tests/accept/run/tvarres2.nim b/tests/accept/run/tvarres2.nim new file mode 100644 index 000000000..119560e7b --- /dev/null +++ b/tests/accept/run/tvarres2.nim @@ -0,0 +1,20 @@ +discard """ + output: "45 hallo" +""" + +type + TKachel = tuple[i: int, s: string] + TSpielwiese = object + k: seq[TKachel] + +var + spielwiese: TSpielwiese +newSeq(spielwiese.k, 64) + +proc at*(s: var TSpielwiese, x, y: int): var TKachel = + result = s.k[y * 8 + x] + +spielwiese.at(3, 4) = (45, "hallo") + +echo spielwiese.at(3,4)[0], " ", spielwiese.at(3,4)[1] + diff --git a/tests/reject/tvarres1.nim b/tests/reject/tvarres1.nim new file mode 100644 index 000000000..de4a505d3 --- /dev/null +++ b/tests/reject/tvarres1.nim @@ -0,0 +1,17 @@ +discard """ + file: "tvarres1.nim" + line: 12 + errormsg: "address of 'bla' may not escape its stack frame" +""" + +var + g = 5 + +proc p(): var int = + var bla: int + result = bla + +p() = 45 + +echo g + diff --git a/tests/reject/tvarres2.nim b/tests/reject/tvarres2.nim new file mode 100644 index 000000000..6bda844fc --- /dev/null +++ b/tests/reject/tvarres2.nim @@ -0,0 +1,16 @@ +discard """ + file: "tvarres1.nim" + line: 11 + errormsg: "expression has no address" +""" + +var + g = 5 + +proc p(): var int = + result = 89 + +p() = 45 + +echo g + diff --git a/todo.txt b/todo.txt index 635f5f566..45b7e47b3 100755 --- a/todo.txt +++ b/todo.txt @@ -1,8 +1,11 @@ Version 0.8.14 ============== -- ``var T`` as a return type; easy to prove that location does not escape its - stack frame +- ``var T`` as a return type: + * for iterators + * add ``modGet`` for generics + * documentation + * provide ``mod`` as an alternative syntax for ``var`` - document Nimrod's two phase symbol lookup for generics - optional indentation for 'case' statement - make threadvar efficient again on linux after testing @@ -41,7 +44,6 @@ version 0.9.XX proc specialization in the code gen - resizing of strings/sequences could take into account the memory that is allocated -- typeAllowed() for parameters... - find a way to reintroduce the cleanup() pass for C code generation: this is hard because of partial evaluation --> symbol files will fix this as a side effect |