diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/extccomp.nim | 2 | ||||
-rw-r--r-- | compiler/msgs.nim | 55 | ||||
-rw-r--r-- | compiler/parser.nim | 15 | ||||
-rw-r--r-- | compiler/sem.nim | 3 | ||||
-rw-r--r-- | compiler/semdata.nim | 4 | ||||
-rw-r--r-- | compiler/semexprs.nim | 30 | ||||
-rw-r--r-- | compiler/semstmts.nim | 39 | ||||
-rw-r--r-- | compiler/semtypes.nim | 3 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 68 |
10 files changed, 142 insertions, 79 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 2a7d8a551..5a5d87d06 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -712,7 +712,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 @@ -1088,7 +1087,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/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/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/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 71951dd3f..ea53afbeb 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 diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 121bf297d..d02359d4c 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 47e07d402..337224aef 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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} @@ -763,7 +772,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 +824,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 @@ -1208,7 +1218,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 +1439,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 +1453,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 +1477,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 diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index ed6787a16..da8ba50a8 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: @@ -879,8 +883,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) @@ -1104,24 +1109,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 = @@ -1129,9 +1134,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) @@ -1221,7 +1226,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: |