support derived values in non-generic user type classes

This commit is contained in:
Zahary Karadjov
2016-08-11 09:09:15 +03:00
parent 77a4512ae8
commit 0b0a3e5f20
7 changed files with 59 additions and 47 deletions

View File

@@ -428,6 +428,7 @@ const
tyAnd, tyOr, tyNot, tyAnything}
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
tyUserTypeClasses* = {tyUserTypeClass, tyUserTypeClassInst}
type
TTypeKinds* = set[TTypeKind]
@@ -471,6 +472,8 @@ type
# can be attached to generic procs with free standing
# type parameters: e.g. proc foo[T]()
# depends on unresolved static params.
tfResolved # marks a user type class, after it has been bound to a
# concrete type (lastSon becomes the concrete type)
tfRetType, # marks return types in proc (used to detect type classes
# used as return types for return type inference)
tfCapturesEnv, # whether proc really captures some environment

View File

@@ -890,7 +890,7 @@ proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.s)
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
var ty = skipTypes(n.sons[0].typ, abstractVarRange + tyUserTypeClasses)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind
of tyArray: genArrayElem(p, n.sons[0], n.sons[1], d)
@@ -1359,7 +1359,7 @@ proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var a = e.sons[1]
if a.kind == nkHiddenAddr: a = a.sons[0]
let typ = skipTypes(a.typ, abstractVar)
var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses)
case typ.kind
of tyOpenArray, tyVarargs:
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")

View File

@@ -136,6 +136,7 @@ proc isCastable(dst, src: PType): bool =
# castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
# tySequence, tyPointer, tyNil, tyOpenArray,
# tyProc, tySet, tyEnum, tyBool, tyChar}
let src = src.skipTypes(tyUserTypeClasses)
if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray:
return false
if skipTypes(src, abstractInst-{tyTypeDesc}).kind == tyTypeDesc:
@@ -908,28 +909,14 @@ proc makeDeref(n: PNode): PNode =
t = skipTypes(baseTyp, {tyGenericInst, tyAlias})
const
tyTypeParamsHolders = {tyGenericInst, tyUserTypeClassInst, tyCompositeTypeClass}
tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass,
tyUserTypeClass, tyUserTypeClassInst}
tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias}
proc readTypeParameter(c: PContext, typ: PType,
paramName: PIdent, info: TLineInfo): PNode =
let ty = if typ.kind in {tyGenericInst, tyUserTypeClassInst}: typ.skipGenericAlias
else: (internalAssert(typ.kind == tyCompositeTypeClass);
typ.sons[1].skipGenericAlias)
let tbody = ty.sons[0]
for s in countup(0, tbody.len-2):
let tParam = tbody.sons[s]
if tParam.sym.name.id == paramName.id:
let rawTyp = ty.sons[s + 1]
if rawTyp.kind == tyStatic:
return rawTyp.n
else:
let foundTyp = makeTypeDesc(c, rawTyp)
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
if ty.n != nil:
for statement in ty.n:
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst}:
for statement in typ.n:
case statement.kind
of nkTypeSection:
for def in statement:
@@ -939,7 +926,7 @@ proc readTypeParameter(c: PContext, typ: PType,
# This seems semantically correct and then we'll be able
# to return the section symbol directly here
let foundType = makeTypeDesc(c, def[2].typ)
return newSymNode(copySym(def[2].sym).linkTo(foundType), info)
return newSymNode(copySym(def[0].sym).linkTo(foundType), info)
of nkConstSection:
for def in statement:
@@ -948,6 +935,20 @@ proc readTypeParameter(c: PContext, typ: PType,
else:
discard
if typ.kind != tyUserTypeClass:
let ty = if typ.kind == tyCompositeTypeClass: typ.sons[1].skipGenericAlias
else: typ.skipGenericAlias
let tbody = ty.sons[0]
for s in countup(0, tbody.len-2):
let tParam = tbody.sons[s]
if tParam.sym.name.id == paramName.id:
let rawTyp = ty.sons[s + 1]
if rawTyp.kind == tyStatic:
return rawTyp.n
else:
let foundTyp = makeTypeDesc(c, rawTyp)
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
return nil

View File

@@ -1197,22 +1197,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else:
return isNone
of tyUserTypeClass:
considerPreviousT:
of tyUserTypeClassInst, tyUserTypeClass:
if f.isResolvedUserTypeClass:
result = typeRel(c, f.lastSon, a)
else:
var matched = matchUserTypeClass(c.c, c, f, aOrig)
if matched != nil:
# TODO, make user type classes skipable too
put(c, f, a)
result = isGeneric
else:
result = isNone
of tyUserTypeClassInst:
considerPreviousT:
var matched = matchUserTypeClass(c.c, c, f, aOrig)
if matched != nil:
matched.sons.add a
put(c.bindings, f, matched)
bindConcreteTypeToUserTypeClass(matched, a)
put(c, f, matched)
result = isGeneric
else:
result = isNone

View File

@@ -63,7 +63,7 @@ const
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
tyTypeDesc, tyAlias, tyInferred}
abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias,
tyInferred}
tyInferred} + tyTypeClasses
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyTypeDesc, tyAlias,
tyInferred}
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
@@ -417,6 +417,13 @@ const
const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
tc.sons.safeAdd concrete
tc.flags.incl tfResolved
template isResolvedUserTypeClass*(t: PType): bool =
tfResolved in t.flags
proc addTypeFlags(name: var string, typ: PType) {.inline.} =
if tfNotNil in typ.flags: name.add(" not nil")
@@ -461,6 +468,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if t.n != nil: result.add "(" & renderTree(t.n) & ")"
of tyUserTypeClass:
internalAssert t.sym != nil and t.sym.owner != nil
if t.isResolvedUserTypeClass: return typeToString(t.lastSon)
return t.sym.owner.name.s
of tyBuiltInTypeClass:
result = case t.base.kind:
@@ -1314,12 +1322,15 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
result = align(result, a)
of tyGenericInst, tyDistinct, tyGenericBody, tyAlias:
result = computeSizeAux(lastSon(typ), a)
of tyTypeClasses:
result = if typ.isResolvedUserTypeClass: computeSizeAux(typ.lastSon, a)
else: szUnknownSize
of tyTypeDesc:
result = computeSizeAux(typ.base, a)
of tyForward: return szIllegalRecursion
of tyStatic:
if typ.n != nil: result = computeSizeAux(lastSon(typ), a)
else: result = szUnknownSize
result = if typ.n != nil: computeSizeAux(typ.lastSon, a)
else: szUnknownSize
else:
#internalError("computeSizeAux()")
result = szUnknownSize
@@ -1492,9 +1503,6 @@ proc isEmptyContainer*(t: PType): bool =
of tyGenericInst, tyAlias: result = isEmptyContainer(t.lastSon)
else: result = false
proc isResolvedUserTypeClass*(t: PType): bool =
t.kind in {tyUserTypeClassInst} and t.base.sonsLen == t.sonsLen - 2
proc takeType*(formal, arg: PType): PType =
# param: openArray[string] = []
# [] is an array constructor of length 0 of type string!

