implemented optional pragma for implicit discard

This commit is contained in:
Araq
2011-09-24 13:55:24 +02:00
parent 033e3dfc50
commit 72ceda98cb
11 changed files with 53 additions and 21 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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