diff options
Diffstat (limited to 'compiler')
56 files changed, 675 insertions, 472 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 5fc8e5978..6a73df3c7 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -565,13 +565,9 @@ const routineKinds* = {skProc, skFunc, skMethod, skIterator, skConverter, skMacro, skTemplate} tfIncompleteStruct* = tfVarargs - tfUncheckedArray* = tfVarargs tfUnion* = tfNoSideEffect tfGcSafe* = tfThread tfObjHasKids* = tfEnumHasHoles - tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \ - # 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be - # deprecated and this mess can be cleaned up. tfReturnsNew* = tfInheritable skError* = skUnknown @@ -660,7 +656,8 @@ type mNHint, mNWarning, mNError, mInstantiationInfo, mGetTypeInfo, mNimvm, mIntDefine, mStrDefine, mRunnableExamples, - mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf + mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf, + mSymIsInstantiationOf # things that we can evaluate safely at compile time, even if not asked for it: const diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 6678a07ca..388ab806e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -173,21 +173,6 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) elif dest.storage == OnHeap: # location is on heap - # now the writer barrier is inlined for performance: - # - # if afSrcIsNotNil in flags: - # UseMagic(p.module, 'nimGCref') - # lineF(p, cpsStmts, 'nimGCref($1);$n', [rdLoc(src)]) - # elif afSrcIsNil notin flags: - # UseMagic(p.module, 'nimGCref') - # lineF(p, cpsStmts, 'if ($1) nimGCref($1);$n', [rdLoc(src)]) - # if afDestIsNotNil in flags: - # UseMagic(p.module, 'nimGCunref') - # lineF(p, cpsStmts, 'nimGCunref($1);$n', [rdLoc(dest)]) - # elif afDestIsNil notin flags: - # UseMagic(p.module, 'nimGCunref') - # lineF(p, cpsStmts, 'if ($1) nimGCunref($1);$n', [rdLoc(dest)]) - # lineF(p, cpsStmts, '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]) if canFormAcycle(dest.t): linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n", addrLoc(p.config, dest), rdLoc(src)) @@ -872,7 +857,7 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses) var first = intLiteral(firstOrd(p.config, ty)) # emit range check: - if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags: + if optBoundsCheck in p.options and ty.kind != tyUncheckedArray: if not isConstExpr(y): # semantic pass has already checked for const index expressions if firstOrd(p.config, ty) == 0: @@ -909,11 +894,10 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = rdLoc(a), rdLoc(b), rdLoc(arr)) of tyArray: let first = intLiteral(firstOrd(p.config, ty)) - if tfUncheckedArray notin ty.flags: - linefmt(p, cpsStmts, - "if ($2-$1 != -1 && " & - "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n", - rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty))) + linefmt(p, cpsStmts, + "if ($2-$1 != -1 && " & + "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n", + rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty))) of tySequence, tyString: linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & @@ -1156,7 +1140,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = getIntTemp(p, tmpL) lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p)) dest.r = ropecg(p.module, "$1$3[$2]", rdLoc(a), tmpL.r, dataField(p)) - genAssignment(p, dest, b, {needToCopy, afDestIsNil}) + genAssignment(p, dest, b, {needToCopy}) gcUsage(p.config, e) proc genReset(p: BProc, n: PNode) = @@ -1395,7 +1379,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = elem.storage = OnHeap # we know that sequences are on the heap initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage) arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), intLiteral(i)) - genAssignment(p, elem, arr, {afDestIsNil, needToCopy}) + genAssignment(p, elem, arr, {needToCopy}) else: var i: TLoc getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) @@ -1406,7 +1390,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = elem.storage = OnHeap # we know that sequences are on the heap initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage) arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), rdLoc(i)) - genAssignment(p, elem, arr, {afDestIsNil, needToCopy}) + genAssignment(p, elem, arr, {needToCopy}) lineF(p, cpsStmts, "}$n", []) @@ -1581,8 +1565,17 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ))) else: internalError(p.config, e.info, "genArrayLen()") +proc makePtrType(baseType: PType): PType = + result = newType(tyPtr, baseType.owner) + addSonSkipIntLit(result, baseType) + +proc makeAddr(n: PNode): PNode = + result = newTree(nkHiddenAddr, n) + result.typ = makePtrType(n.typ) + proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = if p.config.selectedGc == gcDestructors: + e.sons[1] = makeAddr(e[1]) genCall(p, e, d) return var a, b, call: TLoc @@ -1964,6 +1957,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mAppendStrStr: genStrAppend(p, e, d) of mAppendSeqElem: if p.config.selectedGc == gcDestructors: + e.sons[1] = makeAddr(e[1]) genCall(p, e, d) else: genSeqElemAppend(p, e, d) @@ -2031,8 +2025,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = let n = lowerings.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil) expr(p, n, d) of mParallel: - let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e) - expr(p, n, d) + when defined(leanCompiler): + quit "compiler built without support for the 'parallel' statement" + else: + let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e) + expr(p, n, d) of mDeepCopy: var a, b: TLoc let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1] @@ -2429,15 +2426,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if ex.kind != nkEmpty: genLineDir(p, n) var a: TLoc - if ex.kind in nkCallKinds and (ex[0].kind != nkSym or - ex[0].sym.magic == mNone): - # bug #6037: do not assign to a temp in C++ mode: - incl a.flags, lfSingleUse - genCall(p, ex, a) - if lfSingleUse notin a.flags: - line(p, cpsStmts, a.r & ";\L") - else: - initLocExpr(p, ex, a) + initLocExprSingleUse(p, ex, a) + line(p, cpsStmts, "(void)(" & a.r & ");\L") of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt: if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions: diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim index 34677ec06..ccfa49a1d 100644 --- a/compiler/ccgliterals.nim +++ b/compiler/ccgliterals.nim @@ -69,7 +69,7 @@ proc genStringLiteralV2(m: BModule; n: PNode): Rope = addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", [result, rope(len(n.strVal)), pureLit]) else: - result = m.tmpBase & rope(id) + result = m.tmpBase & rope(id+1) proc genStringLiteralV2Const(m: BModule; n: PNode): Rope = let id = nodeTableTestOrSet(m.dataCache, n, m.labels) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 5ebe0323d..3665a7e85 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -509,7 +509,7 @@ proc genWhileStmt(p: BProc, t: PNode) = # for closure support weird loop bodies are generated: if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty: loopBody = loopBody.sons[1] - genComputedGoto(p, loopBody) # TODO foobar + genComputedGoto(p, loopBody) else: p.breakIdx = startBlock(p, "while (1) {$n") p.blocks[p.breakIdx].isLoop = true @@ -874,14 +874,15 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = discard pop(p.nestedTryStmts) - if not catchAllPresent and t[^1].kind == nkFinally: - # finally requires catch all presence - startBlock(p, "catch (...) {$n") - genSimpleBlock(p, t[^1][0]) - line(p, cpsStmts, ~"throw;$n") - endBlock(p) - if t[^1].kind == nkFinally: + # c++ does not have finally, therefore code needs to be generated twice + if not catchAllPresent: + # finally requires catch all presence + startBlock(p, "catch (...) {$n") + genStmts(p, t[^1][0]) + line(p, cpsStmts, ~"throw;$n") + endBlock(p) + genSimpleBlock(p, t[^1][0]) proc genTry(p: BProc, t: PNode, d: var TLoc) = diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 75566fb38..bbfd72354 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -492,7 +492,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, # with heavily templatized C++ code: if not isImportedCppType(rectype): let fieldType = field.loc.lode.typ.skipTypes(abstractInst) - if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: + if fieldType.kind == tyUncheckedArray: addf(result, "$1 $2[SEQ_DECL_SIZE];$n", [getTypeDescAux(m, fieldType.elemType, check), sname]) elif fieldType.kind == tySequence and m.config.selectedGC != gcDestructors: @@ -1188,6 +1188,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = let owner = t.skipTypes(typedescPtrs).owner.getModule if owner != m.module: # make sure the type info is created in the owner module + assert m.g.modules[owner.position] != nil discard genTypeInfo(m.g.modules[owner.position], origType, info) # reference the type info as extern here discard cgsym(m, "TNimType") @@ -1213,8 +1214,8 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = let x = fakeClosureType(m, t.owner) genTupleInfo(m, x, x, result, info) of tySequence: + genTypeInfoAux(m, t, t, result, info) if m.config.selectedGC != gcDestructors: - genTypeInfoAux(m, t, t, result, info) if m.config.selectedGC >= gcMarkAndSweep: let markerProc = genTraverseProc(m, origType, sig) addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc]) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index ab5584786..199a93be2 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -14,7 +14,10 @@ import nversion, nimsets, msgs, std / sha1, bitsets, idents, types, ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, - lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils, transf + lowerings, tables, sets, ndi, lineinfos, pathutils, transf + +when not defined(leanCompiler): + import semparallel import strutils except `%` # collides with ropes.`%` @@ -42,8 +45,7 @@ when options.hasTinyCBackend: # implementation proc addForwardedProc(m: BModule, prc: PSym) = - m.forwardedProcs.add(prc) - inc(m.g.forwardedProcsCounter) + m.g.forwardedProcs.add(prc) proc findPendingModule(m: BModule, s: PSym): BModule = var ms = getModule(s) @@ -292,7 +294,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, type TAssignmentFlag = enum - needToCopy, afDestIsNil, afDestIsNotNil, afSrcIsNil, afSrcIsNotNil + needToCopy TAssignmentFlags = set[TAssignmentFlag] proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) @@ -311,7 +313,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = var nilLoc: TLoc initLoc(nilLoc, locTemp, loc.lode, OnStack) nilLoc.r = rope("NIM_NIL") - genRefAssign(p, loc, nilLoc, {afSrcIsNil}) + genRefAssign(p, loc, nilLoc, {}) else: linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc)) else: @@ -1391,7 +1393,6 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule result.preInitProc = newPreInitProc(result) initNodeTable(result.dataCache) result.typeStack = @[] - result.forwardedProcs = @[] result.typeNodesName = getTempName(result) result.nimTypesName = getTempName(result) # no line tracing for the init sections of the system module so that we @@ -1407,49 +1408,6 @@ proc nullify[T](arr: var T) = for i in low(arr)..high(arr): arr[i] = Rope(nil) -proc resetModule*(m: BModule) = - # between two compilations in CAAS mode, we can throw - # away all the data that was written to disk - m.headerFiles = @[] - m.declaredProtos = initIntSet() - m.forwTypeCache = initTable[SigHash, Rope]() - m.initProc = newProc(nil, m) - m.initProc.options = initProcOptions(m) - m.preInitProc = newPreInitProc(m) - initNodeTable(m.dataCache) - m.typeStack = @[] - m.forwardedProcs = @[] - m.typeNodesName = getTempName(m) - m.nimTypesName = getTempName(m) - if sfSystemModule in m.module.flags: - incl m.flags, preventStackTrace - else: - excl m.flags, preventStackTrace - nullify m.s - m.typeNodes = 0 - m.nimTypes = 0 - nullify m.extensionLoaders - - # indicate that this is now cached module - # the cache will be invalidated by nullifying gModules - #m.fromCache = true - m.g = nil - - # we keep only the "merge info" information for the module - # and the properties that can't change: - # m.filename - # m.cfilename - # m.isHeaderFile - # m.module ? - # m.typeCache - # m.declaredThings - # m.typeInfoMarker - # m.labels - # m.FrameDeclared - -proc resetCgenModules*(g: BModuleList) = - for m in cgenModules(g): resetModule(m) - proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule = result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex)) @@ -1528,20 +1486,6 @@ proc myProcess(b: PPassContext, n: PNode): PNode = let tranformed_n = transformStmt(m.g.graph, m.module, n) genStmts(m.initProc, tranformed_n) -proc finishModule(m: BModule) = - var i = 0 - while i <= high(m.forwardedProcs): - # Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use - # a ``for`` loop here - var prc = m.forwardedProcs[i] - if sfForward in prc.flags: - internalError(m.config, prc.info, "still forwarded: " & prc.name.s) - genProcNoForward(m, prc) - inc(i) - assert(m.g.forwardedProcsCounter >= i) - dec(m.g.forwardedProcsCounter, i) - setLen(m.forwardedProcs, 0) - proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = result = true if optForceFullMake notin m.config.globalOptions: @@ -1637,12 +1581,26 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = registerModuleToMain(m.g, m.module) if sfMainModule in m.module.flags: - if m.g.forwardedProcsCounter == 0: + if m.g.forwardedProcs.len == 0: incl m.flags, objHasKidsValid let disp = generateMethodDispatchers(graph) for x in disp: genProcAux(m, x.sym) genMainProc(m) +proc genForwardedProcs(g: BModuleList) = + # Forward declared proc:s lack bodies when first encountered, so they're given + # a second pass here + # Note: ``genProcNoForward`` may add to ``forwardedProcs`` + while g.forwardedProcs.len > 0: + let + prc = g.forwardedProcs.pop() + ms = getModule(prc) + m = g.modules[ms.position] + if sfForward in prc.flags: + internalError(m.config, prc.info, "still forwarded: " & prc.name.s) + + genProcNoForward(m, prc) + proc cgenWriteModules*(backend: RootRef, config: ConfigRef) = let g = BModuleList(backend) # we need to process the transitive closure because recursive module @@ -1652,10 +1610,9 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) = let (outDir, _, _) = splitFile(config.outfile) if not outDir.isEmpty: createDir(outDir) - if g.generatedHeader != nil: finishModule(g.generatedHeader) - while g.forwardedProcsCounter > 0: - for m in cgenModules(g): - finishModule(m) + + genForwardedProcs(g) + for m in cgenModules(g): m.writeModule(pending=true) writeMapping(config, g.mapping) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 0c6097fbe..28e36364e 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -112,7 +112,7 @@ type mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope mapping*: Rope # the generated mapping file (if requested) modules*: seq[BModule] # list of all compiled modules - forwardedProcsCounter*: int + forwardedProcs*: seq[PSym] # proc:s that did not yet have a body generatedHeader*: BModule breakPointId*: int breakpoints*: Rope # later the breakpoints are inserted into the main proc @@ -150,7 +150,6 @@ type preInitProc*: BProc # code executed before the init proc typeStack*: TTypeSeq # used for type generation dataCache*: TNodeTable - forwardedProcs*: TSymSeq # keep forwarded procs here typeNodes*, nimTypes*: int # used for type info generation typeNodesName*, nimTypesName*: Rope # used for type info generation labels*: Natural # for generating unique module-scope names @@ -188,12 +187,12 @@ proc newProc*(prc: PSym, module: BModule): BProc = result.sigConflicts = initCountTable[string]() proc newModuleList*(g: ModuleGraph): BModuleList = - BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config, - graph: g, nimtvDeps: @[], nimtvDeclared: initIntSet()) + BModuleList(typeInfoMarker: initTable[SigHash, Rope](), config: g.config, + graph: g, nimtvDeclared: initIntSet()) iterator cgenModules*(g: BModuleList): BModule = - for i in 0..high(g.modules): + for m in g.modules: # ultimately, we are iterating over the file ids here. # some "files" won't have an associated cgen module (like stdin) # and we must skip over them. - if g.modules[i] != nil: yield g.modules[i] + if m != nil: yield m diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 258372d76..c2d908193 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -462,10 +462,17 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = result.typ = n.typ for i in 0 ..< n.len: - if n[i].kind == nkStmtListExpr: + case n[i].kind + of nkExprColonExpr: + if n[i][1].kind == nkStmtListExpr: + let (st, ex) = exprToStmtList(n[i][1]) + result.add(st) + n[i][1] = ex + of nkStmtListExpr: let (st, ex) = exprToStmtList(n[i]) result.add(st) n[i] = ex + else: discard result.add(n) of nkIfStmt, nkIfExpr: @@ -852,15 +859,8 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode discard of nkStmtList, nkStmtListExpr: - assert(isEmptyType(n.typ), "nkStmtListExpr not lowered") - result = addGotoOut(result, gotoOut) for i in 0 ..< n.len: - if n[i].hasYieldsInExpressions: - # Lower nkStmtListExpr nodes inside `n[i]` first - var ns = false - n[i] = ctx.lowerStmtListExprs(n[i], ns) - if n[i].hasYields: # Create a new split let go = newNodeI(nkGotoState, n[i].info) @@ -1294,11 +1294,17 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode = ctx.stateVarSym.typ = g.createClosureIterStateType(fn) ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info) - let n = n.toStmtList + var n = n.toStmtList discard ctx.newState(n, nil) let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1)) + var ns = false + n = ctx.lowerStmtListExprs(n, ns) + + if n.hasYieldsInExpressions(): + internalError(ctx.g.config, "yield in expr not lowered") + # Splitting transformation discard ctx.transformClosureIteratorBody(n, gotoOut) diff --git a/compiler/commands.nim b/compiler/commands.nim index b39cc0b72..fa17e9851 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -642,14 +642,19 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "help", "h": expectNoArg(conf, switch, arg, pass, info) helpOnError(conf, pass) - of "symbolfiles", "incremental": + of "symbolfiles": discard "ignore for backwards compat" + of "incremental": + when not defined(nimIncremental): + localError(conf, info, "the compiler was not built with " & + "incremental compilation features; bootstrap with " & + "-d:nimIncremental to enable") case arg.normalize of "on": conf.symbolFiles = v2Sf of "off": conf.symbolFiles = disabledSf of "writeonly": conf.symbolFiles = writeOnlySf of "readonly": conf.symbolFiles = readOnlySf of "v2": conf.symbolFiles = v2Sf - else: localError(conf, info, "invalid option for --symbolFiles: " & arg) + else: localError(conf, info, "invalid option for --incremental: " & arg) of "skipcfg": expectNoArg(conf, switch, arg, pass, info) incl(conf.globalOptions, optSkipSystemConfigFile) @@ -739,6 +744,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint} of "error": conf.globalOptions = conf.globalOptions + {optStyleError} else: localError(conf, info, errOffHintsError % arg) + of "showallmismatches": + processOnOffSwitchG(conf, {optShowAllMismatches}, arg, pass, info) of "cppcompiletonamespace": if arg.len > 0: conf.cppCustomNamespace = arg @@ -774,6 +781,7 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser; # nim filename.nims is the same as "nim e filename.nims": if p.key.endswith(".nims"): config.command = "e" + incl(config.globalOptions, optWasNimscript) config.projectName = unixToNativePath(p.key) config.arguments = cmdLineRest(p) result = true diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 648dcd8c4..9a4c1701c 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -85,7 +85,8 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasUserErrors") defineSymbol("nimUncheckedArrayTyp") defineSymbol("nimHasTypeof") - + defineSymbol("nimErrorProcCanHaveBody") + defineSymbol("nimHasInstantiationOfInMacro") defineSymbol("nimHasNilSeqs") for f in low(Feature)..high(Feature): defineSymbol("nimHas" & $f) diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index b621e99b9..c515ba1d4 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -261,6 +261,11 @@ proc isLastRead(n: PNode; c: var Con): bool = template interestingSym(s: PSym): bool = s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ) +template isUnpackedTuple(s: PSym): bool = + ## we move out all elements of unpacked tuples, + ## hence unpacked tuples themselves don't need to be destroyed + s.kind == skTemp and s.typ.kind == tyTuple + proc patchHead(n: PNode) = if n.kind in nkCallKinds and n[0].kind == nkSym and n.len > 1: let s = n[0].sym @@ -446,6 +451,13 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = ri2.add pArg(ri[i], c, i < L and parameters[i].kind == tySink) #recurse(ri, ri2) result.add ri2 + of nkBracketExpr: + if ri[0].kind == nkSym and isUnpackedTuple(ri[0].sym): + # unpacking of tuple: move out the elements + result = genSink(c, dest.typ, dest, ri) + else: + result = genCopy(c, dest.typ, dest, ri) + result.add p(ri, c) of nkObjConstr: result = genSink(c, dest.typ, dest, ri) let ri2 = copyTree(ri) @@ -454,6 +466,17 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = # so these all act like 'sink' parameters: ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true) result.add ri2 + of nkTupleConstr: + result = genSink(c, dest.typ, dest, ri) + let ri2 = copyTree(ri) + for i in 0..<ri.len: + # everything that is passed to an tuple constructor is consumed, + # so these all act like 'sink' parameters: + if ri[i].kind == nkExprColonExpr: + ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true) + else: + ri2[i] = pArg(ri[i], c, isSink = true) + result.add ri2 of nkSym: if ri.sym.kind != skParam and isLastRead(ri, c): # Rule 3: `=sink`(x, z); wasMoved(z) @@ -483,7 +506,7 @@ proc p(n: PNode; c: var Con): PNode = if it.kind == nkVarTuple and hasDestructor(ri.typ): let x = lowerTupleUnpacking(c.graph, it, c.owner) result.add p(x, c) - elif it.kind == nkIdentDefs and hasDestructor(it[0].typ): + elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isUnpackedTuple(it[0].sym): for j in 0..L-2: let v = it[j] doAssert v.kind == nkSym diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 4b624e93b..415cc4ab3 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -56,6 +56,7 @@ type inCall, inTryStmt: int blocks: seq[TBlock] tryStmtFixups: seq[TPosition] + owner: PSym proc debugInfo(info: TLineInfo): string = result = $info.line #info.toFilename & ":" & $info.line @@ -259,8 +260,15 @@ proc genRaise(c: var Con; n: PNode) = else: c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len) +proc genImplicitReturn(c: var Con) = + if c.owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter} and resultPos < c.owner.ast.len: + gen(c, c.owner.ast.sons[resultPos]) + proc genReturn(c: var Con; n: PNode) = - if n.sons[0].kind != nkEmpty: gen(c, n.sons[0]) + if n.sons[0].kind != nkEmpty: + gen(c, n.sons[0]) + else: + genImplicitReturn(c) c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len) const @@ -461,11 +469,13 @@ proc dfa(code: seq[Instr]; conf: ConfigRef) = proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) = var c = Con(code: @[], blocks: @[]) gen(c, body) + genImplicitReturn(c) when defined(useDfa) and defined(debugDfa): echoCfg(c.code) dfa(c.code, conf) proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph = ## constructs a control flow graph for ``body``. - var c = Con(code: @[], blocks: @[]) + var c = Con(code: @[], blocks: @[], owner: s) gen(c, body) + genImplicitReturn(c) shallowCopy(result, c.code) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index f5795e1d2..6f61d020d 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -897,7 +897,7 @@ proc genOutFile(d: PDoc): Rope = setIndexTerm(d[], external, "", title) else: # Modules get an automatic title for the HTML, but no entry in the index. - title = "Module " & extractFilename(changeFileExt(d.filename, "")) + title = extractFilename(changeFileExt(d.filename, "")) let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group" elif d.hasToc: "doc.body_toc" diff --git a/compiler/importer.nim b/compiler/importer.nim index 60b7872fe..131b1ad8a 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -100,7 +100,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) = if s.kind != skModule: if s.kind != skEnumField: if s.kind notin ExportableSymKinds: - internalError(c.config, s.info, "importAllSymbols: " & $s.kind) + internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s) if exceptSet.isNil or s.name.id notin exceptSet: rawImportSymbol(c, s) s = nextIter(i, fromMod.tab) diff --git a/compiler/incremental.nim b/compiler/incremental.nim index 47637b3c1..f66a75efd 100644 --- a/compiler/incremental.nim +++ b/compiler/incremental.nim @@ -59,8 +59,8 @@ when nimIncremental: let id = row[0] let fullhash = hashFileCached(conf, fileIdx, AbsoluteFile fullpath) if id.len == 0: - result = int incr.db.insertID(sql"insert into filenames(fullpath, fullhash) values (?, ?)", - fullpath, fullhash) + result = int incr.db.insertID(sql"insert into filenames(nimid, fullpath, fullhash) values (?, ?, ?)", + int(fileIdx), fullpath, fullhash) else: if row[1] != fullhash: incr.db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath) @@ -102,6 +102,7 @@ when nimIncremental: db.exec(sql""" create table if not exists filenames( id integer primary key, + nimid integer not null, fullpath varchar(8000) not null, fullHash varchar(256) not null ); diff --git a/compiler/layouter.nim b/compiler/layouter.nim index f96f88da1..8605ade45 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -30,7 +30,7 @@ type lastTok: TTokType inquote, lastTokWasTerse: bool semicolons: SemicolonKind - col, lastLineNumber, lineSpan, indentLevel, indWidth: int + col, lastLineNumber, lineSpan, indentLevel, indWidth*: int keepIndents*: int doIndentMore*: int content: string @@ -41,9 +41,10 @@ type proc openEmitter*(em: var Emitter, cache: IdentCache; config: ConfigRef, fileIdx: FileIndex) = let fullPath = Absolutefile config.toFullPath(fileIdx) - em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead), - cache, config) - if em.indWidth == 0: em.indWidth = 2 + if em.indWidth == 0: + 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 @@ -245,7 +246,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = wr(TokTypeToStr[tok.tokType]) if not em.inquote: wr(" ") of tkOpr, tkDotDot: - if tok.strongSpaceA == 0 and tok.strongSpaceB == 0: + if (tok.strongSpaceA == 0 and tok.strongSpaceB == 0) or em.inquote: # bug #9504: remember to not spacify a keyword: lastTokWasTerse = true # if not surrounded by whitespace, don't produce any whitespace either: diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 877369c2a..635e6f08d 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -635,7 +635,8 @@ proc handleHexChar(L: var TLexer, xi: var int) = inc(L.bufpos) else: lexMessage(L, errGenerated, - "expected a hex digit, but found: " & L.buf[L.bufpos]) + "expected a hex digit, but found: " & L.buf[L.bufpos] & + " ; maybe prepend with 0") # Need to progress for `nim check` inc(L.bufpos) @@ -966,7 +967,7 @@ proc getPrecedence*(tok: TToken, strongSpaces: bool): int = of '?': result = 2 else: considerAsgn(2) of tkDiv, tkMod, tkShl, tkShr: result = 9 - of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5 + of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs: result = 5 of tkDotDot: result = 6 of tkAnd: result = 4 of tkOr, tkXor, tkPtr, tkRef: result = 3 diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index cd160313c..b1ecf779e 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -41,7 +41,7 @@ type hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, - hintConditionAlwaysTrue, hintName, hintPattern, + hintConditionAlwaysTrue, hintConditionAlwaysFalse, hintName, hintPattern, hintExecuting, hintLinking, hintDependency, hintSource, hintPerformance, hintStackTrace, hintGCStats, hintGlobalVar, @@ -107,6 +107,7 @@ const hintConf: "used config file '$1'", hintPath: "added path: '$1'", hintConditionAlwaysTrue: "condition is always true: '$1'", + hintConditionAlwaysFalse: "condition is always false: '$1'", hintName: "name should be: '$1'", hintPattern: "$1", hintExecuting: "$1", @@ -140,7 +141,7 @@ const "Success", "SuccessX", "CC", "LineTooLong", "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", - "Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency", + "Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency", "Source", "Performance", "StackTrace", "GCStats", "GlobalVar", "User", "UserRaw", "ExtendedContext", ] diff --git a/compiler/lookups.nim b/compiler/lookups.nim index d2e7fdcfa..2fb4e5241 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -168,7 +168,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) = localError(c.config, s.info, "implementation of '$1' expected" % getSymRepr(c.config, s)) inc missingImpls - elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options: + elif {sfUsed, sfExported} * s.flags == {}: if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}: # XXX: implicit type params are currently skTypes # maybe they can be made skGenericParam as well. diff --git a/compiler/main.nim b/compiler/main.nim index 6c8b0343e..6afe57d87 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -15,12 +15,15 @@ when not defined(nimcore): import llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs, os, condsyms, times, - wordrecg, sem, semdata, idents, passes, docgen, extccomp, - cgen, jsgen, json, nversion, + wordrecg, sem, semdata, idents, passes, extccomp, + cgen, json, nversion, platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, - docgen2, parser, modules, ccgutils, sigmatch, ropes, + parser, modules, ccgutils, sigmatch, ropes, modulegraphs, tables, rod, lineinfos, pathutils +when not defined(leanCompiler): + import jsgen, docgen, docgen2 + from magicsys import resetSysTypes proc codegenPass(g: ModuleGraph) = @@ -57,13 +60,14 @@ proc commandCheck(graph: ModuleGraph) = semanticPasses(graph) # use an empty backend for semantic checking only compileProject(graph) -proc commandDoc2(graph: ModuleGraph; json: bool) = - graph.config.errorMax = high(int) # do not stop after first error - semanticPasses(graph) - if json: registerPass(graph, docgen2JsonPass) - else: registerPass(graph, docgen2Pass) - compileProject(graph) - finishDoc2Pass(graph.config.projectName) +when not defined(leanCompiler): + proc commandDoc2(graph: ModuleGraph; json: bool) = + graph.config.errorMax = high(int) # do not stop after first error + semanticPasses(graph) + if json: registerPass(graph, docgen2JsonPass) + else: registerPass(graph, docgen2Pass) + compileProject(graph) + finishDoc2Pass(graph.config.projectName) proc commandCompileToC(graph: ModuleGraph) = let conf = graph.config @@ -84,15 +88,16 @@ proc commandJsonScript(graph: ModuleGraph) = let proj = changeFileExt(graph.config.projectFull, "") extccomp.runJsonBuildInstructions(graph.config, proj) -proc commandCompileToJS(graph: ModuleGraph) = - #incl(gGlobalOptions, optSafeCode) - setTarget(graph.config.target, osJS, cpuJS) - #initDefines() - defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility - defineSymbol(graph.config.symbols, "js") - semanticPasses(graph) - registerPass(graph, JSgenPass) - compileProject(graph) +when not defined(leanCompiler): + proc commandCompileToJS(graph: ModuleGraph) = + #incl(gGlobalOptions, optSafeCode) + setTarget(graph.config.target, osJS, cpuJS) + #initDefines() + defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility + defineSymbol(graph.config.symbols, "js") + semanticPasses(graph) + registerPass(graph, JSgenPass) + compileProject(graph) proc interactivePasses(graph: ModuleGraph) = initDefines(graph.config.symbols) @@ -177,49 +182,76 @@ proc mainCommand*(graph: ModuleGraph) = else: rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc") of "js", "compiletojs": - conf.cmd = cmdCompileToJS - commandCompileToJS(graph) + when defined(leanCompiler): + quit "compiler wasn't built with JS code generator" + else: + conf.cmd = cmdCompileToJS + commandCompileToJS(graph) of "doc0": - wantMainModule(conf) - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - commandDoc(cache, conf) + when defined(leanCompiler): + quit "compiler wasn't built with documentation generator" + else: + wantMainModule(conf) + conf.cmd = cmdDoc + loadConfigs(DocConfig, cache, conf) + commandDoc(cache, conf) of "doc2", "doc": - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - defineSymbol(conf.symbols, "nimdoc") - commandDoc2(graph, false) + when defined(leanCompiler): + quit "compiler wasn't built with documentation generator" + else: + conf.cmd = cmdDoc + loadConfigs(DocConfig, cache, conf) + defineSymbol(conf.symbols, "nimdoc") + commandDoc2(graph, false) of "rst2html": - conf.cmd = cmdRst2html - loadConfigs(DocConfig, cache, conf) - commandRst2Html(cache, conf) + when defined(leanCompiler): + quit "compiler wasn't built with documentation generator" + else: + conf.cmd = cmdRst2html + loadConfigs(DocConfig, cache, conf) + commandRst2Html(cache, conf) of "rst2tex": - conf.cmd = cmdRst2tex - loadConfigs(DocTexConfig, cache, conf) - commandRst2TeX(cache, conf) + when defined(leanCompiler): + quit "compiler wasn't built with documentation generator" + else: + conf.cmd = cmdRst2tex + loadConfigs(DocTexConfig, cache, conf) + commandRst2TeX(cache, conf) of "jsondoc0": - wantMainModule(conf) - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - wantMainModule(conf) - defineSymbol(conf.symbols, "nimdoc") - commandJson(cache, conf) + when defined(leanCompiler): + quit "compiler wasn't built with documentation generator" + else: + wantMainModule(conf) + conf.cmd = cmdDoc + loadConfigs(DocConfig, cache, conf) + wantMainModule(conf) + defineSymbol(conf.symbols, "nimdoc") + commandJson(cache, conf) of "jsondoc2", "jsondoc": - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - wantMainModule(conf) - defineSymbol(conf.symbols, "nimdoc") - commandDoc2(graph, true) + when defined(leanCompiler): + quit "compiler wasn't built with documentation generator" + else: + conf.cmd = cmdDoc + loadConfigs(DocConfig, cache, conf) + wantMainModule(conf) + defineSymbol(conf.symbols, "nimdoc") + commandDoc2(graph, true) of "ctags": - wantMainModule(conf) - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - defineSymbol(conf.symbols, "nimdoc") - commandTags(cache, conf) + when defined(leanCompiler): + quit "compiler wasn't built with documentation generator" + else: + wantMainModule(conf) + conf.cmd = cmdDoc + loadConfigs(DocConfig, cache, conf) + defineSymbol(conf.symbols, "nimdoc") + commandTags(cache, conf) of "buildindex": - conf.cmd = cmdDoc - loadConfigs(DocConfig, cache, conf) - commandBuildIndex(cache, conf) + when defined(leanCompiler): + quit "compiler wasn't built with documentation generator" + else: + conf.cmd = cmdDoc + loadConfigs(DocConfig, cache, conf) + commandBuildIndex(cache, conf) of "gendepend": conf.cmd = cmdGenDepend commandGenDepend(graph) @@ -265,6 +297,7 @@ proc mainCommand*(graph: ModuleGraph) = conf.cmd = cmdInteractive commandInteractive(graph) of "e": + incl conf.globalOptions, optWasNimscript commandEval(graph, mainCommandArg(conf)) of "nop", "help": # prevent the "success" message: diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 16704fab6..d05b301ae 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -63,6 +63,9 @@ type cacheCounters*: Table[string, BiggestInt] cacheTables*: Table[string, BTree[string, PNode]] passes*: seq[TPass] + onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} + onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} + onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} TPassContext* = object of RootObj # the pass's context PPassContext* = ref TPassContext @@ -78,6 +81,32 @@ type proc hash*(x: FileIndex): Hash {.borrow.} +when defined(nimfind): + template onUse*(info: TLineInfo; s: PSym) = + when compiles(c.c.graph): + if c.c.graph.onUsage != nil: c.c.graph.onUsage(c.c.graph, s, info) + else: + if c.graph.onUsage != nil: c.graph.onUsage(c.graph, s, info) + + template onDef*(info: TLineInfo; s: PSym) = + when compiles(c.c.graph): + if c.c.graph.onDefinition != nil: c.c.graph.onDefinition(c.c.graph, s, info) + else: + if c.graph.onDefinition != nil: c.graph.onDefinition(c.graph, s, info) + + template onDefResolveForward*(info: TLineInfo; s: PSym) = + when compiles(c.c.graph): + if c.c.graph.onDefinitionResolveForward != nil: + c.c.graph.onDefinitionResolveForward(c.c.graph, s, info) + else: + if c.graph.onDefinitionResolveForward != nil: + c.graph.onDefinitionResolveForward(c.graph, s, info) + +else: + template onUse*(info: TLineInfo; s: PSym) = discard + template onDef*(info: TLineInfo; s: PSym) = discard + template onDefResolveForward*(info: TLineInfo; s: PSym) = discard + proc stopCompile*(g: ModuleGraph): bool {.inline.} = result = g.doStopCompile != nil and g.doStopCompile() diff --git a/compiler/modules.nim b/compiler/modules.nim index 75e95e453..e2f322561 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -67,6 +67,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P graph.config.mainPackageId = result.owner.id result.id = getModuleId(graph, fileIdx, AbsoluteFile toFullPath(graph.config, fileIdx)) + registerModule(graph, result) discard processModule(graph, result, if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil) elif graph.isDirty(result): @@ -128,6 +129,7 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIDX) = proc makeModule*(graph: ModuleGraph; filename: AbsoluteFile): PSym = result = graph.newModule(fileInfoIdx(graph.config, filename)) result.id = getID() + registerModule(graph, result) proc makeModule*(graph: ModuleGraph; filename: string): PSym = result = makeModule(graph, AbsoluteFile filename) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index dee1081f9..7e6b67cbe 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -190,10 +190,13 @@ template toFullPath*(conf: ConfigRef; info: TLineInfo): string = proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string = if info.fileIndex.int32 < 0: result = "???" - elif optListFullPaths in conf.globalOptions: - result = conf.m.fileInfos[info.fileIndex.int32].fullPath.string + return + let absPath = conf.m.fileInfos[info.fileIndex.int32].fullPath.string + let relPath = conf.m.fileInfos[info.fileIndex.int32].projPath.string + if optListFullPaths in conf.globalOptions: + result = absPath else: - result = conf.m.fileInfos[info.fileIndex.int32].projPath.string + result = if absPath.len < relPath.len: absPath else: relPath proc toLinenumber*(info: TLineInfo): int {.inline.} = result = int info.line diff --git a/compiler/nim.nim b/compiler/nim.nim index 5f3347255..1c4dbd3be 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -54,7 +54,8 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) = of cmdArgument: if processArgument(pass, p, argsCount, config): break if pass == passCmd2: - if optRun notin config.globalOptions and config.arguments.len > 0 and config.command.normalize != "run": + if {optRun, optWasNimscript} * config.globalOptions == {} and + config.arguments.len > 0 and config.command.normalize notin ["run", "e"]: rawMessage(config, errGenerated, errArgsNeedRunOption) proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = diff --git a/compiler/options.nim b/compiler/options.nim index 1280cb59b..80d665d62 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -45,7 +45,7 @@ type # please make sure we have under 32 options TOptions* = set[TOption] TGlobalOption* = enum # **keep binary compatible** gloptNone, optForceFullMake, - optDeadCodeElimUnused, # deprecated, always on + optWasNimscript, optListCmd, optCompileOnly, optNoLinking, optCDebug, # turn on debugging information optGenDynLib, # generate a dynamic library @@ -74,6 +74,7 @@ type # please make sure we have under 32 options optIdeTerse # idetools: use terse descriptions optNoCppExceptions # use C exception handling even with CPP optExcessiveStackTrace # fully qualified module filenames + optShowAllMismatches # show all overloading resolution candidates optWholeProject # for 'doc2': output any dependency optMixedMode # true if some module triggered C++ codegen optListFullPaths @@ -401,7 +402,8 @@ proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc template compilationCachePresent*(conf: ConfigRef): untyped = - conf.symbolFiles in {v2Sf, writeOnlySf} + false +# conf.symbolFiles in {v2Sf, writeOnlySf} template optPreserveOrigSource*(conf: ConfigRef): untyped = optEmbedOrigSrc in conf.globalOptions diff --git a/compiler/parser.nim b/compiler/parser.nim index 02083ca83..54b360a24 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -37,8 +37,7 @@ type TParser* = object # A TParser object represents a file that # is being parsed currInd: int # current indentation level - firstTok, strongSpaces: bool # Has the first token been read? - # Is strongSpaces on? + firstTok: bool # Has the first token been read? hasProgress: bool # some while loop requires progress ensurance lex*: TLexer # The lexer that is used for parsing tok*: TToken # The current token @@ -46,7 +45,7 @@ type inSemiStmtList*: int emptyNode: PNode when defined(nimpretty2): - em: Emitter + em*: Emitter SymbolMode = enum smNormal, smAllowNil, smAfterDot @@ -102,8 +101,7 @@ proc getTok(p: var TParser) = emitTok(p.em, p.lex, p.tok) proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream, - cache: IdentCache; config: ConfigRef; - strongSpaces=false) = + cache: IdentCache; config: ConfigRef) = ## Open a parser, using the given arguments to set up its internal state. ## initToken(p.tok) @@ -112,13 +110,11 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream, openEmitter(p.em, cache, config, fileIdx) getTok(p) # read the first token p.firstTok = true - p.strongSpaces = strongSpaces p.emptyNode = newNode(nkEmpty) proc openParser*(p: var TParser, filename: AbsoluteFile, inputStream: PLLStream, - cache: IdentCache; config: ConfigRef; - strongSpaces=false) = - openParser(p, fileInfoIdx(config, filename), inputStream, cache, config, strongSpaces) + cache: IdentCache; config: ConfigRef) = + openParser(p, fileInfoIdx(config, filename), inputStream, cache, config) proc closeParser(p: var TParser) = ## Close a parser, freeing up its resources. @@ -286,7 +282,7 @@ proc checkBinary(p: TParser) {.inline.} = #| #| prefixOperator = operator #| -#| optInd = COMMENT? +#| optInd = COMMENT? IND? #| optPar = (IND{>} | IND{=})? #| #| simpleExpr = arrowExpr (OP0 optInd arrowExpr)* pragma? @@ -706,8 +702,11 @@ proc namedParams(p: var TParser, callee: PNode, # progress guaranteed exprColonEqExprListAux(p, endTok, result) -proc commandParam(p: var TParser, isFirstParam: var bool): PNode = - result = parseExpr(p) +proc commandParam(p: var TParser, isFirstParam: var bool; mode: TPrimaryMode): PNode = + if mode == pmTypeDesc: + result = simpleExpr(p, mode) + else: + result = parseExpr(p) if p.tok.tokType == tkDo: result = postExprBlocks(p, result) elif p.tok.tokType == tkEquals and not isFirstParam: @@ -780,7 +779,7 @@ proc primarySuffix(p: var TParser, r: PNode, when true: # progress NOT guaranteed p.hasProgress = false - addSon result, commandParam(p, isFirstParam) + addSon result, commandParam(p, isFirstParam, mode) if not p.hasProgress: break else: while p.tok.tokType != tkEof: @@ -798,7 +797,7 @@ proc parseOperators(p: var TParser, headNode: PNode, limit: int, mode: TPrimaryMode): PNode = result = headNode # expand while operators have priorities higher than 'limit' - var opPrec = getPrecedence(p.tok, p.strongSpaces) + var opPrec = getPrecedence(p.tok, false) let modeB = if mode == pmTypeDef: pmTypeDesc else: mode # the operator itself must not start on a new line: # progress guaranteed @@ -815,7 +814,7 @@ proc parseOperators(p: var TParser, headNode: PNode, addSon(a, result) addSon(a, b) result = a - opPrec = getPrecedence(p.tok, p.strongSpaces) + opPrec = getPrecedence(p.tok, false) proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode = result = primary(p, mode) @@ -1255,14 +1254,29 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode = if mode != pmSkipSuffix: result = primarySuffix(p, result, baseInd, mode) +proc binaryNot(p: var TParser; a: PNode): PNode = + if p.tok.tokType == tkNot: + let notOpr = newIdentNodeP(p.tok.ident, p) + getTok(p) + optInd(p, notOpr) + let b = parseExpr(p) + result = newNodeP(nkInfix, p) + result.add notOpr + result.add a + result.add b + else: + result = a + proc parseTypeDesc(p: var TParser): PNode = - #| typeDesc = simpleExpr + #| typeDesc = simpleExpr ('not' expr)? result = simpleExpr(p, pmTypeDesc) + result = binaryNot(p, result) proc parseTypeDefAux(p: var TParser): PNode = - #| typeDefAux = simpleExpr + #| typeDefAux = simpleExpr ('not' expr)? #| | 'concept' typeClass result = simpleExpr(p, pmTypeDef) + result = binaryNot(p, result) proc makeCall(n: PNode): PNode = ## Creates a call if the given node isn't already a call. @@ -1370,12 +1384,12 @@ proc parseExprStmt(p: var TParser): PNode = while true: getTok(p) optInd(p, result) - addSon(result, commandParam(p, isFirstParam)) + addSon(result, commandParam(p, isFirstParam, pmNormal)) if p.tok.tokType != tkComma: break elif p.tok.indent < 0 and isExprStart(p): result = newNode(nkCommand, a.info, @[a]) while true: - addSon(result, commandParam(p, isFirstParam)) + addSon(result, commandParam(p, isFirstParam, pmNormal)) if p.tok.tokType != tkComma: break getTok(p) optInd(p, result) @@ -2236,10 +2250,8 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef; stream.lineOffset = line var parser: TParser - # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong - # spaces... parser.lex.errorHandler = errorHandler - openParser(parser, AbsoluteFile filename, stream, cache, config, false) + openParser(parser, AbsoluteFile filename, stream, cache, config) result = parser.parseAll closeParser(parser) diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index 4873f90d6..703467bc4 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -73,23 +73,6 @@ iterator dirs(x: string): (int, int) = var it: PathIter while hasNext(it, x): yield next(it, x) -when false: - iterator dirs(x: string): (int, int) = - var i = 0 - var first = true - while i < x.len: - let prev = i - if first and x[i] in {DirSep, AltSep}: - # absolute path: - inc i - else: - while i < x.len and x[i] notin {DirSep, AltSep}: inc i - if i > prev: - yield (prev, i-1) - first = false - # skip all separators: - while i < x.len and x[i] in {DirSep, AltSep}: inc i - proc isDot(x: string; bounds: (int, int)): bool = bounds[1] == bounds[0] and x[bounds[0]] == '.' diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 08e3c34d4..ef5223559 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1019,8 +1019,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, else: incl(sym.typ.flags, tfIncompleteStruct) of wUnchecked: noVal(c, it) - if sym.typ == nil: invalidPragma(c, it) - else: incl(sym.typ.flags, tfUncheckedArray) + if sym.typ == nil or sym.typ.kind notin {tyArray, tyUncheckedArray}: + invalidPragma(c, it) + else: + sym.typ.kind = tyUncheckedArray of wUnion: noVal(c, it) if sym.typ == nil: invalidPragma(c, it) @@ -1060,6 +1062,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, invalidPragma(c, it) else: sym.bitsize = expectIntLit(c, it) + if sym.bitsize <= 0: + localError(c.config, it.info, "bitsize needs to be positive") of wGuard: if sym == nil or sym.kind notin {skVar, skLet, skField}: invalidPragma(c, it) diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 07462bb3e..8c4d0d307 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -1,6 +1,6 @@ import - intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils, + intsets, ast, idents, algorithm, renderer, parser, os, strutils, sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables, lineinfos diff --git a/compiler/rod.nim b/compiler/rod.nim index f6fc24ec0..92489ffdd 100644 --- a/compiler/rod.nim +++ b/compiler/rod.nim @@ -22,6 +22,8 @@ when not nimIncremental: template storeRemaining*(g: ModuleGraph; module: PSym) = discard + template registerModule*(g: ModuleGraph; module: PSym) = discard + else: include rodimpl diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim index 839a9c6ca..730328642 100644 --- a/compiler/rodimpl.nim +++ b/compiler/rodimpl.nim @@ -321,6 +321,9 @@ proc encodeSym(g: ModuleGraph, s: PSym, result: var string) = result.add('\16') encodeVInt(s.gcUnsafetyReason.id, result) pushSym(w, s.gcUnsafetyReason) + if s.transformedBody != nil: + result.add('\24') + encodeNode(g, s.info, s.transformedBody, result) of skModule, skPackage: encodeInstantiations(g, s.usedGenerics, result) # we don't serialize: @@ -363,13 +366,7 @@ proc storeType(g: ModuleGraph; t: PType) = db.exec(sql"insert into types(nimid, module, data) values (?, ?, ?)", t.id, mid, buf) -proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) = - if g.config.symbolFiles == disabledSf: return - var buf = newStringOfCap(160) - encodeNode(g, module.info, n, buf) - db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)", - abs(module.id), module.offset, buf) - inc module.offset +proc transitiveClosure(g: ModuleGraph) = var i = 0 while true: if i > 10_000: @@ -388,9 +385,25 @@ proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) = break inc i +proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) = + if g.config.symbolFiles == disabledSf: return + var buf = newStringOfCap(160) + encodeNode(g, module.info, n, buf) + db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)", + abs(module.id), module.offset, buf) + inc module.offset + transitiveClosure(g) + proc recordStmt*(g: ModuleGraph; module: PSym; n: PNode) = storeNode(g, module, n) +proc storeFilename(g: ModuleGraph; fullpath: AbsoluteFile; fileIdx: FileIndex) = + let id = db.getValue(sql"select id from filenames where fullpath = ?", fullpath.string) + if id.len == 0: + let fullhash = hashFileCached(g.config, fileIdx, fullpath) + db.exec(sql"insert into filenames(nimid, fullpath, fullhash) values (?, ?, ?)", + int(fileIdx), fullpath.string, fullhash) + proc storeRemaining*(g: ModuleGraph; module: PSym) = if g.config.symbolFiles == disabledSf: return var stillForwarded: seq[PSym] = @[] @@ -400,6 +413,13 @@ proc storeRemaining*(g: ModuleGraph; module: PSym) = else: stillForwarded.add s swap w.forwardedSyms, stillForwarded + transitiveClosure(g) + var nimid = 0 + for x in items(g.config.m.fileInfos): + # don't store the "command line" entry: + if nimid != 0: + storeFilename(g, x.fullPath, FileIndex(nimid)) + inc nimid # ---------------- decoder ----------------------------------- @@ -725,6 +745,9 @@ proc loadSymFromBlob(g; b; info: TLineInfo): PSym = if b.s[b.pos] == '\16': inc(b.pos) result.gcUnsafetyReason = loadSym(g, decodeVInt(b.s, b.pos), result.info) + if b.s[b.pos] == '\24': + inc b.pos + result.transformedBody = decodeNode(g, b, result.info) of skModule, skPackage: decodeInstantiations(g, b, result.info, result.usedGenerics) of skLet, skVar, skField, skForVar: @@ -752,6 +775,9 @@ proc loadSym(g; id: int; info: TLineInfo): PSym = result = loadSymFromBlob(g, b, info) doAssert id == result.id, "symbol ID is not consistent!" +proc registerModule*(g; module: PSym) = + g.incr.r.syms.add(abs module.id, module) + proc loadModuleSymTab(g; module: PSym) = ## goal: fill module.tab g.incr.r.syms.add(module.id, module) @@ -765,7 +791,8 @@ proc loadModuleSymTab(g; module: PSym) = b.s.add '\0' s = loadSymFromBlob(g, b, module.info) assert s != nil - strTableAdd(module.tab, s) + if s.kind != skField: + strTableAdd(module.tab, s) if sfSystemModule in module.flags: g.systemModule = module @@ -843,8 +870,9 @@ proc replay(g: ModuleGraph; module: PSym; n: PNode) = internalAssert g.config, false of nkImportStmt: for x in n: - internalAssert g.config, x.kind == nkStrLit - let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, AbsoluteFile n[0].strVal)) + internalAssert g.config, x.kind == nkSym + let modpath = AbsoluteFile toFullPath(g.config, x.sym.info) + let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, modpath)) internalAssert g.config, imported.id < 0 of nkStmtList, nkStmtListExpr: for x in n: replay(g, module, x) @@ -868,16 +896,23 @@ proc setupModuleCache*(g: ModuleGraph) = let dbfile = getNimcacheDir(g.config) / RelativeFile"rodfiles.db" if g.config.symbolFiles == writeOnlySf: removeFile(dbfile) + createDir getNimcacheDir(g.config) + let ec = encodeConfig(g) if not fileExists(dbfile): db = open(connection=string dbfile, user="nim", password="", database="nim") createDb(db) - db.exec(sql"insert into config(config) values (?)", encodeConfig(g)) + db.exec(sql"insert into config(config) values (?)", ec) else: db = open(connection=string dbfile, user="nim", password="", database="nim") let oldConfig = db.getValue(sql"select config from config") - g.incr.configChanged = oldConfig != encodeConfig(g) + g.incr.configChanged = oldConfig != ec + # ensure the filename IDs stay consistent: + for row in db.rows(sql"select fullpath, nimid from filenames order by nimid"): + let id = fileInfoIdx(g.config, AbsoluteFile row[0]) + doAssert id.int == parseInt(row[1]) + db.exec(sql"update config set config = ?", ec) db.exec(sql"pragma journal_mode=off") # This MUST be turned off, otherwise it's way too slow even for testing purposes: db.exec(sql"pragma SYNCHRONOUS=off") diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index f94533177..bfff86479 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -123,6 +123,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; cbconf setCommand: conf.command = a.getString 0 let arg = a.getString 1 + incl(conf.globalOptions, optWasNimscript) if arg.len > 0: conf.projectName = arg let path = @@ -158,6 +159,8 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; freshDefines=true; conf: ConfigRef) = rawMessage(conf, hintConf, scriptName.string) + let oldSymbolFiles = conf.symbolFiles + conf.symbolFiles = disabledSf let graph = newModuleGraph(cache, conf) connectCallbacks(graph) @@ -183,3 +186,4 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; #initDefines() undefSymbol(conf.symbols, "nimscript") undefSymbol(conf.symbols, "nimconfig") + conf.symbolFiles = oldSymbolFiles diff --git a/compiler/sem.nim b/compiler/sem.nim index 97a47ceca..775c9f7c9 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -16,13 +16,16 @@ import procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, - semparallel, lowerings, pluginsupport, plugins/active, rod, lineinfos + lowerings, pluginsupport, plugins/active, rod, lineinfos -from modulegraphs import ModuleGraph, PPassContext +from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward when defined(nimfix): import nimfix/prettybase +when not defined(leanCompiler): + import semparallel + # implementation proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.} @@ -447,7 +450,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, pushInfoContext(c.config, nOrig.info, sym.detailedInfo) markUsed(c.config, n.info, sym, c.graph.usageSym) - styleCheckUse(n.info, sym) + onUse(n.info, sym) if sym == c.p.owner: globalError(c.config, n.info, "recursive dependency: '$1'" % sym.name.s) diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 7d6ae70de..3947e4f6c 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -81,8 +81,8 @@ proc genAddr(c: PContext; x: PNode): PNode = addSon(result, x) proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode = - if sfError in op.flags: - localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s) + #if sfError in op.flags: + # localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s) result = newNodeI(nkCall, x.info) result.add newSymNode(op) result.add genAddr(c, x) @@ -121,8 +121,11 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; op = field if op == nil: op = liftBody(c.c, t, c.kind, c.info) - markUsed(c.c.config, c.info, op, c.c.graph.usageSym) - styleCheckUse(c.info, op) + if sfError in op.flags: + incl c.fn.flags, sfError + else: + markUsed(c.c.config, c.info, op, c.c.graph.usageSym) + onUse(c.info, op) body.add newAsgnCall(c.c, op, x, y) result = true @@ -132,7 +135,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = let op = t.destructor if op != nil: markUsed(c.c.config, c.info, op, c.c.graph.usageSym) - styleCheckUse(c.info, op) + onUse(c.info, op) body.add destructorCall(c.c, op, x) result = true of attachedAsgn: @@ -143,7 +146,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = let op = t.deepCopy if op != nil: markUsed(c.c.config, c.info, op, c.c.graph.usageSym) - styleCheckUse(c.info, op) + onUse(c.info, op) body.add newDeepCopyCall(op, x, y) result = true @@ -200,7 +203,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = tyPtr, tyRef, tyOpt, tyUncheckedArray: defaultOp(c, t, body, x, y) of tyArray: - if {tfHasAsgn, tfUncheckedArray} * t.flags == {tfHasAsgn}: + if tfHasAsgn in t.flags: let i = declareCounter(c, body, firstOrd(c.c.config, t)) let whileLoop = genWhileLoop(c, i, x) let elemType = t.lastSon diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 49b344274..7e0ea5490 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -138,6 +138,7 @@ proc effectProblem(f, a: PType; result: var string) = proc renderNotLValue(n: PNode): string = result = $n + let n = if n.kind == nkHiddenDeref: n[0] else: n if n.kind == nkHiddenCallConv and n.len > 1: result = $n[0] & "(" & result & ")" elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2: @@ -166,20 +167,22 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): prefer = preferModuleInfo break - when false: - # we pretend procs are attached to the type of the first - # argument in order to remove plenty of candidates. This is - # comparable to what C# does and C# is doing fine. - var filterOnlyFirst = false + # we pretend procs are attached to the type of the first + # argument in order to remove plenty of candidates. This is + # comparable to what C# does and C# is doing fine. + var filterOnlyFirst = false + if optShowAllMismatches notin c.config.globalOptions: for err in errors: if err.firstMismatch > 1: filterOnlyFirst = true break var candidates = "" + var skipped = 0 for err in errors: - when false: - if filterOnlyFirst and err.firstMismatch == 1: continue + if filterOnlyFirst and err.firstMismatch == 1: + inc skipped + continue if err.sym.kind in routineKinds and err.sym.ast != nil: add(candidates, renderTree(err.sym.ast, {renderNoBody, renderNoComments, renderNoPragmas})) @@ -216,7 +219,9 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): "' is immutable\n") for diag in err.diagnostics: candidates.add(diag & "\n") - + if skipped > 0: + candidates.add($skipped & " other mismatching symbols have been " & + " suppressed; compile with --showAllMismatches:on to see them\n") result = (prefer, candidates) const @@ -390,6 +395,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, args]) proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) = + let a = if a.kind == nkHiddenDeref: a[0] else: a if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym: let s = a.sons[0].sym if s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty: @@ -450,7 +456,7 @@ proc semResolvedCall(c: PContext, x: TCandidate, assert x.state == csMatch var finalCallee = x.calleeSym markUsed(c.config, n.sons[0].info, finalCallee, c.graph.usageSym) - styleCheckUse(n.sons[0].info, finalCallee) + onUse(n.sons[0].info, finalCallee) assert finalCallee.ast != nil if x.hasFauxMatch: result = x.call @@ -558,14 +564,17 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = var newInst = generateInstance(c, s, m.bindings, n.info) newInst.typ.flags.excl tfUnresolved markUsed(c.config, n.info, s, c.graph.usageSym) - styleCheckUse(n.info, s) + onUse(n.info, s) result = newSymNode(newInst, n.info) proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = assert n.kind == nkBracketExpr for i in 1..sonsLen(n)-1: let e = semExpr(c, n.sons[i]) - n.sons[i].typ = e.typ.skipTypes({tyTypeDesc}) + if e.typ == nil: + localError(c.config, e.info, "expression has no type") + else: + n.sons[i].typ = e.typ.skipTypes({tyTypeDesc}) var s = s var a = n.sons[0] if a.kind == nkSym: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 1725d7a31..669862c56 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -25,7 +25,7 @@ const proc semTemplateExpr(c: PContext, n: PNode, s: PSym, flags: TExprFlags = {}): PNode = markUsed(c.config, n.info, s, c.graph.usageSym) - styleCheckUse(n.info, s) + onUse(n.info, s) pushInfoContext(c.config, n.info, s.detailedInfo) result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags) @@ -265,7 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode = let status = checkConvertible(c, result.typ, it.typ) if status in {convOK, convNotNeedeed}: markUsed(c.config, n.info, it.sym, c.graph.usageSym) - styleCheckUse(n.info, it.sym) + onUse(n.info, it.sym) markIndirect(c, it.sym) return it errorUseQualifier(c, n.info, op.sons[0].sym) @@ -614,7 +614,8 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = const FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, - mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy} + mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove, + mWasMoved} # get the real type of the callee # it may be a proc var with a generic alias type, so we skip over them @@ -640,6 +641,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = return for i in countup(1, sonsLen(n) - 1): + let n = if n.kind == nkHiddenDeref: n[0] else: n if n.sons[i].kind == nkHiddenCallConv: # we need to recurse explicitly here as converters can create nested # calls and then they wouldn't be analysed otherwise @@ -1036,7 +1038,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = case s.kind of skConst: markUsed(c.config, n.info, s, c.graph.usageSym) - styleCheckUse(n.info, s) + onUse(n.info, s) case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, tyTuple, tySet, tyUInt..tyUInt64: @@ -1061,7 +1063,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or (n.kind notin nkCallKinds and s.requiredParams > 0): markUsed(c.config, n.info, s, c.graph.usageSym) - styleCheckUse(n.info, s) + onUse(n.info, s) result = symChoice(c, n, s, scClosed) else: result = semMacroExpr(c, n, n, s, flags) @@ -1070,13 +1072,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = (n.kind notin nkCallKinds and s.requiredParams > 0) or sfCustomPragma in sym.flags: markUsed(c.config, n.info, s, c.graph.usageSym) - styleCheckUse(n.info, s) + onUse(n.info, s) result = symChoice(c, n, s, scClosed) else: result = semTemplateExpr(c, n, s, flags) of skParam: markUsed(c.config, n.info, s, c.graph.usageSym) - styleCheckUse(n.info, s) + onUse(n.info, s) if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil: # XXX see the hack in sigmatch.nim ... return s.typ.n @@ -1098,14 +1100,14 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = localError(c.config, n.info, "illegal context for 'nimvm' magic") markUsed(c.config, n.info, s, c.graph.usageSym) - styleCheckUse(n.info, s) + onUse(n.info, s) result = newSymNode(s, n.info) # We cannot check for access to outer vars for example because it's still # not sure the symbol really ends up being used: # var len = 0 # but won't be called # genericThatUsesLen(x) # marked as taking a closure? of skGenericParam: - styleCheckUse(n.info, s) + onUse(n.info, s) if s.typ.kind == tyStatic: result = newSymNode(s, n.info) result.typ = s.typ @@ -1116,7 +1118,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = return n of skType: markUsed(c.config, n.info, s, c.graph.usageSym) - styleCheckUse(n.info, s) + onUse(n.info, s) if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil: return s.typ.n result = newSymNode(s, n.info) @@ -1138,7 +1140,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = # is the access to a public field or in the same module or in a friend? doAssert f == s markUsed(c.config, n.info, f, c.graph.usageSym) - styleCheckUse(n.info, f) + onUse(n.info, f) result = newNodeIT(nkDotExpr, n.info, f.typ) result.add makeDeref(newSymNode(p.selfSym)) result.add newSymNode(f) # we now have the correct field @@ -1151,11 +1153,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = ty = skipTypes(ty.sons[0], skipPtrs) # old code, not sure if it's live code: markUsed(c.config, n.info, s, c.graph.usageSym) - styleCheckUse(n.info, s) + onUse(n.info, s) result = newSymNode(s, n.info) else: markUsed(c.config, n.info, s, c.graph.usageSym) - styleCheckUse(n.info, s) + onUse(n.info, s) result = newSymNode(s, n.info) proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = @@ -1178,7 +1180,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = else: markUsed(c.config, n.sons[1].info, s, c.graph.usageSym) result = semSym(c, n, s, flags) - styleCheckUse(n.sons[1].info, s) + onUse(n.sons[1].info, s) return n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType}) @@ -1241,7 +1243,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result.info = n.info result.typ = ty markUsed(c.config, n.info, f, c.graph.usageSym) - styleCheckUse(n.info, f) + onUse(n.info, f) return of tyObject, tyTuple: if ty.n != nil and ty.n.kind == nkRecList: @@ -1272,7 +1274,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? markUsed(c.config, n.sons[1].info, f, c.graph.usageSym) - styleCheckUse(n.sons[1].info, f) + onUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) # we now have the correct field n.typ = f.typ @@ -1286,7 +1288,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = f = getSymFromList(ty.n, i) if f != nil: markUsed(c.config, n.sons[1].info, f, c.graph.usageSym) - styleCheckUse(n.sons[1].info, f) + onUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) n.typ = f.typ @@ -1538,7 +1540,9 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = # a = b # both are vars, means: a[] = b[] # a = b # b no 'var T' means: a = addr(b) var le = a.typ - if (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and + if le == nil: + localError(c.config, a.info, "expression has no type") + elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and isAssignable(c, a) == arNone) or skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}: # Direct assignment to a discriminant is allowed! @@ -1756,7 +1760,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) markUsed(c.config, n.info, expandedSym, c.graph.usageSym) - styleCheckUse(n.info, expandedSym) + onUse(n.info, expandedSym) if isCallExpr(macroCall): for i in countup(1, macroCall.len-1): @@ -1781,7 +1785,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = let info = macroCall.sons[0].info macroCall.sons[0] = newSymNode(cand, info) markUsed(c.config, info, cand, c.graph.usageSym) - styleCheckUse(info, cand) + onUse(info, cand) # we just perform overloading resolution here: #n.sons[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro}) @@ -1811,6 +1815,7 @@ proc processQuotations(c: PContext; n: var PNode, op: string, ids.add n return + if n.kind == nkPrefix: checkSonsLen(n, 2, c.config) if n[0].kind == nkIdent: @@ -1821,6 +1826,9 @@ proc processQuotations(c: PContext; n: var PNode, op: string, n.sons[0] = newIdentNode(getIdent(c.cache, examinedOp.substr(op.len)), n.info) elif n.kind == nkAccQuoted and op == "``": returnQuote n[0] + elif n.kind == nkIdent: + if n.ident.s == "result": + n = ids[0] for i in 0 ..< n.safeLen: processQuotations(c, n.sons[i], op, quotes, ids) @@ -1832,15 +1840,18 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = var quotedBlock = n[^1] op = if n.len == 3: expectString(c, n[1]) else: "``" - quotes = newSeq[PNode](1) + quotes = newSeq[PNode](2) # the quotes will be added to a nkCall statement - # leave some room for the callee symbol - ids = newSeq[PNode]() + # leave some room for the callee symbol and the result symbol + ids = newSeq[PNode](1) # this will store the generated param names + # leave some room for the result symbol if quotedBlock.kind != nkStmtList: localError(c.config, n.info, errXExpected, "block") + # This adds a default first field to pass the result symbol + ids[0] = newAnonSym(c, skParam, n.info).newSymNode processQuotations(c, quotedBlock, op, quotes, ids) var dummyTemplate = newProcNode( @@ -1859,6 +1870,8 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = var tmpl = semTemplateDef(c, dummyTemplate) quotes[0] = tmpl[namePos] + # This adds a call to newIdentNode("result") as the first argument to the template call + quotes[1] = newNode(nkCall, n.info, @[newIdentNode(getIdent(c.cache, "newIdentNode"), n.info), newStrNode(nkStrLit, "result")]) result = newNode(nkCall, n.info, @[ createMagic(c.graph, "getAst", mExpandToAst).newSymNode, newNode(nkCall, n.info, quotes)]) @@ -2254,6 +2267,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode = n.sons[0] = newSymNode(labl, n.sons[0].info) suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym) styleCheckDef(c.config, labl) + onDef(n[0].info, labl) n.sons[1] = semExpr(c, n.sons[1], flags) n.typ = n.sons[1].typ if isEmptyType(n.typ): n.kind = nkBlockStmt @@ -2332,7 +2346,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = {checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields} var s = qualifiedLookUp(c, n, checks) if c.matchedConcept == nil: semCaptureSym(s, c.p.owner) - result = semSym(c, n, s, flags) if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator}: #performProcvarCheck(c, n, s) result = symChoice(c, n, s, scClosed) @@ -2340,6 +2353,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = markIndirect(c, result.sym) # if isGenericRoutine(result.sym): # localError(c.config, n.info, errInstantiateXExplicitly, s.name.s) + else: + result = semSym(c, n, s, flags) of nkSym: # because of the changed symbol binding, this does not mean that we # don't have to check the symbol for semantics here again! diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 5565e8ed9..5ec702257 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -267,12 +267,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g) of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g) of mDivF64: - if getFloat(b) == 0.0: - if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n, g) - elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n, g) - else: result = newFloatNodeT(Inf, n, g) - else: - result = newFloatNodeT(getFloat(a) / getFloat(b), n, g) + result = newFloatNodeT(getFloat(a) / getFloat(b), n, g) of mMaxF64: if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g) else: result = newFloatNodeT(getFloat(b), n, g) @@ -413,15 +408,14 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode = result = newStrNodeT("console", n, g) proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) = - if tfUncheckedArray notin n.typ.flags: - var err = false - if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}: - err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true) - else: - err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ) - if err: - localError(g.config, n.info, "cannot convert " & $value & - " to " & typeToString(n.typ)) + var err = false + if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}: + err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true) + else: + err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ) + if err: + localError(g.config, n.info, "cannot convert " & $value & + " to " & typeToString(n.typ)) proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode = let dstTyp = skipTypes(n.typ, abstractRange) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index a0044a0af..5972f3b55 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -76,14 +76,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result = symChoice(c, n, s, scOpen) of skTemplate: if macroToExpandSym(s): - styleCheckUse(n.info, s) + onUse(n.info, s) result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) else: result = symChoice(c, n, s, scOpen) of skMacro: if macroToExpandSym(s): - styleCheckUse(n.info, s) + onUse(n.info, s) result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) else: @@ -96,20 +96,20 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result = n else: result = newSymNodeTypeDesc(s, n.info) - styleCheckUse(n.info, s) + onUse(n.info, s) of skParam: result = n - styleCheckUse(n.info, s) + onUse(n.info, s) of skType: if (s.typ != nil) and (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}): result = newSymNodeTypeDesc(s, n.info) else: result = n - styleCheckUse(n.info, s) + onUse(n.info, s) else: result = newSymNode(s, n.info) - styleCheckUse(n.info, s) + onUse(n.info, s) proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx): PNode = @@ -172,6 +172,7 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) = let s = newSymS(skUnknown, getIdentNode(c, n), c) addPrelimDecl(c, s) styleCheckDef(c.config, n.info, s, kind) + onDef(n.info, s) proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx): PNode = @@ -230,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode, case s.kind of skMacro: if macroToExpand(s) and sc.safeLen <= 1: - styleCheckUse(fn.info, s) + onUse(fn.info, s) result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, flags, ctx) else: @@ -239,7 +240,7 @@ proc semGenericStmt(c: PContext, n: PNode, mixinContext = true of skTemplate: if macroToExpand(s) and sc.safeLen <= 1: - styleCheckUse(fn.info, s) + onUse(fn.info, s) result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, flags, ctx) else: @@ -262,17 +263,17 @@ proc semGenericStmt(c: PContext, n: PNode, inc first of skGenericParam: result.sons[0] = newSymNodeTypeDesc(s, fn.info) - styleCheckUse(fn.info, s) + onUse(fn.info, s) first = 1 of skType: # bad hack for generics: if (s.typ != nil) and (s.typ.kind != tyGenericParam): result.sons[0] = newSymNodeTypeDesc(s, fn.info) - styleCheckUse(fn.info, s) + onUse(fn.info, s) first = 1 else: result.sons[0] = newSymNode(s, fn.info) - styleCheckUse(fn.info, s) + onUse(fn.info, s) first = 1 elif fn.kind == nkDotExpr: result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 09d971236..2aae562f9 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -306,7 +306,13 @@ proc semOf(c: PContext, n: PNode): PNode = result.typ = getSysType(c.graph, n.info, tyBool) return result elif diff == high(int): - localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a)) + if commonSuperclass(a, b) == nil: + localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a)) + else: + message(c.config, n.info, hintConditionAlwaysFalse, renderTree(n)) + result = newIntNode(nkIntLit, 0) + result.info = n.info + result.typ = getSysType(c.graph, n.info, tyBool) else: localError(c.config, n.info, "'of' takes 2 arguments") n.typ = getSysType(c.graph, n.info, tyBool) @@ -329,23 +335,19 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, of mTypeOf: result = semTypeOf(c, n) of mSizeOf: - # TODO there is no proper way to find out if a type cannot be queried for the size. - let size = getSize(c.config, n[1].typ) - # We just assume here that the type might come from the c backend - if size == szUnknownSize: - # Forward to the c code generation to emit a `sizeof` in the C code. - result = n - elif size >= 0: - result = newIntNode(nkIntLit, size) - result.info = n.info - result.typ = n.typ - else: - - localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely") - - result = nil - - + # TODO there is no proper way to find out if a type cannot be queried for the size. + let size = getSize(c.config, n[1].typ) + # We just assume here that the type might come from the c backend + if size == szUnknownSize: + # Forward to the c code generation to emit a `sizeof` in the C code. + result = n + elif size >= 0: + result = newIntNode(nkIntLit, size) + result.info = n.info + result.typ = n.typ + else: + localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely") + result = n of mAlignOf: result = newIntNode(nkIntLit, getAlign(c.config, n[1].typ)) result.info = n.info diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index c1bdb08a8..0317fd8ba 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -9,9 +9,12 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - wordrecg, strutils, options, guards, writetracking, lineinfos, semfold, + wordrecg, strutils, options, guards, lineinfos, semfold, modulegraphs +when not defined(leanCompiler): + import writetracking + when defined(useDfa): import dfa @@ -713,7 +716,7 @@ proc track(tracked: PEffects, n: PNode) = track(tracked, n.sons[i]) of nkCallKinds: if getConstExpr(tracked.owner_module, n, tracked.graph) != nil: - return + return # p's effects are ours too: var a = n.sons[0] let op = a.typ diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5c7f866ce..1f2b9f0b3 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -41,8 +41,13 @@ proc semDiscard(c: PContext, n: PNode): PNode = checkSonsLen(n, 1, c.config) if n.sons[0].kind != nkEmpty: n.sons[0] = semExprWithType(c, n.sons[0]) - if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone or n.sons[0].kind == nkTypeOfExpr: + let sonType = n.sons[0].typ + let sonKind = n.sons[0].kind + if isEmptyType(sonType) or sonType.kind == tyNone or n.sons[0].kind == nkTypeOfExpr: localError(c.config, n.info, errInvalidDiscard) + if sonType.kind == tyProc and sonKind notin nkCallKinds: + # tyProc is disallowed to prevent ``discard foo`` to be valid, when ``discard foo()`` is meant. + localError(c.config, n.info, "illegal discard proc, did you mean: " & $n[0] & "()") proc semBreakOrContinue(c: PContext, n: PNode): PNode = result = n @@ -61,7 +66,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = incl(s.flags, sfUsed) n.sons[0] = x suggestSym(c.config, x.info, s, c.graph.usageSym) - styleCheckUse(x.info, s) + onUse(x.info, s) else: localError(c.config, n.info, errInvalidControlFlowX % s.name.s) else: @@ -359,6 +364,7 @@ proc semUsing(c: PContext; n: PNode): PNode = for j in countup(0, length-3): let v = semIdentDef(c, a.sons[j], skParam) styleCheckDef(c.config, v) + onDef(a[j].info, v) v.typ = typ strTableIncl(c.signatures, v) else: @@ -490,6 +496,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = continue var v = semIdentDef(c, a.sons[j], symkind) styleCheckDef(c.config, v) + onDef(a[j].info, v) if sfGenSym notin v.flags and not isDiscardUnderscore(v): addInterfaceDecl(c, v) when oKeepVariableNames: @@ -544,6 +551,7 @@ proc semConst(c: PContext, n: PNode): PNode = checkSonsLen(a, 3, c.config) var v = semIdentDef(c, a.sons[0], skConst) styleCheckDef(c.config, v) + onDef(a[0].info, v) var typ: PType = nil if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil) @@ -587,6 +595,7 @@ proc symForVar(c: PContext, n: PNode): PSym = let m = if n.kind == nkPragmaExpr: n.sons[0] else: n result = newSymG(skForVar, m, c) styleCheckDef(c.config, result) + onDef(n.info, result) if n.kind == nkPragmaExpr: pragma(c, result, n.sons[1], forVarPragmas) @@ -692,7 +701,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode = if r.state == csMatch: var match = r.calleeSym markUsed(c.config, n[0].info, match, c.graph.usageSym) - styleCheckUse(n[0].info, match) + onUse(n[0].info, match) # but pass 'n' to the 'match' macro, not 'n[0]': r.call.sons[1] = n @@ -876,6 +885,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = if typsym.isNil: s = semIdentDef(c, name[1], skType) styleCheckDef(c.config, s) + onDef(name[1].info, s) s.typ = newTypeS(tyObject, c) s.typ.sym = s s.flags.incl sfForward @@ -890,6 +900,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = else: s = semIdentDef(c, name, skType) styleCheckDef(c.config, s) + onDef(name.info, s) s.typ = newTypeS(tyForward, c) s.typ.sym = s # process pragmas: if name.kind == nkPragmaExpr: @@ -1621,6 +1632,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, else: implicitPragmas(c, s, n, validPragmas) styleCheckDef(c.config, s) + onDef(n[namePos].info, s) else: if n.sons[pragmasPos].kind != nkEmpty: pragma(c, s, n.sons[pragmasPos], validPragmas) @@ -1634,6 +1646,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX % ("'" & proto.name.s & "' from " & c.config$proto.info)) styleCheckDef(c.config, s) + onDefResolveForward(n[namePos].info, proto) if sfForward notin proto.flags and proto.magic == mNone: wrongRedefinition(c, n.info, proto.name.s, proto.info) excl(proto.flags, sfForward) @@ -1666,7 +1679,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, localError(c.config, n.info, "the overloaded " & s.name.s & " operator has to be enabled with {.experimental: \"callOperator\".}") - if n.sons[bodyPos].kind != nkEmpty: + if n.sons[bodyPos].kind != nkEmpty and sfError notin s.flags: # for DLL generation it is annoying to check for sfImportc! if sfBorrow in s.flags: localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index a64315037..14507cf9d 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -64,6 +64,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode = # for instance 'nextTry' is both in tables.nim and astalgo.nim ... result = newSymNode(s, n.info) markUsed(c.config, n.info, s, c.graph.usageSym) + onUse(n.info, s) else: # semantic checking requires a type; ``fitNode`` deals with it # appropriately @@ -75,6 +76,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode = if a.kind != skModule: incl(a.flags, sfUsed) addSon(result, newSymNode(a, n.info)) + onUse(n.info, a) a = nextOverloadIter(o, c, n) proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode = @@ -160,7 +162,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and s.kind == skParam: incl(s.flags, sfUsed) result = newSymNode(s, n.info) - styleCheckUse(n.info, s) + onUse(n.info, s) else: for i in 0 ..< n.safeLen: result.sons[i] = onlyReplaceParams(c, n.sons[i]) @@ -208,19 +210,20 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = # So we need only check the *current* scope. let s = localSearchInScope(c.c, considerQuotedIdent(c.c, ident)) if s != nil and s.owner == c.owner and sfGenSym in s.flags: - styleCheckUse(n.info, s) + onUse(n.info, s) replaceIdentBySym(c.c, n, newSymNode(s, n.info)) elif not (n.kind == nkSym and sfGenSym in n.sym.flags): let local = newGenSym(k, ident, c) addPrelimDecl(c.c, local) styleCheckDef(c.c.config, n.info, local) + onDef(n.info, local) replaceIdentBySym(c.c, n, newSymNode(local, n.info)) else: replaceIdentBySym(c.c, n, ident) proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode = incl(s.flags, sfUsed) - # we do not call styleCheckUse here, as the identifier is not really + # we do not call onUse here, as the identifier is not really # resolved here. We will fixup the used identifiers later. case s.kind of skUnknown: @@ -245,7 +248,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags): incl(s.flags, sfUsed) result = newSymNode(s, n.info) - styleCheckUse(n.info, s) + onUse(n.info, s) else: for i in countup(0, safeLen(n) - 1): result.sons[i] = semRoutineInTemplName(c, n.sons[i]) @@ -261,6 +264,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode = s.ast = n addPrelimDecl(c.c, s) styleCheckDef(c.c.config, n.info, s) + onDef(n.info, s) n.sons[namePos] = newSymNode(s, n.sons[namePos].info) else: n.sons[namePos] = ident @@ -314,7 +318,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and s.kind == skParam: incl(s.flags, sfUsed) result = newSymNode(s, n.info) - styleCheckUse(n.info, s) + onUse(n.info, s) elif contains(c.toBind, s.id): result = symChoice(c.c, n, s, scClosed) elif contains(c.toMixin, s.name.id): @@ -324,7 +328,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = # var yz: T incl(s.flags, sfUsed) result = newSymNode(s, n.info) - styleCheckUse(n.info, s) + onUse(n.info, s) else: result = semTemplSymbol(c.c, n, s) of nkBind: @@ -382,6 +386,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = let s = newGenSym(skLabel, n.sons[0], c) addPrelimDecl(c.c, s) styleCheckDef(c.c.config, s) + onDef(n[0].info, s) n.sons[0] = newSymNode(s, n.sons[0].info) n.sons[1] = semTemplBody(c, n.sons[1]) closeScope(c) @@ -505,7 +510,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and s.kind == skParam and n.kind == nkAccQuoted and n.len == 1: incl(s.flags, sfUsed) - styleCheckUse(n.info, s) + onUse(n.info, s) return newSymNode(s, n.info) elif contains(c.toBind, s.id): return symChoice(c.c, n, s, scClosed) @@ -553,6 +558,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = else: s = semIdentVis(c, skTemplate, n.sons[0], {}) styleCheckDef(c.config, s) + onDef(n[0].info, s) # check parameter list: #s.scope = c.currentScope pushOwner(c, s) @@ -635,7 +641,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = # semtypes.addParamOrResult). Within the pattern we have to ensure # to use the param with the proper type though: incl(s.flags, sfUsed) - styleCheckUse(n.info, s) + onUse(n.info, s) let x = c.owner.typ.n.sons[s.position+1].sym assert x.name == s.name result = newSymNode(x, n.info) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 5215a1d11..f4a1b0302 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -122,6 +122,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = if not isPure: strTableAdd(c.module.tab, e) addSon(result.n, newSymNode(e)) styleCheckDef(c.config, e) + onDef(e.info, e) if sfGenSym notin e.flags: if not isPure: addDecl(c, e) else: importPureEnumField(c, e) @@ -377,7 +378,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) if result != nil: markUsed(c.config, n.info, result, c.graph.usageSym) - styleCheckUse(n.info, result) + onUse(n.info, result) if result.kind == skParam and result.typ.kind == tyTypeDesc: # This is a typedesc param. is it already bound? @@ -466,6 +467,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = addSon(result.n, newSymNode(field)) addSonSkipIntLit(result, typ) styleCheckDef(c.config, a.sons[j].info, field) + onDef(field.info, field) if result.n.len == 0: result.n = nil proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, @@ -688,7 +690,6 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, else: rectype.sym for i in countup(0, sonsLen(n)-3): var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported}) - styleCheckDef(c.config, n.sons[i].info, f) suggestSym(c.config, n.sons[i].info, f, c.graph.usageSym) f.typ = typ f.position = pos @@ -703,6 +704,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, if a.kind == nkEmpty: addSon(father, newSymNode(f)) else: addSon(a, newSymNode(f)) styleCheckDef(c.config, f) + onDef(f.info, f) if a.kind != nkEmpty: addSon(father, a) of nkSym: # This branch only valid during generic object @@ -988,7 +990,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyGenericParam: markUsed(c.config, info, paramType.sym, c.graph.usageSym) - styleCheckUse(info, paramType.sym) + onUse(info, paramType.sym) if tfWildcard in paramType.flags: paramType.flags.excl tfWildcard paramType.sym.kind = skType @@ -1110,6 +1112,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, rawAddSon(result, finalType) addParamOrResult(c, arg, kind) styleCheckDef(c.config, a.sons[j].info, arg) + onDef(a[j].info, arg) var r: PType if n.sons[0].kind != nkEmpty: @@ -1621,8 +1624,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = prev of nkSym: let s = getGenSym(c, n.sym) - if s.kind == skType and s.typ != nil or - s.kind == skParam and s.typ.kind == tyTypeDesc: + if s.typ != nil and (s.kind == skType or s.typ.kind == tyTypeDesc): var t = if s.kind == skType: s.typ @@ -1638,7 +1640,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = assignType(prev, t) result = prev markUsed(c.config, n.info, n.sym, c.graph.usageSym) - styleCheckUse(n.info, n.sym) + onUse(n.info, n.sym) else: if s.kind != skError: localError(c.config, n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) @@ -1745,10 +1747,8 @@ proc processMagicType(c: PContext, m: PSym) = setMagicType(c.config, m, tyAnything, 0) else: setMagicType(c.config, m, tyExpr, 0) - if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt of mStmt: setMagicType(c.config, m, tyStmt, 0) - if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt of mTypeDesc, mType: setMagicType(c.config, m, tyTypeDesc, 0) rawAddSon(m.typ, newTypeS(tyNone, c)) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index be6ffc586..b05fb37ae 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -30,11 +30,6 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) = localError(conf, info, "type 'var var' is not allowed") elif computeSize(conf, t) == szIllegalRecursion: localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'") - - t = typ.skipTypes({tyGenericInst}) - if t.kind == tyArray and tfUncheckedArray in t.flags: - t[0].flags.incl tfUncheckedArray # mark range of unchecked array also unchecked - when false: if t.kind == tyObject and t.sons[0] != nil: if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 4dc7690ef..4adf0bed3 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -13,9 +13,9 @@ import intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees, - linter, lineinfos + linter, lineinfos, lowerings, modulegraphs -when defined(booting) or defined(nimsuggest): +when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler): import docgen type @@ -1210,9 +1210,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, if f.kind == tyVarargs: if tfVarargs in a.flags: return typeRel(c, f.base, a.lastSon) - if tfOldSchoolExprStmt in f.sons[0].flags: - if f.sons[0].kind == tyExpr: return - elif f.sons[0].kind == tyStmt: return + if f.sons[0].kind == tyStmt: return template matchArrayOrSeq(aBase: PType) = let ff = f.base @@ -1758,7 +1756,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, result = isNone of tyStmt: - if aOrig != nil and tfOldSchoolExprStmt notin f.flags: + if aOrig != nil: put(c, f, aOrig) result = isGeneric @@ -1857,8 +1855,14 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, else: param = copyTree(arg) addSon(result, param) + + if dest.kind in {tyVar, tyLent}: + dest.flags.incl tfVarIsPtr + result = newDeref(result) + inc(m.convMatches) - m.genericConverter = srca == isGeneric or destIsGeneric + if m.genericConverter == false: + m.genericConverter = srca == isGeneric or destIsGeneric return result proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, @@ -2151,7 +2155,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, else: # only one valid interpretation found: markUsed(m.c.config, arg.info, arg.sons[best].sym, m.c.graph.usageSym) - styleCheckUse(arg.info, arg.sons[best].sym) + onUse(arg.info, arg.sons[best].sym) result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], argOrig) when false: @@ -2215,8 +2219,7 @@ proc incrIndexType(t: PType) = inc t.sons[0].n.sons[1].intVal template isVarargsUntyped(x): untyped = - x.kind == tyVarargs and x.sons[0].kind == tyExpr and - tfOldSchoolExprStmt notin x.sons[0].flags + x.kind == tyVarargs and x.sons[0].kind == tyExpr proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var IntSet) = diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 573b27094..4791788fa 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -1,3 +1,12 @@ +# +# +# The Nim Compiler +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# +## code owner: Arne Döring +## e-mail: arne.doering@gmx.net proc align(address, alignment: BiggestInt): BiggestInt = result = (address + (alignment - 1)) and not (alignment - 1) @@ -118,9 +127,14 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOffset: result.offset = align(offset, result.align) of nkSym: - computeSizeAlign(conf, n.sym.typ) - let size = n.sym.typ.size - let align = n.sym.typ.align + var size = szUnknownSize + var align = szUnknownSize + + if n.sym.bitsize == 0: # 0 represents bitsize not set + computeSizeAlign(conf, n.sym.typ) + size = n.sym.typ.size.int + align = n.sym.typ.align.int + result.align = align if initialOffset == szUnknownSize or size == szUnknownSize: n.sym.offset = szUnknownSize @@ -309,16 +323,24 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = var headerAlign: int16 if typ.sons[0] != nil: # compute header size - var st = typ.sons[0] - while st.kind in skipPtrs: - st = st.sons[^1] - computeSizeAlign(conf, st) - if st.size == szIllegalRecursion: - typ.size = st.size - typ.align = st.align - return - headerSize = st.size - headerAlign = st.align + + if conf.cmd == cmdCompileToCpp: + # if the target is C++ the members of this type are written + # into the padding byets at the end of the parent type. At the + # moment it is not supported to calculate that. + headerSize = szUnknownSize + headerAlign = szUncomputedSize + else: + var st = typ.sons[0] + while st.kind in skipPtrs: + st = st.sons[^1] + computeSizeAlign(conf, st) + if st.size == szIllegalRecursion: + typ.size = st.size + typ.align = st.align + return + headerSize = st.size + headerAlign = st.align elif isObjectWithTypeFieldPredicate(typ): # this branch is taken for RootObj headerSize = conf.target.intSize diff --git a/compiler/suggest.nim b/compiler/suggest.nim index b264415d8..dfa6e5ddb 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -115,7 +115,7 @@ proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info result.forth = typeToString(s.typ) else: result.forth = "" - when defined(nimsuggest) and not defined(noDocgen): + when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): result.doc = s.extractDocComment let infox = if section in {ideUse, ideHighlight, ideOutline}: info else: s.info result.filePath = toFullPath(conf, infox) @@ -153,7 +153,7 @@ proc `$`*(suggest: Suggest): string = result.add(sep) result.add($suggest.column) result.add(sep) - when defined(nimsuggest) and not defined(noDocgen): + when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): result.add(suggest.doc.escape) if suggest.version == 0: result.add(sep) diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index decdf1715..60246b9bf 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -17,10 +17,10 @@ type TFilterKind* = enum filtNone, filtTemplate, filtReplace, filtStrip TParserKind* = enum - skinStandard, skinStrongSpaces, skinEndX + skinStandard, skinEndX const - parserNames*: array[TParserKind, string] = ["standard", "strongspaces", + parserNames*: array[TParserKind, string] = ["standard", "endx"] filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace", "strip"] @@ -34,14 +34,14 @@ template config(p: TParsers): ConfigRef = p.parser.lex.config proc parseAll*(p: var TParsers): PNode = case p.skin - of skinStandard, skinStrongSpaces: + of skinStandard: result = parser.parseAll(p.parser) of skinEndX: internalError(p.config, "parser to implement") proc parseTopLevelStmt*(p: var TParsers): PNode = case p.skin - of skinStandard, skinStrongSpaces: + of skinStandard: result = parser.parseTopLevelStmt(p.parser) of skinEndX: internalError(p.config, "parser to implement") @@ -153,21 +153,23 @@ proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream; else: s = inputstream case p.skin of skinStandard, skinEndX: - parser.openParser(p.parser, fileIdx, s, cache, config, false) - of skinStrongSpaces: - parser.openParser(p.parser, fileIdx, s, cache, config, true) + parser.openParser(p.parser, fileIdx, s, cache, config) proc closeParsers*(p: var TParsers) = parser.closeParser(p.parser) -proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} = - var - p: TParsers - f: File +proc setupParsers*(p: var TParsers; fileIdx: FileIndex; cache: IdentCache; + config: ConfigRef): bool = + var f: File let filename = toFullPathConsiderDirty(config, fileIdx) if not open(f, filename.string): rawMessage(config, errGenerated, "cannot open file: " & filename.string) - return + return false openParsers(p, fileIdx, llStreamOpen(f), cache, config) - result = parseAll(p) - closeParsers(p) + result = true + +proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} = + var p: TParsers + if setupParsers(p, fileIdx, cache, config): + result = parseAll(p) + closeParsers(p) diff --git a/compiler/transf.nim b/compiler/transf.nim index 800d56b3a..7b2979dea 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -24,7 +24,8 @@ import sempass2, lowerings, destroyer, liftlocals, modulegraphs, lineinfos -proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode +proc transformBody*(g: ModuleGraph, prc: PSym, cache = true; + noDestructors = false): PNode import closureiters, lambdalifting @@ -48,7 +49,7 @@ type inlining: int # > 0 if we are in inlining context (copy vars) nestedProcs: int # > 0 if we are in a nested proc contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' - deferDetected, tooEarly, needsDestroyPass: bool + deferDetected, tooEarly, needsDestroyPass, noDestructors: bool graph: ModuleGraph PTransf = ref TTransfContext @@ -130,7 +131,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = let s = n.sym if s.typ != nil and s.typ.callConv == ccClosure: if s.kind in routineKinds: - discard transformBody(c.graph, s) + discard transformBody(c.graph, s, true, c.noDestructors) if s.kind == skIterator: if c.tooEarly: return n else: return liftIterSym(c.graph, n, getCurrOwner(c)) @@ -159,7 +160,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = return tc = tc.next result = b - + proc transformSym(c: PTransf, n: PNode): PTransNode = result = PTransNode(transformSymAux(c, n)) @@ -243,7 +244,7 @@ proc newLabel(c: PTransf, n: PNode): PSym = result.name = getIdent(c.graph.cache, genPrefix & $result.id) proc transformBlock(c: PTransf, n: PNode): PTransNode = - var labl: PSym + var labl: PSym if c.inlining > 0: labl = newLabel(c, n[0]) idNodeTablePut(c.transCon.mapping, n[0].sym, newSymNode(labl)) @@ -611,7 +612,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode)) idNodeTablePut(newC.mapping, formal, temp) - let body = transformBody(c.graph, iter) + let body = transformBody(c.graph, iter, true, c.noDestructors) pushInfoContext(c.graph.config, n.info) inc(c.inlining) add(stmtList, transform(c, body)) @@ -1029,7 +1030,8 @@ template liftDefer(c, root) = if c.deferDetected: liftDeferAux(root) -proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode = +proc transformBody*(g: ModuleGraph, prc: PSym, cache = true; + noDestructors = false): PNode = assert prc.kind in routineKinds if prc.transformedBody != nil: @@ -1037,22 +1039,22 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode = elif nfTransf in prc.ast[bodyPos].flags or prc.kind in {skTemplate}: result = prc.ast[bodyPos] else: - prc.transformedBody = newNode(nkEmpty) # protects from recursion var c = openTransf(g, prc.getModule, "") + c.noDestructors = noDestructors result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly) result = processTransf(c, result, prc) liftDefer(c, result) result = liftLocalsIfRequested(prc, result, g.cache, g.config) - if c.needsDestroyPass: #and newDestructors: + if c.needsDestroyPass and not noDestructors: result = injectDestructorCalls(g, prc, result) if prc.isIterator: result = g.transformClosureIterator(prc, result) - + incl(result.flags, nfTransf) - let cache = cache or prc.typ.callConv == ccInline + let cache = cache or prc.typ.callConv == ccInline if cache: # genProc for inline procs will be called multiple times from diffrent modules, # it is important to transform exactly once to get sym ids and locations right @@ -1072,7 +1074,8 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode = result = injectDestructorCalls(g, module, result) incl(result.flags, nfTransf) -proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode = +proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode; + noDestructors = false): PNode = if nfTransf in n.flags: result = n else: @@ -1081,6 +1084,6 @@ proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode = liftDefer(c, result) # expressions are not to be injected with destructor calls as that # the list of top level statements needs to be collected before. - if c.needsDestroyPass: + if c.needsDestroyPass and not noDestructors: result = injectDestructorCalls(g, module, result) incl(result.flags, nfTransf) diff --git a/compiler/types.nim b/compiler/types.nim index 5b14015c1..b163ca4e9 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1086,8 +1086,8 @@ proc inheritanceDiff*(a, b: PType): int = # | returns: +x iff `a` is the x'th direct subclass of `b` # | returns: `maxint` iff `a` and `b` are not compatible at all if a == b or a.kind == tyError or b.kind == tyError: return 0 - assert a.kind == tyObject - assert b.kind == tyObject + assert a.kind in {tyObject} + skipPtrs + assert b.kind in {tyObject} + skipPtrs var x = a result = 0 while x != nil: diff --git a/compiler/vm.nim b/compiler/vm.nim index 05ee3b90e..7e7ec8903 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -503,7 +503,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcAsgnFloat64FromInt: let rb = instr.regB ensureKind(rkFloat) - regs[ra].floatVal = cast[float64](int64(regs[rb].intVal)) + regs[ra].floatVal = cast[float64](int64(regs[rb].intVal)) of opcAsgnComplex: asgnComplex(regs[ra], regs[instr.regB]) of opcAsgnRef: @@ -945,10 +945,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let a = regs[rb].node if a.kind == nkSym: regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit) - else: + else: let ast = a.sym.ast.shallowCopy for i in 0..<a.sym.ast.len: - ast[i] = a.sym.ast[i] + ast[i] = a.sym.ast[i] ast[bodyPos] = transformBody(c.graph, a.sym) ast.copyTree() of opcSymOwner: @@ -960,6 +960,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].node.flags.incl nfIsRef else: stackTrace(c, tos, pc, "node is not a symbol") + of opcSymIsInstantiationOf: + decodeBC(rkInt) + let a = regs[rb].node + let b = regs[rc].node + if a.kind == nkSym and a.sym.kind in skProcKinds and + b.kind == nkSym and b.sym.kind in skProcKinds: + regs[ra].intVal = + if sfFromGeneric in a.sym.flags and a.sym.owner == b.sym: 1 + else: 0 + else: + stackTrace(c, tos, pc, "node is not a proc symbol") of opcEcho: let rb = instr.regB if rb == 1: @@ -1228,7 +1239,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcOf: decodeBC(rkInt) let typ = c.types[regs[rc].intVal.int] - regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) >= 0) + regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) <= 0) of opcIs: decodeBC(rkInt) let t1 = regs[rb].node.typ.skipTypes({tyTypeDesc}) @@ -1822,7 +1833,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = "NimScript: attempt to call non-routine: " & sym.name.s) proc evalStmt*(c: PCtx, n: PNode) = - let n = transformExpr(c.graph, c.module, n) + let n = transformExpr(c.graph, c.module, n, noDestructors = true) let start = genStmt(c, n) # execute new instructions; this redundant opcEof check saves us lots # of allocations in 'execute': @@ -1830,7 +1841,7 @@ proc evalStmt*(c: PCtx, n: PNode) = discard execute(c, start) proc evalExpr*(c: PCtx, n: PNode): PNode = - let n = transformExpr(c.graph, c.module, n) + let n = transformExpr(c.graph, c.module, n, noDestructors = true) let start = genExpr(c, n) assert c.code[start].opcode != opcEof result = execute(c, start) @@ -1877,7 +1888,7 @@ const evalPass* = makePass(myOpen, myProcess, myClose) proc evalConstExprAux(module: PSym; g: ModuleGraph; prc: PSym, n: PNode, mode: TEvalMode): PNode = - let n = transformExpr(g, module, n) + let n = transformExpr(g, module, n, noDestructors = true) setupGlobalCtx(module, g) var c = PCtx g.vm let oldMode = c.mode diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 25ace3cdd..493078f74 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -147,7 +147,8 @@ type opcTypeTrait, opcMarshalLoad, opcMarshalStore, opcToNarrowInt, - opcSymOwner + opcSymOwner, + opcSymIsInstantiationOf TBlock* = object label*: PSym diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 8aac5fb87..f160a3096 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -157,7 +157,10 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; of tyObject: if inst: result = newNodeX(nkObjectTy) - result.add t.sym.ast[2][0].copyTree # copy object pragmas + if t.sym.ast != nil: + result.add t.sym.ast[2][0].copyTree # copy object pragmas + else: + result.add newNodeI(nkEmpty, info) if t.sons[0] == nil: result.add newNodeI(nkEmpty, info) else: # handle parent object diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index ea0fb35ff..e52f460d2 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -182,7 +182,10 @@ const HighRegisterPressure = 40 proc bestEffort(c: PCtx): TLineInfo = - (if c.prc == nil: c.module.info else: c.prc.sym.info) + if c.prc != nil and c.prc.sym != nil: + c.prc.sym.info + else: + c.module.info proc getTemp(cc: PCtx; tt: PType): TRegister = let typ = tt.skipTypesOrNil({tyStatic}) @@ -776,7 +779,7 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) = let src = n.sons[1].typ.skipTypes(abstractRange)#.kind let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind let src_size = getSize(c.config, src) - let dst_size = getSize(c.config, dst) + let dst_size = getSize(c.config, dst) if c.config.target.intSize < 8: signedIntegers.incl(tyInt) unsignedIntegers.incl(tyUInt) @@ -820,7 +823,7 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) = c.freeTemp(tmp) elif src_size == dst_size and src.kind in {tyFloat, tyFloat32, tyFloat64} and - dst.kind in allowedIntegers: + dst.kind in allowedIntegers: let tmp = c.genx(n[1]) if dest < 0: dest = c.getTemp(n[0].typ) if src.kind == tyFloat32: @@ -1095,7 +1098,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = var tmp = c.genx(n.sons[1]) var idx = c.getTemp(getSysType(c.graph, n.info, tyInt)) var typ = n.sons[2].typ - if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc}) + if m == mOf: typ = typ.skipTypes(abstractPtrs) c.gABx(n, opcLdImmInt, idx, c.genType(typ)) c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx) c.freeTemp(tmp) @@ -1112,13 +1115,14 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mEcho: unused(c, n, dest) let n = n[1].skipConv - let x = c.getTempRange(n.len, slotTempUnknown) - internalAssert c.config, n.kind == nkBracket - for i in 0..<n.len: - var r: TRegister = x+i - c.gen(n.sons[i], r) - c.gABC(n, opcEcho, x, n.len) - c.freeTempRange(x, n.len) + if n.kind == nkBracket: + # can happen for nim check, see bug #9609 + let x = c.getTempRange(n.len, slotTempUnknown) + for i in 0..<n.len: + var r: TRegister = x+i + c.gen(n.sons[i], r) + c.gABC(n, opcEcho, x, n.len) + c.freeTempRange(x, n.len) of mAppendStrCh: unused(c, n, dest) genBinaryStmtVar(c, n, opcAddStrCh) @@ -1144,6 +1148,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl) of mGetImplTransf: genUnaryABC(c, n, dest, opcGetImplTransf) of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner) + of mSymIsInstantiationOf: genBinaryABC(c, n, dest, opcSymIsInstantiationOf) of mNChild: genBinaryABC(c, n, dest, opcNChild) of mNSetChild: genVoidABC(c, n, dest, opcNSetChild) of mNDel: genVoidABC(c, n, dest, opcNDel) @@ -2150,7 +2155,8 @@ proc genProc(c: PCtx; s: PSym): int = s.ast.sons[miscPos] = x # thanks to the jmp we can add top level statements easily and also nest # procs easily: - let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s)) + let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s), + noDestructors = true) let procStart = c.xjmp(body, opcJmp, 0) var p = PProc(blocks: @[], sym: s) let oldPrc = c.prc diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 83e65279a..f87ab4508 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -11,7 +11,7 @@ #import vmdeps, vm from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, - floor, ceil, fmod + floor, ceil, `mod`, fmod from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir @@ -21,9 +21,6 @@ template mathop(op) {.dirty.} = template osop(op) {.dirty.} = registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`) -template ospathsop(op) {.dirty.} = - registerCallback(c, "stdlib.ospaths." & astToStr(op), `op Wrapper`) - template systemop(op) {.dirty.} = registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`) @@ -107,10 +104,14 @@ proc registerAdditionalOps*(c: PCtx) = wrap1f_math(ceil) wrap2f_math(fmod) + proc `mod Wrapper`(a: VmArgs) {.nimcall.} = + setResult(a, `mod`(getFloat(a, 0), getFloat(a, 1))) + registerCallback(c, "stdlib.math.mod", `mod Wrapper`) + when defined(nimcore): - wrap2s(getEnv, ospathsop) - wrap1s(existsEnv, ospathsop) - wrap2svoid(putEnv, ospathsop) + wrap2s(getEnv, osop) + wrap1s(existsEnv, osop) + wrap2svoid(putEnv, osop) wrap1s(dirExists, osop) wrap1s(fileExists, osop) wrap2svoid(writeFile, systemop) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 800b5dc18..41bdc9fcb 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -69,13 +69,13 @@ type wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks, wPartial, wExplain, wLiftLocals, - wAuto, wBool, wCatch, wChar, wClass, + wAuto, wBool, wCatch, wChar, wClass, wCompl wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast, wExplicit, wExtern, wFalse, wFloat, wFriend, wGoto, wInt, wLong, wMutable, wNamespace, wNew, wOperator, - wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast, + wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast, wRestrict, wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch, - wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename, + wThis, wThrow, wTrue, wTypedef, wTypeid, wTypeof, wTypename, wUnion, wPacked, wUnsigned, wVirtual, wVoid, wVolatile, wWchar_t, wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept, @@ -156,14 +156,14 @@ const "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked", "guard", "locks", "partial", "explain", "liftlocals", - "auto", "bool", "catch", "char", "class", + "auto", "bool", "catch", "char", "class", "compl", "const_cast", "default", "delete", "double", "dynamic_cast", "explicit", "extern", "false", "float", "friend", "goto", "int", "long", "mutable", "namespace", "new", "operator", - "private", "protected", "public", "register", "reinterpret_cast", + "private", "protected", "public", "register", "reinterpret_cast", "restrict", "short", "signed", "sizeof", "static_cast", "struct", "switch", - "this", "throw", "true", "typedef", "typeid", + "this", "throw", "true", "typedef", "typeid", "typeof", "typename", "union", "packed", "unsigned", "virtual", "void", "volatile", "wchar_t", |