diff options
author | Zahary Karadjov <zahary@gmail.com> | 2012-10-02 16:45:34 +0300 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2012-10-03 01:59:49 +0300 |
commit | 9c8bc3a244b4bbcdc56fdd255bb4e1a7ed30f781 (patch) | |
tree | c5d561cdd51566a5f46c2c2558b36ffdd24f42b5 /compiler | |
parent | 770d4a997eab25a04cdfd83b325491a2e63bea08 (diff) | |
download | Nim-9c8bc3a244b4bbcdc56fdd255bb4e1a7ed30f781.tar.gz |
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
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/evals.nim | 26 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 29 | ||||
-rwxr-xr-x | compiler/semfold.nim | 11 | ||||
-rwxr-xr-x | compiler/semgnrc.nim | 20 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 33 | ||||
-rwxr-xr-x | compiler/semtypinst.nim | 3 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 37 | ||||
-rwxr-xr-x | compiler/types.nim | 33 |
8 files changed, 112 insertions, 80 deletions
diff --git a/compiler/evals.nim b/compiler/evals.nim index 9c73a6b78..0886b1ef5 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -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], {}) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a658f7f44..51ede1614 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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 + 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] diff --git a/compiler/semfold.nim b/compiler/semfold.nim index c2958ca5e..d0805d921 100755 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -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: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index dde799ab3..bffa8ad8e 100755 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -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: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index eeb48a647..c41727b10 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index d75594dff..70453c6db 100755 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -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 diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 82a8c9399..8f1ca5f36 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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 diff --git a/compiler/types.nim b/compiler/types.nim index b650b49b8..e02d93233 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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 |