concept type params inference working in basic examples
This commit is contained in:
parent
0d8a503e45
commit
66e0f0e19c
5 changed files with 93 additions and 2 deletions
|
|
@ -482,6 +482,7 @@ type
|
||||||
tfHasStatic
|
tfHasStatic
|
||||||
tfGenericTypeParam
|
tfGenericTypeParam
|
||||||
tfImplicitTypeParam
|
tfImplicitTypeParam
|
||||||
|
tfInferrableTypeClassTypeParam
|
||||||
tfWildcard # consider a proc like foo[T, I](x: Type[T, I])
|
tfWildcard # consider a proc like foo[T, I](x: Type[T, I])
|
||||||
# T and I here can bind to both typedesc and static types
|
# T and I here can bind to both typedesc and static types
|
||||||
# before this is determined, we'll consider them to be a
|
# before this is determined, we'll consider them to be a
|
||||||
|
|
|
||||||
|
|
@ -318,7 +318,9 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
result = newIntNode(nkIntLit, 0)
|
result = newIntNode(nkIntLit, 0)
|
||||||
else:
|
else:
|
||||||
var t2 = n[2].typ.skipTypes({tyTypeDesc})
|
var rhsOrigType = n[2].typ
|
||||||
|
discard inferTypeClassParam(c, t1, rhsOrigType)
|
||||||
|
var t2 = rhsOrigType.skipTypes({tyTypeDesc})
|
||||||
maybeLiftType(t2, c, n.info)
|
maybeLiftType(t2, c, n.info)
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
initCandidate(c, m, t2)
|
initCandidate(c, m, t2)
|
||||||
|
|
|
||||||
|
|
@ -883,7 +883,8 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
for i in 1 .. <paramType.len:
|
for i in 1 .. <paramType.len:
|
||||||
let lifted = liftingWalk(paramType.sons[i])
|
let lifted = liftingWalk(paramType.sons[i])
|
||||||
if lifted != nil: paramType.sons[i] = lifted
|
if lifted != nil: paramType.sons[i] = lifted
|
||||||
when false:
|
|
||||||
|
if paramType.base.lastSon.kind == tyUserTypeClass:
|
||||||
let expanded = instGenericContainer(c, info, paramType,
|
let expanded = instGenericContainer(c, info, paramType,
|
||||||
allowMetaTypes = true)
|
allowMetaTypes = true)
|
||||||
result = liftingWalk(expanded, true)
|
result = liftingWalk(expanded, true)
|
||||||
|
|
|
||||||
|
|
@ -585,6 +585,8 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
dec c.inTypeClass
|
dec c.inTypeClass
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
|
var typeParams: seq[(PSym, PType)]
|
||||||
|
|
||||||
if ff.kind == tyUserTypeClassInst:
|
if ff.kind == tyUserTypeClassInst:
|
||||||
for i in 1 .. <(ff.len - 1):
|
for i in 1 .. <(ff.len - 1):
|
||||||
var
|
var
|
||||||
|
|
@ -607,7 +609,12 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
param = paramSym skType
|
param = paramSym skType
|
||||||
param.typ = makeTypeDesc(c, typ)
|
param.typ = makeTypeDesc(c, typ)
|
||||||
|
|
||||||
|
if typ.isMetaType:
|
||||||
|
param.typ.flags.incl tfInferrableTypeClassTypeParam
|
||||||
|
|
||||||
addDecl(c, param)
|
addDecl(c, param)
|
||||||
|
typeParams.safeAdd((param, typ))
|
||||||
|
|
||||||
#echo "A ", param.name.s, " ", typeToString(param.typ), " ", param.kind
|
#echo "A ", param.name.s, " ", typeToString(param.typ), " ", param.kind
|
||||||
|
|
||||||
for param in body.n[0]:
|
for param in body.n[0]:
|
||||||
|
|
@ -630,6 +637,13 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
|
|
||||||
var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
|
var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
|
||||||
if checkedBody == nil: return isNone
|
if checkedBody == nil: return isNone
|
||||||
|
|
||||||
|
# The inferrable type params have been identified during the semTryExpr above.
|
||||||
|
# We need to put them in the current sigmatch's binding table in order for them
|
||||||
|
# to be resolvable while matching the rest of the parameters
|
||||||
|
for p in typeParams:
|
||||||
|
put(m.bindings, p[0].typ, p[1])
|
||||||
|
|
||||||
return isGeneric
|
return isGeneric
|
||||||
|
|
||||||
proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
|
proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
|
||||||
|
|
@ -1355,6 +1369,27 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
|
||||||
of isEqual: inc(m.exactMatches)
|
of isEqual: inc(m.exactMatches)
|
||||||
of isNone: discard
|
of isNone: discard
|
||||||
|
|
||||||
|
proc skipToInferrableParam(tt: PType): PType =
|
||||||
|
var t = tt
|
||||||
|
while t != nil:
|
||||||
|
if tfInferrableTypeClassTypeParam in t.flags:
|
||||||
|
return t
|
||||||
|
if t.sonsLen > 0 and t.kind == tyTypeDesc:
|
||||||
|
t = t.base
|
||||||
|
else:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
proc inferTypeClassParam*(c: PContext, f, a: PType): bool =
|
||||||
|
if c.inTypeClass == 0: return false
|
||||||
|
|
||||||
|
var inferrableType = a.skipToInferrableParam
|
||||||
|
if inferrableType == nil: return false
|
||||||
|
|
||||||
|
inferrableType.assignType f
|
||||||
|
return true
|
||||||
|
|
||||||
proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
argSemantized, argOrig: PNode): PNode =
|
argSemantized, argOrig: PNode): PNode =
|
||||||
var
|
var
|
||||||
|
|
@ -1363,6 +1398,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
argType = argType
|
argType = argType
|
||||||
c = m.c
|
c = m.c
|
||||||
|
|
||||||
|
if inferTypeClassParam(c, f, argType):
|
||||||
|
return argSemantized
|
||||||
|
|
||||||
if tfHasStatic in fMaybeStatic.flags:
|
if tfHasStatic in fMaybeStatic.flags:
|
||||||
# XXX: When implicit statics are the default
|
# XXX: When implicit statics are the default
|
||||||
# this will be done earlier - we just have to
|
# this will be done earlier - we just have to
|
||||||
|
|
|
||||||
49
tests/concepts/tstackconcept.nim
Normal file
49
tests/concepts/tstackconcept.nim
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
discard """
|
||||||
|
output: "20\n10"
|
||||||
|
msg: '''
|
||||||
|
INFERRED int
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
template reject(e: expr) =
|
||||||
|
static: assert(not compiles(e))
|
||||||
|
|
||||||
|
type
|
||||||
|
ArrayStack = object
|
||||||
|
data: seq[int]
|
||||||
|
|
||||||
|
proc push(s: var ArrayStack, item: int) =
|
||||||
|
s.data.add item
|
||||||
|
|
||||||
|
proc pop(s: var ArrayStack): int =
|
||||||
|
return s.data.pop()
|
||||||
|
|
||||||
|
type
|
||||||
|
Stack[T] = concept var s
|
||||||
|
s.push(T)
|
||||||
|
s.pop() is T
|
||||||
|
|
||||||
|
proc genericAlgorithm[T](s: var Stack[T], y: T) =
|
||||||
|
static: echo "INFERRED ", T.name
|
||||||
|
|
||||||
|
s.push(y)
|
||||||
|
echo s.pop
|
||||||
|
|
||||||
|
proc implicitGeneric(s: var Stack): auto =
|
||||||
|
# static: echo "IMPLICIT INFERRED ", s.T.name, " ", Stack.T.name
|
||||||
|
|
||||||
|
return s.pop()
|
||||||
|
|
||||||
|
var s = ArrayStack(data: @[])
|
||||||
|
|
||||||
|
s.push 10
|
||||||
|
s.genericAlgorithm 20
|
||||||
|
echo s.implicitGeneric
|
||||||
|
|
||||||
|
reject s.genericAlgorithm "x"
|
||||||
|
reject s.genericAlgorithm 1.0
|
||||||
|
reject "str".implicitGeneric
|
||||||
|
reject implicitGeneric(10)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue