diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/jsgen.nim | 48 | ||||
-rw-r--r-- | compiler/llstream.nim | 6 | ||||
-rw-r--r-- | compiler/parser.nim | 39 | ||||
-rw-r--r-- | compiler/sem.nim | 8 | ||||
-rw-r--r-- | compiler/semexprs.nim | 27 | ||||
-rw-r--r-- | compiler/semfields.nim | 4 | ||||
-rw-r--r-- | compiler/semfold.nim | 75 | ||||
-rw-r--r-- | compiler/semstmts.nim | 73 | ||||
-rw-r--r-- | compiler/semtypes.nim | 17 | ||||
-rw-r--r-- | compiler/transf.nim | 6 |
10 files changed, 171 insertions, 132 deletions
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 1878081fd..aa2386526 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1540,18 +1540,18 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) = if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar: r.res.add("[$1].concat(" % [a.res]) else: - r.res.add("($1.slice(0,-1)).concat(" % [a.res]) + r.res.add("($1).concat(" % [a.res]) for i in countup(2, sonsLen(n) - 2): gen(p, n.sons[i], a) if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar: r.res.add("[$1]," % [a.res]) else: - r.res.add("$1.slice(0,-1)," % [a.res]) + r.res.add("$1," % [a.res]) gen(p, n.sons[sonsLen(n) - 1], a) if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar: - r.res.add("[$1, 0])" % [a.res]) + r.res.add("[$1])" % [a.res]) else: r.res.add("$1)" % [a.res]) @@ -1658,14 +1658,20 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)") of mAppendStrCh: binaryExpr(p, n, r, "addChar", - "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }") + "if ($1 != null) { addChar($1, $2); } else { $1 = [$2]; }") of mAppendStrStr: + var lhs, rhs: TCompRes + gen(p, n[1], lhs) + gen(p, n[2], rhs) + + let rhsIsLit = n[2].kind in nkStrKinds if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString: - binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }") + r.res = "if ($1 != null) { $1 += $2; } else { $1 = $2$3; }" % [ + lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()"] else: - binaryExpr(p, n, r, "", - "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}") - # XXX: make a copy of $2, because of Javascript's sucking semantics + r.res = "if ($1 != null) { $1 = ($1).concat($2); } else { $1 = $2$3; }" % [ + lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()"] + r.kind = resExpr of mAppendSeqElem: var x, y: TCompRes gen(p, n.sons[1], x) @@ -1693,21 +1699,12 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mSizeOf: r.res = rope(getSize(p.config, n.sons[1].typ)) of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do of mOrd: genOrd(p, n, r) - of mLengthStr: - if n.sons[1].typ.skipTypes(abstractInst).kind == tyCString: - unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)") - else: - unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)") - of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1") - of mLengthSeq, mLengthOpenArray, mLengthArray: + of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray: unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)") - of mXLenSeq: + of mXLenStr, mXLenSeq: unaryExpr(p, n, r, "", "$1.length") of mHigh: - if skipTypes(n.sons[1].typ, abstractVar).kind == tyString: - unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)") - else: - unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)") + unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)") of mInc: if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64: binaryUintExpr(p, n, r, "+", true) @@ -1721,7 +1718,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2") else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)") of mSetLengthStr: - binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0") + binaryExpr(p, n, r, "", "$1.length = $2") of mSetLengthSeq: var x, y: TCompRes gen(p, n.sons[1], x) @@ -1750,8 +1747,6 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = localError(p.config, n.info, errXMustBeCompileTime % n.sons[0].sym.name.s) of mCopyStr: binaryExpr(p, n, r, "", "($1.slice($2))") - of mCopyStrLast: - ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))") of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)") of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)") @@ -2076,8 +2071,11 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = r.kind = resExpr of nkStrLit..nkTripleStrLit: if skipTypes(n.typ, abstractVarRange).kind == tyString: - useMagic(p, "makeNimstrLit") - r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)] + if n.strVal.len != 0: + useMagic(p, "makeNimstrLit") + r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)] + else: + r.res = rope"[]" else: r.res = makeJSString(n.strVal, false) r.kind = resExpr diff --git a/compiler/llstream.nim b/compiler/llstream.nim index e121901b1..e1108147f 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -87,9 +87,9 @@ proc endsWithOpr*(x: string): bool = result = x.endsWith(LineContinuationOprs) proc continueLine(line: string, inTripleString: bool): bool {.inline.} = - result = inTripleString or - line[0] == ' ' or - line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs) + result = inTripleString or line.len > 0 and ( + line[0] == ' ' or + line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)) proc countTriples(s: string): int = var i = 0 diff --git a/compiler/parser.nim b/compiler/parser.nim index 245d2e390..7667d3a0e 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -538,7 +538,7 @@ proc parsePar(p: var TParser): PNode = flexComment(p, result) if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase, tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock, - tkConst, tkLet, tkWhen, tkVar, + tkConst, tkLet, tkWhen, tkVar, tkFor, tkMixin}: # XXX 'bind' used to be an expression, so we exclude it here; # tests/reject/tbind2 fails otherwise. @@ -1113,7 +1113,7 @@ proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode = proc isExprStart(p: TParser): bool = case p.tok.tokType - of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, + of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkFor, tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics, tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, tkTuple, tkObject, tkWhen, tkCase, tkOut: @@ -1153,16 +1153,35 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, result.addSon list parseSymbolList(p, list) +proc parseFor(p: var TParser): PNode = + #| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt + #| forExpr = forStmt + result = newNodeP(nkForStmt, p) + getTokNoInd(p) + var a = identWithPragma(p) + addSon(result, a) + while p.tok.tokType == tkComma: + getTok(p) + optInd(p, a) + a = identWithPragma(p) + addSon(result, a) + eat(p, tkIn) + addSon(result, parseExpr(p)) + colcom(p, result) + addSon(result, parseStmt(p)) + proc parseExpr(p: var TParser): PNode = #| expr = (blockExpr #| | ifExpr #| | whenExpr #| | caseExpr + #| | forExpr #| | tryExpr) #| / simpleExpr case p.tok.tokType: of tkBlock: result = parseBlock(p) of tkIf: result = parseIfExpr(p, nkIfExpr) + of tkFor: result = parseFor(p) of tkWhen: result = parseIfExpr(p, nkWhenExpr) of tkCase: result = parseCase(p) of tkTry: result = parseTry(p, isExpr=true) @@ -1569,22 +1588,6 @@ proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode = colcom(p, result) addSon(result, parseStmt(p)) -proc parseFor(p: var TParser): PNode = - #| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt - result = newNodeP(nkForStmt, p) - getTokNoInd(p) - var a = identWithPragma(p) - addSon(result, a) - while p.tok.tokType == tkComma: - getTok(p) - optInd(p, a) - a = identWithPragma(p) - addSon(result, a) - eat(p, tkIn) - addSon(result, parseExpr(p)) - colcom(p, result) - addSon(result, parseStmt(p)) - proc parseBlock(p: var TParser): PNode = #| blockStmt = 'block' symbol? colcom stmt #| blockExpr = 'block' symbol? colcom stmt diff --git a/compiler/sem.nim b/compiler/sem.nim index 7a83c3079..5e5205c20 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -37,7 +37,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode proc semTypeNode(c: PContext, n: PNode, prev: PType): PType -proc semStmt(c: PContext, n: PNode): PNode +proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode proc semOpAux(c: PContext, n: PNode) proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) proc addParams(c: PContext, n: PNode, kind: TSymKind) @@ -399,7 +399,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, excl(result.flags, nfSem) #resetSemFlag n if s.typ.sons[0] == nil: - result = semStmt(c, result) + result = semStmt(c, result, flags) else: case s.typ.sons[0].kind of tyExpr: @@ -408,7 +408,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, # semExprWithType(c, result) result = semExpr(c, result, flags) of tyStmt: - result = semStmt(c, result) + result = semStmt(c, result, flags) of tyTypeDesc: if result.kind == nkStmtList: result.kind = nkStmtListType var typ = semTypeNode(c, result, nil) @@ -557,7 +557,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = result = semAllTypeSections(c, n) else: result = n - result = semStmt(c, result) + result = semStmt(c, result, {}) when false: # Code generators are lazy now and can deal with undeclared procs, so these # steps are not required anymore and actually harmful for the upcoming diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index ce953f17c..43f04fc9f 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -113,6 +113,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus = if castDest.kind notin IntegralTypes+{tyRange}: result = convNotNeedeed return + # Save for later var d = skipTypes(castDest, abstractVar) var s = src if s.kind in tyUserTypeClasses and s.isResolvedUserTypeClass: @@ -135,7 +136,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus = # we use d, s here to speed up that operation a bit: case cmpTypes(c, d, s) of isNone, isGeneric: - if not compareTypes(castDest, src, dcEqIgnoreDistinct): + if not compareTypes(castDest.skipTypes(abstractVar), src, dcEqIgnoreDistinct): result = convNotLegal else: discard @@ -917,7 +918,7 @@ proc semExprNoType(c: PContext, n: PNode): PNode = let isPush = hintExtendedContext in c.config.notes if isPush: pushInfoContext(c.config, n.info) result = semExpr(c, n, {efWantStmt}) - discardCheck(c, result) + discardCheck(c, result, {}) if isPush: popInfoContext(c.config) proc isTypeExpr(n: PNode): bool = @@ -1529,7 +1530,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = # unfortunately we need to rewrite ``(x, y) = foo()`` already here so # that overloading of the assignment operator still works. Usually we # prefer to do these rewritings in transf.nim: - return semStmt(c, lowerTupleUnpackingForAsgn(c.graph, n, c.p.owner)) + return semStmt(c, lowerTupleUnpackingForAsgn(c.graph, n, c.p.owner), {}) else: a = semExprWithType(c, a, {efLValue}) else: @@ -1613,7 +1614,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = a.sons[1] = result result = semAsgn(c, a) else: - discardCheck(c, result) + discardCheck(c, result, {}) if c.p.owner.kind notin {skMacro, skTemplate} and c.p.resultSym != nil and c.p.resultSym.typ.isMetaType: @@ -1989,7 +1990,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = var x = n.lastSon if x.kind == nkDo: x = x.sons[bodyPos] inc c.inParallelStmt - result.sons[1] = semStmt(c, x) + result.sons[1] = semStmt(c, x, {}) dec c.inParallelStmt of mSpawn: result = setMs(n, s) @@ -2240,7 +2241,7 @@ proc isTupleType(n: PNode): bool = include semobjconstr -proc semBlock(c: PContext, n: PNode): PNode = +proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode = result = n inc(c.p.nestedBlockCounter) checkSonsLen(n, 2, c.config) @@ -2252,7 +2253,7 @@ proc semBlock(c: PContext, n: PNode): PNode = n.sons[0] = newSymNode(labl, n.sons[0].info) suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym) styleCheckDef(c.config, labl) - n.sons[1] = semExpr(c, n.sons[1]) + n.sons[1] = semExpr(c, n.sons[1], flags) n.typ = n.sons[1].typ if isEmptyType(n.typ): n.kind = nkBlockStmt else: n.kind = nkBlockExpr @@ -2497,7 +2498,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = checkSonsLen(n, 1, c.config) n.sons[0] = semExpr(c, n.sons[0], flags) of nkCast: result = semCast(c, n) - of nkIfExpr, nkIfStmt: result = semIf(c, n) + of nkIfExpr, nkIfStmt: result = semIf(c, n, flags) of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv: checkSonsLen(n, 2, c.config) considerGenSyms(c, n) @@ -2518,7 +2519,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = discard of nkStaticExpr: result = semStaticExpr(c, n[0]) of nkAsgn: result = semAsgn(c, n) - of nkBlockStmt, nkBlockExpr: result = semBlock(c, n) + of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags) of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags) of nkRaiseStmt: result = semRaise(c, n) of nkVarSection: result = semVarOrLet(c, n, skVar) @@ -2526,11 +2527,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkConstSection: result = semConst(c, n) of nkTypeSection: result = semTypeSection(c, n) of nkDiscardStmt: result = semDiscard(c, n) - of nkWhileStmt: result = semWhile(c, n) - of nkTryStmt: result = semTry(c, n) + of nkWhileStmt: result = semWhile(c, n, flags) + of nkTryStmt: result = semTry(c, n, flags) of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n) - of nkForStmt, nkParForStmt: result = semFor(c, n) - of nkCaseStmt: result = semCase(c, n) + of nkForStmt, nkParForStmt: result = semFor(c, n, flags) + of nkCaseStmt: result = semCase(c, n, flags) of nkReturnStmt: result = semReturn(c, n) of nkUsingStmt: result = semUsing(c, n) of nkAsmStmt: result = semAsm(c, n) diff --git a/compiler/semfields.nim b/compiler/semfields.nim index 869f5ae74..07321f477 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -70,7 +70,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = openScope(c.c) inc c.c.inUnrolledContext let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop) - father.add(semStmt(c.c, body)) + father.add(semStmt(c.c, body, {})) dec c.c.inUnrolledContext closeScope(c.c) of nkNilLit: discard @@ -145,7 +145,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = fc.replaceByFieldName = m == mFieldPairs var body = instFieldLoopBody(fc, loopBody, n) inc c.inUnrolledContext - stmts.add(semStmt(c, body)) + stmts.add(semStmt(c, body, {})) dec c.inUnrolledContext closeScope(c) else: diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 27a6af1f4..0018f0755 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -214,7 +214,24 @@ proc evalIs(n: PNode, lhs: PSym, g: ModuleGraph): PNode = result = newIntNode(nkIntLit, ord(res)) result.typ = n.typ +proc fitLiteral(c: ConfigRef, n: PNode): PNode = + # Trim the literal value in order to make it fit in the destination type + if n == nil: + # `n` may be nil if the overflow check kicks in + return + + doAssert n.kind in {nkIntLit, nkCharLit} + + result = n + + let typ = n.typ.skipTypes(abstractRange) + if typ.kind in tyUInt..tyUint32: + result.intVal = result.intVal and lastOrd(c, typ, fixedUnsigned=true) + proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = + template doAndFit(op: untyped): untyped = + # Implements wrap-around behaviour for unsigned types + fitLiteral(g.config, op) # b and c may be nil result = nil case m @@ -224,12 +241,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g) of mNot: result = newIntNodeT(1 - getInt(a), n, g) of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g) - of mBitnotI: - case skipTypes(n.typ, abstractRange).kind - of tyUInt..tyUInt64: - result = newIntNodeT((not getInt(a)) and lastOrd(g.config, a.typ, fixedUnsigned=true), n, g) - else: - result = newIntNodeT(not getInt(a), n, g) + of mBitnotI: result = doAndFit(newIntNodeT(not getInt(a), n, g)) of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g) of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr: if a.kind == nkNilLit: @@ -251,9 +263,9 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g) of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g) of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g) - of mUnaryLt: result = foldSub(getOrdValue(a), 1, n, g) - of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g) - of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g) + of mUnaryLt: result = doAndFit(foldSub(getOrdValue(a), 1, n, g)) + of mSucc: result = doAndFit(foldAdd(getOrdValue(a), getInt(b), n, g)) + of mPred: result = doAndFit(foldSub(getOrdValue(a), getInt(b), n, g)) of mAddI: result = foldAdd(getInt(a), getInt(b), n, g) of mSubI: result = foldSub(getInt(a), getInt(b), n, g) of mMulI: result = foldMul(getInt(a), getInt(b), n, g) @@ -271,7 +283,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of tyInt64, tyInt: result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g) of tyUInt..tyUInt64: - result = newIntNodeT(`shl`(getInt(a), getInt(b)) and lastOrd(g.config, a.typ, fixedUnsigned=true), n, g) + result = doAndFit(newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)) else: internalError(g.config, n.info, "constant folding for shl") of mShrI: case skipTypes(n.typ, abstractRange).kind @@ -324,14 +336,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g) of mLeU, mLeU64: result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g) - of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n, g) - of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n, g) - of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n, g) - of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n, g) - of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n, g) - of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g) - of mModU: result = foldModU(getInt(a), getInt(b), n, g) - of mDivU: result = foldDivU(getInt(a), getInt(b), n, g) + of mBitandI, mAnd: result = doAndFit(newIntNodeT(a.getInt and b.getInt, n, g)) + of mBitorI, mOr: result = doAndFit(newIntNodeT(getInt(a) or getInt(b), n, g)) + of mBitxorI, mXor: result = doAndFit(newIntNodeT(a.getInt xor b.getInt, n, g)) + of mAddU: result = doAndFit(newIntNodeT(`+%`(getInt(a), getInt(b)), n, g)) + of mSubU: result = doAndFit(newIntNodeT(`-%`(getInt(a), getInt(b)), n, g)) + of mMulU: result = doAndFit(newIntNodeT(`*%`(getInt(a), getInt(b)), n, g)) + of mModU: result = doAndFit(foldModU(getInt(a), getInt(b), n, g)) + of mDivU: result = doAndFit(foldDivU(getInt(a), getInt(b), n, g)) of mLeSet: result = newIntNodeT(ord(containsSets(g.config, a, b)), n, g) of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g) of mLtSet: @@ -462,17 +474,24 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode = result = newIntNodeT(int(getFloat(a)), n, g) of tyChar: result = newIntNodeT(getOrdValue(a), n, g) - of tyUInt8..tyUInt32, tyInt8..tyInt32: - let fromSigned = srcTyp.kind in tyInt..tyInt64 + of tyUInt..tyUInt64, tyInt..tyInt64: let toSigned = dstTyp.kind in tyInt..tyInt64 - - let mask = lastOrd(g.config, dstTyp, fixedUnsigned=true) - - var val = - if toSigned: - a.getOrdValue mod mask - else: - a.getOrdValue and mask + var val = a.getOrdValue + + if dstTyp.kind in {tyInt, tyInt64, tyUint, tyUInt64}: + # No narrowing needed + discard + elif dstTyp.kind in {tyInt..tyInt64}: + # Signed type: Overflow check (if requested) and conversion + if check: rangeCheck(n, val, g) + let mask = (`shl`(1, getSize(g.config, dstTyp) * 8) - 1) + let valSign = val < 0 + val = abs(val) and mask + if valSign: val = -val + else: + # Unsigned type: Conversion + let mask = (`shl`(1, getSize(g.config, dstTyp) * 8) - 1) + val = val and mask result = newIntNodeT(val, n, g) else: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index fb01127fc..566b634af 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -76,17 +76,19 @@ proc semAsm(c: PContext, n: PNode): PNode = if marker == '\0': marker = '`' # default marker result = semAsmOrEmit(c, n, marker) -proc semWhile(c: PContext, n: PNode): PNode = +proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode = result = n checkSonsLen(n, 2, c.config) openScope(c) n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0])) inc(c.p.nestedLoopCounter) - n.sons[1] = semStmt(c, n.sons[1]) + n.sons[1] = semStmt(c, n.sons[1], flags) dec(c.p.nestedLoopCounter) closeScope(c) if n.sons[1].typ == c.enforceVoidContext: result.typ = c.enforceVoidContext + elif efInTypeof in flags: + result.typ = n[1].typ proc toCover(c: PContext, t: PType): BiggestInt = let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc}) @@ -97,8 +99,8 @@ proc toCover(c: PContext, t: PType): BiggestInt = proc semProc(c: PContext, n: PNode): PNode -proc semExprBranch(c: PContext, n: PNode): PNode = - result = semExpr(c, n) +proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}): PNode = + result = semExpr(c, n, flags) if result.typ != nil: # XXX tyGenericInst here? if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) @@ -130,8 +132,9 @@ proc fixNilType(c: PContext; n: PNode) = for it in n: fixNilType(c, it) n.typ = nil -proc discardCheck(c: PContext, result: PNode) = - if c.matchedConcept != nil: return +proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) = + if c.matchedConcept != nil or efInTypeof in flags: return + if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}: if implicitlyDiscardable(result): var n = newNodeI(nkDiscardStmt, result.info, 1) @@ -148,7 +151,7 @@ proc discardCheck(c: PContext, result: PNode) = s.add "; for a function call use ()" localError(c.config, n.info, s) -proc semIf(c: PContext, n: PNode): PNode = +proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode = result = n var typ = commonTypeBegin var hasElse = false @@ -165,8 +168,9 @@ proc semIf(c: PContext, n: PNode): PNode = it.sons[0] = semExprBranchScope(c, it.sons[0]) typ = commonType(typ, it.sons[0]) else: illFormedAst(it, c.config) - if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: - for it in n: discardCheck(c, it.lastSon) + if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or + (not hasElse and efInTypeof notin flags): + for it in n: discardCheck(c, it.lastSon, flags) result.kind = nkIfStmt # propagate any enforced VoidContext: if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext @@ -178,8 +182,7 @@ proc semIf(c: PContext, n: PNode): PNode = result.kind = nkIfExpr result.typ = typ -proc semTry(c: PContext, n: PNode): PNode = - +proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode = var check = initIntSet() template semExceptBranchType(typeNode: PNode): bool = # returns true if exception type is imported type @@ -246,12 +249,12 @@ proc semTry(c: PContext, n: PNode): PNode = dec c.p.inTryStmt if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}: - discardCheck(c, n.sons[0]) - for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) + discardCheck(c, n.sons[0], flags) + for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags) if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext else: - if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon) + if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags) n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info) for i in 1..last: var it = n.sons[i] @@ -570,7 +573,7 @@ proc symForVar(c: PContext, n: PNode): PSym = if n.kind == nkPragmaExpr: pragma(c, result, n.sons[1], forVarPragmas) -proc semForVars(c: PContext, n: PNode): PNode = +proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = result = n var length = sonsLen(n) let iterBase = n.sons[length-2].typ @@ -601,7 +604,7 @@ proc semForVars(c: PContext, n: PNode): PNode = addForVarDecl(c, v) inc(c.p.nestedLoopCounter) openScope(c) - n.sons[length-1] = semStmt(c, n.sons[length-1]) + n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags) closeScope(c) dec(c.p.nestedLoopCounter) @@ -685,7 +688,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode = when false: result = handleStmtMacro(c, n, n[0], "CaseStmt") -proc semFor(c: PContext, n: PNode): PNode = +proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode = checkMinSonsLen(n, 3, c.config) var length = sonsLen(n) if forLoopMacros in c.features: @@ -702,14 +705,14 @@ proc semFor(c: PContext, n: PNode): PNode = if isCallExpr and call[0].kind == nkSym and call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}: if call.sons[0].sym.magic == mOmpParFor: - result = semForVars(c, n) + result = semForVars(c, n, flags) result.kind = nkParForStmt else: result = semForFields(c, n, call.sons[0].sym.magic) elif isCallExpr and call.sons[0].typ.callConv == ccClosure and tfIterator in call.sons[0].typ.flags: # first class iterator: - result = semForVars(c, n) + result = semForVars(c, n, flags) elif not isCallExpr or call.sons[0].kind != nkSym or call.sons[0].sym.kind != skIterator: if length == 3: @@ -718,15 +721,17 @@ proc semFor(c: PContext, n: PNode): PNode = n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2]) else: localError(c.config, n.sons[length-2].info, "iterator within for loop context expected") - result = semForVars(c, n) + result = semForVars(c, n, flags) else: - result = semForVars(c, n) + result = semForVars(c, n, flags) # propagate any enforced VoidContext: if n.sons[length-1].typ == c.enforceVoidContext: result.typ = c.enforceVoidContext + elif efInTypeof in flags: + result.typ = result.lastSon.typ closeScope(c) -proc semCase(c: PContext, n: PNode): PNode = +proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode = result = n checkMinSonsLen(n, 2, c.config) openScope(c) @@ -782,8 +787,9 @@ proc semCase(c: PContext, n: PNode): PNode = else: localError(c.config, n.info, "not all cases are 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) + if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or + (not hasElse and efInTypeof notin flags): + for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags) # propagate any enforced VoidContext: if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext @@ -1173,6 +1179,9 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) = if b != nil: # store the alias: n.sons[bodyPos] = newSymNode(b) + # Carry over the original symbol magic, this is necessary in order to ensure + # the semantic pass is correct + s.magic = b.magic else: localError(c.config, n.info, errNoSymbolToBorrowFromFound) @@ -1792,7 +1801,7 @@ proc evalInclude(c: PContext, n: PNode): PNode = if containsOrIncl(c.includedFiles, f.int): localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f)) else: - addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f))) + addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {})) excl(c.includedFiles, f.int) proc setLine(n: PNode, info: TLineInfo) = @@ -1819,7 +1828,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode = #writeStackTrace() inc c.inStaticContext openScope(c) - let a = semStmt(c, n.sons[0]) + let a = semStmt(c, n.sons[0], {}) closeScope(c) dec c.inStaticContext n.sons[0] = a @@ -1895,11 +1904,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = if n.sons[i].typ == c.enforceVoidContext: #or usesResult(n.sons[i]): voidContext = true n.typ = c.enforceVoidContext - if i == last and (length == 1 or efWantValue in flags): + if i == last and (length == 1 or ({efWantValue, efInTypeof} * flags != {})): n.typ = n.sons[i].typ if not isEmptyType(n.typ): n.kind = nkStmtListExpr elif i != last or voidContext: - discardCheck(c, n.sons[i]) + discardCheck(c, n.sons[i], flags) else: n.typ = n.sons[i].typ if not isEmptyType(n.typ): n.kind = nkStmtListExpr @@ -1928,6 +1937,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = # it is an old-style comment statement: we replace it with 'discard ""': prettybase.replaceComment(result.info) -proc semStmt(c: PContext, n: PNode): PNode = - # now: simply an alias: - result = semExprNoType(c, n) +proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode = + if efInTypeof notin flags: + result = semExprNoType(c, n) + else: + result = semExpr(c, n, flags) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 86f3a17ab..a90a06150 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1161,7 +1161,7 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = checkMinSonsLen(n, 1, c.config) var length = sonsLen(n) for i in countup(0, length - 2): - n.sons[i] = semStmt(c, n.sons[i]) + n.sons[i] = semStmt(c, n.sons[i], {}) if length > 0: result = semTypeNode(c, n.sons[length - 1], prev) n.typ = result @@ -1406,6 +1406,13 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType = result.rawAddSon(base) result.flags.incl tfHasStatic +proc semTypeof(c: PContext; n: PNode; prev: PType): PType = + openScope(c) + let t = semExprWithType(c, n, {efInTypeof}) + closeScope(c) + fixupTypeOf(c, prev, t) + result = t.typ + proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = nil inc c.inTypeContext @@ -1416,9 +1423,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkTypeOfExpr: # for ``type(countup(1,3))``, see ``tests/ttoseq``. checkSonsLen(n, 1, c.config) - let typExpr = semExprWithType(c, n.sons[0], {efInTypeof}) - fixupTypeOf(c, prev, typExpr) - result = typExpr.typ + result = semTypeof(c, n.sons[0], prev) if result.kind == tyTypeDesc: result.flags.incl tfExplicit of nkPar: if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) @@ -1487,9 +1492,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = semAnyRef(c, n, tyRef, prev) elif op.id == ord(wType): checkSonsLen(n, 2, c.config) - let typExpr = semExprWithType(c, n.sons[1], {efInTypeof}) - fixupTypeOf(c, prev, typExpr) - result = typExpr.typ + result = semTypeof(c, n[1], prev) else: if c.inGenericContext > 0 and n.kind == nkCall: result = makeTypeFromExpr(c, n.copyTree) diff --git a/compiler/transf.nim b/compiler/transf.nim index 84297aa6a..347df3e49 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -624,7 +624,11 @@ proc transformCase(c: PTransf, n: PNode): PTransNode = case it.kind of nkElifBranch: if ifs.PNode == nil: - ifs = newTransNode(nkIfStmt, it.info, 0) + # Generate the right node depending on whether `n` is used as a stmt or + # as an expr + let kind = if n.typ != nil: nkIfExpr else: nkIfStmt + ifs = newTransNode(kind, it.info, 0) + ifs.PNode.typ = n.typ ifs.add(e) of nkElse: if ifs.PNode == nil: result.add(e) |