diff options
-rw-r--r-- | compiler/ccgexprs.nim | 6 | ||||
-rw-r--r-- | tests/generics/tgeneric_closure.nim | 37 | ||||
-rw-r--r-- | tests/generics/tunique_type.nim | 60 |
3 files changed, 101 insertions, 2 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 4372ca524..93bb5dbf5 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -215,6 +215,7 @@ proc asgnComplexity(n: PNode): int = else: discard proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc = + assert field != nil result.k = locField result.s = a.s result.t = t @@ -229,7 +230,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = flags - {needToCopy} else: flags - let t = skipTypes(dest.t, abstractInst) + let t = skipTypes(dest.t, abstractInst).getUniqueType() for i in 0 .. <t.len: let t = t.sons[i] let field = ropef("Field$1", i.toRope) @@ -336,6 +337,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = elif needsComplexAssignment(ty): if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4: discard getTypeDesc(p.module, ty) + ty = getUniqueType(ty) internalAssert ty.n != nil genOptAsgnObject(p, dest, src, flags, ty.n) else: @@ -1131,7 +1133,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = var tmp2: TLoc tmp2.r = r var field: PSym = nil - var ty = t + var ty = getUniqueType(t) while ty != nil: field = lookupInRecord(ty.n, it.sons[0].sym.name) if field != nil: break diff --git a/tests/generics/tgeneric_closure.nim b/tests/generics/tgeneric_closure.nim new file mode 100644 index 000000000..7198dce96 --- /dev/null +++ b/tests/generics/tgeneric_closure.nim @@ -0,0 +1,37 @@ +# Test to ensure TEventHandler is '.closure' + +# bug #1187 + +type + TEventArgs* = object + skip*: bool + TEventHandler[T] = proc (e: var TEventArgs, data: T) {.closure.} + TEvent*[T] = object + #handlers: seq[TEventHandler[T]] # Does not work + handlers: seq[proc (e: var TEventArgs, data: T) {.closure.}] # works + + TData = object + x: int + + TSomething = object + s: TEvent[TData] + +proc init*[T](e: var TEvent[T]) = + e.handlers.newSeq(0) + +#proc add*[T](e: var TEvent[T], h: proc (e: var TEventArgs, data: T) {.closure.}) = +# this line works +proc add*[T](e: var TEvent[T], h: TEventHandler[T]) = + # this line does not work + e.handlers.add(h) + +proc main () = + var something: TSomething + something.s.init() + var fromOutside = 4711 + + something.s.add() do (e: var TEventArgs, data: TData): + var x = data.x + x = fromOutside + +main() diff --git a/tests/generics/tunique_type.nim b/tests/generics/tunique_type.nim new file mode 100644 index 000000000..f8901d3bd --- /dev/null +++ b/tests/generics/tunique_type.nim @@ -0,0 +1,60 @@ +# Bug #2022 + +## The goal of this snippet is to provide and test a construct for general- +## purpose, random-access mapping. I use an AST-manipulation-based approach +## because it's more efficient than using procedure pointers and less +## verbose than defining a new callable type for every invocation of `map`. + +import future +import macros +import strutils + +#=============================================================================== +# Define a system for storing copies of ASTs as static strings. +# This serves the same purpose as D's `alias` parameters for types, used heavily +# in its popular `ranges` and `algorithm` modules. + +var exprNodes {.compileTime.} = newSeq[PNimrodNode]() + +proc refExpr(exprNode: PNimrodNode): string {.compileTime.} = + exprNodes.add exprNode.copy + "expr" & $(exprNodes.len - 1) + +proc derefExpr(exprRef: string): PNimrodNode {.compileTime.} = + exprNodes[parseInt(exprRef[4 .. -1])] + +#=============================================================================== +# Define a type that allows a callable expression to be mapped onto elements +# of an indexable collection. + +type Mapped[Input; predicate: static[string]] = object + input: Input + +macro map(input, predicate: expr): expr = + newNimNode(nnkObjConstr).add( + newNimNode(nnkBracketExpr).add( + ident"Mapped", + newNimNode(nnkTypeOfExpr).add(input), + newLit(refExpr(predicate))), + newNimNode(nnkExprColonExpr).add( + ident"input", input)) + +proc `[]`(m: Mapped, i: int): auto = + macro buildResult: expr = + newCall( + derefExpr(m.predicate), + newNimNode(nnkBracketExpr).add( + newDotExpr(ident"m", ident"input"), + ident"i")) + buildResult() + +#=============================================================================== +# Test out our generic mapping construct. + +let a = "a-string".map(ord) +let b = @["a", "seq"].map((e: string) => e == "a") +let c = "another-string".map((e: char) => e == 'o') + +echo(@[a[0], a[1]]) # @[97, 45] +echo(@[b[0], b[1]]) # @[true, false] +echo(@[c[0], c[1]]) # @[false, false] |