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:
parent
2dcfd73260
commit
0014b9c48e
17 changed files with 599 additions and 199 deletions
|
|
@ -674,7 +674,7 @@ type
|
||||||
mInSet, mRepr, mExit,
|
mInSet, mRepr, mExit,
|
||||||
mSetLengthStr, mSetLengthSeq,
|
mSetLengthStr, mSetLengthSeq,
|
||||||
mIsPartOf, mAstToStr, mParallel,
|
mIsPartOf, mAstToStr, mParallel,
|
||||||
mSwap, mIsNil, mArrToSeq,
|
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
|
||||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||||
mMove, mWasMoved, mDestroy, mTrace,
|
mMove, mWasMoved, mDestroy, mTrace,
|
||||||
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
|
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
|
||||||
|
|
@ -708,8 +708,8 @@ type
|
||||||
mSymIsInstantiationOf, mNodeId, mPrivateAccess
|
mSymIsInstantiationOf, mNodeId, mPrivateAccess
|
||||||
|
|
||||||
|
|
||||||
# things that we can evaluate safely at compile time, even if not asked for it:
|
|
||||||
const
|
const
|
||||||
|
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||||
ctfeWhitelist* = {mNone, mSucc,
|
ctfeWhitelist* = {mNone, mSucc,
|
||||||
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
||||||
mLengthStr, mLengthArray, mLengthSeq,
|
mLengthStr, mLengthArray, mLengthSeq,
|
||||||
|
|
@ -739,6 +739,9 @@ const
|
||||||
mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||||
mInSet, mRepr}
|
mInSet, mRepr}
|
||||||
|
|
||||||
|
generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq}
|
||||||
|
## magics that are generated as normal procs in the backend
|
||||||
|
|
||||||
type
|
type
|
||||||
ItemId* = object
|
ItemId* = object
|
||||||
module*: int32
|
module*: int32
|
||||||
|
|
@ -1677,6 +1680,10 @@ proc transitionIntKind*(n: PNode, kind: range[nkCharLit..nkUInt64Lit]) =
|
||||||
transitionNodeKindCommon(kind)
|
transitionNodeKindCommon(kind)
|
||||||
n.intVal = obj.intVal
|
n.intVal = obj.intVal
|
||||||
|
|
||||||
|
proc transitionIntToFloatKind*(n: PNode, kind: range[nkFloatLit..nkFloat128Lit]) =
|
||||||
|
transitionNodeKindCommon(kind)
|
||||||
|
n.floatVal = BiggestFloat(obj.intVal)
|
||||||
|
|
||||||
proc transitionNoneToSym*(n: PNode) =
|
proc transitionNoneToSym*(n: PNode) =
|
||||||
transitionNodeKindCommon(nkSym)
|
transitionNodeKindCommon(nkSym)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2369,7 +2369,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
genDollar(p, e, d, "#nimFloatToStr($1)")
|
genDollar(p, e, d, "#nimFloatToStr($1)")
|
||||||
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
|
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
|
||||||
of mStrToStr, mUnown: expr(p, e[1], d)
|
of mStrToStr, mUnown: expr(p, e[1], d)
|
||||||
of mIsolate, mFinished: genCall(p, e, d)
|
of generatedMagics: genCall(p, e, d)
|
||||||
of mEnumToStr:
|
of mEnumToStr:
|
||||||
if optTinyRtti in p.config.globalOptions:
|
if optTinyRtti in p.config.globalOptions:
|
||||||
genEnumToStr(p, e, d)
|
genEnumToStr(p, e, d)
|
||||||
|
|
@ -2978,7 +2978,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
if n[genericParamsPos].kind == nkEmpty:
|
if n[genericParamsPos].kind == nkEmpty:
|
||||||
var prc = n[namePos].sym
|
var prc = n[namePos].sym
|
||||||
if useAliveDataFromDce in p.module.flags:
|
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)
|
genProc(p.module, prc)
|
||||||
elif prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
|
elif prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
|
||||||
if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||||
|
|
|
||||||
|
|
@ -140,4 +140,5 @@ proc initDefines*(symbols: StringTableRef) =
|
||||||
defineSymbol("nimHasEffectsOf")
|
defineSymbol("nimHasEffectsOf")
|
||||||
|
|
||||||
defineSymbol("nimHasEnforceNoRaises")
|
defineSymbol("nimHasEnforceNoRaises")
|
||||||
|
defineSymbol("nimHasTopDownInference")
|
||||||
defineSymbol("nimHasTemplateRedefinitionPragma")
|
defineSymbol("nimHasTemplateRedefinitionPragma")
|
||||||
|
|
|
||||||
|
|
@ -1455,7 +1455,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
s.name.s)
|
s.name.s)
|
||||||
discard mangleName(p.module, s)
|
discard mangleName(p.module, s)
|
||||||
r.res = s.loc.r
|
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 != {}:
|
{sfImportc, sfInfixCall} * s.flags != {}:
|
||||||
discard
|
discard
|
||||||
elif s.kind == skMethod and getBody(p.module.graph, s).kind == nkEmpty:
|
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)
|
gen(p, n[1], x)
|
||||||
useMagic(p, "nimCopy")
|
useMagic(p, "nimCopy")
|
||||||
r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)]
|
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 mDestroy, mTrace: discard "ignore calls to the default destructor"
|
||||||
of mOrd: genOrd(p, n, r)
|
of mOrd: genOrd(p, n, r)
|
||||||
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
|
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
|
||||||
|
|
@ -2622,7 +2624,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
let s = n[namePos].sym
|
let s = n[namePos].sym
|
||||||
discard mangleName(p.module, s)
|
discard mangleName(p.module, s)
|
||||||
r.res = s.loc.r
|
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):
|
elif not p.g.generatedSyms.containsOrIncl(s.id):
|
||||||
p.locals.add(genProc(p, s))
|
p.locals.add(genProc(p, s))
|
||||||
of nkType: r.res = genTypeInfo(p, n.typ)
|
of nkType: r.res = genTypeInfo(p, n.typ)
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,11 @@ when not defined(leanCompiler):
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc semExpr(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 = {}): PNode
|
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode
|
||||||
proc semExprNoType(c: PContext, n: PNode): PNode
|
proc semExprNoType(c: PContext, n: PNode): PNode
|
||||||
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): 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 fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode
|
||||||
proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
|
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 finishMethod(c: PContext, s: PSym)
|
||||||
proc evalAtCompileTime(c: PContext, n: PNode): PNode
|
proc evalAtCompileTime(c: PContext, n: PNode): PNode
|
||||||
proc indexTypesMatch(c: PContext, f, a: PType, arg: 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 semStaticType(c: PContext, childNode: PNode, prev: PType): PType
|
||||||
proc semTypeOf(c: PContext; n: PNode): PNode
|
proc semTypeOf(c: PContext; n: PNode): PNode
|
||||||
proc computeRequiresInit(c: PContext, t: PType): bool
|
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)
|
typeAllowedCheck(c, typ.n.info, typ, skProc)
|
||||||
|
|
||||||
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
|
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 semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
|
||||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
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,
|
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 =
|
proc symFromType(c: PContext; t: PType, info: TLineInfo): PSym =
|
||||||
if t.sym != nil: return t.sym
|
if t.sym != nil: return t.sym
|
||||||
|
|
@ -334,8 +334,8 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
|
||||||
isArrayConstr(arg):
|
isArrayConstr(arg):
|
||||||
arg.typ = eOrig.typ
|
arg.typ = eOrig.typ
|
||||||
|
|
||||||
proc tryConstExpr(c: PContext, n: PNode): PNode =
|
proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
|
||||||
var e = semExprWithType(c, n)
|
var e = semExprWithType(c, n, expectedType = expectedType)
|
||||||
if e == nil: return
|
if e == nil: return
|
||||||
|
|
||||||
result = getConstExpr(c.module, e, c.idgen, c.graph)
|
result = getConstExpr(c.module, e, c.idgen, c.graph)
|
||||||
|
|
@ -365,8 +365,8 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
|
||||||
const
|
const
|
||||||
errConstExprExpected = "constant expression expected"
|
errConstExprExpected = "constant expression expected"
|
||||||
|
|
||||||
proc semConstExpr(c: PContext, n: PNode): PNode =
|
proc semConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
|
||||||
var e = semExprWithType(c, n)
|
var e = semExprWithType(c, n, expectedType = expectedType)
|
||||||
if e == nil:
|
if e == nil:
|
||||||
localError(c.config, n.info, errConstExprExpected)
|
localError(c.config, n.info, errConstExprExpected)
|
||||||
return n
|
return n
|
||||||
|
|
@ -388,14 +388,14 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
result = fixupTypeAfterEval(c, result, e)
|
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 efNeedStatic in flags:
|
||||||
if efPreferNilResult in flags:
|
if efPreferNilResult in flags:
|
||||||
return tryConstExpr(c, n)
|
return tryConstExpr(c, n, expectedType)
|
||||||
else:
|
else:
|
||||||
return semConstExpr(c, n)
|
return semConstExpr(c, n, expectedType)
|
||||||
else:
|
else:
|
||||||
result = semExprWithType(c, n, flags)
|
result = semExprWithType(c, n, flags, expectedType)
|
||||||
if efPreferStatic in flags:
|
if efPreferStatic in flags:
|
||||||
var evaluated = getConstExpr(c.module, result, c.idgen, c.graph)
|
var evaluated = getConstExpr(c.module, result, c.idgen, c.graph)
|
||||||
if evaluated != nil: return evaluated
|
if evaluated != nil: return evaluated
|
||||||
|
|
@ -414,7 +414,7 @@ proc resetSemFlag(n: PNode) =
|
||||||
resetSemFlag(n[i])
|
resetSemFlag(n[i])
|
||||||
|
|
||||||
proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
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.
|
## Semantically check the output of a macro.
|
||||||
## This involves processes such as re-checking the macro output for type
|
## This involves processes such as re-checking the macro output for type
|
||||||
## coherence, making sure that variables declared with 'let' aren't
|
## coherence, making sure that variables declared with 'let' aren't
|
||||||
|
|
@ -438,10 +438,10 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||||
case retType.kind
|
case retType.kind
|
||||||
of tyUntyped:
|
of tyUntyped:
|
||||||
# Not expecting a type here allows templates like in ``tmodulealias.in``.
|
# Not expecting a type here allows templates like in ``tmodulealias.in``.
|
||||||
result = semExpr(c, result, flags)
|
result = semExpr(c, result, flags, expectedType)
|
||||||
of tyTyped:
|
of tyTyped:
|
||||||
# More restrictive version.
|
# More restrictive version.
|
||||||
result = semExprWithType(c, result, flags)
|
result = semExprWithType(c, result, flags, expectedType)
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
if result.kind == nkStmtList: result.transitionSonsKind(nkStmtListType)
|
if result.kind == nkStmtList: result.transitionSonsKind(nkStmtListType)
|
||||||
var typ = semTypeNode(c, result, nil)
|
var typ = semTypeNode(c, result, nil)
|
||||||
|
|
@ -465,7 +465,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||||
retType = generateTypeInstance(c, paramTypes,
|
retType = generateTypeInstance(c, paramTypes,
|
||||||
macroResult.info, retType)
|
macroResult.info, retType)
|
||||||
|
|
||||||
result = semExpr(c, result, flags)
|
result = semExpr(c, result, flags, expectedType)
|
||||||
result = fitNode(c, retType, result, result.info)
|
result = fitNode(c, retType, result, result.info)
|
||||||
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0]))
|
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0]))
|
||||||
dec(c.config.evalTemplateCounter)
|
dec(c.config.evalTemplateCounter)
|
||||||
|
|
@ -476,7 +476,7 @@ const
|
||||||
errFloatToString = "cannot convert '$1' to '$2'"
|
errFloatToString = "cannot convert '$1' to '$2'"
|
||||||
|
|
||||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
flags: TExprFlags = {}): PNode =
|
flags: TExprFlags = {}; expectedType: PType = nil): PNode =
|
||||||
rememberExpansion(c, nOrig.info, sym)
|
rememberExpansion(c, nOrig.info, sym)
|
||||||
pushInfoContext(c.config, nOrig.info, sym.detailedInfo)
|
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)
|
# c.evalContext = c.createEvalContext(emStatic)
|
||||||
result = evalMacroCall(c.module, c.idgen, c.graph, c.templInstCounter, n, nOrig, sym)
|
result = evalMacroCall(c.module, c.idgen, c.graph, c.templInstCounter, n, nOrig, sym)
|
||||||
if efNoSemCheck notin flags:
|
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):
|
if c.config.macrosToExpand.hasKey(sym.name.s):
|
||||||
message(c.config, nOrig.info, hintExpandMacro, renderTree(result))
|
message(c.config, nOrig.info, hintExpandMacro, renderTree(result))
|
||||||
result = wrapInComesFrom(nOrig.info, sym, result)
|
result = wrapInComesFrom(nOrig.info, sym, result)
|
||||||
|
|
@ -507,7 +507,7 @@ proc forceBool(c: PContext, n: PNode): PNode =
|
||||||
if result == nil: result = n
|
if result == nil: result = n
|
||||||
|
|
||||||
proc semConstBoolExpr(c: PContext, n: PNode): PNode =
|
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:
|
if result.kind != nkIntLit:
|
||||||
localError(c.config, n.info, errConstExprExpected)
|
localError(c.config, n.info, errConstExprExpected)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -120,10 +120,10 @@ type
|
||||||
symMapping*: TIdTable # every gensym'ed symbol needs to be mapped
|
symMapping*: TIdTable # every gensym'ed symbol needs to be mapped
|
||||||
# to some new symbol in a generic instantiation
|
# to some new symbol in a generic instantiation
|
||||||
libs*: seq[PLib] # all libs used by this module
|
libs*: seq[PLib] # all libs used by this module
|
||||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
semConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.} # for the pragmas
|
||||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode {.nimcall.}
|
||||||
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): 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.}
|
computeRequiresInit*: proc (c: PContext, t: PType): bool {.nimcall.}
|
||||||
hasUnresolvedArgs*: proc (c: PContext, n: PNode): bool
|
hasUnresolvedArgs*: proc (c: PContext, n: PNode): bool
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ const
|
||||||
errUndeclaredFieldX = "undeclared field: '$1'"
|
errUndeclaredFieldX = "undeclared field: '$1'"
|
||||||
|
|
||||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||||
flags: TExprFlags = {}): PNode =
|
flags: TExprFlags = {}; expectedType: PType = nil): PNode =
|
||||||
rememberExpansion(c, n.info, s)
|
rememberExpansion(c, n.info, s)
|
||||||
let info = getCallLineInfo(n)
|
let info = getCallLineInfo(n)
|
||||||
markUsed(c, info, s)
|
markUsed(c, info, s)
|
||||||
|
|
@ -36,7 +36,8 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||||
pushInfoContext(c.config, n.info, s.detailedInfo)
|
pushInfoContext(c.config, n.info, s.detailedInfo)
|
||||||
result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache,
|
result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache,
|
||||||
c.templInstCounter, c.idgen, efFromHlo in flags)
|
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)
|
popInfoContext(c.config)
|
||||||
|
|
||||||
# XXX: A more elaborate line info rewrite might be needed
|
# 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}))
|
renderTree(result, {renderNoComments}))
|
||||||
result.typ = errorType(c)
|
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)
|
rejectEmptyNode(n)
|
||||||
result = semExpr(c, n, flags+{efWantValue})
|
result = semExpr(c, n, flags+{efWantValue}, expectedType)
|
||||||
|
|
||||||
let
|
let
|
||||||
isEmpty = result.kind == nkEmpty
|
isEmpty = result.kind == nkEmpty
|
||||||
|
|
@ -82,8 +83,8 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# do not produce another redundant error message:
|
# do not produce another redundant error message:
|
||||||
result = errorNode(c, n)
|
result = errorNode(c, n)
|
||||||
|
|
||||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
|
||||||
result = semExprCheck(c, n, flags)
|
result = semExprCheck(c, n, flags, expectedType)
|
||||||
if result.typ == nil and efInTypeof in flags:
|
if result.typ == nil and efInTypeof in flags:
|
||||||
result.typ = c.voidType
|
result.typ = c.voidType
|
||||||
elif result.typ == nil or result.typ == c.enforceVoidContext:
|
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, {})
|
let s = qualifiedLookUp(c, n, {})
|
||||||
result = s != nil and sfSystemModule in s.owner.flags and s.name.s == "owned"
|
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:
|
if n.len != 2:
|
||||||
localError(c.config, n.info, "a type conversion takes exactly one argument")
|
localError(c.config, n.info, "a type conversion takes exactly one argument")
|
||||||
return n
|
return n
|
||||||
|
|
@ -277,7 +278,7 @@ proc semConv(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
targetType = targetType.base
|
targetType = targetType.base
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
var evaluated = semStaticExpr(c, n[1])
|
var evaluated = semStaticExpr(c, n[1], expectedType)
|
||||||
if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc:
|
if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc:
|
||||||
result = n
|
result = n
|
||||||
result.typ = c.makeTypeDesc semStaticType(c, evaluated, nil)
|
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)
|
typ[0] = makeRangeType(c, 0, n.len - 1, n.info)
|
||||||
result = typ
|
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 = newNodeI(nkBracket, n.info)
|
||||||
result.typ = newTypeS(tyArray, c)
|
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
|
rawAddSon(result.typ, nil) # index type
|
||||||
var
|
var
|
||||||
firstIndex, lastIndex: Int128
|
firstIndex, lastIndex: Int128
|
||||||
indexType = getSysType(c.graph, n.info, tyInt)
|
indexType = getSysType(c.graph, n.info, tyInt)
|
||||||
lastValidIndex = lastOrd(c.config, indexType)
|
lastValidIndex = lastOrd(c.config, indexType)
|
||||||
if n.len == 0:
|
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)
|
lastIndex = toInt128(-1)
|
||||||
else:
|
else:
|
||||||
var x = n[0]
|
var x = n[0]
|
||||||
if x.kind == nkExprColonExpr and x.len == 2:
|
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):
|
if not isOrdinalType(idx.typ):
|
||||||
localError(c.config, idx.info, "expected ordinal value for array " &
|
localError(c.config, idx.info, "expected ordinal value for array " &
|
||||||
"index, got '$1'" % renderTree(idx))
|
"index, got '$1'" % renderTree(idx))
|
||||||
|
|
@ -608,8 +624,10 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
lastValidIndex = lastOrd(c.config, indexType)
|
lastValidIndex = lastOrd(c.config, indexType)
|
||||||
x = x[1]
|
x = x[1]
|
||||||
|
|
||||||
let yy = semExprWithType(c, x)
|
let yy = semExprWithType(c, x, expectedType = expectedElementType)
|
||||||
var typ = yy.typ
|
var typ = yy.typ
|
||||||
|
if expectedElementType == nil:
|
||||||
|
expectedElementType = typ
|
||||||
result.add yy
|
result.add yy
|
||||||
#var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
|
#var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
|
||||||
for i in 1..<n.len:
|
for i in 1..<n.len:
|
||||||
|
|
@ -621,13 +639,13 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
x = n[i]
|
x = n[i]
|
||||||
if x.kind == nkExprColonExpr and x.len == 2:
|
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)
|
idx = fitNode(c, indexType, idx, x.info)
|
||||||
if lastIndex+1 != getOrdValue(idx):
|
if lastIndex+1 != getOrdValue(idx):
|
||||||
localError(c.config, x.info, "invalid order in array constructor")
|
localError(c.config, x.info, "invalid order in array constructor")
|
||||||
x = x[1]
|
x = x[1]
|
||||||
|
|
||||||
let xx = semExprWithType(c, x, {})
|
let xx = semExprWithType(c, x, {}, expectedElementType)
|
||||||
result.add xx
|
result.add xx
|
||||||
typ = commonType(c, typ, xx.typ)
|
typ = commonType(c, typ, xx.typ)
|
||||||
#n[i] = semExprWithType(c, x, {})
|
#n[i] = semExprWithType(c, x, {})
|
||||||
|
|
@ -853,10 +871,10 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||||
#if result != n:
|
#if result != n:
|
||||||
# echo "SUCCESS evaluated at compile time: ", call.renderTree
|
# 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
|
inc c.inStaticContext
|
||||||
openScope(c)
|
openScope(c)
|
||||||
let a = semExprWithType(c, n)
|
let a = semExprWithType(c, n, expectedType = expectedType)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
dec c.inStaticContext
|
dec c.inStaticContext
|
||||||
if a.findUnresolvedStatic != nil: return a
|
if a.findUnresolvedStatic != nil: return a
|
||||||
|
|
@ -900,7 +918,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||||
rawAddSon(typ, result.typ)
|
rawAddSon(typ, result.typ)
|
||||||
result.typ = 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;
|
proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
|
||||||
t: PType): TCandidate =
|
t: PType): TCandidate =
|
||||||
|
|
@ -923,15 +941,15 @@ proc setGenericParams(c: PContext, n: PNode) =
|
||||||
for i in 1..<n.len:
|
for i in 1..<n.len:
|
||||||
n[i].typ = semTypeNode(c, n[i], nil)
|
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:
|
if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError:
|
||||||
return errorNode(c, n)
|
return errorNode(c, n)
|
||||||
|
|
||||||
result = n
|
result = n
|
||||||
let callee = result[0].sym
|
let callee = result[0].sym
|
||||||
case callee.kind
|
case callee.kind
|
||||||
of skMacro: result = semMacroExpr(c, result, orig, callee, flags)
|
of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType)
|
||||||
of skTemplate: result = semTemplateExpr(c, result, callee, flags)
|
of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType)
|
||||||
else:
|
else:
|
||||||
semFinishOperands(c, result)
|
semFinishOperands(c, result)
|
||||||
activate(c, result)
|
activate(c, result)
|
||||||
|
|
@ -947,7 +965,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||||
if c.matchedConcept == nil:
|
if c.matchedConcept == nil:
|
||||||
result = evalAtCompileTime(c, result)
|
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
|
result = nil
|
||||||
checkMinSonsLen(n, 1, c.config)
|
checkMinSonsLen(n, 1, c.config)
|
||||||
var prc = n[0]
|
var prc = n[0]
|
||||||
|
|
@ -972,13 +990,17 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
let s = bracketedMacro(n[0])
|
let s = bracketedMacro(n[0])
|
||||||
if s != nil:
|
if s != nil:
|
||||||
setGenericParams(c, n[0])
|
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
|
var t: PType = nil
|
||||||
if n[0].typ != nil:
|
if n[0].typ != nil:
|
||||||
t = skipTypes(n[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct})
|
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:
|
if t != nil and t.kind == tyProc:
|
||||||
# This is a proc variable, apply normal overload resolution
|
# This is a proc variable, apply normal overload resolution
|
||||||
let m = resolveIndirectCall(c, n, nOrig, t)
|
let m = resolveIndirectCall(c, n, nOrig, t)
|
||||||
|
|
@ -1017,9 +1039,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = m.call
|
result = m.call
|
||||||
instGenericConvertersSons(c, result, m)
|
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:
|
else:
|
||||||
result = overloadedCallOpr(c, n)
|
result = overloadedCallOpr(c, n)
|
||||||
# Now that nkSym does not imply an iteration over the proc/iterator space,
|
# 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
|
return result
|
||||||
#result = afterCallActions(c, result, nOrig, flags)
|
#result = afterCallActions(c, result, nOrig, flags)
|
||||||
if result[0].kind == nkSym:
|
if result[0].kind == nkSym:
|
||||||
result = afterCallActions(c, result, nOrig, flags)
|
result = afterCallActions(c, result, nOrig, flags, expectedType)
|
||||||
else:
|
else:
|
||||||
fixAbstractType(c, result)
|
fixAbstractType(c, result)
|
||||||
analyseIfAddressTakenInCall(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!
|
# this seems to be a hotspot in the compiler!
|
||||||
let nOrig = n.copyTree
|
let nOrig = n.copyTree
|
||||||
#semLazyOpAux(c, n)
|
#semLazyOpAux(c, n)
|
||||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
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)
|
else: result = errorNode(c, n)
|
||||||
|
|
||||||
proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -1594,11 +1613,11 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
else:
|
else:
|
||||||
discard
|
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)
|
result = semSubscript(c, n, flags)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
# overloaded [] operator:
|
# 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 =
|
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
|
||||||
var id = considerQuotedIdent(c, a[1], a)
|
var id = considerQuotedIdent(c, a[1], a)
|
||||||
|
|
@ -1774,7 +1793,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||||
renderTree(a, {renderNoComments}))
|
renderTree(a, {renderNoComments}))
|
||||||
else:
|
else:
|
||||||
let lhs = n[0]
|
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:
|
if lhs.kind == nkSym and lhs.sym.kind == skResult:
|
||||||
n.typ = c.enforceVoidContext
|
n.typ = c.enforceVoidContext
|
||||||
if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
|
if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
|
||||||
|
|
@ -1823,9 +1842,9 @@ proc semReturn(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
localError(c.config, n.info, "'return' not allowed here")
|
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)
|
openScope(c)
|
||||||
result = semExpr(c, n)
|
result = semExpr(c, n, expectedType = expectedType)
|
||||||
if c.p.resultSym != nil and not isEmptyType(result.typ):
|
if c.p.resultSym != nil and not isEmptyType(result.typ):
|
||||||
if result.kind == nkNilLit:
|
if result.kind == nkNilLit:
|
||||||
# or ImplicitlyDiscardable(result):
|
# or ImplicitlyDiscardable(result):
|
||||||
|
|
@ -2256,7 +2275,7 @@ proc semSizeof(c: PContext, n: PNode): PNode =
|
||||||
n.typ = getSysType(c.graph, n.info, tyInt)
|
n.typ = getSysType(c.graph, n.info, tyInt)
|
||||||
result = foldSizeOf(c.config, n, n)
|
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!
|
# this is a hotspot in the compiler!
|
||||||
result = n
|
result = n
|
||||||
case s.magic # magics that need special treatment
|
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:
|
of mSizeOf:
|
||||||
markUsed(c, n.info, s)
|
markUsed(c, n.info, s)
|
||||||
result = semSizeof(c, setMs(n, 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:
|
else:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags, expectedType)
|
||||||
|
|
||||||
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||||
# If semCheck is set to false, ``when`` will return the verbatim AST of
|
# 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)
|
result = newNodeI(nkEmpty, n.info)
|
||||||
if whenNimvm: result.typ = typ
|
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 = newNodeI(nkCurly, n.info)
|
||||||
result.typ = newTypeS(tySet, c)
|
result.typ = newTypeS(tySet, c)
|
||||||
result.typ.flags.incl tfIsConstructor
|
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:
|
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:
|
else:
|
||||||
# only semantic checking for all elements, later type checking:
|
# only semantic checking for all elements, later type checking:
|
||||||
var typ: PType = nil
|
var typ: PType = nil
|
||||||
for i in 0..<n.len:
|
for i in 0..<n.len:
|
||||||
if isRange(n[i]):
|
if isRange(n[i]):
|
||||||
checkSonsLen(n[i], 3, c.config)
|
checkSonsLen(n[i], 3, c.config)
|
||||||
n[i][1] = semExprWithType(c, n[i][1])
|
n[i][1] = semExprWithType(c, n[i][1], {}, expectedElementType)
|
||||||
n[i][2] = semExprWithType(c, n[i][2])
|
n[i][2] = semExprWithType(c, n[i][2], {}, expectedElementType)
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
typ = skipTypes(n[i][1].typ,
|
typ = skipTypes(n[i][1].typ,
|
||||||
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||||
|
if expectedElementType == nil:
|
||||||
|
expectedElementType = typ
|
||||||
n[i].typ = n[i][2].typ # range node needs type too
|
n[i].typ = n[i][2].typ # range node needs type too
|
||||||
elif n[i].kind == nkRange:
|
elif n[i].kind == nkRange:
|
||||||
# already semchecked
|
# already semchecked
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
typ = skipTypes(n[i][0].typ,
|
typ = skipTypes(n[i][0].typ,
|
||||||
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||||
|
if expectedElementType == nil:
|
||||||
|
expectedElementType = typ
|
||||||
else:
|
else:
|
||||||
n[i] = semExprWithType(c, n[i])
|
n[i] = semExprWithType(c, n[i], {}, expectedElementType)
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
typ = skipTypes(n[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
typ = skipTypes(n[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||||
|
if expectedElementType == nil:
|
||||||
|
expectedElementType = typ
|
||||||
if not isOrdinalType(typ, allowEnumWithHoles=true):
|
if not isOrdinalType(typ, allowEnumWithHoles=true):
|
||||||
localError(c.config, n.info, errOrdinalTypeExpected)
|
localError(c.config, n.info, errOrdinalTypeExpected)
|
||||||
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
|
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)
|
m = fitNode(c, typ, n[i], info)
|
||||||
result.add m
|
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
|
# we simply transform ``{key: value, key2, key3: value}`` to
|
||||||
# ``[(key, value), (key2, value2), (key3, value2)]``
|
# ``[(key, value), (key2, value2), (key3, value2)]``
|
||||||
result = newNodeI(nkBracket, n.info)
|
result = newNodeI(nkBracket, n.info)
|
||||||
|
|
@ -2499,7 +2543,7 @@ proc semTableConstr(c: PContext, n: PNode): PNode =
|
||||||
lastKey = i+1
|
lastKey = i+1
|
||||||
|
|
||||||
if lastKey != n.len: illFormedAst(n, c.config)
|
if lastKey != n.len: illFormedAst(n, c.config)
|
||||||
result = semExpr(c, result)
|
result = semExpr(c, result, expectedType = expectedType)
|
||||||
|
|
||||||
type
|
type
|
||||||
TParKind = enum
|
TParKind = enum
|
||||||
|
|
@ -2526,8 +2570,13 @@ proc checkPar(c: PContext; n: PNode): TParKind =
|
||||||
localError(c.config, n[i].info, errNamedExprNotAllowed)
|
localError(c.config, n[i].info, errNamedExprNotAllowed)
|
||||||
return paNone
|
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)
|
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)
|
var typ = newTypeS(tyTuple, c)
|
||||||
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
|
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
|
||||||
var ids = initIntSet()
|
var ids = initIntSet()
|
||||||
|
|
@ -2537,7 +2586,9 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
let id = considerQuotedIdent(c, n[i][0])
|
let id = considerQuotedIdent(c, n[i][0])
|
||||||
if containsOrIncl(ids, id.id):
|
if containsOrIncl(ids, id.id):
|
||||||
localError(c.config, n[i].info, errFieldInitTwice % id.s)
|
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:
|
if n[i][1].typ.kind == tyTypeDesc:
|
||||||
localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
|
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.add n[i]
|
||||||
result.typ = typ
|
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 = n # we don't modify n, but compute the type:
|
||||||
result.transitionSonsKind(nkTupleConstr)
|
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!
|
var typ = newTypeS(tyTuple, c) # leave typ.n nil!
|
||||||
for i in 0..<n.len:
|
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)
|
addSonSkipIntLit(typ, n[i].typ, c.idgen)
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
include semobjconstr
|
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
|
result = n
|
||||||
inc(c.p.nestedBlockCounter)
|
inc(c.p.nestedBlockCounter)
|
||||||
checkSonsLen(n, 2, c.config)
|
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)
|
suggestSym(c.graph, n[0].info, labl, c.graph.usageSym)
|
||||||
styleCheckDef(c, labl)
|
styleCheckDef(c, labl)
|
||||||
onDef(n[0].info, 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
|
n.typ = n[1].typ
|
||||||
if isEmptyType(n.typ): n.transitionSonsKind(nkBlockStmt)
|
if isEmptyType(n.typ): n.transitionSonsKind(nkBlockStmt)
|
||||||
else: n.transitionSonsKind(nkBlockExpr)
|
else: n.transitionSonsKind(nkBlockExpr)
|
||||||
|
|
@ -2644,8 +2701,8 @@ proc semExport(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
s = nextOverloadIter(o, c, a)
|
s = nextOverloadIter(o, c, a)
|
||||||
|
|
||||||
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
|
||||||
var tupexp = semTuplePositionsConstr(c, n, flags)
|
var tupexp = semTuplePositionsConstr(c, n, flags, expectedType)
|
||||||
var isTupleType: bool
|
var isTupleType: bool
|
||||||
if tupexp.len > 0: # don't interpret () as type
|
if tupexp.len > 0: # don't interpret () as type
|
||||||
isTupleType = tupexp[0].typ.kind == tyTypeDesc
|
isTupleType = tupexp[0].typ.kind == tyTypeDesc
|
||||||
|
|
@ -2770,7 +2827,7 @@ proc semPragmaStmt(c: PContext; n: PNode) =
|
||||||
else:
|
else:
|
||||||
pragma(c, c.p.owner, n, stmtPragmas, true)
|
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):
|
when defined(nimCompilerStacktraceHints):
|
||||||
setFrameMsg c.config$n.info & " " & $n.kind
|
setFrameMsg c.config$n.info & " " & $n.kind
|
||||||
when false: # see `tdebugutils`
|
when false: # see `tdebugutils`
|
||||||
|
|
@ -2780,18 +2837,38 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
if isCompilerDebug():
|
if isCompilerDebug():
|
||||||
echo ("<", c.config$n.info, n, ?.result.typ)
|
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
|
result = n
|
||||||
if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
|
if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
|
||||||
if nfSem in n.flags: return
|
if nfSem in n.flags: return
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkIdent, nkAccQuoted:
|
of nkIdent, nkAccQuoted:
|
||||||
|
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:
|
let checks = if efNoEvaluateGeneric in flags:
|
||||||
{checkUndeclared, checkPureEnumFields}
|
{checkUndeclared, checkPureEnumFields}
|
||||||
elif efInCall in flags:
|
elif efInCall in flags:
|
||||||
{checkUndeclared, checkModule, checkPureEnumFields}
|
{checkUndeclared, checkModule, checkPureEnumFields}
|
||||||
else:
|
else:
|
||||||
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
|
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
|
||||||
var s = qualifiedLookUp(c, n, checks)
|
s = qualifiedLookUp(c, n, checks)
|
||||||
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
|
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
|
||||||
case s.kind
|
case s.kind
|
||||||
of skProc, skFunc, skMethod, skConverter, skIterator:
|
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)
|
result = semSym(c, n, s, flags)
|
||||||
else:
|
else:
|
||||||
result = semSym(c, n, s, flags)
|
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:
|
of nkSym:
|
||||||
# because of the changed symbol binding, this does not mean that we
|
# because of the changed symbol binding, this does not mean that we
|
||||||
# don't have to check the symbol for semantics here again!
|
# 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:
|
of nkEmpty, nkNone, nkCommentStmt, nkType:
|
||||||
discard
|
discard
|
||||||
of nkNilLit:
|
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:
|
of nkIntLit:
|
||||||
if result.typ == nil: setIntLitType(c, result)
|
if result.typ == nil:
|
||||||
of nkInt8Lit:
|
if expectedType != nil and (
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt8)
|
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
|
||||||
of nkInt16Lit:
|
expected.kind in {tyInt..tyInt64,
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt16)
|
tyUInt..tyUInt64,
|
||||||
of nkInt32Lit:
|
tyFloat..tyFloat128}):
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt32)
|
result.typ = expected
|
||||||
of nkInt64Lit:
|
if expected.kind in {tyFloat..tyFloat128}:
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt64)
|
n.transitionIntToFloatKind(nkFloatLit)
|
||||||
of nkUIntLit:
|
changeType(c, result, expectedType, check=true)
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt)
|
else:
|
||||||
of nkUInt8Lit:
|
setIntLitType(c, result)
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt8)
|
of nkInt8Lit: directLiteral(tyInt8)
|
||||||
of nkUInt16Lit:
|
of nkInt16Lit: directLiteral(tyInt16)
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt16)
|
of nkInt32Lit: directLiteral(tyInt32)
|
||||||
of nkUInt32Lit:
|
of nkInt64Lit: directLiteral(tyInt64)
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt32)
|
of nkUIntLit: directLiteral(tyUInt)
|
||||||
of nkUInt64Lit:
|
of nkUInt8Lit: directLiteral(tyUInt8)
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt64)
|
of nkUInt16Lit: directLiteral(tyUInt16)
|
||||||
#of nkFloatLit:
|
of nkUInt32Lit: directLiteral(tyUInt32)
|
||||||
# if result.typ == nil: result.typ = getFloatLitType(result)
|
of nkUInt64Lit: directLiteral(tyUInt64)
|
||||||
of nkFloat32Lit:
|
of nkFloatLit:
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat32)
|
if result.typ == nil:
|
||||||
of nkFloat64Lit, nkFloatLit:
|
if expectedType != nil and (
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat64)
|
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
|
||||||
of nkFloat128Lit:
|
expected.kind in {tyFloat..tyFloat128}):
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, 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:
|
of nkStrLit..nkTripleStrLit:
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyString)
|
if result.typ == nil:
|
||||||
of nkCharLit:
|
if expectedType != nil and (
|
||||||
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyChar)
|
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:
|
of nkDotExpr:
|
||||||
result = semFieldAccess(c, n, flags)
|
result = semFieldAccess(c, n, flags)
|
||||||
if result.kind == nkDotCall:
|
if result.kind == nkDotCall:
|
||||||
|
|
@ -2858,7 +2956,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = semExpr(c, result, flags)
|
result = semExpr(c, result, flags)
|
||||||
of nkBind:
|
of nkBind:
|
||||||
message(c.config, n.info, warnDeprecated, "bind is deprecated")
|
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:
|
of nkTypeOfExpr..nkTupleClassTy, nkStaticTy, nkRefTy..nkEnumTy:
|
||||||
if c.matchedConcept != nil and n.len == 1:
|
if c.matchedConcept != nil and n.len == 1:
|
||||||
let modifier = n.modifierTypeKindOfNode
|
let modifier = n.modifierTypeKindOfNode
|
||||||
|
|
@ -2884,40 +2982,40 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
# pretty.checkUse(n[0][1].info, s)
|
# pretty.checkUse(n[0][1].info, s)
|
||||||
case s.kind
|
case s.kind
|
||||||
of skMacro, skTemplate:
|
of skMacro, skTemplate:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags, expectedType)
|
||||||
of skType:
|
of skType:
|
||||||
# XXX think about this more (``set`` procs)
|
# XXX think about this more (``set`` procs)
|
||||||
let ambig = c.isAmbiguous
|
let ambig = c.isAmbiguous
|
||||||
if not (n[0].kind in {nkClosedSymChoice, nkOpenSymChoice, nkIdent} and ambig) and n.len == 2:
|
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:
|
elif ambig and n.len == 1:
|
||||||
errorUseQualifier(c, n.info, s)
|
errorUseQualifier(c, n.info, s)
|
||||||
elif n.len == 1:
|
elif n.len == 1:
|
||||||
result = semObjConstr(c, n, flags)
|
result = semObjConstr(c, n, flags, expectedType)
|
||||||
elif s.magic == mNone: result = semDirectOp(c, n, flags)
|
elif s.magic == mNone: result = semDirectOp(c, n, flags, expectedType)
|
||||||
else: result = semMagic(c, n, s, flags)
|
else: result = semMagic(c, n, s, flags, expectedType)
|
||||||
of skProc, skFunc, skMethod, skConverter, skIterator:
|
of skProc, skFunc, skMethod, skConverter, skIterator:
|
||||||
if s.magic == mNone: result = semDirectOp(c, n, flags)
|
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:
|
else:
|
||||||
#liMessage(n.info, warnUser, renderTree(n));
|
#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
|
elif (n[0].kind == nkBracketExpr or shouldBeBracketExpr(n)) and
|
||||||
isSymChoice(n[0][0]):
|
isSymChoice(n[0][0]):
|
||||||
# indirectOp can deal with explicit instantiations; the fixes
|
# indirectOp can deal with explicit instantiations; the fixes
|
||||||
# the 'newSeq[T](x)' bug
|
# the 'newSeq[T](x)' bug
|
||||||
setGenericParams(c, n[0])
|
setGenericParams(c, n[0])
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags, expectedType)
|
||||||
elif nfDotField in n.flags:
|
elif nfDotField in n.flags:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags, expectedType)
|
||||||
elif isSymChoice(n[0]):
|
elif isSymChoice(n[0]):
|
||||||
let b = asBracketExpr(c, n)
|
let b = asBracketExpr(c, n)
|
||||||
if b != nil:
|
if b != nil:
|
||||||
result = semExpr(c, b, flags)
|
result = semExpr(c, b, flags, expectedType)
|
||||||
else:
|
else:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags, expectedType)
|
||||||
else:
|
else:
|
||||||
result = semIndirectOp(c, n, flags)
|
result = semIndirectOp(c, n, flags, expectedType)
|
||||||
|
|
||||||
if nfDefaultRefsParam in result.flags:
|
if nfDefaultRefsParam in result.flags:
|
||||||
result = result.copyTree #XXX: Figure out what causes default param nodes to be shared.. (sigmatch bug?)
|
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.
|
# This is a "when nimvm" stmt.
|
||||||
result = semWhen(c, n, true)
|
result = semWhen(c, n, true)
|
||||||
else:
|
else:
|
||||||
result = semExpr(c, result, flags)
|
result = semExpr(c, result, flags, expectedType)
|
||||||
of nkBracketExpr:
|
of nkBracketExpr:
|
||||||
checkMinSonsLen(n, 1, c.config)
|
checkMinSonsLen(n, 1, c.config)
|
||||||
result = semArrayAccess(c, n, flags)
|
result = semArrayAccess(c, n, flags, expectedType)
|
||||||
of nkCurlyExpr:
|
of nkCurlyExpr:
|
||||||
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "{}")), flags)
|
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "{}")), flags, expectedType)
|
||||||
of nkPragmaExpr:
|
of nkPragmaExpr:
|
||||||
var
|
var
|
||||||
pragma = n[1]
|
pragma = n[1]
|
||||||
|
|
@ -2963,12 +3061,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkPar, nkTupleConstr:
|
of nkPar, nkTupleConstr:
|
||||||
case checkPar(c, n)
|
case checkPar(c, n)
|
||||||
of paNone: result = errorNode(c, n)
|
of paNone: result = errorNode(c, n)
|
||||||
of paTuplePositions: result = semTupleConstr(c, n, flags)
|
of paTuplePositions: result = semTupleConstr(c, n, flags, expectedType)
|
||||||
of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
|
of paTupleFields: result = semTupleFieldsConstr(c, n, flags, expectedType)
|
||||||
of paSingle: result = semExpr(c, n[0], flags)
|
of paSingle: result = semExpr(c, n[0], flags, expectedType)
|
||||||
of nkCurly: result = semSetConstr(c, n)
|
of nkCurly: result = semSetConstr(c, n, expectedType)
|
||||||
of nkBracket: result = semArrayConstr(c, n, flags)
|
of nkBracket: result = semArrayConstr(c, n, flags, expectedType)
|
||||||
of nkObjConstr: result = semObjConstr(c, n, flags)
|
of nkObjConstr: result = semObjConstr(c, n, flags, expectedType)
|
||||||
of nkLambdaKinds: result = semProcAux(c, n, skProc, lambdaPragmas, flags)
|
of nkLambdaKinds: result = semProcAux(c, n, skProc, lambdaPragmas, flags)
|
||||||
of nkDerefExpr: result = semDeref(c, n)
|
of nkDerefExpr: result = semDeref(c, n)
|
||||||
of nkAddr:
|
of nkAddr:
|
||||||
|
|
@ -2978,9 +3076,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result.typ = makePtrType(c, result[0].typ)
|
result.typ = makePtrType(c, result[0].typ)
|
||||||
of nkHiddenAddr, nkHiddenDeref:
|
of nkHiddenAddr, nkHiddenDeref:
|
||||||
checkSonsLen(n, 1, c.config)
|
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 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:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
|
||||||
checkSonsLen(n, 2, c.config)
|
checkSonsLen(n, 2, c.config)
|
||||||
considerGenSyms(c, n)
|
considerGenSyms(c, n)
|
||||||
|
|
@ -2994,15 +3092,15 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
checkMinSonsLen(n, 2, c.config)
|
checkMinSonsLen(n, 2, c.config)
|
||||||
considerGenSyms(c, n)
|
considerGenSyms(c, n)
|
||||||
of nkTableConstr:
|
of nkTableConstr:
|
||||||
result = semTableConstr(c, n)
|
result = semTableConstr(c, n, expectedType)
|
||||||
of nkClosedSymChoice, nkOpenSymChoice:
|
of nkClosedSymChoice, nkOpenSymChoice:
|
||||||
# handling of sym choices is context dependent
|
# handling of sym choices is context dependent
|
||||||
# the node is left intact for now
|
# the node is left intact for now
|
||||||
discard
|
discard
|
||||||
of nkStaticExpr: result = semStaticExpr(c, n[0])
|
of nkStaticExpr: result = semStaticExpr(c, n[0], expectedType)
|
||||||
of nkAsgn: result = semAsgn(c, n)
|
of nkAsgn: result = semAsgn(c, n)
|
||||||
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags)
|
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags, expectedType)
|
||||||
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
|
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags, expectedType)
|
||||||
of nkRaiseStmt: result = semRaise(c, n)
|
of nkRaiseStmt: result = semRaise(c, n)
|
||||||
of nkVarSection: result = semVarOrLet(c, n, skVar)
|
of nkVarSection: result = semVarOrLet(c, n, skVar)
|
||||||
of nkLetSection: result = semVarOrLet(c, n, skLet)
|
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 nkTypeSection: result = semTypeSection(c, n)
|
||||||
of nkDiscardStmt: result = semDiscard(c, n)
|
of nkDiscardStmt: result = semDiscard(c, n)
|
||||||
of nkWhileStmt: result = semWhile(c, n, flags)
|
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 nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
|
||||||
of nkForStmt, nkParForStmt: result = semFor(c, n, flags)
|
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 nkReturnStmt: result = semReturn(c, n)
|
||||||
of nkUsingStmt: result = semUsing(c, n)
|
of nkUsingStmt: result = semUsing(c, n)
|
||||||
of nkAsmStmt: result = semAsm(c, n)
|
of nkAsmStmt: result = semAsm(c, n)
|
||||||
|
|
@ -3052,7 +3150,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
|
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
|
||||||
result = semExportExcept(c, n)
|
result = semExportExcept(c, n)
|
||||||
of nkPragmaBlock:
|
of nkPragmaBlock:
|
||||||
result = semPragmaBlock(c, n)
|
result = semPragmaBlock(c, n, expectedType)
|
||||||
of nkStaticStmt:
|
of nkStaticStmt:
|
||||||
result = semStaticStmt(c, n)
|
result = semStaticStmt(c, n)
|
||||||
of nkDefer:
|
of nkDefer:
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ proc semConstrField(c: PContext, flags: TExprFlags,
|
||||||
"the field '$1' is not accessible." % [field.name.s])
|
"the field '$1' is not accessible." % [field.name.s])
|
||||||
return
|
return
|
||||||
|
|
||||||
var initValue = semExprFlagDispatched(c, assignment[1], flags)
|
var initValue = semExprFlagDispatched(c, assignment[1], flags, field.typ)
|
||||||
if initValue != nil:
|
if initValue != nil:
|
||||||
initValue = fitNodeConsiderViewType(c, field.typ, initValue, assignment.info)
|
initValue = fitNodeConsiderViewType(c, field.typ, initValue, assignment.info)
|
||||||
assignment[0] = newSymNode(field)
|
assignment[0] = newSymNode(field)
|
||||||
|
|
@ -375,7 +375,7 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
|
||||||
else:
|
else:
|
||||||
assert false, "Must not enter here."
|
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)
|
var t = semTypeNode(c, n[0], nil)
|
||||||
result = newNodeIT(nkObjConstr, n.info, t)
|
result = newNodeIT(nkObjConstr, n.info, t)
|
||||||
for child in n: result.add child
|
for child in n: result.add child
|
||||||
|
|
@ -383,6 +383,12 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if t == nil:
|
if t == nil:
|
||||||
return localErrorNode(c, result, "object constructor needs an object type")
|
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})
|
t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned})
|
||||||
if t.kind == tyRef:
|
if t.kind == tyRef:
|
||||||
t = skipTypes(t[0], {tyGenericInst, tyAlias, tySink, tyOwned})
|
t = skipTypes(t[0], {tyGenericInst, tyAlias, tySink, tyOwned})
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 2, c.config)
|
checkSonsLen(n, 2, c.config)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
n[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)
|
inc(c.p.nestedLoopCounter)
|
||||||
n[1] = semStmt(c, n[1], flags)
|
n[1] = semStmt(c, n[1], flags)
|
||||||
dec(c.p.nestedLoopCounter)
|
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 semProc(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}): PNode =
|
proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}; expectedType: PType = nil): PNode =
|
||||||
result = semExpr(c, n, flags)
|
result = semExpr(c, n, flags, expectedType)
|
||||||
if result.typ != nil:
|
if result.typ != nil:
|
||||||
# XXX tyGenericInst here?
|
# XXX tyGenericInst here?
|
||||||
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
||||||
|
|
||||||
proc semExprBranchScope(c: PContext, n: PNode): PNode =
|
proc semExprBranchScope(c: PContext, n: PNode; expectedType: PType = nil): PNode =
|
||||||
openScope(c)
|
openScope(c)
|
||||||
result = semExprBranch(c, n)
|
result = semExprBranch(c, n, expectedType = expectedType)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -152,22 +152,25 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
|
||||||
s.add "; for a function call use ()"
|
s.add "; for a function call use ()"
|
||||||
localError(c.config, n.info, s)
|
localError(c.config, n.info, s)
|
||||||
|
|
||||||
proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
proc semIf(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
|
||||||
result = n
|
result = n
|
||||||
var typ = commonTypeBegin
|
var typ = commonTypeBegin
|
||||||
|
var expectedType = expectedType
|
||||||
var hasElse = false
|
var hasElse = false
|
||||||
for i in 0..<n.len:
|
for i in 0..<n.len:
|
||||||
var it = n[i]
|
var it = n[i]
|
||||||
if it.len == 2:
|
if it.len == 2:
|
||||||
openScope(c)
|
openScope(c)
|
||||||
it[0] = forceBool(c, semExprWithType(c, it[0]))
|
it[0] = forceBool(c, semExprWithType(c, it[0], expectedType = getSysType(c.graph, n.info, tyBool)))
|
||||||
it[1] = semExprBranch(c, it[1], flags)
|
it[1] = semExprBranch(c, it[1], flags, expectedType)
|
||||||
typ = commonType(c, typ, it[1])
|
typ = commonType(c, typ, it[1])
|
||||||
|
expectedType = typ
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
elif it.len == 1:
|
elif it.len == 1:
|
||||||
hasElse = true
|
hasElse = true
|
||||||
it[0] = semExprBranchScope(c, it[0])
|
it[0] = semExprBranchScope(c, it[0], expectedType)
|
||||||
typ = commonType(c, typ, it[0])
|
typ = commonType(c, typ, it[0])
|
||||||
|
expectedType = typ
|
||||||
else: illFormedAst(it, c.config)
|
else: illFormedAst(it, c.config)
|
||||||
if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped} or
|
if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped} or
|
||||||
(not hasElse and efInTypeof notin flags):
|
(not hasElse and efInTypeof notin flags):
|
||||||
|
|
@ -183,7 +186,7 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
result.transitionSonsKind(nkIfExpr)
|
result.transitionSonsKind(nkIfExpr)
|
||||||
result.typ = typ
|
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()
|
var check = initIntSet()
|
||||||
template semExceptBranchType(typeNode: PNode): bool =
|
template semExceptBranchType(typeNode: PNode): bool =
|
||||||
# returns true if exception type is imported type
|
# returns true if exception type is imported type
|
||||||
|
|
@ -203,8 +206,10 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
checkMinSonsLen(n, 2, c.config)
|
checkMinSonsLen(n, 2, c.config)
|
||||||
|
|
||||||
var typ = commonTypeBegin
|
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)
|
typ = commonType(c, typ, n[0].typ)
|
||||||
|
expectedType = typ
|
||||||
|
|
||||||
var last = n.len - 1
|
var last = n.len - 1
|
||||||
var catchAllExcepts = 0
|
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")
|
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:
|
# last child of an nkExcept/nkFinally branch is a statement:
|
||||||
|
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])
|
a[^1] = semExprBranchScope(c, a[^1])
|
||||||
if a.kind != nkFinally: typ = commonType(c, typ, a[^1])
|
dec last
|
||||||
else: dec last
|
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped}:
|
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
|
var def: PNode = c.graph.emptyNode
|
||||||
if a[^1].kind != nkEmpty:
|
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:
|
if def.kind in nkSymChoices and def[0].typ.skipTypes(abstractInst).kind == tyEnum:
|
||||||
errorSymChoiceUseQualifier(c, def)
|
errorSymChoiceUseQualifier(c, def)
|
||||||
|
|
@ -753,7 +762,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
var typFlags: TTypeAllowedFlags
|
var typFlags: TTypeAllowedFlags
|
||||||
|
|
||||||
# don't evaluate here since the type compatibility check below may add a converter
|
# 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}:
|
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
|
||||||
typFlags.incl taIsTemplateOrMacro
|
typFlags.incl taIsTemplateOrMacro
|
||||||
|
|
@ -1039,7 +1048,7 @@ proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
result.typ = result.lastSon.typ
|
result.typ = result.lastSon.typ
|
||||||
closeScope(c)
|
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
|
result = n
|
||||||
checkMinSonsLen(n, 2, c.config)
|
checkMinSonsLen(n, 2, c.config)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -1048,6 +1057,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
var chckCovered = false
|
var chckCovered = false
|
||||||
var covered: Int128 = toInt128(0)
|
var covered: Int128 = toInt128(0)
|
||||||
var typ = commonTypeBegin
|
var typ = commonTypeBegin
|
||||||
|
var expectedType = expectedType
|
||||||
var hasElse = false
|
var hasElse = false
|
||||||
let caseTyp = skipTypes(n[0].typ, abstractVar-{tyTypeDesc})
|
let caseTyp = skipTypes(n[0].typ, abstractVar-{tyTypeDesc})
|
||||||
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool}
|
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)
|
checkMinSonsLen(x, 2, c.config)
|
||||||
semCaseBranch(c, n, x, i, covered)
|
semCaseBranch(c, n, x, i, covered)
|
||||||
var last = x.len-1
|
var last = x.len-1
|
||||||
x[last] = semExprBranchScope(c, x[last])
|
x[last] = semExprBranchScope(c, x[last], expectedType)
|
||||||
typ = commonType(c, typ, x[last])
|
typ = commonType(c, typ, x[last])
|
||||||
|
expectedType = typ
|
||||||
of nkElifBranch:
|
of nkElifBranch:
|
||||||
chckCovered = false
|
chckCovered = false
|
||||||
checkSonsLen(x, 2, c.config)
|
checkSonsLen(x, 2, c.config)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
x[0] = forceBool(c, semExprWithType(c, x[0]))
|
x[0] = forceBool(c, semExprWithType(c, x[0], expectedType = getSysType(c.graph, n.info, tyBool)))
|
||||||
x[1] = semExprBranch(c, x[1])
|
x[1] = semExprBranch(c, x[1], expectedType = expectedType)
|
||||||
typ = commonType(c, typ, x[1])
|
typ = commonType(c, typ, x[1])
|
||||||
|
expectedType = typ
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
of nkElse:
|
of nkElse:
|
||||||
checkSonsLen(x, 1, c.config)
|
checkSonsLen(x, 1, c.config)
|
||||||
x[0] = semExprBranchScope(c, x[0])
|
x[0] = semExprBranchScope(c, x[0], expectedType)
|
||||||
typ = commonType(c, typ, x[0])
|
typ = commonType(c, typ, x[0])
|
||||||
|
expectedType = typ
|
||||||
if (chckCovered and covered == toCover(c, n[0].typ)) or hasElse:
|
if (chckCovered and covered == toCover(c, n[0].typ)) or hasElse:
|
||||||
message(c.config, x.info, warnUnreachableElse)
|
message(c.config, x.info, warnUnreachableElse)
|
||||||
hasElse = true
|
hasElse = true
|
||||||
|
|
@ -1678,7 +1691,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} =
|
||||||
addParams(c, params, skProc)
|
addParams(c, params, skProc)
|
||||||
pushProcCon(c, s)
|
pushProcCon(c, s)
|
||||||
addResult(c, n, n.typ[0], skProc)
|
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])
|
trackProc(c, s, s.ast[bodyPos])
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
popOwner(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.
|
# allowed, everything else, including a nullary generic is an error.
|
||||||
pushProcCon(c, s)
|
pushProcCon(c, s)
|
||||||
addResult(c, n, s.typ[0], skProc)
|
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])
|
trackProc(c, s, s.ast[bodyPos])
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
elif efOperand notin flags:
|
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)
|
if s.kind notin {skMacro, skTemplate} and s.magic == mNone: paramsTypeCheck(c, s.typ)
|
||||||
|
|
||||||
maybeAddResult(c, s, n)
|
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
|
# 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'
|
# unfortunately we cannot skip this step when in 'system.compiles'
|
||||||
# context as it may even be evaluated in 'system.compiles':
|
# context as it may even be evaluated in 'system.compiles':
|
||||||
trackProc(c, s, s.ast[bodyPos])
|
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)
|
for i in 0..<n.safeLen: setLine(n[i], info)
|
||||||
n.info = 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)
|
checkSonsLen(n, 2, c.config)
|
||||||
let pragmaList = n[0]
|
let pragmaList = n[0]
|
||||||
pragma(c, nil, pragmaList, exprPragmas, isStatement = true)
|
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)
|
localError(c.config, p.info, "invalid pragma block: " & $p)
|
||||||
|
|
||||||
inc c.inUncheckedAssignSection, inUncheckedAssignSection
|
inc c.inUncheckedAssignSection, inUncheckedAssignSection
|
||||||
n[1] = semExpr(c, n[1])
|
n[1] = semExpr(c, n[1], expectedType = expectedType)
|
||||||
dec c.inUncheckedAssignSection, inUncheckedAssignSection
|
dec c.inUncheckedAssignSection, inUncheckedAssignSection
|
||||||
result = n
|
result = n
|
||||||
result.typ = n[1].typ
|
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])
|
"attempt to equate '%s' and '%s'." % [inferred.renderTree, $res.typ, $typ.base])
|
||||||
typ.n = res
|
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 = n
|
||||||
result.transitionSonsKind(nkStmtList)
|
result.transitionSonsKind(nkStmtList)
|
||||||
var voidContext = false
|
var voidContext = false
|
||||||
|
|
@ -2370,7 +2390,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# nkNilLit, nkEmpty}:
|
# nkNilLit, nkEmpty}:
|
||||||
# dec last
|
# dec last
|
||||||
for i in 0..<n.len:
|
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
|
n[i] = x
|
||||||
if c.matchedConcept != nil and x.typ != nil and
|
if c.matchedConcept != nil and x.typ != nil and
|
||||||
(nfFromTemplate notin n.flags or i != last):
|
(nfFromTemplate notin n.flags or i != last):
|
||||||
|
|
|
||||||
|
|
@ -454,9 +454,9 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||||
setSize typ, 1
|
setSize typ, 1
|
||||||
of tyInt16, tyUInt16:
|
of tyInt16, tyUInt16:
|
||||||
setSize typ, 2
|
setSize typ, 2
|
||||||
of tyInt32, tyUInt32:
|
of tyInt32, tyUInt32, tyFloat32:
|
||||||
setSize typ, 4
|
setSize typ, 4
|
||||||
of tyInt64, tyUInt64:
|
of tyInt64, tyUInt64, tyFloat64, tyFloat:
|
||||||
setSize typ, 8
|
setSize typ, 8
|
||||||
else:
|
else:
|
||||||
typ.size = szUnknownSize
|
typ.size = szUnknownSize
|
||||||
|
|
|
||||||
|
|
@ -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)'
|
# 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'
|
# there is a connection betwen 'src' and 'dest' so that mutations to 'src'
|
||||||
# also reflect 'dest':
|
# 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:
|
for i in 1..<n.len:
|
||||||
# we always have to assume a 'select(...)' like mechanism.
|
# we always have to assume a 'select(...)' like mechanism.
|
||||||
# But at least we do filter out simple POD types from the
|
# But at least we do filter out simple POD types from the
|
||||||
|
|
|
||||||
|
|
@ -1026,7 +1026,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||||
c.genAsgnPatch(n[1], d)
|
c.genAsgnPatch(n[1], d)
|
||||||
c.freeTemp(d)
|
c.freeTemp(d)
|
||||||
of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest)
|
of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest)
|
||||||
of mIsolate, mFinished:
|
of generatedMagics:
|
||||||
genCall(c, n, dest)
|
genCall(c, n, dest)
|
||||||
of mNew, mNewFinalize:
|
of mNew, mNewFinalize:
|
||||||
unused(c, n, dest)
|
unused(c, n, dest)
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,64 @@ ambiguous, a static error will be produced.
|
||||||
p value2
|
p value2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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])
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Package level objects
|
Package level objects
|
||||||
=====================
|
=====================
|
||||||
|
|
|
||||||
|
|
@ -791,7 +791,7 @@ template toSeq1(s: not iterator): untyped =
|
||||||
i += 1
|
i += 1
|
||||||
result
|
result
|
||||||
else:
|
else:
|
||||||
var result: seq[OutType] = @[]
|
var result: seq[OutType]# = @[]
|
||||||
for it in s:
|
for it in s:
|
||||||
result.add(it)
|
result.add(it)
|
||||||
result
|
result
|
||||||
|
|
@ -808,7 +808,7 @@ template toSeq2(iter: iterator): untyped =
|
||||||
result
|
result
|
||||||
else:
|
else:
|
||||||
type OutType = typeof(iter2())
|
type OutType = typeof(iter2())
|
||||||
var result: seq[OutType] = @[]
|
var result: seq[OutType]# = @[]
|
||||||
when compiles(iter2()):
|
when compiles(iter2()):
|
||||||
evalOnceAs(iter4, iter, false)
|
evalOnceAs(iter4, iter, false)
|
||||||
let iter3 = iter4()
|
let iter3 = iter4()
|
||||||
|
|
@ -852,7 +852,7 @@ template toSeq*(iter: untyped): untyped =
|
||||||
inc i
|
inc i
|
||||||
result
|
result
|
||||||
else:
|
else:
|
||||||
var result: seq[typeof(iter)] = @[]
|
var result: seq[typeof(iter)]# = @[]
|
||||||
for x in iter:
|
for x in iter:
|
||||||
result.add(x)
|
result.add(x)
|
||||||
result
|
result
|
||||||
|
|
@ -1020,7 +1020,7 @@ template mapIt*(s: typed, op: untyped): untyped =
|
||||||
i += 1
|
i += 1
|
||||||
result
|
result
|
||||||
else:
|
else:
|
||||||
var result: seq[OutType] = @[]
|
var result: seq[OutType]# = @[]
|
||||||
# use `items` to avoid https://github.com/nim-lang/Nim/issues/12639
|
# use `items` to avoid https://github.com/nim-lang/Nim/issues/12639
|
||||||
for it {.inject.} in items(s):
|
for it {.inject.} in items(s):
|
||||||
result.add(op)
|
result.add(op)
|
||||||
|
|
|
||||||
|
|
@ -1614,7 +1614,17 @@ proc isNil*[T: proc](x: T): bool {.noSideEffect, magic: "IsNil".}
|
||||||
## `== nil`.
|
## `== nil`.
|
||||||
|
|
||||||
|
|
||||||
proc `@`*[T](a: openArray[T]): seq[T] =
|
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.
|
## Turns an *openArray* into a sequence.
|
||||||
##
|
##
|
||||||
## This is not as efficient as turning a fixed length array into a sequence
|
## This is not as efficient as turning a fixed length array into a sequence
|
||||||
|
|
|
||||||
|
|
@ -453,8 +453,8 @@ block:
|
||||||
for i in 0..<len:
|
for i in 0..<len:
|
||||||
yield i
|
yield i
|
||||||
|
|
||||||
when not defined(js):
|
|
||||||
# xxx: obscure CT error: basic_types.nim(16, 16) Error: internal error: symbol has no generated name: true
|
# xxx: obscure CT error: basic_types.nim(16, 16) Error: internal error: symbol has no generated name: true
|
||||||
|
when not defined(js):
|
||||||
doAssert: iter(3).mapIt(2*it).foldl(a + b) == 6
|
doAssert: iter(3).mapIt(2*it).foldl(a + b) == 6
|
||||||
|
|
||||||
block: # strictFuncs tests with ref object
|
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")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue