summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2014-03-10 22:23:38 +0100
committerAraq <rumpf_a@web.de>2014-03-10 22:23:38 +0100
commit3270676e77676335446287fcff05aa6a6b9b4919 (patch)
tree4bd724bed5ae887efa9d8f97494755715980ca20
parent121553d1a69c4d175259944f6bdc9f9dcfda9cdd (diff)
parent1546d210c5739213ebf93eb0cb624ca7a9fe9ad6 (diff)
downloadNim-3270676e77676335446287fcff05aa6a6b9b4919.tar.gz
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
-rw-r--r--compiler/ast.nim4
-rw-r--r--compiler/astalgo.nim8
-rw-r--r--compiler/guards.nim4
-rw-r--r--compiler/msgs.nim6
-rw-r--r--compiler/sem.nim7
-rw-r--r--compiler/semcall.nim12
-rw-r--r--compiler/semexprs.nim62
-rw-r--r--compiler/seminst.nim2
-rw-r--r--compiler/semstmts.nim18
-rw-r--r--compiler/semtempl.nim4
-rw-r--r--compiler/semtypes.nim99
-rw-r--r--compiler/semtypinst.nim16
-rw-r--r--compiler/sigmatch.nim19
-rw-r--r--compiler/transf.nim12
-rw-r--r--compiler/vm.nim4
-rw-r--r--doc/manual.txt24
-rw-r--r--lib/impure/db_mysql.nim10
-rw-r--r--lib/nimbase.h3
-rw-r--r--lib/posix/epoll.nim2
-rw-r--r--lib/pure/asyncio2.nim28
-rw-r--r--lib/pure/selectors.nim26
-rw-r--r--lib/pure/sockets2.nim22
-rw-r--r--lib/system.nim53
-rw-r--r--tests/async/tasyncawait.nim10
-rw-r--r--tests/generics/tgenericshardcases.nim18
-rw-r--r--tests/iter/tchainediterators.nim38
-rw-r--r--tests/iter/titerable.nim26
-rw-r--r--tests/metatype/tstaticparams.nim26
-rw-r--r--tests/overload/tissue966.nim12
-rw-r--r--tests/static/tstaticparammacro.nim52
-rw-r--r--tests/system/alloc.nim37
-rw-r--r--tests/template/tissue909.nim16
-rw-r--r--tests/testament/htmlgen.nim18
-rw-r--r--tests/vm/tstaticprintseq.nim36
34 files changed, 567 insertions, 167 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 9c9dfce9a..f9cab0d88 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -818,6 +818,9 @@ type
counter*: int
data*: TObjectSeq
+ TImplication* = enum
+ impUnknown, impNo, impYes
+
# BUGFIX: a module is overloadable so that a proc can have the
# same name as an imported module. This is necessary because of
# the poor naming choices in the standard library.
@@ -865,6 +868,7 @@ const
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit, nkHiddenCallConv}
+ nkLiterals* = {nkCharLit..nkTripleStrLit}
nkLambdaKinds* = {nkLambda, nkDo}
declarativeDefs* = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
procDefs* = nkLambdaKinds + declarativeDefs
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index cce2cc215..36dd7f562 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -50,7 +50,7 @@ proc strTableGet*(t: TStrTable, name: PIdent): PSym
type
TTabIter*{.final.} = object # consider all fields here private
h*: THash # current hash
-
+
proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
# usage:
@@ -157,6 +157,12 @@ proc leValue*(a, b: PNode): bool =
#InternalError(a.info, "leValue")
discard
+proc weakLeValue*(a, b: PNode): TImplication =
+ if a.kind notin nkLiterals or b.kind notin nkLiterals:
+ result = impUnknown
+ else:
+ result = if leValue(a, b): impYes else: impNo
+
proc lookupInRecord(n: PNode, field: PIdent): PSym =
result = nil
case n.kind
diff --git a/compiler/guards.nim b/compiler/guards.nim
index fe868054f..f475f5068 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -274,10 +274,6 @@ proc pred(n: PNode): PNode =
else:
result = n
-type
- TImplication* = enum
- impUnknown, impNo, impYes
-
proc impliesEq(fact, eq: PNode): TImplication =
let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 66763e7f5..5bc490d14 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -96,8 +96,8 @@ type
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
errMacroBodyDependsOnGenericTypes,
errDestructorNotGenericEnough,
-
- errXExpectsTwoArguments,
+ errInlineIteratorsAsProcParams,
+ errXExpectsTwoArguments,
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
@@ -331,6 +331,8 @@ const
"because the parameter '$1' has a generic type",
errDestructorNotGenericEnough: "Destructor signarue is too specific. " &
"A destructor must be associated will all instantiations of a generic type",
+ errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
+ "templates, macros and other inline iterators",
errXExpectsTwoArguments: "\'$1\' expects two arguments",
errXExpectsObjectTypes: "\'$1\' expects object types",
errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 5ee46654e..c8228618b 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -139,6 +139,10 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
result = n.sym
internalAssert sfGenSym in result.flags
internalAssert result.kind == kind
+ # when there is a nested proc inside a template, semtmpl
+ # will assign a wrong owner during the first pass over the
+ # template; we must fix it here: see #909
+ result.owner = getCurrOwner()
else:
result = newSym(kind, considerAcc(n), getCurrOwner(), n.info)
@@ -194,7 +198,8 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
result = semExprWithType(c, evaluated)
else:
result = evaluated
- semmacrosanity.annotateType(result, eOrig.typ)
+ let expectedType = eOrig.typ.skipTypes({tyStatic})
+ semmacrosanity.annotateType(result, expectedType)
else:
result = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case:
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 2e5def75a..5d480bc98 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -82,7 +82,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
# fail fast:
globalError(n.info, errTypeMismatch, "")
var result = msgKindToString(errTypeMismatch)
- add(result, describeArgs(c, n, 1 + ord(nfDotField in n.flags)))
+ add(result, describeArgs(c, n, 1))
add(result, ')')
var candidates = ""
@@ -114,7 +114,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
var errors: seq[string]
var usedSyms: seq[PNode]
-
+
template pickBest(headSymbol: expr) =
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
filter, result, alt, errors)
@@ -166,7 +166,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
n.sons[0..1] = [callOp, n[1], calleeName]
orig.sons[0..1] = [callOp, orig[1], calleeName]
pickBest(callOp)
-
+
if overloadsState == csEmpty and result.state == csEmpty:
localError(n.info, errUndeclaredIdentifier, considerAcc(f).s)
return
@@ -175,9 +175,15 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
localError(n.info, errExprXCannotBeCalled,
renderTree(n, {renderNoComments}))
else:
+ if {nfDotField, nfDotSetter} * n.flags != {}:
+ # clean up the inserted ops
+ n.sons.delete(2)
+ n.sons[0] = f
+
errors = @[]
pickBest(f)
notFoundError(c, n, errors)
+
return
if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 203a51816..62a816a50 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -885,7 +885,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
of nkSym:
if r.sym.name.id == field.id: result = r.sym
else: illFormedAst(n)
-
+
proc makeDeref(n: PNode): PNode =
var t = skipTypes(n.typ, {tyGenericInst})
result = n
@@ -899,6 +899,21 @@ proc makeDeref(n: PNode): PNode =
addSon(result, a)
t = skipTypes(t.sons[0], {tyGenericInst})
+proc readTypeParameter(c: PContext, ty: PType,
+ paramName: PIdent, info: TLineInfo): PNode =
+ internalAssert ty.kind == tyGenericInst
+ let ty = ty.skipGenericAlias
+ let tbody = ty.sons[0]
+ for s in countup(0, tbody.len-2):
+ let tParam = tbody.sons[s]
+ if tParam.sym.name == paramName:
+ let rawTyp = ty.sons[s + 1]
+ if rawTyp.kind == tyStatic:
+ return rawTyp.n
+ else:
+ let foundTyp = makeTypeDesc(c, rawTyp)
+ return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
+
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
## returns nil if it's not a built-in field access
checkSonsLen(n, 2)
@@ -916,7 +931,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
var ty = n.sons[0].typ
var f: PSym = nil
result = nil
- if isTypeExpr(n.sons[0]) or ty.kind == tyTypeDesc and ty.base.kind != tyNone:
+ if isTypeExpr(n.sons[0]) or (ty.kind == tyTypeDesc and ty.base.kind != tyNone):
if ty.kind == tyTypeDesc: ty = ty.base
case ty.kind
of tyEnum:
@@ -925,28 +940,17 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
f = getSymFromList(ty.n, i)
if f != nil: break
ty = ty.sons[0] # enum inheritance
- if f != nil:
+ if f != nil:
result = newSymNode(f)
result.info = n.info
result.typ = ty
markUsed(n, f)
return
of tyGenericInst:
- assert ty.sons[0].kind == tyGenericBody
- let tbody = ty.sons[0]
- for s in countup(0, tbody.len-2):
- let tParam = tbody.sons[s]
- if tParam.sym.name == i:
- let rawTyp = ty.sons[s + 1]
- if rawTyp.kind == tyStatic:
- return rawTyp.n
- else:
- let foundTyp = makeTypeDesc(c, rawTyp)
- return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info)
- return
+ return readTypeParameter(c, ty, i, n.info)
of tyObject, tyTuple:
if ty.n.kind == nkRecList:
- for field in ty.n.sons:
+ for field in ty.n:
if field.sym.name == i:
n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ])
n.typ.n = copyTree(n)
@@ -958,6 +962,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# XXX: This is probably not relevant any more
# reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
ty = n.sons[0].typ
+ return nil
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
var check: PNode = nil
@@ -990,6 +995,10 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
n.typ = f.typ
result = n
+ # we didn't find any field, let's look for a generic param
+ if result == nil and n.sons[0].typ.kind == tyGenericInst:
+ result = readTypeParameter(c, n.sons[0].typ, i, n.info)
+
proc dotTransformation(c: PContext, n: PNode): PNode =
if isSymChoice(n.sons[1]):
result = newNodeI(nkDotCall, n.info)
@@ -1119,6 +1128,9 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
n.sons[0] = x # 'result[]' --> 'result'
n.sons[1] = takeImplicitAddr(c, ri)
+template resultTypeIsInferrable(typ: PType): expr =
+ typ.isMetaType and typ.kind != tyTypeDesc
+
proc semAsgn(c: PContext, n: PNode): PNode =
checkSonsLen(n, 2)
var a = n.sons[0]
@@ -1170,7 +1182,7 @@ proc semAsgn(c: PContext, n: PNode): PNode =
if lhsIsResult: {efAllowDestructor} else: {})
if lhsIsResult:
n.typ = enforceVoidContext
- if lhs.sym.typ.isMetaType and lhs.sym.typ.kind != tyTypeDesc:
+ if resultTypeIsInferrable(lhs.sym.typ):
if cmpTypes(c, lhs.typ, rhs.typ) == isGeneric:
internalAssert c.p.resultSym != nil
lhs.typ = rhs.typ
@@ -1259,12 +1271,21 @@ proc semYield(c: PContext, n: PNode): PNode =
localError(n.info, errYieldNotAllowedInTryStmt)
elif n.sons[0].kind != nkEmpty:
n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility:
- var restype = c.p.owner.typ.sons[0]
+ var iterType = c.p.owner.typ
+ var restype = iterType.sons[0]
if restype != nil:
let adjustedRes = if c.p.owner.kind == skIterator: restype.base
else: restype
n.sons[0] = fitNode(c, adjustedRes, n.sons[0])
if n.sons[0].typ == nil: internalError(n.info, "semYield")
+
+ if resultTypeIsInferrable(adjustedRes):
+ let inferred = n.sons[0].typ
+ if c.p.owner.kind == skIterator:
+ iterType.sons[0].sons[0] = inferred
+ else:
+ iterType.sons[0] = inferred
+
semYieldVarResult(c, n, adjustedRes)
else:
localError(n.info, errCannotReturnExpr)
@@ -1346,7 +1367,7 @@ proc expectString(c: PContext, n: PNode): string =
localError(n.info, errStringLiteralExpected)
proc getMagicSym(magic: TMagic): PSym =
- result = newSym(skProc, getIdent($magic), getCurrOwner(), gCodegenLineInfo)
+ result = newSym(skProc, getIdent($magic), systemModule, gCodegenLineInfo)
result.magic = magic
proc newAnonSym(kind: TSymKind, info: TLineInfo,
@@ -1939,7 +1960,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkBracketExpr:
checkMinSonsLen(n, 1)
var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared})
- if s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators:
+ if (s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators) or
+ n[0].kind in nkSymChoices:
# type parameters: partial generic specialization
n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
result = explicitGenericInstantiation(c, n, s)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 8faf1d21a..4bcfa7f15 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -20,7 +20,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
if a.kind != nkSym:
internalError(a.info, "instantiateGenericParamList; no symbol")
var q = a.sym
- if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses:
+ if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
continue
var s = newSym(skType, q.name, getCurrOwner(), q.info)
s.flags = s.flags + {sfUsed, sfFromGeneric}
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index a11386966..edce7c9bd 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -661,10 +661,18 @@ proc semFor(c: PContext, n: PNode): PNode =
openScope(c)
n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
var call = n.sons[length-2]
- if call.kind in nkCallKinds and call.sons[0].typ.callConv == ccClosure:
+ let isCallExpr = call.kind in nkCallKinds
+ if isCallExpr and call.sons[0].sym.magic != mNone:
+ if call.sons[0].sym.magic == mOmpParFor:
+ result = semForVars(c, n)
+ result.kind = nkParForStmt
+ else:
+ result = semForFields(c, n, call.sons[0].sym.magic)
+ elif (isCallExpr and call.sons[0].typ.callConv == ccClosure) or
+ call.typ.kind == tyIter:
# first class iterator:
result = semForVars(c, n)
- elif call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
+ elif not isCallExpr or call.sons[0].kind != nkSym or
call.sons[0].sym.kind notin skIterators:
if length == 3:
n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2])
@@ -673,12 +681,6 @@ proc semFor(c: PContext, n: PNode): PNode =
else:
localError(n.sons[length-2].info, errIteratorExpected)
result = semForVars(c, n)
- elif call.sons[0].sym.magic != mNone:
- if call.sons[0].sym.magic == mOmpParFor:
- result = semForVars(c, n)
- result.kind = nkParForStmt
- else:
- result = semForFields(c, n, call.sons[0].sym.magic)
else:
result = semForVars(c, n)
# propagate any enforced VoidContext:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 31624a97f..42268d44f 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -348,7 +348,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
of nkMethodDef:
result = semRoutineInTemplBody(c, n, skMethod)
of nkIteratorDef:
- result = semRoutineInTemplBody(c, n, n[namePos].sym.kind)
+ let kind = if hasPragma(n[pragmasPos], wClosure): skClosureIterator
+ else: skIterator
+ result = semRoutineInTemplBody(c, n, kind)
of nkTemplateDef:
result = semRoutineInTemplBody(c, n, skTemplate)
of nkMacroDef:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index a619de7ff..f91222477 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -147,26 +147,38 @@ proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
else:
result = newConstraint(c, tyDistinct)
-proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
+proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
assert isRange(n)
checkSonsLen(n, 3)
result = newOrPrevType(tyRange, prev, c)
result.n = newNodeI(nkRange, n.info)
- if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
+ if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
localError(n.info, errRangeIsEmpty)
- var a = semConstExpr(c, n[1])
- var b = semConstExpr(c, n[2])
- if not sameType(a.typ, b.typ):
+
+ var range: array[2, PNode]
+ range[0] = semExprWithType(c, n[1], {efDetermineType})
+ range[1] = semExprWithType(c, n[2], {efDetermineType})
+
+ var rangeT: array[2, PType]
+ for i in 0..1: rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
+
+ if not sameType(rangeT[0], rangeT[1]):
localError(n.info, errPureTypeMismatch)
- elif a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,
- tyFloat..tyFloat128,tyUInt8..tyUInt32}:
+ elif not rangeT[0].isOrdinalType:
localError(n.info, errOrdinalTypeExpected)
- elif enumHasHoles(a.typ):
- localError(n.info, errEnumXHasHoles, a.typ.sym.name.s)
- elif not leValue(a, b): localError(n.info, errRangeIsEmpty)
- addSon(result.n, a)
- addSon(result.n, b)
- addSonSkipIntLit(result, b.typ)
+ elif enumHasHoles(rangeT[0]):
+ localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
+
+ for i in 0..1:
+ if hasGenericArguments(range[i]):
+ result.n.addSon makeStaticExpr(c, range[i])
+ else:
+ result.n.addSon semConstExpr(c, range[i])
+
+ if weakLeValue(result.n[0], result.n[1]) == impNo:
+ localError(n.info, errRangeIsEmpty)
+
+ addSonSkipIntLit(result, rangeT[0])
proc semRange(c: PContext, n: PNode, prev: PType): PType =
result = nil
@@ -602,15 +614,24 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
incl(result.flags, tfFinal)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
- if kind == skMacro and param.typ.kind notin {tyTypeDesc, tyStatic}:
- # within a macro, every param has the type PNimrodNode!
- # and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
- let nn = getSysSym"PNimrodNode"
- var a = copySym(param)
- a.typ = nn.typ
- if sfGenSym notin a.flags: addDecl(c, a)
+ template addDecl(x) =
+ if sfGenSym notin x.flags: addDecl(c, x)
+
+ if kind == skMacro:
+ if param.typ.kind == tyTypeDesc:
+ addDecl(param)
+ elif param.typ.kind == tyStatic:
+ var a = copySym(param)
+ a.typ = param.typ.base
+ addDecl(a)
+ else:
+ # within a macro, every param has the type PNimrodNode!
+ let nn = getSysSym"PNimrodNode"
+ var a = copySym(param)
+ a.typ = nn.typ
+ addDecl(a)
else:
- if sfGenSym notin param.flags: addDecl(c, param)
+ addDecl(param)
let typedescId = getIdent"typedesc"
@@ -721,7 +742,16 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
allowMetaTypes = true)
result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
result = addImplicitGeneric(result)
-
+
+ of tyIter:
+ if paramType.callConv == ccInline:
+ if procKind notin {skTemplate, skMacro, skIterator}:
+ localError(info, errInlineIteratorsAsProcParams)
+ if paramType.len == 1:
+ let lifted = liftingWalk(paramType.base)
+ if lifted != nil: paramType.sons[0] = lifted
+ result = addImplicitGeneric(paramType)
+
of tyGenericInst:
if paramType.lastSon.kind == tyUserTypeClass:
var cp = copyType(paramType, getCurrOwner(), false)
@@ -840,9 +870,13 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
addParamOrResult(c, arg, kind)
if gCmd == cmdPretty: checkDef(a.sons[j], arg)
-
+ var r: PType
if n.sons[0].kind != nkEmpty:
- var r = semTypeNode(c, n.sons[0], nil)
+ r = semTypeNode(c, n.sons[0], nil)
+ elif kind == skIterator:
+ r = newTypeS(tyAnything, c)
+
+ if r != nil:
# turn explicit 'void' return type into 'nil' because the rest of the
# compiler only checks for 'nil':
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
@@ -852,7 +886,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if lifted != nil: r = lifted
r.flags.incl tfRetType
r = skipIntLit(r)
- if kind == skIterator: r = newTypeWithSons(c, tyIter, @[r])
+ if kind == skIterator:
+ # see tchainediterators
+ # in cases like iterator foo(it: iterator): type(it)
+ # we don't need to change the return type to iter[T]
+ if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
result.sons[0] = r
res.typ = r
@@ -984,7 +1022,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkTypeOfExpr:
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
checkSonsLen(n, 1)
- result = semExprWithType(c, n.sons[0], {efInTypeof}).typ.skipTypes({tyIter})
+ let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
+ result = typExpr.typ.skipTypes({tyIter})
of nkPar:
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
else:
@@ -1103,8 +1142,12 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = newConstraint(c, tyIter)
else:
result = semProcTypeWithScope(c, n, prev, skClosureIterator)
- result.flags.incl(tfIterator)
- result.callConv = ccClosure
+ if n.lastSon.kind == nkPragma and hasPragma(n.lastSon, wInline):
+ result.kind = tyIter
+ result.callConv = ccInline
+ else:
+ result.flags.incl(tfIterator)
+ result.callConv = ccClosure
of nkProcTy:
if n.sonsLen == 0:
result = newConstraint(c, tyProc)
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 22edc6e32..80e2aa284 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -181,7 +181,8 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
of nkStaticExpr:
var n = prepareNode(cl, n)
n = reResolveCallsWithTypedescParams(cl, n)
- result = cl.c.semExpr(cl.c, n)
+ result = if cl.allowMetaTypes: n
+ else: cl.c.semExpr(cl.c, n)
else:
var length = sonsLen(n)
if length > 0:
@@ -305,6 +306,11 @@ proc skipIntLiteralParams(t: PType) =
if skipped != p:
t.sons[i] = skipped
if i > 0: t.n.sons[i].sym.typ = skipped
+
+ # when the typeof operator is used on a static input
+ # param, the results gets infected with static as well:
+ if t.sons[0] != nil and t.sons[0].kind == tyStatic:
+ t.sons[0] = t.sons[0].base
proc propagateFieldFlags(t: PType, n: PNode) =
# This is meant for objects and tuples
@@ -314,16 +320,15 @@ proc propagateFieldFlags(t: PType, n: PNode) =
of nkSym:
propagateToOwner(t, n.sym.typ)
of nkRecList, nkRecCase, nkOfBranch, nkElse:
- if n.sons != nil:
- for son in n.sons:
- propagateFieldFlags(t, son)
+ for son in n:
+ propagateFieldFlags(t, son)
else: discard
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result = t
if t == nil: return
- if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses:
+ if t.kind in {tyStatic, tyGenericParam, tyIter} + tyTypeClasses:
let lookup = PType(idTableGet(cl.typeMap, t))
if lookup != nil: return lookup
@@ -336,6 +341,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result = replaceTypeVarsT(cl, lastSon(t))
of tyFromExpr:
+ if cl.allowMetaTypes: return
var n = prepareNode(cl, t.n)
n = cl.c.semConstExpr(cl.c, n)
if n.typ.kind == tyTypeDesc:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index c0898ef26..19f10def8 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1014,6 +1014,10 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
result.typ = getInstantiatedType(c, arg, m, base(f))
m.baseTypeMatch = true
+proc isInlineIterator*(t: PType): bool =
+ result = t.kind == tyIter or
+ (t.kind == tyBuiltInTypeClass and t.base.kind == tyIter)
+
proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
argSemantized, argOrig: PNode): PNode =
var
@@ -1021,7 +1025,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
arg = argSemantized
argType = argType
c = m.c
-
+
if tfHasStatic in fMaybeStatic.flags:
# XXX: When implicit statics are the default
# this will be done earlier - we just have to
@@ -1060,7 +1064,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
return arg.typ.n
else:
return argOrig
-
+
+ if r != isNone and f.isInlineIterator:
+ var inlined = newTypeS(tyStatic, c)
+ inlined.sons = @[argType]
+ inlined.n = argSemantized
+ put(m.bindings, f, inlined)
+ return argSemantized
+
case r
of isConvertible:
inc(m.convMatches)
@@ -1188,7 +1199,9 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
# a.typ == nil is valid
result = a
elif a.typ.isNil:
- result = c.semOperand(c, a, {efDetermineType})
+ let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator}
+ else: {efDetermineType}
+ result = c.semOperand(c, a, flags)
else:
result = a
diff --git a/compiler/transf.nim b/compiler/transf.nim
index f4b716c5b..9586398c9 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -425,7 +425,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
else:
for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
-
+
proc transformFor(c: PTransf, n: PNode): PTransNode =
# generate access statements for the parameters (unless they are constant)
# put mapping from formal parameters to actual parameters
@@ -433,12 +433,13 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
var length = sonsLen(n)
var call = n.sons[length - 2]
- if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
- call.sons[0].sym.kind != skIterator:
+ if call.typ.kind != tyIter and
+ (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
+ call.sons[0].sym.kind != skIterator):
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
return lambdalifting.liftForLoop(n).PTransNode
#InternalError(call.info, "transformFor")
-
+
#echo "transforming: ", renderTree(n)
result = newTransNode(nkStmtList, n.info, 0)
var loopBody = transformLoopBody(c, n.sons[length-1])
@@ -459,6 +460,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
for i in countup(1, sonsLen(call) - 1):
var arg = transform(c, call.sons[i]).PNode
var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
+ if arg.typ.kind == tyIter: continue
case putArgInto(arg, formal.typ)
of paDirectMapping:
idNodeTablePut(newC.mapping, formal, arg)
@@ -480,7 +482,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
dec(c.inlining)
popInfoContext()
popTransCon(c)
- #echo "transformed: ", renderTree(n)
+ # echo "transformed: ", result.PNode.renderTree
proc getMagicOp(call: PNode): TMagic =
if call.sons[0].kind == nkSym and
diff --git a/compiler/vm.nim b/compiler/vm.nim
index f9b143bce..2a80106a5 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -425,7 +425,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
decodeBC(rkNode)
let src = regs[rb].node
if src.kind notin {nkEmpty..nkNilLit}:
- regs[ra].node = src.sons[rc]
+ let n = src.sons[rc]
+ regs[ra].node = if n.kind == nkExprColonExpr: n[1]
+ else: n
else:
stackTrace(c, tos, pc, errIndexOutOfBounds)
of opcWrObj:
diff --git a/doc/manual.txt b/doc/manual.txt
index 04c69cf94..ab1badaf3 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -2875,7 +2875,6 @@ as there are components in the tuple. The i'th iteration variable's type is
the type of the i'th component. In other words, implicit tuple unpacking in a
for loop context is supported.
-
Implict items/pairs invocations
-------------------------------
@@ -2900,10 +2899,11 @@ First class iterators
There are 2 kinds of iterators in Nimrod: *inline* and *closure* iterators.
An `inline iterator`:idx: is an iterator that's always inlined by the compiler
leading to zero overhead for the abstraction, but may result in a heavy
-increase in code size. Inline iterators are second class
-citizens; one cannot pass them around like first class procs.
+increase in code size. Inline iterators are second class citizens;
+They can be passed as parameters only to other inlining code facilities like
+templates, macros and other inline iterators.
-In contrast to that, a `closure iterator`:idx: can be passed around:
+In contrast to that, a `closure iterator`:idx: can be passed around more freely:
.. code-block:: nimrod
iterator count0(): int {.closure.} =
@@ -2926,9 +2926,7 @@ Closure iterators have other restrictions than inline iterators:
1. ``yield`` in a closure iterator can not occur in a ``try`` statement.
2. For now, a closure iterator cannot be evaluated at compile time.
3. ``return`` is allowed in a closure iterator (but rarely useful).
-4. Since closure iterators can be used as a collaborative tasking
- system, ``void`` is a valid return type for them.
-5. Both inline and closure iterators cannot be recursive.
+4. Both inline and closure iterators cannot be recursive.
Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly
default to being inline, but that this may change in future versions of the
@@ -2990,6 +2988,14 @@ parameters of an outer factory proc:
for f in foo():
echo f
+Implicit return type
+--------------------
+
+Since inline interators must always produce values that will be consumed in
+a for loop, the compiler will implicity use the ``auto`` return type if no
+type is given by the user. In contrast, since closure iterators can be used
+as a collaborative tasking system, ``void`` is a valid return type for them.
+
Type sections
=============
@@ -4069,8 +4075,8 @@ Static params can also appear in the signatures of generic types:
AffineTransform2D[T] = Matrix[3, 3, T]
AffineTransform3D[T] = Matrix[4, 4, T]
- AffineTransform3D[float] # OK
- AffineTransform2D[string] # Error, `string` is not a `Number`
+ var m1: AffineTransform3D[float] # OK
+ var m2: AffineTransform2D[string] # Error, `string` is not a `Number`
typedesc
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 74aaa1a59..32cda3e4d 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -195,8 +195,14 @@ proc open*(connection, user, password, database: string): TDbConn {.
## be established.
result = mysql.Init(nil)
if result == nil: dbError("could not open database connection")
- if mysql.RealConnect(result, "", user, password, database,
- 0'i32, nil, 0) == nil:
+ let
+ colonPos = connection.find(':')
+ host = if colonPos < 0: connection
+ else: substr(connection, 0, colonPos-1)
+ port: int32 = if colonPos < 0: 0'i32
+ else: substr(connection, colonPos+1).parseInt.int32
+ if mysql.RealConnect(result, host, user, password, database,
+ port, nil, 0) == nil:
var errmsg = $mysql.error(result)
db_mysql.Close(result)
dbError(errmsg)
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 1100e084b..b16b27b2c 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -314,6 +314,9 @@ static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff};
# define INF INFINITY
# elif defined(HUGE_VAL)
# define INF HUGE_VAL
+# elif defined(_MSC_VER)
+# include <float.h>
+# define INF (DBL_MAX+DBL_MAX)
# else
# define INF (1.0 / 0.0)
# endif
diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim
index 366521551..57a2f001f 100644
--- a/lib/posix/epoll.nim
+++ b/lib/posix/epoll.nim
@@ -36,7 +36,7 @@ type
epoll_data* {.importc: "union epoll_data",
header: "<sys/epoll.h>", pure, final.} = object # TODO: This is actually a union.
#thePtr* {.importc: "ptr".}: pointer
- fd*: cint # \
+ fd* {.importc: "fd".}: cint # \
#u32*: uint32
#u64*: uint64
diff --git a/lib/pure/asyncio2.nim b/lib/pure/asyncio2.nim
index 12d4cb5a3..60d489dda 100644
--- a/lib/pure/asyncio2.nim
+++ b/lib/pure/asyncio2.nim
@@ -473,7 +473,6 @@ else:
proc update(p: PDispatcher, sock: TSocketHandle, events: set[TEvent]) =
assert sock in p.selector
- echo("Update: ", events)
if events == {}:
discard p.selector.unregister(sock)
else:
@@ -499,23 +498,25 @@ else:
for info in p.selector.select(timeout):
let data = PData(info.key.data)
assert data.sock == info.key.fd
- echo("R: ", data.readCBs.len, " W: ", data.writeCBs.len, ". ", info.events)
if EvRead in info.events:
- var newReadCBs: seq[TCallback] = @[]
- for cb in data.readCBs:
+ # Callback may add items to ``data.readCBs`` which causes issues if
+ # we are iterating over ``data.readCBs`` at the same time. We therefore
+ # make a copy to iterate over.
+ let currentCBs = data.readCBs
+ data.readCBs = @[]
+ for cb in currentCBs:
if not cb(data.sock):
# Callback wants to be called again.
- newReadCBs.add(cb)
- data.readCBs = newReadCBs
+ data.readCBs.add(cb)
if EvWrite in info.events:
- var newWriteCBs: seq[TCallback] = @[]
- for cb in data.writeCBs:
+ let currentCBs = data.writeCBs
+ data.writeCBs = @[]
+ for cb in currentCBs:
if not cb(data.sock):
# Callback wants to be called again.
- newWriteCBs.add(cb)
- data.writeCBs = newWriteCBs
+ data.writeCBs.add(cb)
var newEvents: set[TEvent]
if data.readCBs.len != 0: newEvents = {EvRead}
@@ -615,7 +616,6 @@ else:
retFuture.complete(0)
addWrite(p, socket, cb)
return retFuture
-
proc acceptAddr*(p: PDispatcher, socket: TSocketHandle):
PFuture[tuple[address: string, client: TSocketHandle]] =
@@ -854,7 +854,7 @@ when isMainModule:
sock.setBlocking false
- when false:
+ when true:
# Await tests
proc main(p: PDispatcher): PFuture[int] {.async.} =
discard await p.connect(sock, "irc.freenode.net", TPort(6667))
@@ -880,7 +880,7 @@ when isMainModule:
else:
- when false:
+ when true:
var f = p.connect(sock, "irc.freenode.org", TPort(6667))
f.callback =
@@ -919,4 +919,4 @@ when isMainModule:
- \ No newline at end of file
+
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index 6482a01a6..e086ee3ab 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -10,11 +10,13 @@
# TODO: Docs.
import tables, os, unsigned, hashes
+import sockets2
when defined(linux): import posix, epoll
elif defined(windows): import winlean
proc hash*(x: TSocketHandle): THash {.borrow.}
+proc `$`*(x: TSocketHandle): string {.borrow.}
type
TEvent* = enum
@@ -31,7 +33,7 @@ when defined(linux) or defined(nimdoc):
type
PSelector* = ref object
epollFD: cint
- events: array[64, ptr epoll_event]
+ events: array[64, epoll_event]
fds: TTable[TSocketHandle, PSelectorKey]
proc createEventStruct(events: set[TEvent], fd: TSocketHandle): epoll_event =
@@ -66,17 +68,25 @@ when defined(linux) or defined(nimdoc):
var event = createEventStruct(events, fd)
s.fds[fd].events = events
- echo("About to update")
if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0:
+ if OSLastError().cint == ENOENT:
+ # Socket has been closed. Epoll automatically removes disconnected
+ # sockets.
+ s.fds.del(fd)
+ osError("Socket has been disconnected")
+
OSError(OSLastError())
- echo("finished updating")
result = s.fds[fd]
proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} =
if not s.fds.hasKey(fd):
raise newException(EInvalidValue, "File descriptor not found.")
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
- OSError(OSLastError())
+ if osLastError().cint == ENOENT:
+ # Socket has been closed. Epoll automatically removes disconnected
+ # sockets so its already been removed.
+ else:
+ OSError(OSLastError())
result = s.fds[fd]
s.fds.del(fd)
@@ -92,21 +102,21 @@ when defined(linux) or defined(nimdoc):
## on the ``fd``.
result = @[]
- let evNum = epoll_wait(s.epollFD, s.events[0], 64.cint, timeout.cint)
+ let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
if evNum < 0: OSError(OSLastError())
if evNum == 0: return @[]
for i in 0 .. <evNum:
var evSet: set[TEvent] = {}
if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
-
let selectorKey = s.fds[s.events[i].data.fd.TSocketHandle]
+ assert selectorKey != nil
result.add((selectorKey, evSet))
proc newSelector*(): PSelector =
new result
result.epollFD = epoll_create(64)
- result.events = cast[array[64, ptr epoll_event]](alloc0(sizeof(epoll_event)*64))
+ result.events = cast[array[64, epoll_event]](alloc0(sizeof(epoll_event)*64))
result.fds = initTable[TSocketHandle, PSelectorKey]()
if result.epollFD < 0:
OSError(OSLastError())
@@ -247,4 +257,4 @@ when isMainModule:
- \ No newline at end of file
+
diff --git a/lib/pure/sockets2.nim b/lib/pure/sockets2.nim
index 3542a0694..290f414b4 100644
--- a/lib/pure/sockets2.nim
+++ b/lib/pure/sockets2.nim
@@ -24,6 +24,10 @@ else:
export TSocketHandle, TSockaddr_in, TAddrinfo, INADDR_ANY, TSockAddr, TSockLen,
inet_ntoa, recv, `==`, connect, send, accept
+export
+ SO_ERROR,
+ SOL_SOCKET
+
type
TPort* = distinct uint16 ## port type
@@ -208,6 +212,24 @@ proc htons*(x: int16): int16 =
## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
result = sockets2.ntohs(x)
+proc getSockOptInt*(socket: TSocketHandle, level, optname: int): int {.
+ tags: [FReadIO].} =
+ ## getsockopt for integer options.
+ var res: cint
+ var size = sizeof(res).TSocklen
+ if getsockopt(socket, cint(level), cint(optname),
+ addr(res), addr(size)) < 0'i32:
+ osError(osLastError())
+ result = int(res)
+
+proc setSockOptInt*(socket: TSocketHandle, level, optname, optval: int) {.
+ tags: [FWriteIO].} =
+ ## setsockopt for integer options.
+ var value = cint(optval)
+ if setsockopt(socket, cint(level), cint(optname), addr(value),
+ sizeof(value).TSocklen) < 0'i32:
+ osError(osLastError())
+
when defined(Windows):
var wsa: TWSADATA
if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
diff --git a/lib/system.nim b/lib/system.nim
index 171c7b6b8..24ad50f97 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1164,13 +1164,13 @@ when not defined(nimrodVM):
## from it before writing to it is undefined behaviour!
## The allocated memory belongs to its allocating thread!
## Use `allocShared` to allocate from a shared heap.
- proc alloc*(T: typedesc, size = 1): ptr T {.inline.} =
+ proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
## allocates a new memory block with at least ``T.sizeof * size``
- ## bytes. The block has to be freed with ``realloc(block, 0)`` or
- ## ``dealloc(block)``. The block is not initialized, so reading
+ ## bytes. The block has to be freed with ``resize(block, 0)`` or
+ ## ``free(block)``. The block is not initialized, so reading
## from it before writing to it is undefined behaviour!
## The allocated memory belongs to its allocating thread!
- ## Use `allocShared` to allocate from a shared heap.
+ ## Use `createSharedU` to allocate from a shared heap.
cast[ptr T](alloc(T.sizeof * size))
proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].}
## allocates a new memory block with at least ``size`` bytes. The
@@ -1179,13 +1179,13 @@ when not defined(nimrodVM):
## containing zero, so it is somewhat safer than ``alloc``.
## The allocated memory belongs to its allocating thread!
## Use `allocShared0` to allocate from a shared heap.
- proc alloc0*(T: typedesc, size = 1): ptr T {.inline.} =
+ proc create*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
## allocates a new memory block with at least ``T.sizeof * size``
- ## bytes. The block has to be freed with ``realloc(block, 0)`` or
- ## ``dealloc(block)``. The block is initialized with all bytes
- ## containing zero, so it is somewhat safer than ``alloc``.
+ ## bytes. The block has to be freed with ``resize(block, 0)`` or
+ ## ``free(block)``. The block is initialized with all bytes
+ ## containing zero, so it is somewhat safer than ``createU``.
## The allocated memory belongs to its allocating thread!
- ## Use `allocShared0` to allocate from a shared heap.
+ ## Use `createShared` to allocate from a shared heap.
cast[ptr T](alloc0(T.sizeof * size))
proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [].}
## grows or shrinks a given memory block. If p is **nil** then a new
@@ -1195,14 +1195,14 @@ when not defined(nimrodVM):
## be freed with ``dealloc``.
## The allocated memory belongs to its allocating thread!
## Use `reallocShared` to reallocate from a shared heap.
- proc reallocType*[T](p: ptr T, newSize: int): ptr T {.inline.} =
+ proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline.} =
## grows or shrinks a given memory block. If p is **nil** then a new
## memory block is returned. In either way the block has at least
## ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is not
- ## **nil** ``realloc`` calls ``dealloc(p)``. In other cases the block
- ## has to be freed with ``dealloc``. The allocated memory belongs to
+ ## **nil** ``resize`` calls ``free(p)``. In other cases the block
+ ## has to be freed with ``free``. The allocated memory belongs to
## its allocating thread!
- ## Use `reallocShared` to reallocate from a shared heap.
+ ## Use `resizeShared` to reallocate from a shared heap.
cast[ptr T](realloc(p, T.sizeof * newSize))
proc dealloc*(p: pointer) {.noconv, rtl, tags: [].}
## frees the memory allocated with ``alloc``, ``alloc0`` or
@@ -1212,16 +1212,18 @@ when not defined(nimrodVM):
## or other memory may be corrupted.
## The freed memory must belong to its allocating thread!
## Use `deallocShared` to deallocate from a shared heap.
+ proc free*[T](p: ptr T) {.inline.} =
+ dealloc(p)
proc allocShared*(size: int): pointer {.noconv, rtl.}
## allocates a new memory block on the shared heap with at
## least ``size`` bytes. The block has to be freed with
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
## is not initialized, so reading from it before writing to it is
## undefined behaviour!
- proc allocShared*(T: typedesc, size: int): ptr T {.inline.} =
+ proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
## allocates a new memory block on the shared heap with at
## least ``T.sizeof * size`` bytes. The block has to be freed with
- ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
+ ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
## is not initialized, so reading from it before writing to it is
## undefined behaviour!
cast[ptr T](allocShared(T.sizeof * size))
@@ -1231,25 +1233,25 @@ when not defined(nimrodVM):
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
## The block is initialized with all bytes
## containing zero, so it is somewhat safer than ``allocShared``.
- proc allocShared0*(T: typedesc, size: int): ptr T {.inline.} =
+ proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
## allocates a new memory block on the shared heap with at
## least ``T.sizeof * size`` bytes. The block has to be freed with
- ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
+ ## ``resizeShared(block, 0)`` or ``freeShared(block)``.
## The block is initialized with all bytes
- ## containing zero, so it is somewhat safer than ``allocShared``.
- cast[ptr T](allocShared(T.sizeof * size))
+ ## containing zero, so it is somewhat safer than ``createSharedU``.
+ cast[ptr T](allocShared0(T.sizeof * size))
proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl.}
## grows or shrinks a given memory block on the heap. If p is **nil**
## then a new memory block is returned. In either way the block has at
## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
## ``reallocShared`` calls ``deallocShared(p)``. In other cases the
## block has to be freed with ``deallocShared``.
- proc reallocSharedType*[T](p: ptr T, newSize: int): ptr T {.inline.} =
+ proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline.} =
## grows or shrinks a given memory block on the heap. If p is **nil**
## then a new memory block is returned. In either way the block has at
## least ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is
- ## not **nil** ``reallocShared`` calls ``deallocShared(p)``. In other
- ## cases the block has to be freed with ``deallocShared``.
+ ## not **nil** ``resizeShared`` calls ``freeShared(p)``. In other
+ ## cases the block has to be freed with ``freeShared``.
cast[ptr T](reallocShared(p, T.sizeof * newSize))
proc deallocShared*(p: pointer) {.noconv, rtl.}
## frees the memory allocated with ``allocShared``, ``allocShared0`` or
@@ -1257,6 +1259,13 @@ when not defined(nimrodVM):
## free the memory a leak occurs; if one tries to access freed
## memory (or just freeing it twice!) a core dump may happen
## or other memory may be corrupted.
+ proc freeShared*[T](p: ptr T) {.inline.} =
+ ## frees the memory allocated with ``createShared``, ``createSharedU`` or
+ ## ``resizeShared``. This procedure is dangerous! If one forgets to
+ ## free the memory a leak occurs; if one tries to access freed
+ ## memory (or just freeing it twice!) a core dump may happen
+ ## or other memory may be corrupted.
+ deallocShared(p)
proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.}
## swaps the values `a` and `b`. This is often more efficient than
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
index bde5bf8c8..9e5d270c3 100644
--- a/tests/async/tasyncawait.nim
+++ b/tests/async/tasyncawait.nim
@@ -15,16 +15,24 @@ const
var clientCount = 0
proc sendMessages(disp: PDispatcher, client: TSocketHandle): PFuture[int] {.async.} =
+ echo("entering sendMessages")
for i in 0 .. <messagesToSend:
- discard await disp.send(client, "Message " & $i & "\c\L")
+ discard await disp.send(client, "Message " & $i & "\c\L")
+ echo("returning sendMessages")
proc launchSwarm(disp: PDispatcher, port: TPort): PFuture[int] {.async.} =
for i in 0 .. <swarmSize:
var sock = socket()
+ # TODO: We may need to explicitly register and unregister the fd.
+ # This is because when the socket is closed, selectors is not aware
+ # that it has been closed. While epoll is. Perhaps we should just unregister
+ # in close()?
+ echo(sock.cint)
#disp.register(sock)
discard await disp.connect(sock, "localhost", port)
when true:
discard await sendMessages(disp, sock)
+ echo("Calling close")
sock.close()
else:
# Issue #932: https://github.com/Araq/Nimrod/issues/932
diff --git a/tests/generics/tgenericshardcases.nim b/tests/generics/tgenericshardcases.nim
index 2ef63bc20..e3b805db6 100644
--- a/tests/generics/tgenericshardcases.nim
+++ b/tests/generics/tgenericshardcases.nim
@@ -14,7 +14,8 @@ macro selectType(a, b: typedesc): typedesc =
type
Foo[T] = object
data1: array[T.high, int]
- data2: array[typeNameLen(T), float] # data3: array[0..T.typeNameLen, selectType(float, int)]
+ data2: array[typeNameLen(T), float]
+ data3: array[0..T.typeNameLen, selectType(float, int)]
MyEnum = enum A, B, C, D
@@ -27,10 +28,15 @@ echo high(f1.data2) # (MyEnum.len = 6) - 1 == 5
echo high(f2.data1) # 127 - 1 == 126
echo high(f2.data2) # int8.len - 1 == 3
-#static:
-# assert high(f1.data1) == ord(D)
-# assert high(f1.data2) == 6 # length of MyEnum
+static:
+ assert high(f1.data1) == ord(C)
+ assert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high
-# assert high(f2.data1) == 127
-# assert high(f2.data2) == 4 # length of int8
+ assert high(f2.data1) == 126
+ assert high(f2.data2) == 3
+
+ assert high(f1.data3) == 6 # length of MyEnum
+ assert high(f2.data3) == 4 # length of int8
+
+ assert f2.data3[0] is float
diff --git a/tests/iter/tchainediterators.nim b/tests/iter/tchainediterators.nim
new file mode 100644
index 000000000..18d096761
--- /dev/null
+++ b/tests/iter/tchainediterators.nim
@@ -0,0 +1,38 @@
+discard """
+ output: '''16
+32
+48
+64
+128
+192
+'''
+"""
+
+iterator gaz(it: iterator{.inline.}): type(it) =
+ for x in it:
+ yield x*2
+
+iterator baz(it: iterator{.inline.}) =
+ for x in gaz(it):
+ yield x*2
+
+type T1 = auto
+
+iterator bar(it: iterator: T1{.inline.}): T1 =
+ for x in baz(it):
+ yield x*2
+
+iterator foo[T](x: iterator: T{.inline.}): T =
+ for e in bar(x):
+ yield e*2
+
+var s = @[1, 2, 3]
+
+# pass an interator several levels deep:
+for x in s.items.foo:
+ echo x
+
+# use some complex iterator as an input for another one:
+for x in s.items.baz.foo:
+ echo x
+
diff --git a/tests/iter/titerable.nim b/tests/iter/titerable.nim
new file mode 100644
index 000000000..3ec79f68d
--- /dev/null
+++ b/tests/iter/titerable.nim
@@ -0,0 +1,26 @@
+discard """
+ output: '''2
+4
+6
+4
+8
+12
+'''
+"""
+
+iterator map[T, U](s: iterator:T{.inline.}, f: proc(x: T): U): U =
+ for e in s: yield f(e)
+
+template toSeq(s: expr): expr =
+ var res = newSeq[type(s)](0)
+ for e in s: res.add(e)
+ res
+
+var s1 = @[1, 2, 3]
+for x in map(s1.items, proc (a:int): int = a*2):
+ echo x
+
+var s2 = toSeq(map(s1.items, proc (a:int): int = a*4))
+for x in s2:
+ echo x
+
diff --git a/tests/metatype/tstaticparams.nim b/tests/metatype/tstaticparams.nim
index b1377443b..e76dae23c 100644
--- a/tests/metatype/tstaticparams.nim
+++ b/tests/metatype/tstaticparams.nim
@@ -1,6 +1,6 @@
discard """
file: "tstaticparams.nim"
- output: "abracadabra\ntest\n3"
+ output: "abracadabra\ntest\n3\n15\4"
"""
type
@@ -11,8 +11,8 @@ type
data: array[I, T]
TA1[T; I: static[int]] = array[I, T]
- # TA2[T; I: static[int]] = array[0..I, T]
- # TA3[T; I: static[int]] = array[I-1, T]
+ TA2[T; I: static[int]] = array[0..I, T]
+ TA3[T; I: static[int]] = array[I-1, T]
proc takeFoo(x: TFoo) =
echo "abracadabra"
@@ -26,6 +26,22 @@ echo high(y.data)
var
t1: TA1[float, 1]
- # t2: TA2[string, 4]
- # t3: TA3[int, 10]
+ t2: TA2[string, 4]
+ t3: TA3[int, 10]
+# example from the manual:
+type
+ Matrix[M,N: static[int]; T] = array[0..(M*N - 1), T]
+ # Note how `Number` is just a type constraint here, while
+ # `static[int]` requires us to supply a compile-time int value
+
+ AffineTransform2D[T] = Matrix[3, 3, T]
+ AffineTransform3D[T] = Matrix[4, 4, T]
+
+var m: AffineTransform3D[float]
+echo high(m)
+
+proc getRows(mtx: Matrix): int =
+ result = mtx.M
+
+echo getRows(m)
diff --git a/tests/overload/tissue966.nim b/tests/overload/tissue966.nim
new file mode 100644
index 000000000..53ec2f108
--- /dev/null
+++ b/tests/overload/tissue966.nim
@@ -0,0 +1,12 @@
+discard """
+ msg: 'type mismatch: got (PTest)'
+"""
+
+type
+ PTest = ref object
+
+proc test(x: PTest, y: int) = nil
+
+var buf: PTest
+buf.test()
+
diff --git a/tests/static/tstaticparammacro.nim b/tests/static/tstaticparammacro.nim
new file mode 100644
index 000000000..7fb9e2014
--- /dev/null
+++ b/tests/static/tstaticparammacro.nim
@@ -0,0 +1,52 @@
+discard """
+ msg: '''letters
+aa
+bb
+numbers
+11
+22
+AST a
+[(11, 22), (33, 44)]
+AST b
+(e: [55, 66], f: [77, 88])
+55
+'''
+"""
+
+import macros
+
+type
+ TConfig = tuple
+ letters: seq[string]
+ numbers:seq[int]
+
+const data: Tconfig = (@["aa", "bb"], @[11, 22])
+
+macro mymacro(data: static[TConfig]): stmt =
+ echo "letters"
+ for s in items(data.letters):
+ echo s
+ echo "numbers"
+ for n in items(data.numbers):
+ echo n
+
+mymacro(data)
+
+type
+ Ta = seq[tuple[c:int, d:int]]
+ Tb = tuple[e:seq[int], f:seq[int]]
+
+const
+ a : Ta = @[(11, 22), (33, 44)]
+ b : Tb = (@[55,66], @[77, 88])
+
+macro mA(data: static[Ta]): stmt =
+ echo "AST a \n", repr(data)
+
+macro mB(data: static[Tb]): stmt =
+ echo "AST b \n", repr(data)
+ echo data.e[0]
+
+mA(a)
+mB(b)
+
diff --git a/tests/system/alloc.nim b/tests/system/alloc.nim
index 665b448ac..7abefec2a 100644
--- a/tests/system/alloc.nim
+++ b/tests/system/alloc.nim
@@ -2,44 +2,51 @@ var x: ptr int
x = cast[ptr int](alloc(7))
assert x != nil
-
-x = alloc(int, 3)
+x = cast[ptr int](x.realloc(2))
assert x != nil
x.dealloc()
-x = alloc0(int, 4)
+x = createU(int, 3)
+assert x != nil
+x.free()
+
+x = create(int, 4)
assert cast[ptr array[4, int]](x)[0] == 0
assert cast[ptr array[4, int]](x)[1] == 0
assert cast[ptr array[4, int]](x)[2] == 0
assert cast[ptr array[4, int]](x)[3] == 0
-x = cast[ptr int](x.realloc(2))
-assert x != nil
-
-x = x.reallocType(4)
+x = x.resize(4)
assert x != nil
-x.dealloc()
+x.free()
x = cast[ptr int](allocShared(100))
assert x != nil
deallocShared(x)
-x = allocShared(int, 3)
+x = createSharedU(int, 3)
assert x != nil
-x.deallocShared()
+x.freeShared()
-x = allocShared0(int, 3)
+x = createShared(int, 3)
assert x != nil
assert cast[ptr array[3, int]](x)[0] == 0
assert cast[ptr array[3, int]](x)[1] == 0
assert cast[ptr array[3, int]](x)[2] == 0
-x = cast[ptr int](reallocShared(x, 2))
assert x != nil
+x = cast[ptr int](x.resizeShared(2))
+assert x != nil
+x.freeShared()
-x = reallocType(x, 12)
+x = create(int, 10)
assert x != nil
+x = x.resize(12)
+assert x != nil
+x.dealloc()
-x = reallocSharedType(x, 1)
+x = createShared(int, 1)
+assert x != nil
+x = x.resizeShared(1)
assert x != nil
-x.deallocShared()
+x.freeShared()
diff --git a/tests/template/tissue909.nim b/tests/template/tissue909.nim
new file mode 100644
index 000000000..5b57a3558
--- /dev/null
+++ b/tests/template/tissue909.nim
@@ -0,0 +1,16 @@
+import macros
+
+template baz() =
+ proc bar() =
+ var x = 5
+ iterator foo(): int {.closure.} =
+ echo x
+ var y = foo
+ discard y()
+
+macro test(): stmt =
+ result = getAst(baz())
+ echo(treeRepr(result))
+
+test()
+bar()
diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim
index 74d8811b8..89d56c693 100644
--- a/tests/testament/htmlgen.nim
+++ b/tests/testament/htmlgen.nim
@@ -174,6 +174,10 @@ proc generateJson*(filename: string, commit: int) =
on A.name = B.name and A.category = B.category
where A.[commit] = ? and B.[commit] = ? and A.machine = ?
and A.result != B.result"""
+ selResults = """select
+ name, category, target, action, result, expected, given
+ from TestResult
+ where [commit] = ?"""
var db = open(connection="testament.db", user="testament", password="",
database="testament")
let lastCommit = db.getCommit(commit)
@@ -189,6 +193,20 @@ proc generateJson*(filename: string, commit: int) =
outfile.writeln("""{"total": $#, "passed": $#, "skipped": $#""" % data)
+ let results = newJArray()
+ for row in db.rows(sql(selResults), lastCommit):
+ var obj = newJObject()
+ obj["name"] = %row[0]
+ obj["category"] = %row[1]
+ obj["target"] = %row[2]
+ obj["action"] = %row[3]
+ obj["result"] = %row[4]
+ obj["expected"] = %row[5]
+ obj["given"] = %row[6]
+ results.add(obj)
+ outfile.writeln(""", "results": """)
+ outfile.write(results.pretty)
+
if not previousCommit.isNil:
let diff = newJArray()
diff --git a/tests/vm/tstaticprintseq.nim b/tests/vm/tstaticprintseq.nim
index 99a56d161..4575f3af1 100644
--- a/tests/vm/tstaticprintseq.nim
+++ b/tests/vm/tstaticprintseq.nim
@@ -4,7 +4,17 @@ discard """
3
1
2
-3'''
+3
+1
+2
+3
+1
+2
+3
+aa
+bb
+aa
+bb'''
"""
const s = @[1,2,3]
@@ -19,3 +29,27 @@ static:
for e in s:
echo e
+macro bar(x: static[seq[int]]): stmt =
+ for e in x:
+ echo e
+
+bar s
+bar(@[1, 2, 3])
+
+type
+ TData = tuple
+ letters: seq[string]
+ numbers: seq[int]
+
+const data: TData = (@["aa", "bb"], @[11, 22])
+
+static:
+ var m = data
+ for x in m.letters:
+ echo x
+
+macro ff(d: static[TData]): stmt =
+ for x in d.letters:
+ echo x
+
+ff(data)