diff options
author | Zahary Karadjov <zahary@gmail.com> | 2014-01-24 14:13:32 +0200 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2014-01-24 14:13:32 +0200 |
commit | a6a18be0899ff0445128c614f285be1924ec5281 (patch) | |
tree | a2d49244bded0fbe6c8cbdc3019c26b4cd1d51f3 /compiler | |
parent | 3c840102bcb3daca6f7c275c2c21183be7a145cb (diff) | |
download | Nim-a6a18be0899ff0445128c614f285be1924ec5281.tar.gz |
support for parametric user-defined type classes
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 21 | ||||
-rw-r--r-- | compiler/semexprs.nim | 4 | ||||
-rw-r--r-- | compiler/semtypes.nim | 9 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 5 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 129 | ||||
-rw-r--r-- | compiler/types.nim | 5 |
6 files changed, 102 insertions, 71 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 0e351a31a..4a3f1e894 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -337,12 +337,20 @@ type tyIter, # unused tyProxy # used as errornous type (for idetools) tyTypeClass - tyParametricTypeClass # structured similarly to tyGenericInst - # lastSon is the body of the type class + tyBuiltInTypeClass # Type such as the catch-all object, tuple, seq, etc + tyUserTypeClass + tyUserTypeClassInst # \ + # Instance of a parametric user-defined type class. + # Structured similarly to tyGenericInst. + # tyGenericInst represents concrete types, while + # this is still a "generic param" that will bind types + # and resolves them during sigmatch and instantiation. - tyBuiltInTypeClass # Type such as the catch-all object, tuple, seq, etc - - tyCompositeTypeClass # + tyCompositeTypeClass # Type such as seq[Number] + # The notes for tyUserTypeClassInst apply here as well + # sons[0]: the original expression used by the user. + # sons[1]: fully expanded and instantiated meta type + # (potentially following aliases) tyAnd, tyOr, tyNot # boolean type classes such as `string|int`,`not seq`, # `Sortable and Enumable`, etc @@ -365,7 +373,8 @@ const tyUnknownTypes* = {tyError, tyFromExpr} tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, tyCompositeTypeClass, - tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything} + tyUserTypeClass, tyUserTypeClassInst, + tyAnd, tyOr, tyNot, tyAnything} tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyStatic, tyExpr} + tyTypeClasses diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 6e2d777fb..37fdf8b34 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -322,12 +322,12 @@ proc isOpImpl(c: PContext, n: PNode): PNode = tfIterator in t.flags)) else: var match: bool - let t2 = n[2].typ + let t2 = n[2].typ.skipTypes({tyTypeDesc}) case t2.kind of tyTypeClasses: var m: TCandidate initCandidate(c, m, t2) - match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil + match = typeRel(m, t2, t1) != isNone of tyOrdinal: var m: TCandidate initCandidate(c, m, t2) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index d5a938a12..4bcaf55d6 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -710,6 +710,11 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, result = addImplicitGeneric(result) of tyGenericInst: + if paramType.lastSon.kind == tyUserTypeClass: + var cp = copyType(paramType, getCurrOwner(), false) + cp.kind = tyUserTypeClassInst + return addImplicitGeneric(cp) + for i in 1 .. (paramType.sons.len - 2): var lifted = liftingWalk(paramType.sons[i]) if lifted != nil: @@ -731,7 +736,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, allowMetaTypes = true) result = liftingWalk(expanded) - of tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: + of tyUserTypeClass, tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true)) of tyExpr: @@ -923,7 +928,7 @@ proc freshType(res, prev: PType): PType {.inline.} = proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = # if n.sonsLen == 0: return newConstraint(c, tyTypeClass) - result = newOrPrevType(tyTypeClass, prev, c) + result = newOrPrevType(tyUserTypeClass, prev, c) result.n = n let diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index ac14179cd..a9322c1f4 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -360,7 +360,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = if tfUnresolved in t.flags: result = result.base elif t.sonsLen > 0: result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0])) - + + of tyUserTypeClass: + result = t + of tyGenericInst: result = instCopyType(cl, t) for i in 1 .. <result.sonsLen: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index bb70e0d6b..d0a832147 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -399,6 +399,69 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = else: result = isNone +proc matchUserTypeClass*(c: PContext, m: var TCandidate, + ff, a: PType): TTypeRelation = + #if f.n == nil: + # let r = typeRel(m, f, a) + # return if r == isGeneric: arg else: nil + + var body = ff.skipTypes({tyUserTypeClassInst}) + + # var prev = PType(idTableGet(m.bindings, f)) + # if prev != nil: + # if sameType(prev, a): return arg + # else: return nil + + # pushInfoContext(arg.info) + openScope(c) + inc c.inTypeClass + + finally: + dec c.inTypeClass + closeScope(c) + + if ff.kind == tyUserTypeClassInst: + for i in 1 .. <(ff.len - 1): + var + typeParamName = ff.base.sons[i-1].sym.name + typ = ff.sons[i] + param = newSym(skType, typeParamName, body.sym, body.sym.info) + + param.typ = makeTypeDesc(c, typ) + addDecl(c, param) + + for param in body.n[0]: + var + dummyName: PNode + dummyType: PType + + if param.kind == nkVarTy: + dummyName = param[0] + dummyType = makeVarType(c, a) + else: + dummyName = param + dummyType = a + + internalAssert dummyName.kind == nkIdent + var dummyParam = newSym(skType, dummyName.ident, body.sym, body.sym.info) + dummyParam.typ = dummyType + addDecl(c, dummyParam) + + for stmt in body.n[3]: + var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false) + m.errors = bufferedMsgs + clearBufferedMsgs() + if e == nil: return isNone + + case e.kind + of nkReturnStmt: discard + of nkTypeSection: discard + of nkConstDef: discard + else: discard + + return isGeneric + # put(m.bindings, f, a) + proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # typeRel can be used to establish various relationships between types: # @@ -751,6 +814,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = else: return isNone + of tyUserTypeClassInst: + considerPreviousT: + result = matchUserTypeClass(c.c, c, f, a) + if result == isGeneric: + put(c.bindings, f, a) + of tyCompositeTypeClass: considerPreviousT: if typeRel(c, f.sons[1], a) != isNone: @@ -904,57 +973,6 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, result.typ = getInstantiatedType(c, arg, m, base(f)) m.baseTypeMatch = true -proc matchUserTypeClass*(c: PContext, m: var TCandidate, - arg: PNode, f, a: PType): PNode = - if f.n == nil: - let r = typeRel(m, f, a) - return if r == isGeneric: arg else: nil - - var prev = PType(idTableGet(m.bindings, f)) - if prev != nil: - if sameType(prev, a): return arg - else: return nil - - # pushInfoContext(arg.info) - openScope(c) - inc c.inTypeClass - - finally: - dec c.inTypeClass - closeScope(c) - - for param in f.n[0]: - var - dummyName: PNode - dummyType: PType - - if param.kind == nkVarTy: - dummyName = param[0] - dummyType = makeVarType(c, a) - else: - dummyName = param - dummyType = a - - internalAssert dummyName.kind == nkIdent - var dummyParam = newSym(skType, dummyName.ident, f.sym, f.sym.info) - dummyParam.typ = dummyType - addDecl(c, dummyParam) - - for stmt in f.n[3]: - var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false) - m.errors = bufferedMsgs - clearBufferedMsgs() - if e == nil: return nil - - case e.kind - of nkReturnStmt: discard - of nkTypeSection: discard - of nkConstDef: discard - else: discard - - result = arg - put(m.bindings, f, a) - proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, argSemantized, argOrig: PNode): PNode = var @@ -980,14 +998,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, else: argType case fMaybeStatic.kind - of tyTypeClass, tyParametricTypeClass: + of tyTypeClass: if fMaybeStatic.n != nil: - let match = matchUserTypeClass(c, m, arg, fMaybeStatic, a) - if match != nil: - r = isGeneric - arg = match - else: - r = isNone + r = matchUserTypeClass(c, m, fMaybeStatic, a) else: r = typeRel(m, f, a) of tyExpr: diff --git a/compiler/types.nim b/compiler/types.nim index d7310596f..cc066a36d 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -404,8 +404,9 @@ const "float", "float32", "float64", "float128", "uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ", - "!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass", - "ParametricTypeClass", "BuiltInTypeClass", "CompositeTypeClass", + "!", "varargs[$1]", "iter[$1]", "Error Type", + "TypeClass", "BuiltInTypeClass", "UserTypeClass", + "UserTypeClassInst", "CompositeTypeClass", "and", "or", "not", "any", "static", "TypeFromExpr"] proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = |