From f127bc387a8e45635a9e4aa9208df4c8e8c0f276 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 19 Aug 2013 01:17:07 +0300 Subject: [PATCH 01/15] Revert "Revert "test cases for the new features"" This reverts commit e1b668c868dbc647bb5da98d8e4769c2c9b351fd. --- compiler/semexprs.nim | 15 +++++++++++---- tests/compile/tgenericdefaults.nim | 29 +++++++++++++++++++++++++++++ tests/compile/ttypeclasses.nim | 21 +++++++++++++++++++++ tests/run/tstaticparams.nim | 17 +++++++++++++++++ 4 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 tests/compile/tgenericdefaults.nim create mode 100644 tests/run/tstaticparams.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 4591c39427..3036a28e1a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -111,7 +111,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = # var len = 0 # but won't be called # genericThatUsesLen(x) # marked as taking a closure? of skGenericParam: - if s.ast != nil: result = semExpr(c, s.ast) + if s.typ.kind == tyExpr: + result = newSymNode(s, n.info) + result.typ = s.typ.lastSon + elif s.ast != nil: + result = semExpr(c, s.ast) else: InternalError(n.info, "no default for") result = emptyNode @@ -888,10 +892,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = let tbody = ty.sons[0] for s in countup(0, tbody.len-2): let tParam = tbody.sons[s] - assert tParam.kind == tyGenericParam if tParam.sym.name == i: - let foundTyp = makeTypeDesc(c, ty.sons[s + 1]) - return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info) + let rawTyp = ty.sons[s + 1] + if rawTyp.kind == tyExpr: + return rawTyp.n + else: + let foundTyp = makeTypeDesc(c, rawTyp) + return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info) return else: # echo "TYPE FIELD ACCESS" diff --git a/tests/compile/tgenericdefaults.nim b/tests/compile/tgenericdefaults.nim new file mode 100644 index 0000000000..ad96f18513 --- /dev/null +++ b/tests/compile/tgenericdefaults.nim @@ -0,0 +1,29 @@ +type + TFoo[T, U, R = int] = object + x: T + y: U + z: R + + TBar[T] = TFoo[T, array[4, T], T] + +var x1: TFoo[int, float] + +static: + assert type(x1.x) is int + assert type(x1.y) is float + assert type(x1.z) is int + +var x2: TFoo[string, R = float, U = seq[int]] + +static: + assert type(x2.x) is string + assert type(x2.y) is seq[int] + assert type(x2.z) is float + +var x3: TBar[float] + +static: + assert type(x3.x) is float + assert type(x3.y) is array[4, float] + assert type(x3.z) is float + diff --git a/tests/compile/ttypeclasses.nim b/tests/compile/ttypeclasses.nim index 5e23e84898..677229868c 100644 --- a/tests/compile/ttypeclasses.nim +++ b/tests/compile/ttypeclasses.nim @@ -5,6 +5,8 @@ type T1 = expr T2 = expr + Numeric = int|float + proc takesExpr(x, y) = echo x, y @@ -32,3 +34,22 @@ takesFoo(f, f) takes2Types(1, 1, "string") takes2Types[string, int]("test", "test", 1) +proc takesSeq(x: seq) = + echo "seq" + +takesSeq(@[1, 2, 3]) +takesSeq(@["x", "y", "z"]) + +proc takesSeqOfFoos(x: seq[TFoo]) = + echo "foo seq" + +var sf = newSeq[TFoo[int]](3) + +takesSeq(sf) +takesSeqOfFoos(sf) + +proc takesFooOfNumeric(x: TFoo[Numeric]) = + echo "foo of numeric" + +takesFooOfNumeric(sf[0]) + diff --git a/tests/run/tstaticparams.nim b/tests/run/tstaticparams.nim new file mode 100644 index 0000000000..3e501ed8b9 --- /dev/null +++ b/tests/run/tstaticparams.nim @@ -0,0 +1,17 @@ +discard """ + file: "tstaticparams.nim" + output: "abracadabra\ntest" +""" + +type + TFoo[T; Val: expr[string]] = object + data: array[4, T] + +proc takeFoo(x: TFoo) = + echo "abracadabra" + echo TFoo.Val + +var x: TFoo[int, "test"] + +takeFoo(x) + From dfb5cb3c5d9c3981cd02d3fa27221e0b7f5af1e8 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 19 Aug 2013 01:26:37 +0300 Subject: [PATCH 02/15] remerge "Fixes #267" --- compiler/ast.nim | 15 ++-- compiler/semdata.nim | 5 ++ compiler/seminst.nim | 103 ++++++++++++++++++++----- compiler/semtypes.nim | 172 +++++++++++++++++++++++------------------- compiler/types.nim | 2 + 5 files changed, 192 insertions(+), 105 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 514ab6a7cf..4be931c8d1 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -366,12 +366,8 @@ type tfFromGeneric, # type is an instantiation of a generic; this is needed # because for instantiations of objects, structural # type equality has to be used - tfInstantiated, # XXX: used to mark generic params after instantiation. - # if the concrete type happens to be an implicit generic - # this can lead to invalid proc signatures in the second - # pass of semProcTypeNode performed after instantiation. - # this won't be needed if we don't perform this redundant - # second pass (stay tuned). + tfUnresolved, # marks unresolved typedesc params: e.g. + # proc foo(T: typedesc, list: seq[T]): var T tfRetType, # marks return types in proc (used to detect type classes # used as return types for return type inference) tfAll, # type class requires all constraints to be met (default) @@ -1053,8 +1049,8 @@ proc NewType(kind: TTypeKind, owner: PSym): PType = result.size = - 1 result.align = 2 # default alignment result.id = getID() - when debugIds: - RegisterId(result) + when debugIds: + RegisterId(result) #if result.id < 2000 then # MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id)) @@ -1091,7 +1087,6 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType = if keepId: result.id = t.id else: - result.id = getID() when debugIds: RegisterId(result) result.sym = t.sym # backend-info should not be copied @@ -1364,7 +1359,7 @@ proc isGenericRoutine*(s: PSym): bool = of skProc, skTemplate, skMacro, skIterator, skMethod, skConverter: result = s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty else: nil - + proc isRoutine*(s: PSym): bool {.inline.} = result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod, skConverter} diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 72d5a5fefc..b9c32a680e 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -207,6 +207,11 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType = proc newTypeS(kind: TTypeKind, c: PContext): PType = result = newType(kind, getCurrOwner()) +proc newTypeWithSons*(c: PContext, kind: TTypeKind, + sons: seq[PType]): PType = + result = newType(kind, getCurrOwner()) + result.sons = sons + proc errorType*(c: PContext): PType = ## creates a type representing an error state result = newTypeS(tyError, c) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 9dc99d173e..35ed009659 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -38,7 +38,6 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable, #t = instGenericContainer(c, a, t) t = generateTypeInstance(c, pt, a, t) #t = ReplaceTypeVarsT(cl, t) - t.flags.incl tfInstantiated s.typ = t addDecl(c, s) entry.concreteTypes[i] = t @@ -84,11 +83,28 @@ proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) = else: for i in 0 .. Date: Mon, 19 Aug 2013 01:27:05 +0300 Subject: [PATCH 03/15] Revert "Revert "bugfix: emulated thread vars used in combination with the mark & sweep GC"" This reverts commit 75c586bbe1cc649b36fc00362ab40ebb1d163d9f. --- compiler/ccgthreadvars.nim | 4 ++-- compiler/ccgtrav.nim | 8 ++++++-- compiler/cgen.nim | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 4785402e75..d312ea0278 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -12,10 +12,10 @@ # included from cgen.nim -proc emulatedThreadVars(): bool {.inline.} = +proc emulatedThreadVars(): bool = result = {optThreads, optTlsEmulation} <= gGlobalOptions -proc AccessThreadLocalVar(p: BProc, s: PSym) = +proc accessThreadLocalVar(p: BProc, s: PSym) = if emulatedThreadVars() and not p.ThreadVarAccessed: p.ThreadVarAccessed = true p.module.usesThreadVars = true diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index aa8b856006..9534eae91d 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -127,18 +127,22 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope = m.s[cfsProcHeaders].appf("$1;$n", header) m.s[cfsProcs].app(generatedProc) - proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope = discard genTypeInfo(m, s.loc.t) var c: TTraversalClosure var p = newProc(nil, m) + var sLoc = s.loc.r result = getGlobalTempName() + if sfThread in s.flags and emulatedThreadVars(): + accessThreadLocalVar(p, s) + sLoc = con("NimTV->", sLoc) + c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n" c.p = p let header = ropef("N_NIMCALL(void, $1)()", result) - genTraverseProc(c, s.loc.r, s.loc.t) + genTraverseProc(c, sLoc, s.loc.t) let generatedProc = ropef("$1 {$n$2$3$4}$n", [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 18f33f32a5..b801add6c5 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -284,6 +284,9 @@ proc genLineDir(p: BProc, t: PNode) = linefmt(p, cpsStmts, "nimln($1, $2);$n", line.toRope, t.info.quotedFilename) +proc accessThreadLocalVar(p: BProc, s: PSym) +proc emulatedThreadVars(): bool {.inline.} + include "ccgtypes.nim" # ------------------------------ Manager of temporaries ------------------ From 19eeb3556e091e541a78b02a389fb608cd382c6c Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 19 Aug 2013 01:29:01 +0300 Subject: [PATCH 04/15] remerge "allow void as field type" --- compiler/ccgtypes.nim | 3 +- compiler/types.nim | 67 ++++++++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index bb9d4c3a17..4548ac641f 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -437,8 +437,9 @@ proc genRecordFieldsAux(m: BModule, n: PNode, app(result, genRecordFieldsAux(m, k, ae, rectype, check)) else: internalError("genRecordFieldsAux(record case branch)") appf(result, "} $1;$n", [uname]) - of nkSym: + of nkSym: field = n.sym + if field.typ.kind == tyEmpty: return #assert(field.ast == nil) sname = mangleRecFieldName(field, rectype) if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname]) diff --git a/compiler/types.nim b/compiler/types.nim index e7bda54ef1..b8aaed45e4 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -926,11 +926,21 @@ proc commonSuperclass*(a, b: PType): PType = if ancestors.contains(y.id): return y y = y.sons[0] -proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool -proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool = +type + TTypeAllowedFlag = enum + taField, + taHeap + + TTypeAllowedFlags = set[TTypeAllowedFlag] + +proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, + flags: TTypeAllowedFlags = {}): bool + +proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind, + flags: TTypeAllowedFlags = {}): bool = result = true if n != nil: - result = typeAllowedAux(marker, n.typ, kind) + result = typeAllowedAux(marker, n.typ, kind, flags) #if not result: debug(n.typ) if result: case n.kind @@ -938,7 +948,7 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool = nil else: for i in countup(0, sonsLen(n) - 1): - result = typeAllowedNode(marker, n.sons[i], kind) + result = typeAllowedNode(marker, n.sons[i], kind, flags) if not result: break proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]], @@ -990,7 +1000,8 @@ proc matchTypeClass*(typeClass, typ: PType): bool = initIdTable(bindings) result = matchTypeClass(bindings, typeClass, typ) -proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = +proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, + flags: TTypeAllowedFlags = {}): bool = assert(kind in {skVar, skLet, skConst, skParam, skResult}) # if we have already checked the type, return true, because we stop the # evaluation if something is wrong: @@ -1004,66 +1015,70 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}) case t2.kind of tyVar: - result = false # ``var var`` is always an invalid type: + result = taHeap in flags # ``var var`` is illegal on the heap: of tyOpenArray: - result = kind == skParam and typeAllowedAux(marker, t2, kind) + result = kind == skParam and typeAllowedAux(marker, t2, kind, flags) else: - result = kind in {skParam, skResult} and typeAllowedAux(marker, t2, kind) + result = kind in {skParam, skResult} and + typeAllowedAux(marker, t2, kind, flags) of tyProc: for i in countup(1, sonsLen(t) - 1): - result = typeAllowedAux(marker, t.sons[i], skParam) + result = typeAllowedAux(marker, t.sons[i], skParam, flags) if not result: break if result and t.sons[0] != nil: - result = typeAllowedAux(marker, t.sons[0], skResult) + result = typeAllowedAux(marker, t.sons[0], skResult, flags) of tyExpr, tyStmt, tyTypeDesc: result = true # XXX er ... no? these should not be allowed! + of tyEmpty: + result = taField in flags of tyTypeClass: result = true of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation: result = false - of tyEmpty, tyNil: + of tyNil: result = kind == skConst of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: result = true of tyOrdinal: result = kind == skParam of tyGenericInst, tyDistinct: - result = typeAllowedAux(marker, lastSon(t), kind) - of tyRange: + result = typeAllowedAux(marker, lastSon(t), kind, flags) + of tyRange: result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in {tyChar, tyEnum, tyInt..tyUInt64} of tyOpenArray, tyVarargs: - result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar) + result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags) of tySequence: result = t.sons[0].kind == tyEmpty or - typeAllowedAux(marker, t.sons[0], skVar) + typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap}) of tyArray: result = t.sons[1].kind == tyEmpty or - typeAllowedAux(marker, t.sons[1], skVar) + typeAllowedAux(marker, t.sons[1], skVar, flags) of tyRef: if kind == skConst: return false - result = typeAllowedAux(marker, t.sons[0], skVar) + result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap}) of tyPtr: - result = typeAllowedAux(marker, t.sons[0], skVar) - of tyArrayConstr, tyTuple, tySet, tyConst, tyMutable, tyIter: + result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap}) + of tyArrayConstr, tySet, tyConst, tyMutable, tyIter: for i in countup(0, sonsLen(t) - 1): - result = typeAllowedAux(marker, t.sons[i], kind) + result = typeAllowedAux(marker, t.sons[i], kind, flags) if not result: break - of tyObject: - if kind == skConst: return false + of tyObject, tyTuple: + if kind == skConst and t.kind == tyObject: return false + let flags = flags+{taField} for i in countup(0, sonsLen(t) - 1): - result = typeAllowedAux(marker, t.sons[i], kind) + result = typeAllowedAux(marker, t.sons[i], kind, flags) if not result: break - if result and t.n != nil: result = typeAllowedNode(marker, t.n, kind) + if result and t.n != nil: result = typeAllowedNode(marker, t.n, kind, flags) of tyProxy: # for now same as error node; we say it's a valid type as it should # prevent cascading errors: result = true - + proc typeAllowed(t: PType, kind: TSymKind): bool = var marker = InitIntSet() - result = typeAllowedAux(marker, t, kind) + result = typeAllowedAux(marker, t, kind, {}) proc align(address, alignment: biggestInt): biggestInt = result = (address + (alignment - 1)) and not (alignment - 1) From ea54aa386c670f113fe4151da41dd2f4f95312cf Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 19 Aug 2013 01:29:22 +0300 Subject: [PATCH 05/15] Revert "Revert "allow keyword params for the `[]` and `{}` operators"" This reverts commit b7ea4a7e65ddf10bf3e425e59bc57e9f9c57e916. --- compiler/parser.nim | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index a92dde74fc..699a50c629 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -627,6 +627,13 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode = getTok(p) # we must consume a token here to prevend endless loops! result = ast.emptyNode +proc namedParams(p: var TParser, callee: PNode, + kind: TNodeKind, endTok: TTokType): PNode = + let a = callee + result = newNodeP(kind, p) + addSon(result, a) + exprColonEqExprListAux(p, endTok, result) + proc primarySuffix(p: var TParser, r: PNode): PNode = #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks? #| | doBlocks @@ -636,11 +643,8 @@ proc primarySuffix(p: var TParser, r: PNode): PNode = result = r while p.tok.indent < 0: case p.tok.tokType - of tkParLe: - var a = result - result = newNodeP(nkCall, p) - addSon(result, a) - exprColonEqExprListAux(p, tkParRi, result) + of tkParLe: + result = namedParams(p, result, nkCall, tkParRi) if result.len > 1 and result.sons[1].kind == nkExprColonExpr: result.kind = nkObjConstr else: @@ -653,10 +657,10 @@ proc primarySuffix(p: var TParser, r: PNode): PNode = of tkDot: result = dotExpr(p, result) result = parseGStrLit(p, result) - of tkBracketLe: - result = indexExprList(p, result, nkBracketExpr, tkBracketRi) + of tkBracketLe: + result = namedParams(p, result, nkBracketExpr, tkBracketRi) of tkCurlyLe: - result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi) + result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) else: break proc primary(p: var TParser, mode: TPrimaryMode): PNode From f760bc243b957ec8ebb529b9eadea53fc93adca5 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 19 Aug 2013 01:29:37 +0300 Subject: [PATCH 06/15] Revert "Revert "static and default params for generics"" This reverts commit 0662ec4a434f4656b5afc486bc4ebaab82c52da6. --- compiler/ast.nim | 2 + compiler/semstmts.nim | 3 +- compiler/semtypes.nim | 135 ++++++++++++++++++++++++------------------ compiler/sigmatch.nim | 19 ++++-- 4 files changed, 95 insertions(+), 64 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 4be931c8d1..13df058e77 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -686,6 +686,8 @@ type # for record types a nkRecord node # for enum types a list of symbols # for tyInt it can be the int literal + # for procs and tyGenericBody, it's the + # formal param list # else: unused destructor*: PSym # destructor. warning: nil here may not necessary # mean that there is no destructor. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 4de1f9151a..33c0adac1d 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -721,7 +721,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = # TGObj[T] = object # TAlias[T] = TGObj[T] # - a.sons[1] = semGenericParamList(c, a.sons[1], s.typ) + s.typ.n = semGenericParamList(c, a.sons[1], s.typ) + a.sons[1] = s.typ.n s.typ.size = -1 # could not be computed properly # 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 diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 4bc0ad7842..bb6c646f26 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -806,29 +806,44 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType = proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = result = newOrPrevType(tyGenericInvokation, prev, c) - var isConcrete = true + addSonSkipIntLit(result, s.typ) + + template addToResult(typ) = + if typ.isNil: + InternalAssert false + rawAddSon(result, typ) + else: addSonSkipIntLit(result, typ) + if s.typ == nil: LocalError(n.info, errCannotInstantiateX, s.name.s) return newOrPrevType(tyError, prev, c) - elif s.typ.kind != tyGenericBody: - isConcrete = false - elif sonsLen(n) != sonsLen(s.typ): - LocalError(n.info, errWrongNumberOfArguments) - return newOrPrevType(tyError, prev, c) - addSonSkipIntLit(result, s.typ) - # iterate over arguments: - for i in countup(1, sonsLen(n)-1): - var elem = semGenericParamInInvokation(c, n.sons[i]) - if containsGenericType(elem): isConcrete = false - #if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false - if elem.isNil: rawAddSon(result, elem) - else: addSonSkipIntLit(result, elem) - if isConcrete: - if s.ast == nil: - LocalError(n.info, errCannotInstantiateX, s.name.s) - result = newOrPrevType(tyError, prev, c) - else: - result = instGenericContainer(c, n, result) + elif s.typ.kind == tyForward: + for i in countup(1, sonsLen(n)-1): + var elem = semGenericParamInInvokation(c, n.sons[i]) + addToResult(elem) + else: + internalAssert s.typ.kind == tyGenericBody + + var m = newCandidate(s, n) + matches(c, n, copyTree(n), m) + + if m.state != csMatch: + LocalError(n.info, errWrongNumberOfArguments) + return newOrPrevType(tyError, prev, c) + + var isConcrete = true + + for i in 1 .. Date: Mon, 19 Aug 2013 01:29:47 +0300 Subject: [PATCH 07/15] Revert "Revert "fix tforwardgeneric"" This reverts commit e3f93241c3824e49b69c647bbd44726a79e8f8f8. --- compiler/ast.nim | 4 ++-- compiler/lambdalifting.nim | 3 +++ compiler/seminst.nim | 2 -- tests/compile/tforwardgeneric.nim | 5 +++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 13df058e77..5f6b658cfc 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1359,9 +1359,9 @@ proc getStrOrChar*(a: PNode): string = proc isGenericRoutine*(s: PSym): bool = case s.kind of skProc, skTemplate, skMacro, skIterator, skMethod, skConverter: - result = s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty + result = sfFromGeneric in s.flags else: nil - + proc isRoutine*(s: PSym): bool {.inline.} = result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod, skConverter} diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 8d4946ab5e..163ea41362 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -288,6 +288,9 @@ proc interestingVar(s: PSym): bool {.inline.} = proc semCaptureSym*(s, owner: PSym) = if interestingVar(s) and owner.id != s.owner.id and s.kind != skResult: if owner.typ != nil and not isGenericRoutine(owner): + # XXX: is this really safe? + # if we capture a var from another generic routine, + # it won't be consider captured. owner.typ.callConv = ccClosure #echo "semCaptureSym ", owner.name.s, owner.id, " ", s.name.s, s.id # since the analysis is not entirely correct, we don't set 'tfCapturesEnv' diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 35ed009659..431635b9c5 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -125,8 +125,6 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) = openScope(c) var n = oldPrc.ast n.sons[bodyPos] = copyTree(s.getBody) - if n.sons[paramsPos].kind != nkEmpty: - addParams(c, oldPrc.typ.n, oldPrc.kind) instantiateBody(c, n, oldPrc) closeScope(c) popInfoContext() diff --git a/tests/compile/tforwardgeneric.nim b/tests/compile/tforwardgeneric.nim index ef263d733d..c5943b9664 100644 --- a/tests/compile/tforwardgeneric.nim +++ b/tests/compile/tforwardgeneric.nim @@ -1,5 +1,5 @@ discard """ - output: "1.0000000000000000e+00 10" + output: "1.1000000000000001e+00 11" ccodecheck: "!@'ClEnv'" """ @@ -8,5 +8,6 @@ proc p[T](a, b: T): T echo p(0.9, 0.1), " ", p(9, 1) proc p[T](a, b: T): T = - result = a + b + let c = b + result = a + b + c From cefa16ae7733df933f76a8599db6fed4f8fb1d4d Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 19 Aug 2013 01:29:58 +0300 Subject: [PATCH 08/15] Revert "Revert "fix threading tests"" This reverts commit 9c45e33d8c8b1a5f5fca69a467fda87b9b547057. --- compiler/semexprs.nim | 2 +- compiler/seminst.nim | 24 ++++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 3036a28e1a..d88cc28b68 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1827,7 +1827,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkBind: Message(n.info, warnDeprecated, "bind") result = semExpr(c, n.sons[0], flags) - of nkTypeOfExpr: + of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy: var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc}) result = symNodeFromType(c, typ, n.info) of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 431635b9c5..98f25efa7c 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -165,28 +165,35 @@ proc fixupProcTypeR(c: PContext, genericType: PType, of tyOpenArray, tyArray, tySet, tySequence, tyTuple, tyProc, tyPtr, tyVar, tyRef, tyOrdinal, tyRange, tyVarargs: if genericType.sons == nil: return + var head = 0 for i in 0 .. Date: Mon, 19 Aug 2013 01:30:17 +0300 Subject: [PATCH 09/15] Revert "Revert "further fixes for void stripping. fixes tvoid."" This reverts commit d11cf5d1915d83159094f5074a6e17a72c65d9fa. --- compiler/seminst.nim | 45 ++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 98f25efa7c..ed842d98ef 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -148,8 +148,8 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType = proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = result = instGenericContainer(c, n.info, header) -proc fixupProcTypeR(c: PContext, genericType: PType, - inst: TInstantiation): PType = +proc fixupProcType(c: PContext, genericType: PType, + inst: TInstantiation): PType = result = genericType if result == nil: return @@ -167,48 +167,53 @@ proc fixupProcTypeR(c: PContext, genericType: PType, if genericType.sons == nil: return var head = 0 for i in 0 .. Date: Mon, 19 Aug 2013 01:34:40 +0300 Subject: [PATCH 10/15] Revert "Revert "made some tests green"" --- compiler/ast.nim | 3 +- compiler/lambdalifting.nim | 2 +- compiler/seminst.nim | 37 +++++++++------- compiler/semtypes.nim | 2 +- tests/compile/tobjects.nim | 86 +++++++++++++++++++------------------- tests/compile/toverprc.nim | 54 ++++++++++++------------ 6 files changed, 95 insertions(+), 89 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 5f6b658cfc..25c66e117b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1359,7 +1359,8 @@ proc getStrOrChar*(a: PNode): string = proc isGenericRoutine*(s: PSym): bool = case s.kind of skProc, skTemplate, skMacro, skIterator, skMethod, skConverter: - result = sfFromGeneric in s.flags + result = sfFromGeneric in s.flags or + (s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty) else: nil proc isRoutine*(s: PSym): bool {.inline.} = diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 163ea41362..9a40b350e1 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -220,7 +220,7 @@ proc getHiddenParam(routine: PSym): PSym = proc isInnerProc(s, outerProc: PSym): bool {.inline.} = result = s.kind in {skProc, skMethod, skConverter} and - s.owner == outerProc and not isGenericRoutine(s) + s.owner == outerProc #s.typ.callConv == ccClosure proc addClosureParam(i: PInnerContext, e: PEnv) = diff --git a/compiler/seminst.nim b/compiler/seminst.nim index ed842d98ef..15be332610 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -91,17 +91,8 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) = addDecl(c, result) pushProcCon(c, result) # add params to scope - let origFormalParams = result.typ.n - result.typ.n = newNodeI(nkFormalParams, - origFormalParams.info, - origFormalParams.len) - result.typ.n.sons[0] = copyNode(origFormalParams.sons[0]) - for i in 1 .. Date: Tue, 28 May 2013 17:14:35 +0300 Subject: [PATCH 11/15] fixes iterating over enums --- compiler/semtypes.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 2c6fc4738d..703b55aced 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -236,11 +236,11 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = markUsed(n, result) if result.kind == skParam and result.typ.kind == tyTypeDesc: # This is a typedesc param. is it already bound? - # it's not bound when it's also used as return type for example - if result.typ.sonsLen > 0: + # it's not bound when it's used multiple times in the + # proc signature for example + if c.InGenericInst > 0: let bound = result.typ.sons[0].sym - if bound != nil: - return bound + if bound != nil: return bound return result if result.typ.sym == nil: LocalError(n.info, errTypeExpected) From 3e79e9f98185148899313da0a7436f861029c10c Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Tue, 28 May 2013 19:52:29 +0300 Subject: [PATCH 12/15] some steps to improve the type mismatches with the new generic instantiation logic --- compiler/semtypes.nim | 5 ++++- compiler/sigmatch.nim | 22 +++++++++++++--------- tests/compile/tgeneric4.nim | 10 ++++++++++ 3 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 tests/compile/tgeneric4.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 703b55aced..8ae23f851d 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -828,7 +828,10 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = matches(c, n, copyTree(n), m) if m.state != csMatch: - LocalError(n.info, errWrongNumberOfArguments) + var err = "cannot instantiate " & typeToString(s.typ) & "\n" & + "got: (" & describeArgs(c, n) & ")\n" & + "but expected: (" & describeArgs(c, s.typ.n, 0) & ")" + LocalError(n.info, errGenerated, err) return newOrPrevType(tyError, prev, c) var isConcrete = true diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 98fa1e1f9d..41268d6d04 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -180,15 +180,9 @@ proc argTypeToString(arg: PNode): string = else: result = arg.typ.typeToString -proc NotFoundError*(c: PContext, n: PNode) = - # Gives a detailed error message; this is separated from semOverloadedCall, - # as semOverlodedCall is already pretty slow (and we need this information - # only in case of an error). - if c.InCompilesContext > 0: - # fail fast: - GlobalError(n.info, errTypeMismatch, "") - var result = msgKindToString(errTypeMismatch) - for i in countup(1, sonsLen(n) - 1): +proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string = + result = "" + for i in countup(startIdx, n.len - 1): var arg = n.sons[i] if n.sons[i].kind == nkExprEqExpr: add(result, renderTree(n.sons[i].sons[0])) @@ -204,6 +198,16 @@ proc NotFoundError*(c: PContext, n: PNode) = if arg.typ.kind == tyError: return add(result, argTypeToString(arg)) if i != sonsLen(n) - 1: add(result, ", ") + +proc NotFoundError*(c: PContext, n: PNode) = + # Gives a detailed error message; this is separated from semOverloadedCall, + # as semOverlodedCall is already pretty slow (and we need this information + # only in case of an error). + if c.InCompilesContext > 0: + # fail fast: + GlobalError(n.info, errTypeMismatch, "") + var result = msgKindToString(errTypeMismatch) + add(result, describeArgs(c, n)) add(result, ')') var candidates = "" var o: TOverloadIter diff --git a/tests/compile/tgeneric4.nim b/tests/compile/tgeneric4.nim new file mode 100644 index 0000000000..f79096636e --- /dev/null +++ b/tests/compile/tgeneric4.nim @@ -0,0 +1,10 @@ +type + TIDGen*[A: Ordinal] = object + next: A + free: seq[A] + +proc newIDGen*[A]: TIDGen[A] = + newSeq result.free, 0 + +var x = newIDGen[int]() + From b01d9b6181be56b1300847cc1352652caa77e437 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sat, 27 Jul 2013 10:17:58 +0300 Subject: [PATCH 13/15] work-in-progress for compiling generics in their owner module --- compiler/ccgstmts.nim | 2 +- compiler/cgen.nim | 12 +++++++++++- compiler/cgendata.nim | 4 +--- compiler/seminst.nim | 7 ++++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 4d52e3aab4..c3374a3548 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -152,7 +152,7 @@ proc genSingleVar(p: BProc, a: PNode) = var immediateAsgn = a.sons[2].kind != nkEmpty if sfGlobal in v.flags: if v.owner.kind != skModule: - targetProc = p.module.preInitProc + targetProc = p.module.postInitProc assignGlobalVar(targetProc, v) # XXX: be careful here. # Global variables should not be zeromem-ed within loops diff --git a/compiler/cgen.nim b/compiler/cgen.nim index b801add6c5..787a2143f0 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1031,8 +1031,9 @@ proc genInitCode(m: BModule) = app(prc, initGCFrame(m.initProc)) app(prc, genSectionStart(cpsLocals)) - app(prc, m.initProc.s(cpsLocals)) app(prc, m.preInitProc.s(cpsLocals)) + app(prc, m.initProc.s(cpsLocals)) + app(prc, m.postInitProc.s(cpsLocals)) app(prc, genSectionEnd(cpsLocals)) if optStackTrace in m.initProc.options and not m.FrameDeclared: @@ -1048,11 +1049,13 @@ proc genInitCode(m: BModule) = app(prc, genSectionStart(cpsInit)) app(prc, m.preInitProc.s(cpsInit)) app(prc, m.initProc.s(cpsInit)) + app(prc, m.postInitProc.s(cpsInit)) app(prc, genSectionEnd(cpsInit)) app(prc, genSectionStart(cpsStmts)) app(prc, m.preInitProc.s(cpsStmts)) app(prc, m.initProc.s(cpsStmts)) + app(prc, m.postInitProc.s(cpsStmts)) app(prc, genSectionEnd(cpsStmts)) if optStackTrace in m.initProc.options and not m.PreventStackTrace: app(prc, deinitFrame(m.initProc)) @@ -1097,6 +1100,11 @@ proc newPreInitProc(m: BModule): BProc = # little hack so that unique temporaries are generated: result.labels = 100_000 +proc newPostInitProc(m: BModule): BProc = + result = newProc(nil, m) + # little hack so that unique temporaries are generated: + result.labels = 200_000 + proc rawNewModule(module: PSym, filename: string): BModule = new(result) InitLinkedList(result.headerFiles) @@ -1111,6 +1119,7 @@ proc rawNewModule(module: PSym, filename: string): BModule = result.initProc = newProc(nil, result) result.initProc.options = gOptions result.preInitProc = newPreInitProc(result) + result.postInitProc = newPostInitProc(result) initNodeTable(result.dataCache) result.typeStack = @[] result.forwardedProcs = @[] @@ -1131,6 +1140,7 @@ proc resetModule*(m: var BModule) = m.initProc = newProc(nil, m) m.initProc.options = gOptions m.preInitProc = newPreInitProc(m) + m.postInitProc = newPostInitProc(m) initNodeTable(m.dataCache) m.typeStack = @[] m.forwardedProcs = @[] diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index ad17194dfd..b5888d0f47 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -100,10 +100,8 @@ type headerFiles*: TLinkedList # needed headers to include typeInfoMarker*: TIntSet # needed for generating type information initProc*: BProc # code for init procedure + postInitProc*: BProc # code to be executed after the init proc preInitProc*: BProc # code executed before the init proc - # used for initialization code for - # .global. variables - # (or instantiated generic variables) typeStack*: TTypeSeq # used for type generation dataCache*: TNodeTable forwardedProcs*: TSymSeq # keep forwarded procs here diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 15be332610..47d889a609 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -233,11 +233,11 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, # we set the friend module: var oldFriend = c.friendModule c.friendModule = getModule(fn) + #let oldScope = c.currentScope + #c.currentScope = fn.scope result = copySym(fn, false) incl(result.flags, sfFromGeneric) - # keep the owner if it's an inner proc (for proper closure transformations): - if fn.owner.kind == skModule: - result.owner = getCurrOwner().owner + result.owner = fn result.ast = n pushOwner(result) openScope(c) @@ -267,6 +267,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, popInfoContext() closeScope(c) # close scope for parameters popOwner() + #c.currentScope = oldScope c.friendModule = oldFriend dec(c.InstCounter) if result.kind == skMethod: finishMethod(c, result) From 4980ef85e254178747dc8ea9fd59b058d33b2df1 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Wed, 14 Aug 2013 22:20:20 +0300 Subject: [PATCH 14/15] check the owners of generic instantiations properly and fix tinvalidclosure --- compiler/ast.nim | 11 ++++++++++- compiler/lambdalifting.nim | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 25c66e117b..bb015ea274 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -792,6 +792,7 @@ const nkStrKinds* = {nkStrLit..nkTripleStrLit} skLocalVars* = {skVar, skLet, skForVar, skParam, skResult} + skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skMethod, skConverter} lfFullExternalName* = lfParamCopy # \ # only used when 'gCmd == cmdPretty': Indicates that the symbol has been @@ -1358,11 +1359,19 @@ proc getStrOrChar*(a: PNode): string = proc isGenericRoutine*(s: PSym): bool = case s.kind - of skProc, skTemplate, skMacro, skIterator, skMethod, skConverter: + of skProcKinds: result = sfFromGeneric in s.flags or (s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty) else: nil +proc skipGenericOwner*(s: PSym): PSym = + InternalAssert s.kind in skProcKinds + ## Generic instantiations are owned by their originating generic + ## symbol. This proc skips such owners and goes straigh to the owner + ## of the generic itself (the module or the enclosing proc). + result = if sfFromGeneric in s.flags: s.owner.owner + else: s.owner + proc isRoutine*(s: PSym): bool {.inline.} = result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod, skConverter} diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 9a40b350e1..96eb3a5f44 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -219,8 +219,8 @@ proc getHiddenParam(routine: PSym): PSym = result = hidden.sym proc isInnerProc(s, outerProc: PSym): bool {.inline.} = - result = s.kind in {skProc, skMethod, skConverter} and - s.owner == outerProc + result = s.kind in {skProc, skMethod, skConverter} and + s.skipGenericOwner == outerProc #s.typ.callConv == ccClosure proc addClosureParam(i: PInnerContext, e: PEnv) = From ca3a4ce6721c87cfcbb9eb02002ecf8aeb89233c Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 15 Aug 2013 22:55:11 +0300 Subject: [PATCH 15/15] hacky fix for generic constraints matching --- compiler/ccgexprs.nim | 4 ++-- compiler/cgen.nim | 4 ++-- compiler/seminst.nim | 2 ++ compiler/sigmatch.nim | 23 ++++++++++++++++++++++- compiler/types.nim | 10 ++++++---- tests/reject/tgenconstraints.nim | 30 ++++++++++++++++++++++++++++++ tests/run/tfieldindex.nim | 2 +- tests/run/tfinally.nim | 10 +++------- 8 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 tests/reject/tgenconstraints.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index bb1035ab67..6357562202 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1932,12 +1932,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = nil of nkPragma: genPragma(p, n) of nkProcDef, nkMethodDef, nkConverterDef: - if (n.sons[genericParamsPos].kind == nkEmpty): + if (n.sons[genericParamsPos].kind == nkEmpty): var prc = n.sons[namePos].sym # due to a bug/limitation in the lambda lifting, unused inner procs # are not transformed correctly. We work around this issue (#411) here # by ensuring it's no inner proc (owner is a module): - if prc.owner.kind == skModule: + if prc.skipGenericOwner.kind == skModule: if (optDeadCodeElim notin gGlobalOptions and sfDeadCodeElim notin getModule(prc).flags) or ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 787a2143f0..0c3f2da840 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -861,8 +861,8 @@ proc isActivated(prc: PSym): bool = prc.typ != nil proc genProc(m: BModule, prc: PSym) = if sfBorrow in prc.flags or not isActivated(prc): return fillProcLoc(prc) - if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc) - else: + if sfForward in prc.flags: addForwardedProc(m, prc) + else: genProcNoForward(m, prc) if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and generatedHeader != nil and lfNoDecl notin prc.loc.Flags: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 47d889a609..601072833d 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -87,6 +87,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) proc instantiateBody(c: PContext, n: PNode, result: PSym) = if n.sons[bodyPos].kind != nkEmpty: + inc c.InGenericInst # add it here, so that recursive generic procs are possible: addDecl(c, result) pushProcCon(c, result) @@ -107,6 +108,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) = #echo "code instantiated ", result.name.s excl(result.flags, sfForward) popProcCon(c) + dec c.InGenericInst proc fixupInstantiatedSymbols(c: PContext, s: PSym) = for i in countup(0, c.generics.len - 1): diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 41268d6d04..626d16d64a 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -38,6 +38,7 @@ type proxyMatch*: bool # to prevent instantiations genericConverter*: bool # true if a generic converter needs to # be instantiated + typedescMatched: bool inheritancePenalty: int # to prefer closest father object type TTypeRelation* = enum # order is important! @@ -499,8 +500,11 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = of tyOrdinal: if isOrdinalType(a): var x = if a.kind == tyOrdinal: a.sons[0] else: a + result = typeRel(c, f.sons[0], x) if result < isGeneric: result = isNone + elif a.kind == tyGenericParam: + result = isGeneric of tyForward: InternalError("forward type in typeRel()") of tyNil: if a.kind == f.kind: result = isEqual @@ -618,7 +622,24 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = of tyGenericParam, tyTypeClass: var x = PType(idTableGet(c.bindings, f)) if x == nil: - result = matchTypeClass(c, f, a) + if c.calleeSym.kind == skType and f.kind == tyGenericParam and not c.typedescMatched: + # XXX: The fact that generic types currently use tyGenericParam for + # their parameters is really a misnomer. tyGenericParam means "match + # any value" and what we need is "match any type", which can be encoded + # by a tyTypeDesc params. Unfortunately, this requires more substantial + # changes in semtypinst and elsewhere. + if a.kind == tyTypeDesc: + if f.sons == nil or f.sons.len == 0: + result = isGeneric + else: + InternalAssert a.sons != nil and a.sons.len > 0 + c.typedescMatched = true + result = typeRel(c, f.sons[0], a.sons[0]) + else: + result = isNone + else: + result = matchTypeClass(c, f, a) + if result == isGeneric: var concrete = concreteType(c, a) if concrete == nil: diff --git a/compiler/types.nim b/compiler/types.nim index b8aaed45e4..2564741d89 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -969,8 +969,8 @@ proc skipGenericAlias*(t: PType): PType = proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool = for i in countup(0, typeClass.sonsLen - 1): let req = typeClass.sons[i] - var match = req.kind == skipTypes(t, {tyGenericInst, tyRange}).kind or - req.kind == skipTypes(t, {tyGenericInst}).kind + var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind + if not match: case req.kind of tyGenericBody: @@ -979,7 +979,9 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool = IdTablePut(bindings, typeClass, t) of tyTypeClass: match = matchTypeClass(bindings, req, t) - else: nil + elif t.kind == tyTypeClass: + match = matchTypeClass(bindings, t, req) + elif t.kind in {tyObject} and req.len != 0: # empty 'object' is fine as constraint in a type class match = sameType(t, req) @@ -1046,7 +1048,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, result = typeAllowedAux(marker, lastSon(t), kind, flags) of tyRange: result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in - {tyChar, tyEnum, tyInt..tyUInt64} + {tyChar, tyEnum, tyInt..tyFloat128} of tyOpenArray, tyVarargs: result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags) of tySequence: diff --git a/tests/reject/tgenconstraints.nim b/tests/reject/tgenconstraints.nim new file mode 100644 index 0000000000..e32aa877b3 --- /dev/null +++ b/tests/reject/tgenconstraints.nim @@ -0,0 +1,30 @@ +discard """ + file: "tgenconstraints.nim" + line: 25 + errormsg: "cannot instantiate T2" +""" + +type + T1[T: int|string] = object + x: T + + T2[T: Ordinal] = object + x: T + +var x1: T1[int] +var x2: T1[string] +var x3: T2[int] + +proc foo[T](x: T): T2[T] {.discardable.} = + var o: T1[T] + +foo(10) + +proc bar(x: string|TNumber): T1[type(x)] {.discardable.} = + when type(x) is TNumber: + var o: T2[type(x)] + +bar "test" +bar 100 +bar 1.1 + diff --git a/tests/run/tfieldindex.nim b/tests/run/tfieldindex.nim index 3ffa65e582..f0674af541 100644 --- a/tests/run/tfieldindex.nim +++ b/tests/run/tfieldindex.nim @@ -5,7 +5,7 @@ discard """ type TMyTuple = tuple[a, b: int] -proc indexOf*(t: typedesc, name: string): int {.compiletime.} = +proc indexOf*(t: typedesc, name: string): int = ## takes a tuple and looks for the field by name. ## returs index of that field. var diff --git a/tests/run/tfinally.nim b/tests/run/tfinally.nim index 273aac72b0..16fb3e7da1 100644 --- a/tests/run/tfinally.nim +++ b/tests/run/tfinally.nim @@ -1,8 +1,6 @@ discard """ file: "tfinally.nim" - output: '''came -here -3''' + output: "came\nhere\n3" """ # Test return in try statement: @@ -14,10 +12,8 @@ proc main: int = echo("came") return 2 finally: - echo("here ") + echo("here") return 3 - + echo main() #OUT came here 3 - -