bugfixes; step one for 'var T' as return type support

This commit is contained in:
Araq 2011-07-28 00:53:52 +02:00
commit 2f066395ba
27 changed files with 234 additions and 68 deletions

View file

@ -186,8 +186,8 @@ type
nkReturnToken # token used for interpretation nkReturnToken # token used for interpretation
TNodeKinds* = set[TNodeKind] TNodeKinds* = set[TNodeKind]
type type
TSymFlag* = enum # already 30 flags! TSymFlag* = enum # already 29 flags!
sfUsed, # read access of sym (for warnings) or simply used sfUsed, # read access of sym (for warnings) or simply used
sfStar, # symbol has * visibility sfStar, # symbol has * visibility
sfMinus, # symbol has - visibility sfMinus, # symbol has - visibility
@ -204,7 +204,6 @@ type
sfRegister, # variable should be placed in a register sfRegister, # variable should be placed in a register
sfPure, # object is "pure" that means it has no type-information sfPure, # object is "pure" that means it has no type-information
sfResult, # variable is 'result' in proc
sfNoSideEffect, # proc has no side effects sfNoSideEffect, # proc has no side effects
sfSideEffect, # proc may have side effects; cannot prove it has none sfSideEffect, # proc may have side effects; cannot prove it has none
sfMainModule, # module is the main module sfMainModule, # module is the main module
@ -293,6 +292,7 @@ type
skType, # a type skType, # a type
skConst, # a constant skConst, # a constant
skVar, # a variable skVar, # a variable
skResult, # special 'result' variable
skProc, # a proc skProc, # a proc
skMethod, # a method skMethod, # a method
skIterator, # an iterator skIterator, # an iterator

View file

@ -136,7 +136,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
case n.sym.kind case n.sym.kind
of skParam, skForVar, skTemp: of skParam, skForVar, skTemp:
result = OnStack result = OnStack
of skVar: of skVar, skResult:
if sfGlobal in n.sym.flags: result = OnHeap if sfGlobal in n.sym.flags: result = OnHeap
else: result = OnStack else: result = OnStack
of skConst: of skConst:
@ -206,6 +206,10 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# This function replaces all other methods for generating # This function replaces all other methods for generating
# the assignment operation in C. # 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) var ty = skipTypes(dest.t, abstractVarRange)
case ty.kind case ty.kind
of tyRef: of tyRef:
@ -1648,7 +1652,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
genComplexConst(p, sym, d) genComplexConst(p, sym, d)
of skEnumField: of skEnumField:
putIntoDest(p, d, e.typ, toRope(sym.position)) putIntoDest(p, d, e.typ, toRope(sym.position))
of skVar: of skVar, skResult:
if sfGlobal in sym.flags: genVarPrototype(p.module, sym) if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
if ((sym.loc.r == nil) or (sym.loc.t == nil)): if ((sym.loc.r == nil) or (sym.loc.t == nil)):
InternalError(e.info, "expr: var not init " & sym.name.s) InternalError(e.info, "expr: var not init " & sym.name.s)

View file

@ -37,7 +37,7 @@ proc mangleName(s: PSym): PRope =
case s.kind case s.kind
of skProc, skMethod, skConverter, skConst: of skProc, skMethod, skConverter, skConst:
result = toRope("@") result = toRope("@")
of skVar: of skVar, skResult:
if sfGlobal in s.flags: result = toRope("@") if sfGlobal in s.flags: result = toRope("@")
else: result = toRope("%") else: result = toRope("%")
of skForVar, skTemp, skParam, skType, skEnumField, skModule: of skForVar, skTemp, skParam, skType, skEnumField, skModule:
@ -153,7 +153,7 @@ proc getGlobalTempName(): PRope =
proc ccgIntroducedPtr(s: PSym): bool = proc ccgIntroducedPtr(s: PSym): bool =
var pt = s.typ var pt = s.typ
assert(not (sfResult in s.flags)) assert skResult != s.kind
case pt.Kind case pt.Kind
of tyObject: of tyObject:
# XXX quick hack floatSize*2 for the pegs module under 64bit # XXX quick hack floatSize*2 for the pegs module under 64bit

