first steps for 'not nil' annotation
This commit is contained in:
parent
019d6e4127
commit
ccd2934e4a
7 changed files with 127 additions and 69 deletions
|
|
@ -715,6 +715,8 @@ const
|
||||||
tyFloat..tyFloat128, tyUInt..tyUInt64}
|
tyFloat..tyFloat128, tyUInt..tyUInt64}
|
||||||
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
||||||
tyTuple, tySequence}
|
tyTuple, tySequence}
|
||||||
|
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
|
||||||
|
tyProc, tyString, tyError}
|
||||||
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
|
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
|
||||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
|
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
|
||||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
|
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
|
||||||
|
|
|
||||||
|
|
@ -183,14 +183,15 @@ proc getPrecedence(tok: TToken): int =
|
||||||
of '?': result = 2
|
of '?': result = 2
|
||||||
else: considerAsgn(2)
|
else: considerAsgn(2)
|
||||||
of tkDiv, tkMod, tkShl, tkShr: result = 9
|
of tkDiv, tkMod, tkShl, tkShr: result = 9
|
||||||
of tkIn, tkNotIn, tkIs, tkIsNot, tkNot, tkOf, tkAs: result = 5
|
of tkIn, tkNotIn, tkIs, tkIsNot, tkOf, tkAs: result = 5
|
||||||
of tkDotDot: result = 6
|
of tkDotDot: result = 6
|
||||||
of tkAnd: result = 4
|
of tkAnd: result = 4
|
||||||
of tkOr, tkXor: result = 3
|
of tkOr, tkXor: result = 3
|
||||||
|
of tkNot: result = -2
|
||||||
else: result = - 10
|
else: result = - 10
|
||||||
|
|
||||||
proc isOperator(tok: TToken): bool =
|
proc isOperator(tok: TToken): bool =
|
||||||
result = getPrecedence(tok) >= 0
|
result = getPrecedence(tok) >= -2
|
||||||
|
|
||||||
proc parseSymbol(p: var TParser): PNode =
|
proc parseSymbol(p: var TParser): PNode =
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
|
@ -509,10 +510,13 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||||
result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
|
result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
|
||||||
else: break
|
else: break
|
||||||
|
|
||||||
proc primary(p: var TParser, skipSuffix = false): PNode
|
type
|
||||||
|
TPrimaryMode = enum pmNormal, pmIsType, pmSkipSuffix
|
||||||
|
|
||||||
proc lowestExprAux(p: var TParser, limit: int): PNode =
|
proc primary(p: var TParser, mode: TPrimaryMode): PNode
|
||||||
result = primary(p)
|
|
||||||
|
proc lowestExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
|
||||||
|
result = primary(p, mode)
|
||||||
# expand while operators have priorities higher than 'limit'
|
# expand while operators have priorities higher than 'limit'
|
||||||
var opPrec = getPrecedence(p.tok)
|
var opPrec = getPrecedence(p.tok)
|
||||||
while opPrec >= limit:
|
while opPrec >= limit:
|
||||||
|
|
@ -522,15 +526,15 @@ proc lowestExprAux(p: var TParser, limit: int): PNode =
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, opNode)
|
optInd(p, opNode)
|
||||||
# read sub-expression with higher priority:
|
# read sub-expression with higher priority:
|
||||||
var b = lowestExprAux(p, opPrec + leftAssoc)
|
var b = lowestExprAux(p, opPrec + leftAssoc, mode)
|
||||||
addSon(a, opNode)
|
addSon(a, opNode)
|
||||||
addSon(a, result)
|
addSon(a, result)
|
||||||
addSon(a, b)
|
addSon(a, b)
|
||||||
result = a
|
result = a
|
||||||
opPrec = getPrecedence(p.tok)
|
opPrec = getPrecedence(p.tok)
|
||||||
|
|
||||||
proc lowestExpr(p: var TParser): PNode =
|
proc lowestExpr(p: var TParser, mode = pmNormal): PNode =
|
||||||
result = lowestExprAux(p, -1)
|
result = lowestExprAux(p, -1, mode)
|
||||||
|
|
||||||
proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
|
proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
|
||||||
result = newNodeP(kind, p)
|
result = newNodeP(kind, p)
|
||||||
|
|
@ -738,12 +742,20 @@ proc isExprStart(p: TParser): bool =
|
||||||
result = true
|
result = true
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
||||||
|
when false:
|
||||||
|
proc parseTypeDescNoSuffix(p: var TParser): PNode =
|
||||||
|
if p.tok.toktype == tkProc: result = parseProcExpr(p, false)
|
||||||
|
elif p.tok.toktype == tkIterator:
|
||||||
|
result = parseProcExpr(p, false)
|
||||||
|
result.kind = nkIteratorTy
|
||||||
|
else: result = primary(p)
|
||||||
|
|
||||||
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind): PNode =
|
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind): PNode =
|
||||||
result = newNodeP(kind, p)
|
result = newNodeP(kind, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
if not isOperator(p.tok) and isExprStart(p):
|
if not isOperator(p.tok) and isExprStart(p):
|
||||||
addSon(result, parseTypeDesc(p))
|
addSon(result, primary(p, pmIsType))
|
||||||
|
|
||||||
proc parseExpr(p: var TParser): PNode =
|
proc parseExpr(p: var TParser): PNode =
|
||||||
#
|
#
|
||||||
|
|
@ -759,7 +771,7 @@ proc parseExpr(p: var TParser): PNode =
|
||||||
# XXX needs proper support:
|
# XXX needs proper support:
|
||||||
#of tkTry: result = parseTry(p)
|
#of tkTry: result = parseTry(p)
|
||||||
|
|
||||||
proc primary(p: var TParser, skipSuffix = false): PNode =
|
proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
# prefix operator?
|
# prefix operator?
|
||||||
if isOperator(p.tok):
|
if isOperator(p.tok):
|
||||||
let isSigil = IsSigilLike(p.tok)
|
let isSigil = IsSigilLike(p.tok)
|
||||||
|
|
@ -770,10 +782,10 @@ proc primary(p: var TParser, skipSuffix = false): PNode =
|
||||||
optInd(p, a)
|
optInd(p, a)
|
||||||
if isSigil:
|
if isSigil:
|
||||||
#XXX prefix operators
|
#XXX prefix operators
|
||||||
addSon(result, primary(p, true))
|
addSon(result, primary(p, pmSkipSuffix))
|
||||||
result = primarySuffix(p, result)
|
result = primarySuffix(p, result)
|
||||||
else:
|
else:
|
||||||
addSon(result, primary(p))
|
addSon(result, primary(p, pmNormal))
|
||||||
return
|
return
|
||||||
|
|
||||||
case p.tok.tokType:
|
case p.tok.tokType:
|
||||||
|
|
@ -782,7 +794,16 @@ proc primary(p: var TParser, skipSuffix = false): PNode =
|
||||||
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy)
|
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy)
|
||||||
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr)
|
of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr)
|
||||||
of tkTuple: result = parseTuple(p)
|
of tkTuple: result = parseTuple(p)
|
||||||
of tkProc: result = parseProcExpr(p, true)
|
of tkProc: result = parseProcExpr(p, mode != pmIsType)
|
||||||
|
of tkIterator:
|
||||||
|
if mode == pmIsType:
|
||||||
|
result = parseProcExpr(p, false)
|
||||||
|
result.kind = nkIteratorTy
|
||||||
|
else:
|
||||||
|
# no anon iterators for now:
|
||||||
|
parMessage(p, errExprExpected, p.tok)
|
||||||
|
getTok(p) # we must consume a token here to prevend endless loops!
|
||||||
|
result = ast.emptyNode
|
||||||
of tkEnum:
|
of tkEnum:
|
||||||
result = newNodeP(nkEnumTy, p)
|
result = newNodeP(nkEnumTy, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -795,27 +816,35 @@ proc primary(p: var TParser, skipSuffix = false): PNode =
|
||||||
of tkAddr:
|
of tkAddr:
|
||||||
result = newNodeP(nkAddr, p)
|
result = newNodeP(nkAddr, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
addSon(result, primary(p))
|
addSon(result, primary(p, pmNormal))
|
||||||
of tkStatic:
|
of tkStatic:
|
||||||
result = newNodeP(nkStaticExpr, p)
|
result = newNodeP(nkStaticExpr, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
addSon(result, primary(p))
|
addSon(result, primary(p, pmNormal))
|
||||||
of tkBind:
|
of tkBind:
|
||||||
result = newNodeP(nkBind, p)
|
result = newNodeP(nkBind, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
addSon(result, primary(p))
|
addSon(result, primary(p, pmNormal))
|
||||||
else:
|
else:
|
||||||
result = identOrLiteral(p)
|
result = identOrLiteral(p)
|
||||||
if not skipSuffix:
|
if mode != pmSkipSuffix:
|
||||||
result = primarySuffix(p, result)
|
result = primarySuffix(p, result)
|
||||||
|
|
||||||
proc parseTypeDesc(p: var TParser): PNode =
|
proc parseTypeDesc(p: var TParser): PNode =
|
||||||
if p.tok.toktype == tkProc: result = parseProcExpr(p, false)
|
result = lowestExpr(p, pmIsType)
|
||||||
elif p.tok.toktype == tkIterator:
|
when false:
|
||||||
result = parseProcExpr(p, false)
|
result = parseTypeDescNoSuffix(p)
|
||||||
result.kind = nkIteratorTy
|
# optional 'not nil' suffix?
|
||||||
else: result = parseExpr(p)
|
if p.tok.tokType == tkNot:
|
||||||
|
# we don't call 'getTok' here, so 'parseExpr' includes the 'not' in the
|
||||||
|
# expression; this will yield an nkPrefix AST ;-)
|
||||||
|
let ex = parseExpr(p)
|
||||||
|
let a = newNodeI(nkInfix, result.info, 3)
|
||||||
|
a.sons[0] = ex.sons[0]
|
||||||
|
a.sons[1] = result
|
||||||
|
a.sons[2] = ex.sons[1]
|
||||||
|
result = a
|
||||||
|
|
||||||
proc parseExprStmt(p: var TParser): PNode =
|
proc parseExprStmt(p: var TParser): PNode =
|
||||||
var a = lowestExpr(p)
|
var a = lowestExpr(p)
|
||||||
|
|
|
||||||
|
|
@ -799,16 +799,18 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||||
else:
|
else:
|
||||||
|
# XXX support anon tuple here
|
||||||
LocalError(n.info, errTypeExpected)
|
LocalError(n.info, errTypeExpected)
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
if n[0].kind == nkIdent:
|
if n[0].kind == nkIdent:
|
||||||
let op = n.sons[0].ident
|
let op = n.sons[0].ident
|
||||||
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
|
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
|
||||||
|
checkSonsLen(n, 3)
|
||||||
var
|
var
|
||||||
t1 = semTypeNode(c, n.sons[1], nil)
|
t1 = semTypeNode(c, n.sons[1], nil)
|
||||||
t2 = semTypeNode(c, n.sons[2], nil)
|
t2 = semTypeNode(c, n.sons[2], nil)
|
||||||
if t1 == nil:
|
if t1 == nil:
|
||||||
LocalError(n.sons[1].info, errTypeExpected)
|
LocalError(n.sons[1].info, errTypeExpected)
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
elif t2 == nil:
|
elif t2 == nil:
|
||||||
|
|
@ -819,6 +821,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result.addSonSkipIntLit(t1)
|
result.addSonSkipIntLit(t1)
|
||||||
result.addSonSkipIntLit(t2)
|
result.addSonSkipIntLit(t2)
|
||||||
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
|
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
|
||||||
|
elif op.id == ord(wNot):
|
||||||
|
checkSonsLen(n, 3)
|
||||||
|
result = semTypeNode(c, n.sons[1], prev)
|
||||||
|
if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
|
||||||
|
result.flags.incl(tfNotNil)
|
||||||
|
else:
|
||||||
|
LocalError(n.info, errGenerated, "invalid type")
|
||||||
else:
|
else:
|
||||||
result = semTypeExpr(c, n)
|
result = semTypeExpr(c, n)
|
||||||
else:
|
else:
|
||||||
|
|
@ -883,25 +892,33 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of nkVarTy: result = semVarType(c, n, prev)
|
of nkVarTy: result = semVarType(c, n, prev)
|
||||||
of nkDistinctTy: result = semDistinct(c, n, prev)
|
of nkDistinctTy: result = semDistinct(c, n, prev)
|
||||||
of nkProcTy, nkIteratorTy:
|
of nkProcTy, nkIteratorTy:
|
||||||
if n.sonsLen == 0: return newConstraint(c, tyProc)
|
if n.sonsLen == 0:
|
||||||
checkSonsLen(n, 2)
|
result = newConstraint(c, tyProc)
|
||||||
openScope(c.tab)
|
|
||||||
result = semProcTypeNode(c, n.sons[0], nil, prev, skProc)
|
|
||||||
# dummy symbol for `pragma`:
|
|
||||||
var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c)
|
|
||||||
s.typ = result
|
|
||||||
if n.sons[1].kind == nkEmpty or n.sons[1].len == 0:
|
|
||||||
if result.callConv == ccDefault:
|
|
||||||
result.callConv = ccClosure
|
|
||||||
#Message(n.info, warnImplicitClosure, renderTree(n))
|
|
||||||
else:
|
else:
|
||||||
pragma(c, s, n.sons[1], procTypePragmas)
|
checkSonsLen(n, 2)
|
||||||
when useEffectSystem: SetEffectsForProcType(result, n.sons[1])
|
openScope(c.tab)
|
||||||
closeScope(c.tab)
|
result = semProcTypeNode(c, n.sons[0], nil, prev, skProc)
|
||||||
|
# dummy symbol for `pragma`:
|
||||||
|
var s = newSymS(skProc, newIdentNode(getIdent("dummy"), n.info), c)
|
||||||
|
s.typ = result
|
||||||
|
if n.sons[1].kind == nkEmpty or n.sons[1].len == 0:
|
||||||
|
if result.callConv == ccDefault:
|
||||||
|
result.callConv = ccClosure
|
||||||
|
#Message(n.info, warnImplicitClosure, renderTree(n))
|
||||||
|
else:
|
||||||
|
pragma(c, s, n.sons[1], procTypePragmas)
|
||||||
|
when useEffectSystem: SetEffectsForProcType(result, n.sons[1])
|
||||||
|
closeScope(c.tab)
|
||||||
|
if n.kind == nkIteratorTy:
|
||||||
|
result.flags.incl(tfIterator)
|
||||||
of nkEnumTy: result = semEnum(c, n, prev)
|
of nkEnumTy: result = semEnum(c, n, prev)
|
||||||
of nkType: result = n.typ
|
of nkType: result = n.typ
|
||||||
of nkStmtListType: result = semStmtListType(c, n, prev)
|
of nkStmtListType: result = semStmtListType(c, n, prev)
|
||||||
of nkBlockType: result = semBlockType(c, n, prev)
|
of nkBlockType: result = semBlockType(c, n, prev)
|
||||||
|
of nkSharedTy:
|
||||||
|
checkSonsLen(n, 1)
|
||||||
|
result = semTypeNode(c, n.sons[0], prev)
|
||||||
|
result.flags.incl(tfShared)
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errTypeExpected)
|
LocalError(n.info, errTypeExpected)
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
|
|
|
||||||
|
|
@ -257,12 +257,14 @@ proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
var y = a.n.sons[i].sym
|
var y = a.n.sons[i].sym
|
||||||
if x.name.id != y.name.id: return isNone
|
if x.name.id != y.name.id: return isNone
|
||||||
|
|
||||||
|
proc allowsNil(f: PType): TTypeRelation {.inline.} =
|
||||||
|
result = if tfNotNil notin f.flags: isSubtype else: isNone
|
||||||
|
|
||||||
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
||||||
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
||||||
|
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyNil: result = isSubtype
|
|
||||||
of tyProc:
|
of tyProc:
|
||||||
if sonsLen(f) != sonsLen(a): return
|
if sonsLen(f) != sonsLen(a): return
|
||||||
# Note: We have to do unification for the parameters before the
|
# Note: We have to do unification for the parameters before the
|
||||||
|
|
@ -299,6 +301,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
return isNone
|
return isNone
|
||||||
when useEffectSystem:
|
when useEffectSystem:
|
||||||
if not compatibleEffects(f, a): return isNone
|
if not compatibleEffects(f, a): return isNone
|
||||||
|
of tyNil: result = f.allowsNil
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
|
|
@ -390,14 +393,13 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
else: nil
|
else: nil
|
||||||
of tySequence:
|
of tySequence:
|
||||||
case a.Kind
|
case a.Kind
|
||||||
of tyNil:
|
|
||||||
result = isSubtype
|
|
||||||
of tySequence:
|
of tySequence:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f.sons[0], a.sons[0])
|
result = typeRel(c, f.sons[0], a.sons[0])
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
|
of tyNil: result = f.allowsNil
|
||||||
else: nil
|
else: nil
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if isOrdinalType(a):
|
if isOrdinalType(a):
|
||||||
|
|
@ -432,21 +434,21 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
of tyPtr:
|
of tyPtr:
|
||||||
result = typeRel(c, base(f), base(a))
|
result = typeRel(c, base(f), base(a))
|
||||||
if result <= isConvertible: result = isNone
|
if result <= isConvertible: result = isNone
|
||||||
of tyNil: result = isSubtype
|
of tyNil: result = f.allowsNil
|
||||||
else: nil
|
else: nil
|
||||||
of tyRef:
|
of tyRef:
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyRef:
|
of tyRef:
|
||||||
result = typeRel(c, base(f), base(a))
|
result = typeRel(c, base(f), base(a))
|
||||||
if result <= isConvertible: result = isNone
|
if result <= isConvertible: result = isNone
|
||||||
of tyNil: result = isSubtype
|
of tyNil: result = f.allowsNil
|
||||||
else: nil
|
else: nil
|
||||||
of tyProc:
|
of tyProc:
|
||||||
result = procTypeRel(c, f, a)
|
result = procTypeRel(c, f, a)
|
||||||
of tyPointer:
|
of tyPointer:
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyPointer: result = isEqual
|
of tyPointer: result = isEqual
|
||||||
of tyNil: result = isSubtype
|
of tyNil: result = f.allowsNil
|
||||||
of tyProc:
|
of tyProc:
|
||||||
if a.callConv != ccClosure: result = isConvertible
|
if a.callConv != ccClosure: result = isConvertible
|
||||||
of tyPtr, tyCString: result = isConvertible
|
of tyPtr, tyCString: result = isConvertible
|
||||||
|
|
@ -454,13 +456,13 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
of tyString:
|
of tyString:
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyString: result = isEqual
|
of tyString: result = isEqual
|
||||||
of tyNil: result = isSubtype
|
of tyNil: result = f.allowsNil
|
||||||
else: nil
|
else: nil
|
||||||
of tyCString:
|
of tyCString:
|
||||||
# conversion from string to cstring is automatic:
|
# conversion from string to cstring is automatic:
|
||||||
case a.Kind
|
case a.Kind
|
||||||
of tyCString: result = isEqual
|
of tyCString: result = isEqual
|
||||||
of tyNil: result = isSubtype
|
of tyNil: result = f.allowsNil
|
||||||
of tyString: result = isConvertible
|
of tyString: result = isConvertible
|
||||||
of tyPtr:
|
of tyPtr:
|
||||||
if a.sons[0].kind == tyChar: result = isConvertible
|
if a.sons[0].kind == tyChar: result = isConvertible
|
||||||
|
|
@ -706,8 +708,7 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
z.calleeSym = m.calleeSym
|
z.calleeSym = m.calleeSym
|
||||||
var best = -1
|
var best = -1
|
||||||
for i in countup(0, sonsLen(arg) - 1):
|
for i in countup(0, sonsLen(arg) - 1):
|
||||||
# iterators are not first class yet, so ignore them
|
if arg.sons[i].sym.kind in {skProc, skIterator, skMethod, skConverter}:
|
||||||
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}:
|
|
||||||
copyCandidate(z, m)
|
copyCandidate(z, m)
|
||||||
var r = typeRel(z, f, arg.sons[i].typ)
|
var r = typeRel(z, f, arg.sons[i].typ)
|
||||||
if r != isNone:
|
if r != isNone:
|
||||||
|
|
|
||||||
|
|
@ -791,6 +791,9 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
else:
|
else:
|
||||||
if containsOrIncl(c, a, b): return true
|
if containsOrIncl(c, a, b): return true
|
||||||
|
|
||||||
|
proc sameFlags(a, b: PType): bool {.inline.} =
|
||||||
|
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
|
||||||
|
|
||||||
if x == y: return true
|
if x == y: return true
|
||||||
var a = skipTypes(x, {tyGenericInst})
|
var a = skipTypes(x, {tyGenericInst})
|
||||||
var b = skipTypes(y, {tyGenericInst})
|
var b = skipTypes(y, {tyGenericInst})
|
||||||
|
|
@ -809,36 +812,37 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
case a.Kind
|
case a.Kind
|
||||||
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
||||||
tyInt..tyBigNum, tyStmt:
|
tyInt..tyBigNum, tyStmt:
|
||||||
result = true
|
result = sameFlags(a, b)
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
result = ExprStructuralEquivalent(a.n, b.n)
|
result = ExprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
|
||||||
of tyObject:
|
of tyObject:
|
||||||
IfFastObjectTypeCheckFailed(a, b):
|
IfFastObjectTypeCheckFailed(a, b):
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
result = sameObjectStructures(a, b, c)
|
result = sameObjectStructures(a, b, c) and sameFlags(a, b)
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
if c.cmp == dcEq: result = sameDistinctTypes(a, b)
|
if c.cmp == dcEq: result = sameDistinctTypes(a, b) and sameFlags(a, b)
|
||||||
else: result = sameTypeAux(a.sons[0], b.sons[0], c)
|
else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
|
||||||
of tyEnum, tyForward, tyProxy:
|
of tyEnum, tyForward, tyProxy:
|
||||||
# XXX generic enums do not make much sense, but require structural checking
|
# XXX generic enums do not make much sense, but require structural checking
|
||||||
result = a.id == b.id
|
result = a.id == b.id and sameFlags(a, b)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
result = sameTuple(a, b, c)
|
result = sameTuple(a, b, c) and sameFlags(a, b)
|
||||||
of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c)
|
of tyGenericInst:
|
||||||
|
result = sameTypeAux(lastSon(a), lastSon(b), c)
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
if TypeDescExactMatch in c.flags:
|
if TypeDescExactMatch in c.flags:
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
result = sameChildrenAux(x, y, c)
|
result = sameChildrenAux(x, y, c) and sameFlags(a, b)
|
||||||
else:
|
else:
|
||||||
result = true
|
result = sameFlags(a, b)
|
||||||
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
|
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
|
||||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
||||||
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
||||||
tyOrdinal, tyTypeClass:
|
tyOrdinal, tyTypeClass:
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
result = sameChildrenAux(a, b, c)
|
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
||||||
if result and (a.kind == tyProc):
|
if result and (a.kind == tyProc):
|
||||||
result = a.callConv == b.callConv
|
result = a.callConv == b.callConv
|
||||||
of tyRange:
|
of tyRange:
|
||||||
|
|
|
||||||
|
|
@ -78,9 +78,10 @@ exprList ::= [expr (comma expr)* [comma]]
|
||||||
|
|
||||||
qualifiedIdent ::= symbol ['.' symbol]
|
qualifiedIdent ::= symbol ['.' symbol]
|
||||||
|
|
||||||
typeDesc ::= exprOrType
|
typeDesc ::= (exprOrType
|
||||||
| 'proc' paramList [pragma]
|
| 'proc' paramList [pragma]
|
||||||
| 'iterator' paramList [pragma]
|
| 'iterator' paramList [pragma] )
|
||||||
|
['not' expr] # for now only 'not nil' suffix is supported
|
||||||
|
|
||||||
macroStmt ::= ':' [stmt] ('of' [exprList] ':' stmt
|
macroStmt ::= ':' [stmt] ('of' [exprList] ':' stmt
|
||||||
|'elif' expr ':' stmt
|
|'elif' expr ':' stmt
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,10 @@ Language Additions
|
||||||
exceptions for you.
|
exceptions for you.
|
||||||
- User defined effects ("tags") tracking has been added and the ``doc2``
|
- User defined effects ("tags") tracking has been added and the ``doc2``
|
||||||
command annotates possible tags for you.
|
command annotates possible tags for you.
|
||||||
|
- Types can be annotated with the new syntax ``not nil`` to explictly state
|
||||||
|
that ``nil`` is not allowed. However currently the compiler performs no
|
||||||
|
advanced static checking for this; for now it's merely for documentation
|
||||||
|
purposes.
|
||||||
|
|
||||||
|
|
||||||
2012-09-23 Version 0.9.0 released
|
2012-09-23 Version 0.9.0 released
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue