the is operator now works with type classes and type variables

bugfixes:
the DLL tests were failing on Mac OS X, due to an incorrect DynlibFormat
This commit is contained in:
Zahary Karadjov
2012-10-02 16:45:34 +03:00
parent 770d4a997e
commit 9c8bc3a244
13 changed files with 162 additions and 88 deletions

View File

@@ -521,7 +521,7 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
else: result = nil
if result == nil or {sfImportc, sfForward} * s.flags != {}:
result = raiseCannotEval(c, n.info)
proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode =
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
@@ -875,6 +875,27 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
else:
internalAssert false
proc evalIsOp*(n: PNode): PNode =
InternalAssert n.sonsLen == 3 and
n[1].kind == nkSym and n[1].sym.kind == skType and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = n[1].sym.typ
if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize
of "closure":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure))
else:
let t2 = n[2].typ
var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
else: sameType(t1, t2)
result = newIntNode(nkIntLit, ord(match))
result.typ = n.typ
proc expectString(n: PNode) =
if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
GlobalError(n.info, errStringLiteralExpected)
@@ -968,6 +989,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mTypeTrait:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalTypeTrait(n, c.module)
of mIs:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalIsOp(n)
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
of mStaticExec:
let cmd = evalAux(c, n.sons[1], {})

View File

@@ -281,18 +281,29 @@ proc semOf(c: PContext, n: PNode): PNode =
n.typ = getSysType(tyBool)
result = n
proc semIs(c: PContext, n: PNode): PNode =
if sonsLen(n) == 3:
n.typ = getSysType(tyBool)
let a = semTypeNode(c, n[1], nil)
n.sons[1] = newNodeIT(nkType, n[1].info, a)
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
let b = semTypeNode(c, n[2], nil)
n.sons[2] = newNodeIT(nkType, n[2].info, b)
else:
proc semIs(c: PContext, n: PNode): PNode =
if sonsLen(n) != 3:
LocalError(n.info, errXExpectsTwoArguments, "is")
result = n
result = n
n.typ = getSysType(tyBool)
n.sons[1] = semExprWithType(c, n[1])
if n[1].typ.kind != tyTypeDesc:
LocalError(n[0].info, errTypeExpected)
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
let t2 = semTypeNode(c, n[2], nil)
n.sons[2] = newNodeIT(nkType, n[2].info, t2)
if n[1].typ.sonsLen == 0:
# this is a typedesc variable, leave for evals
return
else:
let t1 = n[1].typ.sons[0]
# BUGFIX: don't evaluate this too early: ``T is void``
if not containsGenericType(t1): result = evalIsOp(n)
proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) =
for i in countup(1, sonsLen(n) - tailToExclude):
var a = n.sons[i]

View File

@@ -610,17 +610,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = newIntNodeT(sonsLen(a), n)
else:
result = magicCall(m, n)
of mIs:
# BUGFIX: don't evaluate this too early: ``T is void``
if not containsGenericType(n[1].typ):
if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize
of "closure":
let t = skipTypes(n[1].typ, abstractRange)
result = newIntNodeT(ord(t.kind == tyProc and
t.callConv == ccClosure), n)
elif not containsGenericType(n[2].typ):
result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n)
of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
of mConStrStr:

View File

