towards support for composite type classes such as seq[Number] and SquareMatrix[T]
This commit is contained in:
parent
4eea2f17d3
commit
a27eb51535
8 changed files with 87 additions and 26 deletions
|
|
@ -340,6 +340,7 @@ type
|
||||||
tyParametricTypeClass # structured similarly to tyGenericInst
|
tyParametricTypeClass # structured similarly to tyGenericInst
|
||||||
# lastSon is the body of the type class
|
# lastSon is the body of the type class
|
||||||
tyBuiltInTypeClass
|
tyBuiltInTypeClass
|
||||||
|
tyCompositeTypeClass
|
||||||
tyAnd
|
tyAnd
|
||||||
tyOr
|
tyOr
|
||||||
tyNot
|
tyNot
|
||||||
|
|
@ -350,7 +351,7 @@ const
|
||||||
tyPureObject* = tyTuple
|
tyPureObject* = tyTuple
|
||||||
GcTypeKinds* = {tyRef, tySequence, tyString}
|
GcTypeKinds* = {tyRef, tySequence, tyString}
|
||||||
tyError* = tyProxy # as an errornous node should match everything
|
tyError* = tyProxy # as an errornous node should match everything
|
||||||
tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass,
|
tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, tyCompositeTypeClass,
|
||||||
tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
|
tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything}
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ proc equalGenericParams(procA, procB: PNode): bool =
|
||||||
let a = procA.sons[i].sym
|
let a = procA.sons[i].sym
|
||||||
let b = procB.sons[i].sym
|
let b = procB.sons[i].sym
|
||||||
if a.name.id != b.name.id or
|
if a.name.id != b.name.id or
|
||||||
not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return
|
not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}): return
|
||||||
if a.ast != nil and b.ast != nil:
|
if a.ast != nil and b.ast != nil:
|
||||||
if not ExprStructuralEquivalent(a.ast, b.ast): return
|
if not ExprStructuralEquivalent(a.ast, b.ast): return
|
||||||
result = true
|
result = true
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ proc sameInstantiation(a, b: TInstantiation): bool =
|
||||||
if a.concreteTypes.len == b.concreteTypes.len:
|
if a.concreteTypes.len == b.concreteTypes.len:
|
||||||
for i in 0..a.concreteTypes.high:
|
for i in 0..a.concreteTypes.high:
|
||||||
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
|
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
|
||||||
flags = {TypeDescExactMatch}): return
|
flags = {ExactTypeDescValues}): return
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc GenericCacheGet(genericSym: Psym, entry: TInstantiation): PSym =
|
proc GenericCacheGet(genericSym: Psym, entry: TInstantiation): PSym =
|
||||||
|
|
@ -165,7 +165,8 @@ proc lateInstantiateGeneric(c: PContext, invocation: PType, info: TLineInfo): PT
|
||||||
result.sons.add instantiated
|
result.sons.add instantiated
|
||||||
cacheTypeInst result
|
cacheTypeInst result
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType =
|
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||||
|
allowMetaTypes = false): PType =
|
||||||
when oUseLateInstantiation:
|
when oUseLateInstantiation:
|
||||||
lateInstantiateGeneric(c, header, info)
|
lateInstantiateGeneric(c, header, info)
|
||||||
else:
|
else:
|
||||||
|
|
@ -174,6 +175,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType =
|
||||||
InitIdTable(cl.typeMap)
|
InitIdTable(cl.typeMap)
|
||||||
cl.info = info
|
cl.info = info
|
||||||
cl.c = c
|
cl.c = c
|
||||||
|
cl.allowMetaTypes = allowMetaTypes
|
||||||
result = ReplaceTypeVarsT(cl, header)
|
result = ReplaceTypeVarsT(cl, header)
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||||
|
|
|
||||||
|
|
@ -666,11 +666,14 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
paramType.sons[i] = lifted
|
paramType.sons[i] = lifted
|
||||||
result = paramType
|
result = paramType
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
# type Foo[T] = object
|
result = newTypeS(tyGenericInvokation, c)
|
||||||
# proc x(a: Foo, b: Foo)
|
result.rawAddSon(paramType)
|
||||||
var typ = newTypeS(tyTypeClass, c)
|
for i in 0 .. paramType.sonsLen - 2:
|
||||||
typ.addSonSkipIntLit(paramType)
|
result.rawAddSon(copyType(paramType.sons[i], getCurrOwner(), true))
|
||||||
result = addImplicitGeneric(typ)
|
result = instGenericContainer(c, paramType.sym.info, result,
|
||||||
|
allowMetaTypes = true)
|
||||||
|
result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
|
||||||
|
result = addImplicitGeneric(result)
|
||||||
of tyGenericInst:
|
of tyGenericInst:
|
||||||
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])
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,8 @@ proc searchInstTypes*(key: PType): PType =
|
||||||
block MatchType:
|
block MatchType:
|
||||||
for j in 1 .. high(key.sons):
|
for j in 1 .. high(key.sons):
|
||||||
# XXX sameType is not really correct for nested generics?
|
# XXX sameType is not really correct for nested generics?
|
||||||
if not sameType(inst.sons[j], key.sons[j]):
|
if not compareTypes(inst.sons[j], key.sons[j],
|
||||||
|
flags = {ExactGenericParams}):
|
||||||
break MatchType
|
break MatchType
|
||||||
|
|
||||||
return inst
|
return inst
|
||||||
|
|
@ -67,6 +68,8 @@ type
|
||||||
typeMap*: TIdTable # map PType to PType
|
typeMap*: TIdTable # map PType to PType
|
||||||
symMap*: TIdTable # map PSym to PSym
|
symMap*: TIdTable # map PSym to PSym
|
||||||
info*: TLineInfo
|
info*: TLineInfo
|
||||||
|
allowMetaTypes*: bool # allow types such as seq[Number]
|
||||||
|
# i.e. the result contains unresolved generics
|
||||||
|
|
||||||
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
|
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
|
||||||
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
|
||||||
|
|
@ -132,9 +135,10 @@ proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
||||||
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
|
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
|
||||||
result = PType(idTableGet(cl.typeMap, t))
|
result = PType(idTableGet(cl.typeMap, t))
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
if cl.allowMetaTypes: return
|
||||||
LocalError(t.sym.info, errCannotInstantiateX, typeToString(t))
|
LocalError(t.sym.info, errCannotInstantiateX, typeToString(t))
|
||||||
result = errorType(cl.c)
|
result = errorType(cl.c)
|
||||||
elif result.kind == tyGenericParam:
|
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
||||||
InternalError(cl.info, "substitution with generic parameter")
|
InternalError(cl.info, "substitution with generic parameter")
|
||||||
|
|
||||||
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
|
|
@ -150,10 +154,10 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
var x = t.sons[i]
|
var x = t.sons[i]
|
||||||
if x.kind == tyGenericParam:
|
if x.kind == tyGenericParam:
|
||||||
x = lookupTypeVar(cl, x)
|
x = lookupTypeVar(cl, x)
|
||||||
|
if x != nil:
|
||||||
if header == nil: header = copyType(t, t.owner, false)
|
if header == nil: header = copyType(t, t.owner, false)
|
||||||
header.sons[i] = x
|
header.sons[i] = x
|
||||||
propagateToOwner(header, x)
|
propagateToOwner(header, x)
|
||||||
#idTablePut(cl.typeMap, body.sons[i-1], x)
|
|
||||||
|
|
||||||
if header != nil:
|
if header != nil:
|
||||||
# search again after first pass:
|
# search again after first pass:
|
||||||
|
|
@ -202,6 +206,7 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
of tyTypeClass: nil
|
of tyTypeClass: nil
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
result = lookupTypeVar(cl, t)
|
result = lookupTypeVar(cl, t)
|
||||||
|
if result == nil: return t
|
||||||
if result.kind == tyGenericInvokation:
|
if result.kind == tyGenericInvokation:
|
||||||
result = handleGenericInvokation(cl, result)
|
result = handleGenericInvokation(cl, result)
|
||||||
of tyGenericInvokation:
|
of tyGenericInvokation:
|
||||||
|
|
|
||||||
|
|
@ -647,6 +647,8 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
|
||||||
result = typeRel(c, lastSon(f), a)
|
result = typeRel(c, lastSon(f), a)
|
||||||
|
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
|
if a.kind == tyGenericInst and a.sons[0] == f:
|
||||||
|
return isGeneric
|
||||||
let ff = lastSon(f)
|
let ff = lastSon(f)
|
||||||
if ff != nil: result = typeRel(c, ff, a)
|
if ff != nil: result = typeRel(c, ff, a)
|
||||||
|
|
||||||
|
|
@ -718,6 +720,17 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, prev, a)
|
result = typeRel(c, prev, a)
|
||||||
|
|
||||||
|
of tyCompositeTypeClass:
|
||||||
|
var prev = PType(idTableGet(c.bindings, f))
|
||||||
|
if prev == nil:
|
||||||
|
if typeRel(c, f.sons[1], a) != isNone:
|
||||||
|
put(c.bindings, f, a)
|
||||||
|
return isGeneric
|
||||||
|
else:
|
||||||
|
return isNone
|
||||||
|
else:
|
||||||
|
result = typeRel(c, prev, a)
|
||||||
|
|
||||||
of tyGenericParam, tyTypeClass:
|
of tyGenericParam, tyTypeClass:
|
||||||
var x = PType(idTableGet(c.bindings, f))
|
var x = PType(idTableGet(c.bindings, f))
|
||||||
if x == nil:
|
if x == nil:
|
||||||
|
|
@ -780,10 +793,13 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
|
||||||
let toMatch = if tfUnresolved in f.flags: a
|
let toMatch = if tfUnresolved in f.flags: a
|
||||||
else: a.sons[0]
|
else: a.sons[0]
|
||||||
result = typeRel(c, prev.sons[0], toMatch)
|
result = typeRel(c, prev.sons[0], toMatch)
|
||||||
|
|
||||||
of tyExpr, tyStmt:
|
of tyExpr, tyStmt:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
||||||
of tyProxy:
|
of tyProxy:
|
||||||
result = isEqual
|
result = isEqual
|
||||||
|
|
||||||
else: internalError("typeRel: " & $f.kind)
|
else: internalError("typeRel: " & $f.kind)
|
||||||
|
|
||||||
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
|
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
|
||||||
|
|
|
||||||
|
|
@ -409,7 +409,7 @@ const
|
||||||
"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", "TypeClass",
|
||||||
"ParametricTypeClass", "BuiltInTypeClass",
|
"ParametricTypeClass", "BuiltInTypeClass", "CompositeTypeClass",
|
||||||
"and", "or", "not", "any", "static"]
|
"and", "or", "not", "any", "static"]
|
||||||
|
|
||||||
proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
|
|
@ -604,8 +604,9 @@ type
|
||||||
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
||||||
|
|
||||||
TTypeCmpFlag* = enum
|
TTypeCmpFlag* = enum
|
||||||
IgnoreTupleFields,
|
IgnoreTupleFields
|
||||||
TypeDescExactMatch,
|
ExactTypeDescValues
|
||||||
|
ExactGenericParams
|
||||||
AllowCommonBase
|
AllowCommonBase
|
||||||
|
|
||||||
TTypeCmpFlags* = set[TTypeCmpFlag]
|
TTypeCmpFlags* = set[TTypeCmpFlag]
|
||||||
|
|
@ -646,7 +647,7 @@ proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
|
||||||
result = SameTypeAux(a, b, c)
|
result = SameTypeAux(a, b, c)
|
||||||
|
|
||||||
proc equalParam(a, b: PSym): TParamsEquality =
|
proc equalParam(a, b: PSym): TParamsEquality =
|
||||||
if SameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}) and
|
if SameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}) and
|
||||||
ExprStructuralEquivalent(a.constraint, b.constraint):
|
ExprStructuralEquivalent(a.constraint, b.constraint):
|
||||||
if a.ast == b.ast:
|
if a.ast == b.ast:
|
||||||
result = paramsEqual
|
result = paramsEqual
|
||||||
|
|
@ -682,7 +683,7 @@ proc equalParams(a, b: PNode): TParamsEquality =
|
||||||
return paramsNotEqual # paramsIncompatible;
|
return paramsNotEqual # paramsIncompatible;
|
||||||
# continue traversal! If not equal, we can return immediately; else
|
# continue traversal! If not equal, we can return immediately; else
|
||||||
# it stays incompatible
|
# it stays incompatible
|
||||||
if not SameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {TypeDescExactMatch}):
|
if not SameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {ExactTypeDescValues}):
|
||||||
if (a.sons[0].typ == nil) or (b.sons[0].typ == nil):
|
if (a.sons[0].typ == nil) or (b.sons[0].typ == nil):
|
||||||
result = paramsNotEqual # one proc has a result, the other not is OK
|
result = paramsNotEqual # one proc has a result, the other not is OK
|
||||||
else:
|
else:
|
||||||
|
|
@ -852,12 +853,15 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
result = sameTypeAux(lastSon(a), lastSon(b), c)
|
result = sameTypeAux(lastSon(a), lastSon(b), c)
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
if c.cmp == dcEqIgnoreDistinct: result = false
|
if c.cmp == dcEqIgnoreDistinct: result = false
|
||||||
elif TypeDescExactMatch in c.flags:
|
elif ExactTypeDescValues in c.flags:
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
result = sameChildrenAux(x, y, c) and sameFlags(a, b)
|
result = sameChildrenAux(x, y, c) and sameFlags(a, b)
|
||||||
else:
|
else:
|
||||||
result = sameFlags(a, b)
|
result = sameFlags(a, b)
|
||||||
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
|
of tyGenericParam:
|
||||||
|
result = if ExactGenericParams in c.flags: a.id == b.id
|
||||||
|
else: sameChildrenAux(a, b, c) and sameFlags(a, b)
|
||||||
|
of tyGenericInvokation, tyGenericBody, tySequence,
|
||||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
||||||
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
||||||
tyOrdinal, tyTypeClasses:
|
tyOrdinal, tyTypeClasses:
|
||||||
|
|
|
||||||
30
tests/compile/tcompositetypeclasses.nim
Normal file
30
tests/compile/tcompositetypeclasses.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
template accept(e) =
|
||||||
|
static: assert(compiles(e))
|
||||||
|
|
||||||
|
template reject(e) =
|
||||||
|
static: assert(not compiles(e))
|
||||||
|
|
||||||
|
type
|
||||||
|
TFoo[T, U] = tuple
|
||||||
|
x: T
|
||||||
|
y: U
|
||||||
|
|
||||||
|
TBar[K] = TFoo[K, K]
|
||||||
|
|
||||||
|
TUserClass = int|string
|
||||||
|
|
||||||
|
# TBaz = TBar[TUserClass]
|
||||||
|
|
||||||
|
var
|
||||||
|
vfoo: TFoo[int, string]
|
||||||
|
vbar: TFoo[string, string]
|
||||||
|
|
||||||
|
proc foo(x: TFoo) = echo "foo"
|
||||||
|
proc bar(x: TBar) = echo "bar"
|
||||||
|
# proc baz(x: TBaz) = echo "baz"
|
||||||
|
|
||||||
|
accept(foo(vfoo))
|
||||||
|
accept(bar(vbar))
|
||||||
|
# baz vbar
|
||||||
|
reject(bar(vfoo))
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue