Merge branch 'devel' into araq-better-docgen

This commit is contained in:
Araq 2018-09-14 15:48:07 +02:00
commit 5709736e82
27 changed files with 383 additions and 160 deletions

View file

@ -1540,18 +1540,18 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar: if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
r.res.add("[$1].concat(" % [a.res]) r.res.add("[$1].concat(" % [a.res])
else: 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): for i in countup(2, sonsLen(n) - 2):
gen(p, n.sons[i], a) gen(p, n.sons[i], a)
if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar: if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
r.res.add("[$1]," % [a.res]) r.res.add("[$1]," % [a.res])
else: else:
r.res.add("$1.slice(0,-1)," % [a.res]) r.res.add("$1," % [a.res])
gen(p, n.sons[sonsLen(n) - 1], a) gen(p, n.sons[sonsLen(n) - 1], a)
if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar: 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: else:
r.res.add("$1)" % [a.res]) 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)") else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
of mAppendStrCh: of mAppendStrCh:
binaryExpr(p, n, r, "addChar", 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: 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: 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: else:
binaryExpr(p, n, r, "", r.res = "if ($1 != null) { $1 = ($1).concat($2); } else { $1 = $2$3; }" % [
"if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}") lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()"]
# XXX: make a copy of $2, because of Javascript's sucking semantics r.kind = resExpr
of mAppendSeqElem: of mAppendSeqElem:
var x, y: TCompRes var x, y: TCompRes
gen(p, n.sons[1], x) 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 mSizeOf: r.res = rope(getSize(p.config, n.sons[1].typ))
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
of mOrd: genOrd(p, n, r) of mOrd: genOrd(p, n, r)
of mLengthStr: of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
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:
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)") unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
of mXLenSeq: of mXLenStr, mXLenSeq:
unaryExpr(p, n, r, "", "$1.length") unaryExpr(p, n, r, "", "$1.length")
of mHigh: of mHigh:
if skipTypes(n.sons[1].typ, abstractVar).kind == tyString: unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)")
else:
unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
of mInc: of mInc:
if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64: if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
binaryUintExpr(p, n, r, "+", true) 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") if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)") else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
of mSetLengthStr: of mSetLengthStr:
binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0") binaryExpr(p, n, r, "", "$1.length = $2")
of mSetLengthSeq: of mSetLengthSeq:
var x, y: TCompRes var x, y: TCompRes
gen(p, n.sons[1], x) 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) localError(p.config, n.info, errXMustBeCompileTime % n.sons[0].sym.name.s)
of mCopyStr: of mCopyStr:
binaryExpr(p, n, r, "", "($1.slice($2))") 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 mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
of mNewStringOfCap: of mNewStringOfCap:
unaryExpr(p, n, r, "mnewString", "mnewString(0)") unaryExpr(p, n, r, "mnewString", "mnewString(0)")
@ -2076,8 +2071,11 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.kind = resExpr r.kind = resExpr
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if skipTypes(n.typ, abstractVarRange).kind == tyString: if skipTypes(n.typ, abstractVarRange).kind == tyString:
useMagic(p, "makeNimstrLit") if n.strVal.len != 0:
r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)] useMagic(p, "makeNimstrLit")
r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
else:
r.res = rope"[]"
else: else:
r.res = makeJSString(n.strVal, false) r.res = makeJSString(n.strVal, false)
r.kind = resExpr r.kind = resExpr

View file

@ -87,9 +87,9 @@ proc endsWithOpr*(x: string): bool =
result = x.endsWith(LineContinuationOprs) result = x.endsWith(LineContinuationOprs)
proc continueLine(line: string, inTripleString: bool): bool {.inline.} = proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
result = inTripleString or result = inTripleString or line.len > 0 and (
line[0] == ' ' or line[0] == ' ' or
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs) line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs))
proc countTriples(s: string): int = proc countTriples(s: string): int =
var i = 0 var i = 0

View file

