Merge branch 'devel' into newasync

This commit is contained in:
Dominik Picheta 2014-02-11 23:50:58 +00:00
commit b3a0906619
15 changed files with 190 additions and 97 deletions

View file

@ -1376,7 +1376,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
getTemp(p, getSysType(tyInt), i) # our counter getTemp(p, getSysType(tyInt), i) # our counter
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, a.t, d) if d.k == locNone: getTemp(p, getSysType(tyBool), d)
lineF(p, cpsStmts, lookupOpr[op], lineF(p, cpsStmts, lookupOpr[op],
[rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)]) [rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
of mEqSet: of mEqSet:

View file

@ -332,6 +332,7 @@ proc myOpen(module: PSym): PPassContext =
c.semOperand = semOperand c.semOperand = semOperand
c.semConstBoolExpr = semConstBoolExpr c.semConstBoolExpr = semConstBoolExpr
c.semOverloadedCall = semOverloadedCall c.semOverloadedCall = semOverloadedCall
c.semGenerateInstance = generateInstance
c.semTypeNode = semTypeNode c.semTypeNode = semTypeNode
pushProcCon(c, module) pushProcCon(c, module)
pushOwner(c.module) pushOwner(c.module)

View file

@ -81,6 +81,8 @@ type
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
filter: TSymKinds): PNode {.nimcall.} filter: TSymKinds): PNode {.nimcall.}
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.} semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym
includedFiles*: TIntSet # used to detect recursive include files includedFiles*: TIntSet # used to detect recursive include files
userPragmas*: TStrTable userPragmas*: TStrTable
evalContext*: PEvalContext evalContext*: PEvalContext

View file

@ -204,7 +204,14 @@ proc semConv(c: PContext, n: PNode): PNode =
if not isSymChoice(op): if not isSymChoice(op):
let status = checkConvertible(c, result.typ, op.typ) let status = checkConvertible(c, result.typ, op.typ)
case status case status
of convOK: discard of convOK:
# handle SomeProcType(SomeGenericProc)
# XXX: This needs fixing. checkConvertible uses typeRel internally, but
# doesn't bother to perform the work done in paramTypeMatchAux/fitNode
# so we are redoing the typeRel work here. Why does semConv exist as a
# separate proc from fitNode?
if op.kind == nkSym and op.sym.isGenericRoutine:
result.sons[1] = fitNode(c, result.typ, result.sons[1])
of convNotNeedeed: of convNotNeedeed:
message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
of convNotLegal: of convNotLegal:

View file

