diff options
author | Araq <rumpf_a@web.de> | 2017-03-14 15:56:08 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2017-03-14 15:56:08 +0100 |
commit | b1c494a1504921a21f5578782db72f274efadd95 (patch) | |
tree | b26c5e92edbc87e8f38cb8994e6e01f897d77494 /compiler | |
parent | 142b604c1353926208220aa7ce0b7724a72958c3 (diff) | |
parent | 0510c0cecefb50dedd691de82151bc629b35d816 (diff) | |
download | Nim-b1c494a1504921a21f5578782db72f274efadd95.tar.gz |
Merge branch 'devel' of github.com:nim-lang/Nim into devel
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/astalgo.nim | 17 | ||||
-rw-r--r-- | compiler/evaltempl.nim | 5 | ||||
-rw-r--r-- | compiler/lexer.nim | 122 | ||||
-rw-r--r-- | compiler/msgs.nim | 13 | ||||
-rw-r--r-- | compiler/options.nim | 22 | ||||
-rw-r--r-- | compiler/parser.nim | 5 | ||||
-rw-r--r-- | compiler/sem.nim | 11 | ||||
-rw-r--r-- | compiler/semcall.nim | 1 | ||||
-rw-r--r-- | compiler/semexprs.nim | 21 | ||||
-rw-r--r-- | compiler/semstmts.nim | 14 | ||||
-rw-r--r-- | compiler/semtypes.nim | 5 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 5 | ||||
-rw-r--r-- | compiler/suggest.nim | 194 | ||||
-rw-r--r-- | compiler/transf.nim | 5 | ||||
-rw-r--r-- | compiler/types.nim | 5 |
16 files changed, 291 insertions, 156 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index d6fc5920e..26305cf3b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -460,6 +460,8 @@ type # proc foo(T: typedesc, list: seq[T]): var T # proc foo(L: static[int]): array[L, int] # can be attached to ranges to indicate that the range + # can be attached to generic procs with free standing + # type parameters: e.g. proc foo[T]() # depends on unresolved static params. tfRetType, # marks return types in proc (used to detect type classes # used as return types for return type inference) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 226d5ee42..161e4d637 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -67,6 +67,23 @@ proc debug*(n: PSym) {.deprecated.} proc debug*(n: PType) {.deprecated.} proc debug*(n: PNode) {.deprecated.} +template mdbg*: bool {.dirty.} = + when compiles(c.module): + c.module.fileIdx == gProjectMainIdx + elif compiles(m.c.module): + m.c.module.fileIdx == gProjectMainIdx + elif compiles(cl.c.module): + cl.c.module.fileIdx == gProjectMainIdx + elif compiles(p): + when compiles(p.lex): + p.lex.fileIdx == gProjectMainIdx + else: + p.module.module.fileIdx == gProjectMainIdx + elif compiles(L.fileIdx): + L.fileIdx == gProjectMainIdx + else: + false + # --------------------------- ident tables ---------------------------------- proc idTableGet*(t: TIdTable, key: PIdObj): RootRef proc idTableGet*(t: TIdTable, key: int): RootRef diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 318254a80..5bd274a3e 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -80,9 +80,14 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = expectedRegularParams = <s.typ.len givenRegularParams = totalParams - genericParams if givenRegularParams < 0: givenRegularParams = 0 + if totalParams > expectedRegularParams + genericParams: globalError(n.info, errWrongNumberOfArguments) + if totalParams < genericParams: + globalError(n.info, errMissingGenericParamsForTemplate, + n.renderTree) + result = newNodeI(nkArgList, n.info) for i in 1 .. givenRegularParams: result.addSon n.sons[i] diff --git a/compiler/lexer.nim b/compiler/lexer.nim index c082a5cb3..2bb228f41 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -67,6 +67,10 @@ type TTokTypes* = set[TTokType] const + weakTokens = {tkComma, tkSemiColon, tkColon, + tkParRi, tkParDotRi, tkBracketRi, tkBracketDotRi, + tkCurlyRi} # \ + # tokens that should not be considered for previousToken tokKeywordLow* = succ(tkSymbol) tokKeywordHigh* = pred(tkIntLit) TokTypeToStr*: array[TTokType, string] = ["tkInvalid", "[EOF]", @@ -105,6 +109,9 @@ type # so that it is the correct default value base2, base8, base16 + CursorPosition* {.pure.} = enum ## XXX remove this again + None, InToken, BeforeToken, AfterToken + TToken* = object # a Nim token tokType*: TTokType # the type of the token indent*: int # the indentation; != -1 if the token has been @@ -128,8 +135,11 @@ type # needs so much look-ahead currLineIndent*: int strongSpaces*, allowTabs*: bool + cursor*: CursorPosition errorHandler*: TErrorHandler cache*: IdentCache + when defined(nimsuggest): + previousToken: TLineInfo var gLinesCompiled*: int # all lines that have been compiled @@ -203,6 +213,8 @@ proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream; lex.currLineIndent = 0 inc(lex.lineNumber, inputstream.lineOffset) lex.cache = cache + when defined(nimsuggest): + lex.previousToken.fileIndex = fileIdx proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream; cache: IdentCache) = @@ -235,6 +247,41 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool = result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second) +template tokenBegin(pos) {.dirty.} = + when defined(nimsuggest): + var colA = getColNumber(L, pos) + +template tokenEnd(pos) {.dirty.} = + when defined(nimsuggest): + let colB = getColNumber(L, pos)+1 + if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and + L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}: + L.cursor = CursorPosition.InToken + gTrackPos.col = colA.int16 + colA = 0 + +template tokenEndIgnore(pos) = + when defined(nimsuggest): + let colB = getColNumber(L, pos) + if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and + L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}: + gTrackPos.fileIndex = trackPosInvalidFileIdx + gTrackPos.line = -1 + colA = 0 + +template tokenEndPrevious(pos) = + when defined(nimsuggest): + # when we detect the cursor in whitespace, we attach the track position + # to the token that came before that, but only if we haven't detected + # the cursor in a string literal or comment: + let colB = getColNumber(L, pos) + if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and + L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}: + L.cursor = CursorPosition.BeforeToken + gTrackPos = L.previousToken + gTrackPosAttached = true + colA = 0 + {.push overflowChecks: off.} # We need to parse the largest uint literal without overflow checks proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int = @@ -318,6 +365,7 @@ proc getNumber(L: var TLexer, result: var TToken) = result.literal = "" result.base = base10 startpos = L.bufpos + tokenBegin(startPos) # First stage: find out base, make verifications, build token literal string if L.buf[L.bufpos] == '0' and L.buf[L.bufpos + 1] in baseCodeChars + {'O'}: @@ -526,6 +574,7 @@ proc getNumber(L: var TLexer, result: var TToken) = lexMessageLitNum(L, errInvalidNumber, startpos) except OverflowError, RangeError: lexMessageLitNum(L, errNumberOutOfRange, startpos) + tokenEnd(postPos-1) L.bufpos = postPos proc handleHexChar(L: var TLexer, xi: var int) = @@ -642,21 +691,11 @@ proc handleCRLF(L: var TLexer, pos: int): int = result = nimlexbase.handleLF(L, pos) else: result = pos -template tokenRange(colA, pos) = - when defined(nimsuggest): - let colB = getColNumber(L, pos) - if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and - L.lineNumber == gTrackPos.line and gIdeCmd == ideSug: - gTrackPos.fileIndex = trackPosInvalidFileIdx - gTrackPos.line = -1 - colA = 0 - proc getString(L: var TLexer, tok: var TToken, rawMode: bool) = var pos = L.bufpos + 1 # skip " var buf = L.buf # put `buf` in a register var line = L.lineNumber # save linenumber for better error message - when defined(nimsuggest): - var colA = getColNumber(L, pos) + tokenBegin(pos) if buf[pos] == '\"' and buf[pos+1] == '\"': tok.tokType = tkTripleStrLit # long string literal: inc(pos, 2) # skip "" @@ -672,18 +711,18 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) = of '\"': if buf[pos+1] == '\"' and buf[pos+2] == '\"' and buf[pos+3] != '\"': - tokenRange(colA, pos+2) + tokenEndIgnore(pos+2) L.bufpos = pos + 3 # skip the three """ break add(tok.literal, '\"') inc(pos) of CR, LF: - tokenRange(colA, pos) + tokenEndIgnore(pos) pos = handleCRLF(L, pos) buf = L.buf add(tok.literal, tnl) of nimlexbase.EndOfFile: - tokenRange(colA, pos) + tokenEndIgnore(pos) var line2 = L.lineNumber L.lineNumber = line lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart) @@ -704,11 +743,11 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) = inc(pos, 2) add(tok.literal, '"') else: - tokenRange(colA, pos) + tokenEndIgnore(pos) inc(pos) # skip '"' break elif c in {CR, LF, nimlexbase.EndOfFile}: - tokenRange(colA, pos) + tokenEndIgnore(pos) lexMessage(L, errClosingQuoteExpected) break elif (c == '\\') and not rawMode: @@ -721,6 +760,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) = L.bufpos = pos proc getCharacter(L: var TLexer, tok: var TToken) = + tokenBegin(L.bufpos) inc(L.bufpos) # skip ' var c = L.buf[L.bufpos] case c @@ -730,12 +770,14 @@ proc getCharacter(L: var TLexer, tok: var TToken) = tok.literal = $c inc(L.bufpos) if L.buf[L.bufpos] != '\'': lexMessage(L, errMissingFinalQuote) + tokenEndIgnore(L.bufpos) inc(L.bufpos) # skip ' proc getSymbol(L: var TLexer, tok: var TToken) = var h: Hash = 0 var pos = L.bufpos var buf = L.buf + tokenBegin(pos) while true: var c = buf[pos] case c @@ -762,6 +804,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) = inc(pos) else: break + tokenEnd(pos-1) h = !$h tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) L.bufpos = pos @@ -782,6 +825,7 @@ proc endOperator(L: var TLexer, tok: var TToken, pos: int, proc getOperator(L: var TLexer, tok: var TToken) = var pos = L.bufpos var buf = L.buf + tokenBegin(pos) var h: Hash = 0 while true: var c = buf[pos] @@ -789,6 +833,7 @@ proc getOperator(L: var TLexer, tok: var TToken) = h = h !& ord(c) inc(pos) endOperator(L, tok, pos, h) + tokenEnd(pos-1) # advance pos but don't store it in L.bufpos so the next token (which might # be an operator too) gets the preceding spaces: tok.strongSpaceB = 0 @@ -803,8 +848,7 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int; var pos = start var buf = L.buf var toStrip = 0 - when defined(nimsuggest): - var colA = getColNumber(L, pos) + tokenBegin(pos) # detect the amount of indentation: if isDoc: toStrip = getColNumber(L, pos) @@ -831,20 +875,20 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int; if isDoc: if buf[pos+1] == '#' and buf[pos+2] == '#': if nesting == 0: - tokenRange(colA, pos+2) + tokenEndIgnore(pos+2) inc(pos, 3) break dec nesting tok.literal.add ']' elif buf[pos+1] == '#': if nesting == 0: - tokenRange(colA, pos+1) + tokenEndIgnore(pos+1) inc(pos, 2) break dec nesting inc pos of CR, LF: - tokenRange(colA, pos) + tokenEndIgnore(pos) pos = handleCRLF(L, pos) buf = L.buf # strip leading whitespace: @@ -856,7 +900,7 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int; inc pos dec c of nimlexbase.EndOfFile: - tokenRange(colA, pos) + tokenEndIgnore(pos) lexMessagePos(L, errGenerated, pos, "end of multiline comment expected") break else: @@ -867,8 +911,6 @@ proc skipMultiLineComment(L: var TLexer; tok: var TToken; start: int; proc scanComment(L: var TLexer, tok: var TToken) = var pos = L.bufpos var buf = L.buf - when defined(nimsuggest): - var colA = getColNumber(L, pos) tok.tokType = tkComment # iNumber contains the number of '\n' in the token tok.iNumber = 0 @@ -876,6 +918,7 @@ proc scanComment(L: var TLexer, tok: var TToken) = if buf[pos+2] == '[': skipMultiLineComment(L, tok, pos+3, true) return + tokenBegin(pos) inc(pos, 2) var toStrip = 0 @@ -889,7 +932,7 @@ proc scanComment(L: var TLexer, tok: var TToken) = if buf[pos] == '\\': lastBackslash = pos+1 add(tok.literal, buf[pos]) inc(pos) - tokenRange(colA, pos) + tokenEndIgnore(pos) pos = handleCRLF(L, pos) buf = L.buf var indent = 0 @@ -908,13 +951,14 @@ proc scanComment(L: var TLexer, tok: var TToken) = else: if buf[pos] > ' ': L.indentAhead = indent - tokenRange(colA, pos) + tokenEndIgnore(pos) break L.bufpos = pos proc skip(L: var TLexer, tok: var TToken) = var pos = L.bufpos var buf = L.buf + tokenBegin(pos) tok.strongSpaceA = 0 while true: case buf[pos] @@ -925,6 +969,7 @@ proc skip(L: var TLexer, tok: var TToken) = if not L.allowTabs: lexMessagePos(L, errTabulatorsAreNotAllowed, pos) inc(pos) of CR, LF: + tokenEndPrevious(pos) pos = handleCRLF(L, pos) buf = L.buf var indent = 0 @@ -951,15 +996,24 @@ proc skip(L: var TLexer, tok: var TToken) = pos = L.bufpos buf = L.buf else: - when defined(nimsuggest): - var colA = getColNumber(L, pos) + tokenBegin(pos) while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos) - tokenRange(colA, pos) + tokenEndIgnore(pos+1) else: break # EndOfFile also leaves the loop + tokenEndPrevious(pos-1) L.bufpos = pos proc rawGetTok*(L: var TLexer, tok: var TToken) = + template atTokenEnd() {.dirty.} = + when defined(nimsuggest): + # we attach the cursor to the last *strong* token + if tok.tokType notin weakTokens: + L.previousToken.line = tok.line.int16 + L.previousToken.col = tok.col.int16 + + when defined(nimsuggest): + L.cursor = CursorPosition.None fillToken(tok) if L.indentAhead >= 0: tok.indent = L.indentAhead @@ -1007,6 +1061,10 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = inc(L.bufpos) else: tok.tokType = tkParLe + when defined(nimsuggest): + if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and + tok.line == gTrackPos.line and gIdeCmd == ideCon: + gTrackPos.col = tok.col.int16 of ')': tok.tokType = tkParRi inc(L.bufpos) @@ -1022,10 +1080,13 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = inc(L.bufpos) of '.': when defined(nimsuggest): - if L.fileIdx == gTrackPos.fileIndex and tok.col == gTrackPos.col and + if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and tok.line == gTrackPos.line and gIdeCmd == ideSug: tok.tokType = tkDot + L.cursor = CursorPosition.InToken + gTrackPos.col = tok.col.int16 inc(L.bufpos) + atTokenEnd() return if L.buf[L.bufpos+1] == ']': tok.tokType = tkBracketDotRi @@ -1092,3 +1153,4 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = tok.tokType = tkInvalid lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')') inc(L.bufpos) + atTokenEnd() diff --git a/compiler/msgs.nim b/compiler/msgs.nim index e50ed0f2a..2db3646b5 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -64,6 +64,8 @@ type errVarForOutParamNeeded, errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX, errAmbiguousCallXYZ, errWrongNumberOfArguments, + errWrongNumberOfArgumentsInCall, + errMissingGenericParamsForTemplate, errXCannotBePassedToProcVar, errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed, errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, @@ -89,6 +91,7 @@ type errMainModuleMustBeSpecified, errXExpected, errTIsNotAConcreteType, + errCastToANonConcreteType, errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly, @@ -107,6 +110,7 @@ type errCannotInferTypeOfTheLiteral, errCannotInferReturnType, errGenericLambdaNotAllowed, + errProcHasNoConcreteType, errCompilerDoesntSupportTarget, errUser, warnCannotOpenFile, @@ -269,6 +273,8 @@ const errButExpectedX: "but expected \'$1\'", errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3", errWrongNumberOfArguments: "wrong number of arguments", + errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'", + errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar", errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration", errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", @@ -326,6 +332,7 @@ const errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file", errXExpected: "\'$1\' expected", errTIsNotAConcreteType: "\'$1\' is not a concrete type.", + errCastToANonConcreteType: "cannot cast to a non concrete type: \'$1\'", errInvalidSectionStart: "invalid section start", errGridTableNotImplemented: "grid table is not implemented", errGeneralParseError: "general parse error", @@ -369,6 +376,7 @@ const errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " & "it is used as an operand to another routine and the types " & "of the generic paramers can be inferred from the expected signature.", + errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.", errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target", errUser: "$1", warnCannotOpenFile: "cannot open \'$1\'", @@ -739,6 +747,8 @@ proc `??`* (info: TLineInfo, filename: string): bool = const trackPosInvalidFileIdx* = -2 # special marker so that no suggestions # are produced within comments and string literals var gTrackPos*: TLineInfo +var gTrackPosAttached*: bool ## whether the tracking position was attached to some + ## close token. type MsgFlag* = enum ## flags altering msgWriteln behavior @@ -863,6 +873,9 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = proc `==`*(a, b: TLineInfo): bool = result = a.line == b.line and a.fileIndex == b.fileIndex +proc exactEquals*(a, b: TLineInfo): bool = + result = a.fileIndex == b.fileIndex and a.line == b.line and a.col == b.col + proc writeContext(lastinfo: TLineInfo) = var info = lastinfo for i in countup(0, len(msgContext) - 1): diff --git a/compiler/options.nim b/compiler/options.nim index c6d016095..6372cddac 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -392,6 +392,23 @@ proc findModule*(modulename, currentModule: string): string = result = findFile(m) patchModule() +proc findProjectNimFile*(pkg: string): string = + const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"] + var candidates: seq[string] = @[] + for k, f in os.walkDir(pkg, relative=true): + if k == pcFile and f != "config.nims": + let (_, name, ext) = splitFile(f) + if ext in extensions: + let x = changeFileExt(pkg / name, ".nim") + if fileExists(x): + candidates.add x + for c in candidates: + # nim-foo foo or foo nfoo + if (pkg in c) or (c in pkg): return c + if candidates.len >= 1: + return candidates[0] + return "" + proc canonDynlibName(s: string): string = let start = if s.startsWith("lib"): 3 else: 0 let ende = strutils.find(s, {'(', ')', '.'}) @@ -420,11 +437,6 @@ proc binaryStrSearch*(x: openArray[string], y: string): int = return mid result = - 1 -template nimdbg*: untyped = c.module.fileIdx == gProjectMainIdx -template cnimdbg*: untyped = p.module.module.fileIdx == gProjectMainIdx -template pnimdbg*: untyped = p.lex.fileIdx == gProjectMainIdx -template lnimdbg*: untyped = L.fileIdx == gProjectMainIdx - proc parseIdeCmd*(s: string): IdeCmd = case s: of "sug": ideSug diff --git a/compiler/parser.nim b/compiler/parser.nim index d34a6d88a..362a5c286 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1846,6 +1846,7 @@ proc parseTypeDef(p: var TParser): PNode = else: addSon(result, ast.emptyNode) if p.tok.tokType == tkEquals: + result.info = parLineInfo(p) getTok(p) optInd(p, result) addSon(result, parseTypeDefAux(p)) @@ -2002,12 +2003,12 @@ proc parseStmt(p: var TParser): PNode = break p.hasProgress = false var a = complexOrSimpleStmt(p) - if not p.hasProgress and p.tok.tokType == tkEof: break - if a.kind != nkEmpty and p.hasProgress: + if a.kind != nkEmpty: addSon(result, a) else: parMessage(p, errExprExpected, p.tok) getTok(p) + if not p.hasProgress and p.tok.tokType == tkEof: break else: # the case statement is only needed for better error messages: case p.tok.tokType diff --git a/compiler/sem.nim b/compiler/sem.nim index 21a5c435a..6ad77e3fb 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -167,6 +167,8 @@ proc commonType*(x, y: PType): PType = proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) + when defined(nimsuggest): + suggestDecl(c, n, result) proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii @@ -191,6 +193,8 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: # incl(result.flags, sfGlobal) + when defined(nimsuggest): + suggestDecl(c, n, result) proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym @@ -381,6 +385,13 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, if sym == c.p.owner: globalError(n.info, errRecursiveDependencyX, sym.name.s) + let genericParams = if sfImmediate in sym.flags: 0 + else: sym.ast[genericParamsPos].len + let suppliedParams = max(n.safeLen - 1, 0) + + if suppliedParams < genericParams: + globalError(n.info, errMissingGenericParamsForTemplate, n.renderTree) + #if c.evalContext == nil: # c.evalContext = c.createEvalContext(emStatic) result = evalMacroCall(c.module, c.cache, n, nOrig, sym) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 98667b085..3a43c63b2 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -411,6 +411,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = let tm = typeRel(m, formal, arg, true) if tm in {isNone, isConvertible}: return nil var newInst = generateInstance(c, s, m.bindings, n.info) + newInst.typ.flags.excl tfUnresolved markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(newInst, n.info) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a419cd000..8f1362691 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -30,6 +30,8 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # result = errorNode(c, n) if result.typ != nil: # XXX tyGenericInst here? + if result.typ.kind == tyProc and tfUnresolved in result.typ.flags: + localError(n.info, errProcHasNoConcreteType, n.renderTree) if result.typ.kind == tyVar: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: result.typ = newTypeS(tyVoid, c) @@ -218,13 +220,16 @@ proc semConv(c: PContext, n: PNode): PNode = proc semCast(c: PContext, n: PNode): PNode = ## Semantically analyze a casting ("cast[type](param)") checkSonsLen(n, 2) + let targetType = semTypeNode(c, n.sons[0], nil) + let castedExpr = semExprWithType(c, n.sons[1]) + if tfHasMeta in targetType.flags: + localError(n.sons[0].info, errCastToANonConcreteType, $targetType) + if not isCastable(targetType, castedExpr.typ): + localError(n.info, errExprCannotBeCastToX, $targetType) result = newNodeI(nkCast, n.info) - result.typ = semTypeNode(c, n.sons[0], nil) + result.typ = targetType addSon(result, copyTree(n.sons[0])) - addSon(result, semExprWithType(c, n.sons[1])) - if not isCastable(result.typ, result.sons[1].typ): - localError(result.info, errExprCannotBeCastToX, - typeToString(result.typ)) + addSon(result, castedExpr) proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = const @@ -1054,7 +1059,9 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # here at all! #if isSymChoice(n.sons[1]): return when defined(nimsuggest): - if gCmd == cmdIdeTools: suggestExpr(c, n) + if gCmd == cmdIdeTools: + suggestExpr(c, n) + if exactEquals(gTrackPos, n[1].info): suggestExprNoCheck(c, n) var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule}) if s != nil: @@ -2234,6 +2241,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1) + #when defined(nimsuggest): + # if gIdeCmd == ideCon and gTrackPos == n.info: suggestExprNoCheck(c, n) let mode = if nfDotField in n.flags: {} else: {checkUndeclared} var s = qualifiedLookUp(c, n.sons[0], mode) if s != nil: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 7c6e3af6d..9a1850932 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -205,7 +205,8 @@ proc semCase(c: PContext, n: PNode): PNode = var typ = commonTypeBegin var hasElse = false var notOrdinal = false - case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind + let caseTyp = skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}) + case caseTyp.kind of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool: chckCovered = true of tyFloat..tyFloat128, tyString, tyError: @@ -215,6 +216,9 @@ proc semCase(c: PContext, n: PNode): PNode = return for i in countup(1, sonsLen(n) - 1): var x = n.sons[i] + when defined(nimsuggest): + if gIdeCmd == ideSug and exactEquals(gTrackPos, x.info) and caseTyp.kind == tyEnum: + suggestEnum(c, x, caseTyp) case x.kind of nkOfBranch: checkMinSonsLen(x, 2) @@ -499,6 +503,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if hasEmpty(typ): localError(def.info, errCannotInferTypeOfTheLiteral, ($typ.kind).substr(2).toLowerAscii) + elif typ.kind == tyProc and tfUnresolved in typ.flags: + localError(def.info, errProcHasNoConcreteType, def.renderTree) else: if symkind == skLet: localError(a.info, errLetNeedsInit) @@ -711,7 +717,11 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = # we even look at the type definitions on the right for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if gCmd == cmdIdeTools: suggestStmt(c, a) + when defined(nimsuggest): + if gCmd == cmdIdeTools: + inc c.inTypeContext + suggestStmt(c, a) + dec c.inTypeContext if a.kind == nkCommentStmt: continue if a.kind != nkTypeDef: illFormedAst(a) checkSonsLen(a, 3) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 83d0c83b2..7877a26a9 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1009,8 +1009,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, result.sons[0] = r result.n.typ = r - if genericParams != nil: + if genericParams != nil and genericParams.len > 0: for n in genericParams: + if {sfUsed, sfAnon} * n.sym.flags == {}: + result.flags.incl tfUnresolved + if tfWildcard in n.sym.typ.flags: n.sym.kind = skType n.sym.typ.flags.excl tfWildcard diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index f2caab41f..bc9888df9 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1514,6 +1514,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, if arg.sons[i].sym.kind in {skProc, skMethod, skConverter, skIterator}: copyCandidate(z, m) z.callee = arg.sons[i].typ + if tfUnresolved in z.callee.flags: continue z.calleeSym = arg.sons[i].sym #if arg.sons[i].sym.name.s == "cmp": # ggDebug = true @@ -1650,7 +1651,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped: incl(marker, formal.position) if container.isNil: - container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info)) + container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info)) setSon(m.call, formal.position + 1, container) else: incrIndexType(container.typ) @@ -1738,7 +1739,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, if formal.typ.isVarargsUntyped: if container.isNil: - container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info)) + container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info)) setSon(m.call, formal.position + 1, container) else: incrIndexType(container.typ) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index ebabed465..f9210cc93 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -63,6 +63,7 @@ type var suggestionResultHook*: proc (result: Suggest) {.closure.} suggestVersion*: int + suggestMaxResults* = 10_000 #template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n" @@ -71,7 +72,7 @@ template origModuleName(m: PSym): string = m.name.s proc findDocComment(n: PNode): PNode = if n == nil: return nil if not isNil(n.comment): return n - if n.kind in {nkStmtList, nkStmtListExpr} and n.len > 0: + if n.kind in {nkStmtList, nkStmtListExpr, nkObjectTy, nkRecList} and n.len > 0: result = findDocComment(n.sons[0]) if result != nil: return if n.len > 1: @@ -104,11 +105,11 @@ proc cmpSuggestions(a, b: Suggest): int = # independent of hashing order: result = cmp(a.name.s, b.name.s) -proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo; +proc symToSuggest(s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo; quality: range[0..100]; prefix: PrefixMatch; inTypeContext: bool; scope: int): Suggest = new(result) - result.section = parseIdeCmd(section) + result.section = section result.quality = quality result.isGlobal = sfGlobal in s.flags result.tokenLen = s.name.s.len @@ -120,15 +121,10 @@ proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo; result.globalUsages = s.allUsages.len var c = 0 for u in s.allUsages: - if u.fileIndex == li.fileIndex: inc c + if u.fileIndex == info.fileIndex: inc c result.localUsages = c - if optIdeTerse in gGlobalOptions: - result.symkind = s.kind - result.filePath = toFullPath(li) - result.line = toLinenumber(li) - result.column = toColumn(li) - else: - result.symkind = s.kind + result.symkind = s.kind + if optIdeTerse notin gGlobalOptions: result.qualifiedPath = @[] if not isLocal and s.kind != skModule: let ow = s.owner @@ -143,11 +139,12 @@ proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo; result.forth = typeToString(s.typ) else: result.forth = "" - result.filePath = toFullPath(li) - result.line = toLinenumber(li) - result.column = toColumn(li) when not defined(noDocgen): result.doc = s.extractDocComment + let infox = if section in {ideUse, ideHighlight, ideOutline}: info else: s.info + result.filePath = toFullPath(infox) + result.line = toLinenumber(infox) + result.column = toColumn(infox) proc `$`*(suggest: Suggest): string = result = $suggest.section @@ -181,18 +178,13 @@ proc `$`*(suggest: Suggest): string = result.add(sep) when not defined(noDocgen): result.add(suggest.doc.escape) - if suggestVersion == 2: + if suggestVersion == 0: result.add(sep) result.add($suggest.quality) if suggest.section == ideSug: result.add(sep) result.add($suggest.prefix) -proc symToSuggest(s: PSym, isLocal: bool, section: string; - quality: range[0..100], prefix: PrefixMatch; inTypeContext: bool; - scope: int): Suggest = - result = symToSuggest(s, isLocal, section, s.info, quality, prefix, inTypeContext, scope) - proc suggestResult(s: Suggest) = if not isNil(suggestionResultHook): suggestionResultHook(s) @@ -202,6 +194,10 @@ proc suggestResult(s: Suggest) = proc produceOutput(a: var Suggestions) = if gIdeCmd in {ideSug, ideCon}: a.sort cmpSuggestions + when defined(debug): + # debug code + writeStackTrace() + if a.len > suggestMaxResults: a.setLen(suggestMaxResults) if not isNil(suggestionResultHook): for s in a: suggestionResultHook(s) @@ -237,10 +233,10 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = result = true break -proc suggestField(c: PContext, s: PSym; f: PNode; outputs: var Suggestions) = +proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var Suggestions) = var pm: PrefixMatch if filterSym(s, f, pm) and fieldVisible(c, s): - outputs.add(symToSuggest(s, isLocal=true, $ideSug, 100, pm, c.inTypeContext > 0, 0)) + outputs.add(symToSuggest(s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0)) proc getQuality(s: PSym): range[0..100] = if s.typ != nil and s.typ.len > 1: @@ -259,25 +255,25 @@ template wholeSymTab(cond, section: untyped) = let it {.inject.} = item var pm {.inject.}: PrefixMatch if cond: - outputs.add(symToSuggest(it, isLocal = isLocal, section, getQuality(it), + outputs.add(symToSuggest(it, isLocal = isLocal, section, info, getQuality(it), pm, c.inTypeContext > 0, scopeN)) -proc suggestSymList(c: PContext, list, f: PNode, outputs: var Suggestions) = +proc suggestSymList(c: PContext, list, f: PNode; info: TLineInfo, outputs: var Suggestions) = for i in countup(0, sonsLen(list) - 1): if list.sons[i].kind == nkSym: - suggestField(c, list.sons[i].sym, f, outputs) + suggestField(c, list.sons[i].sym, f, info, outputs) #else: InternalError(list.info, "getSymFromList") -proc suggestObject(c: PContext, n, f: PNode, outputs: var Suggestions) = +proc suggestObject(c: PContext, n, f: PNode; info: TLineInfo, outputs: var Suggestions) = case n.kind of nkRecList: - for i in countup(0, sonsLen(n)-1): suggestObject(c, n.sons[i], f, outputs) + for i in countup(0, sonsLen(n)-1): suggestObject(c, n.sons[i], f, info, outputs) of nkRecCase: var L = sonsLen(n) if L > 0: - suggestObject(c, n.sons[0], f, outputs) - for i in countup(1, L-1): suggestObject(c, lastSon(n.sons[i]), f, outputs) - of nkSym: suggestField(c, n.sym, f, outputs) + suggestObject(c, n.sons[0], f, info, outputs) + for i in countup(1, L-1): suggestObject(c, lastSon(n.sons[i]), f, info, outputs) + of nkSym: suggestField(c, n.sym, f, info, outputs) else: discard proc nameFits(c: PContext, s: PSym, n: PNode): bool = @@ -301,8 +297,9 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool = result = false proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var Suggestions) = + let info = n.info wholeSymTab(filterSym(it, nil, pm) and nameFits(c, it, n) and argsFit(c, it, n, nOrig), - $ideCon) + ideCon) proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = if s.typ != nil and sonsLen(s.typ) > 1 and s.typ.sons[1] != nil: @@ -319,7 +316,8 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = proc suggestOperations(c: PContext, n, f: PNode, typ: PType, outputs: var Suggestions) = assert typ != nil - wholeSymTab(filterSymNoOpr(it, f, pm) and typeFits(c, it, typ), $ideSug) + let info = n.info + wholeSymTab(filterSymNoOpr(it, f, pm) and typeFits(c, it, typ), ideSug) proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) = # do not produce too many symbols: @@ -331,8 +329,9 @@ proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) = for it in items(scope.symbols): var pm: PrefixMatch if filterSym(it, f, pm): - outputs.add(symToSuggest(it, isLocal = isLocal, $ideSug, 0, pm, c.inTypeContext > 0, scopeN)) - if scope == c.topLevelScope and f.isNil: break + outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, n.info, 0, pm, + c.inTypeContext > 0, scopeN)) + #if scope == c.topLevelScope and f.isNil: break proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) = # special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but @@ -340,7 +339,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) var typ = n.typ var pm: PrefixMatch when defined(nimsuggest): - if n.kind == nkSym and n.sym.kind == skError and suggestVersion == 2: + if n.kind == nkSym and n.sym.kind == skError and suggestVersion == 0: # consider 'foo.|' where 'foo' is some not imported module. let fullPath = findModule(n.sym.name.s, n.info.toFullPath) if fullPath.len == 0: @@ -352,8 +351,8 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) else: for it in items(n.sym.tab): if filterSym(it, field, pm): - outputs.add(symToSuggest(it, isLocal=false, $ideSug, 100, pm, c.inTypeContext > 0, -100)) - outputs.add(symToSuggest(m, isLocal=false, $ideMod, 100, PrefixMatch.None, + outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100)) + outputs.add(symToSuggest(m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None, c.inTypeContext > 0, -99)) if typ == nil: @@ -363,11 +362,11 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) # all symbols accessible, because we are in the current module: for it in items(c.topLevelScope.symbols): if filterSym(it, field, pm): - outputs.add(symToSuggest(it, isLocal=false, $ideSug, 100, pm, c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) else: for it in items(n.sym.tab): if filterSym(it, field, pm): - outputs.add(symToSuggest(it, isLocal=false, $ideSug, 100, pm, c.inTypeContext > 0, -99)) + outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99)) else: # fallback: suggestEverything(c, n, field, outputs) @@ -375,7 +374,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) # look up if the identifier belongs to the enum: var t = typ while t != nil: - suggestSymList(c, t.n, field, outputs) + suggestSymList(c, t.n, field, n.info, outputs) t = t.sons[0] suggestOperations(c, n, field, typ, outputs) else: @@ -384,11 +383,11 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) if typ.kind == tyObject: var t = typ while true: - suggestObject(c, t.n, field, outputs) + suggestObject(c, t.n, field, n.info, outputs) if t.sons[0] == nil: break t = skipTypes(t.sons[0], skipPtrs) elif typ.kind == tyTuple and typ.n != nil: - suggestSymList(c, typ.n, field, outputs) + suggestSymList(c, typ.n, field, n.info, outputs) suggestOperations(c, n, field, orig, outputs) if typ != orig: suggestOperations(c, n, field, typ, outputs) @@ -405,36 +404,12 @@ proc inCheckpoint*(current: TLineInfo): TCheckPointResult = if current.line >= gTrackPos.line: return cpFuzzy -proc findClosestDot(n: PNode): PNode = - if n.kind == nkDotExpr and inCheckpoint(n.info) == cpExact: - result = n - else: - for i in 0.. <safeLen(n): - result = findClosestDot(n.sons[i]) - if result != nil: return - -proc findClosestCall(n: PNode): PNode = - if n.kind in nkCallKinds and inCheckpoint(n.info) == cpExact: - result = n - else: - for i in 0.. <safeLen(n): - result = findClosestCall(n.sons[i]) - if result != nil: return - proc isTracked*(current: TLineInfo, tokenLen: int): bool = if current.fileIndex==gTrackPos.fileIndex and current.line==gTrackPos.line: let col = gTrackPos.col if col >= current.col and col <= current.col+tokenLen-1: return true -proc findClosestSym(n: PNode): PNode = - if n.kind == nkSym and inCheckpoint(n.info) == cpExact: - result = n - elif n.kind notin {nkNone..nkNilLit}: - for i in 0.. <sonsLen(n): - result = findClosestSym(n.sons[i]) - if result != nil: return - when defined(nimsuggest): # Since TLineInfo defined a == operator that doesn't include the column, # we map TLineInfo to a unique int here for this lookup table: @@ -453,26 +428,26 @@ var lastLineInfo*: TLineInfo proc findUsages(info: TLineInfo; s: PSym; usageSym: var PSym) = - if suggestVersion < 2: + if suggestVersion == 1: if usageSym == nil and isTracked(info, s.name.s.len): usageSym = s - suggestResult(symToSuggest(s, isLocal=false, $ideUse, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) elif s == usageSym: if lastLineInfo != info: - suggestResult(symToSuggest(s, isLocal=false, $ideUse, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0)) lastLineInfo = info when defined(nimsuggest): proc listUsages*(s: PSym) = #echo "usages ", len(s.allUsages) for info in s.allUsages: - let x = if info == s.info and info.col == s.info.col: "def" else: "use" + let x = if info == s.info and info.col == s.info.col: ideDef else: ideUse suggestResult(symToSuggest(s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0)) proc findDefinition(info: TLineInfo; s: PSym) = if s.isNil: return if isTracked(info, s.name.s.len): - suggestResult(symToSuggest(s, isLocal=false, $ideDef, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) suggestQuit() proc ensureIdx[T](x: var T, y: int) = @@ -484,7 +459,7 @@ proc ensureSeq[T](x: var seq[T]) = proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} = ## misnamed: should be 'symDeclared' when defined(nimsuggest): - if suggestVersion == 2: + if suggestVersion == 0: if s.allUsages.isNil: s.allUsages = @[info] else: @@ -496,13 +471,13 @@ proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.in findDefinition(info, s) elif gIdeCmd == ideDus and s != nil: if isTracked(info, s.name.s.len): - suggestResult(symToSuggest(s, isLocal=false, $ideDef, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0)) findUsages(info, s, usageSym) elif gIdeCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex: - suggestResult(symToSuggest(s, isLocal=false, $ideHighlight, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0)) elif gIdeCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and isDecl: - suggestResult(symToSuggest(s, isLocal=false, $ideOutline, info, 100, PrefixMatch.None, false, 0)) + suggestResult(symToSuggest(s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) proc markUsed(info: TLineInfo; s: PSym; usageSym: var PSym) = incl(s.flags, sfUsed) @@ -525,40 +500,31 @@ proc safeSemExpr*(c: PContext, n: PNode): PNode = except ERecoverableError: result = ast.emptyNode -proc suggestExpr*(c: PContext, node: PNode) = - if gTrackPos.line < 0: return - var cp = inCheckpoint(node.info) - if cp == cpNone: return +proc sugExpr(c: PContext, n: PNode, outputs: var Suggestions) = + if n.kind == nkDotExpr: + var obj = safeSemExpr(c, n.sons[0]) + # it can happen that errnously we have collected the fieldname + # of the next line, so we check the 'field' is actually on the same + # line as the object to prevent this from happening: + let prefix = if n.len == 2 and n[1].info.line == n[0].info.line and + not gTrackPosAttached: n[1] else: nil + suggestFieldAccess(c, obj, prefix, outputs) + + #if optIdeDebug in gGlobalOptions: + # echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ) + #writeStackTrace() + else: + let prefix = if gTrackPosAttached: nil else: n + suggestEverything(c, n, prefix, outputs) + +proc suggestExprNoCheck*(c: PContext, n: PNode) = # This keeps semExpr() from coming here recursively: if c.compilesContextId > 0: return inc(c.compilesContextId) - var outputs: Suggestions = @[] if gIdeCmd == ideSug: - var n = findClosestDot(node) - if n == nil: n = node - if n.kind == nkDotExpr: - var obj = safeSemExpr(c, n.sons[0]) - # it can happen that errnously we have collected the fieldname - # of the next line, so we check the 'field' is actually on the same - # line as the object to prevent this from happening: - let prefix = if n.len == 2 and n[1].info.line == n[0].info.line: n[1] else: nil - suggestFieldAccess(c, obj, prefix, outputs) - - #if optIdeDebug in gGlobalOptions: - # echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ) - #writeStackTrace() - else: - #let m = findClosestSym(node) - #if m != nil: - # suggestPrefix(c, m, outputs) - #else: - let prefix = if cp == cpExact: n else: nil - suggestEverything(c, n, prefix, outputs) - + sugExpr(c, n, outputs) elif gIdeCmd == ideCon: - var n = findClosestCall(node) - if n == nil: n = node if n.kind in nkCallKinds: var a = copyNode(n) var x = safeSemExpr(c, n.sons[0]) @@ -576,16 +542,32 @@ proc suggestExpr*(c: PContext, node: PNode) = produceOutput(outputs) suggestQuit() +proc suggestExpr*(c: PContext, n: PNode) = + if exactEquals(gTrackPos, n.info): suggestExprNoCheck(c, n) + +proc suggestDecl*(c: PContext, n: PNode; s: PSym) = + let attached = gTrackPosAttached + if attached: inc(c.inTypeContext) + defer: + if attached: dec(c.inTypeContext) + suggestExpr(c, n) + proc suggestStmt*(c: PContext, n: PNode) = suggestExpr(c, n) +proc suggestEnum*(c: PContext; n: PNode; t: PType) = + var outputs: Suggestions = @[] + suggestSymList(c, t.n, nil, n.info, outputs) + produceOutput(outputs) + if outputs.len > 0: suggestQuit() + proc suggestSentinel*(c: PContext) = if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex: return if c.compilesContextId > 0: return inc(c.compilesContextId) + var outputs: Suggestions = @[] # suggest everything: var isLocal = true - var outputs: Suggestions = @[] var scopeN = 0 for scope in walkScopes(c.currentScope): if scope == c.topLevelScope: isLocal = false @@ -593,7 +575,7 @@ proc suggestSentinel*(c: PContext) = for it in items(scope.symbols): var pm: PrefixMatch if filterSymNoOpr(it, nil, pm): - outputs.add(symToSuggest(it, isLocal = isLocal, $ideSug, 0, PrefixMatch.None, false, scopeN)) + outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, newLineInfo(gTrackPos.fileIndex, -1, -1), 0, PrefixMatch.None, false, scopeN)) - produceOutput(outputs) dec(c.compilesContextId) + produceOutput(outputs) diff --git a/compiler/transf.nim b/compiler/transf.nim index 0c53c0cbf..771dc58f4 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -291,10 +291,13 @@ proc transformBreak(c: PTransf, n: PNode): PTransNode = else: result = newTransNode(n.kind, n.info, 1) result[0] = lablCopy.PTransNode - else: + elif c.breakSyms.len > 0: + # this check can fail for 'nim check' let labl = c.breakSyms[c.breakSyms.high] result = transformSons(c, n) result[0] = newSymNode(labl).PTransNode + else: + result = n.PTransNode proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) = # XXX: BUG: what if `n` is an expression with side-effects? diff --git a/compiler/types.nim b/compiler/types.nim index df1d3e3ca..f4ef75094 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -20,6 +20,7 @@ type preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string +template `$`*(typ: PType): string = typeToString(typ) proc base*(t: PType): PType = result = t.sons[0] @@ -547,7 +548,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if prefer != preferExported: result.add("(" & typeToString(t.sons[0]) & ")") of tyProc: - result = if tfIterator in t.flags: "iterator (" else: "proc (" + result = if tfIterator in t.flags: "iterator " else: "proc " + if tfUnresolved in t.flags: result.add "[*missing parameters*]" + result.add "(" for i in countup(1, sonsLen(t) - 1): if t.n != nil and i < t.n.len and t.n[i].kind == nkSym: add(result, t.n[i].sym.name.s) |