@@ -261,16 +261,16 @@ proc semGenericStmt(c: PContext, n: PNode,
else:
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
of nkEnumTy:
checkMinSonsLen(n, 1)
if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
for i in countup(1, sonsLen(n) - 1):
var a: PNode
case n.sons[i].kind
of nkEnumFieldDef: a = n.sons[i].sons[0]
of nkIdent: a = n.sons[i]
else: illFormedAst(n)
addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
if n.sonsLen > 0:
if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
for i in countup(1, sonsLen(n) - 1):
var a: PNode
case n.sons[i].kind
of nkEnumFieldDef: a = n.sons[i].sons[0]
of nkIdent: a = n.sons[i]
else: illFormedAst(n)
addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
of nkObjectTy, nkTupleTy:
nil
of nkFormalParams:

View File

@@ -799,22 +799,25 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
LocalError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
of nkCallKinds:
let op = n.sons[0].ident
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
var
t1 = semTypeNode(c, n.sons[1], nil)
t2 = semTypeNode(c, n.sons[2], nil)
if t1 == nil:
LocalError(n.sons[1].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif t2 == nil:
LocalError(n.sons[2].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
if n[0].kind == nkIdent:
let op = n.sons[0].ident
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
var
t1 = semTypeNode(c, n.sons[1], nil)
t2 = semTypeNode(c, n.sons[2], nil)
if t1 == nil:
LocalError(n.sons[1].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif t2 == nil:
LocalError(n.sons[2].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
else:
result = newTypeS(tyTypeClass, c)
result.addSonSkipIntLit(t1)
result.addSonSkipIntLit(t2)
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
else:
result = newTypeS(tyTypeClass, c)
result.addSonSkipIntLit(t1)
result.addSonSkipIntLit(t2)
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
result = semTypeExpr(c, n)
else:
result = semTypeExpr(c, n)
of nkCurlyExpr:

View File

@@ -59,6 +59,7 @@ type
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
result = copyNode(n)
@@ -66,7 +67,7 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
for i in 0 .. safeLen(n)-1:
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
if i == 0: result.add(n[i])
else: result.add(prepareNode(cl, n[i]))
else: result.add(ReplaceTypeVarsN(cl, n[i]))
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
if n == nil: return

View File

@@ -11,7 +11,7 @@
## the call to overloaded procs, generic procs and operators.
import
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
magicsys, condsyms, idents, lexer, options
type
@@ -257,37 +257,6 @@ proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation =
var y = a.n.sons[i].sym
if x.name.id != y.name.id: return isNone
proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation =
for i in countup(0, typeClass.sonsLen - 1):
let req = typeClass.sons[i]
var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
if not match:
case req.kind
of tyGenericBody:
if t.kind == tyGenericInst and t.sons[0] == req:
match = true
put(c.bindings, typeClass, t)
of tyTypeClass:
match = matchTypeClass(c, req, t) == isGeneric
else: nil
elif t.kind in {tyObject}:
match = sameType(t, req)
if tfAny in typeClass.flags:
if match: return isGeneric
else:
if not match: return isNone
# if the loop finished without returning, either all constraints matched
# or none of them matched.
result = if tfAny in typeClass.flags: isNone else: isGeneric
proc matchTypeClass*(typeClass, typ: PType): bool =
var c: TCandidate
InitCandidate(c, typeClass)
result = matchTypeClass(c, typeClass, typ) == isGeneric
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
@@ -330,6 +299,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
result = isNone
else: nil
proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
result = if matchTypeClass(c.bindings, f, a): isGeneric
else: isNone
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
# is a subtype of f?
result = isNone

View File

@@ -904,7 +904,38 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
if i >= a.sonslen or a.sons[i] == nil: return false
a = a.sons[i]
result = a.kind == last
proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
for i in countup(0, typeClass.sonsLen - 1):
let req = typeClass.sons[i]
var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
if not match:
case req.kind
of tyGenericBody:
if t.kind == tyGenericInst and t.sons[0] == req:
match = true
IdTablePut(bindings, typeClass, t)
of tyTypeClass:
match = matchTypeClass(bindings, req, t)
else: nil
elif t.kind in {tyObject}:
match = sameType(t, req)
if tfAny in typeClass.flags:
if match: return true
else:
if not match: return false
# if the loop finished without returning, either all constraints matched
# or none of them matched.
result = if tfAny in typeClass.flags: false else: true
proc matchTypeClass*(typeClass, typ: PType): bool =
var bindings: TIdTable
initIdTable(bindings)
result = matchTypeClass(bindings, typeClass, typ)
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
assert(kind in {skVar, skLet, skConst, skParam, skResult})
# if we have already checked the type, return true, because we stop the

View File

@@ -149,7 +149,7 @@ else: # UNIX-like operating system
FileSystemCaseSensitive* = true
ExeExt* = ""
ScriptExt* = ""
DynlibFormat* = "lib$1.so"
DynlibFormat* = when defined(macosx): "lib$1.dylib" else: "lib$1.so"
when defined(macosx) or defined(bsd):
var

42
tests/compile/tisop.nim Normal file
View File

@@ -0,0 +1,42 @@
import typetraits
type
TRecord = (tuple) or (object)
TFoo[T, U] = object
x: int
when T is string:
y: float
else:
y: string
when U is TRecord:
z: float
E = enum A, B, C
macro m(t: typedesc): typedesc =
if t is enum:
result = string
else:
result = int
var f: TFoo[int, int]
static: assert(f.y.type.name == "string")
when compiles(f.z):
{.error: "Foo should not have a `z` field".}
proc p(a, b) =
when a.type is int:
static: assert false
var f: TFoo[m(a.type), b.type]
static:
assert f.x.type.name == "int"
assert f.y.type.name == "float"
assert f.z.type.name == "float"
p(A, f)

View File

@@ -2,8 +2,8 @@ type
TFoo[T] = object
val: T
T1 = distinct expr
T2 = distinct expr
T1 = expr
T2 = expr
proc takesExpr(x, y) =
echo x, y

View File

@@ -1,11 +1,11 @@
discard """
file: "tcaseexpr1.nim"
line: 23
errormsg: "not all cases are covered"
line: 29
errormsg: "type mismatch: got (string) but expected 'int'"
line: 23
errormsg: "not all cases are covered"
"""
type

View File

@@ -1,6 +1,6 @@
discard """
file: "system.nim"
line: 643
line: 649
errormsg: "type mismatch"
"""