@ -51,6 +51,8 @@ type
isSubtype, isSubtype,
isSubrange, # subrange of the wanted type; no type conversion isSubrange, # subrange of the wanted type; no type conversion
# but apart from that counts as ``isSubtype`` # but apart from that counts as ``isSubtype``
isInferred, # generic proc was matched against a concrete type
isInferredConvertible, # same as above, but requiring proc CC conversion
isGeneric, isGeneric,
isFromIntLit, # conversion *from* int literal; proven safe isFromIntLit, # conversion *from* int literal; proven safe
isEqual isEqual
@ -338,10 +340,40 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
proc allowsNil(f: PType): TTypeRelation {.inline.} = proc allowsNil(f: PType): TTypeRelation {.inline.} =
result = if tfNotNil notin f.flags: isSubtype else: isNone result = if tfNotNil notin f.flags: isSubtype else: isNone
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar) result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
proc procParamTypeRel(c: var TCandidate, f, a: PType,
result: var TTypeRelation) =
var
m: TTypeRelation
f = f
if a.isMetaType:
if f.isMetaType:
# we are matching a generic proc (as proc param)
# to another generic type appearing in the proc
# sigunature. there is a change that the target
# type is already fully-determined, so we are
# going to try resolve it
f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
if f == nil or f.isMetaType:
# no luck resolving the type, so the inference fails
result = isNone
return
let reverseRel = typeRel(c, a, f)
if reverseRel == isGeneric:
m = isInferred
else:
m = typeRel(c, f, a)
if m <= isSubtype or inconsistentVarTypes(f, a):
result = isNone
return
else:
result = minRel(m, result)
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
case a.kind case a.kind
of tyProc: of tyProc:
if sonsLen(f) != sonsLen(a): return if sonsLen(f) != sonsLen(a): return
@ -350,18 +382,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
result = isEqual # start with maximum; also correct for no result = isEqual # start with maximum; also correct for no
# params at all # params at all
for i in countup(1, sonsLen(f)-1): for i in countup(1, sonsLen(f)-1):
var m = typeRel(c, f.sons[i], a.sons[i]) procParamTypeRel(c, f.sons[i], a.sons[i], result)
if m <= isSubtype or inconsistentVarTypes(f.sons[i], a.sons[i]):
return isNone
else: result = minRel(m, result)
if f.sons[0] != nil: if f.sons[0] != nil:
if a.sons[0] != nil: if a.sons[0] != nil:
var m = typeRel(c, f.sons[0], a.sons[0]) procParamTypeRel(c, f.sons[0], a.sons[0], result)
# Subtype is sufficient for return types!
if m < isSubtype or inconsistentVarTypes(f.sons[0], a.sons[0]):
return isNone
elif m == isSubtype: result = isConvertible
else: result = minRel(m, result)
else: else:
return isNone return isNone
elif a.sons[0] != nil: elif a.sons[0] != nil:
@ -376,7 +400,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
elif f.callConv != a.callConv: elif f.callConv != a.callConv:
# valid to pass a 'nimcall' thingie to 'closure': # valid to pass a 'nimcall' thingie to 'closure':
if f.callConv == ccClosure and a.callConv == ccDefault: if f.callConv == ccClosure and a.callConv == ccDefault:
result = isConvertible result = if result != isInferred: isConvertible
else: isInferredConvertible
else: else:
return isNone return isNone
when useEffectSystem: when useEffectSystem:
@ -402,18 +427,8 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
proc matchUserTypeClass*(c: PContext, m: var TCandidate, proc matchUserTypeClass*(c: PContext, m: var TCandidate,
ff, a: PType): TTypeRelation = ff, a: PType): TTypeRelation =
#if f.n == nil:
# let r = typeRel(m, f, a)
# return if r == isGeneric: arg else: nil
var body = ff.skipTypes({tyUserTypeClassInst}) var body = ff.skipTypes({tyUserTypeClassInst})
# var prev = PType(idTableGet(m.bindings, f))
# if prev != nil:
# if sameType(prev, a): return arg
# else: return nil
# pushInfoContext(arg.info)
openScope(c) openScope(c)
inc c.inTypeClass inc c.inTypeClass
@ -462,7 +477,6 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
else: discard else: discard
return isGeneric return isGeneric
# put(m.bindings, f, a)
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# typeRel can be used to establish various relationships between types: # typeRel can be used to establish various relationships between types:
@ -1022,6 +1036,13 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
inc(m.subtypeMatches) inc(m.subtypeMatches)
#result = copyTree(arg) #result = copyTree(arg)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isInferred, isInferredConvertible:
var prc = if arg.kind in nkLambdaKinds: arg[0].sym
else: arg.sym
let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
result = newSymNode(inferred, arg.info)
if r == isInferredConvertible:
result = implicitConv(nkHiddenStdConv, f, result, m, c)
of isGeneric: of isGeneric:
inc(m.genericMatches) inc(m.genericMatches)
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}: if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:

View file

@ -441,7 +441,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
decodeBImm(nkIntLit) decodeBImm(nkIntLit)
#assert regs[rb].kind == nkBracket #assert regs[rb].kind == nkBracket
# also used by mNLen: # also used by mNLen:
regs[ra].intVal = regs[rb].skipMeta.len - imm regs[ra].intVal = regs[rb].skipMeta.safeLen - imm
of opcLenStr: of opcLenStr:
decodeBImm(nkIntLit) decodeBImm(nkIntLit)
if regs[rb].kind == nkNilLit: if regs[rb].kind == nkNilLit:

View file

@ -216,10 +216,12 @@ proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
internalAssert tmp >= 0 internalAssert tmp >= 0
result = TRegister(tmp) result = TRegister(tmp)
proc clearDest(n: PNode; dest: var TDest) {.inline.} = proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
# stmt is different from 'void' in meta programming contexts. # stmt is different from 'void' in meta programming contexts.
# So we only set dest to -1 if 'void': # So we only set dest to -1 if 'void':
if n.typ.isNil or n.typ.kind == tyEmpty: dest = -1 if dest >= 0 and (n.typ.isNil or n.typ.kind == tyEmpty):
c.freeTemp(dest)
dest = -1
proc isNotOpr(n: PNode): bool = proc isNotOpr(n: PNode): bool =
n.kind in nkCallKinds and n.sons[0].kind == nkSym and n.kind in nkCallKinds and n.sons[0].kind == nkSym and
@ -259,7 +261,7 @@ proc genWhile(c: PCtx; n: PNode) =
proc genBlock(c: PCtx; n: PNode; dest: var TDest) = proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
withBlock(n.sons[0].sym): withBlock(n.sons[0].sym):
c.gen(n.sons[1], dest) c.gen(n.sons[1], dest)
clearDest(n, dest) c.clearDest(n, dest)
proc genBreak(c: PCtx; n: PNode) = proc genBreak(c: PCtx; n: PNode) =
let L1 = c.xjmp(n, opcJmp) let L1 = c.xjmp(n, opcJmp)
@ -297,14 +299,16 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
else: else:
c.gen(it.sons[0], tmp) c.gen(it.sons[0], tmp)
elsePos = c.xjmp(it.sons[0], opcFJmp, tmp) # if false elsePos = c.xjmp(it.sons[0], opcFJmp, tmp) # if false
c.clearDest(n, dest)
c.gen(it.sons[1], dest) # then part c.gen(it.sons[1], dest) # then part
if i < sonsLen(n)-1: if i < sonsLen(n)-1:
endings.add(c.xjmp(it.sons[1], opcJmp, 0)) endings.add(c.xjmp(it.sons[1], opcJmp, 0))
c.patch(elsePos) c.patch(elsePos)
else: else:
c.clearDest(n, dest)
c.gen(it.sons[0], dest) c.gen(it.sons[0], dest)
for endPos in endings: c.patch(endPos) for endPos in endings: c.patch(endPos)
clearDest(n, dest) c.clearDest(n, dest)
proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) = proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
# asgn dest, a # asgn dest, a
@ -385,8 +389,8 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
if i < sonsLen(n)-1: if i < sonsLen(n)-1:
endings.add(c.xjmp(it.lastSon, opcJmp, 0)) endings.add(c.xjmp(it.lastSon, opcJmp, 0))
c.patch(elsePos) c.patch(elsePos)
c.clearDest(n, dest)
for endPos in endings: c.patch(endPos) for endPos in endings: c.patch(endPos)
clearDest(n, dest)
proc genType(c: PCtx; typ: PType): int = proc genType(c: PCtx; typ: PType): int =
for i, t in c.types: for i, t in c.types:
@ -400,6 +404,7 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
var endings: seq[TPosition] = @[] var endings: seq[TPosition] = @[]
let elsePos = c.xjmp(n, opcTry, 0) let elsePos = c.xjmp(n, opcTry, 0)
c.gen(n.sons[0], dest) c.gen(n.sons[0], dest)
c.clearDest(n, dest)
c.patch(elsePos) c.patch(elsePos)
for i in 1 .. <n.len: for i in 1 .. <n.len:
let it = n.sons[i] let it = n.sons[i]
@ -415,6 +420,7 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
# general except section: # general except section:
c.gABx(it, opcExcept, 0, 0) c.gABx(it, opcExcept, 0, 0)
c.gen(it.lastSon, dest) c.gen(it.lastSon, dest)
c.clearDest(n, dest)
if i < sonsLen(n)-1: if i < sonsLen(n)-1:
endings.add(c.xjmp(it, opcJmp, 0)) endings.add(c.xjmp(it, opcJmp, 0))
c.patch(endExcept) c.patch(endExcept)
@ -425,8 +431,8 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
c.gABx(fin, opcFinally, 0, 0) c.gABx(fin, opcFinally, 0, 0)
if fin.kind == nkFinally: if fin.kind == nkFinally:
c.gen(fin.sons[0], dest) c.gen(fin.sons[0], dest)
c.clearDest(n, dest)
c.gABx(fin, opcFinallyEnd, 0, 0) c.gABx(fin, opcFinallyEnd, 0, 0)
clearDest(n, dest)
proc genRaise(c: PCtx; n: PNode) = proc genRaise(c: PCtx; n: PNode) =
let dest = genx(c, n.sons[0]) let dest = genx(c, n.sons[0])
@ -860,7 +866,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym) of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI, mAbsI64: of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI, mAbsI64:
c.genCall(n, dest) c.genCall(n, dest)
clearDest(n, dest)
of mExpandToAst: of mExpandToAst:
if n.len != 2: if n.len != 2:
globalError(n.info, errGenerated, "expandToAst requires 1 argument") globalError(n.info, errGenerated, "expandToAst requires 1 argument")
@ -1281,7 +1286,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
genMagic(c, n, dest) genMagic(c, n, dest)
else: else:
genCall(c, n, dest) genCall(c, n, dest)
clearDest(n, dest) clearDest(c, n, dest)
of nkCharLit..nkInt64Lit: of nkCharLit..nkInt64Lit:
if isInt16Lit(n): if isInt16Lit(n):
if dest < 0: dest = c.getTemp(n.typ) if dest < 0: dest = c.getTemp(n.typ)

