diff --git a/compiler/ast.nim b/compiler/ast.nim index cd8154e46..ea88322a7 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -371,7 +371,7 @@ type skEnumField, # an identifier in an enum skForVar, # a for loop variable skLabel, # a label (for block statement) - skStub # symbol is a stub and not yet loaded from the ROD + skStub, # symbol is a stub and not yet loaded from the ROD # file (it is loaded on demand, which may # mean: never) TSymKinds* = set[TSymKind] @@ -380,6 +380,7 @@ const routineKinds* = {skProc, skMethod, skIterator, skConverter, skMacro, skTemplate} tfIncompleteStruct* = tfVarargs + skError* = skUnknown type TMagic* = enum # symbols that require compiler magic: diff --git a/compiler/lookups.nim b/compiler/lookups.nim index de546c959..556f6eb4a 100755 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -37,7 +37,7 @@ proc considerAcc*(n: PNode): PIdent = else: GlobalError(n.info, errIdentifierExpected, renderTree(n)) -proc errorSym*(n: PNode): PSym = +proc errorSym*(c: PContext, n: PNode): PSym = ## creates an error symbol to avoid cascading errors (for IDE support) var m = n # ensure that 'considerAcc' can't fail: @@ -46,8 +46,12 @@ proc errorSym*(n: PNode): PSym = considerAcc(m) else: getIdent("err:" & renderTree(m)) - result = newSym(skUnknown, ident, getCurrOwner()) + result = newSym(skError, ident, getCurrOwner()) result.info = n.info + result.typ = errorType(c) + incl(result.flags, sfDiscardable) + # pretend it's imported from some unknown module to prevent cascading errors: + SymTabAddAt(c.tab, result, ast.ImportTablePos) type TOverloadIterMode* = enum @@ -106,7 +110,6 @@ proc AddInterfaceDeclAux(c: PContext, sym: PSym) = # add to interface: if c.module != nil: StrTableAdd(c.module.tab, sym) else: InternalError(sym.info, "AddInterfaceDeclAux") - #if getCurrOwner().kind == skModule: incl(sym.flags, sfGlobal) proc addInterfaceDeclAt*(c: PContext, sym: PSym, at: Natural) = addDeclAt(c, sym, at) @@ -139,7 +142,7 @@ proc lookUp*(c: PContext, n: PNode): PSym = result = SymtabGet(c.Tab, n.ident) if result == nil: LocalError(n.info, errUndeclaredIdentifier, n.ident.s) - result = errorSym(n) + result = errorSym(c, n) of nkSym: result = n.sym of nkAccQuoted: @@ -147,7 +150,7 @@ proc lookUp*(c: PContext, n: PNode): PSym = result = SymtabGet(c.Tab, ident) if result == nil: LocalError(n.info, errUndeclaredIdentifier, ident.s) - result = errorSym(n) + result = errorSym(c, n) else: InternalError(n.info, "lookUp") return @@ -166,11 +169,11 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym = result = SymtabGet(c.Tab, ident) if result == nil and checkUndeclared in flags: LocalError(n.info, errUndeclaredIdentifier, ident.s) - result = errorSym(n) + result = errorSym(c, n) elif checkAmbiguity in flags and result != nil and Contains(c.AmbiguousSymbols, result.id): LocalError(n.info, errUseQualifier, ident.s) - of nkSym: + of nkSym: result = n.sym if checkAmbiguity in flags and Contains(c.AmbiguousSymbols, result.id): LocalError(n.info, errUseQualifier, n.sym.name.s) @@ -190,11 +193,11 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym = result = StrTableGet(m.tab, ident) if result == nil and checkUndeclared in flags: LocalError(n.sons[1].info, errUndeclaredIdentifier, ident.s) - result = errorSym(n.sons[1]) + result = errorSym(c, n.sons[1]) elif checkUndeclared in flags: LocalError(n.sons[1].info, errIdentifierExpected, renderTree(n.sons[1])) - result = errorSym(n.sons[1]) + result = errorSym(c, n.sons[1]) else: result = nil if result != nil and result.kind == skStub: loadStub(result) @@ -231,7 +234,7 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = else: LocalError(n.sons[1].info, errIdentifierExpected, renderTree(n.sons[1])) - result = errorSym(n.sons[1]) + result = errorSym(c, n.sons[1]) of nkSymChoice: o.mode = oimSymChoice result = n.sons[0].sym diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 69c9154c7..fd2205270 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -526,7 +526,7 @@ proc `??`* (info: TLineInfo, filename: string): bool = # only for debugging purposes result = filename in info.toFilename -var checkPoints: seq[TLineInfo] = @[] +var checkPoints*: seq[TLineInfo] = @[] proc addCheckpoint*(info: TLineInfo) = checkPoints.add(info) @@ -541,6 +541,7 @@ proc OutWriteln*(s: string) = 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) @@ -587,7 +588,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = elif eh == doRaise: raiseRecoverableError(s) -proc `==`(a, b: TLineInfo): bool = +proc `==`*(a, b: TLineInfo): bool = result = a.line == b.line and a.fileIndex == b.fileIndex proc writeContext(lastinfo: TLineInfo) = @@ -637,7 +638,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, frmt = posErrorFormat # we try to filter error messages so that not two error message # in the same file and line are produced: - ignoreMsg = lastError == info and eh != doAbort + #ignoreMsg = lastError == info and eh != doAbort lastError = info of warnMin..warnMax: ignoreMsg = optWarns notin gOptions or msg notin gNotes @@ -661,7 +662,6 @@ proc GlobalError*(info: TLineInfo, msg: TMsgKind, arg = "") = liMessage(info, msg, arg, doRaise) proc LocalError*(info: TLineInfo, msg: TMsgKind, arg = "") = - #if gCmd == cmdIdeTools and gErrorCounter > 10: return liMessage(info, msg, arg, doNothing) proc Message*(info: TLineInfo, msg: TMsgKind, arg = "") = diff --git a/compiler/sem.nim b/compiler/sem.nim index 0af9c4d99..ef4109c68 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -14,7 +14,7 @@ import wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, magicsys, parser, nversion, nimsets, semfold, importer, procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch, - suggest, semthreads, intsets, transf, evals, idgen, aliases + semthreads, intsets, transf, evals, idgen, aliases proc semPass*(): TPass # implementation @@ -37,9 +37,10 @@ proc addResultNode(c: PContext, n: PNode) proc instGenericContainer(c: PContext, n: PNode, header: PType): PType proc typeMismatch(n: PNode, formal, actual: PType) = - LocalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) & - typeToString(actual) & ") " & - `%`(msgKindToString(errButExpectedX), [typeToString(formal)])) + if formal.kind != tyError and actual.kind != tyError: + LocalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) & + typeToString(actual) & ") " & + `%`(msgKindToString(errButExpectedX), [typeToString(formal)])) proc fitNode(c: PContext, formal: PType, arg: PNode): PNode = result = IndexTypesMatch(c, formal, arg.typ, arg) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 003500b57..5bc4fa29e 100755 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -72,7 +72,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode, if c.inCompilesContext > 0: # quick error message for performance of 'compiles' built-in: GlobalError(n.Info, errAmbiguousCallXYZ, "") - else: + elif gErrorCounter == 0: + # don't cascade errors var args = "(" for i in countup(1, sonsLen(n) - 1): if i > 1: add(args, ", ") @@ -91,8 +92,14 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check! if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty: # a generic proc! - finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info) - + if not x.proxyMatch: + finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info) + else: + result = x.call + result.sons[0] = newSymNode(finalCallee) + result.typ = finalCallee.typ.sons[0] + if ContainsGenericType(result.typ): result.typ = errorType(c) + return result = x.call result.sons[0] = newSymNode(finalCallee) result.typ = finalCallee.typ.sons[0] diff --git a/compiler/semdata.nim b/compiler/semdata.nim index f78672837..00943a063 100755 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -74,6 +74,8 @@ type filename*: string # the module's filename userPragmas*: TStrTable evalContext*: PEvalContext + UnknownIdents*: TIntSet # ids of all unknown identifiers to prevent + # naming it multiple times var gGenericsCache: PGenericsCache # save for modularity @@ -194,6 +196,7 @@ proc newContext(module: PSym, nimfile: string): PContext = # we have to give up and use a per-module cache for generic instantiations: result.generics = newGenericsCache() assert gGenericsCache == nil + result.UnknownIdents = initIntSet() proc addConverter(c: PContext, conv: PSym) = var L = len(c.converters) @@ -230,6 +233,10 @@ proc errorType*(c: PContext): PType = ## creates a type representing an error state result = newTypeS(tyError, c) +proc errorNode*(c: PContext, n: PNode): PNode = + result = newNodeI(nkEmpty, n.info) + result.typ = errorType(c) + proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) = dest.kind = kind dest.owner = getCurrOwner() @@ -243,22 +250,12 @@ proc makeRangeType*(c: PContext, first, last: biggestInt, result = newTypeS(tyRange, c) result.n = n rawAddSon(result, getSysType(tyInt)) # basetype of range - -proc markUsed*(n: PNode, s: PSym) = - incl(s.flags, sfUsed) - if {sfDeprecated, sfError} * s.flags != {}: - if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s) - if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s) -proc markIndirect*(c: PContext, s: PSym) = +proc markIndirect*(c: PContext, s: PSym) {.inline.} = if s.kind in {skProc, skConverter, skMethod, skIterator}: incl(s.flags, sfAddrTaken) # XXX add to 'c' for global analysis -proc useSym*(sym: PSym): PNode = - result = newSymNode(sym) - markUsed(result, sym) - proc illFormedAst*(n: PNode) = GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments})) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 21d8ed617..4e8e80d53 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -38,7 +38,8 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExpr(c, n, flags) if result.kind == nkEmpty: # do not produce another redundant error message: - raiseRecoverableError("") + #raiseRecoverableError("") + result = errorNode(c, n) if result.typ != nil: if result.typ.kind == tyVar: result = newDeref(result) else: @@ -50,7 +51,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExpr(c, n, flags) if result.kind == nkEmpty: # do not produce another redundant error message: - raiseRecoverableError("") + result = errorNode(c, n) if result.typ == nil: LocalError(n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) @@ -614,8 +615,8 @@ proc semDirectCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = result = nil - var prc = n.sons[0] checkMinSonsLen(n, 1) + var prc = n.sons[0] if n.sons[0].kind == nkDotExpr: checkSonsLen(n.sons[0], 2) n.sons[0] = semFieldAccess(c, n.sons[0]) @@ -638,19 +639,25 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = if m.state != csMatch: if c.inCompilesContext > 0: # speed up error generation: - LocalError(n.Info, errTypeMismatch, "") + GlobalError(n.Info, errTypeMismatch, "") return emptyNode else: + var hasErrorType = false var msg = msgKindToString(errTypeMismatch) for i in countup(1, sonsLen(n) - 1): if i > 1: add(msg, ", ") - add(msg, typeToString(n.sons[i].typ)) - add(msg, ")\n" & msgKindToString(errButExpected) & "\n" & - typeToString(n.sons[0].typ)) - LocalError(n.Info, errGenerated, msg) - return emptyNode + let nt = n.sons[i].typ + add(msg, typeToString(nt)) + if nt.kind == tyError: + hasErrorType = true + break + if not hasErrorType: + add(msg, ")\n" & msgKindToString(errButExpected) & "\n" & + typeToString(n.sons[0].typ)) + LocalError(n.Info, errGenerated, msg) + return errorNode(c, n) result = nil - else: + else: result = m.call # we assume that a procedure that calls something indirectly # has side-effects: @@ -663,10 +670,11 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = n.sons[0] = prc nOrig.sons[0] = prc result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) - if result == nil: - LocalError(n.info, errExprXCannotBeCalled, - renderTree(n, {renderNoComments})) - return emptyNode + if result == nil: + if c.inCompilesContext > 0 or gErrorCounter == 0: + LocalError(n.info, errExprXCannotBeCalled, + renderTree(n, {renderNoComments})) + return errorNode(c, n) fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) if result.sons[0].kind == nkSym and result.sons[0].sym.magic != mNone: @@ -680,9 +688,9 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) if result == nil: result = overloadedCallOpr(c, n) - if result == nil: - LocalError(n.Info, errGenerated, getNotFoundError(c, n)) - return emptyNode + if result == nil: + NotFoundError(c, n) + return errorNode(c, n) let callee = result.sons[0].sym case callee.kind of skMacro: result = semMacroExpr(c, nOrig, callee) @@ -718,7 +726,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode = addSon(result, newSymNode(e)) else: LocalError(n.info, errSystemNeeds, "echo") - addSon(result, emptyNode) + addSon(result, errorNode(c, n)) var arg = buildStringify(c, n) # problem is: implicit '$' is not checked for semantics yet. So we give up # and check 'arg' for semantics again: @@ -732,7 +740,7 @@ proc semExprNoType(c: PContext, n: PNode): PNode = if result.typ != nil and result.typ.kind != tyStmt: if gCmd == cmdInteractive: result = buildEchoStmt(c, result) - elif not ImplicitelyDiscardable(result): + elif not ImplicitelyDiscardable(result) and result.typ.kind != tyError: localError(n.info, errDiscardValue) proc isTypeExpr(n: PNode): bool = @@ -909,8 +917,9 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = addSon(result, newIdentNode(i, n.info)) addSon(result, copyTree(n[0])) else: - LocalError(n.Info, errUndeclaredFieldX, i.s) - result = emptyNode + if not ContainsOrIncl(c.UnknownIdents, i.id): + LocalError(n.Info, errUndeclaredFieldX, i.s) + result = errorNode(c, n) proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode = result = newNodeI(nkCall, n.info) @@ -992,8 +1001,9 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) else: - LocalError(n.Info, errUndeclaredFieldX, id.s) - result = emptyNode + if not ContainsOrIncl(c.UnknownIdents, id.id): + LocalError(n.Info, errUndeclaredFieldX, id.s) + result = errorNode(c, n) proc takeImplicitAddr(c: PContext, n: PNode): PNode = case n.kind @@ -1116,16 +1126,16 @@ proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym = var expandedSym = qualifiedLookup(c, n[0], {checkUndeclared}) if expandedSym == nil: LocalError(n.info, errUndeclaredIdentifier, n[0].renderTree) - return errorSym(n[0]) + return errorSym(c, n[0]) if expandedSym.kind notin {skMacro, skTemplate}: LocalError(n.info, errXisNoMacroOrTemplate, expandedSym.name.s) - return errorSym(n[0]) + return errorSym(c, n[0]) result = expandedSym else: LocalError(n.info, errXisNoMacroOrTemplate, n.renderTree) - result = errorSym(n) + result = errorSym(c, n) proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, flags: TExprFlags): PNode = @@ -1395,11 +1405,11 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode = result = semTemplateExpr(c, result, s, semCheck) else: LocalError(n.info, errXisNoMacroOrTemplate, s.name.s) - result = emptyNode + result = errorNode(c, n) else: LocalError(n.info, errInvalidExpressionX, renderTree(a, {renderNoComments})) - result = emptyNode + result = errorNode(c, n) proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = n diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 47806af62..5beac49ab 100755 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -27,8 +27,8 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable, var t = PType(IdTableGet(pt, q.typ)) if t == nil: LocalError(a.info, errCannotInstantiateX, s.name.s) - break - if t.kind == tyGenericParam: + t = errorType(c) + elif t.kind == tyGenericParam: InternalError(a.info, "instantiateGenericParamList: " & q.name.s) elif t.kind == tyGenericInvokation: #t = instGenericContainer(c, a, t) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0e882c076..a5967a26d 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -79,7 +79,8 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = x.info = n.info incl(s.flags, sfUsed) n.sons[0] = x - else: + suggestSym(x, s) + else: localError(n.info, errInvalidControlFlowX, s.name.s) elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): localError(n.info, errInvalidControlFlowX, @@ -94,6 +95,7 @@ proc semBlock(c: PContext, n: PNode): PNode = var labl = newSymS(skLabel, n.sons[0], c) addDecl(c, labl) n.sons[0] = newSymNode(labl) + suggestSym(n.sons[0], labl) n.sons[1] = semStmt(c, n.sons[1]) closeScope(c.tab) Dec(c.p.nestedBlockCounter) @@ -132,7 +134,7 @@ proc semCase(c: PContext, n: PNode): PNode = case skipTypes(n.sons[0].Typ, abstractVarRange).Kind of tyInt..tyInt64, tyChar, tyEnum: chckCovered = true - of tyFloat..tyFloat128, tyString: + of tyFloat..tyFloat128, tyString, tyError: nil else: LocalError(n.info, errSelectorMustBeOfCertainTypes) @@ -229,8 +231,9 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = if isTopLevel(c): result = semIdentWithPragma(c, kind, n, {sfExported}) incl(result.flags, sfGlobal) - else: + else: result = semIdentWithPragma(c, kind, n, {}) + suggestSym(n, result) proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var b: PNode diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index de6e6cb0e..1525f93af 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -222,8 +222,8 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = amb = nextOverloadIter(ov, c, n) if amb != nil: result = amb else: - LocalError(n.info, errTypeExpected) - return errorSym(n) + if result.kind != skError: LocalError(n.info, errTypeExpected) + return errorSym(c, n) if result.typ.kind != tyGenericParam: # XXX get rid of this hack! reset(n[]) @@ -231,7 +231,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = n.sym = result else: LocalError(n.info, errIdentifierExpected) - result = errorSym(n) + result = errorSym(c, n) proc semTuple(c: PContext, n: PNode, prev: PType): PType = if n.sonsLen == 0: return newConstraint(c, tyTuple) @@ -827,7 +827,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkIdent, nkDotExpr, nkAccQuoted: var s = semTypeIdent(c, n) if s.typ == nil: - LocalError(n.info, errTypeExpected) + if s.kind != skError: LocalError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) elif prev == nil: result = s.typ @@ -845,7 +845,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = prev markUsed(n, n.sym) else: - LocalError(n.info, errTypeExpected) + if n.sym.kind != skError: LocalError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) of nkObjectTy: result = semObjectNode(c, n, prev) of nkTupleTy: result = semTuple(c, n, prev) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 6a5b6ff60..3c338fbf0 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -12,7 +12,7 @@ import intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, - magicsys, condsyms, idents + magicsys, condsyms, idents, lexer, options type TCandidateState* = enum @@ -32,6 +32,7 @@ type bindings*: TIdTable # maps types to types baseTypeMatch: bool # needed for conversions from T to openarray[T] # for example + proxyMatch*: bool # to prevent instantiations inheritancePenalty: int # to prefer closest father object type TTypeRelation* = enum # order is important! @@ -43,7 +44,9 @@ type isGeneric, isFromIntLit, # conversion *from* int literal; proven safe isEqual - + +proc markUsed*(n: PNode, s: PSym) + proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} = c.exactMatches = 0 c.subtypeMatches = 0 @@ -114,22 +117,26 @@ proc writeMatches*(c: TCandidate) = Writeln(stdout, "intconv matches: " & $c.intConvMatches) Writeln(stdout, "generic matches: " & $c.genericMatches) -proc getNotFoundError*(c: PContext, n: PNode): string = +proc NotFoundError*(c: PContext, n: PNode) = # Gives a detailed error message; this is separated from semOverloadedCall, # as semOverlodedCall is already pretty slow (and we need this information # only in case of an error). - if c.InCompilesContext > 0: return "" - result = msgKindToString(errTypeMismatch) + if c.InCompilesContext > 0: + # fail fast: + GlobalError(n.info, errTypeMismatch, "") + var result = msgKindToString(errTypeMismatch) for i in countup(1, sonsLen(n) - 1): #debug(n.sons[i].typ) if n.sons[i].kind == nkExprEqExpr: add(result, renderTree(n.sons[i].sons[0])) add(result, ": ") - add(result, typeToString(n.sons[i].typ)) + let nt = n.sons[i].typ + if nt.kind == tyError: return + add(result, typeToString(nt)) if i != sonsLen(n) - 1: add(result, ", ") add(result, ')') var candidates = "" - var o: TOverloadIter + var o: TOverloadIter var sym = initOverloadIter(o, c, n.sons[0]) while sym != nil: if sym.kind in {skProc, skMethod, skIterator, skConverter}: @@ -139,6 +146,7 @@ proc getNotFoundError*(c: PContext, n: PNode): string = sym = nextOverloadIter(o, c, n.sons[0]) if candidates != "": add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) + LocalError(n.Info, errGenerated, result) proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation proc concreteType(c: TCandidate, t: PType): PType = @@ -418,7 +426,7 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = result = typeRel(c, f.sons[0], x) if result < isGeneric: result = isNone of tyForward: InternalError("forward type in typeRel()") - of tyNil: + of tyNil: if a.kind == f.kind: result = isEqual of tyTuple: if a.kind == tyTuple: result = tupleRel(c, f, a) @@ -539,8 +547,10 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = if result == isGeneric: put(c.bindings, f, a) else: result = isNone - of tyExpr, tyStmt, tyProxy: + of tyExpr, tyStmt: result = isGeneric + of tyProxy: + result = isEqual else: internalError("typeRel: " & $f.kind) proc cmpTypes*(f, a: PType): TTypeRelation = @@ -560,8 +570,13 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate, proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, c: PContext): PNode = result = newNodeI(kind, arg.info) - if containsGenericType(f): result.typ = getInstantiatedType(c, arg, m, f) - else: result.typ = f + if containsGenericType(f): + if not m.proxyMatch: + result.typ = getInstantiatedType(c, arg, m, f) + else: + result.typ = errorType(c) + else: + result.typ = f if result.typ == nil: InternalError(arg.info, "implicitConv") addSon(result, ast.emptyNode) addSon(result, arg) @@ -648,11 +663,12 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, result = copyTree(arg) if skipTypes(f, abstractVar).kind in {tyTuple}: result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) - of isNone: - # we test for this here to not slow down ``typeRel``: + of isNone: + # do not do this in ``typeRel`` as it then can't infere T in ``ref T``: if a.kind == tyProxy: inc(m.genericMatches) - return copyTree(arg) + m.proxyMatch = true + return copyTree(arg) result = userConvMatch(c, m, f, a, arg) # check for a base type match, which supports openarray[T] without [] # constructor in a call: @@ -854,3 +870,5 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = # use default value: setSon(m.call, formal.position + 1, copyTree(formal.ast)) inc(f) + +include suggest diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 320548457..bdd3cfb34 100755 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -9,15 +9,14 @@ ## This file implements features required for IDE support. -import - lexer, idents, ast, astalgo, semdata, msgs, types, sigmatch, options, - renderer +# imported from sigmatch.nim const sep = '\t' sectionSuggest = "sug" sectionDef = "def" sectionContext = "con" + sectionUsage = "use" proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string = result = section @@ -183,6 +182,16 @@ proc findClosestCall(n: PNode): PNode = result = findClosestCall(n.sons[i]) if result != nil: return +proc isTracked(current: TLineInfo, tokenLen: int): bool = + # the column of an identifier is at its *end*, so we subtract to get the + # start of it. + for i in countup(0, high(checkPoints)): + if current.fileIndex == checkPoints[i].fileIndex: + if current.line == checkPoints[i].line: + let col = checkPoints[i].col + if col >= current.col-tokenLen and col <= current.col: + return true + proc findClosestSym(n: PNode): PNode = if n.kind == nkSym and msgs.inCheckpoint(n.info) == cpExact: result = n @@ -205,7 +214,40 @@ proc fuzzySemCheck(c: PContext, n: PNode): PNode = for i in 0 .. < sonsLen(n): result.addSon(fuzzySemCheck(c, n.sons[i])) var - usageSym: PSym + usageSym*: PSym + lastLineInfo: TLineInfo + +proc findUsages(node: PNode, s: PSym) = + if usageSym == nil and isTracked(node.info, s.name.s.len): + usageSym = s + OutWriteln(SymToStr(s, isLocal=false, sectionUsage)) + elif s == usageSym: + if lastLineInfo != node.info: + OutWriteln(SymToStr(s, isLocal=false, sectionUsage, node.info)) + lastLineInfo = node.info + +proc findDefinition(node: PNode, s: PSym) = + if isTracked(node.info, s.name.s.len): + OutWriteln(SymToStr(s, isLocal=false, sectionDef)) + quit(0) + +proc suggestSym*(n: PNode, s: PSym) {.inline.} = + ## misnamed: should be 'symDeclared' + if optUsages in gGlobalOptions: + findUsages(n, s) + if optDef in gGlobalOptions: + findDefinition(n, s) + +proc markUsed(n: PNode, s: PSym) = + incl(s.flags, sfUsed) + if {sfDeprecated, sfError} * s.flags != {}: + if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s) + if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s) + suggestSym(n, s) + +proc useSym*(sym: PSym): PNode = + result = newSymNode(sym) + markUsed(result, sym) proc suggestExpr*(c: PContext, node: PNode) = var cp = msgs.inCheckpoint(node.info) @@ -243,25 +285,6 @@ proc suggestExpr*(c: PContext, node: PNode) = addSon(a, x) suggestCall(c, a, n, outputs) - if optDef in gGlobalOptions: - let n = findClosestSym(fuzzySemCheck(c, node)) - if n != nil: - OutWriteln(SymToStr(n.sym, isLocal=false, sectionDef)) - inc outputs - - if optUsages in gGlobalOptions: - if usageSym == nil: - let n = findClosestSym(fuzzySemCheck(c, node)) - if n != nil: - usageSym = n.sym - OutWriteln(SymToStr(n.sym, isLocal=false, sectionDef)) - inc outputs - else: - let n = node - if n.kind == nkSym and n.sym == usageSym: - OutWriteln(SymToStr(n.sym, isLocal=false, sectionDef, n.info)) - inc outputs - dec(c.InCompilesContext) if outputs > 0 and optUsages notin gGlobalOptions: quit(0) diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt index 13bf5295a..98e1b96d8 100755 --- a/doc/nimrodc.txt +++ b/doc/nimrodc.txt @@ -514,3 +514,40 @@ efficient: of "license": c.license = UnixToNativePath(k.value) else: quit(errorStr(p, "unknown variable: " & k.key)) + +The ECMAScript target +===================== + +Nimrod can also generate `ECMAScript`:idx: (also known as `JavaScript`:idx:) +code. However, the ECMAScript code generator is experimental! + +Nimrod targets ECMAScript 1.5 which is supported by any widely used browser. +Since ECMAScript does not have a portable means to include another module, +Nimrod just generates a long ``.js`` file. + +Features or modules that the ECMAScript platform does not support are not +available. This includes: + +* manual memory management (``alloc``, etc.) +* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.) +* file management +* most modules of the Standard library +* proper 64 bit integer arithmetic +* unsigned integer arithmetic + +However, the modules `strutils`:idx:, `math`:idx:, and `times`:idx: are +available! To access the DOM, use the `dom`:idx: module that is only +available for the ECMAScript platform. + +To compile a Nimrod module into a ``.js`` file use the ``js`` command; the +default is a ``.js`` file that is supposed to be referenced in an ``.html`` +file. However, you can also run the code with `nodejs`:idx:\: + + nimrod js -d:nodejs -r examples/hallo.nim + + +Known bugs +---------- + +* exception handling does not work + diff --git a/todo.txt b/todo.txt index f98b65ab0..40e9f7003 100755 --- a/todo.txt +++ b/todo.txt @@ -6,19 +6,11 @@ version 0.9.0 - implicit deref for parameter matching - ``borrow`` needs to take type classes into account -- ``=`` should be overloadable; requires specialization for ``=`` - optimize genericAssign in the code generator - fix remaining closure bugs: - fix evals.nim with closures - implement "closure tuple consists of a single 'ref'" optimization -- document 'do' notation -- rethink the syntax: distinction between expr and stmt is unfortunate; - indentation handling is quite complex too; problem with exception handling - is that often the scope of ``try`` is wrong and apart from that ``try`` is - a full blown statement; a ``try`` expression might be a good idea to make - error handling more light-weight - Bugs ---- @@ -36,9 +28,15 @@ version 0.9.XX ============== - JS gen: - - document it - fix exception handling +- document 'do' notation +- rethink the syntax: distinction between expr and stmt is unfortunate; + indentation handling is quite complex too; problem with exception handling + is that often the scope of ``try`` is wrong and apart from that ``try`` is + a full blown statement; a ``try`` expression might be a good idea to make + error handling more light-weight +- ``=`` should be overloadable; requires specialization for ``=`` - ``hoist`` pragma for loop hoisting - document destructors; don't work yet when used as expression - make use of ``tyIter`` to fix the implicit items/pairs issue