progress towards adding negative type classes
[unittest bugfixes] the block form of check now allows comments errors when inspecting the arguments of var-accepting procs
This commit is contained in:
parent
208924b929
commit
de3b7cd413
9 changed files with 267 additions and 46 deletions
|
|
@ -335,12 +335,19 @@ type
|
||||||
tyConst, tyMutable, tyVarargs,
|
tyConst, tyMutable, tyVarargs,
|
||||||
tyIter, # unused
|
tyIter, # unused
|
||||||
tyProxy # used as errornous type (for idetools)
|
tyProxy # used as errornous type (for idetools)
|
||||||
tyTypeClass,
|
tyTypeClass
|
||||||
|
tyAnd
|
||||||
|
tyOr
|
||||||
|
tyNot
|
||||||
|
tyAnything
|
||||||
|
tyParametricTypeClass # structured similarly to tyGenericInst
|
||||||
|
# lastSon is the body of the type class
|
||||||
|
|
||||||
const
|
const
|
||||||
tyPureObject* = tyTuple
|
tyPureObject* = tyTuple
|
||||||
GcTypeKinds* = {tyRef, tySequence, tyString}
|
GcTypeKinds* = {tyRef, tySequence, tyString}
|
||||||
tyError* = tyProxy # as an errornous node should match everything
|
tyError* = tyProxy # as an errornous node should match everything
|
||||||
|
tyTypeClasses* = {tyTypeClass, tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
|
||||||
|
|
||||||
type
|
type
|
||||||
TTypeKinds* = set[TTypeKind]
|
TTypeKinds* = set[TTypeKind]
|
||||||
|
|
@ -377,6 +384,7 @@ type
|
||||||
# used as return types for return type inference)
|
# used as return types for return type inference)
|
||||||
tfAll, # type class requires all constraints to be met (default)
|
tfAll, # type class requires all constraints to be met (default)
|
||||||
tfAny, # type class requires any constraint to be met
|
tfAny, # type class requires any constraint to be met
|
||||||
|
tfNot, # type class with a negative check
|
||||||
tfCapturesEnv, # whether proc really captures some environment
|
tfCapturesEnv, # whether proc really captures some environment
|
||||||
tfByCopy, # pass object/tuple by copy (C backend)
|
tfByCopy, # pass object/tuple by copy (C backend)
|
||||||
tfByRef, # pass object/tuple by reference (C backend)
|
tfByRef, # pass object/tuple by reference (C backend)
|
||||||
|
|
@ -1416,3 +1424,4 @@ proc isAtom*(n: PNode): bool {.inline.} =
|
||||||
proc isEmptyType*(t: PType): bool {.inline.} =
|
proc isEmptyType*(t: PType): bool {.inline.} =
|
||||||
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
|
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
|
||||||
result = t == nil or t.kind in {tyEmpty, tyStmt}
|
result = t == nil or t.kind in {tyEmpty, tyStmt}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ proc GetUniqueType*(key: PType): PType =
|
||||||
if result == nil:
|
if result == nil:
|
||||||
gCanonicalTypes[k] = key
|
gCanonicalTypes[k] = key
|
||||||
result = key
|
result = key
|
||||||
of tyTypeDesc, tyTypeClass:
|
of tyTypeDesc, tyTypeClasses:
|
||||||
InternalError("value expected, but got a type")
|
InternalError("value expected, but got a type")
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
InternalError("GetUniqueType")
|
InternalError("GetUniqueType")
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ proc mapType(typ: PType): TJSTypeKind =
|
||||||
result = etyObject
|
result = etyObject
|
||||||
of tyNil: result = etyNull
|
of tyNil: result = etyNull
|
||||||
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone,
|
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone,
|
||||||
tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc, tyTypeClass:
|
tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc, tyTypeClasses:
|
||||||
result = etyNone
|
result = etyNone
|
||||||
of tyProc: result = etyProc
|
of tyProc: result = etyProc
|
||||||
of tyCString: result = etyString
|
of tyCString: result = etyString
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
|
||||||
var match: bool
|
var match: bool
|
||||||
let t2 = n[2].typ
|
let t2 = n[2].typ
|
||||||
case t2.kind
|
case t2.kind
|
||||||
of tyTypeClass:
|
of tyTypeClasses:
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
InitCandidate(m, t2)
|
InitCandidate(m, t2)
|
||||||
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
|
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
if a.kind != nkSym:
|
if a.kind != nkSym:
|
||||||
InternalError(a.info, "instantiateGenericParamList; no symbol")
|
InternalError(a.info, "instantiateGenericParamList; no symbol")
|
||||||
var q = a.sym
|
var q = a.sym
|
||||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass, tyExpr}: continue
|
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyExpr}+tyTypeClasses:
|
||||||
|
continue
|
||||||
var s = newSym(skType, q.name, getCurrOwner(), q.info)
|
var s = newSym(skType, q.name, getCurrOwner(), q.info)
|
||||||
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
||||||
var t = PType(IdTableGet(pt, q.typ))
|
var t = PType(IdTableGet(pt, q.typ))
|
||||||
|
|
@ -193,7 +194,7 @@ proc fixupProcType(c: PContext, genericType: PType,
|
||||||
if result == nil: return
|
if result == nil: return
|
||||||
|
|
||||||
case genericType.kind
|
case genericType.kind
|
||||||
of tyGenericParam, tyTypeClass:
|
of tyGenericParam, tyTypeClasses:
|
||||||
result = inst.concreteTypes[genericType.sym.position]
|
result = inst.concreteTypes[genericType.sym.position]
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
result = inst.concreteTypes[genericType.sym.position]
|
result = inst.concreteTypes[genericType.sym.position]
|
||||||
|
|
|
||||||
|
|
@ -677,7 +677,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
paramType.sons[i] = lifted
|
paramType.sons[i] = lifted
|
||||||
result = paramType
|
result = paramType
|
||||||
|
|
||||||
if result != nil:
|
if paramType.lastSon.kind == tyTypeClass:
|
||||||
|
result = paramType
|
||||||
|
result.kind = tyParametricTypeClass
|
||||||
|
result = addImplicitGeneric(copyType(result,
|
||||||
|
getCurrOwner(), false))
|
||||||
|
elif result != nil:
|
||||||
result.kind = tyGenericInvokation
|
result.kind = tyGenericInvokation
|
||||||
result.sons.setLen(result.sons.len - 1)
|
result.sons.setLen(result.sons.len - 1)
|
||||||
of tyTypeClass:
|
of tyTypeClass:
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
||||||
add(result, argTypeToString(arg))
|
add(result, argTypeToString(arg))
|
||||||
if i != sonsLen(n) - 1: add(result, ", ")
|
if i != sonsLen(n) - 1: add(result, ", ")
|
||||||
|
|
||||||
proc typeRel*(c: var TCandidate, f, a: PType): TTypeRelation
|
proc typeRel*(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation
|
||||||
proc concreteType(c: TCandidate, t: PType): PType =
|
proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyArrayConstr:
|
of tyArrayConstr:
|
||||||
|
|
@ -213,7 +213,7 @@ proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
addSonSkipIntLit(result, t.sons[1]) # XXX: semantic checking for the type?
|
addSonSkipIntLit(result, t.sons[1]) # XXX: semantic checking for the type?
|
||||||
of tyNil:
|
of tyNil:
|
||||||
result = nil # what should it be?
|
result = nil # what should it be?
|
||||||
of tyGenericParam:
|
of tyGenericParam, tyAnything:
|
||||||
result = t
|
result = t
|
||||||
while true:
|
while true:
|
||||||
result = PType(idTableGet(c.bindings, t))
|
result = PType(idTableGet(c.bindings, t))
|
||||||
|
|
@ -385,8 +385,23 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
|
||||||
# is a subtype of f?
|
# typeRel can be used to establish various relationships between types:
|
||||||
|
#
|
||||||
|
# 1) When used with concrete types, it will check for type equivalence
|
||||||
|
# or a subtype relationship.
|
||||||
|
#
|
||||||
|
# 2) When used with a concrete type against a type class (such as generic
|
||||||
|
# signature of a proc), it will check whether the concrete type is a member
|
||||||
|
# of the designated type class.
|
||||||
|
#
|
||||||
|
# 3) When used with two type classes, it will check whether the types
|
||||||
|
# matching the first type class are a strict subset of the types matching
|
||||||
|
# the other. This allows us to compare the signatures of generic procs in
|
||||||
|
# order to give preferrence to the most specific one:
|
||||||
|
#
|
||||||
|
# seq[seq[any]] is a strict subset of seq[any] and hence more specific.
|
||||||
|
|
||||||
result = isNone
|
result = isNone
|
||||||
assert(f != nil)
|
assert(f != nil)
|
||||||
assert(a != nil)
|
assert(a != nil)
|
||||||
|
|
@ -397,6 +412,50 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
return typeRel(c, f, lastSon(a))
|
return typeRel(c, f, lastSon(a))
|
||||||
if a.kind == tyVar and f.kind != tyVar:
|
if a.kind == tyVar and f.kind != tyVar:
|
||||||
return typeRel(c, f, a.sons[0])
|
return typeRel(c, f, a.sons[0])
|
||||||
|
|
||||||
|
template bindingRet(res) =
|
||||||
|
when res == isGeneric: put(c.bindings, f, a)
|
||||||
|
return res
|
||||||
|
|
||||||
|
case a.kind
|
||||||
|
of tyOr:
|
||||||
|
# seq[int|string] vs seq[number]
|
||||||
|
# both int and string must match against number
|
||||||
|
for branch in a.sons:
|
||||||
|
if typeRel(c, f, branch, false) == isNone:
|
||||||
|
return isNone
|
||||||
|
|
||||||
|
return isGeneric
|
||||||
|
|
||||||
|
of tyAnd:
|
||||||
|
# seq[Sortable and Iterable] vs seq[Sortable]
|
||||||
|
# only one match is enough
|
||||||
|
for branch in a.sons:
|
||||||
|
if typeRel(c, f, branch, false) != isNone:
|
||||||
|
return isGeneric
|
||||||
|
|
||||||
|
return isNone
|
||||||
|
|
||||||
|
of tyNot:
|
||||||
|
case f.kind
|
||||||
|
of tyNot:
|
||||||
|
# seq[!int] vs seq[!number]
|
||||||
|
# seq[float] matches the first, but not the second
|
||||||
|
# we must turn the problem around:
|
||||||
|
# is number a subset of int?
|
||||||
|
return typeRel(c, a.lastSon, f.lastSon)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# negative type classes are essentially infinite,
|
||||||
|
# so only the `any` type class is their superset
|
||||||
|
return if f.kind == tyAnything: isGeneric
|
||||||
|
else: isNone
|
||||||
|
|
||||||
|
of tyAnything:
|
||||||
|
return if f.kind == tyAnything: isGeneric
|
||||||
|
else: isNone
|
||||||
|
else: nil
|
||||||
|
|
||||||
case f.kind
|
case f.kind
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual
|
if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual
|
||||||
|
|
@ -486,6 +545,9 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
if isOrdinalType(a):
|
if isOrdinalType(a):
|
||||||
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
||||||
|
|
||||||
|
if f.sonsLen == 0:
|
||||||
|
result = isGeneric
|
||||||
|
else:
|
||||||
result = typeRel(c, f.sons[0], x)
|
result = typeRel(c, f.sons[0], x)
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
elif a.kind == tyGenericParam:
|
elif a.kind == tyGenericParam:
|
||||||
|
|
@ -574,13 +636,17 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
(a.sons[1].kind == tyChar):
|
(a.sons[1].kind == tyChar):
|
||||||
result = isConvertible
|
result = isConvertible
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
of tyEmpty:
|
of tyEmpty:
|
||||||
if a.kind == tyEmpty: result = isEqual
|
if a.kind == tyEmpty: result = isEqual
|
||||||
|
|
||||||
of tyGenericInst:
|
of tyGenericInst:
|
||||||
result = typeRel(c, lastSon(f), a)
|
result = typeRel(c, lastSon(f), a)
|
||||||
|
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
let ff = lastSon(f)
|
let ff = lastSon(f)
|
||||||
if ff != nil: result = typeRel(c, ff, a)
|
if ff != nil: result = typeRel(c, ff, a)
|
||||||
|
|
||||||
of tyGenericInvokation:
|
of tyGenericInvokation:
|
||||||
var x = a.skipGenericAlias
|
var x = a.skipGenericAlias
|
||||||
if x.kind == tyGenericInvokation or f.sons[0].kind != tyGenericBody:
|
if x.kind == tyGenericInvokation or f.sons[0].kind != tyGenericBody:
|
||||||
|
|
@ -604,6 +670,38 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
|
if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
|
||||||
InternalError("wrong instantiated type!")
|
InternalError("wrong instantiated type!")
|
||||||
put(c.bindings, f.sons[i], x)
|
put(c.bindings, f.sons[i], x)
|
||||||
|
|
||||||
|
of tyAnd:
|
||||||
|
for branch in f.sons:
|
||||||
|
if typeRel(c, branch, a) == isNone:
|
||||||
|
return isNone
|
||||||
|
|
||||||
|
bindingRet isGeneric
|
||||||
|
|
||||||
|
of tyOr:
|
||||||
|
for branch in f.sons:
|
||||||
|
if typeRel(c, branch, a) != isNone:
|
||||||
|
bindingRet isGeneric
|
||||||
|
|
||||||
|
return isNone
|
||||||
|
|
||||||
|
of tyNot:
|
||||||
|
for branch in f.sons:
|
||||||
|
if typeRel(c, branch, a) != isNone:
|
||||||
|
return isNone
|
||||||
|
|
||||||
|
bindingRet isGeneric
|
||||||
|
|
||||||
|
of tyAnything:
|
||||||
|
var prev = PType(idTableGet(c.bindings, f))
|
||||||
|
if prev == nil:
|
||||||
|
var concrete = concreteType(c, a)
|
||||||
|
if concrete != nil and doBind:
|
||||||
|
put(c.bindings, f, concrete)
|
||||||
|
return isGeneric
|
||||||
|
else:
|
||||||
|
return typeRel(c, prev, a)
|
||||||
|
|
||||||
of tyGenericParam, tyTypeClass:
|
of tyGenericParam, tyTypeClass:
|
||||||
var x = PType(idTableGet(c.bindings, f))
|
var x = PType(idTableGet(c.bindings, f))
|
||||||
if x == nil:
|
if x == nil:
|
||||||
|
|
@ -634,7 +732,7 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
if concrete == nil:
|
if concrete == nil:
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
put(c.bindings, f, concrete)
|
if doBind: put(c.bindings, f, concrete)
|
||||||
elif a.kind == tyEmpty:
|
elif a.kind == tyEmpty:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
elif x.kind == tyGenericParam:
|
elif x.kind == tyGenericParam:
|
||||||
|
|
@ -809,8 +907,8 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
|
||||||
InternalAssert a.len > 0
|
InternalAssert a.len > 0
|
||||||
r = typeRel(m, f.lastSon, a.lastSon)
|
r = typeRel(m, f.lastSon, a.lastSon)
|
||||||
else:
|
else:
|
||||||
let match = matchTypeClass(m, fMaybeExpr, a)
|
let match = matchTypeClass(m.bindings, fMaybeExpr, a)
|
||||||
if match != isGeneric: r = isNone
|
if not match: r = isNone
|
||||||
else:
|
else:
|
||||||
# XXX: Ideally, this should happen much earlier somewhere near
|
# XXX: Ideally, this should happen much earlier somewhere near
|
||||||
# semOpAux, but to do that, we need to be able to query the
|
# semOpAux, but to do that, we need to be able to query the
|
||||||
|
|
@ -827,7 +925,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
|
||||||
|
|
||||||
if r == isGeneric:
|
if r == isGeneric:
|
||||||
put(m.bindings, f, arg.typ)
|
put(m.bindings, f, arg.typ)
|
||||||
of tyTypeClass:
|
of tyTypeClass, tyParametricTypeClass:
|
||||||
if fMaybeExpr.n != nil:
|
if fMaybeExpr.n != nil:
|
||||||
let match = matchUserTypeClass(c, m, arg, fMaybeExpr, a)
|
let match = matchUserTypeClass(c, m, arg, fMaybeExpr, a)
|
||||||
if match != nil:
|
if match != nil:
|
||||||
|
|
@ -1156,15 +1254,120 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||||
|
|
||||||
include suggest
|
include suggest
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
suite "typerel":
|
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
|
||||||
test "ordinals":
|
|
||||||
# var owner = newSym(skModule, getIdent("dummy"), nil, UnknownLineInfo())
|
proc `|` (t1, t2: PType): PType =
|
||||||
var m: TCandidate
|
result = newType(tyOr, dummyOwner)
|
||||||
InitCandidate(m, f)
|
result.rawAddSon(t1)
|
||||||
|
result.rawAddSon(t2)
|
||||||
|
|
||||||
|
proc `&` (t1, t2: PType): PType =
|
||||||
|
result = newType(tyAnd, dummyOwner)
|
||||||
|
result.rawAddSon(t1)
|
||||||
|
result.rawAddSon(t2)
|
||||||
|
|
||||||
|
proc `!` (t: PType): PType =
|
||||||
|
result = newType(tyNot, dummyOwner)
|
||||||
|
result.rawAddSon(t)
|
||||||
|
|
||||||
|
proc seq(t: PType): PType =
|
||||||
|
result = newType(tySequence, dummyOwner)
|
||||||
|
result.rawAddSon(t)
|
||||||
|
|
||||||
|
proc array(x: int, t: PType): PType =
|
||||||
|
result = newType(tyArray, dummyOwner)
|
||||||
|
|
||||||
|
var n = newNodeI(nkRange, UnknownLineInfo())
|
||||||
|
addSon(n, newIntNode(nkIntLit, 0))
|
||||||
|
addSon(n, newIntNode(nkIntLit, x))
|
||||||
|
let range = newType(tyRange, dummyOwner)
|
||||||
|
|
||||||
|
result.rawAddSon(range)
|
||||||
|
result.rawAddSon(t)
|
||||||
|
|
||||||
|
suite "type classes":
|
||||||
|
let
|
||||||
|
int = newType(tyInt, dummyOwner)
|
||||||
|
float = newType(tyFloat, dummyOwner)
|
||||||
|
string = newType(tyString, dummyOwner)
|
||||||
|
ordinal = newType(tyOrdinal, dummyOwner)
|
||||||
|
any = newType(tyAnything, dummyOwner)
|
||||||
|
number = int | float
|
||||||
|
|
||||||
|
var TFoo = newType(tyObject, dummyOwner)
|
||||||
|
TFoo.sym = newSym(skType, getIdent"TFoo", dummyOwner, UnknownLineInfo())
|
||||||
|
|
||||||
|
var T1 = newType(tyGenericParam, dummyOwner)
|
||||||
|
T1.sym = newSym(skType, getIdent"T1", dummyOwner, UnknownLineInfo())
|
||||||
|
T1.sym.position = 0
|
||||||
|
|
||||||
|
var T2 = newType(tyGenericParam, dummyOwner)
|
||||||
|
T2.sym = newSym(skType, getIdent"T2", dummyOwner, UnknownLineInfo())
|
||||||
|
T2.sym.position = 1
|
||||||
|
|
||||||
|
setup:
|
||||||
|
var c: TCandidate
|
||||||
|
InitCandidate(c, nil)
|
||||||
|
|
||||||
|
template yes(x, y) =
|
||||||
|
test astToStr(x) & " is " & astToStr(y):
|
||||||
|
check typeRel(c, y, x) == isGeneric
|
||||||
|
|
||||||
|
template no(x, y) =
|
||||||
|
test astToStr(x) & " is not " & astToStr(y):
|
||||||
|
check typeRel(c, y, x) == isNone
|
||||||
|
|
||||||
|
yes seq(any), array(10, int) | seq(any)
|
||||||
|
# Sure, seq[any] is directly included
|
||||||
|
|
||||||
|
yes seq(int), seq(any)
|
||||||
|
yes seq(int), seq(number)
|
||||||
|
# Sure, the int sequence is certainly
|
||||||
|
# part of the number sequences (and all sequences)
|
||||||
|
|
||||||
|
no seq(any), seq(float)
|
||||||
|
# Nope, seq[any] includes types that are not seq[float] (e.g. seq[int])
|
||||||
|
|
||||||
|
yes seq(int|string), seq(any)
|
||||||
|
# Sure
|
||||||
|
|
||||||
|
yes seq(int&string), seq(any)
|
||||||
|
# Again
|
||||||
|
|
||||||
|
yes seq(int&string), seq(int)
|
||||||
|
# A bit more complicated
|
||||||
|
# seq[int&string] is not a real type, but it's analogous to
|
||||||
|
# seq[Sortable and Iterable], which is certainly a subset of seq[Sortable]
|
||||||
|
|
||||||
|
no seq(int|string), seq(int|float)
|
||||||
|
# Nope, seq[string] is not included in not included in
|
||||||
|
# the seq[int|float] set
|
||||||
|
|
||||||
|
no seq(!(int|string)), seq(string)
|
||||||
|
# A sequence that is neither seq[int] or seq[string]
|
||||||
|
# is obviously not seq[string]
|
||||||
|
|
||||||
|
no seq(!int), seq(number)
|
||||||
|
# Now your head should start to hurt a bit
|
||||||
|
# A sequence that is not seq[int] is not necessarily a number sequence
|
||||||
|
# it could well be seq[string] for example
|
||||||
|
|
||||||
|
yes seq(!(int|string)), seq(!string)
|
||||||
|
# all sequnece types besides seq[int] and seq[string]
|
||||||
|
# are subset of all sequence types that are not seq[string]
|
||||||
|
|
||||||
|
no seq(!(int|string)), seq(!(string|TFoo))
|
||||||
|
# Nope, seq[TFoo] is included in the first set, but not in the second
|
||||||
|
|
||||||
|
no seq(!string), seq(!number)
|
||||||
|
# Nope, seq[int] in included in the first set, but not in the second
|
||||||
|
|
||||||
|
yes seq(!number), seq(any)
|
||||||
|
yes seq(!int), seq(any)
|
||||||
|
no seq(any), seq(!any)
|
||||||
|
no seq(!int), seq(!any)
|
||||||
|
|
||||||
|
yes int, ordinal
|
||||||
|
no string, ordinal
|
||||||
|
|
||||||
# let f = newType(tyOrdinal, owner)
|
|
||||||
# let a = getSysType(tyInt)
|
|
||||||
# check typerel(m, f, a) == isGeneric
|
|
||||||
|
|
|
||||||
|
|
@ -408,7 +408,8 @@ const
|
||||||
"float", "float32", "float64", "float128",
|
"float", "float32", "float64", "float128",
|
||||||
"uint", "uint8", "uint16", "uint32", "uint64",
|
"uint", "uint8", "uint16", "uint32", "uint64",
|
||||||
"bignum", "const ",
|
"bignum", "const ",
|
||||||
"!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass"]
|
"!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass",
|
||||||
|
"ParametricTypeClass", "and", "or", "not", "any"]
|
||||||
|
|
||||||
proc consToStr(t: PType): string =
|
proc consToStr(t: PType): string =
|
||||||
if t.len > 0: result = t.typeToString
|
if t.len > 0: result = t.typeToString
|
||||||
|
|
@ -861,7 +862,7 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
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, tyTypeClasses:
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
||||||
if result and (a.kind == tyProc):
|
if result and (a.kind == tyProc):
|
||||||
|
|
@ -1042,7 +1043,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
|
||||||
# XXX er ... no? these should not be allowed!
|
# XXX er ... no? these should not be allowed!
|
||||||
of tyEmpty:
|
of tyEmpty:
|
||||||
result = taField in flags
|
result = taField in flags
|
||||||
of tyTypeClass:
|
of tyTypeClasses:
|
||||||
result = true
|
result = true
|
||||||
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation:
|
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation:
|
||||||
result = false
|
result = false
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,8 @@ macro check*(conditions: stmt): stmt {.immediate.} =
|
||||||
counter = 0
|
counter = 0
|
||||||
|
|
||||||
template asgn(a, value: expr): stmt =
|
template asgn(a, value: expr): stmt =
|
||||||
let a = value
|
var a = value # XXX: we need "var: var" here in order to
|
||||||
|
# preserve the semantics of var params
|
||||||
|
|
||||||
template print(name, value: expr): stmt =
|
template print(name, value: expr): stmt =
|
||||||
when compiles(string($value)):
|
when compiles(string($value)):
|
||||||
|
|
@ -150,6 +151,7 @@ macro check*(conditions: stmt): stmt {.immediate.} =
|
||||||
of nnkStmtList:
|
of nnkStmtList:
|
||||||
result = newNimNode(nnkStmtList)
|
result = newNimNode(nnkStmtList)
|
||||||
for i in countup(0, checked.len - 1):
|
for i in countup(0, checked.len - 1):
|
||||||
|
if checked[i].kind != nnkCommentStmt:
|
||||||
result.add(newCall(!"check", checked[i]))
|
result.add(newCall(!"check", checked[i]))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue