mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-31 18:32:11 +00:00
implemented optional pragma for implicit discard
This commit is contained in:
@@ -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]
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 ")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
13
tests/accept/compile/toptional_pragma.nim
Normal file
13
tests/accept/compile/toptional_pragma.nim
Normal 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)
|
||||
|
||||
1
todo.txt
1
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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user