View file

@ -534,7 +534,7 @@ proc cgsym(m: BModule, name: string): PRope =
if sym != nil: if sym != nil:
case sym.kind case sym.kind
of skProc, skMethod, skConverter: genProc(m, sym) 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) of skType: discard getTypeDesc(m, sym.typ)
else: InternalError("cgsym: " & name) else: InternalError("cgsym: " & name)
else: else:

View file

@ -810,7 +810,7 @@ proc generateDoc(d: PDoc, n: PNode) =
proc genSection(d: PDoc, kind: TSymKind) = proc genSection(d: PDoc, kind: TSymKind) =
const sectionNames: array[skModule..skTemplate, string] = [ const sectionNames: array[skModule..skTemplate, string] = [
"Imports", "Types", "Consts", "Vars", "Procs", "Methods", "Imports", "Types", "Consts", "Vars", "Vars", "Procs", "Methods",
"Iterators", "Converters", "Macros", "Templates" "Iterators", "Converters", "Macros", "Templates"
] ]
if d.section[kind] == nil: return if d.section[kind] == nil: return

View file

@ -832,7 +832,7 @@ proc genAddr(p: var TProc, n: PNode, r: var TCompRes) =
s = n.sons[0].sym s = n.sons[0].sym
if s.loc.r == nil: InternalError(n.info, "genAddr: 3") if s.loc.r == nil: InternalError(n.info, "genAddr: 3")
case s.kind case s.kind
of skVar: of skVar, skResult:
if mapType(n.typ) == etyObject: if mapType(n.typ) == etyObject:
# make addr() a no-op: # make addr() a no-op:
r.kind = etyNone r.kind = etyNone
@ -863,7 +863,7 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) =
if s.loc.r == nil: if s.loc.r == nil:
InternalError(n.info, "symbol has no generated name: " & s.name.s) InternalError(n.info, "symbol has no generated name: " & s.name.s)
case s.kind case s.kind
of skVar, skParam, skTemp: of skVar, skParam, skTemp, skResult:
var k = mapType(s.typ) var k = mapType(s.typ)
if k == etyBaseIndex: if k == etyBaseIndex:
r.kind = etyBaseIndex r.kind = etyBaseIndex

View file

@ -293,7 +293,7 @@ proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
# which can be modified. # which can be modified.
var x = c var x = c
while x != nil: while x != nil:
if sfResult in sym.flags: if sym.kind == skResult:
result = x.params[0] result = x.params[0]
if result == nil: result = emptyNode if result == nil: result = emptyNode
return return
@ -425,7 +425,8 @@ proc evalSwap(c: PEvalContext, n: PNode): PNode =
proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
case n.sym.kind case n.sym.kind
of skProc, skConverter, skMacro: result = n.sym.ast.sons[codePos] 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: of skParam:
# XXX what about LValue? # XXX what about LValue?
result = c.tos.params[n.sym.position + 1] result = c.tos.params[n.sym.position + 1]

View file

@ -393,7 +393,7 @@ proc UseMagic(m: BModule, name: string) =
if sym != nil: if sym != nil:
case sym.kind case sym.kind
of skProc, skMethod, skConverter: genProc(m, sym) 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) of skType: discard getTypeDesc(m, sym.typ)
else: InternalError("useMagic: " & name) else: InternalError("useMagic: " & name)
elif not (sfSystemModule in m.module.flags): elif not (sfSystemModule in m.module.flags):

View file

@ -56,7 +56,8 @@ type
errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig, errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,
errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects, errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX, errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
errCannotInstantiateX, errExprHasNoAddress, errVarForOutParamNeeded, errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
errVarForOutParamNeeded,
errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX, errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
errAmbiguousCallXYZ, errWrongNumberOfArguments, errXCannotBePassedToProcVar, errAmbiguousCallXYZ, errWrongNumberOfArguments, errXCannotBePassedToProcVar,
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
@ -227,6 +228,7 @@ const
errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'", errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'",
errCannotInstantiateX: "cannot instantiate: \'$1\'", errCannotInstantiateX: "cannot instantiate: \'$1\'",
errExprHasNoAddress: "expression has no address", 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", errVarForOutParamNeeded: "for a \'var\' type a variable needs to be passed",
errPureTypeMismatch: "type mismatch", errPureTypeMismatch: "type mismatch",
errTypeMismatch: "type mismatch: got (", errTypeMismatch: "type mismatch: got (",

View file

@ -50,6 +50,10 @@ proc addResult(c: PContext, t: PType, info: TLineInfo)
proc addResultNode(c: PContext, n: PNode) proc addResultNode(c: PContext, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType 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 = proc semConstExpr(c: PContext, n: PNode): PNode =
result = semExprWithType(c, n) result = semExprWithType(c, n)
if result == nil: if result == nil:

View file

@ -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 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 = proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExpr(c, n, flags) result = semExpr(c, n, flags)
if result.kind == nkEmpty: if result.kind == nkEmpty:
# do not produce another redundant error message: # do not produce another redundant error message:
raiseRecoverableError() raiseRecoverableError()
if result.typ != nil: if result.typ != nil:
if result.typ.kind == tyVar: if result.typ.kind == tyVar: result = newDeref(result)
var d = newNodeIT(nkHiddenDeref, result.info, result.typ.sons[0])
addSon(d, result)
result = d
else: else:
GlobalError(n.info, errExprXHasNoType, GlobalError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments})) 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 = proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s) 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) result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, s) of skMacro: result = semMacroExpr(c, n, s)
of skTemplate: result = semTemplateExpr(c, n, s) of skTemplate: result = semTemplateExpr(c, n, s)
of skVar: of skVar, skResult:
markUsed(n, s) markUsed(n, s)
# if a proc accesses a global variable, it is not side effect free: # if a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect) if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect)
@ -330,33 +341,37 @@ type
TAssignableResult = enum TAssignableResult = enum
arNone, # no l-value and no discriminant arNone, # no l-value and no discriminant
arLValue, # is an l-value arLValue, # is an l-value
arLocalLValue, # is an l-value, but local var; must not escape
# its stack frame!
arDiscriminant # is a discriminant arDiscriminant # is a discriminant
proc isAssignable(n: PNode): TAssignableResult = proc isAssignable(c: PContext, n: PNode): TAssignableResult =
result = arNone result = arNone
case n.kind case n.kind
of nkSym: of nkSym:
if n.sym.kind in {skVar, skTemp}: result = arLValue if n.sym.kind in {skVar, skResult, skTemp}:
if c.p.owner.id == n.sym.owner.id: result = arLocalLValue
else: result = arLValue
of nkDotExpr: of nkDotExpr:
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}:
result = arLValue result = arLValue
else: else:
result = isAssignable(n.sons[0]) result = isAssignable(c, n.sons[0])
if result == arLValue and sfDiscriminant in n.sons[1].sym.flags: if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
result = arDiscriminant result = arDiscriminant
of nkBracketExpr: of nkBracketExpr:
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}:
result = arLValue result = arLValue
else: else:
result = isAssignable(n.sons[0]) result = isAssignable(c, n.sons[0])
of nkHiddenStdConv, nkHiddenSubConv, nkConv: of nkHiddenStdConv, nkHiddenSubConv, nkConv:
# Object and tuple conversions are still addressable, so we skip them # Object and tuple conversions are still addressable, so we skip them
if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}: if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}:
result = isAssignable(n.sons[1]) result = isAssignable(c, n.sons[1])
of nkHiddenDeref, nkDerefExpr: of nkHiddenDeref, nkDerefExpr:
result = arLValue result = arLValue
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isAssignable(n.sons[0]) result = isAssignable(c, n.sons[0])
else: else:
nil nil
@ -367,7 +382,7 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
else: else:
result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ)) result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
addSon(result, n) addSon(result, n)
if isAssignable(n) != arLValue: if isAssignable(c, n) notin {arLValue, arLocalLValue}:
localError(n.info, errVarForOutParamNeeded) localError(n.info, errVarForOutParamNeeded)
proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = 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): for i in countup(1, sonsLen(n) - 1):
if i < sonsLen(t) and t.sons[i] != nil and if i < sonsLen(t) and t.sons[i] != nil and
skipTypes(t.sons[i], abstractInst).kind == tyVar: 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) LocalError(n.sons[i].info, errVarForOutParamNeeded)
return return
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
@ -751,7 +766,30 @@ proc propertyWriteAccess(c: PContext, n, a: PNode): PNode =
else: else:
globalError(n.Info, errUndeclaredFieldX, id.s) 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) checkSonsLen(n, 2)
var a = n.sons[0] var a = n.sons[0]
case a.kind case a.kind
@ -762,8 +800,8 @@ proc semAsgn(c: PContext, n: PNode): PNode =
if a == nil: if a == nil:
return propertyWriteAccess(c, n, n[0]) return propertyWriteAccess(c, n, n[0])
of nkBracketExpr: of nkBracketExpr:
# a[i..j] = x # a[i] = x
# --> `[..]=`(a, i, j, x) # --> `[]=`(a, i, x)
a = semSubscript(c, a, {efLValue}) a = semSubscript(c, a, {efLValue})
if a == nil: if a == nil:
result = buildOverloadedSubscripts(n.sons[0], inAsgn=true) result = buildOverloadedSubscripts(n.sons[0], inAsgn=true)
@ -772,15 +810,19 @@ proc semAsgn(c: PContext, n: PNode): PNode =
else: else:
a = semExprWithType(c, a, {efLValue}) a = semExprWithType(c, a, {efLValue})
n.sons[0] = a 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 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! # Direct assignment to a discriminant is allowed!
localError(a.info, errXCannotBeAssignedTo, localError(a.info, errXCannotBeAssignedTo,
renderTree(a, {renderNoComments})) renderTree(a, {renderNoComments}))
else: else:
n.sons[1] = semExprWithType(c, n.sons[1])
n.sons[1] = fitNode(c, le, n.sons[1]) n.sons[1] = fitNode(c, le, n.sons[1])
fixAbstractType(c, n) fixAbstractType(c, n)
asgnToResultVar(c, n, n.sons[0], n.sons[1])
result = n result = n
proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym = proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym =
@ -1144,7 +1186,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = n result = n
checkSonsLen(n, 1) checkSonsLen(n, 1)
n.sons[0] = semExprWithType(c, n.sons[0]) 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) GlobalError(n.info, errExprHasNoAddress)
n.typ = makePtrType(c, n.sons[0].typ) n.typ = makePtrType(c, n.sons[0].typ)
of nkHiddenAddr, nkHiddenDeref: of nkHiddenAddr, nkHiddenDeref:

View file

@ -100,6 +100,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
result.typ = newTypeS(tyProc, c) result.typ = newTypeS(tyProc, c)
addSon(result.typ, nil) addSon(result.typ, nil)
result.typ.callConv = fn.typ.callConv result.typ.callConv = fn.typ.callConv
ParamsTypeCheck(c, result.typ)
var oldPrc = GenericCacheGet(c, entry) var oldPrc = GenericCacheGet(c, entry)
if oldPrc == nil: if oldPrc == nil:
# add it here, so that recursive generic procs are possible: # add it here, so that recursive generic procs are possible:

View file

@ -164,7 +164,7 @@ proc SemReturn(c: PContext, n: PNode): PNode =
addSon(a, n.sons[0]) addSon(a, n.sons[0])
n.sons[0] = semAsgn(c, a) n.sons[0] = semAsgn(c, a)
# optimize away ``result = result``: # 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 n.sons[0] = ast.emptyNode
proc SemYield(c: PContext, n: PNode): PNode = 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) = proc addResult(c: PContext, t: PType, info: TLineInfo) =
if t != nil: if t != nil:
var s = newSym(skVar, getIdent"result", getCurrOwner()) var s = newSym(skResult, getIdent"result", getCurrOwner())
s.info = info s.info = info
s.typ = t s.typ = t
incl(s.flags, sfResult)
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
addDecl(c, s) addDecl(c, s)
c.p.resultSym = s c.p.resultSym = s
@ -569,7 +568,8 @@ proc semLambda(c: PContext, n: PNode): PNode =
if n.sons[paramsPos].kind != nkEmpty: if n.sons[paramsPos].kind != nkEmpty:
semParamList(c, n.sons[ParamsPos], nil, s) semParamList(c, n.sons[ParamsPos], nil, s)
addParams(c, s.typ.n) addParams(c, s.typ.n)
else: ParamsTypeCheck(c, s.typ)
else:
s.typ = newTypeS(tyProc, c) s.typ = newTypeS(tyProc, c)
addSon(s.typ, nil) addSon(s.typ, nil)
s.typ.callConv = ccClosure s.typ.callConv = ccClosure
@ -664,6 +664,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if sfBorrow in s.flags: if sfBorrow in s.flags:
LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s) LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s)
if n.sons[genericParamsPos].kind == nkEmpty: if n.sons[genericParamsPos].kind == nkEmpty:
ParamsTypeCheck(c, s.typ)
pushProcCon(c, s) pushProcCon(c, s)
if (s.typ.sons[0] != nil) and (kind != skIterator): if (s.typ.sons[0] != nil) and (kind != skIterator):
addResult(c, s.typ.sons[0], n.info) addResult(c, s.typ.sons[0], n.info)

