support for matching generic types' procs in generic concepts

This commit is contained in:
Zahary Karadjov
2016-07-31 02:13:32 +03:00
parent 33f4e69759
commit 0a9a878bd3
5 changed files with 145 additions and 11 deletions

View File

@@ -319,11 +319,11 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
result = newIntNode(nkIntLit, 0)
else:
var rhsOrigType = n[2].typ
discard inferTypeClassParam(c, t1, rhsOrigType)
var t2 = rhsOrigType.skipTypes({tyTypeDesc})
maybeLiftType(t2, c, n.info)
var m: TCandidate
initCandidate(c, m, t2)
discard inferTypeClassParam(m, t1, rhsOrigType)
let match = typeRel(m, t2, t1) >= isSubtype # isNone
result = newIntNode(nkIntLit, ord(match))
@@ -912,8 +912,6 @@ const
tyTypeParamsHolders = {tyGenericInst, tyUserTypeClassInst, tyCompositeTypeClass}
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

View File

@@ -1631,8 +1631,12 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
else: discard
if result.len == 1 and result.sons[0].kind != nkDefer:
if result.len == 1 and
c.inTypeClass == 0 and # concept bodies should be preserved as a stmt list
result.sons[0].kind != nkDefer:
result = result.sons[0]
when defined(nimfix):
if result.kind == nkCommentStmt and not result.comment.isNil and
not (result.comment[0] == '#' and result.comment[1] == '#'):

View File

@@ -645,7 +645,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
put(m.bindings, p[1], p[0].typ)
if ff.kind == tyUserTypeClassInst:
result = generateTypeInstance(c, m.bindings, m.call.info, ff)
result = generateTypeInstance(c, m.bindings, ff.sym.info, ff)
else:
result = copyType(ff, ff.owner, true)
@@ -1403,13 +1403,34 @@ proc skipToInferrableParam(tt: PType): PType =
return nil
proc inferTypeClassParam*(c: PContext, f, a: PType): bool =
proc inferTypeClassParam*(m: var TCandidate, f, a: PType): bool =
var c = m.c
if c.inTypeClass == 0: return false
var inferrableType = a.skipToInferrableParam
if inferrableType == nil: return false
inferrableType.assignType f
var inferAs = f
case f.kind
of tyGenericParam:
var prev = PType(idTableGet(m.bindings, f))
if prev != nil: inferAs = prev
of tyFromExpr:
let computedType = tryResolvingStaticExpr(m, f.n).typ
case computedType.kind
of tyTypeDesc:
inferAs = computedType.base
of tyStatic:
inferAs = computedType
else:
localError(f.n.info, errTypeExpected)
else:
discard
inferrableType.assignType inferAs
return true
proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
@@ -1420,7 +1441,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
argType = argType
c = m.c
if inferTypeClassParam(c, f, argType):
if inferTypeClassParam(m, f, argType):
return argSemantized
if tfHasStatic in fMaybeStatic.flags:
@@ -1448,9 +1469,18 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
arg.typ.n = evaluated
argType = arg.typ
var a = argType
var r = typeRel(m, f, a)
var
useTypeLoweringRuleInTypeClass = c.inTypeClass > 0 and
not m.isNoCall and
f.kind != tyTypeDesc
a = if useTypeLoweringRuleInTypeClass:
argType.skipTypes({tyTypeDesc, tyFieldAccessor})
else:
argType
r = typeRel(m, f, a)
if r != isNone and m.calleeSym != nil and
m.calleeSym.kind in {skMacro, skTemplate}:
# XXX: duplicating this is ugly, but we cannot (!) move this

View File

@@ -0,0 +1,102 @@
discard """
output: '''10
10
nil
1'''
msg: '''
K=string V=int
K=int64 V=string
K=int V=int
'''
"""
import tables, typetraits
template ok(check) = assert check
template no(check) = assert(not check)
type
Enumerable[T] = concept e
for v in e:
v is T
Map[K, V] = concept m, var mvar
m[K] is V
mvar[K] = V
m.contains(K) is bool
m.valuesSeq is Enumerable[V]
TreeMap[K, V] = object
root: int
SparseSeq = object
data: seq[int]
JudyArray = object
data: SparseSeq
static:
ok seq[int] is Enumerable[int]
ok seq[string] is Enumerable
ok seq[int] is Enumerable[SomeNumber]
ok SparseSeq.data is Enumerable
no seq[string] is Enumerable[int]
no int is Enumerable
no int is Enumerable[int]
# Complete the map concept implementation for the Table type
proc valuesSeq[K, V](t: Table[K, V]): seq[V] =
result = @[]
for k, v in t:
result.add v
# Map concept inplementation for TreeMap
proc valuesSeq(t: TreeMap): array[1, TreeMap.V] =
var v: t.V
result = [v]
proc contains[K, V](t: TreeMap[K, V], key: K): bool = true
proc `[]=`[K, V](t: var TreeMap[K, V], key: K, val: V) = discard
proc `[]`(t: TreeMap, key: t.K): TreeMap.V = discard
# Map concept implementation for the non-generic JudyArray
proc valuesSeq(j: JudyArray): SparseSeq = j.data
proc contains(t: JudyArray, key: int): bool = true
proc `[]=`(t: var JudyArray, key, val: int) = discard
proc `[]`(t: JudyArray, key: int): int = discard
iterator items(s: SparseSeq): int =
for i in s.data: yield i
# Generic proc defined over map
proc getFirstValue[K,V](m : Map[K,V]): V =
static: echo "K=", K.name, " V=", V.name
for i in m.valuesSeq:
return i
raise newException(RangeError, "no values")
proc useConceptProcInGeneric[K, V](t: Table[K, V]): V =
return t.getFirstValue
var t = initTable[string, int]()
t["test"] = 10
echo t.getFirstValue
echo t.useConceptProcInGeneric
var tm = TreeMap[int64, string](root: 0)
echo getFirstValue(tm)
var j = JudyArray(data: SparseSeq(data: @[1, 2, 3]))
echo getFirstValue(j)
static:
ok Table[int, float] is Map
ok Table[int, string] is Map[SomeNumber, string]
no JudyArray is Map[string, int]

View File

@@ -46,7 +46,7 @@ proc implicitGeneric(s: var Stack): auto =
static:
echo "IMPLICIT INFERRED ", s.T.name, " ", Stack.T.name
echo "IMPLICIT VALUE TYPE ", s.ValueType.name, " ", Stack.ValueType.name
echo "IMPLICIT VALUE TYPE NAME ", s.ValueTypeName, " ", s.ValueTypeName
echo "IMPLICIT VALUE TYPE NAME ", s.ValueTypeName, " ", Stack.ValueTypeName
return s.pop()