top-down type inference, implements rfc 149 (#20091)

* micro implementation of rfc 149

refs https://github.com/nim-lang/RFCs/issues/149

* number/array/seq literals, more statements

* try fix number literal alias issue

* renew expectedType with if/case/try branch types

* fix (nerf) index type handling and float typed int

* use typeAllowed

* tweaks + const test (tested locally) [skip ci]

* fill out more of the checklist

* more literals, change @ order, type conversions

Not copying the full call tree before the typedesc call check
in `semIndirectOp` is also a small performance improvement.

* disable self-conversion warning

* revert type conversions (maybe separate op later)

* deal with CI for now (seems unrelated), try enums

* workaround CI different way

* proper fix

* again

* see sizes

* lol

* overload selection, simplify int literal -> float

* range, new @ solution, try use fitNode for nil

* use new magic

* try fix ranges, new magic, deal with #20193

* add documentation, support templates

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
metagn 2022-08-24 08:11:41 +03:00 • committed by GitHub
commit 0014b9c48e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 599 additions and 199 deletions

View file

@ -674,7 +674,7 @@ type
mInSet, mRepr, mExit,
mSetLengthStr, mSetLengthSeq,
mIsPartOf, mAstToStr, mParallel,
mSwap, mIsNil, mArrToSeq,
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mWasMoved, mDestroy, mTrace,
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
@ -708,8 +708,8 @@ type
mSymIsInstantiationOf, mNodeId, mPrivateAccess
# things that we can evaluate safely at compile time, even if not asked for it:
const
# things that we can evaluate safely at compile time, even if not asked for it:
ctfeWhitelist* = {mNone, mSucc,
mPred, mInc, mDec, mOrd, mLengthOpenArray,
mLengthStr, mLengthArray, mLengthSeq,
@ -738,6 +738,9 @@ const
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet,
mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInSet, mRepr}
generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq}
## magics that are generated as normal procs in the backend
type
ItemId* = object
@ -1677,6 +1680,10 @@ proc transitionIntKind*(n: PNode, kind: range[nkCharLit..nkUInt64Lit]) =
transitionNodeKindCommon(kind)
n.intVal = obj.intVal
proc transitionIntToFloatKind*(n: PNode, kind: range[nkFloatLit..nkFloat128Lit]) =
transitionNodeKindCommon(kind)
n.floatVal = BiggestFloat(obj.intVal)
proc transitionNoneToSym*(n: PNode) =
transitionNodeKindCommon(nkSym)

View file

@ -2369,7 +2369,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
genDollar(p, e, d, "#nimFloatToStr($1)")
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
of mStrToStr, mUnown: expr(p, e[1], d)
of mIsolate, mFinished: genCall(p, e, d)
of generatedMagics: genCall(p, e, d)
of mEnumToStr:
if optTinyRtti in p.config.globalOptions:
genEnumToStr(p, e, d)
@ -2978,7 +2978,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if n[genericParamsPos].kind == nkEmpty:
var prc = n[namePos].sym
if useAliveDataFromDce in p.module.flags:
if p.module.alive.contains(prc.itemId.item) and prc.magic in {mNone, mIsolate, mFinished}:
if p.module.alive.contains(prc.itemId.item) and
prc.magic in generatedMagics:
genProc(p.module, prc)
elif prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or

View file

@ -140,4 +140,5 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasEffectsOf")
defineSymbol("nimHasEnforceNoRaises")
defineSymbol("nimHasTopDownInference")
defineSymbol("nimHasTemplateRedefinitionPragma")

View file

@ -1455,7 +1455,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
s.name.s)
discard mangleName(p.module, s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate} or
if lfNoDecl in s.loc.flags or s.magic notin generatedMagics or
{sfImportc, sfInfixCall} * s.flags != {}:
discard
elif s.kind == skMethod and getBody(p.module.graph, s).kind == nkEmpty:
@ -2106,6 +2106,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n[1], x)
useMagic(p, "nimCopy")
r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)]
of mOpenArrayToSeq:
genCall(p, n, r)
of mDestroy, mTrace: discard "ignore calls to the default destructor"
of mOrd: genOrd(p, n, r)
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
@ -2622,7 +2624,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
let s = n[namePos].sym
discard mangleName(p.module, s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate}: discard
if lfNoDecl in s.loc.flags or s.magic notin generatedMagics: discard
elif not p.g.generatedSyms.containsOrIncl(s.id):
p.locals.add(genProc(p, s))
of nkType: r.res = genTypeInfo(p, n.typ)

View file

