diff options
-rwxr-xr-x | lib/impure/re.nim | 10 | ||||
-rw-r--r-- | lib/pure/algorithm.nim | 101 | ||||
-rwxr-xr-x | lib/pure/strutils.nim | 9 | ||||
-rwxr-xr-x | lib/pure/unicode.nim | 18 | ||||
-rwxr-xr-x | lib/system.nim | 16 | ||||
-rwxr-xr-x | rod/ast.nim | 11 | ||||
-rw-r--r-- | rod/semcall.nim | 36 | ||||
-rwxr-xr-x | rod/semexprs.nim | 46 | ||||
-rwxr-xr-x | rod/semgnrc.nim | 22 | ||||
-rwxr-xr-x | rod/semstmts.nim | 8 | ||||
-rwxr-xr-x | rod/semtypes.nim | 13 | ||||
-rwxr-xr-x | rod/sigmatch.nim | 7 | ||||
-rw-r--r-- | rod/suggest.nim | 2 | ||||
-rw-r--r-- | tests/accept/compile/tsortdev.nim | 69 | ||||
-rwxr-xr-x | tests/accept/run/tgenerics1.nim | 76 | ||||
-rw-r--r-- | tests/gc/gcleak.nim | 11 | ||||
-rw-r--r-- | tests/reject/ttypenoval.nim | 55 | ||||
-rwxr-xr-x | todo.txt | 1 |
18 files changed, 395 insertions, 116 deletions
diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 9198a5bfe..b74116395 100755 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -62,7 +62,7 @@ proc finalizeRegEx(x: TRegEx) = proc re*(s: string, flags = {reExtended}): TRegEx = ## Constructor of regular expressions. Note that Nimrod's - ## extended raw string literals supports this syntax ``re"[abc]"`` as + ## extended raw string literals support this syntax ``re"[abc]"`` as ## a short form for ``re(r"[abc]")``. new(result, finalizeRegEx) result.h = rawCompile(s, cast[cint](flags)) @@ -152,8 +152,12 @@ proc find*(s: string, pattern: TRegEx, matches: var openarray[string], proc find*(s: string, pattern: TRegEx, start = 0): int = ## returns the starting position of ``pattern`` in ``s``. If it does not ## match, -1 is returned. - var matches: array[0..maxSubpatterns-1, string] - result = find(s, pattern, matches, start) + var + rawMatches: array[0..3 - 1, cint] + res = pcre.Exec(pattern.h, nil, s, len(s), start, 0'i32, + cast[ptr cint](addr(rawMatches)), 3) + if res < 0'i32: return res + return rawMatches[0] iterator findAll*(s: string, pattern: TRegEx, start = 0): string = ## yields all matching captures of pattern in `s`. diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim new file mode 100644 index 000000000..c9e5b0e14 --- /dev/null +++ b/lib/pure/algorithm.nim @@ -0,0 +1,101 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2010 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements some common generic algorithms. + +type + TSortOrder* = enum ## sort order + Descending, Ascending + +proc `*`*(x: int, order: TSortOrder): int {.inline.} = + ## flips `x` if ``order == Descending``; + ## if ``order == Ascending`` then `x` is returned. + ## `x` is supposed to be the result of a comparator. + var y = order.ord - 1 + result = (x xor y) - y + +proc reverse*[T](a: var openArray[T], first, last: int) = + ## reverses the array ``a[first..last]``. + var x = first + var y = last + while x < y: + swap(a[x], a[y]) + dec(y) + inc(x) + +proc reverse*[T](a: var openArray[T]) = + ## reverses the array `a`. + reverse(a, 0, a.high) + +const + onlySafeCode = false + +proc merge[T](a, b: var openArray[T], lo, m, hi: int, + cmp: proc (x, y: T): int, order: TSortOrder) = + template `<-` (a, b: expr) = + when onlySafeCode: + a = b + else: + copyMem(addr(a), addr(b), sizeof(T)) + # optimization: If max(left) <= min(right) there is nothing to do! + # 1 2 3 4 ## 5 6 7 8 + # -> O(n) for sorted arrays. + # On random data this safes up to 40% of merge calls + if cmp(a[m], a[m+1]) * order <= 0: return + var j = lo + # copy a[j..m] into b: + assert j <= m + when onlySafeCode: + var bb = 0 + while j <= m: + b[bb] = a[j] + inc(bb) + inc(j) + else: + CopyMem(addr(b[0]), addr(a[j]), sizeof(T)*(m-j+1)) + j = m+1 + var i = 0 + var k = lo + # copy proper element back: + while k < j and j <= hi: + if cmp(b[i], a[j]) * order <= 0: + a[k] <- b[i] + inc(i) + else: + a[k] <- a[j] + inc(j) + inc(k) + # copy rest of b: + when onlySafeCode: + while k < j: + a[k] = b[i] + inc(k) + inc(i) + else: + if k < j: copyMem(addr(a[k]), addr(b[i]), sizeof(T)*(j-k)) + +proc sort*[T](a: var openArray[T], + cmp: proc (x, y: T): int = cmp, + order = TSortOrder.Ascending) = + ## Default Nimrod sort. The sorting is guaranteed to be stable and + ## the worst case is guaranteed to be O(n log n). + ## The current implementation uses an iterative + ## mergesort to achieve this. It uses a temporary sequence of + ## length ``a.len div 2``. + var n = a.len + var b: seq[T] + newSeq(b, n div 2) + var s = 1 + while s < n: + var m = n-1-s + while m >= 0: + merge(a, b, max(m-s+1, 0), m, m+s, cmp, order) + dec(m, s*2) + s = s*2 + diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 8d5966670..0673a9588 100755 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -97,14 +97,15 @@ proc normalize*(s: string): string {.noSideEffect, procvar, add result, s[i] proc cmpIgnoreCase*(a, b: string): int {.noSideEffect, - rtl, extern: "nsuCmpIgnoreCase".} = + rtl, extern: "nsuCmpIgnoreCase", procvar.} = ## Compares two strings in a case insensitive manner. Returns: ## ## | 0 iff a == b ## | < 0 iff a < b ## | > 0 iff a > b - var i = 0 - while i < a.len and i < b.len: + var i = 0 + var m = min(a.len, b.len) + while i < m: result = ord(toLower(a[i])) - ord(toLower(b[i])) if result != 0: return inc(i) @@ -114,7 +115,7 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect, # thus we compile without checks here proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, - rtl, extern: "nsuCmpIgnoreStyle".} = + rtl, extern: "nsuCmpIgnoreStyle", procvar.} = ## Compares two strings normalized (i.e. case and ## underscores do not matter). Returns: ## diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 0939a3066..f0b906b1f 100755 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -1075,7 +1075,7 @@ proc binarySearch(c: irune, tab: openArray[iRune], len, stride: int): int = return t return -1 -proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1".} = +proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} = ## Converts `c` into lower case. This works for any Unicode character. ## If possible, prefer `toLower` over `toUpper`. var c = irune(c) @@ -1087,7 +1087,7 @@ proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1".} = return TRune(c + toLowerSinglets[p+1] - 500) return TRune(c) -proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1".} = +proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} = ## Converts `c` into upper case. This works for any Unicode character. ## If possible, prefer `toLower` over `toUpper`. var c = irune(c) @@ -1099,14 +1099,14 @@ proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1".} = return TRune(c + toUpperSinglets[p+1] - 500) return TRune(c) -proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1".} = +proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} = var c = irune(c) var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2) if p >= 0 and c == toTitleSinglets[p]: return TRune(c + toTitleSinglets[p+1] - 500) return TRune(c) -proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1".} = +proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = ## returns true iff `c` is a lower case Unicode character ## If possible, prefer `isLower` over `isUpper`. var c = irune(c) @@ -1118,7 +1118,7 @@ proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1".} = if p >= 0 and c == toUpperSinglets[p]: return true -proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1".} = +proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = ## returns true iff `c` is a upper case Unicode character ## If possible, prefer `isLower` over `isUpper`. var c = irune(c) @@ -1130,7 +1130,7 @@ proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1".} = if p >= 0 and c == toLowerSinglets[p]: return true -proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1".} = +proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = ## returns true iff `c` is an *alpha* Unicode character (i.e. a letter) if isUpper(c) or isLower(c): return true @@ -1142,10 +1142,10 @@ proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1".} = if p >= 0 and c == alphaSinglets[p]: return true -proc isTitle*(c: TRune): bool {.rtl, extern: "nuc$1".} = +proc isTitle*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = return isUpper(c) and isLower(c) -proc isWhiteSpace*(c: TRune): bool {.rtl, extern: "nuc$1".} = +proc isWhiteSpace*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = ## returns true iff `c` is a Unicode whitespace character var c = irune(c) var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2) @@ -1161,7 +1161,7 @@ iterator runes*(s: string): TRune = fastRuneAt(s, i, result, true) yield result -proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1".} = +proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} = ## compares two UTF8 strings and ignores the case. Returns: ## ## | 0 iff a == b diff --git a/lib/system.nim b/lib/system.nim index cf92594d9..aeca9b683 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -623,7 +623,7 @@ template `not_in` * (x, y: expr): expr = not contains(y, x) proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.} template `is_not` *(x, y: expr): expr = not (x is y) -proc cmp*[T, S: typeDesc](x: T, y: S): int = +proc cmp*[T, S: typeDesc](x: T, y: S): int {.procvar.} = ## Generic compare proc. Returns a value < 0 iff x < y, a value > 0 iff x > y ## and 0 iff x == y. This is useful for writing generic algorithms without ## performance loss. This generic implementation uses the `==` and `<` @@ -632,7 +632,7 @@ proc cmp*[T, S: typeDesc](x: T, y: S): int = if x < y: return -1 return 1 -proc cmp*(x, y: string): int {.noSideEffect.} +proc cmp*(x, y: string): int {.noSideEffect, procvar.} ## Compare proc for strings. More efficient than the generic version. proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {. @@ -714,7 +714,8 @@ const cpuEndian* {.magic: "CpuEndian"}: TEndian = littleEndian ## is the endianness of the target CPU. This is a valuable piece of - ## information for low-level code only. This works thanks to compiler magic. + ## information for low-level code only. This works thanks to compiler + ## magic. hostOS* {.magic: "HostOS"}: string = "" ## a string that describes the host operating system. Possible values: @@ -1307,7 +1308,7 @@ proc echo*[Ty](x: openarray[Ty]) {.magic: "Echo".} ## available for the ECMAScript target too! template newException*(exceptn, message: expr): expr = - ## creates an exception object of type "exceptn" and sets its ``msg`` field + ## creates an exception object of type ``exceptn`` and sets its ``msg`` field ## to `message`. Returns the new exception object. block: # open a new scope var @@ -1365,7 +1366,7 @@ when not defined(EcmaScript) and not defined(NimrodVM): include "system/ansi_c" proc cmp(x, y: string): int = - return int(c_strcmp(x, y)) + result = int(c_strcmp(x, y)) const pccHack = if defined(pcc): "_" else: "" # Hack for PCC when defined(windows): @@ -1419,8 +1420,9 @@ when not defined(EcmaScript) and not defined(NimrodVM): ## stream* is a good idea, but since it is named ``stderr`` there are few ## programs out there that distinguish properly between ``stdout`` and ## ``stderr``. So, that's what you get if you don't name your variables - ## appropriately. It also annoys people if redirection via ``>output.txt`` - ## does not work because the program writes to ``stderr``. + ## appropriately. It also annoys people if redirection + ## via ``>output.txt`` does not work because the program writes + ## to ``stderr``. proc Open*(f: var TFile, filename: string, mode: TFileMode = fmRead, bufSize: int = -1): Bool diff --git a/rod/ast.nim b/rod/ast.nim index 7bdfef82c..ba0de6319 100755 --- a/rod/ast.nim +++ b/rod/ast.nim @@ -750,6 +750,12 @@ proc newSymNode(sym: PSym): PNode = result.typ = sym.typ result.info = sym.info +proc newSymNode*(sym: PSym, info: TLineInfo): PNode = + result = newNode(nkSym) + result.sym = sym + result.typ = sym.typ + result.info = info + proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode = result = newNode(kind) result.info = info @@ -869,6 +875,11 @@ proc len*(n: PNode): int {.inline.} = if isNil(n.sons): result = 0 else: result = len(n.sons) +proc safeLen*(n: PNode): int {.inline.} = + ## works even for leaves. + if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0 + else: result = len(n.sons) + proc add*(father, son: PNode) = assert son != nil if isNil(father.sons): father.sons = @[] diff --git a/rod/semcall.nim b/rod/semcall.nim index 1b31558ca..294c0399b 100644 --- a/rod/semcall.nim +++ b/rod/semcall.nim @@ -79,20 +79,42 @@ proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode = initialBinding = nil result = semDirectCallWithBinding(c, n, f, filter, initialBinding) -proc explictGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = +proc explicitGenericInstError(n: PNode): PNode = + LocalError(n.info, errCannotInstantiateX, renderTree(n)) + result = n + +proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = assert n.kind == nkBracketExpr for i in 1..sonsLen(n)-1: n.sons[i].typ = semTypeNode(c, n.sons[i], nil) - # we cannot check for the proper number of type parameters because in - # `f[a,b](x, y)` `f` is not resolved yet properly. - # XXX: BUG this should be checked somehow! - assert n.sons[0].kind == nkSym + var s = s + var a = n.sons[0] + if a.kind == nkSym: + # common case; check the only candidate has the right + # number of generic type parameters: + if safeLen(s.ast.sons[genericParamsPos]) != n.len-1: + return explicitGenericInstError(n) + elif a.kind == nkSymChoice: + # choose the generic proc with the proper number of type parameters. + # XXX I think this could be improved by reusing sigmatch.ParamTypesMatch. + # It's good enough for now. + var candidateCount = 0 + for i in countup(0, len(a)-1): + var candidate = a.sons[i].sym + if candidate.kind in {skProc, skMethod, skConverter, skIterator}: + # if suffices that the candidate has the proper number of generic + # type parameters: + if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1: + s = candidate + inc(candidateCount) + if candidateCount != 1: return explicitGenericInstError(n) + else: + assert false var x: TCandidate initCandidate(x, s, n) var newInst = generateInstance(c, s, x.bindings, n.info) markUsed(n, s) - result = newSymNode(newInst) - result.info = n.info + result = newSymNode(newInst, n.info) diff --git a/rod/semexprs.nim b/rod/semexprs.nim index 89b5ecfe2..7e46c69cd 100755 --- a/rod/semexprs.nim +++ b/rod/semexprs.nim @@ -61,24 +61,22 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = if s.typ.kind in ConstAbstractTypes: result = copyTree(s.ast) result.typ = s.typ + result.info = n.info else: - result = newSymNode(s) - result.info = n.info + result = newSymNode(s, n.info) of skMacro: result = semMacroExpr(c, n, s) of skTemplate: result = semTemplateExpr(c, n, s) of skVar: markUsed(n, s) # if a proc accesses a global variable, it is not side effect free: if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect) - result = newSymNode(s) - result.info = n.info + result = newSymNode(s, n.info) of skGenericParam: if s.ast == nil: InternalError(n.info, "no default for") result = semExpr(c, s.ast) else: markUsed(n, s) - result = newSymNode(s) - result.info = n.info + result = newSymNode(s, n.info) proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) = var diff = inheritanceDiff(castDest, src) @@ -645,23 +643,22 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = var ty = n.sons[0].Typ var f: PSym = nil result = nil - if ty.kind == tyEnum: - # look up if the identifier belongs to the enum: - while ty != nil: - f = getSymFromList(ty.n, i) - if f != nil: break - ty = ty.sons[0] # enum inheritance - if f != nil: - result = newSymNode(f) - result.info = n.info - result.typ = ty - markUsed(n, f) - else: - GlobalError(n.sons[1].info, errEnumHasNoValueX, i.s) - return - elif not (efAllowType in flags) and isTypeExpr(n.sons[0]): - GlobalError(n.sons[0].info, errATypeHasNoValue) - return + if isTypeExpr(n.sons[0]): + if ty.kind == tyEnum: + # look up if the identifier belongs to the enum: + while ty != nil: + f = getSymFromList(ty.n, i) + if f != nil: break + ty = ty.sons[0] # enum inheritance + if f != nil: + result = newSymNode(f) + result.info = n.info + result.typ = ty + markUsed(n, f) + return + elif efAllowType notin flags: + GlobalError(n.sons[0].info, errATypeHasNoValue) + return ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef}) var check: PNode = nil if ty.kind == tyObject: @@ -1027,7 +1024,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = var s = qualifiedLookup(c, n.sons[0], {checkUndeclared}) if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}: # type parameters: partial generic specialization - result = explictGenericInstantiation(c, n, s) + n.sons[0] = semSym(c, n.sons[0], s, flags) + result = explicitGenericInstantiation(c, n, s) else: result = semArrayAccess(c, n, flags) of nkPragmaExpr: diff --git a/rod/semgnrc.nim b/rod/semgnrc.nim index b13d605d6..633994942 100755 --- a/rod/semgnrc.nim +++ b/rod/semgnrc.nim @@ -40,13 +40,15 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode = of skMacro: result = semMacroExpr(c, n, s, false) of skGenericParam: - result = newSymNode(s) + result = newSymNode(s, n.info) of skParam: result = n of skType: - if (s.typ != nil) and (s.typ.kind != tyGenericParam): result = newSymNode(s) - else: result = n - else: result = newSymNode(s) + if (s.typ != nil) and (s.typ.kind != tyGenericParam): + result = newSymNode(s, n.info) + else: + result = n + else: result = newSymNode(s, n.info) proc getIdentNode(n: PNode): PNode = case n.kind @@ -101,12 +103,12 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode of skProc, skMethod, skIterator, skConverter: n.sons[0] = symChoice(c, n.sons[0], s) of skGenericParam: - n.sons[0] = newSymNode(s) + n.sons[0] = newSymNode(s, n.sons[0].info) of skType: # bad hack for generics: if (s.typ != nil) and (s.typ.kind != tyGenericParam): - n.sons[0] = newSymNode(s) - else: n.sons[0] = newSymNode(s) + n.sons[0] = newSymNode(s, n.sons[0].info) + else: n.sons[0] = newSymNode(s, n.sons[0].info) for i in countup(1, sonsLen(n) - 1): n.sons[i] = semGenericStmt(c, n.sons[i], flags) of nkMacroStmt: @@ -221,9 +223,9 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode if (a.kind != nkIdentDefs): IllFormedAst(a) checkMinSonsLen(a, 3) L = sonsLen(a) - a.sons[L - 1] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc}) - a.sons[L - 1] = semGenericStmt(c, a.sons[L - 1]) - for j in countup(0, L - 3): + a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc}) + a.sons[L-1] = semGenericStmt(c, a.sons[L-1]) + for j in countup(0, L-3): addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef, nkLambda: diff --git a/rod/semstmts.nim b/rod/semstmts.nim index 8425c5b67..34b95c936 100755 --- a/rod/semstmts.nim +++ b/rod/semstmts.nim @@ -522,11 +522,15 @@ proc SemTypeSection(c: PContext, n: PNode): PNode = InternalError(a.info, "semTypeSection: containerID") s.typ.containerID = getID() a.sons[1] = semGenericParamList(c, a.sons[1], s.typ) - addSon(s.typ, nil) # to be filled out later + + # we fill it out later. For magic generics like 'seq', it won't be filled + # so we use tyEmpty instead of nil to not crash for strange conversions + # like: mydata.seq + addSon(s.typ, newTypeS(tyEmpty, c)) s.ast = a body = semTypeNode(c, a.sons[2], nil) if body != nil: body.sym = s - s.typ.sons[sonsLen(s.typ) - 1] = body #debug(s.typ); + s.typ.sons[sonsLen(s.typ) - 1] = body popOwner() closeScope(c.tab) elif a.sons[2].kind != nkEmpty: diff --git a/rod/semtypes.nim b/rod/semtypes.nim index 267a1f7fd..991a75792 100755 --- a/rod/semtypes.nim +++ b/rod/semtypes.nim @@ -488,7 +488,8 @@ proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType = result = addTypeVarsOfGenericBody(c, result, genericParams, cl) #if result.kind == tyGenericInvokation: debug(result) -proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType = +proc semProcTypeNode(c: PContext, n, genericParams: PNode, + prev: PType): PType = var def, res: PNode typ: PType @@ -515,12 +516,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType): PType = if a.sons[length - 1].kind != nkEmpty: def = semExprWithType(c, a.sons[length - 1]) # check type compability between def.typ and typ: - if typ != nil: - if cmpTypes(typ, def.typ) < isConvertible: - typeMismatch(a.sons[length - 1], typ, def.typ) - def = fitNode(c, typ, def) - else: + if typ == nil: typ = def.typ + elif def != nil and def.typ != nil and def.typ.kind != tyNone: + # example code that triggers it: + # proc sort[T](cmp: proc(a, b: T): int = cmp) + def = fitNode(c, typ, def) else: def = ast.emptyNode for j in countup(0, length - 3): diff --git a/rod/sigmatch.nim b/rod/sigmatch.nim index 59112a7f4..2192c168a 100755 --- a/rod/sigmatch.nim +++ b/rod/sigmatch.nim @@ -130,8 +130,11 @@ proc concreteType(mapping: TIdTable, t: PType): PType = result = t while true: result = PType(idTableGet(mapping, t)) - if result == nil: InternalError("lookup failed") - if result.kind != tyGenericParam: break + if result == nil: + break # it's ok, no match + # example code that triggers it: + # proc sort[T](cmp: proc(a, b: T): int = cmp) + if result.kind != tyGenericParam: break else: result = t # Note: empty is valid here diff --git a/rod/suggest.nim b/rod/suggest.nim index f553bde90..6f4babe63 100644 --- a/rod/suggest.nim +++ b/rod/suggest.nim @@ -123,7 +123,7 @@ proc suggestFieldAccess(c: PContext, n: PNode) = else: # fallback: suggestEverything(c, n) - elif typ.kind == tyEnum: + elif typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType: # look up if the identifier belongs to the enum: var t = typ while t != nil: diff --git a/tests/accept/compile/tsortdev.nim b/tests/accept/compile/tsortdev.nim new file mode 100644 index 000000000..488836cc7 --- /dev/null +++ b/tests/accept/compile/tsortdev.nim @@ -0,0 +1,69 @@ + +import math, algorithm + +proc sorted[T](a: openArray[T], order: TSortOrder): bool = + result = true + for i in 0 .. < a.high: + if cmp(a[i], a[i+1]) * order > 0: + echo "Out of order: ", a[i], " ", a[i+1] + result = false + +proc bubbleSort[T](a: var openArray[T], + cmp: proc (x, y: T): int = cmp, + order = TSortOrder.Ascending) = + while true: + var sorted = true + for i in 0 .. a.len-2: + if cmp(a[i], a[i+1]) * order > 0: + swap(a[i], a[i+1]) + sorted = false + if sorted: break + +when isMainModule: + proc main() = + const order = Ascending + var data: seq[string] = @[] + + for i in 0..10_000: + var L = random(59) + setLen(data, L) + for j in 0 .. L-1: + data[j] = $(math.random(90) - 10) + var copy = data + sort(data, cmp, order) + if not sorted(data, order): + #for x in items(data): echo x + break + else: + echo "SUCCESS!" + bubblesort(copy, cmp, order) + if copy.len != data.len: + quit "lengths differ!" + for i in 0 .. copy.high: + if copy[i] != data[i]: + quit "algorithms differ!" + + for i in 0..10_000: + var data: seq[int] = @[] + var L = random(59) + setLen(data, L) + for j in 0 .. L-1: + data[j] = (math.random(90) - 10) + var copy = data + sort(data, cmp[int, int], order) + if not sorted(data, order): + #for x in items(data): echo x + break + else: + echo "SUCCESS!" + bubblesort(copy) + if copy.len != data.len: + quit "lengths differ!" + for i in 0 .. copy.high: + if copy[i] != data[i]: + quit "algorithms differ!" + + main() + +echo "done" + diff --git a/tests/accept/run/tgenerics1.nim b/tests/accept/run/tgenerics1.nim index b30171831..e9ccd6917 100755 --- a/tests/accept/run/tgenerics1.nim +++ b/tests/accept/run/tgenerics1.nim @@ -4,51 +4,47 @@ discard """ # A min-heap. type - TNode[T] = tuple[priority: int, data: T] + TNode[T] = tuple[priority: int, data: T] - TBinHeap[T] = object - heap: seq[TNode[T]] - last: int - - PBinHeap[T] = ref TBinHeap[T] + TBinHeap[T] = object + heap: seq[TNode[T]] + last: int + + PBinHeap[T] = ref TBinHeap[T] proc newBinHeap*[T](heap: var PBinHeap[T], size: int) = - new(heap) - heap.last = 0 - newSeq(heap.seq, size) - -when false: - - proc parent(elem: int): int = - return (elem-1) div 2 - - proc siftUp[T](heap: PBinHeap[T], elem: int) = - var idx = elem - while idx != 0: - var p = parent(idx) - if heap.heap[idx] < heap.heap[p]: - var tmp = heap.heap[idx] - heap.heap[idx] = heap.heap[p] - heap.heap[p] = tmp - idx = p - else: - break - - proc add*[T](heap: PBinHeap[T], priority: int, data: T) = - var node: TNode - new(node) - node.priority = int - node.data = data - heap.heap[heap.last] = node - siftUp(heap, heap.last) - inc(heap.last) - - proc print*[T](heap: PBinHeap[T]) = - for i in countup(0, heap.last): - echo($heap.heap[i]) + new(heap) + heap.last = 0 + newSeq(heap.heap, size) + #newSeq(heap.seq, size) + +proc parent(elem: int): int {.inline.} = + return (elem-1) div 2 + +proc siftUp[T](heap: PBinHeap[T], elem: int) = + var idx = elem + while idx != 0: + var p = parent(idx) + if heap.heap[idx].priority < heap.heap[p].priority: + swap(heap.heap[idx], heap.heap[p]) + idx = p + else: + break + +proc add*[T](heap: PBinHeap[T], priority: int, data: T) = + var node: TNode[T] + node.priority = priority + node.data = data + heap.heap[heap.last] = node + siftUp(heap, heap.last) + inc(heap.last) + +proc print*[T](heap: PBinHeap[T]) = + for i in countup(0, heap.last): + echo heap.heap[i].data var - heap: PBinHeap[int] + heap: PBinHeap[int] newBinHeap(heap, 256) add(heap, 1, 100) diff --git a/tests/gc/gcleak.nim b/tests/gc/gcleak.nim new file mode 100644 index 000000000..88aeda56d --- /dev/null +++ b/tests/gc/gcleak.nim @@ -0,0 +1,11 @@ +type + TTestObj = object of TObject + x: string + +proc MakeObj(): TTestObj = + result.x = "Hello" + +while true: + var obj = MakeObj() + + diff --git a/tests/reject/ttypenoval.nim b/tests/reject/ttypenoval.nim new file mode 100644 index 000000000..ed91b05e2 --- /dev/null +++ b/tests/reject/ttypenoval.nim @@ -0,0 +1,55 @@ +discard """ + file: "tambsym.nim" + line: 36 + errormsg: "a type has no value" +""" + +# A min-heap. +type + TNode[T] = tuple[priority: int, data: T] + + TBinHeap[T] = object + heap: seq[TNode[T]] + last: int + + PBinHeap[T] = ref TBinHeap[T] + +proc newBinHeap*[T](heap: var PBinHeap[T], size: int) = + new(heap) + heap.last = 0 + newSeq(heap.heap, size) + #newSeq(heap.seq, size) + +proc parent(elem: int): int {.inline.} = + return (elem-1) div 2 + +proc siftUp[T](heap: PBinHeap[T], elem: int) = + var idx = elem + while idx != 0: + var p = parent(idx) + if heap.heap[idx] < heap.heap[p]: + swap(heap.heap[idx], heap.heap[p]) + idx = p + else: + break + +proc add*[T](heap: PBinHeap[T], priority: int, data: T) = + var node: TNode[T] + node.priority = int + node.data = data + heap.heap[heap.last] = node + siftUp(heap, heap.last) + inc(heap.last) + +proc print*[T](heap: PBinHeap[T]) = + for i in countup(0, heap.last): + echo($heap.heap[i]) + +var + heap: PBinHeap[int] + +newBinHeap(heap, 256) +add(heap, 1, 100) +print(heap) + + diff --git a/todo.txt b/todo.txt index 6b0128299..904fd83a2 100755 --- a/todo.txt +++ b/todo.txt @@ -35,7 +35,6 @@ Bugs To implement ------------ -* sort routine * hash tables and sets * distinct types for array/seq indexes * constant sequences |