mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-03 11:42:33 +00:00
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>
(cherry picked from commit 0014b9c48e)
This commit is contained in:
@@ -670,7 +670,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,
|
||||
@@ -704,8 +704,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,
|
||||
@@ -734,6 +734,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
|
||||
@@ -1679,6 +1682,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)
|
||||
|
||||
|
||||
@@ -2384,7 +2384,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)
|
||||
@@ -2979,7 +2979,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
|
||||
|
||||
@@ -141,3 +141,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
|
||||
defineSymbol("nimHasEnforceNoRaises")
|
||||
defineSymbol("nimHasWarnBareExcept")
|
||||
defineSymbol("nimHasTopDownInference")
|
||||
|
||||
@@ -1451,7 +1451,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:
|
||||
@@ -2102,6 +2102,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:
|
||||
@@ -2618,7 +2620,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)
|
||||
|
||||
@@ -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, tyAnything:
|
||||
# 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)
|
||||
|
||||
|
||||
@@ -118,10 +118,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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -589,21 +590,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))
|
||||
@@ -614,8 +630,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:
|
||||
@@ -627,13 +645,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, {})
|
||||
@@ -862,10 +880,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
|
||||
@@ -909,7 +927,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 =
|
||||
@@ -932,7 +950,7 @@ 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)
|
||||
|
||||
@@ -947,8 +965,8 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||
|
||||
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)
|
||||
@@ -964,7 +982,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]
|
||||
@@ -989,16 +1007,20 @@ 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)
|
||||
elif isSymChoice(n[0]):
|
||||
# overloaded generic procs e.g. newSeq[int] can end up here
|
||||
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)
|
||||
@@ -1037,9 +1059,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) # this uses efNoUndeclared
|
||||
# Now that nkSym does not imply an iteration over the proc/iterator space,
|
||||
@@ -1058,17 +1077,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 =
|
||||
@@ -1641,11 +1660,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)
|
||||
@@ -1819,7 +1838,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):
|
||||
@@ -1870,12 +1889,12 @@ 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 =
|
||||
when defined(nimsuggest):
|
||||
if c.graph.config.expandDone():
|
||||
return n
|
||||
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):
|
||||
@@ -2294,7 +2313,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
|
||||
@@ -2410,8 +2429,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
|
||||
@@ -2473,33 +2501,49 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
if n.len == 1:
|
||||
result.add(newTree(nkElse, newNode(nkStmtList)))
|
||||
|
||||
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)
|
||||
@@ -2518,7 +2562,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)
|
||||
@@ -2540,7 +2584,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
|
||||
@@ -2567,8 +2611,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()
|
||||
@@ -2578,7 +2627,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.")
|
||||
@@ -2593,18 +2644,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)
|
||||
@@ -2619,7 +2676,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)
|
||||
@@ -2685,8 +2742,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
|
||||
@@ -2811,7 +2868,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`
|
||||
@@ -2820,6 +2877,16 @@ 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
|
||||
when defined(nimsuggest):
|
||||
@@ -2839,13 +2906,23 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
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:
|
||||
@@ -2865,6 +2942,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!
|
||||
@@ -2872,39 +2953,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:
|
||||
@@ -2912,7 +3010,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, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy:
|
||||
if c.matchedConcept != nil and n.len == 1:
|
||||
let modifier = n.modifierTypeKindOfNode
|
||||
@@ -2938,40 +3036,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?)
|
||||
@@ -2990,12 +3088,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]
|
||||
@@ -3017,12 +3115,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:
|
||||
@@ -3032,9 +3130,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)
|
||||
@@ -3048,15 +3146,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, nkFastAsgn: 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)
|
||||
@@ -3064,10 +3162,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)
|
||||
@@ -3106,7 +3204,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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -98,7 +98,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)
|
||||
@@ -112,15 +112,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
|
||||
@@ -169,22 +169,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):
|
||||
@@ -200,7 +203,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
|
||||
@@ -222,8 +225,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
|
||||
@@ -281,9 +286,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}:
|
||||
@@ -563,7 +572,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)
|
||||
@@ -717,7 +726,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
|
||||
@@ -1008,7 +1017,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)
|
||||
@@ -1017,6 +1026,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}
|
||||
@@ -1048,20 +1058,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
|
||||
@@ -1670,7 +1683,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)
|
||||
@@ -2092,7 +2105,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:
|
||||
@@ -2105,8 +2118,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])
|
||||
@@ -2280,7 +2300,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)
|
||||
@@ -2297,7 +2317,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
|
||||
@@ -2346,7 +2366,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
|
||||
@@ -2359,7 +2379,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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -491,7 +491,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
|
||||
|
||||
@@ -1038,7 +1038,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)
|
||||
|
||||
@@ -123,6 +123,65 @@ This feature has to be enabled via `{.experimental: "implicitDeref".}`:
|
||||
echo n.depth
|
||||
# no need to write n[].depth either
|
||||
|
||||
Top-down type inference
|
||||
=======================
|
||||
|
||||
In expressions such as:
|
||||
|
||||
```nim
|
||||
let a: T = ex
|
||||
```
|
||||
|
||||
Normally, the compiler type checks the expression `ex` by itself, then
|
||||
attempts to statically convert the type-checked expression to the given type
|
||||
`T` as much as it can, while making sure it matches the type. The extent of
|
||||
this process is limited however due to the expression usually having
|
||||
an assumed type that might clash with the given type.
|
||||
|
||||
With top-down type inference, the expression is type checked with the
|
||||
extra knowledge that it is supposed to be of type `T`. For example,
|
||||
the following code is does not compile with the former method, but
|
||||
compiles with top-down type inference:
|
||||
|
||||
```nim
|
||||
let foo: (float, uint8, cstring) = (1, 2, "abc")
|
||||
```
|
||||
|
||||
The tuple expression has an expected type of `(float, uint8, cstring)`.
|
||||
Since it is a tuple literal, we can use this information to assume the types
|
||||
of its elements. The expected types for the expressions `1`, `2` and `"abc"`
|
||||
are respectively `float`, `uint8`, and `cstring`; and these expressions can be
|
||||
statically converted to these types.
|
||||
|
||||
Without this information, the type of the tuple expression would have been
|
||||
assumed to be `(int, int, string)`. Thus the type of the tuple expression
|
||||
would not match the type of the variable, and an error would be given.
|
||||
|
||||
The extent of this varies, but there are some notable special cases.
|
||||
|
||||
Sequence literals
|
||||
-----------------
|
||||
|
||||
Top-down type inference applies to sequence literals.
|
||||
|
||||
```nim
|
||||
let x: seq[seq[float]] = @[@[1, 2, 3], @[4, 5, 6]]
|
||||
```
|
||||
|
||||
This behavior is tied to the `@` overloads in the `system` module,
|
||||
so overloading `@` can disable this behavior. This can be circumvented by
|
||||
specifying the `` system.`@` `` overload.
|
||||
|
||||
```nim
|
||||
proc `@`(x: string): string = "@" & x
|
||||
|
||||
# does not compile:
|
||||
let x: seq[float] = @[1, 2, 3]
|
||||
# compiles:
|
||||
let x: seq[float] = system.`@`([1, 2, 3])
|
||||
```
|
||||
|
||||
|
||||
|
||||
Code reordering
|
||||
===============
|
||||
|
||||
@@ -787,7 +787,7 @@ template toSeq1(s: not iterator): untyped =
|
||||
i += 1
|
||||
result
|
||||
else:
|
||||
var result: seq[OutType] = @[]
|
||||
var result: seq[OutType]# = @[]
|
||||
for it in s:
|
||||
result.add(it)
|
||||
result
|
||||
@@ -804,7 +804,7 @@ template toSeq2(iter: iterator): untyped =
|
||||
result
|
||||
else:
|
||||
type OutType = typeof(iter2())
|
||||
var result: seq[OutType] = @[]
|
||||
var result: seq[OutType]# = @[]
|
||||
when compiles(iter2()):
|
||||
evalOnceAs(iter4, iter, false)
|
||||
let iter3 = iter4()
|
||||
@@ -848,7 +848,7 @@ template toSeq*(iter: untyped): untyped =
|
||||
inc i
|
||||
result
|
||||
else:
|
||||
var result: seq[typeof(iter)] = @[]
|
||||
var result: seq[typeof(iter)]# = @[]
|
||||
for x in iter:
|
||||
result.add(x)
|
||||
result
|
||||
@@ -1016,7 +1016,7 @@ template mapIt*(s: typed, op: untyped): untyped =
|
||||
i += 1
|
||||
result
|
||||
else:
|
||||
var result: seq[OutType] = @[]
|
||||
var result: seq[OutType]# = @[]
|
||||
# use `items` to avoid https://github.com/nim-lang/Nim/issues/12639
|
||||
for it {.inject.} in items(s):
|
||||
result.add(op)
|
||||
|
||||
@@ -1624,13 +1624,23 @@ proc isNil*[T: proc](x: T): bool {.noSideEffect, magic: "IsNil".}
|
||||
## `== nil`.
|
||||
|
||||
|
||||
proc `@`*[T](a: openArray[T]): seq[T] =
|
||||
## Turns an *openArray* into a sequence.
|
||||
##
|
||||
## This is not as efficient as turning a fixed length array into a sequence
|
||||
## as it always copies every element of `a`.
|
||||
newSeq(result, a.len)
|
||||
for i in 0..a.len-1: result[i] = a[i]
|
||||
when defined(nimHasTopDownInference):
|
||||
# magic used for seq type inference
|
||||
proc `@`*[T](a: openArray[T]): seq[T] {.magic: "OpenArrayToSeq".} =
|
||||
## Turns an *openArray* into a sequence.
|
||||
##
|
||||
## This is not as efficient as turning a fixed length array into a sequence
|
||||
## as it always copies every element of `a`.
|
||||
newSeq(result, a.len)
|
||||
for i in 0..a.len-1: result[i] = a[i]
|
||||
else:
|
||||
proc `@`*[T](a: openArray[T]): seq[T] =
|
||||
## Turns an *openArray* into a sequence.
|
||||
##
|
||||
## This is not as efficient as turning a fixed length array into a sequence
|
||||
## as it always copies every element of `a`.
|
||||
newSeq(result, a.len)
|
||||
for i in 0..a.len-1: result[i] = a[i]
|
||||
|
||||
|
||||
when defined(nimSeqsV2):
|
||||
|
||||
@@ -453,8 +453,8 @@ block:
|
||||
for i in 0..<len:
|
||||
yield i
|
||||
|
||||
# xxx: obscure CT error: basic_types.nim(16, 16) Error: internal error: symbol has no generated name: true
|
||||
when not defined(js):
|
||||
# xxx: obscure CT error: basic_types.nim(16, 16) Error: internal error: symbol has no generated name: true
|
||||
doAssert: iter(3).mapIt(2*it).foldl(a + b) == 6
|
||||
|
||||
block: # strictFuncs tests with ref object
|
||||
|
||||
195
tests/types/ttopdowninference.nim
Normal file
195
tests/types/ttopdowninference.nim
Normal file
@@ -0,0 +1,195 @@
|
||||
block:
|
||||
var s: seq[string] = (discard; @[])
|
||||
|
||||
var x: set[char] =
|
||||
if true:
|
||||
try:
|
||||
case 1
|
||||
of 1:
|
||||
if false:
|
||||
{'4'}
|
||||
else:
|
||||
block:
|
||||
s.add "a"
|
||||
{}
|
||||
else: {'3'}
|
||||
except: {'2'}
|
||||
else: {'1'}
|
||||
doAssert x is set[char]
|
||||
doAssert x == {}
|
||||
doAssert s == @["a"]
|
||||
|
||||
x = {'a', 'b'}
|
||||
doAssert x == {'a', 'b'}
|
||||
|
||||
x = (s.add "b"; {})
|
||||
doAssert x == {}
|
||||
doAssert s == @["a", "b"]
|
||||
|
||||
let x2: set[byte] = {1}
|
||||
doAssert x2 == {1u8}
|
||||
|
||||
block:
|
||||
let x3: array[0..2, byte] = [1, 2, 3]
|
||||
#let x4: openarray[byte] = [1, 2, 3]
|
||||
#let x5: openarray[byte] = @[1, 2, 3]
|
||||
let x6: seq[byte] = @[1, 2, 3]
|
||||
let x7: seq[seq[float32]] = @[@[1, 2, 3], @[4.3, 5, 6]]
|
||||
type ABC = enum a, b, c
|
||||
let x8: array[ABC, byte] = [1, 2, 3]
|
||||
doAssert x8[a] == 1
|
||||
doAssert x8[a] + x8[b] == x8[c]
|
||||
|
||||
const x9: array[-2..2, float] = [0, 1, 2, 3, 4]
|
||||
let x10: array[ABC, byte] = block:
|
||||
{.gcsafe.}:
|
||||
[a: 1, b: 2, c: 3]
|
||||
proc `@`(x: float): float = x + 1
|
||||
doAssert @1 == 2
|
||||
let x11: seq[byte] = system.`@`([1, 2, 3])
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: BiggestInt
|
||||
var foo: Foo
|
||||
foo.x = case true
|
||||
of true: ord(1)
|
||||
else: 0
|
||||
foo.x = if true: ord(1) else: 0
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: (float, seq[(byte, seq[byte])])
|
||||
|
||||
let foo = Foo(x: (1, @{2: @[], 3: @[4, 5]}))
|
||||
doAssert foo.x == (1.0, @{2u8: @[], 3u8: @[4u8, 5]})
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: tuple[a: float, b: seq[(byte, seq[byte])]]
|
||||
|
||||
let foo = Foo(x: (a: 1, b: @{2: @[3, 4], 5: @[]}))
|
||||
doAssert foo.x == (1.0, @{2u8: @[3u8, 4], 5u8: @[]})
|
||||
|
||||
block:
|
||||
proc foo(): seq[float] = @[1]
|
||||
|
||||
let fooLamb = proc(): seq[float] = @[1]
|
||||
|
||||
doAssert foo() == fooLamb()
|
||||
|
||||
block:
|
||||
type Foo[T] = float32
|
||||
|
||||
let x: seq[Foo[int32]] = @[1]
|
||||
|
||||
block:
|
||||
type Foo = ref object
|
||||
type Bar[T] = ptr object
|
||||
|
||||
let x1: seq[Foo] = @[nil]
|
||||
let x2: seq[Bar[int]] = @[nil]
|
||||
let x3: seq[cstring] = @[nil]
|
||||
|
||||
block:
|
||||
let x: seq[cstring] = @["abc", nil, "def"]
|
||||
doAssert x.len == 3
|
||||
doAssert x[0] == cstring"abc"
|
||||
doAssert x[1].isNil
|
||||
doAssert x[2] == "def".cstring
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: tuple[a: float, b: seq[(byte, seq[cstring])]]
|
||||
|
||||
let foo = Foo(x: (a: 1, b: @{2: @[nil, "abc"]}))
|
||||
doAssert foo.x == (1.0, @{2u8: @[cstring nil, cstring "abc"]})
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: tuple[a: float, b: seq[(byte, seq[ptr int])]]
|
||||
|
||||
let foo = Foo(x: (a: 1, b: @{2: @[nil, nil]}))
|
||||
doAssert foo.x == (1.0, @{2u8: @[(ptr int)(nil), nil]})
|
||||
|
||||
when false: # unsupported
|
||||
block: # type conversion
|
||||
let x = seq[(cstring, float32)](@{"abc": 1.0, "def": 2.0})
|
||||
doAssert x[0] == (cstring"abc", 1.0'f32)
|
||||
doAssert x[1] == (cstring"def", 2.0'f32)
|
||||
|
||||
block: # enum
|
||||
type Foo {.pure.} = enum a
|
||||
type Bar {.pure.} = enum a, b, c
|
||||
|
||||
var s: seq[Bar] = @[a, b, c]
|
||||
|
||||
block: # overload selection
|
||||
proc foo(x, y: int): int = x + y + 1
|
||||
proc foo(x: int): int = x - 1
|
||||
var s: seq[proc (x, y: int): int] = @[nil, foo, foo]
|
||||
var s2: seq[int]
|
||||
for a in s:
|
||||
if not a.isNil: s2.add(a(1, 2))
|
||||
doAssert s2 == @[4, 4]
|
||||
|
||||
block: # with generics?
|
||||
proc foo(x, y: int): int = x + y + 1
|
||||
proc foo(x: int): int = x - 1
|
||||
proc bar[T](x, y: T): T = x - y
|
||||
var s: seq[proc (x, y: int): int] = @[nil, foo, foo, bar]
|
||||
var s2: seq[int]
|
||||
for a in s:
|
||||
if not a.isNil: s2.add(a(1, 2))
|
||||
doAssert s2 == @[4, 4, -1]
|
||||
proc foo(x, y: float): float = x + y + 1.0
|
||||
var s3: seq[proc (x, y: float): float] = @[nil, foo, foo, bar]
|
||||
var s4: seq[float]
|
||||
for a in s3:
|
||||
if not a.isNil: s4.add(a(1, 2))
|
||||
doAssert s4 == @[4.0, 4, -1]
|
||||
|
||||
block: # range types
|
||||
block:
|
||||
let x: set[range[1u8..5u8]] = {1, 3}
|
||||
doAssert x == {range[1u8..5u8](1), 3}
|
||||
doAssert $x == "{1, 3}"
|
||||
block:
|
||||
let x: seq[set[range[1u8..5u8]]] = @[{1, 3}]
|
||||
doAssert x == @[{range[1u8..5u8](1), 3}]
|
||||
doAssert $x[0] == "{1, 3}"
|
||||
block:
|
||||
let x: seq[range[1u8..5u8]] = @[1, 3]
|
||||
doAssert x == @[range[1u8..5u8](1), 3]
|
||||
doAssert $x == "@[1, 3]"
|
||||
block: # already worked before, make sure it still works
|
||||
let x: set[range['a'..'e']] = {'a', 'c'}
|
||||
doAssert x == {range['a'..'e']('a'), 'c'}
|
||||
doAssert $x == "{'a', 'c'}"
|
||||
block: # extended
|
||||
let x: seq[set[range['a'..'e']]] = @[{'a', 'c'}]
|
||||
doAssert x[0] == {range['a'..'e']('a'), 'c'}
|
||||
doAssert $x == "@[{'a', 'c'}]"
|
||||
block:
|
||||
type Foo = object
|
||||
x: (range[1u8..5u8], seq[(range[1f32..5f32], seq[range['a'..'e']])])
|
||||
|
||||
let foo = Foo(x: (1, @{2: @[], 3: @['c', 'd']}))
|
||||
doAssert foo.x == (range[1u8..5u8](1u8), @{range[1f32..5f32](2f32): @[], 3f32: @[range['a'..'e']('c'), 'd']})
|
||||
block:
|
||||
type Foo = object
|
||||
x: (range[1u8..5u8], seq[(range[1f32..5f32], seq[set[range['a'..'e']]])])
|
||||
|
||||
let foo = Foo(x: (1, @{2: @[], 3: @[{'c', 'd'}]}))
|
||||
doAssert foo.x == (range[1u8..5u8](1u8), @{range[1f32..5f32](2f32): @[], 3f32: @[{range['a'..'e']('c'), 'd'}]})
|
||||
|
||||
block: # templates
|
||||
template foo: untyped = (1, 2, "abc")
|
||||
let x: (float, byte, cstring) = foo()
|
||||
doAssert x[0] == float(1)
|
||||
doAssert x[1] == byte(2)
|
||||
doAssert x[2] == cstring("abc")
|
||||
let (a, b, c) = x
|
||||
doAssert a == float(1)
|
||||
doAssert b == byte(2)
|
||||
doAssert c == cstring("abc")
|
||||
Reference in New Issue
Block a user