View file

@ -107,7 +107,7 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner =
result = c.mapping[v.id] result = c.mapping[v.id]
if result != toUndefined: return if result != toUndefined: return
case v.kind case v.kind
of skVar: of skVar, skResult:
result = toNil result = toNil
if sfGlobal in v.flags: if sfGlobal in v.flags:
if sfThreadVar 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 if prc.ast.sons[codePos].kind == nkEmpty and
{sfNoSideEffect, sfThread, sfImportc} * prc.flags == {}: {sfNoSideEffect, sfThread, sfImportc} * prc.flags == {}:
Message(n.info, warnAnalysisLoophole, renderTree(n)) Message(n.info, warnAnalysisLoophole, renderTree(n))
if result == toUndefined: result = toNil
if prc.typ.sons[0] != nil: if prc.typ.sons[0] != nil:
if prc.ast.len > resultPos: if prc.ast.len > resultPos:
result = newCtx.mapping[prc.ast.sons[resultPos].sym.id] 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: else:
result = toNil result = toNil
else: else:

View file

@ -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... # n.sons[0] contains the pragmas (if any). We process these later...
checkSonsLen(n, 3) checkSonsLen(n, 3)
if n.sons[1].kind != nkEmpty: if n.sons[1].kind != nkEmpty:
base = semTypeNode(c, n.sons[1].sons[0], nil) base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
var concreteBase = skipGenericInvokation(skipTypes(base, skipPtrs)) var concreteBase = skipGenericInvokation(base)
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
addInheritedFields(c, check, pos, concreteBase) addInheritedFields(c, check, pos, concreteBase)
else: else:
@ -528,10 +528,10 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType = proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
result = semTypeNode(c, n, nil) 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) result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
#if result.kind == tyGenericInvokation: debug(result) #if result.kind == tyGenericInvokation: debug(result)
proc semProcTypeNode(c: PContext, n, genericParams: PNode, proc semProcTypeNode(c: PContext, n, genericParams: PNode,
prev: PType): PType = prev: PType): PType =
var var

