support for parametric user-defined type classes
This commit is contained in:
parent
3c840102bc
commit
a6a18be089
6 changed files with 102 additions and 71 deletions
|
|
@ -337,12 +337,20 @@ type
|
||||||
tyIter, # unused
|
tyIter, # unused
|
||||||
tyProxy # used as errornous type (for idetools)
|
tyProxy # used as errornous type (for idetools)
|
||||||
tyTypeClass
|
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
|
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.
|
||||||
|
|
||||||
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`,
|
tyAnd, tyOr, tyNot # boolean type classes such as `string|int`,`not seq`,
|
||||||
# `Sortable and Enumable`, etc
|
# `Sortable and Enumable`, etc
|
||||||
|
|
@ -365,7 +373,8 @@ const
|
||||||
tyUnknownTypes* = {tyError, tyFromExpr}
|
tyUnknownTypes* = {tyError, tyFromExpr}
|
||||||
|
|
||||||
tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, tyCompositeTypeClass,
|
tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, tyCompositeTypeClass,
|
||||||
tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
|
tyUserTypeClass, tyUserTypeClassInst,
|
||||||
|
tyAnd, tyOr, tyNot, tyAnything}
|
||||||
|
|
||||||
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyStatic, tyExpr} + tyTypeClasses
|
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyStatic, tyExpr} + tyTypeClasses
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -322,12 +322,12 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
|
||||||
tfIterator in t.flags))
|
tfIterator in t.flags))
|
||||||
else:
|
else:
|
||||||
var match: bool
|
var match: bool
|
||||||
let t2 = n[2].typ
|
let t2 = n[2].typ.skipTypes({tyTypeDesc})
|
||||||
case t2.kind
|
case t2.kind
|
||||||
of tyTypeClasses:
|
of tyTypeClasses:
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
initCandidate(c, m, t2)
|
initCandidate(c, m, t2)
|
||||||
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
|
match = typeRel(m, t2, t1) != isNone
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
initCandidate(c, m, t2)
|
initCandidate(c, m, t2)
|
||||||
|
|
|
||||||
|
|
@ -710,6 +710,11 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
result = addImplicitGeneric(result)
|
result = addImplicitGeneric(result)
|
||||||
|
|
||||||
of tyGenericInst:
|
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):
|
for i in 1 .. (paramType.sons.len - 2):
|
||||||
var lifted = liftingWalk(paramType.sons[i])
|
var lifted = liftingWalk(paramType.sons[i])
|
||||||
if lifted != nil:
|
if lifted != nil:
|
||||||
|
|
@ -731,7 +736,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
allowMetaTypes = true)
|
allowMetaTypes = true)
|
||||||
result = liftingWalk(expanded)
|
result = liftingWalk(expanded)
|
||||||
|
|
||||||
of tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
of tyUserTypeClass, tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
||||||
|
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
|
|
@ -923,7 +928,7 @@ proc freshType(res, prev: PType): PType {.inline.} =
|
||||||
|
|
||||||
proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
||||||
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
||||||
result = newOrPrevType(tyTypeClass, prev, c)
|
result = newOrPrevType(tyUserTypeClass, prev, c)
|
||||||
result.n = n
|
result.n = n
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
|
||||||
|
|
@ -361,6 +361,9 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
elif t.sonsLen > 0:
|
elif t.sonsLen > 0:
|
||||||
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
|
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
|
||||||
|
|
||||||
|
of tyUserTypeClass:
|
||||||
|
result = t
|
||||||
|
|
||||||
of tyGenericInst:
|
of tyGenericInst:
|
||||||
result = instCopyType(cl, t)
|
result = instCopyType(cl, t)
|
||||||
for i in 1 .. <result.sonsLen:
|
for i in 1 .. <result.sonsLen:
|
||||||
|
|
|
||||||
|
|
@ -399,6 +399,69 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
|
||||||
else:
|
else:
|
||||||
result = isNone
|
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 =
|
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# typeRel can be used to establish various relationships between types:
|
# 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:
|
else:
|
||||||
return isNone
|
return isNone
|
||||||
|
|
||||||
|
of tyUserTypeClassInst:
|
||||||
|
considerPreviousT:
|
||||||
|
result = matchUserTypeClass(c.c, c, f, a)
|
||||||
|
if result == isGeneric:
|
||||||
|
put(c.bindings, f, a)
|
||||||
|
|
||||||
of tyCompositeTypeClass:
|
of tyCompositeTypeClass:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
if typeRel(c, f.sons[1], a) != isNone:
|
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))
|
result.typ = getInstantiatedType(c, arg, m, base(f))
|
||||||
m.baseTypeMatch = true
|
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,
|
proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
argSemantized, argOrig: PNode): PNode =
|
argSemantized, argOrig: PNode): PNode =
|
||||||
var
|
var
|
||||||
|
|
@ -980,14 +998,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
else: argType
|
else: argType
|
||||||
|
|
||||||
case fMaybeStatic.kind
|
case fMaybeStatic.kind
|
||||||
of tyTypeClass, tyParametricTypeClass:
|
of tyTypeClass:
|
||||||
if fMaybeStatic.n != nil:
|
if fMaybeStatic.n != nil:
|
||||||
let match = matchUserTypeClass(c, m, arg, fMaybeStatic, a)
|
r = matchUserTypeClass(c, m, fMaybeStatic, a)
|
||||||
if match != nil:
|
|
||||||
r = isGeneric
|
|
||||||
arg = match
|
|
||||||
else:
|
|
||||||
r = isNone
|
|
||||||
else:
|
else:
|
||||||
r = typeRel(m, f, a)
|
r = typeRel(m, f, a)
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
|
|
|
||||||
|
|
@ -404,8 +404,9 @@ 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",
|
||||||
"ParametricTypeClass", "BuiltInTypeClass", "CompositeTypeClass",
|
"TypeClass", "BuiltInTypeClass", "UserTypeClass",
|
||||||
|
"UserTypeClassInst", "CompositeTypeClass",
|
||||||
"and", "or", "not", "any", "static", "TypeFromExpr"]
|
"and", "or", "not", "any", "static", "TypeFromExpr"]
|
||||||
|
|
||||||
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue