From 72ceda98cbbef896c31102a2c90d5f9fe1033d03 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 24 Sep 2011 13:55:24 +0200 Subject: [PATCH] implemented optional pragma for implicit discard --- compiler/ast.nim | 7 ++++--- compiler/ccgexprs.nim | 2 +- compiler/cgen.nim | 4 ++-- compiler/pragmas.nim | 11 +++++++---- compiler/semexprs.nim | 6 ++++-- compiler/semthreads.nim | 2 +- compiler/wordrecg.nim | 4 ++-- doc/manual.txt | 22 +++++++++++++++++----- tests/accept/compile/toptional_pragma.nim | 13 +++++++++++++ todo.txt | 1 - web/news.txt | 2 ++ 11 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 tests/accept/compile/toptional_pragma.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index fb4300c890..fc2348a77f 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -197,7 +197,7 @@ type # be written into the ROD file sfGlobal, # symbol is at global scope - sfForward, # symbol is forward directed + sfForward, # symbol is forward declared sfImportc, # symbol is external; imported sfExportc, # symbol is exported (under a specified name) sfVolatile, # variable is volatile @@ -218,15 +218,16 @@ type sfError, # usage of symbol should trigger a compile-time error sfInClosure, # variable is accessed by a closure sfThread, # proc will run as a thread + # variable is a thread variable sfCompileTime, # proc can be evaluated at compile time - sfThreadVar, # variable is a thread variable sfMerge, # proc can be merged with itself sfDeadCodeElim, # dead code elimination for the module is turned on sfBorrow, # proc is borrowed sfInfixCall, # symbol needs infix call syntax in target language; # for interfacing with C++, JS - sfNamedParamCall # symbol needs named parameter call syntax in target + sfNamedParamCall, # symbol needs named parameter call syntax in target # language; for interfacing with Objective C + sfOptional # returned value may be discarded implicitely TSymFlags* = set[TSymFlag] diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 0b07eaeb1d..409dd51c22 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1761,7 +1761,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) = if sfGlobal in sym.flags: genVarPrototype(p.module, sym) if sym.loc.r == nil or sym.loc.t == nil: InternalError(e.info, "expr: var not init " & sym.name.s) - if sfThreadVar in sym.flags: + if sfThread in sym.flags: AccessThreadLocalVar(p, sym) if emulatedThreadVars(): putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r)) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 4188e7df0e..70b3069cf5 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -445,7 +445,7 @@ proc assignGlobalVar(p: BProc, s: PSym) = fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap) useHeader(p.module, s) if lfNoDecl in s.loc.flags: return - if sfThreadVar in s.flags: + if sfThread in s.flags: declareThreadVar(p.module, s, sfImportc in s.flags) else: if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ") @@ -724,7 +724,7 @@ proc genVarPrototype(m: BModule, sym: PSym) = if sym.owner.id != m.module.id: # else we already have the symbol generated! assert(sym.loc.r != nil) - if sfThreadVar in sym.flags: + if sfThread in sym.flags: declareThreadVar(m, sym, true) else: app(m.s[cfsVars], "extern ") diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 9bc5adf656..dc120ef1d7 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -23,15 +23,15 @@ const wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, - wNoStackFrame, wError} + wNoStackFrame, wError, wOptional} converterPragmas* = procPragmas methodPragmas* = procPragmas macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern, - wImportcpp, wImportobjc, wError} + wImportcpp, wImportobjc, wError, wOptional} iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, - wImportcpp, wImportobjc, wError} + wImportcpp, wImportobjc, wError, wOptional} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal, @@ -461,7 +461,7 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = incl(sym.flags, sfRegister) of wThreadVar: noVal(it) - incl(sym.flags, sfThreadVar) + incl(sym.flags, sfThread) of wDeadCodeElim: pragmaDeadCodeElim(c, it) of wMagic: processMagic(c, it, sym) of wCompileTime: @@ -553,6 +553,9 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = of wPragma: processPragma(c, n, i) break + of wOptional: + noVal(it) + if sym != nil: incl(sym.flags, sfOptional) of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir, wStacktrace, wLinetrace, wOptimization, wByRef, diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 95808b85af..5e9f9e28de 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -548,11 +548,14 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode = addSon(result, semExpr(c, arg)) proc semExprNoType(c: PContext, n: PNode): PNode = + proc ImplicitelyDiscardable(n: PNode): bool {.inline.} = + result = isCallExpr(n) and n.sons[0].kind == nkSym and + sfOptional in n.sons[0].sym.flags result = semExpr(c, n) if result.typ != nil and result.typ.kind != tyStmt: if gCmd == cmdInteractive: result = buildEchoStmt(c, result) - else: + elif not ImplicitelyDiscardable(result): localError(n.info, errDiscardValue) proc isTypeExpr(n: PNode): bool = @@ -1196,7 +1199,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of skMacro: result = semMacroExpr(c, n, s) of skTemplate: result = semTemplateExpr(c, n, s) of skType: - if n.kind != nkCall: GlobalError(n.info, errXisNotCallable, s.name.s) # XXX think about this more (``set`` procs) if n.len == 2: result = semConv(c, n, s) diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim index 66760a3c83..16c9f2738f 100755 --- a/compiler/semthreads.nim +++ b/compiler/semthreads.nim @@ -110,7 +110,7 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner = of skVar, skResult: result = toNil if sfGlobal in v.flags: - if sfThreadVar in v.flags: + if sfThread in v.flags: result = toMine elif containsGarbageCollectedRef(v.typ): result = toTheirs diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 6ba47fb942..0389439ddb 100755 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -51,7 +51,7 @@ type wDeadCodeElim, wSafecode, wPragma, wCompileTime, - wPassc, wPassl, wBorrow, + wPassc, wPassl, wBorrow, wOptional, wFieldChecks, wCheckPoint, wSubsChar, wAcyclic, wShallow, wUnroll, wLinearScanEnd, @@ -96,7 +96,7 @@ const "deadcodeelim", "safecode", "pragma", "compiletime", - "passc", "passl", "borrow", "fieldchecks", + "passc", "passl", "borrow", "optional", "fieldchecks", "checkpoint", "subschar", "acyclic", "shallow", "unroll", "linearscanend", "write", "putenv", "prependenv", "appendenv", "threadvar", "emit", diff --git a/doc/manual.txt b/doc/manual.txt index 122668dfbc..55a0086324 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -1474,14 +1474,26 @@ Syntax:: Example: .. code-block:: nimrod + proc p(x, y: int): int {.optional.} = + return x + y - discard proc_call("arg1", "arg2") # discard the return value of `proc_call` + discard p(3, 4) # discard the return value of `p` The `discard`:idx: statement evaluates its expression for side-effects and -throws the expression's resulting value away. If the expression has no -side-effects, this generates a static error. Ignoring the return value of a -procedure without using a discard statement is a static error too. - +throws the expression's resulting value away. + +Ignoring the return value of a procedure without using a discard statement is +a static error. + +The return value can be ignored implicitely if the called proc/iterator has +been declared with the `optional`:idx: pragma: + +.. code-block:: nimrod + proc p(x, y: int): int {.optional.} = + return x + y + + p(3, 4) # now valid + Var statement ~~~~~~~~~~~~~ diff --git a/tests/accept/compile/toptional_pragma.nim b/tests/accept/compile/toptional_pragma.nim new file mode 100644 index 0000000000..80ebe68a3e --- /dev/null +++ b/tests/accept/compile/toptional_pragma.nim @@ -0,0 +1,13 @@ +# Test the optional pragma + +proc p(x, y: int): int {.optional.} = + return x + y + +# test that it is inherited from generic procs too: +proc q[T](x, y: T): T {.optional.} = + return x + y + + +p(8, 2) +q[float](0.8, 0.2) + diff --git a/todo.txt b/todo.txt index 7a2c6dbf7f..19abdb298b 100755 --- a/todo.txt +++ b/todo.txt @@ -2,7 +2,6 @@ Version 0.8.14 ============== - 'let x = y' -- T(x) as l-value - fix actors.nim - make threadvar efficient again on linux after testing - fix the 'const' issues diff --git a/web/news.txt b/web/news.txt index 462133d249..a531f03341 100755 --- a/web/news.txt +++ b/web/news.txt @@ -47,6 +47,8 @@ Language Additions - Return types may be of the type ``var T`` to return an l-value. - The error pragma can now be used to mark symbols whose *usage* should trigger a compile-time error. +- There is a new ``optional`` pragma that can be used to mark a routine so that + its result can be discarded implicitely. Compiler Additions