support derived values in non-generic user type classes
This commit is contained in:
parent
77a4512ae8
commit
0b0a3e5f20
7 changed files with 59 additions and 47 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)")
|
||||||
|
|
|
||||||
|
|
@ -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,28 +909,14 @@ 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)
|
|
||||||
|
|
||||||
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:
|
|
||||||
case statement.kind
|
case statement.kind
|
||||||
of nkTypeSection:
|
of nkTypeSection:
|
||||||
for def in statement:
|
for def in statement:
|
||||||
|
|
@ -939,7 +926,7 @@ proc readTypeParameter(c: PContext, typ: PType,
|
||||||
# This seems semantically correct and then we'll be able
|
# This seems semantically correct and then we'll be able
|
||||||
# to return the section symbol directly here
|
# to return the section symbol directly here
|
||||||
let foundType = makeTypeDesc(c, def[2].typ)
|
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:
|
of nkConstSection:
|
||||||
for def in statement:
|
for def in statement:
|
||||||
|
|
@ -948,6 +935,20 @@ proc readTypeParameter(c: PContext, typ: PType,
|
||||||
|
|
||||||
else:
|
else:
|
||||||
discard
|
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
|
return nil
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
result = typeRel(c, f.lastSon, a)
|
||||||
|
else:
|
||||||
var matched = matchUserTypeClass(c.c, c, f, aOrig)
|
var matched = matchUserTypeClass(c.c, c, f, aOrig)
|
||||||
if matched != nil:
|
if matched != nil:
|
||||||
# TODO, make user type classes skipable too
|
bindConcreteTypeToUserTypeClass(matched, a)
|
||||||
put(c, f, a)
|
put(c, f, matched)
|
||||||
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)
|
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
|
||||||
|
|
@ -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!
|
||||||
|
|
|
||||||
|
|
@ -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,9 +285,12 @@ 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:
|
||||||
result = mapTypeToBracket("concept", mNone, t, info)
|
if t.isResolvedUserTypeClass:
|
||||||
result.add t.n.copyTree
|
result = mapTypeToAst(t.lastSon, info)
|
||||||
|
else:
|
||||||
|
result = mapTypeToBracket("concept", mNone, t, info)
|
||||||
|
result.add t.n.copyTree
|
||||||
of tyCompositeTypeClass:
|
of tyCompositeTypeClass:
|
||||||
result = mapTypeToBracket("compositeTypeClass", mNone, t, info)
|
result = mapTypeToBracket("compositeTypeClass", mNone, t, info)
|
||||||
of tyAnd: result = mapTypeToBracket("and", mAnd, t, info)
|
of tyAnd: result = mapTypeToBracket("and", mAnd, t, info)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ discard """
|
||||||
output: '''Sortable
|
output: '''Sortable
|
||||||
Sortable
|
Sortable
|
||||||
Container
|
Container
|
||||||
|
TObj
|
||||||
|
int
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -20,7 +22,7 @@ type
|
||||||
C.len is Ordinal
|
C.len is Ordinal
|
||||||
for v in items(C):
|
for v in items(C):
|
||||||
v.type is tuple|object
|
v.type is tuple|object
|
||||||
|
|
||||||
proc foo(c: ObjectContainer) =
|
proc foo(c: ObjectContainer) =
|
||||||
echo "Container"
|
echo "Container"
|
||||||
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue