diff options
author | Araq <rumpf_a@web.de> | 2013-12-05 00:03:27 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2013-12-05 00:03:27 +0100 |
commit | 5eba93d584d5446256d05f0eef111ace5e12bac3 (patch) | |
tree | 7b638031f3e77c16ca0c27b9c83630d78846f19e /compiler | |
parent | 9035d15ed22de1f80486d94ec63e720a4d04cbc0 (diff) | |
parent | 2264875237cb72cf0288f2bd3d4a930c2a1acc50 (diff) | |
download | Nim-5eba93d584d5446256d05f0eef111ace5e12bac3.tar.gz |
Merge branch 'master' into vm2
Conflicts: compiler/sem.nim
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 6 | ||||
-rw-r--r-- | compiler/cgen.nim | 23 | ||||
-rw-r--r-- | compiler/cgendata.nim | 1 | ||||
-rw-r--r-- | compiler/extccomp.nim | 2 | ||||
-rw-r--r-- | compiler/lists.nim | 18 | ||||
-rw-r--r-- | compiler/msgs.nim | 55 | ||||
-rw-r--r-- | compiler/nimconf.nim | 5 | ||||
-rw-r--r-- | compiler/nimrod.nimrod.cfg (renamed from compiler/nimrod.cfg) | 0 | ||||
-rw-r--r-- | compiler/parser.nim | 15 | ||||
-rw-r--r-- | compiler/sem.nim | 53 | ||||
-rw-r--r-- | compiler/semdata.nim | 4 | ||||
-rw-r--r-- | compiler/semexprs.nim | 44 | ||||
-rw-r--r-- | compiler/semstmts.nim | 41 | ||||
-rw-r--r-- | compiler/semtypes.nim | 3 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 68 | ||||
-rw-r--r-- | compiler/types.nim | 28 |
17 files changed, 238 insertions, 130 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 9d85e8ff2..1eb5bffc4 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -713,7 +713,6 @@ type # -1 means that the size is unkwown align*: int # the type's alignment requirements loc*: TLoc - testeeName*: PIdent # the test variable in user-defined type classes TPair*{.final.} = object key*, val*: PObject @@ -1089,7 +1088,6 @@ proc assignType(dest, src: PType) = dest.size = src.size dest.align = src.align dest.destructor = src.destructor - dest.testeeName = src.testeeName # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index c50fd4536..873c61ed4 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -240,6 +240,7 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if needToCopy notin flags or tfShallow in skipTypes(dest.t, abstractVarRange).flags: if dest.s == OnStack or not usesNativeGC(): + useStringh(p.module) linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", addrLoc(dest), addrLoc(src), rdLoc(dest)) @@ -316,6 +317,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if needsComplexAssignment(dest.t): genGenericAsgn(p, dest, src, flags) else: + useStringh(p.module) linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n", rdLoc(dest), rdLoc(src)) @@ -327,11 +329,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n", addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)) else: + useStringh(p.module) linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len0);$n", rdLoc(dest), rdLoc(src)) of tySet: if mapType(ty) == ctArray: + useStringh(p.module) linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n", rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))) else: @@ -1361,6 +1365,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = lineF(p, cpsStmts, lookupOpr[op], [rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)]) of mEqSet: + useStringh(p.module) binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)") of mMulSet, mPlusSet, mMinusSet, mSymDiffSet: # we inline the simple for loop for better code generation: @@ -1612,6 +1617,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = if d.k == locNone: getTemp(p, e.typ, d) if getSize(e.typ) > 8: # big set: + useStringh(p.module) lineF(p, cpsStmts, "memset($1, 0, sizeof($1));$n", [rdLoc(d)]) for i in countup(0, sonsLen(e) - 1): if e.sons[i].kind == nkRange: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 910e675e1..ad9ade63c 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -72,6 +72,11 @@ proc isSimpleConst(typ: PType): bool = {tyTuple, tyObject, tyArray, tyArrayConstr, tySet, tySequence} and not (t.kind == tyProc and t.callConv == ccClosure) +proc useStringh(m: BModule) = + if not m.includesStringh: + m.includesStringh = true + discard lists.IncludeStr(m.headerFiles, "<string.h>") + proc useHeader(m: BModule, sym: PSym) = if lfHeader in sym.loc.Flags: assert(sym.annex != nil) @@ -358,19 +363,24 @@ proc resetLoc(p: BProc, loc: var TLoc) = # field, so disabling this should be safe: genObjectInit(p, cpsStmts, loc.t, loc, true) else: + useStringh(p.module) linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n", addrLoc(loc), rdLoc(loc)) # XXX: We can be extra clever here and call memset only # on the bytes following the m_type field? genObjectInit(p, cpsStmts, loc.t, loc, true) -proc constructLoc(p: BProc, loc: TLoc, section = cpsStmts) = +proc constructLoc(p: BProc, loc: TLoc, isTemp = false) = if not isComplexValueType(skipTypes(loc.t, abstractRange)): - linefmt(p, section, "$1 = 0;$n", rdLoc(loc)) + linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc)) else: - linefmt(p, section, "memset((void*)$1, 0, sizeof($2));$n", - addrLoc(loc), rdLoc(loc)) - genObjectInit(p, section, loc.t, loc, true) + if not isTemp or containsGarbageCollectedRef(loc.t): + # don't use memset for temporary values for performance if we can + # avoid it: + useStringh(p.module) + linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n", + addrLoc(loc), rdLoc(loc)) + genObjectInit(p, cpsStmts, loc.t, loc, true) proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = if sfNoInit notin v.flags: @@ -396,7 +406,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc) = result.t = getUniqueType(t) result.s = OnStack result.flags = {} - constructLoc(p, result) + constructLoc(p, result, isTemp=true) proc keepAlive(p: BProc, toKeepAlive: TLoc) = when false: @@ -418,6 +428,7 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) = if not isComplexValueType(skipTypes(toKeepAlive.t, abstractVarRange)): linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(result), rdLoc(toKeepAlive)) else: + useStringh(p.module) linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", addrLoc(result), addrLoc(toKeepAlive), rdLoc(result)) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index b5888d0f4..c156c40fe 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -91,6 +91,7 @@ type FrameDeclared*: bool # hack for ROD support so that we don't declare # a frame var twice in an init proc isHeaderFile*: bool # C source file is the header file + includesStringh*: bool # C source file already includes ``<string.h>`` cfilename*: string # filename of the module (including path, # without extension) typeCache*: TIdTable # cache the generated types diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index d7f3386e3..13eb972f6 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -583,7 +583,7 @@ proc CallCCompiler*(projectfile: string) = else: rawMessage(errGenerated, " execution of an external program failed; " & "rerun with --parallelBuild:1 to see the error message") - if optNoLinking notin gGlobalOptions and cmds.len > 0: + if optNoLinking notin gGlobalOptions: # call the linker: var it = PStrEntry(toLink.head) var objfiles = "" diff --git a/compiler/lists.nim b/compiler/lists.nim index 67b32f919..22b1a183a 100644 --- a/compiler/lists.nim +++ b/compiler/lists.nim @@ -91,13 +91,17 @@ proc Remove*(list: var TLinkedList, entry: PListEntry) = if entry.prev != nil: entry.prev.next = entry.next proc bringToFront*(list: var TLinkedList, entry: PListEntry) = - if entry == list.head: return - if entry == list.tail: list.tail = entry.prev - if entry.next != nil: entry.next.prev = entry.prev - if entry.prev != nil: entry.prev.next = entry.next - entry.prev = nil - entry.next = list.head - list.head = entry + when true: + list.remove entry + list.prepend entry + else: + if entry == list.head: return + if entry == list.tail: list.tail = entry.prev + if entry.next != nil: entry.next.prev = entry.prev + if entry.prev != nil: entry.prev.next = entry.next + entry.prev = nil + entry.next = list.head + list.head = entry proc ExcludeStr*(list: var TLinkedList, data: string) = var it = list.head diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 5363442b4..895ba71f3 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -436,7 +436,14 @@ type # only 8 bytes. line*, col*: int16 fileIndex*: int32 - + + TErrorOutput* = enum + eStdOut + eStdErr + eInMemory + + TErrorOutputs* = set[TErrorOutput] + ERecoverableError* = object of EInvalidValue ESuggestDone* = object of EBase @@ -534,13 +541,27 @@ var gHintCounter*: int = 0 gWarnCounter*: int = 0 gErrorMax*: int = 1 # stop after gErrorMax errors - gSilence*: int # == 0 if we produce any output at all when useCaas: var stdoutSocket*: TSocket +proc UnknownLineInfo*(): TLineInfo = + result.line = int16(-1) + result.col = int16(-1) + result.fileIndex = -1 + +var + msgContext: seq[TLineInfo] = @[] + lastError = UnknownLineInfo() + bufferedMsgs*: seq[string] + + errorOutputs* = {eStdOut, eStdErr} + +proc clearBufferedMsgs* = + bufferedMsgs = nil + proc SuggestWriteln*(s: string) = - if gSilence == 0: + if eStdOut in errorOutputs: when useCaas: if isNil(stdoutSocket): Writeln(stdout, s) else: @@ -548,6 +569,9 @@ proc SuggestWriteln*(s: string) = stdoutSocket.send(s & "\c\L") else: Writeln(stdout, s) + + if eInMemory in errorOutputs: + bufferedMsgs.safeAdd(s) proc SuggestQuit*() = if not isServing: @@ -570,14 +594,6 @@ const RawWarningFormat* = "Warning: $1" RawHintFormat* = "Hint: $1" -proc UnknownLineInfo*(): TLineInfo = - result.line = int16(-1) - result.col = int16(-1) - result.fileIndex = -1 - -var - msgContext: seq[TLineInfo] = @[] - proc getInfoContextLen*(): int = return msgContext.len proc setInfoContextLen*(L: int) = setLen(msgContext, L) @@ -642,14 +658,18 @@ proc addCheckpoint*(filename: string, line: int) = proc OutWriteln*(s: string) = ## Writes to stdout. Always. - if gSilence == 0: Writeln(stdout, s) + if eStdOut in errorOutputs: Writeln(stdout, s) proc MsgWriteln*(s: string) = ## Writes to stdout. If --stdout option is given, writes to stderr instead. - if gSilence == 0: - if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return - if optStdout in gGlobalOptions: Writeln(stderr, s) - else: Writeln(stdout, s) + if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return + + if optStdout in gGlobalOptions: + if eStdErr in errorOutputs: Writeln(stderr, s) + else: + if eStdOut in errorOutputs: Writeln(stdout, s) + + if eInMemory in errorOutputs: bufferedMsgs.safeAdd(s) proc coordToStr(coord: int): string = if coord == -1: result = "???" @@ -736,9 +756,6 @@ proc rawMessage*(msg: TMsgKind, args: openarray[string]) = proc rawMessage*(msg: TMsgKind, arg: string) = rawMessage(msg, [arg]) -var - lastError = UnknownLineInfo() - proc writeSurroundingSrc(info: TLineInfo) = const indent = " " MsgWriteln(indent & info.sourceLine.ropeToStr) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 507812d9c..7ec566a01 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -243,11 +243,6 @@ proc LoadConfigs*(cfg: string) = readConfigFile(pd / cfg) if gProjectName.len != 0: - var conffile = changeFileExt(gProjectFull, "cfg") - if conffile != pd / cfg and existsFile(conffile): - readConfigFile(conffile) - rawMessage(warnConfigDeprecated, conffile) - # new project wide config file: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg")) diff --git a/compiler/nimrod.cfg b/compiler/nimrod.nimrod.cfg index 0affe86d9..0affe86d9 100644 --- a/compiler/nimrod.cfg +++ b/compiler/nimrod.nimrod.cfg diff --git a/compiler/parser.nim b/compiler/parser.nim index e8439466a..fd51b04ec 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1624,10 +1624,23 @@ proc parseObject(p: var TParser): PNode = return addSon(result, parseObjectPart(p)) +proc parseTypeClassParam(p: var TParser): PNode = + if p.tok.tokType == tkVar: + getTok(p) + result = newNode(nkVarTy) + result.addSon(p.parseSymbol) + else: + result = p.parseSymbol + proc parseTypeClass(p: var TParser): PNode = result = newNodeP(nkTypeClassTy, p) getTok(p) - addSon(result, p.parseSymbol) + var args = newNode(nkArgList) + addSon(result, args) + addSon(args, p.parseTypeClassParam) + while p.tok.TokType == tkComma: + getTok(p) + addSon(args, p.parseTypeClassParam) if p.tok.tokType == tkCurlyDotLe and p.validInd: addSon(result, parsePragma(p)) else: diff --git a/compiler/sem.nim b/compiler/sem.nim index ee3df9f6a..f639b831a 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -36,7 +36,8 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) proc addParams(c: PContext, n: PNode, kind: TSymKind) proc maybeAddResult(c: PContext, s: PSym, n: PNode) proc instGenericContainer(c: PContext, n: PNode, header: PType): PType -proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode +proc tryExpr(c: PContext, n: PNode, + flags: TExprFlags = {}, bufferErrors = false): PNode proc fixImmediateParams(n: PNode): PNode proc activate(c: PContext, n: PNode) proc semQuoteAst(c: PContext, n: PNode): PNode @@ -89,6 +90,24 @@ proc commonType*(x, y: PType): PType = let idx = ord(b.kind in {tyArray, tyArrayConstr}) if a.sons[idx].kind == tyEmpty: return y #elif b.sons[idx].kind == tyEmpty: return x + elif a.kind == tyRange and b.kind == tyRange: + # consider: (range[0..3], range[0..4]) here. We should make that + # range[0..4]. But then why is (range[0..4], 6) not range[0..6]? + # But then why is (2,4) not range[2..4]? But I think this would break + # too much code. So ... it's the same range or the base type. This means + # type(if b: 0 else 1) == int and not range[0..1]. For now. In the long + # run people expect ranges to work properly within a tuple. + if not sameType(a, b): + result = skipTypes(a, {tyRange}).skipIntLit + when false: + if a.kind != tyRange and b.kind == tyRange: + # XXX This really needs a better solution, but a proper fix now breaks + # code. + result = a #.skipIntLit + elif a.kind == tyRange and b.kind != tyRange: + result = b #.skipIntLit + elif a.kind in IntegralTypes and a.n != nil: + result = a #.skipIntLit else: var k = tyNone if a.kind in {tyRef, tyPtr}: @@ -102,7 +121,7 @@ proc commonType*(x, y: PType): PType = if result.isNil: return x if k != tyNone: let r = result - result = NewType(k, r.owner) + result = newType(k, r.owner) result.addSonSkipIntLit(r) proc isTopLevel(c: PContext): bool {.inline.} = @@ -139,27 +158,28 @@ proc IsOpImpl(c: PContext, n: PNode): PNode proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, semCheck: bool = true): PNode -proc symFromType(t: PType, info: TLineInfo): PSym = - if t.sym != nil: return t.sym - result = newSym(skType, getIdent"AnonType", t.owner, info) - result.flags.incl sfAnon - result.typ = t +when false: + proc symFromType(t: PType, info: TLineInfo): PSym = + if t.sym != nil: return t.sym + result = newSym(skType, getIdent"AnonType", t.owner, info) + result.flags.incl sfAnon + result.typ = t -proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode = - result = newSymNode(symFromType(t, info), info) - result.typ = makeTypeDesc(c, t) + proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode = + result = newSymNode(symFromType(t, info), info) + result.typ = makeTypeDesc(c, t) when false: proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext = result = newEvalContext(c.module, mode) result.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 = tryExpr(c, n) + if result == nil: + result = newSymNode(errorSym(c, n)) + elif result.typ == nil: result = newSymNode(getSysSym"void") else: - result = symNodeFromType(c, e.typ, n.info) + result.typ = makeTypeDesc(c, result.typ) result.handleIsOperator = proc (n: PNode): PNode = result = IsOpImpl(c, n) @@ -215,7 +235,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = of tyTypeDesc: if n.kind == nkStmtList: result.kind = nkStmtListType var typ = semTypeNode(c, result, nil) - result = symNodeFromType(c, typ, n.info) + result.typ = makeTypeDesc(c, typ) + #result = symNodeFromType(c, typ, n.info) else: result = semExpr(c, result) result = fitNode(c, s.typ.sons[0], result) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 9ab365c9d..650a399f7 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -60,6 +60,7 @@ type threadEntries*: TSymSeq # list of thread entries to check AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot # store this info in the syms themselves!) + InTypeClass*: int # > 0 if we are in a user-defined type class InGenericContext*: int # > 0 if we are in a generic type InUnrolledContext*: int # > 0 if we are unrolling a loop InCompilesContext*: int # > 0 if we are in a ``compiles`` magic @@ -72,7 +73,8 @@ type libs*: TLinkedList # all libs used by this module semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} - semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} + semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}, + bufferErrors = false): PNode {.nimcall.} semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b5d3ced66..78d828e43 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -191,7 +191,7 @@ proc isCastable(dst, src: PType): bool = proc isSymChoice(n: PNode): bool {.inline.} = result = n.kind in nkSymChoices -proc semConv(c: PContext, n: PNode, s: PSym): PNode = +proc semConv(c: PContext, n: PNode): PNode = if sonsLen(n) != 2: LocalError(n.info, errConvNeedsOneArg) return n @@ -299,7 +299,7 @@ proc semOf(c: PContext, n: PNode): PNode = n.typ = getSysType(tyBool) result = n -proc IsOpImpl(c: PContext, n: PNode): PNode = +proc isOpImpl(c: PContext, 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} @@ -321,10 +321,19 @@ proc IsOpImpl(c: PContext, n: PNode): PNode = else: var match: bool let t2 = n[2].typ - if t2.kind == tyTypeClass: + case t2.kind + of tyTypeClass: var m: TCandidate InitCandidate(m, t2) match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil + of tyOrdinal: + var m: TCandidate + InitCandidate(m, t2) + match = isOrdinalType(t1) + of tySequence, tyArray, tySet: + var m: TCandidate + InitCandidate(m, t2) + match = typeRel(m, t2, t1) != isNone else: match = sameType(t1, t2) @@ -353,7 +362,7 @@ proc semIs(c: PContext, n: PNode): PNode = let t1 = n[1].typ.sons[0] # BUGFIX: don't evaluate this too early: ``T is void`` - if not containsGenericType(t1): result = IsOpImpl(c, n) + if not containsGenericType(t1): result = isOpImpl(c, n) proc semOpAux(c: PContext, n: PNode) = const flags = {efDetermineType} @@ -729,8 +738,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = elif t != nil and t.kind == tyTypeDesc: if n.len == 1: return semObjConstr(c, n, flags) let destType = t.skipTypes({tyTypeDesc, tyGenericInst}) - result = semConv(c, n, symFromType(destType, n.info)) - return + return semConv(c, n) else: result = overloadedCallOpr(c, n) # Now that nkSym does not imply an iteration over the proc/iterator space, @@ -763,7 +771,8 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode = analyseIfAddressTakenInCall(c, result) if callee.magic != mNone: result = magicsAfterOverloadResolution(c, result, flags) - result = evalAtCompileTime(c, result) + if c.InTypeClass == 0: + result = evalAtCompileTime(c, result) proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = # this seems to be a hotspot in the compiler! @@ -814,7 +823,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode = proc semExprNoType(c: PContext, n: PNode): PNode = result = semExpr(c, n, {efWantStmt}) - discardCheck(result) + discardCheck(c, result) proc isTypeExpr(n: PNode): bool = case n.kind @@ -1038,7 +1047,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = # The result so far is a tyTypeDesc bound # a tyGenericBody. The line below will substitute # it with the instantiated type. - result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) + result = n + result.typ = makeTypeDesc(c, semTypeNode(c, n, nil)) + #result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) of tyTuple: checkSonsLen(n, 2) n.sons[0] = makeDeref(n.sons[0]) @@ -1208,7 +1219,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = a.sons[1] = result result = semAsgn(c, a) else: - discardCheck(result) + discardCheck(c, result) closeScope(c) proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) = @@ -1429,12 +1440,12 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = newNode(nkCall, n.info, quotes)]) result = semExpandToAst(c, result) -proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = +proc tryExpr(c: PContext, n: PNode, + flags: TExprFlags = {}, bufferErrors = false): PNode = # watch out, hacks ahead: let oldErrorCount = msgs.gErrorCounter let oldErrorMax = msgs.gErrorMax inc c.InCompilesContext - inc msgs.gSilence # do not halt after first error: msgs.gErrorMax = high(int) @@ -1443,6 +1454,8 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = openScope(c) let oldOwnerLen = len(gOwners) let oldGenerics = c.generics + let oldErrorOutputs = errorOutputs + errorOutputs = if bufferErrors: {eInMemory} else: {} let oldContextLen = msgs.getInfoContextLen() let oldInGenericContext = c.InGenericContext @@ -1465,7 +1478,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = setlen(gOwners, oldOwnerLen) c.currentScope = oldScope dec c.InCompilesContext - dec msgs.gSilence + errorOutputs = oldErrorOutputs msgs.gErrorCounter = oldErrorCount msgs.gErrorMax = oldErrorMax @@ -1871,7 +1884,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExpr(c, n.sons[0], flags) of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy: var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc}) - result = symNodeFromType(c, typ, n.info) + result.typ = makeTypeDesc(c, typ) + #result = symNodeFromType(c, typ, n.info) of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1) @@ -1894,7 +1908,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of skType: # XXX think about this more (``set`` procs) if n.len == 2: - result = semConv(c, n, s) + result = semConv(c, n) elif n.len == 1: result = semObjConstr(c, n, flags) elif Contains(c.AmbiguousSymbols, s.id): diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 441102989..cd714ef6e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -132,7 +132,7 @@ proc fixNilType(n: PNode) = for it in n: fixNilType(it) n.typ = nil -proc discardCheck(result: PNode) = +proc discardCheck(c: PContext, result: PNode) = if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}: if result.kind == nkNilLit: result.typ = nil @@ -142,6 +142,10 @@ proc discardCheck(result: PNode) = while n.kind in skipForDiscardable: n = n.lastSon n.typ = nil + elif c.InTypeClass > 0 and result.typ.kind == tyBool: + let verdict = semConstExpr(c, result) + if verdict.intVal == 0: + localError(result.info, "type class predicate failed.") elif result.typ.kind != tyError and gCmd != cmdInteractive: if result.typ.kind == tyNil: fixNilType(result) @@ -169,7 +173,7 @@ proc semIf(c: PContext, n: PNode): PNode = typ = commonType(typ, it.sons[0].typ) else: illFormedAst(it) if isEmptyType(typ) or typ.kind == tyNil or not hasElse: - for it in n: discardCheck(it.lastSon) + for it in n: discardCheck(c, it.lastSon) result.kind = nkIfStmt # propagate any enforced VoidContext: if typ == EnforceVoidContext: result.typ = EnforceVoidContext @@ -230,7 +234,7 @@ proc semCase(c: PContext, n: PNode): PNode = localError(n.info, errNotAllCasesCovered) closeScope(c) if isEmptyType(typ) or typ.kind == tyNil or not hasElse: - for i in 1..n.len-1: discardCheck(n.sons[i].lastSon) + for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) # propagate any enforced VoidContext: if typ == EnforceVoidContext: result.typ = EnforceVoidContext @@ -275,8 +279,8 @@ proc semTry(c: PContext, n: PNode): PNode = typ = commonType(typ, a.sons[length-1].typ) dec c.p.inTryStmt if isEmptyType(typ) or typ.kind == tyNil: - discardCheck(n.sons[0]) - for i in 1..n.len-1: discardCheck(n.sons[i].lastSon) + discardCheck(c, n.sons[0]) + for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) if typ == EnforceVoidContext: result.typ = EnforceVoidContext else: @@ -881,8 +885,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = openScope(c) if n.sons[genericParamsPos].kind != nkEmpty: illFormedAst(n) # process parameters: - if n.sons[paramsPos].kind != nkEmpty: - semParamList(c, n.sons[ParamsPos], nil, s) + if n.sons[paramsPos].kind != nkEmpty: + var gp = newNodeI(nkGenericParams, n.info) + semParamList(c, n.sons[ParamsPos], gp, s) ParamsTypeCheck(c, s.typ) else: s.typ = newTypeS(tyProc, c) @@ -1084,6 +1089,8 @@ proc semIterator(c: PContext, n: PNode): PNode = # -- at least for 0.9.2. if s.typ.callConv == ccClosure: incl(s.typ.flags, tfCapturesEnv) + else: + s.typ.callConv = ccInline when false: if s.typ.callConv != ccInline: s.typ.callConv = ccClosure @@ -1106,24 +1113,24 @@ proc finishMethod(c: PContext, s: PSym) = methodDef(s, false) proc semMethod(c: PContext, n: PNode): PNode = - if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "method") + if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method") result = semProcAux(c, n, skMethod, methodPragmas) var s = result.sons[namePos].sym - if not isGenericRoutine(s): + if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty: if hasObjParam(s): - methodDef(s, false) + methodDef(s, fromCache=false) else: - LocalError(n.info, errXNeedsParamObjectType, "method") + localError(n.info, errXNeedsParamObjectType, "method") proc semConverterDef(c: PContext, n: PNode): PNode = - if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter") + if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter") checkSonsLen(n, bodyPos + 1) result = semProcAux(c, n, skConverter, converterPragmas) var s = result.sons[namePos].sym var t = s.typ - if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "converter") - if sonsLen(t) != 2: LocalError(n.info, errXRequiresOneArgument, "converter") + if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter") + if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter") addConverter(c, s) proc semMacroDef(c: PContext, n: PNode): PNode = @@ -1131,9 +1138,9 @@ proc semMacroDef(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skMacro, macroPragmas) var s = result.sons[namePos].sym var t = s.typ - if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "macro") + if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro") if n.sons[bodyPos].kind == nkEmpty: - LocalError(n.info, errImplOfXexpected, s.name.s) + localError(n.info, errImplOfXexpected, s.name.s) proc evalInclude(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) @@ -1223,7 +1230,7 @@ proc semStmtList(c: PContext, n: PNode): PNode = voidContext = true n.typ = EnforceVoidContext if i != last or voidContext: - discardCheck(n.sons[i]) + discardCheck(c, n.sons[i]) else: n.typ = n.sons[i].typ if not isEmptyType(n.typ): diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index b9893d037..92f47f585 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -876,8 +876,7 @@ proc freshType(res, prev: PType): PType {.inline.} = proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = # if n.sonsLen == 0: return newConstraint(c, tyTypeClass) result = newOrPrevType(tyTypeClass, prev, c) - result.testeeName = considerAcc(n[0]) - result.n = n[3] + result.n = n let pragmas = n[1] diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 318acc660..00f3b2b10 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -85,6 +85,7 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode, c.calleeSym = callee c.calleeScope = calleeScope initIdTable(c.bindings) + c.errors = nil if binding != nil and callee.kind in RoutineKinds: var typeParams = callee.ast[genericParamsPos] for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1): @@ -202,7 +203,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string = add(result, argTypeToString(arg)) if i != sonsLen(n) - 1: add(result, ", ") -proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation +proc typeRel*(c: var TCandidate, f, a: PType): TTypeRelation proc concreteType(c: TCandidate, t: PType): PType = case t.kind of tyArrayConstr: @@ -750,40 +751,55 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, # pushInfoContext(arg.info) openScope(c) + inc c.InTypeClass - var testee = newSym(skParam, f.testeeName, f.sym, f.sym.info) - testee.typ = a - addDecl(c, testee) + finally: + dec c.InTypeClass + closeScope(c) - for stmt in f.n: - var e = c.semTryExpr(c, copyTree(stmt)) - if e == nil: - let expStr = renderTree(stmt, {renderNoComments}) - m.errors.safeAdd("can't compile " & expStr & " for " & a.typeToString) - return nil - case e.kind - of nkReturnStmt: - nil - of nkTypeSection: nil - of nkConstDef: nil + for param in f.n[0]: + var + dummyName: PNode + dummyType: PType + + if param.kind == nkVarTy: + dummyName = param[0] + dummyType = makeVarType(c, a) else: - if e.typ.kind == tyBool: - let verdict = c.semConstExpr(c, e) - if verdict.intVal == 0: - let expStr = renderTree(stmt, {renderNoComments}) - m.errors.safeAdd(expStr & " doesn't hold for " & a.typeToString) - return nil + dummyName = param + dummyType = a + + InternalAssert dummyName.kind == nkIdent + var dummyParam = newSym(skType, dummyName.ident, f.sym, f.sym.info) + dummyParam.typ = dummyType + addDecl(c, dummyParam) - closeScope(c) + for stmt in f.n[3]: + var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false) + m.errors = bufferedMsgs + clearBufferedMsgs() + if e == nil: return nil + case e.kind + of nkReturnStmt: nil + of nkTypeSection: nil + of nkConstDef: nil + else: nil + result = arg put(m.bindings, f, a) -proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, +proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType, argSemantized, argOrig: PNode): PNode = - var arg = argSemantized - var r: TTypeRelation - let fMaybeExpr = f.skipTypes({tyDistinct}) + var + r: TTypeRelation + arg = argSemantized + + let + a = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc}) + else: argType + fMaybeExpr = f.skipTypes({tyDistinct}) + case fMaybeExpr.kind of tyExpr: if fMaybeExpr.sonsLen == 0: diff --git a/compiler/types.nim b/compiler/types.nim index f9c40e201..4dec9ea2f 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -621,7 +621,7 @@ type proc initSameTypeClosure: TSameTypeClosure = # we do the initialization lazily for performance (avoids memory allocations) nil - + proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool = result = not IsNil(c.s) and c.s.contains((a.id, b.id)) if not result: @@ -750,9 +750,9 @@ template IfFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} = proc sameObjectTypes*(a, b: PType): bool = # specialized for efficiency (sigmatch uses it) - IfFastObjectTypeCheckFailed(a, b): + IfFastObjectTypeCheckFailed(a, b): var c = initSameTypeClosure() - result = sameTypeAux(a, b, c) + result = sameTypeAux(a, b, c) proc sameDistinctTypes*(a, b: PType): bool {.inline.} = result = sameObjectTypes(a, b) @@ -808,11 +808,11 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = if containsOrIncl(c, a, b): return true proc sameFlags(a, b: PType): bool {.inline.} = - result = eqTypeFlags*a.flags == eqTypeFlags*b.flags - + result = eqTypeFlags*a.flags == eqTypeFlags*b.flags + if x == y: return true var a = skipTypes(x, {tyGenericInst}) - var b = skipTypes(y, {tyGenericInst}) + var b = skipTypes(y, {tyGenericInst}) assert(a != nil) assert(b != nil) if a.kind != b.kind: @@ -824,7 +824,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = if a.kind != b.kind: return false of dcEqOrDistinctOf: while a.kind == tyDistinct: a = a.sons[0] - if a.kind != b.kind: return false + if a.kind != b.kind: return false case a.Kind of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, tyInt..tyBigNum, tyStmt: @@ -837,15 +837,19 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = sameObjectStructures(a, b, c) and sameFlags(a, b) of tyDistinct: CycleCheck() - if c.cmp == dcEq: result = sameDistinctTypes(a, b) and sameFlags(a, b) - else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b) + if c.cmp == dcEq: + if sameFlags(a, b): + IfFastObjectTypeCheckFailed(a, b): + result = sameTypeAux(a.sons[0], b.sons[0], c) + else: + result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b) of tyEnum, tyForward, tyProxy: # XXX generic enums do not make much sense, but require structural checking result = a.id == b.id and sameFlags(a, b) of tyTuple: CycleCheck() result = sameTuple(a, b, c) and sameFlags(a, b) - of tyGenericInst: + of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c) of tyTypeDesc: if c.cmp == dcEqIgnoreDistinct: result = false @@ -858,7 +862,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter, tyOrdinal, tyTypeClass: - CycleCheck() + CycleCheck() result = sameChildrenAux(a, b, c) and sameFlags(a, b) if result and (a.kind == tyProc): result = a.callConv == b.callConv @@ -867,7 +871,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = SameTypeOrNilAux(a.sons[0], b.sons[0], c) and SameValue(a.n.sons[0], b.n.sons[0]) and SameValue(a.n.sons[1], b.n.sons[1]) - of tyNone: result = false + of tyNone: result = false proc sameType*(x, y: PType): bool = var c = initSameTypeClosure() |