mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 01:14:41 +00:00
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:
@@ -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], {})
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
42
tests/compile/tisop.nim
Normal 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
discard """
|
||||
file: "system.nim"
|
||||
line: 643
|
||||
line: 649
|
||||
errormsg: "type mismatch"
|
||||
"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user