View file

@ -526,12 +526,12 @@ proc gatherVars(c: PTransf, n: PNode, marked: var TIntSet, owner: PSym,
container: PNode) = container: PNode) =
# gather used vars for closure generation # gather used vars for closure generation
case n.kind case n.kind
of nkSym: of nkSym:
var s = n.sym var s = n.sym
var found = false var found = false
case s.kind case s.kind
of skVar: found = sfGlobal notin s.flags of skVar: found = sfGlobal notin s.flags
of skTemp, skForVar, skParam: found = true of skTemp, skForVar, skParam, skResult: found = true
else: nil else: nil
if found and owner.id != s.owner.id and not ContainsOrIncl(marked, s.id): if found and owner.id != s.owner.id and not ContainsOrIncl(marked, s.id):
incl(s.flags, sfInClosure) incl(s.flags, sfInClosure)

View file

@ -758,8 +758,8 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
result = typeAllowedNode(marker, n.sons[i], kind) result = typeAllowedNode(marker, n.sons[i], kind)
if not result: return if not result: return
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
assert(kind in {skVar, skConst, skParam}) assert(kind in {skVar, skConst, skParam, skResult})
# if we have already checked the type, return true, because we stop the # if we have already checked the type, return true, because we stop the
# evaluation if something is wrong: # evaluation if something is wrong:
result = true result = true
@ -773,13 +773,14 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
of tyVar: of tyVar:
result = false # ``var var`` is always an invalid type: result = false # ``var var`` is always an invalid type:
of tyOpenArray: of tyOpenArray:
result = (kind == skParam) and typeAllowedAux(marker, t2, kind) result = kind == skParam and typeAllowedAux(marker, t2, kind)
else: result = (kind != skConst) and typeAllowedAux(marker, t2, kind) else:
result = kind in {skParam, skResult} and typeAllowedAux(marker, t2, kind)
of tyProc: of tyProc:
for i in countup(1, sonsLen(t) - 1): for i in countup(1, sonsLen(t) - 1):
result = typeAllowedAux(marker, t.sons[i], skParam) result = typeAllowedAux(marker, t.sons[i], skParam)
if not result: return 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: of tyExpr, tyStmt, tyTypeDesc:
result = true result = true
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation: 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) result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar)
of tySequence: of tySequence:
result = (kind != skConst) and typeAllowedAux(marker, t.sons[0], skVar) or result = (kind != skConst) and typeAllowedAux(marker, t.sons[0], skVar) or
(t.sons[0].kind == tyEmpty) t.sons[0].kind == tyEmpty
of tyArray: of tyArray:
result = typeAllowedAux(marker, t.sons[1], skVar) result = typeAllowedAux(marker, t.sons[1], skVar) or
of tyPtr, tyRef: t.sons[1].kind == tyEmpty
of tyPtr, tyRef:
result = typeAllowedAux(marker, t.sons[0], skVar) result = typeAllowedAux(marker, t.sons[0], skVar)
of tyArrayConstr, tyTuple, tySet: of tyArrayConstr, tyTuple, tySet:
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):

View file