View File

@@ -175,7 +175,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
result.add mapTypeToAst(t.sons[i], info)
else:
result = mapTypeToAstX(t.lastSon, info, inst, allowRecursion)
of tyGenericBody, tyOrdinal, tyUserTypeClassInst:
of tyGenericBody, tyOrdinal:
result = mapTypeToAst(t.lastSon, info)
of tyDistinct:
if inst:
@@ -285,9 +285,12 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
of tyProxy: result = atomicType("error", mNone)
of tyBuiltInTypeClass:
result = mapTypeToBracket("builtinTypeClass", mNone, t, info)
of tyUserTypeClass:
result = mapTypeToBracket("concept", mNone, t, info)
result.add t.n.copyTree
of tyUserTypeClass, tyUserTypeClassInst:
if t.isResolvedUserTypeClass:
result = mapTypeToAst(t.lastSon, info)
else:
result = mapTypeToBracket("concept", mNone, t, info)
result.add t.n.copyTree
of tyCompositeTypeClass:
result = mapTypeToBracket("compositeTypeClass", mNone, t, info)
of tyAnd: result = mapTypeToBracket("and", mAnd, t, info)

View File

@@ -2,6 +2,8 @@ discard """
output: '''Sortable
Sortable
Container
TObj
int
'''
"""
@@ -20,7 +22,7 @@ type
C.len is Ordinal
for v in items(C):
v.type is tuple|object
proc foo(c: ObjectContainer) =
echo "Container"
@@ -79,6 +81,9 @@ proc ptrproc(x: ptr TObj, y: string) = discard
proc staticproc(x: static[TObj]) = discard
proc typeproc(t: type TObj) = discard
proc testFoo(x: TFoo) = discard
proc testFoo(x: TFoo) =
echo x.TypeName
echo x.MappedType.name
testFoo(TObj(x: 10))