From bc725eaa131b621bec7a8af084f631c1d31c0bf8 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 10 Sep 2015 13:18:11 +0200 Subject: [PATCH 01/19] documented void context --- doc/manual/stmts.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt index 062c08d7cc..a833d7b7da 100644 --- a/doc/manual/stmts.txt +++ b/doc/manual/stmts.txt @@ -60,6 +60,24 @@ An empty ``discard`` statement is often used as a null statement: else: discard +Void context +------------ + +In a list of statements every expression except the last one needs to have the +type ``void``. In addition to this rule an assignment to the builtin ``result`` +symbol also triggers a ``void`` context: + +.. code-block:: nim + proc invalid*(): string = + result = "foo" + "invalid" # Error: value of type 'string' has to be discarded + +.. code-block:: nim + proc valid*(): string = + let x = 317 + "valid" + + Var statement ------------- From 31bbc24462e1c5e05c2eea4837292ac5e9367515 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 10 Sep 2015 13:19:13 +0200 Subject: [PATCH 02/19] minor testsuite cleanup --- tests/misc/tvarious1.nim | 2 +- tests/parser/tstrongspaces.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/misc/tvarious1.nim b/tests/misc/tvarious1.nim index 9d7cf6584b..1d5ad876a5 100644 --- a/tests/misc/tvarious1.nim +++ b/tests/misc/tvarious1.nim @@ -22,7 +22,7 @@ import queues type TWidget = object - names: TQueue[string] + names: Queue[string] var w = TWidget(names: initQueue[string]()) diff --git a/tests/parser/tstrongspaces.nim b/tests/parser/tstrongspaces.nim index e70b91988c..cb02199761 100644 --- a/tests/parser/tstrongspaces.nim +++ b/tests/parser/tstrongspaces.nim @@ -1,4 +1,4 @@ -#! strongSpaces +#? strongSpaces discard """ output: '''35 From 34ab1d3e340635620d41ea1b0250830971648dda Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 10 Sep 2015 13:20:15 +0200 Subject: [PATCH 03/19] fixes #1528 --- compiler/semstmts.nim | 2 +- compiler/semtempl.nim | 25 +------------------------ tests/discard/tvoidcontext.nim | 12 ++++++++++++ 3 files changed, 14 insertions(+), 25 deletions(-) create mode 100644 tests/discard/tvoidcontext.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index ffda6a1bb9..4399c0ab05 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1425,7 +1425,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = localError(result.info, "type class predicate failed") of tyUnknown: continue else: discard - if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]): + if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]): voidContext = true n.typ = enforceVoidContext if i == last and (length == 1 or efWantValue in flags): diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 4d1eae48f2..84ba49e0cf 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -471,27 +471,6 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode = for i in countup(0, sonsLen(n) - 1): result.sons[i] = semTemplBodyDirty(c, n.sons[i]) -proc transformToExpr(n: PNode): PNode = - var realStmt: int - result = n - case n.kind - of nkStmtList: - realStmt = - 1 - for i in countup(0, sonsLen(n) - 1): - case n.sons[i].kind - of nkCommentStmt, nkEmpty, nkNilLit: - discard - else: - if realStmt == - 1: realStmt = i - else: realStmt = - 2 - if realStmt >= 0: result = transformToExpr(n.sons[realStmt]) - else: n.kind = nkStmtListExpr - of nkBlockStmt: - n.kind = nkBlockExpr - #nkIfStmt: n.kind = nkIfExpr // this is not correct! - else: - discard - proc semTemplateDef(c: PContext, n: PNode): PNode = var s: PSym if isTopLevel(c): @@ -549,9 +528,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = n.sons[bodyPos] = semTemplBodyDirty(ctx, n.sons[bodyPos]) else: n.sons[bodyPos] = semTemplBody(ctx, n.sons[bodyPos]) - if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}: - n.sons[bodyPos] = transformToExpr(n.sons[bodyPos]) - # only parameters are resolved, no type checking is performed + # only parameters are resolved, no type checking is performed semIdeForTemplateOrGeneric(c, n.sons[bodyPos], ctx.cursorInBody) closeScope(c) popOwner() diff --git a/tests/discard/tvoidcontext.nim b/tests/discard/tvoidcontext.nim new file mode 100644 index 0000000000..c3ea68baec --- /dev/null +++ b/tests/discard/tvoidcontext.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "value of type 'string' has to be discarded" + line: 12 +""" + +proc valid*(): string = + let x = 317 + "valid" + +proc invalid*(): string = + result = "foo" + "invalid" From 63cdcb2be188cfe613edbbcca58e193973b7b9f3 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 10 Sep 2015 15:57:57 +0200 Subject: [PATCH 04/19] implicit return types for iterators are now deprecated --- compiler/semtypes.nim | 1 + todo.txt | 1 - web/news.txt | 2 ++ 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 5ae3d16c01..2ee17fcaf9 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -970,6 +970,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, elif kind == skIterator: # XXX This is special magic we should likely get rid of r = newTypeS(tyExpr, c) + message(n.info, warnDeprecated, "implicit return type for 'iterator'") if r != nil: # turn explicit 'void' return type into 'nil' because the rest of the diff --git a/todo.txt b/todo.txt index c645f45e94..91c6f16255 100644 --- a/todo.txt +++ b/todo.txt @@ -23,7 +23,6 @@ version 1.0 - nimsuggest: auto-completion needs to work in 'class' macros - The bitwise 'not' operator will be renamed to 'bnot' to prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs! -- iterators always require a return type - split docgen into separate tool - special rule for ``[]=``, items, pairs - BUG: echo with template `$`*(info: TLineInfo): expr = toFileLineCol(info) diff --git a/web/news.txt b/web/news.txt index aaf3c93859..c786d7d5a0 100644 --- a/web/news.txt +++ b/web/news.txt @@ -73,6 +73,8 @@ News multi methods less error-prone to use with the effect system. - Nim's parser directive ``#!`` is now ``#?`` in order to produce no conflicts with Unix's ``#!``. + - An implicit return type for an iterator is now deprecated. Use ``auto`` if + you want more type inference. Library Additions From f1d1ff50e2e6f935b8bfa0f25b3dff023caa2e1a Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 10 Sep 2015 16:06:09 +0200 Subject: [PATCH 05/19] config cleanup --- config/nim.cfg | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/config/nim.cfg b/config/nim.cfg index 56bfbc64d4..bf78c35cc7 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -27,28 +27,18 @@ mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc" cs:partial @end -path="$lib/core" - -path="$lib/pure" path="$lib/pure/collections" path="$lib/pure/concurrency" path="$lib/impure" path="$lib/wrappers" -# path="$lib/wrappers/cairo" -# path="$lib/wrappers/gtk" -# path="$lib/wrappers/lua" -# path="$lib/wrappers/opengl" -path="$lib/wrappers/pcre" path="$lib/wrappers/linenoise" -path="$lib/wrappers/sdl" -# path="$lib/wrappers/x11" -path="$lib/wrappers/zip" -path="$lib/wrappers/libffi" path="$lib/windows" path="$lib/posix" path="$lib/js" path="$lib/pure/unidecode" path="$lib/arch" +path="$lib/core" +path="$lib/pure" @if nimbabel: nimblepath="$home/.nimble/pkgs/" From 2a797c362a1c70d708eb21a18a227296dcac71a4 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 12 Sep 2015 10:51:20 +0200 Subject: [PATCH 06/19] preparations for better handling of 'a[i]' in generics; stmt lists can be lvalues --- compiler/ast.nim | 10 +++++++++- compiler/parampatterns.nim | 5 ++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 7b6f39cbc6..860bf67e80 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -537,7 +537,7 @@ const type TMagic* = enum # symbols that require compiler magic: mNone, - mDefined, mDefinedInScope, mCompiles, + mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, @@ -614,6 +614,7 @@ const ctfeWhitelist* = {mNone, mUnaryLt, mSucc, mPred, mInc, mDec, mOrd, mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq, + mArrGet, mArrPut, mAsgn, mIncl, mExcl, mCard, mChr, mAddI, mSubI, mMulI, mDivI, mModI, mAddF64, mSubF64, mMulF64, mDivF64, @@ -1586,3 +1587,10 @@ proc createMagic*(name: string, m: TMagic): PSym = let opNot* = createMagic("not", mNot) opContains* = createMagic("contains", mInSet) + +when false: + proc containsNil*(n: PNode): bool = + # only for debugging + if n.isNil: return true + for i in 0 ..< n.safeLen: + if n[i].containsNil: return true diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index ae391945aa..978583c14e 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -225,8 +225,11 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult result = isAssignable(owner, n.sons[0], isUnsafeAddr) of nkCallKinds: # builtin slice keeps lvalue-ness: - if getMagic(n) == mSlice: + if getMagic(n) in {mArrGet, mSlice}: result = isAssignable(owner, n.sons[1], isUnsafeAddr) + of nkStmtList, nkStmtListExpr: + if n.typ != nil: + result = isAssignable(owner, n.lastSon, isUnsafeAddr) else: discard From 8ef66b973d86a75c8dfa4c6761d322d94c54efad Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 12 Sep 2015 10:55:28 +0200 Subject: [PATCH 07/19] first attempt to fix 'a[i]' handling in generics --- compiler/cgen.nim | 2 +- compiler/condsyms.nim | 1 + compiler/semcall.nim | 5 ++++- compiler/semexprs.nim | 13 ++++++++--- compiler/semgnrc.nim | 23 +++++++++++++++++++ compiler/semmagic.nim | 34 +++++++++++++++++++++++++++++ compiler/semstmts.nim | 1 + compiler/semtempl.nim | 51 +++++++++++++++++++++++++++++++++++++++++++ compiler/semtypes.nim | 12 +++++++++- compiler/sigmatch.nim | 6 +++++ lib/system.nim | 8 +++++++ todo.txt | 1 - web/news.txt | 3 +++ 13 files changed, 153 insertions(+), 7 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3f88e63ee4..f63134b66b 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1110,7 +1110,7 @@ proc rawNewModule(module: PSym, filename: string): BModule = proc nullify[T](arr: var T) = for i in low(arr)..high(arr): - arr[i] = nil + arr[i] = Rope(nil) proc resetModule*(m: BModule) = # between two compilations in CAAS mode, we can throw diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 31bd85a067..60e8f28262 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -92,3 +92,4 @@ proc initDefines*() = defineSymbol("nimvarargstyped") defineSymbol("nimtypedescfixed") defineSymbol("nimKnowsNimvm") + defineSymbol("nimArrIdx") diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 2f181b5f37..6787afe27f 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -308,7 +308,10 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = let gp = finalCallee.ast.sons[genericParamsPos] if gp.kind != nkEmpty: if x.calleeSym.kind notin {skMacro, skTemplate}: - finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info) + if x.calleeSym.magic == mArrPut: + finalCallee = x.calleeSym + else: + finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info) else: # For macros and templates, the resolved generic params # are added as normal params. diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 3ff04a4fc0..20b6775a56 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1250,7 +1250,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = template resultTypeIsInferrable(typ: PType): expr = typ.isMetaType and typ.kind != tyTypeDesc -proc semAsgn(c: PContext, n: PNode): PNode = +proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = checkSonsLen(n, 2) var a = n.sons[0] case a.kind @@ -1273,12 +1273,15 @@ proc semAsgn(c: PContext, n: PNode): PNode = # --> `[]=`(a, i, x) let oldBracketExpr = c.p.bracketExpr a = semSubscript(c, a, {efLValue}) - if a == nil: + if a == nil and mode != noOverloadedSubscript: result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=") add(result, n[1]) result = semExprNoType(c, result) c.p.bracketExpr = oldBracketExpr return result + elif a == nil: + localError(n.info, "could not resolve: " & $n[0]) + return n c.p.bracketExpr = oldBracketExpr of nkCurlyExpr: # a{i} = x --> `{}=`(a, i, x) @@ -1323,7 +1326,8 @@ proc semAsgn(c: PContext, n: PNode): PNode = typeMismatch(n, lhs.typ, rhs.typ) n.sons[1] = fitNode(c, le, rhs) - if tfHasAsgn in lhs.typ.flags and not lhsIsResult: + if tfHasAsgn in lhs.typ.flags and not lhsIsResult and + mode != noOverloadedAsgn: return overloadedAsgn(c, lhs, n.sons[1]) fixAbstractType(c, n) @@ -1715,6 +1719,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mTypeOf: checkSonsLen(n, 2) result = semTypeOf(c, n.sons[1]) + #of mArrGet: result = semArrGet(c, n, flags) + #of mArrPut: result = semArrPut(c, n, flags) + #of mAsgn: result = semAsgnOpr(c, n) of mDefined: result = semDefined(c, setMs(n, s), false) of mDefinedInScope: result = semDefined(c, setMs(n, s), true) of mCompiles: result = semCompiles(c, setMs(n, s), flags) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index e3b5989192..ed0244b0c6 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -251,6 +251,29 @@ proc semGenericStmt(c: PContext, n: PNode, let flags = if mixinContext: flags+{withinMixin} else: flags for i in countup(first, sonsLen(result) - 1): result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx) + of nkBracketExpr, nkCurlyExpr: + result = newNodeI(nkCall, n.info) + result.add newIdentNode(getIdent(if n.kind == nkBracketExpr:"[]" else:"{}"), + n.info) + for i in 0 ..< n.len: result.add(n[i]) + result = semGenericStmt(c, result, flags, ctx) + of nkAsgn, nkFastAsgn: + checkSonsLen(n, 2) + let a = n.sons[0] + let b = n.sons[1] + + let k = a.kind + case k + of nkBracketExpr, nkCurlyExpr: + result = newNodeI(nkCall, n.info) + result.add newIdentNode(getIdent(if k == nkBracketExpr:"[]=" else:"{}="), + n.info) + for i in 0 ..< a.len: result.add(a[i]) + result.add(b) + result = semGenericStmt(c, result, flags, ctx) + else: + for i in countup(0, sonsLen(n) - 1): + result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx) of nkIfStmt: for i in countup(0, sonsLen(n)-1): n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 5d16470b0b..65185f762a 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -26,6 +26,37 @@ proc semTypeOf(c: PContext; n: PNode): PNode = result.add typExpr result.typ = makeTypeDesc(c, typExpr.typ.skipTypes({tyTypeDesc, tyIter})) +type + SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn + +proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode +proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode + +proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode = + result = newNodeI(nkBracketExpr, n.info) + for i in 1.. requires 'mixin' annotation for procs! - split docgen into separate tool -- special rule for ``[]=``, items, pairs - BUG: echo with template `$`*(info: TLineInfo): expr = toFileLineCol(info) - make 'nil' work for 'add': - resizeString diff --git a/web/news.txt b/web/news.txt index c786d7d5a0..fd0cf8d8a0 100644 --- a/web/news.txt +++ b/web/news.txt @@ -95,6 +95,9 @@ News - The compiler now supports a new configuration system based on `NimScript `_. + - The compiler finally considers symbol binding rules in templates and + generics for overloaded ``[]``, ``[]=``, ``{}``, ``{}=`` operators + (issue `#2599 `_). Language Additions From e01e0a4b4056ac4a42797bab9f10822ae8996607 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 13 Sep 2015 22:42:21 +0200 Subject: [PATCH 08/19] next steps in binding [] properly --- compiler/semcall.nim | 2 +- compiler/semdata.nim | 3 ++- compiler/semexprs.nim | 43 +++++++++++++++++++++++++++++-------------- compiler/sigmatch.nim | 1 + 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 6787afe27f..f9fadeec75 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -308,7 +308,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = let gp = finalCallee.ast.sons[genericParamsPos] if gp.kind != nkEmpty: if x.calleeSym.kind notin {skMacro, skTemplate}: - if x.calleeSym.magic == mArrPut: + if x.calleeSym.magic in {mArrGet, mArrPut}: finalCallee = x.calleeSym else: finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 345a8c0d13..e6456293cd 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -45,7 +45,8 @@ type TExprFlag* = enum efLValue, efWantIterator, efInTypeof, efWantStmt, efAllowStmt, efDetermineType, - efAllowDestructor, efWantValue, efOperand, efNoSemCheck + efAllowDestructor, efWantValue, efOperand, efNoSemCheck, + efNoProcvarCheck TExprFlags* = set[TExprFlag] TTypeAttachedOp* = enum diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 20b6775a56..84cbbdc93e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -52,7 +52,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result.typ = errorType(c) else: # XXX tyGenericInst here? - semProcvarCheck(c, result) + if efNoProcvarCheck notin flags: semProcvarCheck(c, result) if result.typ.kind == tyVar: result = newDeref(result) semDestructorCheck(c, result, flags) @@ -1156,7 +1156,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result.add(x[0]) return checkMinSonsLen(n, 2) - n.sons[0] = semExprWithType(c, n.sons[0]) + n.sons[0] = semExprWithType(c, n.sons[0], {efNoProcvarCheck}) let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef}) case arr.kind of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, @@ -1196,7 +1196,17 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = localError(n.info, errIndexTypesDoNotMatch) result = n else: - c.p.bracketExpr = n.sons[0] + let s = if n.sons[0].kind == nkSym: n.sons[0].sym + elif n[0].kind in nkSymChoices: n.sons[0][0].sym + else: nil + if s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators: + # type parameters: partial generic specialization + n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) + result = explicitGenericInstantiation(c, n, s) + elif s != nil and s.kind == skType: + result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) + else: + c.p.bracketExpr = n.sons[0] proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = let oldBracketExpr = c.p.bracketExpr @@ -2073,6 +2083,19 @@ proc semExport(c: PContext, n: PNode): PNode = c.module.ast.add x result = n +proc shouldBeBracketExpr(n: PNode): bool = + assert n.kind in nkCallKinds + let a = n.sons[0] + if a.kind in nkCallKinds: + let b = a[0] + if b.kind in nkSymChoices: + for i in 0.. Date: Sun, 13 Sep 2015 23:26:44 +0200 Subject: [PATCH 09/19] fixes #2599 --- compiler/semfold.nim | 9 +-------- compiler/sigmatch.nim | 5 +---- tests/generics/mbind_bracket.nim | 17 +++++++++++++++++ tests/generics/tbind_bracket.nim | 20 ++++++++++++++++++++ tests/generics/tthread_generic.nim | 2 +- 5 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 tests/generics/mbind_bracket.nim create mode 100644 tests/generics/tbind_bracket.nim diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 70276a6d41..5fe4e32994 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -430,17 +430,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mCompileOptionArg: result = newIntNodeT(ord( testCompileOptionArg(getStr(a), getStr(b), n.info)), n) - of mNewString, mNewStringOfCap, - mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, - mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, - mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot, - mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, - mParallel, mPlugin, mGetTypeInfo, mTypeOf: - discard of mEqProc: result = newIntNodeT(ord( exprStructuralEquivalent(a, b, strictSymEquality=true)), n) - else: internalError(a.info, "evalOp(" & $m & ')') + else: discard proc getConstIfExpr(c: PSym, n: PNode): PNode = result = nil diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index b25f40c509..f6f0299366 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -265,9 +265,6 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1; proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation proc concreteType(c: TCandidate, t: PType): PType = - # currently `[]=` is defined rather sloppily in system.nim, so we have - # a special type matching rule for it: - if c.calleeSym != nil and c.calleeSym.magic == mArrPut: return t case t.kind of tyArrayConstr: # make it an array @@ -1694,7 +1691,7 @@ proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) = matchesAux(c, n, nOrig, m, marker) proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = - if m.calleeSym != nil and m.calleeSym.magic == mArrGet: + if m.calleeSym != nil and m.calleeSym.magic in {mArrGet, mArrPut}: m.state = csMatch m.call = n return diff --git a/tests/generics/mbind_bracket.nim b/tests/generics/mbind_bracket.nim new file mode 100644 index 0000000000..4bf18b471a --- /dev/null +++ b/tests/generics/mbind_bracket.nim @@ -0,0 +1,17 @@ + +import tables + +type + UUIDObject* = ref object + uuid: string + + Registry*[T] = ref object + objects: Table[string, T] + +proc newRegistry*[T](): Registry[T] = + result = Registry[T]() + result.objects = initTable[string, T](128) + +proc register*[T](self: Registry[T], obj: T) = + self.objects[obj.uuid] = obj + diff --git a/tests/generics/tbind_bracket.nim b/tests/generics/tbind_bracket.nim new file mode 100644 index 0000000000..d0c5e2c6b8 --- /dev/null +++ b/tests/generics/tbind_bracket.nim @@ -0,0 +1,20 @@ +discard """ + output: "317" +""" + +# bug #2599 + +import mbind_bracket + +# also test that `[]` can be passed now as a first class construct: + +template takeBracket(x, a, i: untyped) = + echo x(a, i) + +var a: array[10, int] +a[8] = 317 + +takeBracket(`[]`, a, 8) + +let reg = newRegistry[UUIDObject]() +reg.register(UUIDObject()) diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim index d34b24628e..e8946caf63 100644 --- a/tests/generics/tthread_generic.nim +++ b/tests/generics/tthread_generic.nim @@ -3,7 +3,7 @@ discard """ """ type - TThreadFuncArgs[T] = object of TObject + TThreadFuncArgs[T] = object of RootObj a: proc(): T {.thread.} b: proc(val: T) {.thread.} From b9df1323f7c117f0159e3afb26d5a3de83506f96 Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Mon, 14 Sep 2015 01:42:46 +0200 Subject: [PATCH 10/19] Provide access to getsockname()/getpeername(). This patch implements procedures getLocalAddr() and getPeerAddr() that return the results of getsockname() and getpeername(), respectively, as pairs (string, Port) for both Socket and SockedHandle. --- lib/pure/net.nim | 8 +++++ lib/pure/rawsockets.nim | 66 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 141543c703..b7a40121fa 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -533,6 +533,14 @@ proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {. var res = getSockOptInt(socket.fd, cint(level), toCInt(opt)) result = res != 0 +proc getLocalAddr*(socket: Socket): (string, Port) = + ## Get the socket's local address and port number + getLocalAddr(socket.fd, socket.domain) + +proc getPeerAddr*(socket: Socket): (string, Port) = + ## Get the socket's peer address and port number + getPeerAddr(socket.fd, socket.domain) + proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {. tags: [WriteIOEffect].} = ## Sets option ``opt`` to a boolean value specified by ``value``. diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim index 7873e7226a..0a69b580e5 100644 --- a/lib/pure/rawsockets.nim +++ b/lib/pure/rawsockets.nim @@ -371,6 +371,72 @@ proc getSockName*(socket: SocketHandle): Port = raiseOSError(osLastError()) result = Port(rawsockets.ntohs(name.sin_port)) +proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = + ## returns the socket's local address and port number. + case domain + of AF_INET: + var name: Sockaddr_in + when useWinVersion: + name.sin_family = int16(ord(AF_INET)) + else: + name.sin_family = posix.AF_INET + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + result = ($inet_ntoa(name.sin_addr), Port(rawsockets.ntohs(name.sin_port))) + of AF_INET6: + var name: Sockaddr_in6 + when useWinVersion: + name.sin6_family = int16(ord(AF_INET6)) + else: + name.sin6_family = posix.AF_INET6 + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + # Cannot use INET6_ADDRSTRLEN here, because it's a C define. + var buf: array[64, char] + if inet_ntop(name.sin6_family.cint, + addr name, buf.cstring, sizeof(buf).int32).isNil: + raiseOSError(osLastError()) + result = ($buf, Port(rawsockets.ntohs(name.sin6_port))) + else: + raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") + +proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) = + ## returns the socket's peer address and port number. + case domain + of AF_INET: + var name: Sockaddr_in + when useWinVersion: + name.sin_family = int16(ord(AF_INET)) + else: + name.sin_family = posix.AF_INET + var namelen = sizeof(name).SockLen + if getpeername(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + result = ($inet_ntoa(name.sin_addr), Port(rawsockets.ntohs(name.sin_port))) + of AF_INET6: + var name: Sockaddr_in6 + when useWinVersion: + name.sin6_family = int16(ord(AF_INET6)) + else: + name.sin6_family = posix.AF_INET6 + var namelen = sizeof(name).SockLen + if getpeername(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + # Cannot use INET6_ADDRSTRLEN here, because it's a C define. + var buf: array[64, char] + if inet_ntop(name.sin6_family.cint, + addr name, buf.cstring, sizeof(buf).int32).isNil: + raiseOSError(osLastError()) + result = ($buf, Port(rawsockets.ntohs(name.sin6_port))) + else: + raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") + proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {. tags: [ReadIOEffect].} = ## getsockopt for integer options. From 612cd25d5dd7f86380367b3a0ac823b4919eea67 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 14 Sep 2015 12:41:49 +0200 Subject: [PATCH 11/19] usage of NimNode triggers .compileTime context; fixes #1679 --- compiler/ast.nim | 5 +++++ compiler/ccgexprs.nim | 7 ++++++- compiler/seminst.nim | 2 ++ compiler/semstmts.nim | 1 + compiler/semtypes.nim | 3 ++- 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 860bf67e80..be11e80be2 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -477,6 +477,8 @@ type # wildcard type. tfHasAsgn # type has overloaded assignment operator tfBorrowDot # distinct type borrows '.' + tfTriggersCompileTime # uses the NimNode type which make the proc + # implicitly '.compiletime' TTypeFlags* = set[TTypeFlag] @@ -1380,6 +1382,9 @@ proc propagateToOwner*(owner, elem: PType) = o2.flags.incl tfHasAsgn owner.flags.incl tfHasAsgn + if tfTriggersCompileTime in elem.flags: + owner.flags.incl tfTriggersCompileTime + if owner.kind notin {tyProc, tyGenericInst, tyGenericBody, tyGenericInvocation, tyPtr}: let elemB = elem.skipTypes({tyGenericInst}) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 54063229fd..32fc76470b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1741,6 +1741,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mEcho: genEcho(p, e[1].skipConv) of mArrToSeq: genArrToSeq(p, e, d) of mNLen..mNError, mSlurp..mQuoteAst: + echo "from here ", p.prc.name.s, " ", p.prc.info + writestacktrace() localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s) of mSpawn: let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil) @@ -1973,6 +1975,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = genProc(p.module, sym) putLocIntoDest(p, d, sym.loc) of skProc, skConverter, skIterators: + if sfCompileTime in sym.flags: + localError(n.info, "request to generate code for .compileTime proc: " & + sym.name.s) genProc(p.module, sym) if sym.loc.r == nil or sym.loc.t == nil: internalError(n.info, "expr: proc not init " & sym.name.s) @@ -2126,7 +2131,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = # due to a bug/limitation in the lambda lifting, unused inner procs # are not transformed correctly. We work around this issue (#411) here # by ensuring it's no inner proc (owner is a module): - if prc.skipGenericOwner.kind == skModule: + if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags: if (optDeadCodeElim notin gGlobalOptions and sfDeadCodeElim notin getModule(prc).flags) or ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 42a39d0df4..64e3e8cb85 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -246,6 +246,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, inc i pushProcCon(c, result) instantiateProcType(c, pt, result, info) + if tfTriggersCompileTime in result.typ.flags: + incl(result.flags, sfCompileTime) n.sons[genericParamsPos] = ast.emptyNode var oldPrc = genericCacheGet(fn, entry[]) if oldPrc == nil: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0bb65dc57e..f67ee2822a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1132,6 +1132,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # semParamList(c, n.sons[ParamsPos], nil, s) else: s.typ = newProcType(c, n.info) + if tfTriggersCompileTime in s.typ.flags: incl(s.flags, sfCompileTime) if n.sons[patternPos].kind != nkEmpty: n.sons[patternPos] = semPattern(c, n.sons[patternPos]) if s.kind in skIterators: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 17e6422260..4ff2081ec1 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1375,7 +1375,8 @@ proc processMagicType(c: PContext, m: PSym) = of mOrdinal: setMagicType(m, tyOrdinal, 0) rawAddSon(m.typ, newTypeS(tyNone, c)) - of mPNimrodNode: discard + of mPNimrodNode: + incl m.typ.flags, tfTriggersCompileTime of mShared: setMagicType(m, tyObject, 0) m.typ.n = newNodeI(nkRecList, m.info) From a3f791f8929871b9e20f2fd4d69571dd20b3c409 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 14 Sep 2015 12:42:22 +0200 Subject: [PATCH 12/19] added testcase for #1679 --- tests/ccgbugs/tnocodegen_for_compiletime.nim | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/ccgbugs/tnocodegen_for_compiletime.nim diff --git a/tests/ccgbugs/tnocodegen_for_compiletime.nim b/tests/ccgbugs/tnocodegen_for_compiletime.nim new file mode 100644 index 0000000000..a88ba4b325 --- /dev/null +++ b/tests/ccgbugs/tnocodegen_for_compiletime.nim @@ -0,0 +1,9 @@ +# bug #1679 +import macros, tables, hashes +proc hash(v: NimNode): Hash = 4 # performance is for suckers +macro test(body: stmt): stmt {.immediate.} = + var a = initCountTable[NimNode]() + a.inc(body) + +test: + 1 + 1 From 48d8728e406155f33898098ef7df3165591babe8 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 14 Sep 2015 12:46:43 +0200 Subject: [PATCH 13/19] documented implicit compileTime procs --- doc/manual/pragmas.txt | 15 ++++++++++++++- web/news.txt | 3 +++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt index 8166994a94..68a88f865a 100644 --- a/doc/manual/pragmas.txt +++ b/doc/manual/pragmas.txt @@ -72,7 +72,20 @@ compileTime pragma ------------------ The ``compileTime`` pragma is used to mark a proc or variable to be used at compile time only. No code will be generated for it. Compile time procs are -useful as helpers for macros. +useful as helpers for macros. Since version 0.12.0 of the language, a proc +that uses ``system.NimNode`` within its parameter types is implictly declared +``compileTime``: + +.. code-block:: nim + proc astHelper(n: NimNode): NimNode = + result = n + +Is the same as: + +.. code-block:: nim + proc astHelper(n: NimNode): NimNode {.compileTime.} = + result = n + noReturn pragma --------------- diff --git a/web/news.txt b/web/news.txt index 225211a650..2aeaeeaedb 100644 --- a/web/news.txt +++ b/web/news.txt @@ -115,6 +115,9 @@ News this ``let (x, y) == f()`` still needs to be used. - ``when nimvm`` can now be used for compiletime versions of some code sections. Click `here `_ for details. + - Usage of the type ``NimNode`` in a proc now implicitly annotates the proc + with ``.compileTime``. This means generics work much better + for ``NimNode``. Bugfixes From f79ec6cdf5a33afc1de4b638149a1ed30d9b8656 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 14 Sep 2015 15:13:08 +0200 Subject: [PATCH 14/19] make the compiler less verbose --- compiler/msgs.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 8b3b11f4a7..c5bc44664c 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -514,6 +514,7 @@ const {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit, warnProveField, warnProveIndex, warnGcUnsafe, + hintPath, hintConf, hintDependency, hintExecuting, hintCodeBegin, hintCodeEnd, From 0aa908c86c84c62bae52618b91d5f1cba4c0dea1 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 14 Sep 2015 20:25:52 +0200 Subject: [PATCH 15/19] clarify the meaning of the 'auto' metatype; 'auto' is now bind-multiple; fixes #3224 --- compiler/semtypes.nim | 20 +++++++++---- doc/manual/generics.txt | 11 +------ doc/manual/types.txt | 24 +++++++++++++++ lib/system.nim | 16 +++++----- tests/metatype/ttypedesc1.nim | 2 +- tests/types/tauto_excessive.nim | 20 +++++++++++++ web/news.txt | 53 ++++++++++++++------------------- 7 files changed, 91 insertions(+), 55 deletions(-) create mode 100644 tests/types/tauto_excessive.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 4ff2081ec1..1cfbc368bb 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -718,12 +718,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, if paramType == nil: return # (e.g. proc return type) proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType = - let finalTypId = if typId != nil: typId - else: getIdent(paramName & ":type") if genericParams == nil: # This happens with anonymous proc types appearing in signatures # XXX: we need to lift these earlier return + let finalTypId = if typId != nil: typId + else: getIdent(paramName & ":type") # is this a bindOnce type class already present in the param list? for i in countup(0, genericParams.len - 1): if genericParams.sons[i].sym.name.id == finalTypId.id: @@ -757,7 +757,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, case paramType.kind: of tyAnything: - result = addImplicitGeneric(newTypeS(tyGenericParam, c)) + result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil) of tyStatic: # proc(a: expr{string}, b: expr{nkLambda}) @@ -868,6 +868,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyExpr: if procKind notin {skMacro, skTemplate}: result = addImplicitGeneric(newTypeS(tyAnything, c)) + #result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil) of tyGenericParam: markUsed(info, paramType.sym) @@ -977,7 +978,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, # compiler only checks for 'nil': if skipTypes(r, {tyGenericInst}).kind != tyEmpty: # 'auto' as a return type does not imply a generic: - if r.kind != tyExpr: + if r.kind == tyAnything: + # 'p(): auto' and 'p(): expr' are equivalent, but the rest of the + # compiler is hardly aware of 'auto': + r = newTypeS(tyExpr, c) + elif r.kind != tyExpr: if r.sym == nil or sfAnon notin r.sym.flags: let lifted = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info) @@ -1346,8 +1351,11 @@ proc processMagicType(c: PContext, m: PSym) = of mIntSetBaseType: setMagicType(m, tyRange, intSize) of mNil: setMagicType(m, tyNil, ptrSize) of mExpr: - setMagicType(m, tyExpr, 0) - if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt + if m.name.s == "auto": + setMagicType(m, tyAnything, 0) + else: + setMagicType(m, tyExpr, 0) + if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt of mStmt: setMagicType(m, tyStmt, 0) if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt index 8f7dcd5801..c6206d0302 100644 --- a/doc/manual/generics.txt +++ b/doc/manual/generics.txt @@ -116,7 +116,7 @@ type class matches ``array`` any array type ``set`` any set type ``seq`` any seq type -``auto`` any type +``any`` any type ================== =================================================== Furthermore, every generic type automatically creates a type class of the same @@ -163,15 +163,6 @@ module to illustrate this: Alternatively, the ``distinct`` type modifier can be applied to the type class to allow each param matching the type class to bind to a different type. -If a proc param doesn't have a type specified, Nim will use the -``distinct auto`` type class (also known as ``any``). Note this behavior is -deprecated for procs; templates, however, support them: - -.. code-block:: nim - # allow any combination of param types - proc concat(a, b): string = $a & $b # deprecated - proc concat(a, b: any): string = $a & $b # preferred - Procs written with the implicitly generic style will often need to refer to the type parameters of the matched generic type. They can be easily accessed using the dot syntax: diff --git a/doc/manual/types.txt b/doc/manual/types.txt index 44a20d0935..c9ac6f0628 100644 --- a/doc/manual/types.txt +++ b/doc/manual/types.txt @@ -1228,3 +1228,27 @@ However, a ``void`` type cannot be inferred in generic code: The ``void`` type is only valid for parameters and return types; other symbols cannot have the type ``void``. + + +Auto type +--------- + +The ``auto`` type can only be used for return types and parameters. For return +types it causes the compiler to infer the type from the routine body: + +.. code-block:: nim + proc returnsInt(): auto = 1984 + +For parameters it currently creates implicitly generic routines: + +.. code-block:: nim + proc foo(a, b: auto) = discard + +Is the same as: + +.. code-block:: nim + proc foo[T1, T2](a: T1, b: T2) = discard + +However later versions of the language might change this to mean "infer the +parameters' types from the body". Then the above ``foo`` would be rejected as +the parameters' types can not be infered from an empty ``discard`` statement. diff --git a/lib/system.nim b/lib/system.nim index cd94cfeaff..27c23e0bc4 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -78,7 +78,7 @@ type stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates) typedesc* {.magic: TypeDesc.} ## meta type to denote a type description void* {.magic: "VoidType".} ## meta type to denote the absence of any type - auto* = expr ## meta type for automatic type determination + auto* {.magic: Expr.} ## meta type for automatic type determination any* = distinct auto ## meta type for any supported type untyped* {.magic: Expr.} ## meta type to denote an expression that ## is not resolved (for templates) @@ -104,7 +104,7 @@ type SomeNumber* = SomeInteger|SomeReal ## type class matching all number types -proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.} +proc defined*(x: expr): bool {.magic: "Defined", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is ## defined. ## `x` is an external symbol introduced through the compiler's @@ -125,7 +125,7 @@ when defined(nimalias): TNumber: SomeNumber, TOrdinal: SomeOrdinal].} -proc declared*(x: expr): bool {.magic: "Defined", noSideEffect.} +proc declared*(x: expr): bool {.magic: "Defined", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is ## declared. `x` has to be an identifier or a qualified identifier. ## This can be used to check whether a library provides a certain @@ -140,11 +140,11 @@ when defined(useNimRtl): {.deadCodeElim: on.} proc definedInScope*(x: expr): bool {. - magic: "DefinedInScope", noSideEffect, deprecated.} + magic: "DefinedInScope", noSideEffect, deprecated, compileTime.} ## **Deprecated since version 0.9.6**: Use ``declaredInScope`` instead. proc declaredInScope*(x: expr): bool {. - magic: "DefinedInScope", noSideEffect.} + magic: "DefinedInScope", noSideEffect, compileTime.} ## Special compile-time procedure that checks whether `x` is ## declared in the current scope. `x` has to be an identifier. @@ -160,7 +160,7 @@ proc unsafeAddr*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = ## Cannot be overloaded. discard -proc `type`*(x: expr): typeDesc {.magic: "TypeOf", noSideEffect.} = +proc `type`*(x: expr): typeDesc {.magic: "TypeOf", noSideEffect, compileTime.} = ## Builtin 'type' operator for accessing the type of an expression. ## Cannot be overloaded. discard @@ -3392,7 +3392,7 @@ when hasAlloc: x[j+i] = item[j] inc(j) -proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} = +proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect, compileTime.} = ## Special compile-time procedure that checks whether `x` can be compiled ## without any semantic error. ## This can be used to check whether a type supports some operation: @@ -3456,7 +3456,7 @@ when hasAlloc and not defined(nimscript) and not defined(JS): include "system/deepcopy" -proc procCall*(x: expr) {.magic: "ProcCall".} = +proc procCall*(x: expr) {.magic: "ProcCall", compileTime.} = ## special magic to prohibit dynamic binding for `method`:idx: calls. ## This is similar to `super`:idx: in ordinary OO languages. ## diff --git a/tests/metatype/ttypedesc1.nim b/tests/metatype/ttypedesc1.nim index 19072d9669..d78c62a94f 100644 --- a/tests/metatype/ttypedesc1.nim +++ b/tests/metatype/ttypedesc1.nim @@ -7,7 +7,7 @@ type proc getTypeName(t: typedesc): string = t.name -proc foo(T: typedesc[float], a: expr): string = +proc foo(T: typedesc[float], a: auto): string = result = "float " & $(a.len > 5) proc foo(T: typedesc[TFoo], a: int): string = diff --git a/tests/types/tauto_excessive.nim b/tests/types/tauto_excessive.nim new file mode 100644 index 0000000000..2626b0cf4f --- /dev/null +++ b/tests/types/tauto_excessive.nim @@ -0,0 +1,20 @@ +discard """ + output: '''10 +10.0 +1.0hiho''' +""" + +# bug #3224 +proc f(x: auto): auto = + result = $(x+10) + +proc f(x, y: auto): auto = + result = $(x+y) + + +echo f(0) # prints 10 +echo f(0.0) # prints 10.0 + +proc `+`(a, b: string): string = a & b + +echo f(0.7, 0.3), f("hi", "ho") diff --git a/web/news.txt b/web/news.txt index 2aeaeeaedb..9f533de8e0 100644 --- a/web/news.txt +++ b/web/news.txt @@ -3,7 +3,7 @@ News ==== .. - 2015-05-05 Version 0.11.4 released + 2015-09-14 Version 0.11.4 released ================================== Changes affecting backwards compatibility @@ -58,7 +58,7 @@ News of all the DLLs the standard library needs. This means that the following DLLs are now split into 32 and 64 versions: - * ``prce.dll``: Split into ``prce32.dll`` and ``prce64.dll``. + * ``pcre.dll``: Split into ``pcre32.dll`` and ``pcre64.dll``. * ``pdcurses.dll``: Split into ``pdcurses32.dll`` and ``pdcurses64.dll``. * ``sqlite3.dll``: Split into ``sqlite3_32.dll`` and ``sqlite3_64.dll``. * ``ssleay32.dll``: Split into ``ssleay32.dll`` and ``ssleay64.dll``. @@ -75,6 +75,13 @@ News with Unix's ``#!``. - An implicit return type for an iterator is now deprecated. Use ``auto`` if you want more type inference. + - The type ``auto`` is now a "multi-bind" metatype, so the following compiles: + + .. code-block:: nim + proc f(x, y: auto): auto = + result = $x & y + + echo f(0, "abc") Library Additions @@ -116,24 +123,20 @@ News - ``when nimvm`` can now be used for compiletime versions of some code sections. Click `here `_ for details. - Usage of the type ``NimNode`` in a proc now implicitly annotates the proc - with ``.compileTime``. This means generics work much better - for ``NimNode``. + with ``.compileTime``. This means generics work much better for ``NimNode``. Bugfixes -------- - - Fixed "Compiler internal error on iterator it(T: typedesc[Base]) called with - it(Child), where Child = object of Base" + - Fixed "Compiler internal error on iterator it(T: typedesc[Base]) called with it(Child), where Child = object of Base" (`#2662 `_) - Fixed "repr() misses base object field in 2nd level derived object" (`#2749 `_) - Fixed "nimsuggest doesn't work more than once on the non-main file" (`#2694 `_) - - Fixed "JS Codegen. Passing arguments by var in certain cases leads to invali -d JS." + - Fixed "JS Codegen. Passing arguments by var in certain cases leads to invalid JS." (`#2798 `_) - - Fixed ""check" proc in unittest.nim prevents the propagation of changes to v -ar parameters." + - Fixed ""check" proc in unittest.nim prevents the propagation of changes to var parameters." (`#964 `_) - Fixed "Excessive letters in integer literals are not an error" (`#2523 `_) @@ -147,8 +150,7 @@ ar parameters." (`#2687 `_) - Fixed "Compile error using object in const array" (`#2774 `_) - - Fixed "httpclient async requests with method httpPOST isn't sending Content- -Length header" + - Fixed "httpclient async requests with method httpPOST isn't sending Content-Length header" (`#2884 `_) - Fixed "Streams module not working with JS backend" (`#2148 `_) @@ -179,8 +181,7 @@ Length header" (`#2974 `_) - Fixed "repr is broken" (`#2992 `_) - - Fixed "Ipv6 devel - add IPv6 support for asyncsockets, make AF_INET6 a defau -lt" + - Fixed "Ipv6 devel - add IPv6 support for asyncsockets, make AF_INET6 a default" (`#2976 `_) - Fixed "Compilation broken on windows" (`#2996 `_) @@ -190,8 +191,7 @@ lt" (`#2672 `_) - Fixed "Uncatched exception in async procedure on raise statement" (`#3014 `_) - - Fixed "nim doc2 fails in Mac OS X due to system.nim (possibly related to #18 -98)" + - Fixed "nim doc2 fails in Mac OS X due to system.nim (possibly related to #1898)" (`#3005 `_) - Fixed "IndexError when rebuilding Nim on iteration 2" (`#3018 `_) @@ -239,8 +239,7 @@ lt" (`#3054 `_) - Fixed "Wrong sharing of static_t instantations" (`#3112 `_) - - Fixed "Automatically generated proc conflicts with user-defined proc when .e -xportc.'ed" + - Fixed "Automatically generated proc conflicts with user-defined proc when .exportc.'ed" (`#3134 `_) - Fixed "getTypeInfo call crashes nim" (`#3099 `_) @@ -260,15 +259,13 @@ xportc.'ed" (`#3149 `_) - Fixed "Inference of `static[T]` in sequences" (`#3144 `_) - - Fixed "Argument named "closure" to proc inside template interfere with closu -re pragma" + - Fixed "Argument named "closure" to proc inside template interfere with closure pragma" (`#3171 `_) - Fixed "Internal error with aliasing inside template" (`#3158 `_) - Fixed "Cardinality of sets prints unexpected value" (`#3135 `_) - - Fixed "Nim crashes on const assignment from function returning var ref objec -t" + - Fixed "Nim crashes on const assignment from function returning var ref object" (`#3103 `_) - Fixed "`repr` cstring" (`#3080 `_) @@ -276,8 +273,7 @@ t" (`#3052 `_) - Fixed "Compiler assertion when evaluating template with static[T]" (`#1858 `_) - - Fixed "Erroneous overflow in iterators when compiler built with overflowChec -ks enabled" + - Fixed "Erroneous overflow in iterators when compiler built with overflowChecks enabled" (`#3140 `_) - Fixed "Unicode dashes as "lisp'ish" alternative to hump and snake notation" (`#2811 `_) @@ -289,8 +285,7 @@ ks enabled" (`#3193 `_) - Fixed "VM crash when accessing array's element" (`#3192 `_) - - Fixed "Unexpected proc invoked when different modules add procs to a type fr -om a 3rd module" + - Fixed "Unexpected proc invoked when different modules add procs to a type from a 3rd module" (`#2664 `_) - Fixed "Nim crashes on conditional declaration inside a template" (`#2670 `_) @@ -298,8 +293,7 @@ om a 3rd module" (`#2752 `_) - Fixed "VM: Cannot assign int value to ref variable" (`#1329 `_) - - Fixed "Incorrect code generated for tagged unions with enums not starting at - zero" + - Fixed "Incorrect code generated for tagged unions with enums not starting at zero" (`#3096 `_) - Fixed "Compile time procs using forward declarations are silently ignored" (`#3066 `_) @@ -307,8 +301,7 @@ om a 3rd module" (`#1965 `_) - Fixed "os.getCreationTime is incorrect/impossible on Posix systems" (`#1058 `_) - - Fixed "Improve error message for osproc.startProcess when command does not e -xist" + - Fixed "Improve error message for osproc.startProcess when command does not exist" (`#2183 `_) - Fixed "gctest segfaults with --gc:markandsweep on x86_64" (`#2305 `_) From 1251fc76c32bdd50a3b9540e0cd80b0c435051ce Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 14 Sep 2015 20:30:55 +0200 Subject: [PATCH 16/19] fixes #3212 --- compiler/semexprs.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 84cbbdc93e..0e1d52fd4c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -452,18 +452,18 @@ proc changeType(n: PNode, newType: PType, check: bool) = let tup = newType.skipTypes({tyGenericInst}) if tup.kind != tyTuple: if tup.kind == tyObject: return - internalError(n.info, "changeType: no tuple type for constructor") + globalError(n.info, "no tuple type for constructor") elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr: # named tuple? for i in countup(0, sonsLen(n) - 1): var m = n.sons[i].sons[0] if m.kind != nkSym: - internalError(m.info, "changeType(): invalid tuple constr") + globalError(m.info, "invalid tuple constructor") return if tup.n != nil: var f = getSymFromList(tup.n, m.sym.name) if f == nil: - internalError(m.info, "changeType(): invalid identifier") + globalError(m.info, "unknown identifier: " & m.sym.name.s) return changeType(n.sons[i].sons[1], f.typ, check) else: From 4da5e474148db9298ec0d730046544278d7e6827 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 15 Sep 2015 10:37:16 +0100 Subject: [PATCH 17/19] Implements getPeerAddr/getPeerName on Windows and adds IDX. --- lib/pure/net.nim | 8 ++++++-- lib/pure/rawsockets.nim | 4 ++++ lib/windows/winlean.nim | 8 +++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index b7a40121fa..0ce5b4d25d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -534,11 +534,15 @@ proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {. result = res != 0 proc getLocalAddr*(socket: Socket): (string, Port) = - ## Get the socket's local address and port number + ## Get the socket's local address and port number. + ## + ## This is high-level interface for `getsockname`:idx:. getLocalAddr(socket.fd, socket.domain) proc getPeerAddr*(socket: Socket): (string, Port) = - ## Get the socket's peer address and port number + ## Get the socket's peer address and port number. + ## + ## This is high-level interface for `getpeername`:idx:. getPeerAddr(socket.fd, socket.domain) proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {. diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim index 0a69b580e5..f5860ef282 100644 --- a/lib/pure/rawsockets.nim +++ b/lib/pure/rawsockets.nim @@ -373,6 +373,8 @@ proc getSockName*(socket: SocketHandle): Port = proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = ## returns the socket's local address and port number. + ## + ## Similar to POSIX's `getsockname`:idx:. case domain of AF_INET: var name: Sockaddr_in @@ -406,6 +408,8 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) = ## returns the socket's peer address and port number. + ## + ## Similar to POSIX's `getpeername`:idx: case domain of AF_INET: var name: Sockaddr_in diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 24015dd3a6..84dac6d798 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -409,7 +409,7 @@ type bytes*: array[0..15, char] Sockaddr_in6* {.importc: "SOCKADDR_IN6", - header: "winsock2.h".} = object + header: "ws2tcpip.h".} = object sin6_family*: int16 sin6_port*: int16 # unsigned sin6_flowinfo*: int32 # unsigned @@ -511,6 +511,9 @@ proc connect*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {. proc getsockname*(s: SocketHandle, name: ptr SockAddr, namelen: ptr SockLen): cint {. stdcall, importc: "getsockname", dynlib: ws2dll.} +proc getpeername*(s: SocketHandle, name: ptr SockAddr, + namelen: ptr SockLen): cint {. + stdcall, importc, dynlib: ws2dll.} proc getsockopt*(s: SocketHandle, level, optname: cint, optval: pointer, optlen: ptr SockLen): cint {. stdcall, importc: "getsockopt", dynlib: ws2dll.} @@ -572,6 +575,9 @@ proc freeaddrinfo*(ai: ptr AddrInfo) {. proc inet_ntoa*(i: InAddr): cstring {. stdcall, importc, dynlib: ws2dll.} +proc inet_ntop*(family: cint, paddr: pointer, pStringBuffer: cstring, + stringBufSize: int32): cstring {.stdcall, importc, dynlib: ws2dll.} + const MAXIMUM_WAIT_OBJECTS* = 0x00000040 From 2ffb38561190381ae166684b3727d32c2d908ca0 Mon Sep 17 00:00:00 2001 From: Bruce Doan Date: Wed, 16 Sep 2015 17:29:14 +0700 Subject: [PATCH 18/19] wait's input is nullable, and it is discardable --- lib/posix/posix.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index d264dc02a9..8486fa04f0 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -2316,7 +2316,7 @@ proc timer_settime*(a1: Timer, a2: cint, a3: var Itimerspec, proc tzset*() {.importc, header: "".} -proc wait*(a1: var cint): Pid {.importc, header: "".} +proc wait*(a1: ptr cint): Pid {.importc, discardable, header: "".} proc waitid*(a1: cint, a2: Id, a3: var SigInfo, a4: cint): cint {. importc, header: "".} proc waitpid*(a1: Pid, a2: var cint, a3: cint): Pid {. From 29a91669667344e3637dbff4fc2009c263af3e11 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 16 Sep 2015 15:34:54 +0200 Subject: [PATCH 19/19] fixes the most pressing regressions introduced by the new handling of a[i] in the compiler --- compiler/semgnrc.nim | 34 ++++++++++++++++++++++++++++------ compiler/semmagic.nim | 25 ++++++++++++++++--------- lib/system.nim | 1 + 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index ed0244b0c6..9c9281da01 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -30,6 +30,13 @@ type GenericCtx = object toMixin: IntSet cursorInBody: bool # only for nimsuggest + bracketExpr: PNode + +template withBracketExpr(x, body: untyped) = + let old = ctx.bracketExpr + ctx.bracketExpr = x + body + ctx.bracketExpr = old type TSemGenericFlag = enum @@ -227,6 +234,10 @@ proc semGenericStmt(c: PContext, n: PNode, discard of skProc, skMethod, skIterators, skConverter, skModule: result.sons[0] = symChoice(c, fn, s, scOption) + # do check of 's.magic==mRoof' here because it might be some + # other '^' but after overload resolution the proper one: + if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^": + result.add ctx.bracketExpr first = 1 of skGenericParam: result.sons[0] = newSymNodeTypeDesc(s, fn.info) @@ -251,12 +262,17 @@ proc semGenericStmt(c: PContext, n: PNode, let flags = if mixinContext: flags+{withinMixin} else: flags for i in countup(first, sonsLen(result) - 1): result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx) - of nkBracketExpr, nkCurlyExpr: + of nkCurlyExpr: result = newNodeI(nkCall, n.info) - result.add newIdentNode(getIdent(if n.kind == nkBracketExpr:"[]" else:"{}"), - n.info) + result.add newIdentNode(getIdent("{}"), n.info) for i in 0 ..< n.len: result.add(n[i]) result = semGenericStmt(c, result, flags, ctx) + of nkBracketExpr: + result = newNodeI(nkCall, n.info) + result.add newIdentNode(getIdent("[]"), n.info) + for i in 0 ..< n.len: result.add(n[i]) + withBracketExpr n.sons[0]: + result = semGenericStmt(c, result, flags, ctx) of nkAsgn, nkFastAsgn: checkSonsLen(n, 2) let a = n.sons[0] @@ -264,13 +280,19 @@ proc semGenericStmt(c: PContext, n: PNode, let k = a.kind case k - of nkBracketExpr, nkCurlyExpr: + of nkCurlyExpr: result = newNodeI(nkCall, n.info) - result.add newIdentNode(getIdent(if k == nkBracketExpr:"[]=" else:"{}="), - n.info) + result.add newIdentNode(getIdent("{}="), n.info) for i in 0 ..< a.len: result.add(a[i]) result.add(b) result = semGenericStmt(c, result, flags, ctx) + of nkBracketExpr: + result = newNodeI(nkCall, n.info) + result.add newIdentNode(getIdent("[]="), n.info) + for i in 0 ..< a.len: result.add(a[i]) + result.add(b) + withBracketExpr a.sons[0]: + result = semGenericStmt(c, result, flags, ctx) else: for i in countup(0, sonsLen(n) - 1): result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 65185f762a..deef38ae32 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -32,6 +32,9 @@ type proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode +proc skipAddr(n: PNode): PNode {.inline.} = + (if n.kind == nkHiddenAddr: n.sons[0] else: n) + proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode = result = newNodeI(nkBracketExpr, n.info) for i in 1.. 2 and isNegative(n.sons[2])): localError(n.info, "use '^' instead of '-'; negative indexing is obsolete") of mRoof: - # error correction: - result = n.sons[1] - if c.p.bracketExpr.isNil: + let bracketExpr = if n.len == 3: n.sons[2] else: c.p.bracketExpr + if bracketExpr.isNil: localError(n.info, "no surrounding array access context for '^'") - elif c.p.bracketExpr.checkForSideEffects != seNoSideEffect: + result = n.sons[1] + elif bracketExpr.checkForSideEffects != seNoSideEffect: localError(n.info, "invalid context for '^' as '$#' has side effects" % - renderTree(c.p.bracketExpr)) - elif c.p.bracketExpr.typ.isStrangeArray: + renderTree(bracketExpr)) + result = n.sons[1] + elif bracketExpr.typ.isStrangeArray: localError(n.info, "invalid context for '^' as len!=high+1 for '$#'" % - renderTree(c.p.bracketExpr)) + renderTree(bracketExpr)) + result = n.sons[1] else: # ^x is rewritten to: len(a)-x let lenExpr = newNodeI(nkCall, n.info) lenExpr.add newIdentNode(getIdent"len", n.info) - lenExpr.add c.p.bracketExpr + lenExpr.add bracketExpr let lenExprB = semExprWithType(c, lenExpr) if lenExprB.typ.isNil or not isOrdinalType(lenExprB.typ): localError(n.info, "'$#' has to be of an ordinal type for '^'" % renderTree(lenExpr)) + result = n.sons[1] else: result = newNodeIT(nkCall, n.info, getSysType(tyInt)) result.add newSymNode(createMagic("-", mSubI), n.info) diff --git a/lib/system.nim b/lib/system.nim index 27c23e0bc4..8f529b8c0f 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -3465,6 +3465,7 @@ proc procCall*(x: expr) {.magic: "ProcCall", compileTime.} = ## procCall someMethod(a, b) discard +proc `^`*[T](x: int; y: openArray[T]): int {.noSideEffect, magic: "Roof".} proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} = ## builtin `roof`:idx: operator that can be used for convenient array access. ## ``a[^x]`` is rewritten to ``a[a.len-x]``. However currently the ``a``