@ -27,11 +27,11 @@ when not defined(leanCompiler):
# implementation
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode
proc semExprNoType(c: PContext, n: PNode): PNode
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semProcBody(c: PContext, n: PNode): PNode
proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode
proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
@ -48,7 +48,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode
proc finishMethod(c: PContext, s: PSym)
proc evalAtCompileTime(c: PContext, n: PNode): PNode
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
proc semStaticExpr(c: PContext, n: PNode): PNode
proc semStaticExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode
proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType
proc semTypeOf(c: PContext; n: PNode): PNode
proc computeRequiresInit(c: PContext, t: PType): bool
@ -269,12 +269,12 @@ proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
typeAllowedCheck(c, typ.n.info, typ, skProc)
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode
flags: TExprFlags = {}; expectedType: PType = nil): PNode
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode
flags: TExprFlags = {}; expectedType: PType = nil): PNode
proc symFromType(c: PContext; t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym
@ -334,8 +334,8 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
isArrayConstr(arg):
arg.typ = eOrig.typ
proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
var e = semExprWithType(c, n, expectedType = expectedType)
if e == nil: return
result = getConstExpr(c.module, e, c.idgen, c.graph)
@ -365,8 +365,8 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
const
errConstExprExpected = "constant expression expected"
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
proc semConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
var e = semExprWithType(c, n, expectedType = expectedType)
if e == nil:
localError(c.config, n.info, errConstExprExpected)
return n
@ -388,14 +388,14 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
else:
result = fixupTypeAfterEval(c, result, e)
proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
if efNeedStatic in flags:
if efPreferNilResult in flags:
return tryConstExpr(c, n)
return tryConstExpr(c, n, expectedType)
else:
return semConstExpr(c, n)
return semConstExpr(c, n, expectedType)
else:
result = semExprWithType(c, n, flags)
result = semExprWithType(c, n, flags, expectedType)
if efPreferStatic in flags:
var evaluated = getConstExpr(c.module, result, c.idgen, c.graph)
if evaluated != nil: return evaluated
@ -414,7 +414,7 @@ proc resetSemFlag(n: PNode) =
resetSemFlag(n[i])
proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
s: PSym, flags: TExprFlags): PNode =
s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode =
## Semantically check the output of a macro.
## This involves processes such as re-checking the macro output for type
## coherence, making sure that variables declared with 'let' aren't
@ -438,10 +438,10 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
case retType.kind
of tyUntyped:
# Not expecting a type here allows templates like in ``tmodulealias.in``.
result = semExpr(c, result, flags)
result = semExpr(c, result, flags, expectedType)
of tyTyped:
# More restrictive version.
result = semExprWithType(c, result, flags)
result = semExprWithType(c, result, flags, expectedType)
of tyTypeDesc:
if result.kind == nkStmtList: result.transitionSonsKind(nkStmtListType)
var typ = semTypeNode(c, result, nil)
@ -465,7 +465,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
retType = generateTypeInstance(c, paramTypes,
macroResult.info, retType)
result = semExpr(c, result, flags)
result = semExpr(c, result, flags, expectedType)
result = fitNode(c, retType, result, result.info)
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0]))
dec(c.config.evalTemplateCounter)
@ -476,7 +476,7 @@ const
errFloatToString = "cannot convert '$1' to '$2'"
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode =
flags: TExprFlags = {}; expectedType: PType = nil): PNode =
rememberExpansion(c, nOrig.info, sym)
pushInfoContext(c.config, nOrig.info, sym.detailedInfo)
@ -496,7 +496,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
# c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, c.idgen, c.graph, c.templInstCounter, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, sym, flags)
result = semAfterMacroCall(c, n, result, sym, flags, expectedType)
if c.config.macrosToExpand.hasKey(sym.name.s):
message(c.config, nOrig.info, hintExpandMacro, renderTree(result))
result = wrapInComesFrom(nOrig.info, sym, result)
@ -507,7 +507,7 @@ proc forceBool(c: PContext, n: PNode): PNode =
if result == nil: result = n
proc semConstBoolExpr(c: PContext, n: PNode): PNode =
result = forceBool(c, semConstExpr(c, n))
result = forceBool(c, semConstExpr(c, n, getSysType(c.graph, n.info, tyBool)))
if result.kind != nkIntLit:
localError(c.config, n.info, errConstExprExpected)

View file

@ -120,10 +120,10 @@ type
symMapping*: TIdTable # every gensym'ed symbol needs to be mapped
# to some new symbol in a generic instantiation
libs*: seq[PLib] # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.}
computeRequiresInit*: proc (c: PContext, t: PType): bool {.nimcall.}
hasUnresolvedArgs*: proc (c: PContext, n: PNode): bool

View file

