From e4081a720190dfdeb347442cdc2c01745476ff9c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 7 Jan 2018 23:09:26 +0100 Subject: preparations for language extensions: 'sink' and 'lent' types --- compiler/semasgn.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'compiler/semasgn.nim') diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 67af6ade7..bbd2baf6e 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -242,9 +242,9 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = tyTypeDesc, tyGenericInvocation, tyForward: internalError(c.info, "assignment requested for type: " & typeToString(t)) of tyOrdinal, tyRange, tyInferred, - tyGenericInst, tyStatic, tyVar, tyAlias: + tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink: liftBodyAux(c, lastSon(t), body, x, y) - of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("liftBodyAux") + of tyUnused, tyOptAsRef: internalError("liftBodyAux") proc newProcType(info: TLineInfo; owner: PSym): PType = result = newType(tyProc, owner) @@ -306,7 +306,7 @@ proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp; proc getAsgnOrLiftBody(c: PContext; typ: PType; info: TLineInfo): PSym = - let t = typ.skipTypes({tyGenericInst, tyVar, tyAlias}) + let t = typ.skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) result = t.assignment if result.isNil: result = liftBody(c, t, attachedAsgn, info) -- cgit 1.4.1-2-gfad0 From ee366f17469a96b418b58db17e03c892cf4f17d8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 24 Apr 2018 09:34:20 +0200 Subject: .experimental can now be used to enable specific features --- changelog.md | 6 ++++ compiler/commands.nim | 39 ++++++++++++++++--------- compiler/nim.nim | 4 +-- compiler/options.nim | 14 +++++++-- compiler/pragmas.nim | 22 ++++++++++---- compiler/scriptconfig.nim | 6 ++-- compiler/semasgn.nim | 4 +-- compiler/semcall.nim | 2 +- compiler/semdata.nim | 6 ++-- compiler/semexprs.nim | 6 ++-- compiler/semstmts.nim | 71 +++++++++++++++------------------------------ compiler/semtypinst.nim | 4 +-- compiler/service.nim | 12 ++++---- compiler/transf.nim | 6 ++-- doc/advopt.txt | 5 ++-- doc/manual.rst | 21 +++++--------- nimsuggest/nimsuggest.nim | 8 ++--- tests/parallel/tparfind.nim | 2 +- 18 files changed, 122 insertions(+), 116 deletions(-) (limited to 'compiler/semasgn.nim') diff --git a/changelog.md b/changelog.md index a3332789a..8ac02a388 100644 --- a/changelog.md +++ b/changelog.md @@ -102,4 +102,10 @@ - Added ``macros.getProjectPath`` and ``ospaths.putEnv`` procs to Nim's virtual machine. +- The ``deadCodeElim`` option is now always turned on and the switch has no + effect anymore, but is recognized for backwards compatibility. + +- ``experimental`` is now a pragma / command line switch that can enable specific + language extensions, it is not an all-or-nothing switch anymore. + ### Bugfixes diff --git a/compiler/commands.nim b/compiler/commands.nim index 8d73ac90e..dc5d808ec 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -46,9 +46,9 @@ type passCmd2, # second pass over the command line passPP # preprocessor called processCommand() -proc processCommand*(switch: string, pass: TCmdLinePass) +proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; - config: ConfigRef = nil) + config: ConfigRef) # implementation @@ -58,7 +58,13 @@ const const Usage = slurp"../doc/basicopt.txt".replace("//", "") - AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") + FeatureDesc = block: + var x = "" + for f in low(Feature)..high(Feature): + if x.len > 0: x.add "|" + x.add $f + x + AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") % FeatureDesc proc getCommandLineDesc(): string = result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, @@ -276,7 +282,6 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool = of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation) of "implicitstatic": result = contains(gOptions, optImplicitStatic) of "patterns": result = contains(gOptions, optPatterns) - of "experimental": result = gExperimentalMode of "excessivestacktrace": result = contains(gGlobalOptions, optExcessiveStackTrace) else: invalidCmdLineOption(passCmd1, switch, info) @@ -339,7 +344,7 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = options.inclDynlibOverride(arg) proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; - config: ConfigRef = nil) = + config: ConfigRef) = var theOS: TSystemOS cpu: TSystemCPU @@ -694,8 +699,13 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; # only supported for compatibility. Does nothing. expectArg(switch, arg, pass, info) of "experimental": - expectNoArg(switch, arg, pass, info) - gExperimentalMode = true + if arg.len == 0: + config.features.incl oldExperimentalFeatures + else: + try: + config.features.incl parseEnum[Feature](arg) + except ValueError: + localError(info, "unknown experimental feature") of "nocppexceptions": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optNoCppExceptions) @@ -706,7 +716,8 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; config.cppDefine(arg) of "newruntime": expectNoArg(switch, arg, pass, info) - newDestructors = true + doAssert(config != nil) + incl(config.features, destructor) defineSymbol("nimNewRuntime") of "cppcompiletonamespace": expectNoArg(switch, arg, pass, info) @@ -716,10 +727,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) else: invalidCmdLineOption(pass, switch, info) -proc processCommand(switch: string, pass: TCmdLinePass) = +proc processCommand(switch: string, pass: TCmdLinePass; config: ConfigRef) = var cmd, arg: string splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) - processSwitch(cmd, arg, pass, gCmdLineInfo) + processSwitch(cmd, arg, pass, gCmdLineInfo, config) var @@ -727,19 +738,19 @@ var # the arguments to be passed to the program that # should be run -proc processSwitch*(pass: TCmdLinePass; p: OptParser) = +proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) = # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") # we fix this here var bracketLe = strutils.find(p.key, '[') if bracketLe >= 0: var key = substr(p.key, 0, bracketLe - 1) var val = substr(p.key, bracketLe + 1) & ':' & p.val - processSwitch(key, val, pass, gCmdLineInfo) + processSwitch(key, val, pass, gCmdLineInfo, config) else: - processSwitch(p.key, p.val, pass, gCmdLineInfo) + processSwitch(p.key, p.val, pass, gCmdLineInfo, config) proc processArgument*(pass: TCmdLinePass; p: OptParser; - argsCount: var int): bool = + argsCount: var int; config: ConfigRef): bool = if argsCount == 0: # nim filename.nims is the same as "nim e filename.nims": if p.key.endswith(".nims"): diff --git a/compiler/nim.nim b/compiler/nim.nim index 8f3463be9..3fa733303 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -42,7 +42,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = writeCommandLineUsage() else: # Process command line arguments: - processCmdLine(passCmd1, "") + processCmdLine(passCmd1, "", config) if gProjectName == "-": gProjectName = "stdinfile" gProjectFull = "stdinfile" @@ -71,7 +71,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = # now process command line arguments again, because some options in the # command line can overwite the config file's settings extccomp.initVars() - processCmdLine(passCmd2, "") + processCmdLine(passCmd2, "", config) if options.command == "": rawMessage(errNoCommand, command) mainCommand(newModuleGraph(config), cache) diff --git a/compiler/options.nim b/compiler/options.nim index 7126d4398..24c9d0f73 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -103,13 +103,23 @@ type ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, ideHighlight, ideOutline, ideKnown, ideMsg + Feature* = enum ## experimental features + implicitDeref, + dotOperators, + callOperator, + parallel, + destructor + ConfigRef* = ref object ## eventually all global configuration should be moved here cppDefines*: HashSet[string] headerFile*: string + features*: set[Feature] + +const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} proc newConfigRef*(): ConfigRef = result = ConfigRef(cppDefines: initSet[string](), - headerFile: "") + headerFile: "", features: {}) proc cppDefine*(c: ConfigRef; define: string) = c.cppDefines.incl define @@ -146,8 +156,6 @@ var gListFullPaths*: bool gPreciseStack*: bool = false gNoNimblePath* = false - gExperimentalMode*: bool - newDestructors*: bool gDynlibOverrideAll*: bool useNimNamespace*: bool diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 9e9233fe7..5aa903771 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -680,6 +680,22 @@ proc semCustomPragma(c: PContext, n: PNode): PNode = elif n.kind == nkExprColonExpr: result.kind = n.kind # pragma(arg) -> pragma: arg +proc processExperimental(c: PContext; n: PNode; s: PSym) = + if not isTopLevel(c): + localError(n.info, "'experimental' pragma only valid as toplevel statement") + if n.kind notin nkPragmaCallKinds or n.len != 2: + c.features.incl oldExperimentalFeatures + else: + n[1] = c.semConstExpr(c, n[1]) + case n[1].kind + of nkStrLit, nkRStrLit, nkTripleStrLit: + try: + c.features.incl parseEnum[Feature](n[1].strVal) + except ValueError: + localError(n[1].info, "unknown experimental feature") + else: + localError(n.info, errStringLiteralExpected) + proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, validPragmas: TSpecialWords): bool = var it = n.sons[i] @@ -993,11 +1009,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, else: it.sons[1] = c.semExpr(c, it.sons[1]) of wExperimental: - noVal(it) - if isTopLevel(c): - c.module.flags.incl sfExperimental - else: - localError(it.info, "'experimental' pragma only valid as toplevel statement") + processExperimental(c, it, sym) of wThis: if it.kind in nkPragmaCallKinds and it.len == 2: c.selfName = considerQuotedIdent(it[1]) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 692a8d896..c533f4cb4 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -26,7 +26,7 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) = setResult(a, result) proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; - config: ConfigRef = nil): PEvalContext = + config: ConfigRef): PEvalContext = # For Nimble we need to export 'setupVM'. result = newCtx(module, cache) result.mode = emRepl @@ -128,7 +128,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; cbconf getCommand: setResult(a, options.command) cbconf switch: - processSwitch(a.getString 0, a.getString 1, passPP, module.info) + processSwitch(a.getString 0, a.getString 1, passPP, module.info, config) cbconf hintImpl: processSpecificNote(a.getString 0, wHint, passPP, module.info, a.getString 1) @@ -150,7 +150,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; options.cppDefine(config, a.getString(0)) proc runNimScript*(cache: IdentCache; scriptName: string; - freshDefines=true; config: ConfigRef=nil) = + freshDefines=true; config: ConfigRef) = rawMessage(hintConf, scriptName) passes.gIncludeFile = includeModule passes.gImportModule = importModule diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index bbd2baf6e..5c7b91f6d 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -101,7 +101,7 @@ proc newOpCall(op: PSym; x: PNode): PNode = proc destructorCall(c: PContext; op: PSym; x: PNode): PNode = result = newNodeIT(nkCall, x.info, op.typ.sons[0]) result.add(newSymNode(op)) - if newDestructors: + if destructor in c.features: result.add genAddr(c, x) else: result.add x @@ -319,7 +319,7 @@ proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) = ## In the semantic pass this is called in strategic places ## to ensure we lift assignment, destructors and moves properly. ## The later 'destroyer' pass depends on it. - if not newDestructors or not hasDestructor(typ): return + if destructor notin c.features or not hasDestructor(typ): return when false: # do not produce wrong liftings while we're still instantiating generics: # now disabled; breaks topttree.nim! diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 0fc12f164..f443339f5 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -434,7 +434,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, "Non-matching candidates for " & renderTree(n) & "\n" & candidates) result = semResolvedCall(c, n, r) - elif experimentalMode(c) and canDeref(n): + elif implicitDeref in c.features and canDeref(n): # try to deref the first argument and then try overloading resolution again: # # XXX: why is this here? diff --git a/compiler/semdata.nim b/compiler/semdata.nim index bcc1bba15..8159abf8f 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -130,6 +130,7 @@ type signatures*: TStrTable recursiveDep*: string suggestionsMade*: bool + features*: set[Feature] inTypeContext*: int typesWithOps*: seq[(PType, PType)] #\ # We need to instantiate the type bound ops lazily after @@ -225,7 +226,7 @@ proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext result.graph = graph initStrTable(result.signatures) result.typesWithOps = @[] - + result.features = graph.config.features proc inclSym(sq: var TSymSeq, s: PSym) = var L = len(sq) @@ -398,6 +399,3 @@ proc checkMinSonsLen*(n: PNode, length: int) = proc isTopLevel*(c: PContext): bool {.inline.} = result = c.currentScope.depthLevel <= 2 - -proc experimentalMode*(c: PContext): bool {.inline.} = - result = gExperimentalMode or sfExperimental in c.module.flags diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 279b6cc57..6ad5d931d 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -663,7 +663,7 @@ proc resolveIndirectCall(c: PContext; n, nOrig: PNode; matches(c, n, nOrig, result) if result.state != csMatch: # try to deref the first argument: - if experimentalMode(c) and canDeref(n): + if implicitDeref in c.features and canDeref(n): n.sons[1] = n.sons[1].tryDeref initCandidate(c, result, t) matches(c, n, nOrig, result) @@ -1452,7 +1452,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = typeMismatch(n.info, lhs.typ, rhsTyp) n.sons[1] = fitNode(c, le, rhs, n.info) - if not newDestructors: + if destructor notin c.features: if tfHasAsgn in lhs.typ.flags and not lhsIsResult and mode != noOverloadedAsgn: return overloadedAsgn(c, lhs, n.sons[1]) @@ -1884,7 +1884,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) result.typ = getSysType(tyString) of mParallel: - if not experimentalMode(c): + if parallel notin c.features: localError(n.info, "use the {.experimental.} pragma to enable 'parallel'") result = setMs(n, s) var x = n.lastSon diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 8d7747fb4..94090852f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -385,30 +385,9 @@ proc checkNilable(v: PSym) = include semasgn proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) = - # consider this: - # var - # x = 0 - # withOverloadedAssignment = foo() - # y = use(withOverloadedAssignment) - # We need to split this into a statement list with multiple 'var' sections - # in order for this transformation to be correct. let L = identDefs.len let value = identDefs[L-1] - if value.typ != nil and tfHasAsgn in value.typ.flags and not newDestructors: - # the spec says we need to rewrite 'var x = T()' to 'var x: T; x = T()': - identDefs.sons[L-1] = emptyNode - if result.kind != nkStmtList: - let oldResult = result - oldResult.add identDefs - result = newNodeI(nkStmtList, result.info) - result.add oldResult - else: - let o = copyNode(orig) - o.add identDefs - result.add o - for i in 0 .. L-3: - result.add overloadedAsgn(c, identDefs[i], value) - elif result.kind == nkStmtList: + if result.kind == nkStmtList: let o = copyNode(orig) o.add identDefs result.add o @@ -1267,9 +1246,6 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = gp = newNodeI(nkGenericParams, n.info) if n.sons[paramsPos].kind != nkEmpty: - #if n.kind == nkDo and not experimentalMode(c): - # localError(n.sons[paramsPos].info, - # "use the {.experimental.} pragma to enable 'do' with parameters") semParamList(c, n.sons[paramsPos], gp, s) # paramsTypeCheck(c, s.typ) if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty: @@ -1363,27 +1339,26 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) = proc semOverride(c: PContext, s: PSym, n: PNode) = case s.name.s.normalize - of "destroy", "=destroy": - if newDestructors: - let t = s.typ - var noError = false - if t.len == 2 and t.sons[0] == nil and t.sons[1].kind == tyVar: - var obj = t.sons[1].sons[0] - while true: - incl(obj.flags, tfHasAsgn) - if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon - elif obj.kind == tyGenericInvocation: obj = obj.sons[0] - else: break - if obj.kind in {tyObject, tyDistinct}: - if obj.destructor.isNil: - obj.destructor = s - else: - localError(n.info, errGenerated, - "cannot bind another '" & s.name.s & "' to: " & typeToString(obj)) - noError = true - if not noError and sfSystemModule notin s.owner.flags: - localError(n.info, errGenerated, - "signature for '" & s.name.s & "' must be proc[T: object](x: var T)") + of "=destroy": + let t = s.typ + var noError = false + if t.len == 2 and t.sons[0] == nil and t.sons[1].kind == tyVar: + var obj = t.sons[1].sons[0] + while true: + incl(obj.flags, tfHasAsgn) + if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon + elif obj.kind == tyGenericInvocation: obj = obj.sons[0] + else: break + if obj.kind in {tyObject, tyDistinct}: + if obj.destructor.isNil: + obj.destructor = s + else: + localError(n.info, errGenerated, + "cannot bind another '" & s.name.s & "' to: " & typeToString(obj)) + noError = true + if not noError and sfSystemModule notin s.owner.flags: + localError(n.info, errGenerated, + "signature for '" & s.name.s & "' must be proc[T: object](x: var T)") incl(s.flags, sfUsed) of "deepcopy", "=deepcopy": if s.typ.len == 2 and @@ -1612,9 +1587,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, s.options = gOptions if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) if s.name.s[0] in {'.', '('}: - if s.name.s in [".", ".()", ".="] and not experimentalMode(c) and not newDestructors: + if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}: message(n.info, warnDeprecated, "overloaded '.' and '()' operators are now .experimental; " & s.name.s) - elif s.name.s == "()" and not experimentalMode(c): + elif s.name.s == "()" and callOperator notin c.features: message(n.info, warnDeprecated, "overloaded '()' operators are now .experimental; " & s.name.s) if n.sons[bodyPos].kind != nkEmpty: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 09434c925..c97c1186e 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -368,7 +368,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = assert newbody.kind in {tyRef, tyPtr} assert newbody.lastSon.typeInst == nil newbody.lastSon.typeInst = result - if newDestructors: + if destructor in cl.c.features: cl.c.typesWithOps.add((newbody, result)) else: typeBound(cl.c, newbody, result, assignment, cl.info) @@ -545,7 +545,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = else: discard proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) = - if not newDestructors: return + if destructor notin c.features: return var i = 0 while i < c.typesWithOps.len: let (newty, oldty) = c.typesWithOps[i] diff --git a/compiler/service.nim b/compiler/service.nim index ac04b7860..7cdfc112c 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -26,7 +26,7 @@ var # in caas mode, the list of defines and options will be given at start-up? # it's enough to check that the previous compilation command is the same? -proc processCmdLine*(pass: TCmdLinePass, cmd: string) = +proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) = var p = parseopt.initOptParser(cmd) var argsCount = 0 while true: @@ -36,19 +36,19 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = of cmdLongoption, cmdShortOption: if p.key == " ": p.key = "-" - if processArgument(pass, p, argsCount): break + if processArgument(pass, p, argsCount, config): break else: - processSwitch(pass, p) + processSwitch(pass, p, config) of cmdArgument: - if processArgument(pass, p, argsCount): break + if processArgument(pass, p, argsCount, config): break if pass == passCmd2: if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run": rawMessage(errArgsNeedRunOption, []) -proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}) = +proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; config: ConfigRef) = template execute(cmd) = curCaasCmd = cmd - processCmdLine(passCmd2, cmd) + processCmdLine(passCmd2, cmd, config) action(cache) gErrorCounter = 0 diff --git a/compiler/transf.nim b/compiler/transf.nim index f30f8583a..f7ec6c97f 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -979,7 +979,7 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = #result = liftLambdas(prc, result) when useEffectSystem: trackProc(prc, result) result = liftLocalsIfRequested(prc, result) - if c.needsDestroyPass and newDestructors: + if c.needsDestroyPass: #and newDestructors: result = injectDestructorCalls(prc, result) incl(result.flags, nfTransf) #if prc.name.s == "testbody": @@ -996,7 +996,7 @@ proc transformStmt*(module: PSym, n: PNode): PNode = when useEffectSystem: trackTopLevelStmt(module, result) #if n.info ?? "temp.nim": # echo renderTree(result, {renderIds}) - if c.needsDestroyPass and newDestructors: + if c.needsDestroyPass: result = injectDestructorCalls(module, result) incl(result.flags, nfTransf) @@ -1007,6 +1007,6 @@ proc transformExpr*(module: PSym, n: PNode): PNode = var c = openTransf(module, "") result = processTransf(c, n, module) liftDefer(c, result) - if c.needsDestroyPass and newDestructors: + if c.needsDestroyPass: result = injectDestructorCalls(module, result) incl(result.flags, nfTransf) diff --git a/doc/advopt.txt b/doc/advopt.txt index bf7dd7fb4..0d1578f78 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -35,7 +35,7 @@ Advanced options: --noLinking compile Nim and generated files but do not link --noMain do not generate a main procedure --genScript generate a compile script (in the 'nimcache' - subdirectory named 'compile_$project$scriptext') + subdirectory named 'compile_$$project$$scriptext') --genDeps generate a '.deps' file containing the dependencies --os:SYMBOL set the target operating system (cross-compilation) --cpu:SYMBOL set the target processor (cross-compilation) @@ -88,5 +88,6 @@ Advanced options: --parallelBuild:0|1|... perform a parallel build value = number of processors (0 for auto-detect) --verbosity:0|1|2|3 set Nim's verbosity level (1 is default) - --experimental enable experimental language features + --experimental:$1 + enable experimental language feature -v, --version show detailed version information diff --git a/doc/manual.rst b/doc/manual.rst index f1330d524..636bf796b 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1397,10 +1397,10 @@ dereferencing operations for reference types: Automatic dereferencing is also performed for the first argument of a routine call. But currently this feature has to be only enabled -via ``{.experimental.}``: +via ``{.experimental: "implicitDeref".}``: .. code-block:: nim - {.experimental.} + {.experimental: "implicitDeref".} proc depth(x: NodeObj): int = ... @@ -5588,7 +5588,7 @@ dot operators ------------- **Note**: Dot operators are still experimental and so need to be enabled -via ``{.experimental.}``. +via ``{.experimental: "dotOperators".}``. Nim offers a special family of dot operators that can be used to intercept and rewrite proc call and field access attempts, referring @@ -6885,17 +6885,12 @@ is uncertain (it may be removed any time). Example: .. code-block:: nim - {.experimental.} - type - FooId = distinct int - BarId = distinct int - using - foo: FooId - bar: BarId + {.experimental: "parallel".} proc useUsing(bar, foo) = - echo "bar is of type BarId" - echo "foo is of type FooId" + parallel: + for i in 0..4: + echo "echo in parallel" Implementation Specific Pragmas @@ -7917,7 +7912,7 @@ Example: # Compute PI in an inefficient way import strutils, math, threadpool - {.experimental.} + {.experimental: "parallel".} proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 49e61b9a9..b2764e9ee 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -518,7 +518,7 @@ proc mainCommand(graph: ModuleGraph; cache: IdentCache) = close(requests) close(results) -proc processCmdLine*(pass: TCmdLinePass, cmd: string) = +proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) = var p = parseopt.initOptParser(cmd) while true: parseopt.next(p) @@ -562,7 +562,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = gRefresh = true of "maxresults": suggestMaxResults = parseInt(p.val) - else: processSwitch(pass, p) + else: processSwitch(pass, p, config) of cmdArgument: let a = unixToNativePath(p.key) if dirExists(a) and not fileExists(a.addFileExt("nim")): @@ -577,7 +577,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = if paramCount() == 0: stdout.writeline(Usage) else: - processCmdLine(passCmd1, "") + processCmdLine(passCmd1, "", config) if gMode != mstdin: msgs.writelnHook = proc (msg: string) = discard if gProjectName != "": @@ -616,7 +616,7 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) = runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config) extccomp.initVars() - processCmdLine(passCmd2, "") + processCmdLine(passCmd2, "", config) let graph = newModuleGraph(config) graph.suggestMode = true diff --git a/tests/parallel/tparfind.nim b/tests/parallel/tparfind.nim index 9de5012f5..4b3610c67 100644 --- a/tests/parallel/tparfind.nim +++ b/tests/parallel/tparfind.nim @@ -4,7 +4,7 @@ discard """ import threadpool, sequtils -{.experimental.} +{.experimental: "parallel".} proc linearFind(a: openArray[int]; x, offset: int): int = for i, y in a: -- cgit 1.4.1-2-gfad0 From dd35111ff27b5aa0a6c67a7afb3bff9c75f036ec Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 May 2018 19:45:19 +0200 Subject: semstmts compiles again --- compiler/configuration.nim | 34 ++------ compiler/semasgn.nim | 52 ++++++------ compiler/semexprs.nim | 6 +- compiler/semfields.nim | 23 +++--- compiler/semgnrc.nim | 80 +++++++++---------- compiler/semstmts.nim | 195 ++++++++++++++++++++++++--------------------- 6 files changed, 192 insertions(+), 198 deletions(-) (limited to 'compiler/semasgn.nim') diff --git a/compiler/configuration.nim b/compiler/configuration.nim index 4b3cecfca..86e3cabf2 100644 --- a/compiler/configuration.nim +++ b/compiler/configuration.nim @@ -185,7 +185,6 @@ errIntLiteralExpected: "integer literal expected", errIdentifierExpected: "identifier expected, but found '$1'", errNewlineExpected: "newline expected, but found '$1'", errInvalidModuleName: "invalid module name: '$1'", -errRecursiveDependencyX: "recursive dependency: '$1'", errOnOrOffExpected: "'on' or 'off' expected", errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected", errInvalidPragma: "invalid pragma", @@ -193,11 +192,7 @@ errUnknownPragma: "unknown pragma: '$1'", errAtPopWithoutPush: "'pop' without a 'push' pragma", errEmptyAsm: "empty asm statement", errInvalidIndentation: "invalid indentation", -errExceptionAlreadyHandled: "exception already handled", -errYieldNotAllowedHere: "'yield' only allowed in an iterator", -errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator", -errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions", -errCannotReturnExpr: "current routine cannot return an expression", + errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type", errAttemptToRedefine: , errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma", @@ -261,13 +256,10 @@ errExprMustBeBool: "expression must be of type 'bool'", errConstExprExpected: "constant expression expected", errDuplicateCaseLabel: "duplicate case label", errRangeIsEmpty: "range is empty", -errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string", +, errSelectorMustBeOrdinal: "selector must be of an ordinal type", errOrdXMustNotBeNegative: "ord($1) must not be negative", errLenXinvalid: "len($1) must be less than 32768", -errWrongNumberOfVariables: "wrong number of variables", -errExprCannotBeRaised: "only a 'ref object' can be raised", -errBreakOnlyInLoop: "'break' only allowed in loop construct", errTypeXhasUnknownSize: "type '$1' has unknown size", errConstNeedsConstExpr: "a constant can only be initialized with a constant expression", errConstNeedsValue: "a constant needs a value", @@ -288,11 +280,9 @@ errWrongNumberOfArguments: "wrong number of arguments", errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'", errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", errXCannotBePassedToProcVar: , -errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", +, errImplOfXexpected: , -errNoSymbolToBorrowFromFound: "no symbol to borrow from found", -errDiscardValueX: "value of type '$1' has to be discarded", -errInvalidDiscard: "statement returns no value that can be discarded", + errIllegalConvFromXtoY: , errCannotBindXTwice: "cannot bind parameter '$1' twice", errInvalidOrderInArrayConstructor: "invalid order in array constructor", @@ -315,7 +305,6 @@ errNoReturnTypeForX: "no return type allowed for $1", errConvNeedsOneArg: "a type conversion needs exactly one argument", errInvalidPragmaX: , errXNotAllowedHere: "$1 not allowed here", -errInvalidControlFlowX: "invalid control flow: $1", errXisNoType: "invalid type: '$1'", errCircumNeedsPointer: "'[]' needs a pointer or reference type", errInvalidExpression: "invalid expression", @@ -325,7 +314,7 @@ errNamedExprExpected: "named expression expected", errNamedExprNotAllowed: "named expression not allowed here", errNoCommand: "no command given", errInvalidCommandX: "invalid command: '$1'", -errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", +errXNeedsParamObjectType: , errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N", errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N", errInstantiationFrom: "template/generic instantiation from here", @@ -344,7 +333,7 @@ errXisNoValidIndexFile: "'$1' is no valid index file", errCannotRenderX: "cannot render reStructuredText element '$1'", errVarVarTypeNotAllowed: , errInstantiateXExplicitly: "instantiate '$1' explicitly", -errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", +errOnlyACallOpCanBeDelegator: , errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " & "because the parameter '$1' has a generic type", @@ -368,18 +357,9 @@ errUnhandledExceptionX: "unhandled exception: $1", errCyclicTree: "macro returned a cyclic abstract syntax tree", errXisNoMacroOrTemplate: "'$1' is no macro or template", errXhasSideEffects: "'$1' can have side effects", -errIteratorExpected: "iterator within for loop context expected", -errLetNeedsInit: "'let' symbol requires an initialization", -errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread", errWrongSymbolX:, errIllegalCaptureX: "illegal capture '$1'", errXCannotBeClosure: "'$1' cannot have 'closure' calling convention", errXMustBeCompileTime: "'$1' can only be used in compile-time context", -errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1", -errCannotInferReturnType: "cannot infer the return type of the proc", -errCannotInferStaticParam: "cannot infer the value of the static param `$1`", -errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " & - "it is used as an operand to another routine and the types " & - "of the generic paramers can be inferred from the expected signature.", -errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.", +, ]# diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 5c7b91f6d..f0fde195c 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -33,7 +33,7 @@ proc at(a, i: PNode, elemType: PType): PNode = proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) = for i in 0 ..< t.len: - let lit = lowerings.newIntLit(i) + let lit = lowerings.newIntLit(c.c.graph, x.info, i) liftBodyAux(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i])) proc dotField(x: PNode, f: PSym): PNode = @@ -66,15 +66,15 @@ proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) = liftBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y) caseStmt.add(branch) body.add(caseStmt) - localError(c.info, "cannot lift assignment operator to 'case' object") + localError(c.c.config, c.info, "cannot lift assignment operator to 'case' object") of nkRecList: for t in items(n): liftBodyObj(c, t, body, x, y) else: - illFormedAstLocal(n) + illFormedAstLocal(n, c.c.config) proc genAddr(c: PContext; x: PNode): PNode = if x.kind == nkHiddenDeref: - checkSonsLen(x, 1) + checkSonsLen(x, 1, c.config) result = x.sons[0] else: result = newNodeIT(nkHiddenAddr, x.info, makeVarType(c, x.typ)) @@ -82,7 +82,7 @@ proc genAddr(c: PContext; x: PNode): PNode = proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode = if sfError in op.flags: - localError(x.info, errWrongSymbolX, op.name.s) + 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) @@ -124,7 +124,7 @@ 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.info, op, c.c.graph.usageSym) + markUsed(c.c.config, c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add newAsgnCall(c.c, op, x, y) result = true @@ -134,7 +134,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = of attachedDestructor: let op = t.destructor if op != nil: - markUsed(c.info, op, c.c.graph.usageSym) + markUsed(c.c.config, c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add destructorCall(c.c, op, x) result = true @@ -145,7 +145,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = of attachedDeepCopy: let op = t.deepCopy if op != nil: - markUsed(c.info, op, c.c.graph.usageSym) + markUsed(c.c.config, c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add newDeepCopyCall(op, x, y) result = true @@ -163,37 +163,37 @@ proc addVar(father, v, value: PNode) = proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = var temp = newSym(skTemp, getIdent(lowerings.genPrefix), c.fn, c.info) - temp.typ = getSysType(tyInt) + temp.typ = getSysType(c.c.graph, body.info, tyInt) incl(temp.flags, sfFromGeneric) var v = newNodeI(nkVarSection, c.info) result = newSymNode(temp) - v.addVar(result, lowerings.newIntLit(first)) + v.addVar(result, lowerings.newIntLit(c.c.graph, body.info, first)) body.add v -proc genBuiltin(magic: TMagic; name: string; i: PNode): PNode = +proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = result = newNodeI(nkCall, i.info) - result.add createMagic(name, magic).newSymNode + result.add createMagic(g, name, magic).newSymNode result.add i proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = result = newNodeI(nkWhileStmt, c.info, 2) - let cmp = genBuiltin(mLeI, "<=", i) - cmp.add genHigh(dest) - cmp.typ = getSysType(tyBool) + let cmp = genBuiltin(c.c.graph, mLeI, "<=", i) + cmp.add genHigh(c.c.graph, dest) + cmp.typ = getSysType(c.c.graph, c.info, tyBool) result.sons[0] = cmp result.sons[1] = newNodeI(nkStmtList, c.info) -proc addIncStmt(body, i: PNode) = - let incCall = genBuiltin(mInc, "inc", i) - incCall.add lowerings.newIntLit(1) +proc addIncStmt(c: var TLiftCtx; body, i: PNode) = + let incCall = genBuiltin(c.c.graph, mInc, "inc", i) + incCall.add lowerings.newIntLit(c.c.graph, c.info, 1) body.add incCall proc newSeqCall(c: PContext; x, y: PNode): PNode = # don't call genAddr(c, x) here: - result = genBuiltin(mNewSeq, "newSeq", x) - let lenCall = genBuiltin(mLengthSeq, "len", y) - lenCall.typ = getSysType(tyInt) + result = genBuiltin(c.graph, mNewSeq, "newSeq", x) + let lenCall = genBuiltin(c.graph, mLengthSeq, "len", y) + lenCall.typ = getSysType(c.graph, x.info, tyInt) result.add lenCall proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = @@ -212,7 +212,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = let elemType = t.lastSon liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType), y.at(i, elemType)) - addIncStmt(whileLoop.sons[1], i) + addIncStmt(c, whileLoop.sons[1], i) body.add whileLoop else: defaultOp(c, t, body, x, y) @@ -231,20 +231,20 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = # have to go through some indirection; we delegate this to the codegen: let call = newNodeI(nkCall, c.info, 2) call.typ = t - call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy)) + call.sons[0] = newSymNode(createMagic(c.c.graph, "deepCopy", mDeepCopy)) call.sons[1] = y body.add newAsgnStmt(x, call) of tyVarargs, tyOpenArray: - localError(c.info, errGenerated, "cannot copy openArray") + localError(c.c.config, c.info, "cannot copy openArray") of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt, tyTypeDesc, tyGenericInvocation, tyForward: - internalError(c.info, "assignment requested for type: " & typeToString(t)) + internalError(c.c.config, c.info, "assignment requested for type: " & typeToString(t)) of tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink: liftBodyAux(c, lastSon(t), body, x, y) - of tyUnused, tyOptAsRef: internalError("liftBodyAux") + of tyUnused, tyOptAsRef: internalError(c.c.config, "liftBodyAux") proc newProcType(info: TLineInfo; owner: PSym): PType = result = newType(tyProc, owner) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 001e0ccf2..0ca3fcd4c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -215,7 +215,7 @@ proc semConv(c: PContext, n: PNode): PNode = elif op.kind in {nkPar, nkTupleConstr} and targetType.kind == tyTuple: op = fitNode(c, targetType, op, result.info) of convNotNeedeed: - message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) + message(c.config, n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) of convNotLegal: result = fitNode(c, result.typ, result.sons[1], result.info) if result == nil: @@ -1494,7 +1494,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = # nil # # comment # are not expressions: - fixNilType(result) + fixNilType(c, result) else: var a = newNodeI(nkAsgn, n.info, 2) a.sons[0] = newSymNode(c.p.resultSym) @@ -2264,7 +2264,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result.kind = nkCall result = semExpr(c, result, flags) of nkBind: - message(n.info, warnDeprecated, "bind") + message(c.config, n.info, warnDeprecated, "bind") result = semExpr(c, n.sons[0], flags) of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy: if c.matchedConcept != nil and n.len == 1: diff --git a/compiler/semfields.nim b/compiler/semfields.nim index 70efe8c4c..16d79c559 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -16,16 +16,17 @@ type tupleIndex: int field: PSym replaceByFieldName: bool + c: PContext proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = case n.kind of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n of nkIdent, nkSym: result = n - let ident = considerQuotedIdent(n) + let ident = considerQuotedIdent(c.c.config, n) var L = sonsLen(forLoop) if c.replaceByFieldName: - if ident.id == considerQuotedIdent(forLoop[0]).id: + if ident.id == considerQuotedIdent(c.c.config, forLoop[0]).id: let fieldName = if c.tupleType.isNil: c.field.name.s elif c.tupleType.n.isNil: "Field" & $c.tupleIndex else: c.tupleType.n.sons[c.tupleIndex].sym.name.s @@ -33,7 +34,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = return # other fields: for i in ord(c.replaceByFieldName)..L-3: - if ident.id == considerQuotedIdent(forLoop[i]).id: + if ident.id == considerQuotedIdent(c.c.config, forLoop[i]).id: var call = forLoop.sons[L-2] var tupl = call.sons[i+1-ord(c.replaceByFieldName)] if c.field.isNil: @@ -47,7 +48,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = break else: if n.kind == nkContinueStmt: - localError(c.config, n.info, errGenerated, + localError(c.c.config, n.info, "'continue' not supported in a 'fields' loop") result = copyNode(n) newSons(result, sonsLen(n)) @@ -63,6 +64,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = case typ.kind of nkSym: var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid + fc.c = c.c fc.field = typ.sym fc.replaceByFieldName = c.m == mFieldPairs openScope(c.c) @@ -76,7 +78,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = let L = forLoop.len let call = forLoop.sons[L-2] if call.len > 2: - localError(c.config, forLoop.info, errGenerated, + localError(c.c.config, forLoop.info, "parallel 'fields' iterator does not work for 'case' objects") return # iterate over the selector: @@ -99,17 +101,17 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = of nkRecList: for t in items(typ): semForObjectFields(c, t, forLoop, father) else: - illFormedAstLocal(typ) + illFormedAstLocal(typ, c.c.config) proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = # so that 'break' etc. work as expected, we produce # a 'while true: stmt; break' loop ... result = newNodeI(nkWhileStmt, n.info, 2) - var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true") + var trueSymbol = strTableGet(c.graph.systemModule.tab, getIdent"true") if trueSymbol == nil: - localError(c.config, n.info, errSystemNeeds, "true") + localError(c.config, n.info, "system needs: 'true'") trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(c), n.info) - trueSymbol.typ = getSysType(tyBool) + trueSymbol.typ = getSysType(c.graph, n.info, tyBool) result.sons[0] = newSymNode(trueSymbol, n.info) var stmts = newNodeI(nkStmtList, n.info) @@ -129,7 +131,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = for i in 1..call.len-1: var tupleTypeB = skipTypes(call.sons[i].typ, skippedTypesForFields) if not sameType(tupleTypeA, tupleTypeB): - typeMismatch(call.sons[i].info, tupleTypeA, tupleTypeB) + typeMismatch(c.config, call.sons[i].info, tupleTypeA, tupleTypeB) inc(c.p.nestedLoopCounter) if tupleTypeA.kind == tyTuple: @@ -139,6 +141,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = var fc: TFieldInstCtx fc.tupleType = tupleTypeA fc.tupleIndex = i + fc.c = c fc.replaceByFieldName = m == mFieldPairs var body = instFieldLoopBody(fc, loopBody, n) inc c.inUnrolledContext diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 16da06952..a620c544d 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -17,13 +17,13 @@ # included from sem.nim -proc getIdentNode(n: PNode): PNode = +proc getIdentNode(c: PContext; n: PNode): PNode = case n.kind - of nkPostfix: result = getIdentNode(n.sons[1]) - of nkPragmaExpr: result = getIdentNode(n.sons[0]) + of nkPostfix: result = getIdentNode(c, n.sons[1]) + of nkPragmaExpr: result = getIdentNode(c, n.sons[0]) of nkIdent, nkAccQuoted, nkSym: result = n else: - illFormedAst(n) + illFormedAst(n, c.config) result = n type @@ -103,8 +103,8 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx): PNode = result = n - let ident = considerQuotedIdent(n) - var s = searchInScopes(c, ident).skipAlias(n) + let ident = considerQuotedIdent(c.config, n) + var s = searchInScopes(c, ident).skipAlias(n, c.config) if s == nil: s = strTableGet(c.pureEnumFields, ident) if s != nil and contains(c.ambiguousSymbols, s.id): @@ -140,8 +140,8 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx) result = n let n = n[1] - let ident = considerQuotedIdent(n) - var s = searchInScopes(c, ident).skipAlias(n) + let ident = considerQuotedIdent(c.config, n) + var s = searchInScopes(c, ident).skipAlias(n, c.config) if s != nil and s.kind in routineKinds: isMacro = s.kind in {skTemplate, skMacro} if withinBind in flags: @@ -158,7 +158,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, result = newDot(result, syms) proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) = - let s = newSymS(skUnknown, getIdentNode(n), c) + let s = newSymS(skUnknown, getIdentNode(c, n), c) addPrelimDecl(c, s) styleCheckDef(n.info, s, kind) @@ -201,13 +201,13 @@ proc semGenericStmt(c: PContext, n: PNode, result = semMixinStmt(c, n, ctx.toMixin) of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: # check if it is an expression macro: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) let fn = n.sons[0] var s = qualifiedLookUp(c, fn, {}) if s == nil and {withinMixin, withinConcept}*flags == {} and fn.kind in {nkIdent, nkAccQuoted} and - considerQuotedIdent(fn).id notin ctx.toMixin: + considerQuotedIdent(c.config, fn).id notin ctx.toMixin: errorUndeclaredIdentifier(c, n.info, fn.renderTree) var first = int ord(withinConcept in flags) @@ -285,7 +285,7 @@ proc semGenericStmt(c: PContext, n: PNode, withBracketExpr ctx, n.sons[0]: result = semGenericStmt(c, result, flags, ctx) of nkAsgn, nkFastAsgn: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) let a = n.sons[0] let b = n.sons[1] @@ -323,7 +323,7 @@ proc semGenericStmt(c: PContext, n: PNode, n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx) for i in countup(1, sonsLen(n)-1): var a = n.sons[i] - checkMinSonsLen(a, 1) + checkMinSonsLen(a, 1, c.config) var L = sonsLen(a) for j in countup(0, L-2): a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx) @@ -340,23 +340,23 @@ proc semGenericStmt(c: PContext, n: PNode, closeScope(c) closeScope(c) of nkBlockStmt, nkBlockExpr, nkBlockType: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) openScope(c) if n.sons[0].kind != nkEmpty: addTempDecl(c, n.sons[0], skLabel) n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx) closeScope(c) of nkTryStmt: - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx) for i in countup(1, sonsLen(n)-1): var a = n.sons[i] - checkMinSonsLen(a, 1) + checkMinSonsLen(a, 1, c.config) var L = sonsLen(a) openScope(c) for j in countup(0, L-2): if a.sons[j].isInfixAs(): - addTempDecl(c, getIdentNode(a.sons[j][2]), skLet) + addTempDecl(c, getIdentNode(c, a.sons[j][2]), skLet) a.sons[j].sons[1] = semGenericStmt(c, a.sons[j][1], flags+{withinTypeDesc}, ctx) else: a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx) @@ -367,44 +367,44 @@ proc semGenericStmt(c: PContext, n: PNode, for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue - if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a) - checkMinSonsLen(a, 3) + if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var L = sonsLen(a) a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) for j in countup(0, L-3): - addTempDecl(c, getIdentNode(a.sons[j]), skVar) + addTempDecl(c, getIdentNode(c, a.sons[j]), skVar) of nkGenericParams: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if (a.kind != nkIdentDefs): illFormedAst(a) - checkMinSonsLen(a, 3) + if (a.kind != nkIdentDefs): illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var L = sonsLen(a) a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) # do not perform symbol lookup for default expressions for j in countup(0, L-3): - addTempDecl(c, getIdentNode(a.sons[j]), skType) + addTempDecl(c, getIdentNode(c, a.sons[j]), skType) of nkConstSection: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue - if (a.kind != nkConstDef): illFormedAst(a) - checkSonsLen(a, 3) - addTempDecl(c, getIdentNode(a.sons[0]), skConst) + if (a.kind != nkConstDef): illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) + addTempDecl(c, getIdentNode(c, a.sons[0]), skConst) a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx) a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx) of nkTypeSection: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue - if (a.kind != nkTypeDef): illFormedAst(a) - checkSonsLen(a, 3) - addTempDecl(c, getIdentNode(a.sons[0]), skType) + if (a.kind != nkTypeDef): illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) + addTempDecl(c, getIdentNode(c, a.sons[0]), skType) for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue - if (a.kind != nkTypeDef): illFormedAst(a) - checkSonsLen(a, 3) + if (a.kind != nkTypeDef): illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) if a.sons[1].kind != nkEmpty: openScope(c) a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx) @@ -421,28 +421,28 @@ proc semGenericStmt(c: PContext, n: PNode, case n.sons[i].kind of nkEnumFieldDef: a = n.sons[i].sons[0] of nkIdent: a = n.sons[i] - else: illFormedAst(n) - addDecl(c, newSymS(skUnknown, getIdentNode(a), c)) + else: illFormedAst(n, c.config) + addDecl(c, newSymS(skUnknown, getIdentNode(c, a), c)) of nkObjectTy, nkTupleTy, nkTupleClassTy: discard of nkFormalParams: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) if n.sons[0].kind != nkEmpty: n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx) for i in countup(1, sonsLen(n) - 1): var a = n.sons[i] - if (a.kind != nkIdentDefs): illFormedAst(a) - checkMinSonsLen(a, 3) + if (a.kind != nkIdentDefs): illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var L = sonsLen(a) a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) for j in countup(0, L-3): - addTempDecl(c, getIdentNode(a.sons[j]), skParam) + addTempDecl(c, getIdentNode(c, a.sons[j]), skParam) of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkFuncDef, nkIteratorDef, nkLambdaKinds: - checkSonsLen(n, bodyPos + 1) + checkSonsLen(n, bodyPos + 1, c.config) if n.sons[namePos].kind != nkEmpty: - addTempDecl(c, getIdentNode(n.sons[0]), skProc) + addTempDecl(c, getIdentNode(c, n.sons[0]), skProc) openScope(c) n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], flags, ctx) @@ -463,7 +463,7 @@ proc semGenericStmt(c: PContext, n: PNode, closeScope(c) of nkPragma, nkPragmaExpr: discard of nkExprColonExpr, nkExprEqExpr: - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx) else: for i in countup(0, sonsLen(n) - 1): diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f1a34785b..f09fad588 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -10,7 +10,33 @@ ## this module does the semantic checking of statements # included from sem.nim -var enforceVoidContext = PType(kind: tyStmt) +const + errNoSymbolToBorrowFromFound = "no symbol to borrow from found" + errDiscardValueX = "value of type '$1' has to be discarded" + errInvalidDiscard = "statement returns no value that can be discarded" + errInvalidControlFlowX = "invalid control flow: $1" + errSelectorMustBeOfCertainTypes = "selector must be of an ordinal type, float or string" + errExprCannotBeRaised = "only a 'ref object' can be raised" + errBreakOnlyInLoop = "'break' only allowed in loop construct" + errExceptionAlreadyHandled = "exception already handled" + errYieldNotAllowedHere = "'yield' only allowed in an iterator" + errYieldNotAllowedInTryStmt = "'yield' cannot be used within 'try' in a non-inlined iterator" + errInvalidNumberOfYieldExpr = "invalid number of 'yield' expressions" + errCannotReturnExpr = "current routine cannot return an expression" + errGenericLambdaNotAllowed = "A nested proc can have generic parameters only when " & + "it is used as an operand to another routine and the types " & + "of the generic paramers can be inferred from the expected signature." + errCannotInferTypeOfTheLiteral = "cannot infer the type of the $1" + errCannotInferReturnType = "cannot infer the return type of the proc" + errCannotInferStaticParam = "cannot infer the value of the static param '$1'" + errProcHasNoConcreteType = "'$1' doesn't have a concrete type, due to unspecified generic parameters." + errLetNeedsInit = "'let' symbol requires an initialization" + errThreadvarCannotInit = "a thread var cannot be initialized explicitly; this would only run for the main thread" + errImplOfXexpected = "implementation of '$1' expected" + errRecursiveDependencyX = "recursive dependency: '$1'" + errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1" + +var enforceVoidContext = PType(kind: tyStmt) # XXX global variable here proc semDiscard(c: PContext, n: PNode): PNode = result = n @@ -39,18 +65,18 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = suggestSym(x.info, s, c.graph.usageSym) styleCheckUse(x.info, s) else: - localError(c.config, n.info, errInvalidControlFlowX, s.name.s) + localError(c.config, n.info, errInvalidControlFlowX % s.name.s) else: localError(c.config, n.info, errGenerated, "'continue' cannot have a label") elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): - localError(c.config, n.info, errInvalidControlFlowX, + localError(c.config, n.info, errInvalidControlFlowX % renderTree(n, {renderNoComments})) -proc semAsm(con: PContext, n: PNode): PNode = +proc semAsm(c: PContext, n: PNode): PNode = checkSonsLen(n, 2, c.config) - var marker = pragmaAsm(con, n.sons[0]) + var marker = pragmaAsm(c, n.sons[0]) if marker == '\0': marker = '`' # default marker - result = semAsmOrEmit(con, n, marker) + result = semAsmOrEmit(c, n, marker) proc semWhile(c: PContext, n: PNode): PNode = result = n @@ -95,13 +121,13 @@ proc implicitlyDiscardable(n: PNode): bool = result = isCallExpr(n) and n.sons[0].kind == nkSym and sfDiscardable in n.sons[0].sym.flags -proc fixNilType(n: PNode) = +proc fixNilType(c: PContext; n: PNode) = if isAtom(n): if n.kind != nkNilLit and n.typ != nil: - localError(c.config, n.info, errDiscardValueX, n.typ.typeToString) + localError(c.config, n.info, errDiscardValueX % n.typ.typeToString) elif n.kind in {nkStmtList, nkStmtListExpr}: n.kind = nkStmtList - for it in n: fixNilType(it) + for it in n: fixNilType(c, it) n.typ = nil proc discardCheck(c: PContext, result: PNode) = @@ -207,7 +233,7 @@ proc semCase(c: PContext, n: PNode): PNode = if covered == toCover(n.sons[0].typ): hasElse = true else: - localError(c.config, n.info, errNotAllCasesCovered) + localError(c.config, n.info, "not all cases covered") closeScope(c) if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) @@ -339,16 +365,16 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = result = semIdentWithPragma(c, kind, n, {}) if result.owner.kind == skModule: incl(result.flags, sfGlobal) - suggestSym(c.config, n.info, result, c.graph.usageSym) + suggestSym(n.info, result, c.graph.usageSym) styleCheckDef(result) -proc checkNilable(v: PSym) = +proc checkNilable(c: PContext; v: PSym) = if {sfGlobal, sfImportC} * v.flags == {sfGlobal} and {tfNotNil, tfNeedsInit} * v.typ.flags != {}: if v.ast.isNil: - message(v.info, warnProveInit, v.name.s) + message(c.config, v.info, warnProveInit, v.name.s) elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags: - message(v.info, warnProveInit, v.name.s) + message(c.config, v.info, warnProveInit, v.name.s) include semasgn @@ -369,7 +395,7 @@ proc isDiscardUnderscore(v: PSym): bool = proc semUsing(c: PContext; n: PNode): PNode = result = ast.emptyNode - if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "using") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "using") for i in countup(0, sonsLen(n)-1): var a = n.sons[i] if gCmd == cmdIdeTools: suggestStmt(c, a) @@ -432,7 +458,7 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) = else: localError(c.config, n.info, "nkDotNode requires 2 children") -proc setVarType(v: PSym, typ: PType) = +proc setVarType(c: PContext; v: PSym, typ: PType) = if v.typ != nil and not sameTypeOrNil(v.typ, typ): localError(c.config, v.info, "inconsistent typing for reintroduced symbol '" & v.name.s & "': previous type was: " & typeToString(v.typ) & @@ -476,16 +502,16 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass: typ = typ.lastSon if hasEmpty(typ): - localError(c.config, def.info, errCannotInferTypeOfTheLiteral, + localError(c.config, def.info, errCannotInferTypeOfTheLiteral % ($typ.kind).substr(2).toLowerAscii) elif typ.kind == tyProc and tfUnresolved in typ.flags: - localError(c.config, def.info, errProcHasNoConcreteType, def.renderTree) + localError(c.config, def.info, errProcHasNoConcreteType % def.renderTree) else: if symkind == skLet: localError(c.config, a.info, errLetNeedsInit) # this can only happen for errornous var statements: if typ == nil: continue - typeAllowedCheck(a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {}) + typeAllowedCheck(c.config, a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {}) liftTypeBoundOps(c, typ, a.info) var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink}) if a.kind == nkVarTuple: @@ -500,7 +526,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = addToVarSection(c, result, n, b) elif tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and a.kind == nkIdentDefs and a.len > 3: - message(a.info, warnEachIdentIsTuple) + message(c.config, a.info, warnEachIdentIsTuple) for j in countup(0, length-3): if a[j].kind == nkDotExpr: @@ -518,17 +544,17 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if shadowed != nil: shadowed.flags.incl(sfShadowed) if shadowed.kind == skResult and sfGenSym notin v.flags: - message(a.info, warnResultShadowed) + message(c.config, a.info, warnResultShadowed) # a shadowed variable is an error unless it appears on the right # side of the '=': - if warnShadowIdent in gNotes and not identWithin(def, v.name): - message(a.info, warnShadowIdent, v.name.s) + if warnShadowIdent in c.config.notes and not identWithin(def, v.name): + message(c.config, a.info, warnShadowIdent, v.name.s) if a.kind != nkVarTuple: if def.kind != nkEmpty: # this is needed for the evaluation pass and for the guard checking: v.ast = def if sfThread in v.flags: localError(c.config, def.info, errThreadvarCannotInit) - setVarType(v, typ) + setVarType(c, v, typ) b = newNodeI(nkIdentDefs, a.info) if importantComments(c.config): # keep documentation information: @@ -540,13 +566,13 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = else: if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j] # bug #7663, for 'nim check' this can be a non-tuple: - if tup.kind == tyTuple: setVarType(v, tup.sons[j]) + if tup.kind == tyTuple: setVarType(c, v, tup.sons[j]) else: v.typ = tup b.sons[j] = newSymNode(v) - checkNilable(v) + checkNilable(c, v) if sfCompileTime in v.flags: hasCompileTime = true if hasCompileTime: - vm.setupCompileTimeVar(c.module, c.cache, c.graph.config, result) + vm.setupCompileTimeVar(c.module, c.cache, c.graph, result) proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) @@ -575,11 +601,11 @@ proc semConst(c: PContext, n: PNode): PNode = if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit: localError(c.config, a.info, "invalid type for const: " & typeToString(typ)) continue - setVarType(v, typ) + setVarType(c, v, typ) v.ast = def # no need to copy if sfGenSym notin v.flags: addInterfaceDecl(c, v) var b = newNodeI(nkConstDef, a.info) - if importantComments(): b.comment = a.comment + if importantComments(c.config): b.comment = a.comment addSon(b, newSymNode(v)) addSon(b, a.sons[1]) addSon(b, copyTree(def)) @@ -588,12 +614,12 @@ proc semConst(c: PContext, n: PNode): PNode = include semfields proc addForVarDecl(c: PContext, v: PSym) = - if warnShadowIdent in gNotes: + if warnShadowIdent in c.config.notes: let shadowed = findShadowedVar(c, v) if shadowed != nil: # XXX should we do this here? #shadowed.flags.incl(sfShadowed) - message(v.info, warnShadowIdent, v.name.s) + message(c.config, v.info, warnShadowIdent, v.name.s) addDecl(c, v) proc symForVar(c: PContext, n: PNode): PSym = @@ -658,7 +684,7 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode = # n := for a, b, c in m(x, y, z): Y # to # m(n) - let forLoopStmt = magicsys.getCompilerProc("ForLoopStmt") + let forLoopStmt = magicsys.getCompilerProc(c.graph, "ForLoopStmt") if forLoopStmt == nil: return let headSymbol = iterExpr[0] @@ -715,7 +741,7 @@ proc semFor(c: PContext, n: PNode): PNode = elif length == 4: n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2]) else: - localError(c.config, n.sons[length-2].info, errIteratorExpected) + localError(c.config, n.sons[length-2].info, "iterator within for loop context expected") result = semForVars(c, n) else: result = semForVars(c, n) @@ -744,7 +770,7 @@ proc addGenericParamListToScope(c: PContext, n: PNode) = if a.kind == nkSym: addDecl(c, a.sym) else: illFormedAst(a, c.config) -proc typeSectionTypeName(n: PNode): PNode = +proc typeSectionTypeName(c: PContext; n: PNode): PNode = if n.kind == nkPragmaExpr: if n.len == 0: illFormedAst(n, c.config) result = n.sons[0] @@ -818,14 +844,12 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = else: a.sons[0] = newSymNode(s) -proc checkCovariantParamsUsages(genericType: PType) = +proc checkCovariantParamsUsages(c: PContext; genericType: PType) = var body = genericType[^1] - proc traverseSubTypes(t: PType): bool = + proc traverseSubTypes(c: PContext; t: PType): bool = template error(msg) = localError(c.config, genericType.sym.info, msg) - result = false - template subresult(r) = let sub = r result = result or sub @@ -834,24 +858,19 @@ proc checkCovariantParamsUsages(genericType: PType) = of tyGenericParam: t.flags.incl tfWeakCovariant return true - of tyObject: for field in t.n: - subresult traverseSubTypes(field.typ) - + subresult traverseSubTypes(c, field.typ) of tyArray: - return traverseSubTypes(t[1]) - + return traverseSubTypes(c, t[1]) of tyProc: for subType in t.sons: if subType != nil: - subresult traverseSubTypes(subType) + subresult traverseSubTypes(c, subType) if result: error("non-invariant type param used in a proc type: " & $t) - of tySequence: - return traverseSubTypes(t[0]) - + return traverseSubTypes(c, t[0]) of tyGenericInvocation: let targetBody = t[0] for i in 1 ..< t.len: @@ -872,32 +891,24 @@ proc checkCovariantParamsUsages(genericType: PType) = "' used in a non-contravariant position") result = true else: - subresult traverseSubTypes(param) - + subresult traverseSubTypes(c, param) of tyAnd, tyOr, tyNot, tyStatic, tyBuiltInTypeClass, tyCompositeTypeClass: error("non-invariant type parameters cannot be used with types such '" & $t & "'") - of tyUserTypeClass, tyUserTypeClassInst: error("non-invariant type parameters are not supported in concepts") - of tyTuple: for fieldType in t.sons: - subresult traverseSubTypes(fieldType) - + subresult traverseSubTypes(c, fieldType) of tyPtr, tyRef, tyVar, tyLent: if t.base.kind == tyGenericParam: return true - return traverseSubTypes(t.base) - + return traverseSubTypes(c, t.base) of tyDistinct, tyAlias, tySink: - return traverseSubTypes(t.lastSon) - + return traverseSubTypes(c, t.lastSon) of tyGenericInst: - internalAssert false - + internalAssert c.config, false else: discard - - discard traverseSubTypes(body) + discard traverseSubTypes(c, body) proc typeSectionRightSidePass(c: PContext, n: PNode) = for i in countup(0, sonsLen(n) - 1): @@ -905,10 +916,10 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = if a.kind == nkCommentStmt: continue if a.kind != nkTypeDef: illFormedAst(a, c.config) checkSonsLen(a, 3, c.config) - let name = typeSectionTypeName(a.sons[0]) + let name = typeSectionTypeName(c, a.sons[0]) var s = name.sym if s.magic == mNone and a.sons[2].kind == nkEmpty: - localError(c.config, a.info, errImplOfXexpected, s.name.s) + localError(c.config, a.info, errImplOfXexpected % s.name.s) if s.magic != mNone: processMagicType(c, s) if a.sons[1].kind != nkEmpty: # We have a generic type declaration here. In generic types, @@ -939,7 +950,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = body.size = -1 # could not be computed properly s.typ.sons[sonsLen(s.typ) - 1] = body if tfCovariant in s.typ.flags: - checkCovariantParamsUsages(s.typ) + checkCovariantParamsUsages(c, s.typ) # XXX: This is a temporary limitation: # The codegen currently produces various failures with # generic imported types that have fields, but we need @@ -974,8 +985,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = # give anonymous object a dummy symbol: var st = s.typ if st.kind == tyGenericBody: st = st.lastSon - internalAssert st.kind in {tyPtr, tyRef} - internalAssert st.lastSon.sym == nil + internalAssert c.config, st.kind in {tyPtr, tyRef} + internalAssert c.config, st.lastSon.sym == nil incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(s.name.s & ":ObjectType"), getCurrOwner(c), s.info) @@ -983,17 +994,17 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = st.lastSon.sym = obj -proc checkForMetaFields(n: PNode) = +proc checkForMetaFields(c: PContext; n: PNode) = template checkMeta(t) = if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags: - localError(c.config, n.info, errTIsNotAConcreteType, t.typeToString) + localError(c.config, n.info, errTIsNotAConcreteType % t.typeToString) if n.isNil: return case n.kind of nkRecList, nkRecCase: - for s in n: checkForMetaFields(s) + for s in n: checkForMetaFields(c, s) of nkOfBranch, nkElse: - checkForMetaFields(n.lastSon) + checkForMetaFields(c, n.lastSon) of nkSym: let t = n.sym.typ case t.kind @@ -1005,13 +1016,13 @@ proc checkForMetaFields(n: PNode) = else: checkMeta(t) else: - internalAssert false + internalAssert c.config, false proc typeSectionFinalPass(c: PContext, n: PNode) = for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue - let name = typeSectionTypeName(a.sons[0]) + let name = typeSectionTypeName(c, a.sons[0]) var s = name.sym # compute the type's size and check for illegal recursions: if a.sons[1].kind == nkEmpty: @@ -1031,9 +1042,9 @@ proc typeSectionFinalPass(c: PContext, n: PNode) = assert s.typ != nil assignType(s.typ, t) s.typ.id = t.id # same id - checkConstructedType(s.info, s.typ) + checkConstructedType(c.config, s.info, s.typ) if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil: - checkForMetaFields(s.typ.n) + checkForMetaFields(c, s.typ.n) instAllTypeBoundOp(c, n.info) @@ -1042,10 +1053,10 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode = case n.kind of nkIncludeStmt: for i in 0..= result.safeLen: return result @@ -1685,7 +1696,7 @@ proc semMethod(c: PContext, n: PNode): PNode = else: disp.ast[resultPos].sym.typ = ret proc semConverterDef(c: PContext, n: PNode): PNode = - if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope, "converter") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "converter") checkSonsLen(n, bodyPos + 1, c.config) result = semProcAux(c, n, skConverter, converterPragmas) # macros can transform converters to nothing: @@ -1696,8 +1707,8 @@ proc semConverterDef(c: PContext, n: PNode): PNode = if result.kind != nkConverterDef: return var s = result.sons[namePos].sym var t = s.typ - if t.sons[0] == nil: localError(c.config, n.info, errXNeedsReturnType, "converter") - if sonsLen(t) != 2: localError(c.config, n.info, errXRequiresOneArgument, "converter") + if t.sons[0] == nil: localError(c.config, n.info, errXNeedsReturnType % "converter") + if sonsLen(t) != 2: localError(c.config, n.info, "a converter takes exactly one argument") addConverter(c, s) proc semMacroDef(c: PContext, n: PNode): PNode = @@ -1718,7 +1729,7 @@ proc semMacroDef(c: PContext, n: PNode): PNode = if allUntyped: incl(s.flags, sfAllUntyped) if t.sons[0] == nil: localError(c.config, n.info, "macro needs a return type") if n.sons[bodyPos].kind == nkEmpty: - localError(c.config, n.info, errImplOfXexpected, s.name.s) + localError(c.config, n.info, errImplOfXexpected % s.name.s) proc evalInclude(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) @@ -1756,7 +1767,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode = #writeStackTrace() let a = semStmt(c, n.sons[0]) n.sons[0] = a - evalStaticStmt(c.module, c.cache, c.graph.config, a, c.p.owner) + evalStaticStmt(c.module, c.cache, c.graph, a, c.p.owner) result = newNodeI(nkDiscardStmt, n.info, 1) result.sons[0] = emptyNode @@ -1839,7 +1850,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = case n.sons[j].kind of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr, nkBlockStmt, nkState: discard - else: localError(c.config, n.sons[j].info, errStmtInvalidAfterReturn) + else: localError(c.config, n.sons[j].info, "unreachable statement after 'return'") else: discard if result.len == 1 and -- cgit 1.4.1-2-gfad0