support derived values in non-generic user type classes

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

View file

@ -428,6 +428,7 @@ const
tyAnd, tyOr, tyNot, tyAnything} tyAnd, tyOr, tyNot, tyAnything}
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
tyUserTypeClasses* = {tyUserTypeClass, tyUserTypeClassInst}
type type
TTypeKinds* = set[TTypeKind] TTypeKinds* = set[TTypeKind]
@ -471,6 +472,8 @@ type
# can be attached to generic procs with free standing # can be attached to generic procs with free standing
# type parameters: e.g. proc foo[T]() # type parameters: e.g. proc foo[T]()
# depends on unresolved static params. # 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 tfRetType, # marks return types in proc (used to detect type classes
# used as return types for return type inference) # used as return types for return type inference)
tfCapturesEnv, # whether proc really captures some environment 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) rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.s)
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) = 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) if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind case ty.kind
of tyArray: genArrayElem(p, n.sons[0], n.sons[1], d) 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) = proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var a = e.sons[1] var a = e.sons[1]
if a.kind == nkHiddenAddr: a = a.sons[0] if a.kind == nkHiddenAddr: a = a.sons[0]
let typ = skipTypes(a.typ, abstractVar) var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses)
case typ.kind case typ.kind
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)") 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, # castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
# tySequence, tyPointer, tyNil, tyOpenArray, # tySequence, tyPointer, tyNil, tyOpenArray,
# tyProc, tySet, tyEnum, tyBool, tyChar} # tyProc, tySet, tyEnum, tyBool, tyChar}
let src = src.skipTypes(tyUserTypeClasses)
if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray: if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray:
return false return false
if skipTypes(src, abstractInst-{tyTypeDesc}).kind == tyTypeDesc: if skipTypes(src, abstractInst-{tyTypeDesc}).kind == tyTypeDesc:
@ -908,15 +909,36 @@ proc makeDeref(n: PNode): PNode =
t = skipTypes(baseTyp, {tyGenericInst, tyAlias}) t = skipTypes(baseTyp, {tyGenericInst, tyAlias})
const const
tyTypeParamsHolders = {tyGenericInst, tyUserTypeClassInst, tyCompositeTypeClass} tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass,
tyUserTypeClass, tyUserTypeClassInst}
tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias} tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias}
proc readTypeParameter(c: PContext, typ: PType, proc readTypeParameter(c: PContext, typ: PType,
paramName: PIdent, info: TLineInfo): PNode = paramName: PIdent, info: TLineInfo): PNode =
let ty = if typ.kind in {tyGenericInst, tyUserTypeClassInst}: typ.skipGenericAlias if typ.kind in {tyUserTypeClass, tyUserTypeClassInst}:
else: (internalAssert(typ.kind == tyCompositeTypeClass); for statement in typ.n:
typ.sons[1].skipGenericAlias) case statement.kind
of nkTypeSection:
for def in statement:
if def[0].sym.name.id == paramName.id:
# XXX: Instead of lifting the section type to a typedesc
# here, we could try doing it earlier in semTypeSection.
# 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[0].sym).linkTo(foundType), info)
of nkConstSection:
for def in statement:
if def[0].sym.name.id == paramName.id:
return def[2]
else:
discard
if typ.kind != tyUserTypeClass:
let ty = if typ.kind == tyCompositeTypeClass: typ.sons[1].skipGenericAlias
else: typ.skipGenericAlias
let tbody = ty.sons[0] let tbody = ty.sons[0]
for s in countup(0, tbody.len-2): for s in countup(0, tbody.len-2):
let tParam = tbody.sons[s] let tParam = tbody.sons[s]
@ -928,27 +950,6 @@ proc readTypeParameter(c: PContext, typ: PType,
let foundTyp = makeTypeDesc(c, rawTyp) let foundTyp = makeTypeDesc(c, rawTyp)
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
if ty.n != nil:
for statement in ty.n:
case statement.kind
of nkTypeSection:
for def in statement:
if def[0].sym.name.id == paramName.id:
# XXX: Instead of lifting the section type to a typedesc
# here, we could try doing it earlier in semTypeSection.
# 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)
of nkConstSection:
for def in statement:
if def[0].sym.name.id == paramName.id:
return def[2]
else:
discard
return nil return nil
proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =

View file

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

View file

@ -63,7 +63,7 @@ const
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
tyTypeDesc, tyAlias, tyInferred} tyTypeDesc, tyAlias, tyInferred}
abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias,
tyInferred} tyInferred} + tyTypeClasses
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyTypeDesc, tyAlias, skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyTypeDesc, tyAlias,
tyInferred} tyInferred}
# typedescX is used if we're sure tyTypeDesc should be included (or skipped) # typedescX is used if we're sure tyTypeDesc should be included (or skipped)
@ -417,6 +417,13 @@ const
const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg} 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.} = proc addTypeFlags(name: var string, typ: PType) {.inline.} =
if tfNotNil in typ.flags: name.add(" not nil") 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) & ")" if t.n != nil: result.add "(" & renderTree(t.n) & ")"
of tyUserTypeClass: of tyUserTypeClass:
internalAssert t.sym != nil and t.sym.owner != nil internalAssert t.sym != nil and t.sym.owner != nil
if t.isResolvedUserTypeClass: return typeToString(t.lastSon)
return t.sym.owner.name.s return t.sym.owner.name.s
of tyBuiltInTypeClass: of tyBuiltInTypeClass:
result = case t.base.kind: result = case t.base.kind:
@ -1314,12 +1322,15 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
result = align(result, a) result = align(result, a)
of tyGenericInst, tyDistinct, tyGenericBody, tyAlias: of tyGenericInst, tyDistinct, tyGenericBody, tyAlias:
result = computeSizeAux(lastSon(typ), a) result = computeSizeAux(lastSon(typ), a)
of tyTypeClasses:
result = if typ.isResolvedUserTypeClass: computeSizeAux(typ.lastSon, a)
else: szUnknownSize
of tyTypeDesc: of tyTypeDesc:
result = computeSizeAux(typ.base, a) result = computeSizeAux(typ.base, a)
of tyForward: return szIllegalRecursion of tyForward: return szIllegalRecursion
of tyStatic: of tyStatic:
if typ.n != nil: result = computeSizeAux(lastSon(typ), a) result = if typ.n != nil: computeSizeAux(typ.lastSon, a)
else: result = szUnknownSize else: szUnknownSize
else: else:
#internalError("computeSizeAux()") #internalError("computeSizeAux()")
result = szUnknownSize result = szUnknownSize
@ -1492,9 +1503,6 @@ proc isEmptyContainer*(t: PType): bool =
of tyGenericInst, tyAlias: result = isEmptyContainer(t.lastSon) of tyGenericInst, tyAlias: result = isEmptyContainer(t.lastSon)
else: result = false 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 = proc takeType*(formal, arg: PType): PType =
# param: openArray[string] = [] # param: openArray[string] = []
# [] is an array constructor of length 0 of type 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) result.add mapTypeToAst(t.sons[i], info)
else: else:
result = mapTypeToAstX(t.lastSon, info, inst, allowRecursion) result = mapTypeToAstX(t.lastSon, info, inst, allowRecursion)
of tyGenericBody, tyOrdinal, tyUserTypeClassInst: of tyGenericBody, tyOrdinal:
result = mapTypeToAst(t.lastSon, info) result = mapTypeToAst(t.lastSon, info)
of tyDistinct: of tyDistinct:
if inst: if inst:
@ -285,7 +285,10 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
of tyProxy: result = atomicType("error", mNone) of tyProxy: result = atomicType("error", mNone)
of tyBuiltInTypeClass: of tyBuiltInTypeClass:
result = mapTypeToBracket("builtinTypeClass", mNone, t, info) result = mapTypeToBracket("builtinTypeClass", mNone, t, info)
of tyUserTypeClass: of tyUserTypeClass, tyUserTypeClassInst:
if t.isResolvedUserTypeClass:
result = mapTypeToAst(t.lastSon, info)
else:
result = mapTypeToBracket("concept", mNone, t, info) result = mapTypeToBracket("concept", mNone, t, info)
result.add t.n.copyTree result.add t.n.copyTree
of tyCompositeTypeClass: of tyCompositeTypeClass:

View file

@ -2,6 +2,8 @@ discard """
output: '''Sortable output: '''Sortable
Sortable Sortable
Container Container
TObj
int
''' '''
""" """
@ -79,6 +81,9 @@ proc ptrproc(x: ptr TObj, y: string) = discard
proc staticproc(x: static[TObj]) = discard proc staticproc(x: static[TObj]) = discard
proc typeproc(t: type 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)) testFoo(TObj(x: 10))