@ -538,7 +538,7 @@ proc parsePar(p: var TParser): PNode =
flexComment(p, result) flexComment(p, result)
if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase, if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock, tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
tkConst, tkLet, tkWhen, tkVar, tkConst, tkLet, tkWhen, tkVar, tkFor,
tkMixin}: tkMixin}:
# XXX 'bind' used to be an expression, so we exclude it here; # XXX 'bind' used to be an expression, so we exclude it here;
# tests/reject/tbind2 fails otherwise. # tests/reject/tbind2 fails otherwise.
@ -1113,7 +1113,7 @@ proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
proc isExprStart(p: TParser): bool = proc isExprStart(p: TParser): bool =
case p.tok.tokType 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, tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
tkTuple, tkObject, tkWhen, tkCase, tkOut: tkTuple, tkObject, tkWhen, tkCase, tkOut:
@ -1153,16 +1153,35 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
result.addSon list result.addSon list
parseSymbolList(p, 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 = proc parseExpr(p: var TParser): PNode =
#| expr = (blockExpr #| expr = (blockExpr
#| | ifExpr #| | ifExpr
#| | whenExpr #| | whenExpr
#| | caseExpr #| | caseExpr
#| | forExpr
#| | tryExpr) #| | tryExpr)
#| / simpleExpr #| / simpleExpr
case p.tok.tokType: case p.tok.tokType:
of tkBlock: result = parseBlock(p) of tkBlock: result = parseBlock(p)
of tkIf: result = parseIfExpr(p, nkIfExpr) of tkIf: result = parseIfExpr(p, nkIfExpr)
of tkFor: result = parseFor(p)
of tkWhen: result = parseIfExpr(p, nkWhenExpr) of tkWhen: result = parseIfExpr(p, nkWhenExpr)
of tkCase: result = parseCase(p) of tkCase: result = parseCase(p)
of tkTry: result = parseTry(p, isExpr=true) of tkTry: result = parseTry(p, isExpr=true)
@ -1569,22 +1588,6 @@ proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
colcom(p, result) colcom(p, result)
addSon(result, parseStmt(p)) 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 = proc parseBlock(p: var TParser): PNode =
#| blockStmt = 'block' symbol? colcom stmt #| blockStmt = 'block' symbol? colcom stmt
#| blockExpr = 'block' symbol? colcom stmt #| blockExpr = 'block' symbol? colcom stmt

View file

@ -37,7 +37,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType 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 semOpAux(c: PContext, n: PNode)
proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
proc addParams(c: PContext, n: PNode, kind: TSymKind) proc addParams(c: PContext, n: PNode, kind: TSymKind)
@ -399,7 +399,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
excl(result.flags, nfSem) excl(result.flags, nfSem)
#resetSemFlag n #resetSemFlag n
if s.typ.sons[0] == nil: if s.typ.sons[0] == nil:
result = semStmt(c, result) result = semStmt(c, result, flags)
else: else:
case s.typ.sons[0].kind case s.typ.sons[0].kind
of tyExpr: of tyExpr:
@ -408,7 +408,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
# semExprWithType(c, result) # semExprWithType(c, result)
result = semExpr(c, result, flags) result = semExpr(c, result, flags)
of tyStmt: of tyStmt:
result = semStmt(c, result) result = semStmt(c, result, flags)
of tyTypeDesc: of tyTypeDesc:
if result.kind == nkStmtList: result.kind = nkStmtListType if result.kind == nkStmtList: result.kind = nkStmtListType
var typ = semTypeNode(c, result, nil) var typ = semTypeNode(c, result, nil)
@ -557,7 +557,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
result = semAllTypeSections(c, n) result = semAllTypeSections(c, n)
else: else:
result = n result = n
result = semStmt(c, result) result = semStmt(c, result, {})
when false: when false:
# Code generators are lazy now and can deal with undeclared procs, so these # Code generators are lazy now and can deal with undeclared procs, so these
# steps are not required anymore and actually harmful for the upcoming # steps are not required anymore and actually harmful for the upcoming

View file

@ -113,6 +113,7 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
if castDest.kind notin IntegralTypes+{tyRange}: if castDest.kind notin IntegralTypes+{tyRange}:
result = convNotNeedeed result = convNotNeedeed
return return
# Save for later
var d = skipTypes(castDest, abstractVar) var d = skipTypes(castDest, abstractVar)
var s = src var s = src
if s.kind in tyUserTypeClasses and s.isResolvedUserTypeClass: 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: # we use d, s here to speed up that operation a bit:
case cmpTypes(c, d, s) case cmpTypes(c, d, s)
of isNone, isGeneric: of isNone, isGeneric:
if not compareTypes(castDest, src, dcEqIgnoreDistinct): if not compareTypes(castDest.skipTypes(abstractVar), src, dcEqIgnoreDistinct):
result = convNotLegal result = convNotLegal
else: else:
discard discard
@ -917,7 +918,7 @@ proc semExprNoType(c: PContext, n: PNode): PNode =
let isPush = hintExtendedContext in c.config.notes let isPush = hintExtendedContext in c.config.notes
if isPush: pushInfoContext(c.config, n.info) if isPush: pushInfoContext(c.config, n.info)
result = semExpr(c, n, {efWantStmt}) result = semExpr(c, n, {efWantStmt})
discardCheck(c, result) discardCheck(c, result, {})
if isPush: popInfoContext(c.config) if isPush: popInfoContext(c.config)
proc isTypeExpr(n: PNode): bool = 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 # unfortunately we need to rewrite ``(x, y) = foo()`` already here so
# that overloading of the assignment operator still works. Usually we # that overloading of the assignment operator still works. Usually we
# prefer to do these rewritings in transf.nim: # 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: else:
a = semExprWithType(c, a, {efLValue}) a = semExprWithType(c, a, {efLValue})
else: else:
@ -1613,7 +1614,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
a.sons[1] = result a.sons[1] = result
result = semAsgn(c, a) result = semAsgn(c, a)
else: else:
discardCheck(c, result) discardCheck(c, result, {})
if c.p.owner.kind notin {skMacro, skTemplate} and if c.p.owner.kind notin {skMacro, skTemplate} and
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType: 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 var x = n.lastSon
if x.kind == nkDo: x = x.sons[bodyPos] if x.kind == nkDo: x = x.sons[bodyPos]
inc c.inParallelStmt inc c.inParallelStmt
result.sons[1] = semStmt(c, x) result.sons[1] = semStmt(c, x, {})
dec c.inParallelStmt dec c.inParallelStmt
of mSpawn: of mSpawn:
result = setMs(n, s) result = setMs(n, s)
@ -2240,7 +2241,7 @@ proc isTupleType(n: PNode): bool =
include semobjconstr include semobjconstr
proc semBlock(c: PContext, n: PNode): PNode = proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
result = n result = n
inc(c.p.nestedBlockCounter) inc(c.p.nestedBlockCounter)
checkSonsLen(n, 2, c.config) 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) n.sons[0] = newSymNode(labl, n.sons[0].info)
suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym) suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
styleCheckDef(c.config, labl) 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 n.typ = n.sons[1].typ
if isEmptyType(n.typ): n.kind = nkBlockStmt if isEmptyType(n.typ): n.kind = nkBlockStmt
else: n.kind = nkBlockExpr else: n.kind = nkBlockExpr
@ -2497,7 +2498,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
checkSonsLen(n, 1, c.config) checkSonsLen(n, 1, c.config)
n.sons[0] = semExpr(c, n.sons[0], flags) n.sons[0] = semExpr(c, n.sons[0], flags)
of nkCast: result = semCast(c, n) 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: of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
checkSonsLen(n, 2, c.config) checkSonsLen(n, 2, c.config)
considerGenSyms(c, n) considerGenSyms(c, n)
@ -2518,7 +2519,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
discard discard
of nkStaticExpr: result = semStaticExpr(c, n[0]) of nkStaticExpr: result = semStaticExpr(c, n[0])
of nkAsgn: result = semAsgn(c, n) 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 nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
of nkRaiseStmt: result = semRaise(c, n) of nkRaiseStmt: result = semRaise(c, n)
of nkVarSection: result = semVarOrLet(c, n, skVar) 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 nkConstSection: result = semConst(c, n)
of nkTypeSection: result = semTypeSection(c, n) of nkTypeSection: result = semTypeSection(c, n)
of nkDiscardStmt: result = semDiscard(c, n) of nkDiscardStmt: result = semDiscard(c, n)
of nkWhileStmt: result = semWhile(c, n) of nkWhileStmt: result = semWhile(c, n, flags)
of nkTryStmt: result = semTry(c, n) of nkTryStmt: result = semTry(c, n, flags)
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n) of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
of nkForStmt, nkParForStmt: result = semFor(c, n) of nkForStmt, nkParForStmt: result = semFor(c, n, flags)
of nkCaseStmt: result = semCase(c, n) of nkCaseStmt: result = semCase(c, n, flags)
of nkReturnStmt: result = semReturn(c, n) of nkReturnStmt: result = semReturn(c, n)
of nkUsingStmt: result = semUsing(c, n) of nkUsingStmt: result = semUsing(c, n)
of nkAsmStmt: result = semAsm(c, n) of nkAsmStmt: result = semAsm(c, n)

View file

@ -70,7 +70,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
openScope(c.c) openScope(c.c)
inc c.c.inUnrolledContext inc c.c.inUnrolledContext
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop) let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
father.add(semStmt(c.c, body)) father.add(semStmt(c.c, body, {}))
dec c.c.inUnrolledContext dec c.c.inUnrolledContext
closeScope(c.c) closeScope(c.c)
of nkNilLit: discard of nkNilLit: discard
@ -145,7 +145,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
fc.replaceByFieldName = m == mFieldPairs fc.replaceByFieldName = m == mFieldPairs
var body = instFieldLoopBody(fc, loopBody, n) var body = instFieldLoopBody(fc, loopBody, n)
inc c.inUnrolledContext inc c.inUnrolledContext
stmts.add(semStmt(c, body)) stmts.add(semStmt(c, body, {}))
dec c.inUnrolledContext dec c.inUnrolledContext
closeScope(c) closeScope(c)
else: else:

View file

@ -214,7 +214,24 @@ proc evalIs(n: PNode, lhs: PSym, g: ModuleGraph): PNode =
result = newIntNode(nkIntLit, ord(res)) result = newIntNode(nkIntLit, ord(res))
result.typ = n.typ 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 = 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 # b and c may be nil
result = nil result = nil
case m 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 mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
of mNot: result = newIntNodeT(1 - getInt(a), n, g) of mNot: result = newIntNodeT(1 - getInt(a), n, g)
of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g) of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g)
of mBitnotI: of mBitnotI: result = doAndFit(newIntNodeT(not getInt(a), n, g))
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 mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g) of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr: of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
if a.kind == nkNilLit: 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 mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g)
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g) of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g) of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
of mUnaryLt: result = foldSub(getOrdValue(a), 1, n, g) of mUnaryLt: result = doAndFit(foldSub(getOrdValue(a), 1, n, g))
of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g) of mSucc: result = doAndFit(foldAdd(getOrdValue(a), getInt(b), n, g))
of mPred: result = foldSub(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 mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
of mSubI: result = foldSub(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) 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: of tyInt64, tyInt:
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g) result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
of tyUInt..tyUInt64: 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") else: internalError(g.config, n.info, "constant folding for shl")
of mShrI: of mShrI:
case skipTypes(n.typ, abstractRange).kind 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) result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g)
of mLeU, mLeU64: of mLeU, mLeU64:
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g) result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g)
of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n, g) of mBitandI, mAnd: result = doAndFit(newIntNodeT(a.getInt and b.getInt, n, g))
of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n, g) of mBitorI, mOr: result = doAndFit(newIntNodeT(getInt(a) or getInt(b), n, g))
of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n, g) of mBitxorI, mXor: result = doAndFit(newIntNodeT(a.getInt xor b.getInt, n, g))
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n, g) of mAddU: result = doAndFit(newIntNodeT(`+%`(getInt(a), getInt(b)), n, g))
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n, g) of mSubU: result = doAndFit(newIntNodeT(`-%`(getInt(a), getInt(b)), n, g))
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g) of mMulU: result = doAndFit(newIntNodeT(`*%`(getInt(a), getInt(b)), n, g))
of mModU: result = foldModU(getInt(a), getInt(b), n, g) of mModU: result = doAndFit(foldModU(getInt(a), getInt(b), n, g))
of mDivU: result = foldDivU(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 mLeSet: result = newIntNodeT(ord(containsSets(g.config, a, b)), n, g)
of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g) of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g)
of mLtSet: of mLtSet:
@ -462,17 +474,24 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
result = newIntNodeT(int(getFloat(a)), n, g) result = newIntNodeT(int(getFloat(a)), n, g)
of tyChar: of tyChar:
result = newIntNodeT(getOrdValue(a), n, g) result = newIntNodeT(getOrdValue(a), n, g)
of tyUInt8..tyUInt32, tyInt8..tyInt32: of tyUInt..tyUInt64, tyInt..tyInt64:
let fromSigned = srcTyp.kind in tyInt..tyInt64
let toSigned = dstTyp.kind in tyInt..tyInt64 let toSigned = dstTyp.kind in tyInt..tyInt64
var val = a.getOrdValue
let mask = lastOrd(g.config, dstTyp, fixedUnsigned=true) if dstTyp.kind in {tyInt, tyInt64, tyUint, tyUInt64}:
# No narrowing needed
var val = discard
if toSigned: elif dstTyp.kind in {tyInt..tyInt64}:
a.getOrdValue mod mask # Signed type: Overflow check (if requested) and conversion
else: if check: rangeCheck(n, val, g)
a.getOrdValue and mask 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) result = newIntNodeT(val, n, g)
else: else:

View file

@ -76,17 +76,19 @@ proc semAsm(c: PContext, n: PNode): PNode =
if marker == '\0': marker = '`' # default marker if marker == '\0': marker = '`' # default marker
result = semAsmOrEmit(c, n, marker) result = semAsmOrEmit(c, n, marker)
proc semWhile(c: PContext, n: PNode): PNode = proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
result = n result = n
checkSonsLen(n, 2, c.config) checkSonsLen(n, 2, c.config)
openScope(c) openScope(c)
n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0])) n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0]))
inc(c.p.nestedLoopCounter) 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) dec(c.p.nestedLoopCounter)
closeScope(c) closeScope(c)
if n.sons[1].typ == c.enforceVoidContext: if n.sons[1].typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext result.typ = c.enforceVoidContext
elif efInTypeof in flags:
result.typ = n[1].typ
proc toCover(c: PContext, t: PType): BiggestInt = proc toCover(c: PContext, t: PType): BiggestInt =
let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc}) 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 semProc(c: PContext, n: PNode): PNode
proc semExprBranch(c: PContext, n: PNode): PNode = proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}): PNode =
result = semExpr(c, n) result = semExpr(c, n, flags)
if result.typ != nil: if result.typ != nil:
# XXX tyGenericInst here? # XXX tyGenericInst here?
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) 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) for it in n: fixNilType(c, it)
n.typ = nil n.typ = nil
proc discardCheck(c: PContext, result: PNode) = proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
if c.matchedConcept != nil: return if c.matchedConcept != nil or efInTypeof in flags: return
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}: if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
if implicitlyDiscardable(result): if implicitlyDiscardable(result):
var n = newNodeI(nkDiscardStmt, result.info, 1) var n = newNodeI(nkDiscardStmt, result.info, 1)
@ -148,7 +151,7 @@ proc discardCheck(c: PContext, result: PNode) =
s.add "; for a function call use ()" s.add "; for a function call use ()"
localError(c.config, n.info, s) localError(c.config, n.info, s)
proc semIf(c: PContext, n: PNode): PNode = proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
result = n result = n
var typ = commonTypeBegin var typ = commonTypeBegin
var hasElse = false var hasElse = false
@ -165,8 +168,9 @@ proc semIf(c: PContext, n: PNode): PNode =
it.sons[0] = semExprBranchScope(c, it.sons[0]) it.sons[0] = semExprBranchScope(c, it.sons[0])
typ = commonType(typ, it.sons[0]) typ = commonType(typ, it.sons[0])
else: illFormedAst(it, c.config) else: illFormedAst(it, c.config)
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
for it in n: discardCheck(c, it.lastSon) (not hasElse and efInTypeof notin flags):
for it in n: discardCheck(c, it.lastSon, flags)
result.kind = nkIfStmt result.kind = nkIfStmt
# propagate any enforced VoidContext: # propagate any enforced VoidContext:
if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
@ -178,8 +182,7 @@ proc semIf(c: PContext, n: PNode): PNode =
result.kind = nkIfExpr result.kind = nkIfExpr
result.typ = typ result.typ = typ
proc semTry(c: PContext, n: PNode): PNode = proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
var check = initIntSet() var check = initIntSet()
template semExceptBranchType(typeNode: PNode): bool = template semExceptBranchType(typeNode: PNode): bool =
# returns true if exception type is imported type # returns true if exception type is imported type
@ -246,12 +249,12 @@ proc semTry(c: PContext, n: PNode): PNode =
dec c.p.inTryStmt dec c.p.inTryStmt
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}: if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}:
discardCheck(c, n.sons[0]) discardCheck(c, n.sons[0], flags)
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
if typ == c.enforceVoidContext: if typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext result.typ = c.enforceVoidContext
else: 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) n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
for i in 1..last: for i in 1..last:
var it = n.sons[i] var it = n.sons[i]
@ -570,7 +573,7 @@ proc symForVar(c: PContext, n: PNode): PSym =
if n.kind == nkPragmaExpr: if n.kind == nkPragmaExpr:
pragma(c, result, n.sons[1], forVarPragmas) 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 result = n
var length = sonsLen(n) var length = sonsLen(n)
let iterBase = n.sons[length-2].typ let iterBase = n.sons[length-2].typ
@ -601,7 +604,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
addForVarDecl(c, v) addForVarDecl(c, v)
inc(c.p.nestedLoopCounter) inc(c.p.nestedLoopCounter)
openScope(c) 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) closeScope(c)
dec(c.p.nestedLoopCounter) dec(c.p.nestedLoopCounter)
@ -685,7 +688,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
when false: when false:
result = handleStmtMacro(c, n, n[0], "CaseStmt") 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) checkMinSonsLen(n, 3, c.config)
var length = sonsLen(n) var length = sonsLen(n)
if forLoopMacros in c.features: if forLoopMacros in c.features:
@ -702,14 +705,14 @@ proc semFor(c: PContext, n: PNode): PNode =
if isCallExpr and call[0].kind == nkSym and if isCallExpr and call[0].kind == nkSym and
call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}: call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}:
if call.sons[0].sym.magic == mOmpParFor: if call.sons[0].sym.magic == mOmpParFor:
result = semForVars(c, n) result = semForVars(c, n, flags)
result.kind = nkParForStmt result.kind = nkParForStmt
else: else:
result = semForFields(c, n, call.sons[0].sym.magic) result = semForFields(c, n, call.sons[0].sym.magic)
elif isCallExpr and call.sons[0].typ.callConv == ccClosure and elif isCallExpr and call.sons[0].typ.callConv == ccClosure and
tfIterator in call.sons[0].typ.flags: tfIterator in call.sons[0].typ.flags:
# first class iterator: # first class iterator:
result = semForVars(c, n) result = semForVars(c, n, flags)
elif not isCallExpr or call.sons[0].kind != nkSym or elif not isCallExpr or call.sons[0].kind != nkSym or
call.sons[0].sym.kind != skIterator: call.sons[0].sym.kind != skIterator:
if length == 3: 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]) n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2])
else: else:
localError(c.config, n.sons[length-2].info, "iterator within for loop context expected") localError(c.config, n.sons[length-2].info, "iterator within for loop context expected")
result = semForVars(c, n) result = semForVars(c, n, flags)
else: else:
result = semForVars(c, n) result = semForVars(c, n, flags)
# propagate any enforced VoidContext: # propagate any enforced VoidContext:
if n.sons[length-1].typ == c.enforceVoidContext: if n.sons[length-1].typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext result.typ = c.enforceVoidContext
elif efInTypeof in flags:
result.typ = result.lastSon.typ
closeScope(c) closeScope(c)
proc semCase(c: PContext, n: PNode): PNode = proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
result = n result = n
checkMinSonsLen(n, 2, c.config) checkMinSonsLen(n, 2, c.config)
openScope(c) openScope(c)
@ -782,8 +787,9 @@ proc semCase(c: PContext, n: PNode): PNode =
else: else:
localError(c.config, n.info, "not all cases are covered") localError(c.config, n.info, "not all cases are covered")
closeScope(c) closeScope(c)
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) (not hasElse and efInTypeof notin flags):
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
# propagate any enforced VoidContext: # propagate any enforced VoidContext:
if typ == c.enforceVoidContext: if typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext result.typ = c.enforceVoidContext
@ -1173,6 +1179,9 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
if b != nil: if b != nil:
# store the alias: # store the alias:
n.sons[bodyPos] = newSymNode(b) 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: else:
localError(c.config, n.info, errNoSymbolToBorrowFromFound) localError(c.config, n.info, errNoSymbolToBorrowFromFound)
@ -1792,7 +1801,7 @@ proc evalInclude(c: PContext, n: PNode): PNode =
if containsOrIncl(c.includedFiles, f.int): if containsOrIncl(c.includedFiles, f.int):
localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f)) localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
else: 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) excl(c.includedFiles, f.int)
proc setLine(n: PNode, info: TLineInfo) = proc setLine(n: PNode, info: TLineInfo) =
@ -1819,7 +1828,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
#writeStackTrace() #writeStackTrace()
inc c.inStaticContext inc c.inStaticContext
openScope(c) openScope(c)
let a = semStmt(c, n.sons[0]) let a = semStmt(c, n.sons[0], {})
closeScope(c) closeScope(c)
dec c.inStaticContext dec c.inStaticContext
n.sons[0] = a 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]): if n.sons[i].typ == c.enforceVoidContext: #or usesResult(n.sons[i]):
voidContext = true voidContext = true
n.typ = c.enforceVoidContext 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 n.typ = n.sons[i].typ
if not isEmptyType(n.typ): n.kind = nkStmtListExpr if not isEmptyType(n.typ): n.kind = nkStmtListExpr
elif i != last or voidContext: elif i != last or voidContext:
discardCheck(c, n.sons[i]) discardCheck(c, n.sons[i], flags)
else: else:
n.typ = n.sons[i].typ n.typ = n.sons[i].typ
if not isEmptyType(n.typ): n.kind = nkStmtListExpr 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 ""': # it is an old-style comment statement: we replace it with 'discard ""':
prettybase.replaceComment(result.info) prettybase.replaceComment(result.info)
proc semStmt(c: PContext, n: PNode): PNode = proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode =
# now: simply an alias: if efInTypeof notin flags:
result = semExprNoType(c, n) result = semExprNoType(c, n)
else:
result = semExpr(c, n, flags)

View file

@ -1161,7 +1161,7 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1, c.config) checkMinSonsLen(n, 1, c.config)
var length = sonsLen(n) var length = sonsLen(n)
for i in countup(0, length - 2): 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: if length > 0:
result = semTypeNode(c, n.sons[length - 1], prev) result = semTypeNode(c, n.sons[length - 1], prev)
n.typ = result n.typ = result
@ -1406,6 +1406,13 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =
result.rawAddSon(base) result.rawAddSon(base)
result.flags.incl tfHasStatic 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 = proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil result = nil
inc c.inTypeContext inc c.inTypeContext
@ -1416,9 +1423,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkTypeOfExpr: of nkTypeOfExpr:
# for ``type(countup(1,3))``, see ``tests/ttoseq``. # for ``type(countup(1,3))``, see ``tests/ttoseq``.
checkSonsLen(n, 1, c.config) checkSonsLen(n, 1, c.config)
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof}) result = semTypeof(c, n.sons[0], prev)
fixupTypeOf(c, prev, typExpr)
result = typExpr.typ
if result.kind == tyTypeDesc: result.flags.incl tfExplicit if result.kind == tyTypeDesc: result.flags.incl tfExplicit
of nkPar: of nkPar:
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) 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) result = semAnyRef(c, n, tyRef, prev)
elif op.id == ord(wType): elif op.id == ord(wType):
checkSonsLen(n, 2, c.config) checkSonsLen(n, 2, c.config)
let typExpr = semExprWithType(c, n.sons[1], {efInTypeof}) result = semTypeof(c, n[1], prev)
fixupTypeOf(c, prev, typExpr)
result = typExpr.typ
else: else:
if c.inGenericContext > 0 and n.kind == nkCall: if c.inGenericContext > 0 and n.kind == nkCall:
result = makeTypeFromExpr(c, n.copyTree) result = makeTypeFromExpr(c, n.copyTree)

View file

@ -624,7 +624,11 @@ proc transformCase(c: PTransf, n: PNode): PTransNode =
case it.kind case it.kind
of nkElifBranch: of nkElifBranch:
if ifs.PNode == nil: 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) ifs.add(e)
of nkElse: of nkElse:
if ifs.PNode == nil: result.add(e) if ifs.PNode == nil: result.add(e)

View file

@ -977,7 +977,7 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]):
## ##
result = newNimNode(nnkIfStmt) result = newNimNode(nnkIfStmt)
for i in branches: for i in branches:
result.add(newNimNode(nnkElifBranch).add(i.cond, i.body)) result.add(newTree(nnkElifBranch, i.cond, i.body))
proc newEnum*(name: NimNode, fields: openArray[NimNode], proc newEnum*(name: NimNode, fields: openArray[NimNode],
public, pure: bool): NimNode {.compileTime.} = public, pure: bool): NimNode {.compileTime.} =

View file

@ -1552,7 +1552,7 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
defaultImpl() defaultImpl()
else: else:
when defined(js): when defined(js):
{.emit: "`x`[`x`_Idx].splice(`i`, 1);".} {.emit: "`x`.splice(`i`, 1);".}
else: else:
defaultImpl() defaultImpl()
@ -1574,7 +1574,7 @@ proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
else: else:
when defined(js): when defined(js):
var it : T var it : T
{.emit: "`x`[`x`_Idx].splice(`i`, 0, `it`);".} {.emit: "`x`.splice(`i`, 0, `it`);".}
else: else:
defaultImpl() defaultImpl()
x[i] = item x[i] = item
@ -2741,12 +2741,12 @@ type
when defined(JS): when defined(JS):
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
asm """ asm """
var len = `x`.length-1; if (`x` === null) { `x` = []; }
var off = `x`.length;
`x`.length += `y`.length;
for (var i = 0; i < `y`.length; ++i) { for (var i = 0; i < `y`.length; ++i) {
`x`[len] = `y`.charCodeAt(i); `x`[off+i] = `y`.charCodeAt(i);
++len;
} }
`x`[len] = 0
""" """
proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
@ -3784,8 +3784,11 @@ template assertImpl(cond: bool, msg = "", enabled: static[bool]) =
bind instantiationInfo bind instantiationInfo
mixin failedAssertImpl mixin failedAssertImpl
when enabled: when enabled:
if not cond: # for stacktrace; fixes #8928 ; Note: `fullPaths = true` is correct
failedAssertImpl(loc & " `" & astToStr(cond) & "` " & msg) # here, regardless of --excessiveStackTrace
{.line: instantiationInfo(fullPaths = true).}:
if not cond:
failedAssertImpl(loc & " `" & astToStr(cond) & "` " & msg)
template assert*(cond: bool, msg = "") = template assert*(cond: bool, msg = "") =
## Raises ``AssertionError`` with `msg` if `cond` is false. Note ## Raises ``AssertionError`` with `msg` if `cond` is false. Note

View file

@ -11,7 +11,7 @@ when declared(ThisIsSystem):
# we are in system module: # we are in system module:
{.pragma: codegenType, compilerproc.} {.pragma: codegenType, compilerproc.}
else: else:
{.pragma: codegenType, importc.} {.pragma: codegenType.}
type type
# This should be the same as ast.TTypeKind # This should be the same as ast.TTypeKind

View file

@ -182,12 +182,10 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
{.emit: """ {.emit: """
var ln = `c`.length; var ln = `c`.length;
var result = new Array(ln + 1); var result = new Array(ln);
var i = 0; for (var i = 0; i < ln; ++i) {
for (; i < ln; ++i) {
result[i] = `c`.charCodeAt(i); result[i] = `c`.charCodeAt(i);
} }
result[i] = 0; // terminating zero
return result; return result;
""".} """.}
@ -225,13 +223,12 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
} }
++r; ++r;
} }
result[r] = 0; // terminating zero
return result; return result;
""".} """.}
proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
asm """ asm """
var len = `s`.length-1; var len = `s`.length;
var asciiPart = new Array(len); var asciiPart = new Array(len);
var fcc = String.fromCharCode; var fcc = String.fromCharCode;
var nonAsciiPart = null; var nonAsciiPart = null;
@ -262,10 +259,7 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} = proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
asm """ asm """
var result = new Array(`len`+1); return new Array(`len`);
result[0] = 0;
result[`len`] = 0;
return result;
""" """
proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} = proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
@ -323,7 +317,7 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
if (`a` == `b`) return 0; if (`a` == `b`) return 0;
if (!`a`) return -1; if (!`a`) return -1;
if (!`b`) return 1; if (!`b`) return 1;
for (var i = 0; i < `a`.length - 1 && i < `b`.length - 1; i++) { for (var i = 0; i < `a`.length && i < `b`.length; i++) {
var result = `a`[i] - `b`[i]; var result = `a`[i] - `b`[i];
if (result != 0) return result; if (result != 0) return result;
} }
@ -651,9 +645,7 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
return true return true
proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} = proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
asm """ asm "`x`.push(`c`);"
`x`[`x`.length-1] = `c`; `x`.push(0);
"""
{.pop.} {.pop.}

View file

