mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-28 09:31:38 +00:00
type constraints; tuple lifting
This commit is contained in:
@@ -237,7 +237,7 @@ type
|
||||
tyGenericParam, # ``a`` in the example
|
||||
tyDistinct,
|
||||
tyEnum,
|
||||
tyOrdinal,
|
||||
tyOrdinal, # misnamed: should become 'tyConstraint'
|
||||
tyArray,
|
||||
tyObject,
|
||||
tyTuple,
|
||||
@@ -329,7 +329,9 @@ type
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mConTArr, mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mConTArr, mConTT, mSlice,
|
||||
mFields, mFieldPairs,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert,
|
||||
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mReset,
|
||||
mArray, mOpenArray, mRange, mSet, mSeq,
|
||||
|
||||
@@ -1014,12 +1014,77 @@ proc parseAsm(p: var TParser): PNode =
|
||||
return
|
||||
getTok(p)
|
||||
|
||||
proc parseGenericConstraint(p: var TParser): PNode =
|
||||
case p.tok.tokType
|
||||
of tkObject:
|
||||
result = newNodeP(nkObjectTy, p)
|
||||
getTok(p)
|
||||
of tkTuple:
|
||||
result = newNodeP(nkTupleTy, p)
|
||||
getTok(p)
|
||||
of tkEnum:
|
||||
result = newNodeP(nkEnumTy, p)
|
||||
getTok(p)
|
||||
of tkProc:
|
||||
result = newNodeP(nkProcTy, p)
|
||||
getTok(p)
|
||||
of tkVar:
|
||||
result = newNodeP(nkVarTy, p)
|
||||
getTok(p)
|
||||
of tkPtr:
|
||||
result = newNodeP(nkPtrTy, p)
|
||||
getTok(p)
|
||||
of tkRef:
|
||||
result = newNodeP(nkRefTy, p)
|
||||
getTok(p)
|
||||
of tkDistinct:
|
||||
result = newNodeP(nkDistinctTy, p)
|
||||
getTok(p)
|
||||
else: result = primary(p)
|
||||
|
||||
proc parseGenericConstraintList(p: var TParser): PNode =
|
||||
result = parseGenericConstraint(p)
|
||||
while p.tok.tokType == tkOpr:
|
||||
var a = result
|
||||
result = newNodeP(nkInfix, p)
|
||||
addSon(result, newIdentNodeP(p.tok.ident, p))
|
||||
addSon(result, a)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
addSon(result, parseGenericConstraint(p))
|
||||
|
||||
proc parseGenericParam(p: var TParser): PNode =
|
||||
var a: PNode
|
||||
result = newNodeP(nkIdentDefs, p)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
of tkSymbol, tkAccent:
|
||||
a = parseSymbol(p)
|
||||
if a.kind == nkEmpty: return
|
||||
else: break
|
||||
addSon(result, a)
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, a)
|
||||
if p.tok.tokType == tkColon:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
addSon(result, parseGenericConstraintList(p))
|
||||
else:
|
||||
addSon(result, ast.emptyNode)
|
||||
if p.tok.tokType == tkEquals:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
addSon(result, parseExpr(p))
|
||||
else:
|
||||
addSon(result, ast.emptyNode)
|
||||
|
||||
proc parseGenericParamList(p: var TParser): PNode =
|
||||
result = newNodeP(nkGenericParams, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent):
|
||||
var a = parseIdentColonEquals(p, {withBothOptional})
|
||||
var a = parseGenericParam(p)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -839,17 +839,29 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
putWithSpace(g, tkType, "type")
|
||||
gsub(g, n.sons[0])
|
||||
of nkRefTy:
|
||||
putWithSpace(g, tkRef, "ref")
|
||||
gsub(g, n.sons[0])
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkRef, "ref")
|
||||
gsub(g, n.sons[0])
|
||||
else:
|
||||
put(g, tkRef, "ref")
|
||||
of nkPtrTy:
|
||||
putWithSpace(g, tkPtr, "ptr")
|
||||
gsub(g, n.sons[0])
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkPtr, "ptr")
|
||||
gsub(g, n.sons[0])
|
||||
else:
|
||||
put(g, tkPtr, "ptr")
|
||||
of nkVarTy:
|
||||
putWithSpace(g, tkVar, "var")
|
||||
gsub(g, n.sons[0])
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkVar, "var")
|
||||
gsub(g, n.sons[0])
|
||||
else:
|
||||
put(g, tkVar, "var")
|
||||
of nkDistinctTy:
|
||||
putWithSpace(g, tkDistinct, "distinct")
|
||||
gsub(g, n.sons[0])
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkDistinct, "distinct")
|
||||
gsub(g, n.sons[0])
|
||||
else:
|
||||
put(g, tkDistinct, "distinct")
|
||||
of nkTypeDef:
|
||||
gsub(g, n.sons[0])
|
||||
gsub(g, n.sons[1])
|
||||
@@ -858,11 +870,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
putWithSpace(g, tkEquals, "=")
|
||||
gsub(g, n.sons[2])
|
||||
of nkObjectTy:
|
||||
putWithSpace(g, tkObject, "object")
|
||||
gsub(g, n.sons[0])
|
||||
gsub(g, n.sons[1])
|
||||
gcoms(g)
|
||||
gsub(g, n.sons[2])
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkObject, "object")
|
||||
gsub(g, n.sons[0])
|
||||
gsub(g, n.sons[1])
|
||||
gcoms(g)
|
||||
gsub(g, n.sons[2])
|
||||
else:
|
||||
put(g, tkObject, "object")
|
||||
of nkRecList:
|
||||
indentNL(g)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
@@ -875,17 +890,23 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
putWithSpace(g, tkOf, "of")
|
||||
gsub(g, n.sons[0])
|
||||
of nkProcTy:
|
||||
putWithSpace(g, tkProc, "proc")
|
||||
gsub(g, n.sons[0])
|
||||
gsub(g, n.sons[1])
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkProc, "proc")
|
||||
gsub(g, n.sons[0])
|
||||
gsub(g, n.sons[1])
|
||||
else:
|
||||
put(g, tkProc, "proc")
|
||||
of nkEnumTy:
|
||||
putWithSpace(g, tkEnum, "enum")
|
||||
gsub(g, n.sons[0])
|
||||
gcoms(g)
|
||||
indentNL(g)
|
||||
gcommaAux(g, n, g.indent, 1)
|
||||
gcoms(g) # BUGFIX: comment for the last enum field
|
||||
dedent(g)
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkEnum, "enum")
|
||||
gsub(g, n.sons[0])
|
||||
gcoms(g)
|
||||
indentNL(g)
|
||||
gcommaAux(g, n, g.indent, 1)
|
||||
gcoms(g) # BUGFIX: comment for the last enum field
|
||||
dedent(g)
|
||||
else:
|
||||
put(g, tkEnum, "enum")
|
||||
of nkEnumFieldDef:
|
||||
gsub(g, n.sons[0])
|
||||
put(g, tkSpaces, Space)
|
||||
@@ -1033,9 +1054,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
gsub(g, n.sons[0])
|
||||
of nkTupleTy:
|
||||
put(g, tkTuple, "tuple")
|
||||
put(g, tkBracketLe, "[")
|
||||
gcomma(g, n)
|
||||
put(g, tkBracketRi, "]")
|
||||
if sonsLen(n) > 0:
|
||||
put(g, tkBracketLe, "[")
|
||||
gcomma(g, n)
|
||||
put(g, tkBracketRi, "]")
|
||||
else:
|
||||
#nkNone, nkMetaNode, nkTableConstr, nkExplicitTypeListCall:
|
||||
InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
|
||||
|
||||
@@ -118,7 +118,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
c.p = oldP # restore
|
||||
c.module = oldMod
|
||||
dec(c.InstCounter)
|
||||
|
||||
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||
var cl: TReplTypeVars
|
||||
InitIdTable(cl.symMap)
|
||||
|
||||
171
rod/semstmts.nim
171
rod/semstmts.nim
@@ -358,49 +358,120 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||
addSon(b, copyTree(def))
|
||||
addSon(result, b)
|
||||
|
||||
proc transfFieldLoopBody(n: PNode, forLoop: PNode,
|
||||
tupleType: PType,
|
||||
tupleIndex, first: int): PNode =
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
|
||||
of nkIdent:
|
||||
result = n
|
||||
var L = sonsLen(forLoop)
|
||||
# field name:
|
||||
if first > 0:
|
||||
if n.ident.id == forLoop[0].ident.id:
|
||||
if tupleType.n == nil:
|
||||
# ugh, there are no field names:
|
||||
result = newStrNode(nkStrLit, "")
|
||||
else:
|
||||
result = newStrNode(nkStrLit, tupleType.n.sons[tupleIndex].sym.name.s)
|
||||
return
|
||||
# other fields:
|
||||
for i in first..L-3:
|
||||
if n.ident.id == forLoop[i].ident.id:
|
||||
var call = forLoop.sons[L-2]
|
||||
var tupl = call.sons[i+1-first]
|
||||
result = newNodeI(nkBracketExpr, n.info)
|
||||
result.add(tupl)
|
||||
result.add(newIntNode(nkIntLit, tupleIndex))
|
||||
break
|
||||
else:
|
||||
result = copyNode(n)
|
||||
newSons(result, sonsLen(n))
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
result.sons[i] = transfFieldLoopBody(n.sons[i], forLoop,
|
||||
tupleType, tupleIndex, first)
|
||||
|
||||
proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
# so that 'break' etc. work as expected, we produce
|
||||
# a 'while true: stmt; break' loop ...
|
||||
result = newNodeI(nkWhileStmt, n.info)
|
||||
var trueSymbol = StrTableGet(magicsys.systemModule.Tab, getIdent"true")
|
||||
if trueSymbol == nil: GlobalError(n.info, errSystemNeeds, "true")
|
||||
|
||||
result.add(newSymNode(trueSymbol, n.info))
|
||||
var stmts = newNodeI(nkStmtList, n.info)
|
||||
result.add(stmts)
|
||||
|
||||
var length = sonsLen(n)
|
||||
var call = n.sons[length-2]
|
||||
if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
|
||||
GlobalError(n.info, errWrongNumberOfVariables)
|
||||
|
||||
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar)
|
||||
if tupleTypeA.kind != tyTuple: InternalError(n.info, "no tuple type!")
|
||||
for i in 1..call.len-1:
|
||||
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar)
|
||||
if not SameType(tupleTypeA, tupleTypeB):
|
||||
typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
|
||||
|
||||
Inc(c.p.nestedLoopCounter)
|
||||
var loopBody = n.sons[length-1]
|
||||
for i in 0..sonsLen(tupleTypeA)-1:
|
||||
openScope(c.tab)
|
||||
var body = transfFieldLoopBody(loopBody, n, tupleTypeA, i,
|
||||
ord(m==mFieldPairs))
|
||||
stmts.add(SemStmt(c, body))
|
||||
closeScope(c.tab)
|
||||
Dec(c.p.nestedLoopCounter)
|
||||
var b = newNodeI(nkBreakStmt, n.info)
|
||||
b.add(ast.emptyNode)
|
||||
stmts.add(b)
|
||||
|
||||
proc createCountupNode(c: PContext, rangeNode: PNode): PNode =
|
||||
# convert ``in 3..5`` to ``in countup(3, 5)``
|
||||
checkSonsLen(rangeNode, 2)
|
||||
result = newNodeI(nkCall, rangeNode.info)
|
||||
var countUp = StrTableGet(magicsys.systemModule.Tab, getIdent"countup")
|
||||
if countUp == nil: GlobalError(rangeNode.info, errSystemNeeds, "countup")
|
||||
newSons(result, 3)
|
||||
result.sons[0] = newSymNode(countup)
|
||||
result.sons[1] = rangeNode.sons[0]
|
||||
result.sons[2] = rangeNode.sons[1]
|
||||
|
||||
proc semFor(c: PContext, n: PNode): PNode =
|
||||
var
|
||||
v, countup: PSym
|
||||
iter: PType
|
||||
countupNode, call: PNode
|
||||
result = n
|
||||
checkMinSonsLen(n, 3)
|
||||
var length = sonsLen(n)
|
||||
openScope(c.tab)
|
||||
if n.sons[length - 2].kind == nkRange:
|
||||
checkSonsLen(n.sons[length - 2], 2)
|
||||
# convert ``in 3..5`` to ``in countup(3, 5)``
|
||||
countupNode = newNodeI(nkCall, n.sons[length - 2].info)
|
||||
countUp = StrTableGet(magicsys.systemModule.Tab, getIdent("countup"))
|
||||
if countUp == nil: GlobalError(countupNode.info, errSystemNeeds, "countup")
|
||||
newSons(countupNode, 3)
|
||||
countupnode.sons[0] = newSymNode(countup)
|
||||
countupNode.sons[1] = n.sons[length - 2].sons[0]
|
||||
countupNode.sons[2] = n.sons[length - 2].sons[1]
|
||||
n.sons[length - 2] = countupNode
|
||||
n.sons[length - 2] = semExprWithType(c, n.sons[length - 2], {efWantIterator})
|
||||
call = n.sons[length - 2]
|
||||
if (call.kind != nkCall) or (call.sons[0].kind != nkSym) or
|
||||
(call.sons[0].sym.kind != skIterator):
|
||||
if n.sons[length-2].kind == nkRange:
|
||||
n.sons[length-2] = createCountupNode(c, n.sons[length-2])
|
||||
n.sons[length-2] = semExprWithType(c, n.sons[length-2], {efWantIterator})
|
||||
var call = n.sons[length-2]
|
||||
if call.kind != nkCall or call.sons[0].kind != nkSym or
|
||||
call.sons[0].sym.kind != skIterator:
|
||||
GlobalError(n.sons[length - 2].info, errIteratorExpected)
|
||||
iter = skipTypes(n.sons[length - 2].typ, {tyGenericInst})
|
||||
if iter.kind != tyTuple:
|
||||
if length != 3: GlobalError(n.info, errWrongNumberOfVariables)
|
||||
v = newSymS(skForVar, n.sons[0], c)
|
||||
v.typ = iter
|
||||
n.sons[0] = newSymNode(v)
|
||||
addDecl(c, v)
|
||||
else:
|
||||
if length-2 != sonsLen(iter): GlobalError(n.info, errWrongNumberOfVariables)
|
||||
for i in countup(0, length - 3):
|
||||
v = newSymS(skForVar, n.sons[i], c)
|
||||
v.typ = iter.sons[i]
|
||||
n.sons[i] = newSymNode(v)
|
||||
elif call.sons[0].sym.magic != mNone:
|
||||
result = semForFields(c, n, call.sons[0].sym.magic)
|
||||
else:
|
||||
var iter = skipTypes(n.sons[length-2].typ, {tyGenericInst})
|
||||
if iter.kind != tyTuple:
|
||||
if length != 3: GlobalError(n.info, errWrongNumberOfVariables)
|
||||
var v = newSymS(skForVar, n.sons[0], c)
|
||||
v.typ = iter
|
||||
n.sons[0] = newSymNode(v)
|
||||
addDecl(c, v)
|
||||
Inc(c.p.nestedLoopCounter)
|
||||
n.sons[length - 1] = SemStmt(c, n.sons[length - 1])
|
||||
else:
|
||||
if length-2 != sonsLen(iter):
|
||||
GlobalError(n.info, errWrongNumberOfVariables)
|
||||
for i in countup(0, length - 3):
|
||||
var v = newSymS(skForVar, n.sons[i], c)
|
||||
v.typ = iter.sons[i]
|
||||
n.sons[i] = newSymNode(v)
|
||||
addDecl(c, v)
|
||||
Inc(c.p.nestedLoopCounter)
|
||||
n.sons[length-1] = SemStmt(c, n.sons[length-1])
|
||||
Dec(c.p.nestedLoopCounter)
|
||||
closeScope(c.tab)
|
||||
Dec(c.p.nestedLoopCounter)
|
||||
|
||||
proc semRaise(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
@@ -436,34 +507,6 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||
# last child of an nkExcept/nkFinally branch is a statement:
|
||||
a.sons[length - 1] = semStmtScope(c, a.sons[length - 1])
|
||||
|
||||
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||
result = copyNode(n)
|
||||
if n.kind != nkGenericParams: InternalError(n.info, "semGenericParamList")
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
var a = n.sons[i]
|
||||
if a.kind != nkIdentDefs: illFormedAst(n)
|
||||
var L = sonsLen(a)
|
||||
var def = a.sons[L-1]
|
||||
var typ: PType
|
||||
if a.sons[L-2].kind != nkEmpty: typ = semTypeNode(c, a.sons[L-2], nil)
|
||||
elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
|
||||
else: typ = nil
|
||||
for j in countup(0, L-3):
|
||||
var s: PSym
|
||||
if (typ == nil) or (typ.kind == tyTypeDesc):
|
||||
s = newSymS(skType, a.sons[j], c)
|
||||
s.typ = newTypeS(tyGenericParam, c)
|
||||
else:
|
||||
# not a type param, but an expression
|
||||
s = newSymS(skGenericParam, a.sons[j], c)
|
||||
s.typ = typ
|
||||
if def.kind != nkEmpty: s.ast = def
|
||||
s.typ.sym = s
|
||||
if father != nil: addSon(father, s.typ)
|
||||
s.position = i
|
||||
addSon(result, newSymNode(s))
|
||||
addDecl(c, s)
|
||||
|
||||
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||
if n.kind != nkGenericParams:
|
||||
InternalError(n.info, "addGenericParamListToScope")
|
||||
@@ -741,7 +784,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
|
||||
var t = s.typ
|
||||
if t.sons[0] == nil:
|
||||
LocalError(n.info, errXNeedsReturnType, "iterator")
|
||||
if n.sons[codePos].kind == nkEmpty:
|
||||
if n.sons[codePos].kind == nkEmpty and s.magic == mNone:
|
||||
LocalError(n.info, errImplOfXexpected, s.name.s)
|
||||
|
||||
proc semProc(c: PContext, n: PNode): PNode =
|
||||
|
||||
@@ -173,12 +173,12 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
|
||||
else:
|
||||
GlobalError(n.info, errXExpectsOneTypeParam, "ordinal")
|
||||
|
||||
proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
|
||||
if (result != nil):
|
||||
if result != nil:
|
||||
markUsed(n, result)
|
||||
if result.kind != skType: GlobalError(n.info, errTypeExpected)
|
||||
else:
|
||||
else:
|
||||
GlobalError(n.info, errIdentifierExpected)
|
||||
|
||||
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
@@ -441,8 +441,6 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
||||
addInheritedFields(c, check, pos, concreteBase)
|
||||
else:
|
||||
debug base
|
||||
debug concreteBase
|
||||
localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
|
||||
if n.kind != nkObjectTy: InternalError(n.info, "semObjectNode")
|
||||
result = newOrPrevType(tyObject, prev, c)
|
||||
@@ -632,10 +630,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
||||
m.typ.kind = kind
|
||||
m.typ.align = size
|
||||
m.typ.size = size #m.typ.sym := nil;
|
||||
m.typ.size = size
|
||||
|
||||
proc processMagicType(c: PContext, m: PSym) =
|
||||
case m.magic #registerSysType(m.typ);
|
||||
case m.magic
|
||||
of mInt: setMagicType(m, tyInt, intSize)
|
||||
of mInt8: setMagicType(m, tyInt8, 1)
|
||||
of mInt16: setMagicType(m, tyInt16, 2)
|
||||
@@ -656,13 +654,70 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||
of mEmptySet:
|
||||
setMagicType(m, tySet, 1)
|
||||
addSon(m.typ, newTypeS(tyEmpty, c))
|
||||
of mIntSetBaseType:
|
||||
setMagicType(m, tyRange, intSize) #intSetBaseType := m.typ;
|
||||
return
|
||||
of mIntSetBaseType: setMagicType(m, tyRange, intSize)
|
||||
of mNil: setMagicType(m, tyNil, ptrSize)
|
||||
of mExpr: setMagicType(m, tyExpr, 0)
|
||||
of mStmt: setMagicType(m, tyStmt, 0)
|
||||
of mTypeDesc: setMagicType(m, tyTypeDesc, 0)
|
||||
of mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal: return
|
||||
of mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal: nil
|
||||
else: GlobalError(m.info, errTypeExpected)
|
||||
|
||||
proc newConstraint(c: PContext, k: TTypeKind): PType =
|
||||
result = newTypeS(tyOrdinal, c)
|
||||
result.addSon(newTypeS(k, c))
|
||||
|
||||
proc semGenericConstraints(c: PContext, n: PNode, result: PType) =
|
||||
case n.kind
|
||||
of nkProcTy: result.addSon(newConstraint(c, tyProc))
|
||||
of nkEnumTy: result.addSon(newConstraint(c, tyEnum))
|
||||
of nkObjectTy: result.addSon(newConstraint(c, tyObject))
|
||||
of nkTupleTy: result.addSon(newConstraint(c, tyTuple))
|
||||
of nkDistinctTy: result.addSon(newConstraint(c, tyDistinct))
|
||||
of nkVarTy: result.addSon(newConstraint(c, tyVar))
|
||||
of nkPtrTy: result.addSon(newConstraint(c, tyPtr))
|
||||
of nkRefTy: result.addSon(newConstraint(c, tyRef))
|
||||
of nkInfix:
|
||||
semGenericConstraints(c, n.sons[1], result)
|
||||
semGenericConstraints(c, n.sons[2], result)
|
||||
else:
|
||||
result.addSon(semTypeNode(c, n, nil))
|
||||
|
||||
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||
result = copyNode(n)
|
||||
if n.kind != nkGenericParams: InternalError(n.info, "semGenericParamList")
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
var a = n.sons[i]
|
||||
if a.kind != nkIdentDefs: illFormedAst(n)
|
||||
var L = sonsLen(a)
|
||||
var def = a.sons[L-1]
|
||||
var typ: PType
|
||||
if a.sons[L-2].kind != nkEmpty:
|
||||
typ = newTypeS(tyGenericParam, c)
|
||||
semGenericConstraints(c, a.sons[L-2], typ)
|
||||
elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
|
||||
else: typ = nil
|
||||
for j in countup(0, L-3):
|
||||
var s: PSym
|
||||
if typ == nil:
|
||||
s = newSymS(skType, a.sons[j], c)
|
||||
s.typ = newTypeS(tyGenericParam, c)
|
||||
else:
|
||||
case typ.kind
|
||||
of tyTypeDesc:
|
||||
s = newSymS(skType, a.sons[j], c)
|
||||
s.typ = newTypeS(tyGenericParam, c)
|
||||
of tyExpr:
|
||||
# not a type param, but an expression
|
||||
s = newSymS(skGenericParam, a.sons[j], c)
|
||||
s.typ = typ
|
||||
else:
|
||||
s = newSymS(skType, a.sons[j], c)
|
||||
s.typ = typ
|
||||
if def.kind != nkEmpty: s.ast = def
|
||||
s.typ.sym = s
|
||||
if father != nil: addSon(father, s.typ)
|
||||
s.position = i
|
||||
addSon(result, newSymNode(s))
|
||||
addDecl(c, s)
|
||||
|
||||
|
||||
|
||||
@@ -32,7 +32,10 @@ type
|
||||
# for example
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
isNone, isConvertible, isIntConv, isSubtype, isGeneric, isEqual
|
||||
isNone, isConvertible, isIntConv, isSubtype,
|
||||
isLifted, # match, but do not change argument type to formal's type!
|
||||
isGeneric,
|
||||
isEqual
|
||||
|
||||
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||
c.exactMatches = 0
|
||||
@@ -144,8 +147,8 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
|
||||
else:
|
||||
var k = skipTypes(a, {tyRange}).kind
|
||||
if k == f.kind: result = isSubtype
|
||||
elif (f.kind == tyInt) and (k in {tyInt..tyInt32}): result = isIntConv
|
||||
elif (k >= min) and (k <= max): result = isConvertible
|
||||
elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv
|
||||
elif k >= min and k <= max: result = isConvertible
|
||||
else: result = isNone
|
||||
|
||||
proc handleFloatRange(f, a: PType): TTypeRelation =
|
||||
@@ -159,7 +162,7 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
|
||||
|
||||
proc isObjectSubtype(a, f: PType): bool =
|
||||
var t = a
|
||||
while (t != nil) and (t.id != f.id): t = base(t)
|
||||
while t != nil and t.id != f.id: t = base(t)
|
||||
result = t != nil
|
||||
|
||||
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
||||
@@ -182,11 +185,15 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
var x = f.n.sons[i].sym
|
||||
var y = a.n.sons[i].sym
|
||||
if x.name.id != y.name.id: return isNone
|
||||
elif sonsLen(f) == 0:
|
||||
idTablePut(mapping, f, a)
|
||||
result = isLifted
|
||||
|
||||
proc constraintRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
result = isNone
|
||||
if f.kind == a.kind: result = isGeneric
|
||||
|
||||
proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
var
|
||||
x, concrete: PType
|
||||
m: TTypeRelation
|
||||
# is a subtype of f?
|
||||
result = isNone
|
||||
assert(f != nil)
|
||||
@@ -272,9 +279,11 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
if result < isGeneric: result = isNone
|
||||
else: nil
|
||||
of tyOrdinal:
|
||||
if isOrdinalType(a):
|
||||
if a.kind == tyOrdinal: x = a.sons[0]
|
||||
else: x = a
|
||||
if f.sons[0].kind != tyGenericParam:
|
||||
# some constraint:
|
||||
result = constraintRel(mapping, f.sons[0], a)
|
||||
elif isOrdinalType(a):
|
||||
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
||||
result = typeRel(mapping, f.sons[0], x)
|
||||
if result < isGeneric: result = isNone
|
||||
of tyForward: InternalError("forward type in typeRel()")
|
||||
@@ -319,6 +328,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
# return type!
|
||||
result = isEqual # start with maximum; also correct for no
|
||||
# params at all
|
||||
var m: TTypeRelation
|
||||
for i in countup(1, sonsLen(f) - 1):
|
||||
m = typeRel(mapping, f.sons[i], a.sons[i])
|
||||
if (m == isNone) and
|
||||
@@ -392,26 +402,25 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
if result != isNone:
|
||||
# we steal the generic parameters from the tyGenericBody:
|
||||
for i in countup(1, sonsLen(f) - 1):
|
||||
x = PType(idTableGet(mapping, f.sons[0].sons[i - 1]))
|
||||
var x = PType(idTableGet(mapping, f.sons[0].sons[i - 1]))
|
||||
if (x == nil) or (x.kind == tyGenericParam):
|
||||
InternalError("wrong instantiated type!")
|
||||
idTablePut(mapping, f.sons[i], x)
|
||||
of tyGenericParam:
|
||||
x = PType(idTableGet(mapping, f))
|
||||
var x = PType(idTableGet(mapping, f))
|
||||
if x == nil:
|
||||
if sonsLen(f) == 0:
|
||||
# no constraints
|
||||
concrete = concreteType(mapping, a)
|
||||
var concrete = concreteType(mapping, a)
|
||||
if concrete != nil:
|
||||
#MessageOut('putting: ' + f.sym.name.s);
|
||||
idTablePut(mapping, f, concrete)
|
||||
result = isGeneric
|
||||
else:
|
||||
InternalError(f.sym.info, "has constraints: " & f.sym.name.s)
|
||||
# check constraints:
|
||||
for i in countup(0, sonsLen(f) - 1):
|
||||
if typeRel(mapping, f.sons[i], a) >= isSubtype:
|
||||
concrete = concreteType(mapping, a)
|
||||
var concrete = concreteType(mapping, a)
|
||||
if concrete != nil:
|
||||
idTablePut(mapping, f, concrete)
|
||||
result = isGeneric
|
||||
@@ -484,6 +493,9 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
||||
of isSubtype:
|
||||
inc(m.subtypeMatches)
|
||||
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
||||
of isLifted:
|
||||
inc(m.genericMatches)
|
||||
result = copyTree(arg)
|
||||
of isGeneric:
|
||||
inc(m.genericMatches)
|
||||
result = copyTree(arg)
|
||||
|
||||
Reference in New Issue
Block a user