@ -26,7 +26,7 @@ const
errUndeclaredFieldX = "undeclared field: '$1'"
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode =
flags: TExprFlags = {}; expectedType: PType = nil): PNode =
rememberExpansion(c, n.info, s)
let info = getCallLineInfo(n)
markUsed(c, info, s)
@ -36,7 +36,8 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
pushInfoContext(c.config, n.info, s.detailedInfo)
result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache,
c.templInstCounter, c.idgen, efFromHlo in flags)
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, s, flags, expectedType)
popInfoContext(c.config)
# XXX: A more elaborate line info rewrite might be needed
@ -65,9 +66,9 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType = nil): PNode =
rejectEmptyNode(n)
result = semExpr(c, n, flags+{efWantValue})
result = semExpr(c, n, flags+{efWantValue}, expectedType)
let
isEmpty = result.kind == nkEmpty
@ -82,8 +83,8 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
# do not produce another redundant error message:
result = errorNode(c, n)
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExprCheck(c, n, flags)
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
result = semExprCheck(c, n, flags, expectedType)
if result.typ == nil and efInTypeof in flags:
result.typ = c.voidType
elif result.typ == nil or result.typ == c.enforceVoidContext:
@ -261,7 +262,7 @@ proc isOwnedSym(c: PContext; n: PNode): bool =
let s = qualifiedLookUp(c, n, {})
result = s != nil and sfSystemModule in s.owner.flags and s.name.s == "owned"
proc semConv(c: PContext, n: PNode): PNode =
proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
if n.len != 2:
localError(c.config, n.info, "a type conversion takes exactly one argument")
return n
@ -277,7 +278,7 @@ proc semConv(c: PContext, n: PNode): PNode =
else:
targetType = targetType.base
of tyStatic:
var evaluated = semStaticExpr(c, n[1])
var evaluated = semStaticExpr(c, n[1], expectedType)
if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc:
result = n
result.typ = c.makeTypeDesc semStaticType(c, evaluated, nil)
@ -583,21 +584,36 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
typ[0] = makeRangeType(c, 0, n.len - 1, n.info)
result = typ
proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = newNodeI(nkBracket, n.info)
result.typ = newTypeS(tyArray, c)
var expectedElementType, expectedIndexType: PType = nil
if expectedType != nil:
let expected = expectedType.skipTypes(abstractRange-{tyDistinct})
case expected.kind
of tyArray:
expectedIndexType = expected[0]
expectedElementType = expected[1]
of tyOpenArray:
expectedElementType = expected[0]
else: discard
rawAddSon(result.typ, nil) # index type
var
firstIndex, lastIndex: Int128
indexType = getSysType(c.graph, n.info, tyInt)
lastValidIndex = lastOrd(c.config, indexType)
if n.len == 0:
rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
rawAddSon(result.typ,
if expectedElementType != nil and
typeAllowed(expectedElementType, skLet, c) == nil:
expectedElementType
else:
newTypeS(tyEmpty, c)) # needs an empty basetype!
lastIndex = toInt128(-1)
else:
var x = n[0]
if x.kind == nkExprColonExpr and x.len == 2:
var idx = semConstExpr(c, x[0])
var idx = semConstExpr(c, x[0], expectedIndexType)
if not isOrdinalType(idx.typ):
localError(c.config, idx.info, "expected ordinal value for array " &
"index, got '$1'" % renderTree(idx))
@ -608,8 +624,10 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
lastValidIndex = lastOrd(c.config, indexType)
x = x[1]
let yy = semExprWithType(c, x)
let yy = semExprWithType(c, x, expectedType = expectedElementType)
var typ = yy.typ
if expectedElementType == nil:
expectedElementType = typ
result.add yy
#var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
for i in 1..<n.len:
@ -621,13 +639,13 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
x = n[i]
if x.kind == nkExprColonExpr and x.len == 2:
var idx = semConstExpr(c, x[0])
var idx = semConstExpr(c, x[0], indexType)
idx = fitNode(c, indexType, idx, x.info)
if lastIndex+1 != getOrdValue(idx):
localError(c.config, x.info, "invalid order in array constructor")
x = x[1]
let xx = semExprWithType(c, x, {})
let xx = semExprWithType(c, x, {}, expectedElementType)
result.add xx
typ = commonType(c, typ, xx.typ)
#n[i] = semExprWithType(c, x, {})
@ -853,10 +871,10 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
#if result != n:
# echo "SUCCESS evaluated at compile time: ", call.renderTree
proc semStaticExpr(c: PContext, n: PNode): PNode =
proc semStaticExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
inc c.inStaticContext
openScope(c)
let a = semExprWithType(c, n)
let a = semExprWithType(c, n, expectedType = expectedType)
closeScope(c)
dec c.inStaticContext
if a.findUnresolvedStatic != nil: return a
@ -900,7 +918,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
rawAddSon(typ, result.typ)
result.typ = typ
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
t: PType): TCandidate =
@ -923,15 +941,15 @@ proc setGenericParams(c: PContext, n: PNode) =
for i in 1..<n.len:
n[i].typ = semTypeNode(c, n[i], nil)
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError:
return errorNode(c, n)
result = n
let callee = result[0].sym
case callee.kind
of skMacro: result = semMacroExpr(c, result, orig, callee, flags)
of skTemplate: result = semTemplateExpr(c, result, callee, flags)
of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType)
of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType)
else:
semFinishOperands(c, result)
activate(c, result)
@ -947,7 +965,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
if c.matchedConcept == nil:
result = evalAtCompileTime(c, result)
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = nil
checkMinSonsLen(n, 1, c.config)
var prc = n[0]
@ -972,13 +990,17 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
let s = bracketedMacro(n[0])
if s != nil:
setGenericParams(c, n[0])
return semDirectOp(c, n, flags)
return semDirectOp(c, n, flags, expectedType)
let nOrig = n.copyTree
semOpAux(c, n)
var t: PType = nil
if n[0].typ != nil:
t = skipTypes(n[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct})
if t != nil and t.kind == tyTypeDesc:
if n.len == 1: return semObjConstr(c, n, flags, expectedType)
return semConv(c, n)
let nOrig = n.copyTree
semOpAux(c, n)
if t != nil and t.kind == tyProc:
# This is a proc variable, apply normal overload resolution
let m = resolveIndirectCall(c, n, nOrig, t)
@ -1017,9 +1039,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = m.call
instGenericConvertersSons(c, result, m)
elif t != nil and t.kind == tyTypeDesc:
if n.len == 1: return semObjConstr(c, n, flags)
return semConv(c, n)
else:
result = overloadedCallOpr(c, n)
# Now that nkSym does not imply an iteration over the proc/iterator space,
@ -1038,17 +1057,17 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
return result
#result = afterCallActions(c, result, nOrig, flags)
if result[0].kind == nkSym:
result = afterCallActions(c, result, nOrig, flags)
result = afterCallActions(c, result, nOrig, flags, expectedType)
else:
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
# this seems to be a hotspot in the compiler!
let nOrig = n.copyTree
#semLazyOpAux(c, n)
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result != nil: result = afterCallActions(c, result, nOrig, flags)
if result != nil: result = afterCallActions(c, result, nOrig, flags, expectedType)
else: result = errorNode(c, n)
proc buildEchoStmt(c: PContext, n: PNode): PNode =
@ -1594,11 +1613,11 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
discard
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = semSubscript(c, n, flags)
if result == nil:
# overloaded [] operator:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "[]")), flags)
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "[]")), flags, expectedType)
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
var id = considerQuotedIdent(c, a[1], a)
@ -1774,7 +1793,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
renderTree(a, {renderNoComments}))
else:
let lhs = n[0]
let rhs = semExprWithType(c, n[1], {})
let rhs = semExprWithType(c, n[1], {}, le)
if lhs.kind == nkSym and lhs.sym.kind == skResult:
n.typ = c.enforceVoidContext
if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
@ -1823,9 +1842,9 @@ proc semReturn(c: PContext, n: PNode): PNode =
else:
localError(c.config, n.info, "'return' not allowed here")
proc semProcBody(c: PContext, n: PNode): PNode =
proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode =
openScope(c)
result = semExpr(c, n)
result = semExpr(c, n, expectedType = expectedType)
if c.p.resultSym != nil and not isEmptyType(result.typ):
if result.kind == nkNilLit:
# or ImplicitlyDiscardable(result):
@ -2256,7 +2275,7 @@ proc semSizeof(c: PContext, n: PNode): PNode =
n.typ = getSysType(c.graph, n.info, tyInt)
result = foldSizeOf(c.config, n, n)
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode =
# this is a hotspot in the compiler!
result = n
case s.magic # magics that need special treatment
@ -2372,8 +2391,17 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
of mSizeOf:
markUsed(c, n.info, s)
result = semSizeof(c, setMs(n, s))
of mArrToSeq, mOpenArrayToSeq:
if n.len == 2 and expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tySequence, tyOpenArray}):
# seq type inference
var arrayType = newType(tyOpenArray, nextTypeId(c.idgen), expected.owner)
arrayType.rawAddSon(expected[0])
n[1] = semExpr(c, n[1], flags, arrayType)
result = semDirectOp(c, n, flags, expectedType)
else:
result = semDirectOp(c, n, flags)
result = semDirectOp(c, n, flags, expectedType)
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
# If semCheck is set to false, ``when`` will return the verbatim AST of
@ -2432,33 +2460,49 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
result = newNodeI(nkEmpty, n.info)
if whenNimvm: result.typ = typ
proc semSetConstr(c: PContext, n: PNode): PNode =
proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
result = newNodeI(nkCurly, n.info)
result.typ = newTypeS(tySet, c)
result.typ.flags.incl tfIsConstructor
var expectedElementType: PType = nil
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind == tySet):
expectedElementType = expected[0]
if n.len == 0:
rawAddSon(result.typ, newTypeS(tyEmpty, c))
rawAddSon(result.typ,
if expectedElementType != nil and
typeAllowed(expectedElementType, skLet, c) == nil:
expectedElementType
else:
newTypeS(tyEmpty, c))
else:
# only semantic checking for all elements, later type checking:
var typ: PType = nil
for i in 0..<n.len:
if isRange(n[i]):
checkSonsLen(n[i], 3, c.config)
n[i][1] = semExprWithType(c, n[i][1])
n[i][2] = semExprWithType(c, n[i][2])
n[i][1] = semExprWithType(c, n[i][1], {}, expectedElementType)
n[i][2] = semExprWithType(c, n[i][2], {}, expectedElementType)
if typ == nil:
typ = skipTypes(n[i][1].typ,
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
if expectedElementType == nil:
expectedElementType = typ
n[i].typ = n[i][2].typ # range node needs type too
elif n[i].kind == nkRange:
# already semchecked
if typ == nil:
typ = skipTypes(n[i][0].typ,
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
if expectedElementType == nil:
expectedElementType = typ
else:
n[i] = semExprWithType(c, n[i])
n[i] = semExprWithType(c, n[i], {}, expectedElementType)
if typ == nil:
typ = skipTypes(n[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
if expectedElementType == nil:
expectedElementType = typ
if not isOrdinalType(typ, allowEnumWithHoles=true):
localError(c.config, n.info, errOrdinalTypeExpected)
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
@ -2477,7 +2521,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
m = fitNode(c, typ, n[i], info)
result.add m
proc semTableConstr(c: PContext, n: PNode): PNode =
proc semTableConstr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
# we simply transform ``{key: value, key2, key3: value}`` to
# ``[(key, value), (key2, value2), (key3, value2)]``
result = newNodeI(nkBracket, n.info)
@ -2499,7 +2543,7 @@ proc semTableConstr(c: PContext, n: PNode): PNode =
lastKey = i+1
if lastKey != n.len: illFormedAst(n, c.config)
result = semExpr(c, result)
result = semExpr(c, result, expectedType = expectedType)
type
TParKind = enum
@ -2526,8 +2570,13 @@ proc checkPar(c: PContext; n: PNode): TParKind =
localError(c.config, n[i].info, errNamedExprNotAllowed)
return paNone
proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = newNodeI(nkTupleConstr, n.info)
var expected: PType = nil
if expectedType != nil:
expected = expectedType.skipTypes(abstractRange-{tyDistinct})
if not (expected.kind == tyTuple and expected.len == n.len):
expected = nil
var typ = newTypeS(tyTuple, c)
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
var ids = initIntSet()
@ -2537,7 +2586,9 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
let id = considerQuotedIdent(c, n[i][0])
if containsOrIncl(ids, id.id):
localError(c.config, n[i].info, errFieldInitTwice % id.s)
n[i][1] = semExprWithType(c, n[i][1], {})
# can check if field name matches expected type here
let expectedElemType = if expected != nil: expected[i] else: nil
n[i][1] = semExprWithType(c, n[i][1], {}, expectedElemType)
if n[i][1].typ.kind == tyTypeDesc:
localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
@ -2552,18 +2603,24 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.add n[i]
result.typ = typ
proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = n # we don't modify n, but compute the type:
result.transitionSonsKind(nkTupleConstr)
var expected: PType = nil
if expectedType != nil:
expected = expectedType.skipTypes(abstractRange-{tyDistinct})
if not (expected.kind == tyTuple and expected.len == n.len):
expected = nil
var typ = newTypeS(tyTuple, c) # leave typ.n nil!
for i in 0..<n.len:
n[i] = semExprWithType(c, n[i], {})
let expectedElemType = if expected != nil: expected[i] else: nil
n[i] = semExprWithType(c, n[i], {}, expectedElemType)
addSonSkipIntLit(typ, n[i].typ, c.idgen)
result.typ = typ
include semobjconstr
proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
proc semBlock(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
result = n
inc(c.p.nestedBlockCounter)
checkSonsLen(n, 2, c.config)
@ -2578,7 +2635,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
suggestSym(c.graph, n[0].info, labl, c.graph.usageSym)
styleCheckDef(c, labl)
onDef(n[0].info, labl)
n[1] = semExpr(c, n[1], flags)
n[1] = semExpr(c, n[1], flags, expectedType)
n.typ = n[1].typ
if isEmptyType(n.typ): n.transitionSonsKind(nkBlockStmt)
else: n.transitionSonsKind(nkBlockExpr)
@ -2644,8 +2701,8 @@ proc semExport(c: PContext, n: PNode): PNode =
s = nextOverloadIter(o, c, a)
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
var tupexp = semTuplePositionsConstr(c, n, flags)
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
var tupexp = semTuplePositionsConstr(c, n, flags, expectedType)
var isTupleType: bool
if tupexp.len > 0: # don't interpret () as type
isTupleType = tupexp[0].typ.kind == tyTypeDesc
@ -2770,7 +2827,7 @@ proc semPragmaStmt(c: PContext; n: PNode) =
else:
pragma(c, c.p.owner, n, stmtPragmas, true)
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
when defined(nimCompilerStacktraceHints):
setFrameMsg c.config$n.info & " " & $n.kind
when false: # see `tdebugutils`
@ -2779,19 +2836,39 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
defer:
if isCompilerDebug():
echo ("<", c.config$n.info, n, ?.result.typ)
template directLiteral(typeKind: TTypeKind) =
if result.typ == nil:
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind == typeKind):
result.typ = expected
changeType(c, result, expectedType, check=true)
else:
result.typ = getSysType(c.graph, n.info, typeKind)
result = n
if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
if nfSem in n.flags: return
case n.kind
of nkIdent, nkAccQuoted:
let checks = if efNoEvaluateGeneric in flags:
{checkUndeclared, checkPureEnumFields}
elif efInCall in flags:
{checkUndeclared, checkModule, checkPureEnumFields}
else:
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
var s = qualifiedLookUp(c, n, checks)
var s: PSym
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind == tyEnum):
let nameId = considerQuotedIdent(c, n).id
for f in expected.n:
if f.kind == nkSym and f.sym.name.id == nameId:
s = f.sym
break
if s == nil:
let checks = if efNoEvaluateGeneric in flags:
{checkUndeclared, checkPureEnumFields}
elif efInCall in flags:
{checkUndeclared, checkModule, checkPureEnumFields}
else:
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
s = qualifiedLookUp(c, n, checks)
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
case s.kind
of skProc, skFunc, skMethod, skConverter, skIterator:
@ -2811,6 +2888,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semSym(c, n, s, flags)
else:
result = semSym(c, n, s, flags)
if expectedType != nil and isSymChoice(result):
result = fitNode(c, expectedType, result, n.info)
if result.kind == nkSym:
result = semSym(c, result, result.sym, flags)
of nkSym:
# because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again!
@ -2818,39 +2899,56 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkEmpty, nkNone, nkCommentStmt, nkType:
discard
of nkNilLit:
if result.typ == nil: result.typ = getNilType(c)
if result.typ == nil:
result.typ = getNilType(c)
if expectedType != nil:
var m = newCandidate(c, result.typ)
if typeRel(m, expectedType, result.typ) >= isSubtype:
result.typ = expectedType
# or: result = fitNode(c, expectedType, result, n.info)
of nkIntLit:
if result.typ == nil: setIntLitType(c, result)
of nkInt8Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt8)
of nkInt16Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt16)
of nkInt32Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt32)
of nkInt64Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt64)
of nkUIntLit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt)
of nkUInt8Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt8)
of nkUInt16Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt16)
of nkUInt32Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt32)
of nkUInt64Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt64)
#of nkFloatLit:
# if result.typ == nil: result.typ = getFloatLitType(result)
of nkFloat32Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat32)
of nkFloat64Lit, nkFloatLit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat64)
of nkFloat128Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat128)
if result.typ == nil:
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tyInt..tyInt64,
tyUInt..tyUInt64,
tyFloat..tyFloat128}):
result.typ = expected
if expected.kind in {tyFloat..tyFloat128}:
n.transitionIntToFloatKind(nkFloatLit)
changeType(c, result, expectedType, check=true)
else:
setIntLitType(c, result)
of nkInt8Lit: directLiteral(tyInt8)
of nkInt16Lit: directLiteral(tyInt16)
of nkInt32Lit: directLiteral(tyInt32)
of nkInt64Lit: directLiteral(tyInt64)
of nkUIntLit: directLiteral(tyUInt)
of nkUInt8Lit: directLiteral(tyUInt8)
of nkUInt16Lit: directLiteral(tyUInt16)
of nkUInt32Lit: directLiteral(tyUInt32)
of nkUInt64Lit: directLiteral(tyUInt64)
of nkFloatLit:
if result.typ == nil:
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tyFloat..tyFloat128}):
result.typ = expected
changeType(c, result, expectedType, check=true)
else:
result.typ = getSysType(c.graph, n.info, tyFloat64)
of nkFloat32Lit: directLiteral(tyFloat32)
of nkFloat64Lit: directLiteral(tyFloat64)
of nkFloat128Lit: directLiteral(tyFloat128)
of nkStrLit..nkTripleStrLit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyString)
of nkCharLit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyChar)
if result.typ == nil:
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tyString, tyCstring}):
result.typ = expectedType
else:
result.typ = getSysType(c.graph, n.info, tyString)
of nkCharLit: directLiteral(tyChar)
of nkDotExpr:
result = semFieldAccess(c, n, flags)
if result.kind == nkDotCall:
@ -2858,7 +2956,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExpr(c, result, flags)
of nkBind:
message(c.config, n.info, warnDeprecated, "bind is deprecated")
result = semExpr(c, n[0], flags)
result = semExpr(c, n[0], flags, expectedType)
of nkTypeOfExpr..nkTupleClassTy, nkStaticTy, nkRefTy..nkEnumTy:
if c.matchedConcept != nil and n.len == 1:
let modifier = n.modifierTypeKindOfNode
@ -2884,40 +2982,40 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# pretty.checkUse(n[0][1].info, s)
case s.kind
of skMacro, skTemplate:
result = semDirectOp(c, n, flags)
result = semDirectOp(c, n, flags, expectedType)
of skType:
# XXX think about this more (``set`` procs)
let ambig = c.isAmbiguous
if not (n[0].kind in {nkClosedSymChoice, nkOpenSymChoice, nkIdent} and ambig) and n.len == 2:
result = semConv(c, n)
result = semConv(c, n, expectedType)
elif ambig and n.len == 1:
errorUseQualifier(c, n.info, s)
elif n.len == 1:
result = semObjConstr(c, n, flags)
elif s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags)
result = semObjConstr(c, n, flags, expectedType)
elif s.magic == mNone: result = semDirectOp(c, n, flags, expectedType)
else: result = semMagic(c, n, s, flags, expectedType)
of skProc, skFunc, skMethod, skConverter, skIterator:
if s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags)
else: result = semMagic(c, n, s, flags, expectedType)
else:
#liMessage(n.info, warnUser, renderTree(n));
result = semIndirectOp(c, n, flags)
result = semIndirectOp(c, n, flags, expectedType)
elif (n[0].kind == nkBracketExpr or shouldBeBracketExpr(n)) and
isSymChoice(n[0][0]):
# indirectOp can deal with explicit instantiations; the fixes
# the 'newSeq[T](x)' bug
setGenericParams(c, n[0])
result = semDirectOp(c, n, flags)
result = semDirectOp(c, n, flags, expectedType)
elif nfDotField in n.flags:
result = semDirectOp(c, n, flags)
result = semDirectOp(c, n, flags, expectedType)
elif isSymChoice(n[0]):
let b = asBracketExpr(c, n)
if b != nil:
result = semExpr(c, b, flags)
result = semExpr(c, b, flags, expectedType)
else:
result = semDirectOp(c, n, flags)
result = semDirectOp(c, n, flags, expectedType)
else:
result = semIndirectOp(c, n, flags)
result = semIndirectOp(c, n, flags, expectedType)
if nfDefaultRefsParam in result.flags:
result = result.copyTree #XXX: Figure out what causes default param nodes to be shared.. (sigmatch bug?)
@ -2936,12 +3034,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# This is a "when nimvm" stmt.
result = semWhen(c, n, true)
else:
result = semExpr(c, result, flags)
result = semExpr(c, result, flags, expectedType)
of nkBracketExpr:
checkMinSonsLen(n, 1, c.config)
result = semArrayAccess(c, n, flags)
result = semArrayAccess(c, n, flags, expectedType)
of nkCurlyExpr:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "{}")), flags)
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "{}")), flags, expectedType)
of nkPragmaExpr:
var
pragma = n[1]
@ -2963,12 +3061,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkPar, nkTupleConstr:
case checkPar(c, n)
of paNone: result = errorNode(c, n)
of paTuplePositions: result = semTupleConstr(c, n, flags)
of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
of paSingle: result = semExpr(c, n[0], flags)
of nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n, flags)
of nkObjConstr: result = semObjConstr(c, n, flags)
of paTuplePositions: result = semTupleConstr(c, n, flags, expectedType)
of paTupleFields: result = semTupleFieldsConstr(c, n, flags, expectedType)
of paSingle: result = semExpr(c, n[0], flags, expectedType)
of nkCurly: result = semSetConstr(c, n, expectedType)
of nkBracket: result = semArrayConstr(c, n, flags, expectedType)
of nkObjConstr: result = semObjConstr(c, n, flags, expectedType)
of nkLambdaKinds: result = semProcAux(c, n, skProc, lambdaPragmas, flags)
of nkDerefExpr: result = semDeref(c, n)
of nkAddr:
@ -2978,9 +3076,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result.typ = makePtrType(c, result[0].typ)
of nkHiddenAddr, nkHiddenDeref:
checkSonsLen(n, 1, c.config)
n[0] = semExpr(c, n[0], flags)
n[0] = semExpr(c, n[0], flags, expectedType)
of nkCast: result = semCast(c, n)
of nkIfExpr, nkIfStmt: result = semIf(c, n, flags)
of nkIfExpr, nkIfStmt: result = semIf(c, n, flags, expectedType)
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
checkSonsLen(n, 2, c.config)
considerGenSyms(c, n)
@ -2994,15 +3092,15 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
checkMinSonsLen(n, 2, c.config)
considerGenSyms(c, n)
of nkTableConstr:
result = semTableConstr(c, n)
result = semTableConstr(c, n, expectedType)
of nkClosedSymChoice, nkOpenSymChoice:
# handling of sym choices is context dependent
# the node is left intact for now
discard
of nkStaticExpr: result = semStaticExpr(c, n[0])
of nkStaticExpr: result = semStaticExpr(c, n[0], expectedType)
of nkAsgn: result = semAsgn(c, n)
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags)
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags, expectedType)
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags, expectedType)
of nkRaiseStmt: result = semRaise(c, n)
of nkVarSection: result = semVarOrLet(c, n, skVar)
of nkLetSection: result = semVarOrLet(c, n, skLet)
@ -3010,10 +3108,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkTypeSection: result = semTypeSection(c, n)
of nkDiscardStmt: result = semDiscard(c, n)
of nkWhileStmt: result = semWhile(c, n, flags)
of nkTryStmt, nkHiddenTryStmt: result = semTry(c, n, flags)
of nkTryStmt, nkHiddenTryStmt: result = semTry(c, n, flags, expectedType)
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
of nkForStmt, nkParForStmt: result = semFor(c, n, flags)
of nkCaseStmt: result = semCase(c, n, flags)
of nkCaseStmt: result = semCase(c, n, flags, expectedType)
of nkReturnStmt: result = semReturn(c, n)
of nkUsingStmt: result = semUsing(c, n)
of nkAsmStmt: result = semAsm(c, n)
@ -3052,7 +3150,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
result = semExportExcept(c, n)
of nkPragmaBlock:
result = semPragmaBlock(c, n)
result = semPragmaBlock(c, n, expectedType)
of nkStaticStmt:
result = semStaticStmt(c, n)
of nkDefer:

View file

@ -77,7 +77,7 @@ proc semConstrField(c: PContext, flags: TExprFlags,
"the field '$1' is not accessible." % [field.name.s])
return
var initValue = semExprFlagDispatched(c, assignment[1], flags)
var initValue = semExprFlagDispatched(c, assignment[1], flags, field.typ)
if initValue != nil:
initValue = fitNodeConsiderViewType(c, field.typ, initValue, assignment.info)
assignment[0] = newSymNode(field)
@ -375,13 +375,19 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
else:
assert false, "Must not enter here."
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
var t = semTypeNode(c, n[0], nil)
result = newNodeIT(nkObjConstr, n.info, t)
for child in n: result.add child
if t == nil:
return localErrorNode(c, result, "object constructor needs an object type")
if t.skipTypes({tyGenericInst,
tyAlias, tySink, tyOwned, tyRef}).kind != tyObject and
expectedType != nil and expectedType.skipTypes({tyGenericInst,
tyAlias, tySink, tyOwned, tyRef}).kind == tyObject:
t = expectedType
t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned})
if t.kind == tyRef:

View file

@ -86,7 +86,7 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
result = n
checkSonsLen(n, 2, c.config)
openScope(c)
n[0] = forceBool(c, semExprWithType(c, n[0]))
n[0] = forceBool(c, semExprWithType(c, n[0], expectedType = getSysType(c.graph, n.info, tyBool)))
inc(c.p.nestedLoopCounter)
n[1] = semStmt(c, n[1], flags)
dec(c.p.nestedLoopCounter)
@ -98,15 +98,15 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
proc semProc(c: PContext, n: PNode): PNode
proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}): PNode =
result = semExpr(c, n, flags)
proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}; expectedType: PType = nil): PNode =
result = semExpr(c, n, flags, expectedType)
if result.typ != nil:
# XXX tyGenericInst here?
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
proc semExprBranchScope(c: PContext, n: PNode): PNode =
proc semExprBranchScope(c: PContext, n: PNode; expectedType: PType = nil): PNode =
openScope(c)
result = semExprBranch(c, n)
result = semExprBranch(c, n, expectedType = expectedType)
closeScope(c)
const
@ -152,22 +152,25 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
s.add "; for a function call use ()"
localError(c.config, n.info, s)
proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
proc semIf(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
result = n
var typ = commonTypeBegin
var expectedType = expectedType
var hasElse = false
for i in 0..<n.len:
var it = n[i]
if it.len == 2:
openScope(c)
it[0] = forceBool(c, semExprWithType(c, it[0]))
it[1] = semExprBranch(c, it[1], flags)
it[0] = forceBool(c, semExprWithType(c, it[0], expectedType = getSysType(c.graph, n.info, tyBool)))
it[1] = semExprBranch(c, it[1], flags, expectedType)
typ = commonType(c, typ, it[1])
expectedType = typ
closeScope(c)
elif it.len == 1:
hasElse = true
it[0] = semExprBranchScope(c, it[0])
it[0] = semExprBranchScope(c, it[0], expectedType)
typ = commonType(c, typ, it[0])
expectedType = typ
else: illFormedAst(it, c.config)
if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped} or
(not hasElse and efInTypeof notin flags):
@ -183,7 +186,7 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
result.transitionSonsKind(nkIfExpr)
result.typ = typ
proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
var check = initIntSet()
template semExceptBranchType(typeNode: PNode): bool =
# returns true if exception type is imported type
@ -203,8 +206,10 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
checkMinSonsLen(n, 2, c.config)
var typ = commonTypeBegin
n[0] = semExprBranchScope(c, n[0])
var expectedType = expectedType
n[0] = semExprBranchScope(c, n[0], expectedType)
typ = commonType(c, typ, n[0].typ)
expectedType = typ
var last = n.len - 1
var catchAllExcepts = 0
@ -261,9 +266,13 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
localError(c.config, a.info, "Only one general except clause is allowed after more specific exceptions")
# last child of an nkExcept/nkFinally branch is a statement:
a[^1] = semExprBranchScope(c, a[^1])
if a.kind != nkFinally: typ = commonType(c, typ, a[^1])
else: dec last
if a.kind != nkFinally:
a[^1] = semExprBranchScope(c, a[^1], expectedType)
typ = commonType(c, typ, a[^1])
expectedType = typ
else:
a[^1] = semExprBranchScope(c, a[^1])
dec last
closeScope(c)
if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped}:
@ -597,7 +606,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var def: PNode = c.graph.emptyNode
if a[^1].kind != nkEmpty:
def = semExprWithType(c, a[^1], {})
def = semExprWithType(c, a[^1], {}, typ)
if def.kind in nkSymChoices and def[0].typ.skipTypes(abstractInst).kind == tyEnum:
errorSymChoiceUseQualifier(c, def)
@ -753,7 +762,7 @@ proc semConst(c: PContext, n: PNode): PNode =
var typFlags: TTypeAllowedFlags
# don't evaluate here since the type compatibility check below may add a converter
var def = semExprWithType(c, a[^1])
var def = semExprWithType(c, a[^1], {}, typ)
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
typFlags.incl taIsTemplateOrMacro
@ -1039,7 +1048,7 @@ proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
result.typ = result.lastSon.typ
closeScope(c)
proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
result = n
checkMinSonsLen(n, 2, c.config)
openScope(c)
@ -1048,6 +1057,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
var chckCovered = false
var covered: Int128 = toInt128(0)
var typ = commonTypeBegin
var expectedType = expectedType
var hasElse = false
let caseTyp = skipTypes(n[0].typ, abstractVar-{tyTypeDesc})
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool}
@ -1079,20 +1089,23 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
checkMinSonsLen(x, 2, c.config)
semCaseBranch(c, n, x, i, covered)
var last = x.len-1
x[last] = semExprBranchScope(c, x[last])
x[last] = semExprBranchScope(c, x[last], expectedType)
typ = commonType(c, typ, x[last])
expectedType = typ
of nkElifBranch:
chckCovered = false
checkSonsLen(x, 2, c.config)
openScope(c)
x[0] = forceBool(c, semExprWithType(c, x[0]))
x[1] = semExprBranch(c, x[1])
x[0] = forceBool(c, semExprWithType(c, x[0], expectedType = getSysType(c.graph, n.info, tyBool)))
x[1] = semExprBranch(c, x[1], expectedType = expectedType)
typ = commonType(c, typ, x[1])
expectedType = typ
closeScope(c)
of nkElse:
checkSonsLen(x, 1, c.config)
x[0] = semExprBranchScope(c, x[0])
x[0] = semExprBranchScope(c, x[0], expectedType)
typ = commonType(c, typ, x[0])
expectedType = typ
if (chckCovered and covered == toCover(c, n[0].typ)) or hasElse:
message(c.config, x.info, warnUnreachableElse)
hasElse = true
@ -1678,7 +1691,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} =
addParams(c, params, skProc)
pushProcCon(c, s)
addResult(c, n, n.typ[0], skProc)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], n.typ[0]))
trackProc(c, s, s.ast[bodyPos])
popProcCon(c)
popOwner(c)
@ -2100,7 +2113,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# allowed, everything else, including a nullary generic is an error.
pushProcCon(c, s)
addResult(c, n, s.typ[0], skProc)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], s.typ[0]))
trackProc(c, s, s.ast[bodyPos])
popProcCon(c)
elif efOperand notin flags:
@ -2113,8 +2126,15 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if s.kind notin {skMacro, skTemplate} and s.magic == mNone: paramsTypeCheck(c, s.typ)
maybeAddResult(c, s, n)
let resultType =
if s.kind == skMacro:
sysTypeFromName(c.graph, n.info, "NimNode")
elif not isInlineIterator(s.typ):
s.typ[0]
else:
nil
# semantic checking also needed with importc in case used in VM
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], resultType))
# unfortunately we cannot skip this step when in 'system.compiles'
# context as it may even be evaluated in 'system.compiles':
trackProc(c, s, s.ast[bodyPos])
@ -2291,7 +2311,7 @@ proc setLine(n: PNode, info: TLineInfo) =
for i in 0..<n.safeLen: setLine(n[i], info)
n.info = info
proc semPragmaBlock(c: PContext, n: PNode): PNode =
proc semPragmaBlock(c: PContext, n: PNode; expectedType: PType = nil): PNode =
checkSonsLen(n, 2, c.config)
let pragmaList = n[0]
pragma(c, nil, pragmaList, exprPragmas, isStatement = true)
@ -2308,7 +2328,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
localError(c.config, p.info, "invalid pragma block: " & $p)
inc c.inUncheckedAssignSection, inUncheckedAssignSection
n[1] = semExpr(c, n[1])
n[1] = semExpr(c, n[1], expectedType = expectedType)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
result = n
result.typ = n[1].typ
@ -2357,7 +2377,7 @@ proc inferConceptStaticParam(c: PContext, inferred, n: PNode) =
"attempt to equate '%s' and '%s'." % [inferred.renderTree, $res.typ, $typ.base])
typ.n = res
proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType = nil): PNode =
result = n
result.transitionSonsKind(nkStmtList)
var voidContext = false
@ -2370,7 +2390,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
# nkNilLit, nkEmpty}:
# dec last
for i in 0..<n.len:
var x = semExpr(c, n[i], flags)
var x = semExpr(c, n[i], flags, if i == n.len - 1: expectedType else: nil)
n[i] = x
if c.matchedConcept != nil and x.typ != nil and
(nfFromTemplate notin n.flags or i != last):

View file

@ -454,9 +454,9 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
setSize typ, 1
of tyInt16, tyUInt16:
setSize typ, 2
of tyInt32, tyUInt32:
of tyInt32, tyUInt32, tyFloat32:
setSize typ, 4
of tyInt64, tyUInt64:
of tyInt64, tyUInt64, tyFloat64, tyFloat:
setSize typ, 8
else:
typ.size = szUnknownSize

View file

@ -494,7 +494,9 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) =
# this list is subtle, we try to answer the question if after 'dest = f(src)'
# there is a connection betwen 'src' and 'dest' so that mutations to 'src'
# also reflect 'dest':
if magic in {mNone, mMove, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mArrToSeq}:
if magic in {mNone, mMove, mSlice,
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mArrToSeq, mOpenArrayToSeq}:
for i in 1..<n.len:
# we always have to assume a 'select(...)' like mechanism.
# But at least we do filter out simple POD types from the

View file

@ -1026,7 +1026,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.genAsgnPatch(n[1], d)
c.freeTemp(d)
of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest)
of mIsolate, mFinished:
of generatedMagics:
genCall(c, n, dest)
of mNew, mNewFinalize:
unused(c, n, dest)