diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ccgexprs.nim | 2 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 2 | ||||
-rw-r--r-- | compiler/jsgen.nim | 19 | ||||
-rw-r--r-- | compiler/pragmas.nim | 55 | ||||
-rw-r--r-- | compiler/semcall.nim | 104 | ||||
-rw-r--r-- | compiler/semexprs.nim | 9 | ||||
-rw-r--r-- | compiler/semgnrc.nim | 13 | ||||
-rw-r--r-- | compiler/seminst.nim | 7 | ||||
-rw-r--r-- | compiler/semmagic.nim | 8 | ||||
-rw-r--r-- | compiler/sempass2.nim | 34 | ||||
-rw-r--r-- | compiler/semstmts.nim | 10 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 5 | ||||
-rw-r--r-- | compiler/transf.nim | 12 | ||||
-rw-r--r-- | compiler/types.nim | 13 |
14 files changed, 161 insertions, 132 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index f9fa1a0f6..6c96f209e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -670,6 +670,8 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = #if e[0].kind != nkBracketExpr: # message(e.info, warnUser, "CAME HERE " & renderTree(e)) expr(p, e.sons[0], d) + if e.sons[0].typ.skipTypes(abstractInst).kind == tyRef: + d.s = OnHeap else: var a: TLoc let typ = skipTypes(e.sons[0].typ, abstractInst) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index a5ce147c3..9056a61cb 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -21,7 +21,7 @@ proc registerGcRoot(p: BProc, v: PSym) = # we register a specialized marked proc here; this has the advantage # that it works out of the box for thread local storage then :-) let prc = genTraverseProcForGlobal(p.module, v) - appcg(p.module, p.module.initProc.procSec(cpsStmts), + appcg(p.module, p.module.initProc.procSec(cpsInit), "#nimRegisterGlobalMarker($1);$n", [prc]) proc isAssignedImmediately(n: PNode): bool {.inline.} = diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index a0b54812f..80bcd2b0e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -8,7 +8,7 @@ # # This is the JavaScript code generator. -# Soon also a PHP code generator. ;-) +# Also a PHP code generator. ;-) discard """ The JS code generator contains only 2 tricks: @@ -1280,14 +1280,15 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = assert(typ.kind == tyProc) genPatternCall(p, n, pat, typ, r) return - gen(p, n.sons[1], r) - if r.typ == etyBaseIndex: - if r.address == nil: - globalError(n.info, "cannot invoke with infix syntax") - r.res = "$1[$2]" % [r.address, r.res] - r.address = nil - r.typ = etyNone - add(r.res, "." | "->") + if n.len != 1: + gen(p, n.sons[1], r) + if r.typ == etyBaseIndex: + if r.address == nil: + globalError(n.info, "cannot invoke with infix syntax") + r.res = "$1[$2]" % [r.address, r.res] + r.address = nil + r.typ = etyNone + add(r.res, "." | "->") var op: TCompRes if p.target == targetPHP: op.kind = resCallee diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 1f93f5317..db5f8e727 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -90,43 +90,38 @@ proc pragmaAsm*(c: PContext, n: PNode): char = else: invalidPragma(it) -proc setExternName(s: PSym, extname: string) = - s.loc.r = rope(extname % s.name.s) +proc setExternName(s: PSym, extname: string, info: TLineInfo) = + # special cases to improve performance: + if extname == "$1": + s.loc.r = rope(s.name.s) + elif '$' notin extname: + s.loc.r = rope(extname) + else: + try: + s.loc.r = rope(extname % s.name.s) + except ValueError: + localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)") if gCmd == cmdPretty and '$' notin extname: # note that '{.importc.}' is transformed into '{.importc: "$1".}' s.loc.flags.incl(lfFullExternalName) -proc makeExternImport(s: PSym, extname: string) = - setExternName(s, extname) +proc makeExternImport(s: PSym, extname: string, info: TLineInfo) = + setExternName(s, extname, info) incl(s.flags, sfImportc) excl(s.flags, sfForward) -proc validateExternCName(s: PSym, info: TLineInfo) = - ## Validates that the symbol name in s.loc.r is a valid C identifier. - ## - ## Valid identifiers are those alphanumeric including the underscore not - ## starting with a number. If the check fails, a generic error will be - ## displayed to the user. - let target = $s.loc.r - if target.len < 1 or target[0] notin IdentStartChars or - not target.allCharsInSet(IdentChars): - localError(info, errGenerated, "invalid exported symbol") - proc makeExternExport(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname) - # XXX to fix make it work with nimrtl. - #if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}: - # validateExternCName(s, info) + setExternName(s, extname, info) incl(s.flags, sfExportc) -proc processImportCompilerProc(s: PSym, extname: string) = - setExternName(s, extname) +proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) = + setExternName(s, extname, info) incl(s.flags, sfImportc) excl(s.flags, sfForward) incl(s.loc.flags, lfImportCompilerProc) -proc processImportCpp(s: PSym, extname: string) = - setExternName(s, extname) +proc processImportCpp(s: PSym, extname: string, info: TLineInfo) = + setExternName(s, extname, info) incl(s.flags, sfImportc) incl(s.flags, sfInfixCall) excl(s.flags, sfForward) @@ -134,8 +129,8 @@ proc processImportCpp(s: PSym, extname: string) = incl(m.flags, sfCompileToCpp) extccomp.gMixedMode = true -proc processImportObjC(s: PSym, extname: string) = - setExternName(s, extname) +proc processImportObjC(s: PSym, extname: string, info: TLineInfo) = + setExternName(s, extname, info) incl(s.flags, sfImportc) incl(s.flags, sfNamedParamCall) excl(s.flags, sfForward) @@ -623,10 +618,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, of wExportc: makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info) incl(sym.flags, sfUsed) # avoid wrong hints - of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1")) + of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"), it.info) of wImportCompilerProc: - processImportCompilerProc(sym, getOptionalStr(c, it, "$1")) - of wExtern: setExternName(sym, expectStrLit(c, it)) + processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info) + of wExtern: setExternName(sym, expectStrLit(c, it), it.info) of wImmediate: if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate) @@ -637,9 +632,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, if sym.kind == skTemplate: incl(sym.flags, sfDirty) else: invalidPragma(it) of wImportCpp: - processImportCpp(sym, getOptionalStr(c, it, "$1")) + processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info) of wImportObjC: - processImportObjC(sym, getOptionalStr(c, it, "$1")) + processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info) of wAlign: if sym.typ == nil: invalidPragma(it) var align = expectIntLit(c, it) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 97209167d..b83872fe9 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -40,67 +40,49 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, filter: TSymKinds, best, alt: var TCandidate, errors: var CandidateErrors) = - var o: TOverloadIter - # thanks to the lazy semchecking for operands, we need to iterate over the - # symbol table *before* any call to 'initCandidate' which might invoke - # semExpr which might modify the symbol table in cases like - # 'init(a, 1, (var b = new(Type2); b))'. - var symx = initOverloadIter(o, c, headSymbol) - let symScope = o.lastOverloadScope - - var syms: seq[tuple[a: PSym, b: int]] = @[] - while symx != nil: - if symx.kind in filter: - syms.add((symx, o.lastOverloadScope)) - symx = nextOverloadIter(o, c, headSymbol) - if syms.len == 0: - when false: - if skIterator notin filter: - # also try iterators, but these are 2nd class: - symx = initOverloadIter(o, c, headSymbol) - while symx != nil: - if symx.kind == skIterator: - syms.add((symx, 100)) - symx = nextOverloadIter(o, c, headSymbol) - if syms.len == 0: return - else: - return - - var z: TCandidate - initCandidate(c, best, syms[0][0], initialBinding, symScope) - initCandidate(c, alt, syms[0][0], initialBinding, symScope) - best.state = csNoMatch - - for i in 0 .. <syms.len: - let sym = syms[i][0] - determineType(c, sym) - initCandidate(c, z, sym, initialBinding, syms[i][1]) - - #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140: - # gDebug = true - matches(c, n, orig, z) - if errors != nil: - errors.safeAdd((sym, int z.mutabilityProblem)) - if z.errors != nil: - for err in z.errors: - errors.add(err) - if z.state == csMatch: - # little hack so that iterators are preferred over everything else: - if sym.kind == skIterator: inc(z.exactMatches, 200) - case best.state - of csEmpty, csNoMatch: best = z - of csMatch: - var cmp = cmpCandidates(best, z) - if cmp < 0: best = z # x is better than the best so far - elif cmp == 0: alt = z # x is as good as the best so far - else: discard - #if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516: - # echo "Matches ", n.info, " ", typeToString(sym.typ) - # debug sym - # writeMatches(z) - # for i in 1 .. <len(z.call): - # z.call[i].typ.debug - # quit 1 + while true: + block pickAttempt: + var o: TOverloadIter + var sym = initOverloadIter(o, c, headSymbol) + # Thanks to the lazy semchecking for operands, we need to check whether + # 'initCandidate' modifies the symbol table (via semExpr). + # This can occur in cases like 'init(a, 1, (var b = new(Type2); b))' + let counterInitial = c.currentScope.symbols.counter + # Initialise 'best' and 'alt' with the first available symbol + while sym != nil: + if sym.kind in filter: + initCandidate(c, best, sym, initialBinding, o.lastOverloadScope) + initCandidate(c, alt, sym, initialBinding, o.lastOverloadScope) + best.state = csNoMatch + break + else: + sym = nextOverloadIter(o, c, headSymbol) + var z: TCandidate + while sym != nil: + if sym.kind notin filter: + sym = nextOverloadIter(o, c, headSymbol) + continue + determineType(c, sym) + initCandidate(c, z, sym, initialBinding, o.lastOverloadScope) + if c.currentScope.symbols.counter != counterInitial: break pickAttempt + matches(c, n, orig, z) + if errors != nil: + errors.safeAdd((sym, int z.mutabilityProblem)) + if z.errors != nil: + for err in z.errors: + errors.add(err) + if z.state == csMatch: + # little hack so that iterators are preferred over everything else: + if sym.kind == skIterator: inc(z.exactMatches, 200) + case best.state + of csEmpty, csNoMatch: best = z + of csMatch: + var cmp = cmpCandidates(best, z) + if cmp < 0: best = z # x is better than the best so far + elif cmp == 0: alt = z # x is as good as the best so far + else: discard + sym = nextOverloadIter(o, c, headSymbol) + break # pick attempt was successful proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = # Gives a detailed error message; this is separated from semOverloadedCall, diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index fc31829ba..e3552f94e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -701,9 +701,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, # error correction, prevents endless for loop elimination in transf. # See bug #2051: result.sons[0] = newSymNode(errorSym(c, n)) - if sfNoSideEffect notin callee.flags: - if {sfImportc, sfSideEffect} * callee.flags != {}: - incl(c.p.owner.flags, sfSideEffect) proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode @@ -804,9 +801,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = else: result = m.call instGenericConvertersSons(c, result, m) - # we assume that a procedure that calls something indirectly - # has side-effects: - if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect) elif t != nil and t.kind == tyTypeDesc: if n.len == 1: return semObjConstr(c, n, flags) return semConv(c, n) @@ -1040,9 +1034,6 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = markUsed(n.info, s) styleCheckUse(n.info, s) - # if a proc accesses a global variable, it is not side effect free: - if sfGlobal in s.flags: - incl(c.p.owner.flags, sfSideEffect) 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: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 9ea3efd0c..b8451865e 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -202,24 +202,25 @@ proc semGenericStmt(c: PContext, n: PNode, if s != nil: incl(s.flags, sfUsed) mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles} - let scOption = if s.name.id in ctx.toMixin: scForceOpen else: scOpen + let sc = symChoice(c, fn, s, + if s.name.id in ctx.toMixin: scForceOpen else: scOpen) case s.kind of skMacro: - if macroToExpand(s): + if macroToExpand(s) and sc.safeLen <= 1: styleCheckUse(fn.info, s) result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, flags, ctx) else: - n.sons[0] = symChoice(c, fn, s, scOption) + n.sons[0] = sc result = n mixinContext = true of skTemplate: - if macroToExpand(s): + if macroToExpand(s) and sc.safeLen <= 1: styleCheckUse(fn.info, s) result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, flags, ctx) else: - n.sons[0] = symChoice(c, fn, s, scOption) + n.sons[0] = sc result = n # BUGFIX: we must not return here, we need to do first phase of # symbol lookup. Also since templates and macros can do scope injections @@ -230,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode, # Leave it as an identifier. discard of skProc, skMethod, skIterator, skConverter, skModule: - result.sons[0] = symChoice(c, fn, s, scOption) + result.sons[0] = sc # do not check of 's.magic==mRoof' here because it might be some # other '^' but after overload resolution the proper one: if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^": diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 460db4f7c..a57b8e520 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -172,9 +172,10 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) = popInfoContext() proc sideEffectsCheck(c: PContext, s: PSym) = - if {sfNoSideEffect, sfSideEffect} * s.flags == - {sfNoSideEffect, sfSideEffect}: - localError(s.info, errXhasSideEffects, s.name.s) + when false: + if {sfNoSideEffect, sfSideEffect} * s.flags == + {sfNoSideEffect, sfSideEffect}: + localError(s.info, errXhasSideEffects, s.name.s) proc instGenericContainer(c: PContext, info: TLineInfo, header: PType, allowMetaTypes = false): PType = diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index d9fec6275..cbe9bc176 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -114,8 +114,12 @@ proc semTypeTraits(c: PContext, n: PNode): PNode = proc semOrd(c: PContext, n: PNode): PNode = result = n - result.typ = makeRangeType(c, firstOrd(n.sons[1].typ), - lastOrd(n.sons[1].typ), n.info) + let parType = n.sons[1].typ + if isOrdinalType(parType) or parType.kind == tySet: + result.typ = makeRangeType(c, firstOrd(parType), lastOrd(parType), n.info) + else: + localError(n.info, errOrdinalTypeExpected) + result.typ = errorType(c) proc semBindSym(c: PContext, n: PNode): PNode = result = copyNode(n) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index b12ab5e96..6d2e82ef0 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -59,7 +59,7 @@ type init: seq[int] # list of initialized variables guards: TModel # nested guards locked: seq[PNode] # locked locations - gcUnsafe, isRecursive, isToplevel: bool + gcUnsafe, isRecursive, isToplevel, hasSideEffect: bool maxLockLevel, currLockLevel: TLockLevel PEffects = var TEffects @@ -192,6 +192,14 @@ proc markGcUnsafe(a: PEffects; reason: PNode) = a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"), a.owner, reason.info) +when true: + template markSideEffect(a: PEffects; reason: typed) = + a.hasSideEffect = true +else: + template markSideEffect(a: PEffects; reason: typed) = + a.hasSideEffect = true + markGcUnsafe(a, reason) + proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) = let u = s.gcUnsafetyReason if u != nil and not cycleCheck.containsOrIncl(u.id): @@ -226,12 +234,16 @@ proc useVar(a: PEffects, n: PNode) = message(n.info, warnUninit, s.name.s) # prevent superfluous warnings about the same variable: a.init.add s.id - if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet}: + if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and + s.magic != mNimVm: if s.guard != nil: guardGlobal(a, n, s.guard) if {sfGlobal, sfThread} * s.flags == {sfGlobal} and (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem): #if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(a, s) + else: + markSideEffect(a, s) + type TIntersection = seq[tuple[id, count: int]] # a simple count table @@ -495,6 +507,8 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = if notGcSafe(s.typ) and sfImportc notin s.flags: if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(tracked, s) + if tfNoSideEffect notin s.typ.flags: + markSideEffect(tracked, s) mergeLockLevels(tracked, n, s.getLockLevel) proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = @@ -550,12 +564,16 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner): if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(tracked, a) + elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner): + markSideEffect(tracked, a) else: mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) if notGcSafe(op): if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(tracked, a) + elif tfNoSideEffect notin op.flags: + markSideEffect(tracked, a) notNilCheck(tracked, n, paramType) proc breaksBlock(n: PNode): bool = @@ -684,6 +702,7 @@ proc track(tracked: PEffects, n: PNode) = if a.sym == tracked.owner: tracked.isRecursive = true # even for recursive calls we need to check the lock levels (!): mergeLockLevels(tracked, n, a.sym.getLockLevel) + if sfSideEffect in a.sym.flags: markSideEffect(tracked, a) else: mergeLockLevels(tracked, n, op.lockLevel) var effectList = op.n.sons[0] @@ -702,6 +721,10 @@ proc track(tracked: PEffects, n: PNode) = if not (a.kind == nkSym and a.sym == tracked.owner): if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(tracked, a) + if tfNoSideEffect notin op.flags and not importedFromC(a): + # and it's not a recursive call: + if not (a.kind == nkSym and a.sym == tracked.owner): + markSideEffect(tracked, a) for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i)) if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}: # may not look like an assignment, but it is: @@ -912,8 +935,15 @@ proc trackProc*(s: PSym, body: PNode) = else: listGcUnsafety(s, onlyWarning=true) #localError(s.info, warnGcUnsafe2, s.name.s) + if sfNoSideEffect in s.flags and t.hasSideEffect: + when false: + listGcUnsafety(s, onlyWarning=false) + else: + localError(s.info, errXhasSideEffects, s.name.s) if not t.gcUnsafe: s.typ.flags.incl tfGcSafe + if not t.hasSideEffect: + s.typ.flags.incl tfNoSideEffect if s.typ.lockLevel == UnspecifiedLockLevel: s.typ.lockLevel = t.maxLockLevel elif t.maxLockLevel > s.typ.lockLevel: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5d1770a32..5f9989ea2 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -304,8 +304,14 @@ proc semTry(c: PContext, n: PNode): PNode = proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = result = fitNode(c, typ, n) if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: - changeType(result.sons[1], typ, check=true) - result = result.sons[1] + let r1 = result.sons[1] + if r1.kind in {nkCharLit..nkUInt64Lit} and typ.skipTypes(abstractRange).kind in {tyFloat..tyFloat128}: + result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal) + result.info = n.info + result.typ = typ + else: + changeType(r1, typ, check=true) + result = r1 elif not sameType(result.typ, typ): changeType(result, typ, check=false) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index ce4f893ea..ec429968c 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -221,13 +221,14 @@ proc cmpCandidates*(a, b: TCandidate): int = if result != 0: return result = a.convMatches - b.convMatches if result != 0: return - result = a.calleeScope - b.calleeScope - if result != 0: return # the other way round because of other semantics: result = b.inheritancePenalty - a.inheritancePenalty if result != 0: return # prefer more specialized generic over more general generic: result = complexDisambiguation(a.callee, b.callee) + # only as a last resort, consider scoping: + if result != 0: return + result = a.calleeScope - b.calleeScope proc writeMatches*(c: TCandidate) = writeLine(stdout, "exact matches: " & $c.exactMatches) diff --git a/compiler/transf.nim b/compiler/transf.nim index d64276cfb..fc400c524 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -474,12 +474,14 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = type TPutArgInto = enum - paDirectMapping, paFastAsgn, paVarAsgn + paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray proc putArgInto(arg: PNode, formal: PType): TPutArgInto = # This analyses how to treat the mapping "formal <-> arg" in an # inline context. if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}: + if arg.kind == nkStmtListExpr: + return paComplexOpenarray return paDirectMapping # XXX really correct? # what if ``arg`` has side-effects? case arg.kind @@ -569,6 +571,14 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = assert(skipTypes(formal.typ, abstractInst).kind == tyVar) idNodeTablePut(newC.mapping, formal, arg) # XXX BUG still not correct if the arg has a side effect! + of paComplexOpenarray: + let typ = newType(tySequence, formal.owner) + addSonSkipIntLit(typ, formal.typ.sons[0]) + var temp = newTemp(c, typ, formal.info) + addVar(v, temp) + add(stmtList, newAsgnStmt(c, temp, arg.PTransNode)) + idNodeTablePut(newC.mapping, formal, temp) + var body = iter.getBody.copyTree pushInfoContext(n.info) # XXX optimize this somehow. But the check "c.inlining" is not correct: diff --git a/compiler/types.nim b/compiler/types.nim index c56382b89..312e36ae5 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -48,6 +48,8 @@ proc isOrdinalType*(t: PType): bool proc enumHasHoles*(t: PType): bool const + # TODO: Remove tyTypeDesc from each abstractX and (where necessary) + # replace with typedescX abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable, tyTypeDesc} abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal, @@ -61,6 +63,7 @@ const skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable, tyTypeDesc} + # typedescX is used if we're sure tyTypeDesc should be included (or skipped) typedescPtrs* = abstractPtrs + {tyTypeDesc} typedescInst* = abstractInst + {tyTypeDesc} @@ -148,10 +151,12 @@ proc skipGeneric(t: PType): PType = proc isOrdinalType(t: PType): bool = assert(t != nil) - # caution: uint, uint64 are no ordinal types! - result = t.kind in {tyChar,tyInt..tyInt64,tyUInt8..tyUInt32,tyBool,tyEnum} or - (t.kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and - isOrdinalType(t.sons[0]) + const + # caution: uint, uint64 are no ordinal types! + baseKinds = {tyChar,tyInt..tyInt64,tyUInt8..tyUInt32,tyBool,tyEnum} + parentKinds = {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst, + tyDistinct} + t.kind in baseKinds or (t.kind in parentKinds and isOrdinalType(t.sons[0])) proc enumHasHoles(t: PType): bool = var b = t |