@ -1,7 +1,7 @@
# #
# #
# Nimrod's Runtime Library # Nimrod's Runtime Library
# (c) Copyright 2010 Dominik Picheta # (c) Copyright 2011 Dominik Picheta
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -87,7 +87,7 @@ proc checkReply(smtp: TSMTP, reply: string) =
proc connect*(address: string, port = 25, proc connect*(address: string, port = 25,
ssl = false, debug = false): TSMTP = ssl = false, debug = false): TSMTP =
## Establishes a connection with a SMTP server. ## 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: if not ssl:
result.sock = socket() result.sock = socket()
@ -125,7 +125,6 @@ proc sendmail*(smtp: TSMTP, fromaddr: string,
## Sends `msg` from `fromaddr` to `toaddr`. ## Sends `msg` from `fromaddr` to `toaddr`.
## Messages may be formed using ``createMessage`` by converting the ## Messages may be formed using ``createMessage`` by converting the
## TMessage into a string. ## TMessage into a string.
## This function sends the QUIT command when finished.
smtp.debugSend("MAIL FROM:<" & fromaddr & ">\c\L") smtp.debugSend("MAIL FROM:<" & fromaddr & ">\c\L")
smtp.checkReply("250") smtp.checkReply("250")
@ -139,8 +138,9 @@ proc sendmail*(smtp: TSMTP, fromaddr: string,
smtp.debugSend(msg & "\c\L") smtp.debugSend(msg & "\c\L")
smtp.debugSend(".\c\L") smtp.debugSend(".\c\L")
smtp.checkReply("250") smtp.checkReply("250")
# quit proc close*(smtp: TSMTP) =
## Disconnects from the SMTP server and closes the socket.
smtp.debugSend("QUIT\c\L") smtp.debugSend("QUIT\c\L")
if not smtp.ssl: if not smtp.ssl:
smtp.sock.close() smtp.sock.close()
@ -201,6 +201,6 @@ when isMainModule:
smtp.auth("someone", "password") smtp.auth("someone", "password")
smtp.sendmail("someone@gmail.com", smtp.sendmail("someone@gmail.com",
@["someone@yahoo.com", "someone@gmail.com"], $msg) @["someone@yahoo.com", "someone@gmail.com"], $msg)
smtp.close()

View file

@ -1,7 +1,7 @@
# #
# #
# Nimrod's Runtime Library # Nimrod's Runtime Library
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.

View file

@ -92,6 +92,14 @@ proc `[]`*(t: PStringTable, key: string): string {.rtl, extern: "nstGet".} =
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: result = "" 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".} = proc hasKey*(t: PStringTable, key: string): bool {.rtl, extern: "nst$1".} =
## returns true iff `key` is in the table `t`. ## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0 result = rawGet(t, key) >= 0
@ -213,4 +221,6 @@ when isMainModule:
assert x["k"] == "v" assert x["k"] == "v"
assert x["11"] == "22" assert x["11"] == "22"
assert x["565"] == "67" assert x["565"] == "67"
x.modGet("11") = "23"
assert x["11"] == "23"

View file

@ -4505,3 +4505,5 @@ proc G_TYPE_GSTRING*(): GType =
proc g_thread_init*(vtable: pointer) {. proc g_thread_init*(vtable: pointer) {.
cdecl, dynlib: gobjectlib, importc: "g_thread_init".} cdecl, dynlib: gobjectlib, importc: "g_thread_init".}
proc g_timeout_add*(interval: guint, function, data: gpointer): guint {.
cdecl, dynlib: gliblib, importc: "g_timeout_add".}

View file

@ -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")

View file

@ -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

View file

@ -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]

17
tests/reject/tvarres1.nim Normal file
View file

@ -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

16
tests/reject/tvarres2.nim Normal file
View file

@ -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

View file

@ -1,8 +1,11 @@
Version 0.8.14 Version 0.8.14
============== ==============
- ``var T`` as a return type; easy to prove that location does not escape its - ``var T`` as a return type:
stack frame * for iterators
* add ``modGet`` for generics
* documentation
* provide ``mod`` as an alternative syntax for ``var``
- document Nimrod's two phase symbol lookup for generics - document Nimrod's two phase symbol lookup for generics
- optional indentation for 'case' statement - optional indentation for 'case' statement
- make threadvar efficient again on linux after testing - make threadvar efficient again on linux after testing
@ -41,7 +44,6 @@ version 0.9.XX
proc specialization in the code gen proc specialization in the code gen
- resizing of strings/sequences could take into account the memory that - resizing of strings/sequences could take into account the memory that
is allocated is allocated
- typeAllowed() for parameters...
- find a way to reintroduce the cleanup() pass for C code generation: this - 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 is hard because of partial evaluation --> symbol files will fix this as
a side effect a side effect