diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2018-06-26 18:33:51 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-06-26 18:33:51 +0200 |
commit | 2a3a128e362929bac9c2dbf7430cbe8732840f95 (patch) | |
tree | ac794774866b8b71c5a6e271a21b42b060b57900 /compiler | |
parent | e129466910b6efa730f8d5d9232efbce6dae46f0 (diff) | |
parent | d08b9eb6731a70504be6d856723fbc94dc7bd506 (diff) | |
download | Nim-2a3a128e362929bac9c2dbf7430cbe8732840f95.tar.gz |
Merge branch 'devel' into typedesc-reforms
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ccgexprs.nim | 4 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 21 | ||||
-rw-r--r-- | compiler/commands.nim | 5 | ||||
-rw-r--r-- | compiler/docgen.nim | 8 | ||||
-rw-r--r-- | compiler/extccomp.nim | 2 | ||||
-rw-r--r-- | compiler/layouter.nim | 164 | ||||
-rw-r--r-- | compiler/lexer.nim | 14 | ||||
-rw-r--r-- | compiler/parser.nim | 28 | ||||
-rw-r--r-- | compiler/pragmas.nim | 2 | ||||
-rw-r--r-- | compiler/semexprs.nim | 4 | ||||
-rw-r--r-- | compiler/semfold.nim | 13 | ||||
-rw-r--r-- | compiler/semstmts.nim | 11 | ||||
-rw-r--r-- | compiler/sighashes.nim | 7 | ||||
-rw-r--r-- | compiler/types.nim | 2 |
14 files changed, 201 insertions, 84 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 82cc3a1fb..0e8af5af5 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -59,7 +59,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = else: result = rope("NIM_NIL") of nkStrLit..nkTripleStrLit: - case skipTypes(ty, abstractVarRange).kind + case skipTypes(ty, abstractVarRange + {tyStatic}).kind of tyNil: result = genNilStringLiteral(p.module, n.info) of tyString: @@ -385,7 +385,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = else: addrLoc(p.config, a) - var ty = skipTypes(dest.t, abstractVarRange) + var ty = skipTypes(dest.t, abstractVarRange + {tyStatic}) case ty.kind of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray: # XXX optimize this diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 71d212282..f9654bb1f 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -978,16 +978,17 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope = if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props: for x in splitLines(res): var j = 0 - while x[j] in {' ', '\t'}: inc(j) - if x[j] in {'"', ':'}: - # don't modify the line if already in quotes or - # some clobber register list: - add(result, x); add(result, "\L") - elif x[j] != '\0': - # ignore empty lines - add(result, "\"") - add(result, x) - add(result, "\\n\"\n") + while j < x.len and x[j] in {' ', '\t'}: inc(j) + if j < x.len: + if x[j] in {'"', ':'}: + # don't modify the line if already in quotes or + # some clobber register list: + add(result, x); add(result, "\L") + else: + # ignore empty lines + add(result, "\"") + add(result, x) + add(result, "\\n\"\n") else: res.add("\L") result = res.rope diff --git a/compiler/commands.nim b/compiler/commands.nim index 330504a76..866405f9f 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -606,7 +606,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; incl(conf.globalOptions, optRun) of "verbosity": expectArg(conf, switch, arg, pass, info) - conf.verbosity = parseInt(arg) + let verbosity = parseInt(arg) + if verbosity notin {0..3}: + localError(conf, info, "invalid verbosity level: '$1'" % arg) + conf.verbosity = verbosity conf.notes = NotesVerbosity[conf.verbosity] incl(conf.notes, conf.enableNotes) excl(conf.notes, conf.disableNotes) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index d463dc3c0..db4e301d4 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -582,7 +582,7 @@ proc traceDeps(d: PDoc, it: PNode) = if d.section[k] != nil: add(d.section[k], ", ") dispA(d.conf, d.section[k], "<a class=\"reference external\" href=\"$1.html\">$1</a>", - "$1", [rope(getModuleName(d.conf, it))]) + "$1", [rope(splitFile(getModuleName(d.conf, it)).name)]) proc generateDoc*(d: PDoc, n: PNode) = case n.kind @@ -780,13 +780,11 @@ proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string = proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) = var content = genOutFile(d) var success = true - var filename: string if optStdout in d.conf.globalOptions: writeRope(stdout, content) - filename = "<stdout>" else: - filename = getOutFile2(d.conf, filename, outExt, "htmldocs") - success = writeRope(content, filename) + let outfile = getOutFile2(d.conf, filename, outExt, "htmldocs") + success = writeRope(content, outfile) if not success: rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, filename) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 615b8c1e1..17133624b 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -603,7 +603,7 @@ proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) = proc addExternalFileToCompile*(conf: ConfigRef; filename: string) = var c = Cfile(cname: filename, - obj: toObjFile(conf, completeCFilePath(conf, changeFileExt(filename, ""), false)), + obj: toObjFile(conf, completeCFilePath(conf, filename, false)), flags: {CfileFlag.External}) addExternalFileToCompile(conf, c) diff --git a/compiler/layouter.nim b/compiler/layouter.nim index 90e9d6fd7..36ad08696 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -7,11 +7,7 @@ # distribution, for details about the copyright. # -## Layouter for nimpretty. Still primitive but useful. -## TODO -## - Fix 'echo ()' vs 'echo()' difference! -## - Make indentations consistent. -## - Align 'if' and 'case' expressions properly. +## Layouter for nimpretty. import idents, lexer, lineinfos, llstream, options, msgs, strutils from os import changeFileExt @@ -24,32 +20,44 @@ type SplitKind = enum splitComma, splitParLe, splitAnd, splitOr, splitIn, splitBinary + SemicolonKind = enum + detectSemicolonKind, useSemicolon, dontTouch + Emitter* = object - f: PLLStream config: ConfigRef fid: FileIndex lastTok: TTokType inquote: bool - col, lastLineNumber, lineSpan, indentLevel: int + semicolons: SemicolonKind + col, lastLineNumber, lineSpan, indentLevel, indWidth: int + nested: int + doIndentMore*: int content: string + indentStack: seq[int] fixedUntil: int # marks where we must not go in the content altSplitPos: array[SplitKind, int] # alternative split positions -proc openEmitter*(em: var Emitter, config: ConfigRef, fileIdx: FileIndex) = - let outfile = changeFileExt(config.toFullPath(fileIdx), ".pretty.nim") - em.f = llStreamOpen(outfile, fmWrite) +proc openEmitter*(em: var Emitter, cache: IdentCache; + config: ConfigRef, fileIdx: FileIndex) = + let fullPath = config.toFullPath(fileIdx) + em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead), + cache, config) + if em.indWidth == 0: em.indWidth = 2 em.config = config em.fid = fileIdx em.lastTok = tkInvalid em.inquote = false em.col = 0 em.content = newStringOfCap(16_000) - if em.f == nil: - rawMessage(config, errGenerated, "cannot open file: " & outfile) + em.indentStack = newSeqOfCap[int](30) + em.indentStack.add 0 proc closeEmitter*(em: var Emitter) = - em.f.llStreamWrite em.content - llStreamClose(em.f) + var f = llStreamOpen(em.config.outFile, fmWrite) + if f == nil: + rawMessage(em.config, errGenerated, "cannot open file: " & em.config.outFile) + f.llStreamWrite em.content + llStreamClose(f) proc countNewlines(s: string): int = result = 0 @@ -69,28 +77,41 @@ template wr(x) = template goodCol(col): bool = col in 40..MaxLineLen -const splitters = {tkComma, tkSemicolon, tkParLe, tkParDotLe, - tkBracketLe, tkBracketLeColon, tkCurlyDotLe, - tkCurlyLe} +const + openPars = {tkParLe, tkParDotLe, + tkBracketLe, tkBracketLeColon, tkCurlyDotLe, + tkCurlyLe} + splitters = openPars + {tkComma, tkSemicolon} + oprSet = {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, + tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor} template rememberSplit(kind) = if goodCol(em.col): em.altSplitPos[kind] = em.content.len +template moreIndent(em): int = + (if em.doIndentMore > 0: em.indWidth*2 else: em.indWidth) + proc softLinebreak(em: var Emitter, lit: string) = # XXX Use an algorithm that is outlined here: # https://llvm.org/devmtg/2013-04/jasper-slides.pdf # +2 because we blindly assume a comma or ' &' might follow if not em.inquote and em.col+lit.len+2 >= MaxLineLen: if em.lastTok in splitters: + while em.content.len > 0 and em.content[em.content.high] == ' ': + setLen(em.content, em.content.len-1) wr("\L") em.col = 0 - for i in 1..em.indentLevel+2: wr(" ") + for i in 1..em.indentLevel+moreIndent(em): wr(" ") else: # search backwards for a good split position: for a in em.altSplitPos: if a > em.fixedUntil: - let ws = "\L" & repeat(' ',em.indentLevel+2) + var spaces = 0 + while a+spaces < em.content.len and em.content[a+spaces] == ' ': + inc spaces + if spaces > 0: delete(em.content, a, a+spaces-1) + let ws = "\L" & repeat(' ',em.indentLevel+moreIndent(em)) em.col = em.content.len - a em.content.insert(ws, a) break @@ -98,7 +119,7 @@ proc softLinebreak(em: var Emitter, lit: string) = proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = template endsInWhite(em): bool = - em.content.len > 0 and em.content[em.content.high] in {' ', '\L'} + em.content.len == 0 or em.content[em.content.high] in {' ', '\L'} template endsInAlpha(em): bool = em.content.len > 0 and em.content[em.content.high] in SymChars+{'_'} @@ -120,14 +141,32 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = em.fixedUntil = em.content.high elif tok.indent >= 0: - em.indentLevel = tok.indent + if em.lastTok in (splitters + oprSet): + em.indentLevel = tok.indent + else: + if tok.indent > em.indentStack[^1]: + em.indentStack.add tok.indent + else: + # dedent? + while em.indentStack.len > 1 and em.indentStack[^1] > tok.indent: + discard em.indentStack.pop() + em.indentLevel = em.indentStack.high * em.indWidth + #[ we only correct the indentation if it is not in an expression context, + so that code like + + const splitters = {tkComma, tkSemicolon, tkParLe, tkParDotLe, + tkBracketLe, tkBracketLeColon, tkCurlyDotLe, + tkCurlyLe} + + is not touched. + ]# # remove trailing whitespace: while em.content.len > 0 and em.content[em.content.high] == ' ': setLen(em.content, em.content.len-1) wr("\L") for i in 2..tok.line - em.lastLineNumber: wr("\L") em.col = 0 - for i in 1..tok.indent: + for i in 1..em.indentLevel: wr(" ") em.fixedUntil = em.content.high @@ -135,49 +174,64 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = of tokKeywordLow..tokKeywordHigh: if endsInAlpha(em): wr(" ") - elif not em.inquote and not endsInWhite(em): + elif not em.inquote and not endsInWhite(em) and + em.lastTok notin openPars: + #and tok.tokType in oprSet wr(" ") - wr(TokTypeToStr[tok.tokType]) + if not em.inquote: + wr(TokTypeToStr[tok.tokType]) - case tok.tokType - of tkAnd: rememberSplit(splitAnd) - of tkOr: rememberSplit(splitOr) - of tkIn, tkNotin: - rememberSplit(splitIn) - wr(" ") - else: discard + case tok.tokType + of tkAnd: rememberSplit(splitAnd) + of tkOr: rememberSplit(splitOr) + of tkIn, tkNotin: + rememberSplit(splitIn) + wr(" ") + else: discard + else: + # keywords in backticks are not normalized: + wr(tok.ident.s) of tkColon: wr(TokTypeToStr[tok.tokType]) wr(" ") of tkSemicolon, tkComma: wr(TokTypeToStr[tok.tokType]) - wr(" ") rememberSplit(splitComma) - of tkParLe, tkParRi, tkBracketLe, - tkBracketRi, tkCurlyLe, tkCurlyRi, - tkBracketDotLe, tkBracketDotRi, - tkCurlyDotLe, tkCurlyDotRi, - tkParDotLe, tkParDotRi, - tkColonColon, tkDot, tkBracketLeColon: + wr(" ") + of tkParDotLe, tkParLe, tkBracketDotLe, tkBracketLe, + tkCurlyLe, tkCurlyDotLe, tkBracketLeColon: + if tok.strongSpaceA > 0 and not em.endsInWhite: + wr(" ") + wr(TokTypeToStr[tok.tokType]) + rememberSplit(splitParLe) + of tkParRi, + tkBracketRi, tkCurlyRi, + tkBracketDotRi, + tkCurlyDotRi, + tkParDotRi, + tkColonColon, tkDot: wr(TokTypeToStr[tok.tokType]) - if tok.tokType in splitters: - rememberSplit(splitParLe) of tkEquals: - if not em.endsInWhite: wr(" ") + if not em.inquote and not em.endsInWhite: wr(" ") wr(TokTypeToStr[tok.tokType]) - wr(" ") + if not em.inquote: wr(" ") of tkOpr, tkDotDot: - if not em.endsInWhite: wr(" ") - wr(tok.ident.s) - template isUnary(tok): bool = - tok.strongSpaceB == 0 and tok.strongSpaceA > 0 + if tok.strongSpaceA == 0 and tok.strongSpaceB == 0: + # if not surrounded by whitespace, don't produce any whitespace either: + wr(tok.ident.s) + else: + if not em.endsInWhite: wr(" ") + wr(tok.ident.s) + template isUnary(tok): bool = + tok.strongSpaceB == 0 and tok.strongSpaceA > 0 - if not isUnary(tok) or em.lastTok in {tkOpr, tkDotDot}: - wr(" ") - rememberSplit(splitBinary) + if not isUnary(tok): + wr(" ") + rememberSplit(splitBinary) of tkAccent: + if not em.inquote and endsInAlpha(em): wr(" ") wr(TokTypeToStr[tok.tokType]) em.inquote = not em.inquote of tkComment: @@ -206,3 +260,15 @@ proc starWasExportMarker*(em: var Emitter) = setLen(em.content, em.content.len-3) em.content.add("*") dec em.col, 2 + +proc commaWasSemicolon*(em: var Emitter) = + if em.semicolons == detectSemicolonKind: + em.semicolons = if em.content.endsWith(", "): dontTouch else: useSemicolon + if em.semicolons == useSemicolon and em.content.endsWith(", "): + setLen(em.content, em.content.len-2) + em.content.add("; ") + +proc curlyRiWasPragma*(em: var Emitter) = + if em.content.endsWith("}"): + setLen(em.content, em.content.len-1) + em.content.add(".}") diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 13460f7c1..c5afa6e97 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -867,7 +867,7 @@ proc getOperator(L: var TLexer, tok: var TToken) = if buf[pos] in {CR, LF, nimlexbase.EndOfFile}: tok.strongSpaceB = -1 -proc newlineFollows*(L: var TLexer): bool = +proc newlineFollows*(L: TLexer): bool = var pos = L.bufpos var buf = L.buf while true: @@ -1220,3 +1220,15 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = lexMessage(L, errGenerated, "invalid token: " & c & " (\\" & $(ord(c)) & ')') inc(L.bufpos) atTokenEnd() + +proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream; + cache: IdentCache; config: ConfigRef): int = + var lex: TLexer + var tok: TToken + initToken(tok) + openLexer(lex, fileIdx, inputstream, cache, config) + while true: + rawGetTok(lex, tok) + result = tok.indent + if result > 0 or tok.tokType == tkEof: break + closeLexer(lex) diff --git a/compiler/parser.nim b/compiler/parser.nim index 5c99363c9..c513fac68 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -108,7 +108,7 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream, initToken(p.tok) openLexer(p.lex, fileIdx, inputStream, cache, config) when defined(nimpretty2): - openEmitter(p.em, config, fileIdx) + openEmitter(p.em, cache, config, fileIdx) getTok(p) # read the first token p.firstTok = true p.strongSpaces = strongSpaces @@ -416,6 +416,8 @@ proc exprColonEqExpr(p: var TParser): PNode = proc exprList(p: var TParser, endTok: TTokType, result: PNode) = #| exprList = expr ^+ comma + when defined(nimpretty2): + inc p.em.doIndentMore getTok(p) optInd(p, result) # progress guaranteed @@ -425,6 +427,8 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) = if p.tok.tokType != tkComma: break getTok(p) optInd(p, a) + when defined(nimpretty2): + dec p.em.doIndentMore proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) @@ -856,7 +860,11 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode = result = parseOperators(p, result, limit, mode) proc simpleExpr(p: var TParser, mode = pmNormal): PNode = + when defined(nimpretty2): + inc p.em.doIndentMore result = simpleExprAux(p, -1, mode) + when defined(nimpretty2): + dec p.em.doIndentMore proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = #| condExpr = expr colcom expr optInd @@ -931,8 +939,12 @@ proc parsePragma(p: var TParser): PNode = getTok(p) skipComment(p, a) optPar(p) - if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p) - else: parMessage(p, "expected '.}'") + if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: + when defined(nimpretty2): + if p.tok.tokType == tkCurlyRi: curlyRiWasPragma(p.em) + getTok(p) + else: + parMessage(p, "expected '.}'") dec p.inPragma proc identVis(p: var TParser; allowDot=false): PNode = @@ -1019,6 +1031,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode = var a = parseIdentColonEquals(p, {}) addSon(result, a) if p.tok.tokType notin {tkComma, tkSemiColon}: break + when defined(nimpretty2): + commaWasSemicolon(p.em) getTok(p) skipComment(p, a) optPar(p) @@ -1053,6 +1067,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode = var a: PNode result = newNodeP(nkFormalParams, p) addSon(result, p.emptyNode) # return type + when defined(nimpretty2): + inc p.em.doIndentMore let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0 if hasParLe: getTok(p) @@ -1072,6 +1088,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode = break addSon(result, a) if p.tok.tokType notin {tkComma, tkSemiColon}: break + when defined(nimpretty2): + commaWasSemicolon(p.em) getTok(p) skipComment(p, a) optPar(p) @@ -1085,6 +1103,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode = elif not retColon and not hasParle: # Mark as "not there" in order to mark for deprecation in the semantic pass: result = p.emptyNode + when defined(nimpretty2): + dec p.em.doIndentMore proc optPragmas(p: var TParser): PNode = if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)): @@ -1678,6 +1698,8 @@ proc parseGenericParamList(p: var TParser): PNode = var a = parseGenericParam(p) addSon(result, a) if p.tok.tokType notin {tkComma, tkSemiColon}: break + when defined(nimpretty2): + commaWasSemicolon(p.em) getTok(p) skipComment(p, a) optPar(p) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c78a3519c..afe60e9dd 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -466,7 +466,7 @@ proc processCompile(c: PContext, n: PNode) = else: found = findFile(c.config, s) if found.len == 0: found = s - let obj = toObjFile(c.config, completeCFilePath(c.config, changeFileExt(found, ""), false)) + let obj = toObjFile(c.config, completeCFilePath(c.config, found, false)) docompile(c, it, found, obj) proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a9258fb62..5d6eaf652 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -289,7 +289,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = localError(c.config, n.info, errXExpectsTypeOrValue % opToStr[m]) else: n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType}) - var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc}) + var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc, tyUserTypeClassInst}) case typ.kind of tySequence, tyString, tyCString, tyOpenArray, tyVarargs: n.typ = getSysType(c.graph, n.info, tyInt) @@ -1351,7 +1351,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = # make sure we don't evaluate generic macros/templates n.sons[0] = semExprWithType(c, n.sons[0], {efNoEvaluateGeneric}) - var arr = skipTypes(n.sons[0].typ, {tyGenericInst, + var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyUserTypeClassInst, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink}) if arr.kind == tyStatic: if arr.base.kind == tyNone: diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 10a223ea2..2f495bc7f 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -211,7 +211,12 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g) of mNot: result = newIntNodeT(1 - getInt(a), n, g) of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g) - of mBitnotI: result = newIntNodeT(not getInt(a), n, g) + of mBitnotI: + case skipTypes(n.typ, abstractRange).kind + of tyUInt..tyUInt64: + result = newIntNodeT((not getInt(a)) and lastOrd(g.config, a.typ, fixedUnsigned=true), n, g) + else: + result = newIntNodeT(not getInt(a), n, g) of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g) of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr: if a.kind == nkNilLit: @@ -250,8 +255,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n, g) of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n, g) of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n, g) - of tyInt64, tyInt, tyUInt..tyUInt64: + of tyInt64, tyInt: result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g) + of tyUInt..tyUInt64: + result = newIntNodeT(`shl`(getInt(a), getInt(b)) and lastOrd(g.config, a.typ, fixedUnsigned=true), n, g) else: internalError(g.config, n.info, "constant folding for shl") of mShrI: case skipTypes(n.typ, abstractRange).kind @@ -612,7 +619,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode = of mLow: result = newIntNodeT(firstOrd(g.config, n.sons[1].typ), n, g) of mHigh: - if skipTypes(n.sons[1].typ, abstractVar).kind notin + if skipTypes(n.sons[1].typ, abstractVar+{tyUserTypeClassInst}).kind notin {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}: result = newIntNodeT(lastOrd(g.config, skipTypes(n[1].typ, abstractVar)), n, g) else: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 292238dc9..f1ff38b01 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -519,7 +519,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = localError(c.config, a.info, errWrongNumberOfVariables) b = newNodeI(nkVarTuple, a.info) newSons(b, length) - b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator + # keep type desc for doc generator + # NOTE: at the moment this is always ast.emptyNode, see parser.nim + b.sons[length-2] = a.sons[length-2] b.sons[length-1] = def addToVarSection(c, result, n, b) elif tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and @@ -558,7 +560,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = # keep documentation information: b.comment = a.comment addSon(b, newSymNode(v)) - addSon(b, a.sons[length-2]) # keep type desc for doc generator + # keep type desc for doc generator, but only if the user explicitly + # added it + if a.sons[length-2].kind != nkEmpty: + addSon(b, newNodeIT(nkType, a.info, typ)) + else: + addSon(b, a.sons[length-2]) addSon(b, copyTree(def)) addToVarSection(c, result, n, b) else: diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 0b95387cd..0bf2b8459 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -189,18 +189,19 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) = c.hashTypeSym(t.sym) else: c.hashSym(t.sym) - if sfAnon in t.sym.flags: + if {sfAnon, sfGenSym} * t.sym.flags != {}: # generated object names can be identical, so we need to # disambiguate furthermore by hashing the field types and names: # mild hack to prevent endless recursions (makes nimforum compile again): - excl t.sym.flags, sfAnon + let oldFlags = t.sym.flags + t.sym.flags = t.sym.flags - {sfAnon, sfGenSym} let n = t.n for i in 0 ..< n.len: assert n[i].kind == nkSym let s = n[i].sym c.hashSym s c.hashType s.typ, flags - incl t.sym.flags, sfAnon + t.sym.flags = oldFlags else: c &= t.id if t.len > 0 and t.sons[0] != nil: diff --git a/compiler/types.nim b/compiler/types.nim index 7f4f86fae..f78e975ee 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -618,7 +618,7 @@ proc firstOrd*(conf: ConfigRef; t: PType): BiggestInt = else: assert(t.n.sons[0].kind == nkSym) result = t.n.sons[0].sym.position - of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred: + of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred, tyUserTypeClassInst: result = firstOrd(conf, lastSon(t)) of tyOrdinal: if t.len > 0: result = firstOrd(conf, lastSon(t)) |