View file

@ -1701,11 +1701,11 @@ algorithm returns true:
result = isOrdinal(t) or t.kind in {float, float32, float64} result = isOrdinal(t) or t.kind in {float, float32, float64}
proc isExplicitlyConvertible(a, b: PType): bool = proc isExplicitlyConvertible(a, b: PType): bool =
result = false
if isImplicitlyConvertible(a, b): return true if isImplicitlyConvertible(a, b): return true
if typeEqualsOrDistinct(a, b): return true if typeEqualsOrDistinct(a, b): return true
if isIntegralType(a) and isIntegralType(b): return true if isIntegralType(a) and isIntegralType(b): return true
if isSubtype(a, b) or isSubtype(b, a): return true if isSubtype(a, b) or isSubtype(b, a): return true
return false
The convertible relation can be relaxed by a user-defined type The convertible relation can be relaxed by a user-defined type
`converter`:idx:. `converter`:idx:.
@ -1774,7 +1774,7 @@ Example:
.. code-block:: nimrod .. code-block:: nimrod
proc p(x, y: int): int = proc p(x, y: int): int =
return x + y result = x + y
discard p(3, 4) # discard the return value of `p` discard p(3, 4) # discard the return value of `p`
@ -1789,7 +1789,7 @@ been declared with the `discardable`:idx: pragma:
.. code-block:: nimrod .. code-block:: nimrod
proc p(x, y: int): int {.discardable.} = proc p(x, y: int): int {.discardable.} =
return x + y result = x + y
p(3, 4) # now valid p(3, 4) # now valid
@ -2440,7 +2440,7 @@ A procedure cannot modify its parameters (unless the parameters have the type
.. code-block:: nimrod .. code-block:: nimrod
proc `$` (x: int): string = proc `$` (x: int): string =
# converts an integer to a string; this is a prefix operator. # converts an integer to a string; this is a prefix operator.
return intToStr(x) result = intToStr(x)
Operators with one parameter are prefix operators, operators with two Operators with one parameter are prefix operators, operators with two
parameters are infix operators. (However, the parser distinguishes these from parameters are infix operators. (However, the parser distinguishes these from
@ -2454,7 +2454,7 @@ notation. (Thus an operator can have more than two parameters):
.. code-block:: nimrod .. code-block:: nimrod
proc `*+` (a, b, c: int): int = proc `*+` (a, b, c: int): int =
# Multiply and add # Multiply and add
return a * b + c result = a * b + c
assert `*+`(3, 4, 6) == `*`(a, `+`(b, c)) assert `*+`(3, 4, 6) == `*`(a, `+`(b, c))
@ -2500,7 +2500,7 @@ different; for this a special setter syntax is needed:
proc host*(s: TSocket): int {.inline.} = proc host*(s: TSocket): int {.inline.} =
## getter of hostAddr ## getter of hostAddr
return s.FHost s.FHost
var var
s: TSocket s: TSocket
@ -2650,11 +2650,12 @@ return values. This can be done in a cleaner way by returning a tuple:
.. code-block:: nimrod .. code-block:: nimrod
proc divmod(a, b: int): tuple[res, remainder: int] = proc divmod(a, b: int): tuple[res, remainder: int] =
return (a div b, a mod b) (a div b, a mod b)
var t = divmod(8, 5) var t = divmod(8, 5)
assert t.res == 1 assert t.res == 1
assert t.remainder = 3 assert t.remainder == 3
One can use `tuple unpacking`:idx: to access the tuple's fields: One can use `tuple unpacking`:idx: to access the tuple's fields:
@ -2726,7 +2727,7 @@ dispatch.
method eval(e: ref TPlusExpr): int = method eval(e: ref TPlusExpr): int =
# watch out: relies on dynamic binding # watch out: relies on dynamic binding
return eval(e.a) + eval(e.b) result = eval(e.a) + eval(e.b)
proc newLit(x: int): ref TLiteral = proc newLit(x: int): ref TLiteral =
new(result) new(result)
@ -2925,7 +2926,7 @@ parameters of an outer factory proc:
.. code-block:: nimrod .. code-block:: nimrod
proc mycount(a, b: int): iterator (): int = proc mycount(a, b: int): iterator (): int =
return iterator (): int = result = iterator (): int =
var x = a var x = a
while x <= b: while x <= b:
yield x yield x
@ -3375,9 +3376,9 @@ module to illustrate this:
## requires `x` and `y` to be of the same tuple type ## requires `x` and `y` to be of the same tuple type
## generic ``==`` operator for tuples that is lifted from the components ## generic ``==`` operator for tuples that is lifted from the components
## of `x` and `y`. ## of `x` and `y`.
result = true
for a, b in fields(x, y): for a, b in fields(x, y):
if a != b: return false if a != b: result = false
return true
Alternatively, the ``distinct`` type modifier can be applied to the type class 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. to allow each param matching the type class to bind to a different type.
@ -3999,9 +4000,9 @@ predicate:
proc re(pattern: semistatic[string]): TRegEx = proc re(pattern: semistatic[string]): TRegEx =
when isStatic(pattern): when isStatic(pattern):
return precompiledRegex(pattern) result = precompiledRegex(pattern)
else: else:
return compile(pattern) result = compile(pattern)
Static params can also appear in the signatures of generic types: Static params can also appear in the signatures of generic types:
@ -4508,7 +4509,7 @@ This is best illustrated by an example:
proc p*(x: A.T1): A.T1 = proc p*(x: A.T1): A.T1 =
# this works because the compiler has already # this works because the compiler has already
# added T1 to A's interface symbol table # added T1 to A's interface symbol table
return x + 1 result = x + 1
Import statement Import statement
@ -5136,41 +5137,43 @@ Example:
.. code-block:: nimrod .. code-block:: nimrod
{.deadCodeElim: on.} {.deadCodeElim: on.}
NoForward pragma
----------------
The `noforward`:idx: pragma can be used to turn on and off a special compilation
mode that to large extent eliminates the need for forward declarations. In this
mode, the proc definitions may appear out of order and the compiler will postpone
their semantic analysis and compilation until it actually needs to generate code
using the definitions. In this regard, this mode is similar to the modus operandi
of dynamic scripting languages, where the function calls are not resolved until
the code is executed. Here is the detailed algorithm taken by the compiler:
1. When a callable symbol is first encountered, the compiler will only note the ..
symbol callable name and it will add it to the appropriate overload set in the NoForward pragma
current scope. At this step, it won't try to resolve any of the type expressions ----------------
used in the signature of the symbol (so they can refer to other not yet defined The `noforward`:idx: pragma can be used to turn on and off a special compilation
symbols). mode that to large extent eliminates the need for forward declarations. In this
mode, the proc definitions may appear out of order and the compiler will postpone
their semantic analysis and compilation until it actually needs to generate code
using the definitions. In this regard, this mode is similar to the modus operandi
of dynamic scripting languages, where the function calls are not resolved until
the code is executed. Here is the detailed algorithm taken by the compiler:
2. When a top level call is encountered (usually at the very end of the module), 1. When a callable symbol is first encountered, the compiler will only note the
the compiler will try to determine the actual types of all of the symbols in the symbol callable name and it will add it to the appropriate overload set in the
matching overload set. This is a potentially recursive process as the signatures current scope. At this step, it won't try to resolve any of the type expressions
of the symbols may include other call expressions, whoose types will be resolved used in the signature of the symbol (so they can refer to other not yet defined
at this point too. symbols).
3. Finally, after the best overload is picked, the compiler will start compiling 2. When a top level call is encountered (usually at the very end of the module),
the body of the respective symbol. This in turn will lead the compiler to discover the compiler will try to determine the actual types of all of the symbols in the
more call expresions that need to be resolved and steps 2 and 3 will be repeated matching overload set. This is a potentially recursive process as the signatures
as necessary. of the symbols may include other call expressions, whoose types will be resolved
at this point too.
Please note that if a callable symbol is never used in this scenario, its body 3. Finally, after the best overload is picked, the compiler will start compiling
will never be compiled. This is the default behavior leading to best compilation the body of the respective symbol. This in turn will lead the compiler to discover
times, but if exhaustive compilation of all definitions is required, using more call expresions that need to be resolved and steps 2 and 3 will be repeated
``nimrod check`` provides this option as well. as necessary.
Example: Please note that if a callable symbol is never used in this scenario, its body
will never be compiled. This is the default behavior leading to best compilation
times, but if exhaustive compilation of all definitions is required, using
``nimrod check`` provides this option as well.
.. code-block:: nimrod Example:
.. code-block:: nimrod
{.noforward: on.} {.noforward: on.}
@ -5182,6 +5185,7 @@ Example:
foo(10) foo(10)
Pragma pragma Pragma pragma
------------- -------------
@ -5199,7 +5203,7 @@ Example:
{.pragma: rtl, importc, dynlib: "client.dll", cdecl.} {.pragma: rtl, importc, dynlib: "client.dll", cdecl.}
proc p*(a, b: int): int {.rtl.} = proc p*(a, b: int): int {.rtl.} =
return a+b result = a+b
In the example a new pragma named ``rtl`` is introduced that either imports In the example a new pragma named ``rtl`` is introduced that either imports
a symbol from a dynamic library or exports the symbol for dynamic library a symbol from a dynamic library or exports the symbol for dynamic library

View file

@ -690,8 +690,8 @@ Nimrod provides the ability to overload procedures similar to C++:
.. code-block:: nimrod .. code-block:: nimrod
proc toString(x: int): string = ... proc toString(x: int): string = ...
proc toString(x: bool): string = proc toString(x: bool): string =
if x: return "true" if x: result = "true"
else: return "false" else: result = "false"
echo(toString(13)) # calls the toString(x: int) proc echo(toString(13)) # calls the toString(x: int) proc
echo(toString(true)) # calls the toString(x: bool) proc echo(toString(true)) # calls the toString(x: bool) proc
@ -1569,7 +1569,7 @@ This is best illustrated by an example:
proc p*(x: A.T1): A.T1 = proc p*(x: A.T1): A.T1 =
# this works because the compiler has already # this works because the compiler has already
# added T1 to A's interface symbol table # added T1 to A's interface symbol table
return x + 1 result = x + 1
A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. If A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. If
@ -1600,11 +1600,11 @@ rules apply:
.. code-block:: nimrod .. code-block:: nimrod
# Module A # Module A
proc x*(a: int): string = return $a proc x*(a: int): string = result = $a
.. code-block:: nimrod .. code-block:: nimrod
# Module B # Module B
proc x*(a: string): string = return $a proc x*(a: string): string = result = $a
.. code-block:: nimrod .. code-block:: nimrod
# Module C # Module C

View file

@ -126,7 +126,7 @@ The syntax for type conversions is ``destination_type(expression_to_convert)``
.. code-block:: nimrod .. code-block:: nimrod
proc getID(x: TPerson): int = proc getID(x: TPerson): int =
return TStudent(x).id TStudent(x).id
The ``EInvalidObjectConversion`` exception is raised if ``x`` is not a The ``EInvalidObjectConversion`` exception is raised if ``x`` is not a
``TStudent``. ``TStudent``.
@ -238,7 +238,7 @@ is needed:
proc host*(s: TSocket): int {.inline.} = proc host*(s: TSocket): int {.inline.} =
## getter of hostAddr ## getter of hostAddr
return s.FHost s.FHost
var var
s: TSocket s: TSocket

View file

@ -241,3 +241,7 @@ proc `<=`*[A](s, t: TSet[A]): bool =
proc `==`*[A](s, t: TSet[A]): bool = proc `==`*[A](s, t: TSet[A]): bool =
s.counter == t.counter and s <= t s.counter == t.counter and s <= t
proc map*[A, B](data: TSet[A], op: proc (x: A): B {.closure.}): TSet[B] =
result = initSet[B]()
for item in data: result.incl(op(item))

View file

@ -0,0 +1,20 @@
discard """
output: '''123
1
2
3'''
"""
# https://github.com/Araq/Nimrod/issues/797
proc foo[T](s:T):string = $s
type IntStringProc = proc(x: int): string
var f1 = IntStringProc(foo)
var f2: proc(x: int): string = foo
var f3: IntStringProc = foo
echo f1(1), f2(2), f3(3)
for x in map([1,2,3], foo): echo x

12
tests/sets/tsets_lt.nim Normal file
View file

@ -0,0 +1,12 @@
discard """
output: '''true
true
true'''
"""
var s, s1: set[char]
s = {'a'..'d'}
s1 = {'a'..'c'}
echo s1 < s
echo s1 * s == {'a'..'c'}
echo s1 <= s

17
tests/stdlib/tsets.nim Normal file
View file

@ -0,0 +1,17 @@
discard """
output: '''true
true'''
"""
import sets
var
a = initSet[int]()
b = initSet[int]()
c = initSet[string]()
for i in 0..5: a.incl(i)
for i in 1..6: b.incl(i)
for i in 0..5: c.incl($i)
echo map(a, proc(x: int): int = x + 1) == b
echo map(a, proc(x: int): string = $x) == c