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