@ -4,6 +4,9 @@ B0
B1 B1
B2 B2
B3 B3
B4
B5
B6
''' '''
""" """
@ -14,6 +17,14 @@ template crossCheck(ty: untyped, exp: untyped) =
echo "Got ", ct echo "Got ", ct
echo "Expected ", rt echo "Expected ", rt
template add1(x: uint8): untyped = x + 1
template add1(x: uint16): untyped = x + 1
template add1(x: uint32): untyped = x + 1
template sub1(x: uint8): untyped = x - 1
template sub1(x: uint16): untyped = x - 1
template sub1(x: uint32): untyped = x - 1
block: block:
when true: when true:
echo "B0" echo "B0"
@ -34,10 +45,34 @@ block:
crossCheck(uint64, (-1).uint64 + 5'u64) crossCheck(uint64, (-1).uint64 + 5'u64)
echo "B3" echo "B3"
crossCheck(int8, 0'u8 - 5'u8) doAssert $sub1(0'u8) == "255"
crossCheck(int16, 0'u16 - 5'u16) doAssert $sub1(0'u16) == "65535"
crossCheck(int32, 0'u32 - 5'u32) doAssert $sub1(0'u32) == "4294967295"
crossCheck(int64, 0'u64 - 5'u64)
echo "B4"
doAssert $add1(255'u8) == "0"
doAssert $add1(65535'u16) == "0"
doAssert $add1(4294967295'u32) == "0"
echo "B5"
crossCheck(int32, high(int32))
crossCheck(int32, high(int32).int32)
crossCheck(int32, low(int32))
crossCheck(int32, low(int32).int32)
crossCheck(int64, high(int8).int16.int32.int64)
crossCheck(int64, low(int8).int16.int32.int64)
echo "B6"
crossCheck(int64, 0xFFFFFFFFFFFFFFFF'u64)
crossCheck(int32, 0xFFFFFFFFFFFFFFFF'u64)
crossCheck(int16, 0xFFFFFFFFFFFFFFFF'u64)
crossCheck(int8 , 0xFFFFFFFFFFFFFFFF'u64)
# Out of range conversion, caught for `let`s only
# crossCheck(int8, 0'u8 - 5'u8)
# crossCheck(int16, 0'u16 - 5'u16)
# crossCheck(int32, 0'u32 - 5'u32)
# crossCheck(int64, 0'u64 - 5'u64)
# crossCheck(int8, 0'u16 - 129'u16) # crossCheck(int8, 0'u16 - 129'u16)
# crossCheck(uint8, 0'i16 + 257'i16) # crossCheck(uint8, 0'i16 + 257'i16)

View file

@ -0,0 +1,19 @@
discard """
output: '''
tfailedassert_stacktrace.nim(16) tfailedassert_stacktrace
tfailedassert_stacktrace.nim(15) foo
system.nim(3778) failedAssertImpl
system.nim(3771) raiseAssert
system.nim(2818) sysFatal
'''
"""
try:
proc foo() =
assert(false)
foo()
except AssertionError:
let e = getCurrentException()
echo e.getStackTrace

View file

@ -0,0 +1,8 @@
type
Bytes = distinct seq[byte]
proc add(x: var Bytes; b: byte) {.borrow.}
var x = @[].Bytes
x.add(42)
let base = cast[seq[byte]](x)
doAssert base.len == 1 and base[0] == 42

View file

@ -0,0 +1,8 @@
discard """
targets: "c cpp"
"""
import typeinfo
var x = ""
discard (getPointer(toAny(x)))

7
tests/js/t7534.nim Normal file
View file

@ -0,0 +1,7 @@
proc f(x: int): int =
result = case x
of 1: 2
elif x == 2: 3
else: 1
doAssert 2 == f(f(f(f(1))))

12
tests/js/t8914.nim Normal file
View file

@ -0,0 +1,12 @@
discard """
output: '''
@[42]
@[24, 42]
'''
"""
var x = @[42,4242]
x.delete(1)
echo x
x.insert(24)
echo x

4
tests/js/taddnilstr.nim Normal file
View file

@ -0,0 +1,4 @@
var x = "foo".cstring
var y: string
add(y, x)
doAssert y == "foo"

5
tests/js/tstrconcat.nim Normal file
View file

@ -0,0 +1,5 @@
var x: string
var y = "foo"
add(x, y)
y[0] = 'm'
doAssert y == "moo" and x == "foo"

63
tests/macros/tcollect.nim Normal file
View file

@ -0,0 +1,63 @@
discard """
output: '''@[2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4]
@[0, 1, 2, 3]'''
"""
const data = [1,2,3,4,5,6]
import macros
macro collect(body): untyped =
# analyse the body, find the deepest expression 'it' and replace it via
# 'result.add it'
let res = genSym(nskVar, "collectResult")
when false:
proc detectForLoopVar(n: NimNode): NimNode =
if n.kind == nnkForStmt:
result = n[0]
else:
for x in n:
result = detectForLoopVar(x)
if result != nil: return result
return nil
proc t(n, res: NimNode): NimNode =
case n.kind
of nnkStmtList, nnkStmtListExpr, nnkBlockStmt, nnkBlockExpr,
nnkWhileStmt,
nnkForStmt, nnkIfExpr, nnkIfStmt, nnkTryStmt, nnkCaseStmt,
nnkElifBranch, nnkElse, nnkElifExpr:
result = copyNimTree(n)
if n.len >= 1:
result[^1] = t(n[^1], res)
else:
if true: #n == it:
template adder(res, it) =
res.add it
result = getAst adder(res, n)
else:
result = n
when false:
let it = detectForLoopVar(body)
if it == nil: error("no for loop in body", body)
let v = newTree(nnkVarSection,
newTree(nnkIdentDefs, res, newTree(nnkBracketExpr, bindSym"seq",
newCall(bindSym"type", body)), newEmptyNode()))
result = newTree(nnkStmtListExpr, v, t(body, res), res)
#echo repr result
let stuff = collect:
var i = -1
while i < 4:
inc i
for it in data:
if it < 5 and it > 1:
it
echo stuff
echo collect(for i in 0..3: i)

10
tests/seq/t7346.nim Normal file
View file

@ -0,0 +1,10 @@
when not defined(nimNewRuntime):
{.error: "This bug could only be reproduced with --newruntime".}
type
Obj = object
a: int
proc `=`(a: var Obj, b: Obj) = discard
let a: seq[Obj] = @[]

7
tests/typerel/t8905.nim Normal file
View file

@ -0,0 +1,7 @@
type
Foo[T] = distinct seq[T]
Bar[T] = object
proc newFoo[T](): Foo[T] = Foo[T](newSeq[T]())
var x = newFoo[Bar[int]]()

10
tests/types/t6969.nim Normal file
View file

@ -0,0 +1,10 @@
discard """
errormsg: "invalid type: 'object' for var"
line: 6
"""
var a: object a: int
# or
var b: ref object a: int
# or
var c: ptr object a: int

1
tests/types/t7581.nim Normal file
View file

@ -0,0 +1 @@
discard int -1