diff options
author | Araq <rumpf_a@web.de> | 2012-10-03 20:51:22 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-10-03 20:51:22 +0200 |
commit | c2b8669e04560e486e5df21b1217e6b9684ba88e (patch) | |
tree | cdff4a9c1ba92e7feb1990989caff5415fe83dd5 /compiler | |
parent | 9fbee85cc9dd95c1f99e5b55a3d382196eabb7fc (diff) | |
parent | 34e62d9f734189a9237725569aa282e9bedc11a3 (diff) | |
download | Nim-c2b8669e04560e486e5df21b1217e6b9684ba88e.tar.gz |
Merge branch 'master' of github.com:Araq/Nimrod
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 7 | ||||
-rwxr-xr-x | compiler/evals.nim | 35 | ||||
-rwxr-xr-x | compiler/msgs.nim | 17 | ||||
-rwxr-xr-x | compiler/parser.nim | 8 | ||||
-rwxr-xr-x | compiler/sem.nim | 11 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 138 | ||||
-rwxr-xr-x | compiler/semfold.nim | 11 | ||||
-rwxr-xr-x | compiler/semgnrc.nim | 23 | ||||
-rwxr-xr-x | compiler/seminst.nim | 11 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 52 | ||||
-rwxr-xr-x | compiler/semtypinst.nim | 3 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 32 | ||||
-rwxr-xr-x | compiler/types.nim | 37 |
13 files changed, 266 insertions, 119 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 814784029..aa94644aa 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -350,6 +350,8 @@ type # pass of semProcTypeNode performed after instantiation. # this won't be needed if we don't perform this redundant # second pass (stay tuned). + 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) tfAny, # type class requires any constraint to be met tfCapturesEnv, # whether proc really captures some environment @@ -779,6 +781,11 @@ proc add*(father, son: PNode) = proc `[]`*(n: PNode, i: int): PNode {.inline.} = result = n.sons[i] +# son access operators with support for negative indices +template `{}`*(n: PNode, i: int): expr = n[i -| n] +template `{}=`*(n: PNode, i: int, s: PNode): stmt = + n.sons[i -| n] = s + var emptyNode* = newNode(nkEmpty) # There is a single empty node that is shared! Do not overwrite it! diff --git a/compiler/evals.nim b/compiler/evals.nim index 9c73a6b78..226415815 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -41,6 +41,7 @@ type callsite: PNode # for 'callsite' magic mode*: TEvalMode globals*: TIdNodeTable # state of global vars + getType*: proc(n: PNode): PNode PEvalContext* = ref TEvalContext @@ -521,7 +522,7 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = else: result = nil if result == nil or {sfImportc, sfForward} * s.flags != {}: result = raiseCannotEval(c, n.info) - + proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode = result = evalAux(c, n.sons[1], {efLValue}) if isSpecial(result): return @@ -875,6 +876,27 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode = else: internalAssert false +proc evalIsOp*(n: PNode): PNode = + InternalAssert n.sonsLen == 3 and + n[1].kind == nkSym and n[1].sym.kind == skType and + n[2].kind in {nkStrLit..nkTripleStrLit, nkType} + + let t1 = n[1].sym.typ + + if n[2].kind in {nkStrLit..nkTripleStrLit}: + case n[2].strVal.normalize + of "closure": + let t = skipTypes(t1, abstractRange) + result = newIntNode(nkIntLit, ord(t.kind == tyProc and + t.callConv == ccClosure)) + else: + let t2 = n[2].typ + var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1) + else: sameType(t1, t2) + result = newIntNode(nkIntLit, ord(match)) + + result.typ = n.typ + proc expectString(n: PNode) = if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}: GlobalError(n.info, errStringLiteralExpected) @@ -968,6 +990,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = of mTypeTrait: n.sons[1] = evalAux(c, n.sons[1], {}) result = evalTypeTrait(n, c.module) + of mIs: + n.sons[1] = evalAux(c, n.sons[1], {}) + result = evalIsOp(n) of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module) of mStaticExec: let cmd = evalAux(c, n.sons[1], {}) @@ -1067,7 +1092,10 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = result = evalAux(c, n.sons[1], {}) if isSpecial(result): return if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident") - of mNGetType: result = evalAux(c, n.sons[1], {}) + of mNGetType: + var ast = evalAux(c, n.sons[1], {}) + InternalAssert c.getType != nil + result = c.getType(ast) of mNStrVal: result = evalAux(c, n.sons[1], {}) if isSpecial(result): return @@ -1128,7 +1156,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = var a = result result = evalAux(c, n.sons[2], {efLValue}) if isSpecial(result): return - a.typ = result.typ # XXX: exception handling? + InternalAssert result.kind == nkSym and result.sym.kind == skType + a.typ = result.sym.typ result = emptyNode of mNSetStrVal: result = evalAux(c, n.sons[1], {efLValue}) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 0ad79f597..c793c1c68 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -575,19 +575,22 @@ proc inCheckpoint*(current: TLineInfo): TCheckPointResult = type TErrorHandling = enum doNothing, doAbort, doRaise -proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = - if msg == errInternal: - assert(false) # we want a stack trace here +proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = + template maybeTrace = + if defined(debug) or gVerbosity >= 3: + writeStackTrace() + + if msg == errInternal: + writeStackTrace() # we always want a stack trace here if msg >= fatalMin and msg <= fatalMax: - if gVerbosity >= 3: assert(false) + maybeTrace() quit(1) if msg >= errMin and msg <= errMax: - if gVerbosity >= 3: assert(false) + maybeTrace() inc(gErrorCounter) options.gExitcode = 1'i8 if gErrorCounter >= gErrorMax or eh == doAbort: - if gVerbosity >= 3: assert(false) - quit(1) # one error stops the compiler + quit(1) # one error stops the compiler elif eh == doRaise: raiseRecoverableError(s) diff --git a/compiler/parser.nim b/compiler/parser.nim index cdbe42c7e..7612980c5 100755 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -743,7 +743,7 @@ proc isExprStart(p: TParser): bool = case p.tok.tokType of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind, tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, - tkTuple, tkType, tkWhen: + tkTuple, tkType, tkWhen, tkCase: result = true else: result = false @@ -763,9 +763,9 @@ proc parseExpr(p: var TParser): PNode = case p.tok.tokType: of tkIf: result = parseIfExpr(p, nkIfExpr) of tkWhen: result = parseIfExpr(p, nkWhenExpr) + of tkCase: result = parseCase(p) else: result = lowestExpr(p) # XXX needs proper support: - #of tkCase: result = parseCase(p) #of tkTry: result = parseTry(p) proc primary(p: var TParser, skipSuffix = false): PNode = @@ -1044,9 +1044,9 @@ proc parseCase(p: var TParser): PNode = if b.kind == nkElse: break if wasIndented: - eat(p, tkDed) + if p.tok.tokType != tkEof: eat(p, tkDed) popInd(p.lex) - + proc parseTry(p: var TParser): PNode = result = newNodeP(nkTryStmt, p) getTok(p) diff --git a/compiler/sem.nim b/compiler/sem.nim index 397581f63..0a6159dfa 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -43,6 +43,7 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind) proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) proc addResultNode(c: PContext, n: PNode) proc instGenericContainer(c: PContext, n: PNode, header: PType): PType +proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc typeMismatch(n: PNode, formal, actual: PType) = if formal.kind != tyError and actual.kind != tyError: @@ -156,8 +157,18 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, markUsed(n, sym) if sym == c.p.owner: GlobalError(n.info, errRecursiveDependencyX, sym.name.s) + if c.evalContext == nil: c.evalContext = newEvalContext(c.module, "", emStatic) + c.evalContext.getType = proc (n: PNode): PNode = + var e = tryExpr(c, n) + if e == nil: + result = symNodeFromType(c, errorType(c), n.info) + elif e.typ == nil: + result = newSymNode(getSysSym"void") + else: + result = symNodeFromType(c, e.typ, n.info) + result = evalMacroCall(c.evalContext, n, nOrig, sym) if semCheck: result = semAfterMacroCall(c, result, sym) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 7c147e778..e9dc5a8e9 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -281,18 +281,29 @@ proc semOf(c: PContext, n: PNode): PNode = n.typ = getSysType(tyBool) result = n -proc semIs(c: PContext, n: PNode): PNode = - if sonsLen(n) == 3: - n.typ = getSysType(tyBool) - let a = semTypeNode(c, n[1], nil) - n.sons[1] = newNodeIT(nkType, n[1].info, a) - if n[2].kind notin {nkStrLit..nkTripleStrLit}: - let b = semTypeNode(c, n[2], nil) - n.sons[2] = newNodeIT(nkType, n[2].info, b) - else: +proc semIs(c: PContext, n: PNode): PNode = + if sonsLen(n) != 3: LocalError(n.info, errXExpectsTwoArguments, "is") + result = n + n.typ = getSysType(tyBool) + + n.sons[1] = semExprWithType(c, n[1]) + if n[1].typ.kind != tyTypeDesc: + LocalError(n[0].info, errTypeExpected) + + if n[2].kind notin {nkStrLit..nkTripleStrLit}: + let t2 = semTypeNode(c, n[2], nil) + n.sons[2] = newNodeIT(nkType, n[2].info, t2) + if n[1].typ.sonsLen == 0: + # this is a typedesc variable, leave for evals + return + else: + let t1 = n[1].typ.sons[0] + # BUGFIX: don't evaluate this too early: ``T is void`` + if not containsGenericType(t1): result = evalIsOp(n) + proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) = for i in countup(1, sonsLen(n) - tailToExclude): var a = n.sons[i] @@ -1048,8 +1059,20 @@ proc semAsgn(c: PContext, n: PNode): PNode = localError(a.info, errXCannotBeAssignedTo, renderTree(a, {renderNoComments})) else: - n.sons[1] = semExprWithType(c, n.sons[1]) - n.sons[1] = fitNode(c, le, n.sons[1]) + var + rhs = semExprWithType(c, n.sons[1]) + lhs = n.sons[0] + if lhs.kind == nkSym and lhs.sym.kind == skResult and + lhs.sym.typ.kind == tyGenericParam: + if matchTypeClass(lhs.typ, rhs.typ): + InternalAssert c.p.resultSym != nil + lhs.typ = rhs.typ + c.p.resultSym.typ = rhs.typ + c.p.owner.typ.sons[0] = rhs.typ + else: + typeMismatch(n, lhs.typ, rhs.typ) + + n.sons[1] = fitNode(c, le, rhs) fixAbstractType(c, n) asgnToResultVar(c, n, n.sons[0], n.sons[1]) result = n @@ -1214,12 +1237,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, else: result = semDirectOp(c, n, flags) -proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = - # we replace this node by a 'true' or 'false' node: - if sonsLen(n) != 2: return semDirectOp(c, n, flags) - result = newIntNode(nkIntLit, 0) - result.info = n.info - result.typ = getSysType(tyBool) +proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # watch out, hacks ahead: let oldErrorCount = msgs.gErrorCounter let oldErrorMax = msgs.gErrorMax @@ -1241,8 +1259,8 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = let oldProcCon = c.p c.generics = newGenericsCache() try: - discard semExpr(c, n.sons[1]) - result.intVal = ord(msgs.gErrorCounter == oldErrorCount) + result = semExpr(c, n, flags) + if msgs.gErrorCounter != oldErrorCount: result = nil except ERecoverableError: nil # undo symbol table changes (as far as it's possible): @@ -1259,6 +1277,14 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = msgs.gErrorCounter = oldErrorCount msgs.gErrorMax = oldErrorMax +proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = + # we replace this node by a 'true' or 'false' node: + if sonsLen(n) != 2: return semDirectOp(c, n, flags) + + result = newIntNode(nkIntLit, ord(tryExpr(c, n, flags) != nil)) + result.info = n.info + result.typ = getSysType(tyBool) + proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode = if sonsLen(n) == 3: # XXX ugh this is really a hack: shallowCopy() can be overloaded only @@ -1352,19 +1378,28 @@ proc semSetConstr(c: PContext, n: PNode): PNode = m = fitNode(c, typ, n.sons[i]) addSon(result, m) -proc semTableConstr(c: PContext, n: PNode): PNode = - # we simply transform ``{key: value, key2: value}`` to - # ``[(key, value), (key2, value2)]`` +proc semTableConstr(c: PContext, n: PNode): PNode = + # we simply transform ``{key: value, key2, key3: value}`` to + # ``[(key, value), (key2, value2), (key3, value2)]`` result = newNodeI(nkBracket, n.info) + var lastKey = 0 for i in 0..n.len-1: var x = n.sons[i] if x.kind == nkExprColonExpr and sonsLen(x) == 2: + for j in countup(lastKey, i-1): + var pair = newNodeI(nkPar, x.info) + pair.add(n.sons[j]) + pair.add(x[1]) + result.add(pair) + var pair = newNodeI(nkPar, x.info) pair.add(x[0]) pair.add(x[1]) result.add(pair) - else: - illFormedAst(x) + + lastKey = i+1 + + if lastKey != n.len: illFormedAst(n) result = semExpr(c, result) type @@ -1507,6 +1542,57 @@ proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags, renderTree(a, {renderNoComments})) result = errorNode(c, n) +proc semCaseExpr(c: PContext, caseStmt: PNode): PNode = + # The case expression is simply rewritten to a StmtListExpr: + # var res {.noInit, genSym.}: type(values) + # + # case E + # of X: res = value1 + # of Y: res = value2 + # + # res + var + info = caseStmt.info + resVar = newSym(skVar, getIdent":res", getCurrOwner(), info) + resNode = newSymNode(resVar, info) + resType: PType + + resVar.flags = { sfGenSym, sfNoInit } + + for i in countup(1, caseStmt.len - 1): + var cs = caseStmt[i] + case cs.kind + of nkOfBranch, nkElifBranch, nkElse: + # the value is always the last son regardless of the branch kind + cs.checkMinSonsLen 1 + var value = cs{-1} + if value.kind == nkStmtList: value.kind = nkStmtListExpr + + value = semExprWithType(c, value) + if resType == nil: + resType = value.typ + elif not sameType(resType, value.typ): + # XXX: semeType is a bit too harsh. + # work on finding a common base type. + # this will be useful for arrays/seq too: + # [ref DerivedA, ref DerivedB, ref Base] + typeMismatch(cs, resType, value.typ) + + cs{-1} = newNode(nkAsgn, cs.info, @[resNode, value]) + else: + IllFormedAst(caseStmt) + + result = newNode(nkStmtListExpr, info, @[ + newNode(nkVarSection, info, @[ + newNode(nkIdentDefs, info, @[ + resNode, + symNodeFromType(c, resType, info), + emptyNode])]), + caseStmt, + resNode]) + + result = semStmtListExpr(c, result) + proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = n if gCmd == cmdIdeTools: suggestExpr(c, n) @@ -1686,7 +1772,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkTryStmt: result = semTry(c, n) of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n) of nkForStmt, nkParForStmt: result = semFor(c, n) - of nkCaseStmt: result = semCase(c, n) + of nkCaseStmt: + if efWantStmt in flags: result = semCase(c, n) + else: result = semCaseExpr(c, n) of nkReturnStmt: result = semReturn(c, n) of nkAsmStmt: result = semAsm(c, n) of nkYieldStmt: result = semYield(c, n) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index c2958ca5e..d0805d921 100755 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -610,17 +610,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode = result = newIntNodeT(sonsLen(a), n) else: result = magicCall(m, n) - of mIs: - # BUGFIX: don't evaluate this too early: ``T is void`` - if not containsGenericType(n[1].typ): - if n[2].kind in {nkStrLit..nkTripleStrLit}: - case n[2].strVal.normalize - of "closure": - let t = skipTypes(n[1].typ, abstractRange) - result = newIntNodeT(ord(t.kind == tyProc and - t.callConv == ccClosure), n) - elif not containsGenericType(n[2].typ): - result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n) of mAstToStr: result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) of mConStrStr: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 2751aa1e1..bffa8ad8e 100755 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -261,16 +261,16 @@ proc semGenericStmt(c: PContext, n: PNode, else: a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind) of nkEnumTy: - checkMinSonsLen(n, 1) - if n.sons[0].kind != nkEmpty: - n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind) - for i in countup(1, sonsLen(n) - 1): - var a: PNode - case n.sons[i].kind - of nkEnumFieldDef: a = n.sons[i].sons[0] - of nkIdent: a = n.sons[i] - else: illFormedAst(n) - addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1) + if n.sonsLen > 0: + if n.sons[0].kind != nkEmpty: + n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind) + for i in countup(1, sonsLen(n) - 1): + var a: PNode + case n.sons[i].kind + of nkEnumFieldDef: a = n.sons[i].sons[0] + of nkIdent: a = n.sons[i] + else: illFormedAst(n) + addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1) of nkObjectTy, nkTupleTy: nil of nkFormalParams: @@ -306,6 +306,9 @@ proc semGenericStmt(c: PContext, n: PNode, n.sons[bodyPos] = semGenericStmtScope(c, body, flags, toBind) closeScope(c.tab) of nkPragma, nkPragmaExpr: nil + of nkExprColonExpr: + checkMinSonsLen(n, 2) + result.sons[1] = semGenericStmt(c, n.sons[1], flags, toBind) else: for i in countup(0, sonsLen(n) - 1): result.sons[i] = semGenericStmt(c, n.sons[i], flags, toBind) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 61210c0f8..8e164531a 100755 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -25,8 +25,13 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable, s.flags = s.flags + {sfUsed, sfFromGeneric} var t = PType(IdTableGet(pt, q.typ)) if t == nil: - LocalError(a.info, errCannotInstantiateX, s.name.s) - t = errorType(c) + if tfRetType in q.typ.flags: + # keep the generic type and allow the return type to be bound + # later by semAsgn in return type inference scenario + t = q.typ + else: + LocalError(a.info, errCannotInstantiateX, s.name.s) + t = errorType(c) elif t.kind == tyGenericParam: InternalError(a.info, "instantiateGenericParamList: " & q.name.s) elif t.kind == tyGenericInvokation: @@ -163,7 +168,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, result.typ = newTypeS(tyProc, c) rawAddSon(result.typ, nil) result.typ.callConv = fn.typ.callConv - ParamsTypeCheck(c, result.typ) var oldPrc = GenericCacheGet(c, entry) if oldPrc == nil: c.generics.generics.add(entry) @@ -174,6 +178,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, if fn.kind != skTemplate: instantiateBody(c, n, result) sideEffectsCheck(c, result) + ParamsTypeCheck(c, result.typ) else: result = oldPrc popInfoContext() diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 5362d6d4a..c41727b10 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -584,22 +584,20 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind): result.typ = newTypeS(tyTypeDesc, c) result.typ.sons = paramType.sons of tyDistinct: - # type T1 = distinct expr - # type S1 = distinct Sortable - # proc x(a, b: T1, c, d: S1) - # This forces bindOnce behavior for the type class, equivalent to - # proc x[T, S](a, b: T, c, d: S) result = paramTypeClass(c, paramType.lastSon, procKind) - result.id = paramType.sym.name + # disable the bindOnce behavior for the type class + result.id = nil + return of tyGenericBody: # type Foo[T] = object # proc x(a: Foo, b: Foo) result.typ = newTypeS(tyTypeClass, c) result.typ.addSonSkipIntLit(paramType) - result.id = paramType.sym.name # bindOnce by default of tyTypeClass: result.typ = copyType(paramType, getCurrOwner(), false) else: nil + # bindOnce by default + if paramType.sym != nil: result.id = paramType.sym.name proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, paramType: PType, paramName: string, @@ -619,7 +617,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, let s = SymtabGet(c.tab, paramTypId) # tests/run/tinterf triggers this: if s != nil: result = s.typ - else: + else: LocalError(info, errCannotInstantiateX, paramName) result = errorType(c) else: @@ -684,8 +682,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue for j in countup(0, length-3): var arg = newSymG(skParam, a.sons[j], c) - var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s, - arg.info).skipIntLit + var finalType = liftParamType(c, kind, genericParams, typ, + arg.name.s, arg.info).skipIntLit arg.typ = finalType arg.position = counter inc(counter) @@ -703,6 +701,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if skipTypes(r, {tyGenericInst}).kind != tyEmpty: if r.sym == nil or sfAnon notin r.sym.flags: r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info) + r.flags.incl tfRetType result.sons[0] = skipIntLit(r) res.typ = result.sons[0] @@ -800,22 +799,25 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = LocalError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) of nkCallKinds: - let op = n.sons[0].ident - if op.id in {ord(wAnd), ord(wOr)} or op.s == "|": - var - t1 = semTypeNode(c, n.sons[1], nil) - t2 = semTypeNode(c, n.sons[2], nil) - if t1 == nil: - LocalError(n.sons[1].info, errTypeExpected) - result = newOrPrevType(tyError, prev, c) - elif t2 == nil: - LocalError(n.sons[2].info, errTypeExpected) - result = newOrPrevType(tyError, prev, c) + if n[0].kind == nkIdent: + let op = n.sons[0].ident + if op.id in {ord(wAnd), ord(wOr)} or op.s == "|": + var + t1 = semTypeNode(c, n.sons[1], nil) + t2 = semTypeNode(c, n.sons[2], nil) + if t1 == nil: + LocalError(n.sons[1].info, errTypeExpected) + result = newOrPrevType(tyError, prev, c) + elif t2 == nil: + LocalError(n.sons[2].info, errTypeExpected) + result = newOrPrevType(tyError, prev, c) + else: + result = newTypeS(tyTypeClass, c) + result.addSonSkipIntLit(t1) + result.addSonSkipIntLit(t2) + result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny) else: - result = newTypeS(tyTypeClass, c) - result.addSonSkipIntLit(t1) - result.addSonSkipIntLit(t2) - result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny) + result = semTypeExpr(c, n) else: result = semTypeExpr(c, n) of nkCurlyExpr: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index d75594dff..70453c6db 100755 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -59,6 +59,7 @@ type proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym +proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode = result = copyNode(n) @@ -66,7 +67,7 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode = for i in 0 .. safeLen(n)-1: # XXX HACK: ``f(a, b)``, avoid to instantiate `f` if i == 0: result.add(n[i]) - else: result.add(prepareNode(cl, n[i])) + else: result.add(ReplaceTypeVarsN(cl, n[i])) proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode = if n == nil: return diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7e482b3d2..8f1ca5f36 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -11,7 +11,7 @@ ## the call to overloaded procs, generic procs and operators. import - intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, + intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, magicsys, condsyms, idents, lexer, options type @@ -257,32 +257,6 @@ proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation = var y = a.n.sons[i].sym if x.name.id != y.name.id: return isNone -proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation = - for i in countup(0, typeClass.sonsLen - 1): - let req = typeClass.sons[i] - var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind - - if not match: - case req.kind - of tyGenericBody: - if t.kind == tyGenericInst and t.sons[0] == req: - match = true - put(c.bindings, typeClass, t) - of tyTypeClass: - match = matchTypeClass(c, req, t) == isGeneric - else: nil - elif t.kind in {tyObject}: - match = sameType(t, req) - - if tfAny in typeClass.flags: - if match: return isGeneric - else: - if not match: return isNone - - # if the loop finished without returning, either all constraints matched - # or none of them matched. - result = if tfAny in typeClass.flags: isNone else: isGeneric - proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = proc inconsistentVarTypes(f, a: PType): bool {.inline.} = result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar) @@ -325,6 +299,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = result = isNone else: nil +proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation = + result = if matchTypeClass(c.bindings, f, a): isGeneric + else: isNone + proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = # is a subtype of f? result = isNone diff --git a/compiler/types.nim b/compiler/types.nim index d8879f1b4..e02d93233 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -626,9 +626,9 @@ proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool = var c = initSameTypeClosure() c.flags = flags result = SameTypeAux(a, b, c) - + proc equalParam(a, b: PSym): TParamsEquality = - if SameTypeOrNil(a.typ, b.typ): + if SameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): if a.ast == b.ast: result = paramsEqual elif a.ast != nil and b.ast != nil: @@ -904,7 +904,38 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]], if i >= a.sonslen or a.sons[i] == nil: return false a = a.sons[i] result = a.kind == last - + +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, {tyRange, tyGenericInst}).kind + + if not match: + case req.kind + of tyGenericBody: + if t.kind == tyGenericInst and t.sons[0] == req: + match = true + IdTablePut(bindings, typeClass, t) + of tyTypeClass: + match = matchTypeClass(bindings, req, t) + else: nil + elif t.kind in {tyObject}: + match = sameType(t, req) + + if tfAny in typeClass.flags: + if match: return true + else: + if not match: return false + + # if the loop finished without returning, either all constraints matched + # or none of them matched. + result = if tfAny in typeClass.flags: false else: true + +proc matchTypeClass*(typeClass, typ: PType): bool = + var bindings: TIdTable + initIdTable(bindings) + result = matchTypeClass(bindings, typeClass, typ) + proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = assert(kind in {skVar, skLet, skConst, skParam, skResult}) # if we have already checked the type, return true, because we stop the |