implemented optional pragma for implicit discard

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

View file

@ -197,7 +197,7 @@ type
# be written into the ROD file # be written into the ROD file
sfGlobal, # symbol is at global scope sfGlobal, # symbol is at global scope
sfForward, # symbol is forward directed sfForward, # symbol is forward declared
sfImportc, # symbol is external; imported sfImportc, # symbol is external; imported
sfExportc, # symbol is exported (under a specified name) sfExportc, # symbol is exported (under a specified name)
sfVolatile, # variable is volatile sfVolatile, # variable is volatile
@ -218,15 +218,16 @@ type
sfError, # usage of symbol should trigger a compile-time error sfError, # usage of symbol should trigger a compile-time error
sfInClosure, # variable is accessed by a closure sfInClosure, # variable is accessed by a closure
sfThread, # proc will run as a thread sfThread, # proc will run as a thread
# variable is a thread variable
sfCompileTime, # proc can be evaluated at compile time sfCompileTime, # proc can be evaluated at compile time
sfThreadVar, # variable is a thread variable
sfMerge, # proc can be merged with itself sfMerge, # proc can be merged with itself
sfDeadCodeElim, # dead code elimination for the module is turned on sfDeadCodeElim, # dead code elimination for the module is turned on
sfBorrow, # proc is borrowed sfBorrow, # proc is borrowed
sfInfixCall, # symbol needs infix call syntax in target language; sfInfixCall, # symbol needs infix call syntax in target language;
# for interfacing with C++, JS # 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 # language; for interfacing with Objective C
sfOptional # returned value may be discarded implicitely
TSymFlags* = set[TSymFlag] 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 sfGlobal in sym.flags: genVarPrototype(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil: if sym.loc.r == nil or sym.loc.t == nil:
InternalError(e.info, "expr: var not init " & sym.name.s) InternalError(e.info, "expr: var not init " & sym.name.s)
if sfThreadVar in sym.flags: if sfThread in sym.flags:
AccessThreadLocalVar(p, sym) AccessThreadLocalVar(p, sym)
if emulatedThreadVars(): if emulatedThreadVars():
putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r)) 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) fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap)
useHeader(p.module, s) useHeader(p.module, s)
if lfNoDecl in s.loc.flags: return 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) declareThreadVar(p.module, s, sfImportc in s.flags)
else: else:
if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ") 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: if sym.owner.id != m.module.id:
# else we already have the symbol generated! # else we already have the symbol generated!
assert(sym.loc.r != nil) assert(sym.loc.r != nil)
if sfThreadVar in sym.flags: if sfThread in sym.flags:
declareThreadVar(m, sym, true) declareThreadVar(m, sym, true)
else: else:
app(m.s[cfsVars], "extern ") app(m.s[cfsVars], "extern ")

View file

@ -23,15 +23,15 @@ const
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wNoStackFrame, wError} wNoStackFrame, wError, wOptional}
converterPragmas* = procPragmas converterPragmas* = procPragmas
methodPragmas* = procPragmas methodPragmas* = procPragmas
macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
wImportcpp, wImportobjc, wError} wImportcpp, wImportobjc, wError, wOptional}
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect, iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
wImportcpp, wImportobjc, wError} wImportcpp, wImportobjc, wError, wOptional}
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir,
wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal, 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) incl(sym.flags, sfRegister)
of wThreadVar: of wThreadVar:
noVal(it) noVal(it)
incl(sym.flags, sfThreadVar) incl(sym.flags, sfThread)
of wDeadCodeElim: pragmaDeadCodeElim(c, it) of wDeadCodeElim: pragmaDeadCodeElim(c, it)
of wMagic: processMagic(c, it, sym) of wMagic: processMagic(c, it, sym)
of wCompileTime: of wCompileTime:
@ -553,6 +553,9 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
of wPragma: of wPragma:
processPragma(c, n, i) processPragma(c, n, i)
break break
of wOptional:
noVal(it)
if sym != nil: incl(sym.flags, sfOptional)
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization, wByRef, wLinedir, wStacktrace, wLinetrace, wOptimization, wByRef,

View file

@ -548,11 +548,14 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
addSon(result, semExpr(c, arg)) addSon(result, semExpr(c, arg))
proc semExprNoType(c: PContext, n: PNode): PNode = 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) result = semExpr(c, n)
if result.typ != nil and result.typ.kind != tyStmt: if result.typ != nil and result.typ.kind != tyStmt:
if gCmd == cmdInteractive: if gCmd == cmdInteractive:
result = buildEchoStmt(c, result) result = buildEchoStmt(c, result)
else: elif not ImplicitelyDiscardable(result):
localError(n.info, errDiscardValue) localError(n.info, errDiscardValue)
proc isTypeExpr(n: PNode): bool = 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 skMacro: result = semMacroExpr(c, n, s)
of skTemplate: result = semTemplateExpr(c, n, s) of skTemplate: result = semTemplateExpr(c, n, s)
of skType: of skType:
if n.kind != nkCall: GlobalError(n.info, errXisNotCallable, s.name.s)
# XXX think about this more (``set`` procs) # XXX think about this more (``set`` procs)
if n.len == 2: if n.len == 2:
result = semConv(c, n, s) result = semConv(c, n, s)

View file

@ -110,7 +110,7 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner =
of skVar, skResult: of skVar, skResult:
result = toNil result = toNil
if sfGlobal in v.flags: if sfGlobal in v.flags:
if sfThreadVar in v.flags: if sfThread in v.flags:
result = toMine result = toMine
elif containsGarbageCollectedRef(v.typ): elif containsGarbageCollectedRef(v.typ):
result = toTheirs result = toTheirs

View file

@ -51,7 +51,7 @@ type
wDeadCodeElim, wSafecode, wDeadCodeElim, wSafecode,
wPragma, wPragma,
wCompileTime, wCompileTime,
wPassc, wPassl, wBorrow, wPassc, wPassl, wBorrow, wOptional,
wFieldChecks, wFieldChecks,
wCheckPoint, wSubsChar, wCheckPoint, wSubsChar,
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wAcyclic, wShallow, wUnroll, wLinearScanEnd,
@ -96,7 +96,7 @@ const
"deadcodeelim", "safecode", "deadcodeelim", "safecode",
"pragma", "pragma",
"compiletime", "compiletime",
"passc", "passl", "borrow", "fieldchecks", "passc", "passl", "borrow", "optional", "fieldchecks",
"checkpoint", "checkpoint",
"subschar", "acyclic", "shallow", "unroll", "linearscanend", "subschar", "acyclic", "shallow", "unroll", "linearscanend",
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit", "write", "putenv", "prependenv", "appendenv", "threadvar", "emit",

View file

@ -1474,14 +1474,26 @@ Syntax::
Example: Example:
.. code-block:: nimrod .. 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 The `discard`:idx: statement evaluates its expression for side-effects and
throws the expression's resulting value away. If the expression has no throws the expression's resulting value away.
side-effects, this generates a static error. Ignoring the return value of a
procedure without using a discard statement is a static error too. 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 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' - 'let x = y'
- T(x) as l-value
- fix actors.nim - fix actors.nim
- make threadvar efficient again on linux after testing - make threadvar efficient again on linux after testing
- fix the 'const' issues - 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. - 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 - The error pragma can now be used to mark symbols whose *usage* should trigger
a compile-time error. 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 Compiler Additions