implemented generic converters
This commit is contained in:
parent
7171ae62cb
commit
38ab30d153
7 changed files with 89 additions and 7 deletions
|
|
@ -84,6 +84,16 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
|
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
|
||||||
args])
|
args])
|
||||||
|
|
||||||
|
proc instantiateGenericConverters(c: PContext, n: PNode, x: TCandidate) {.
|
||||||
|
noinline.}=
|
||||||
|
for i in 1 .. <n.len:
|
||||||
|
var a = n.sons[i]
|
||||||
|
if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym and
|
||||||
|
isGenericRoutine(a.sons[0].sym):
|
||||||
|
let finalCallee = generateInstance(c, a.sons[0].sym, x.bindings, n.info)
|
||||||
|
a.sons[0].sym = finalCallee
|
||||||
|
a.sons[0].typ = finalCallee.typ
|
||||||
|
|
||||||
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||||
assert x.state == csMatch
|
assert x.state == csMatch
|
||||||
var finalCallee = x.calleeSym
|
var finalCallee = x.calleeSym
|
||||||
|
|
@ -101,6 +111,8 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||||
if ContainsGenericType(result.typ): result.typ = errorType(c)
|
if ContainsGenericType(result.typ): result.typ = errorType(c)
|
||||||
return
|
return
|
||||||
result = x.call
|
result = x.call
|
||||||
|
if x.genericConverter:
|
||||||
|
instantiateGenericConverters(c, result, x)
|
||||||
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
|
||||||
result.typ = finalCallee.typ.sons[0]
|
result.typ = finalCallee.typ.sons[0]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -869,8 +869,8 @@ proc semMethod(c: PContext, n: PNode): PNode =
|
||||||
proc semConverterDef(c: PContext, n: PNode): PNode =
|
proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
|
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
|
||||||
checkSonsLen(n, bodyPos + 1)
|
checkSonsLen(n, bodyPos + 1)
|
||||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
#if n.sons[genericParamsPos].kind != nkEmpty:
|
||||||
LocalError(n.info, errNoGenericParamsAllowedForX, "converter")
|
# LocalError(n.info, errNoGenericParamsAllowedForX, "converter")
|
||||||
result = semProcAux(c, n, skConverter, converterPragmas)
|
result = semProcAux(c, n, skConverter, converterPragmas)
|
||||||
var s = result.sons[namePos].sym
|
var s = result.sons[namePos].sym
|
||||||
var t = s.typ
|
var t = s.typ
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ type
|
||||||
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
||||||
# for example
|
# for example
|
||||||
proxyMatch*: bool # to prevent instantiations
|
proxyMatch*: bool # to prevent instantiations
|
||||||
|
genericConverter*: bool # true if a generic converter needs to
|
||||||
|
# be instantiated
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
|
|
@ -57,6 +59,7 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||||
c.callee = callee
|
c.callee = callee
|
||||||
c.call = nil
|
c.call = nil
|
||||||
c.baseTypeMatch = false
|
c.baseTypeMatch = false
|
||||||
|
c.genericConverter = false
|
||||||
c.inheritancePenalty = 0
|
c.inheritancePenalty = 0
|
||||||
|
|
||||||
proc initCandidate*(c: var TCandidate, callee: PType) =
|
proc initCandidate*(c: var TCandidate, callee: PType) =
|
||||||
|
|
@ -571,16 +574,26 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
for i in countup(0, len(c.converters) - 1):
|
for i in countup(0, len(c.converters) - 1):
|
||||||
var src = c.converters[i].typ.sons[1]
|
var src = c.converters[i].typ.sons[1]
|
||||||
var dest = c.converters[i].typ.sons[0]
|
var dest = c.converters[i].typ.sons[0]
|
||||||
if (typeRel(m, f, dest) == isEqual) and
|
# for generic type converters we need to check 'src <- a' before
|
||||||
(typeRel(m, src, a) == isEqual):
|
# 'f <- dest' in order to not break the unification:
|
||||||
|
# see tests/tgenericconverter:
|
||||||
|
let srca = typeRel(m, src, a)
|
||||||
|
if srca notin {isEqual, isGeneric}: continue
|
||||||
|
|
||||||
|
let destIsGeneric = containsGenericType(dest)
|
||||||
|
if destIsGeneric:
|
||||||
|
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
||||||
|
let fdest = typeRel(m, f, dest)
|
||||||
|
if fdest in {isEqual, isGeneric}:
|
||||||
markUsed(arg, c.converters[i])
|
markUsed(arg, c.converters[i])
|
||||||
var s = newSymNode(c.converters[i])
|
var s = newSymNode(c.converters[i])
|
||||||
s.typ = c.converters[i].typ
|
s.typ = c.converters[i].typ
|
||||||
s.info = arg.info
|
s.info = arg.info
|
||||||
result = newNodeIT(nkHiddenCallConv, arg.info, s.typ.sons[0])
|
result = newNodeIT(nkHiddenCallConv, arg.info, dest)
|
||||||
addSon(result, s)
|
addSon(result, s)
|
||||||
addSon(result, copyTree(arg))
|
addSon(result, copyTree(arg))
|
||||||
inc(m.convMatches)
|
inc(m.convMatches)
|
||||||
|
m.genericConverter = srca == isGeneric or destIsGeneric
|
||||||
return
|
return
|
||||||
|
|
||||||
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
|
|
|
||||||
28
tests/compile/tsecondarrayproperty.nim
Normal file
28
tests/compile/tsecondarrayproperty.nim
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
type
|
||||||
|
TFoo = object
|
||||||
|
data: array[0..100, int]
|
||||||
|
TSecond = distinct TFoo
|
||||||
|
|
||||||
|
proc `[]` (self: var TFoo, x: int): var int =
|
||||||
|
return self.data[x]
|
||||||
|
|
||||||
|
proc `[]=` (self: var TFoo, x, y: int) =
|
||||||
|
# only `[]` returning a 'var T' seems to not work for now :-/
|
||||||
|
self.data[x] = y
|
||||||
|
|
||||||
|
proc second(self: var TFoo): var TSecond =
|
||||||
|
return TSecond(self)
|
||||||
|
|
||||||
|
proc `[]`(self: var TSecond, x: int): var int =
|
||||||
|
return TFoo(self).data[2*x]
|
||||||
|
|
||||||
|
var f: TFoo
|
||||||
|
|
||||||
|
for i in 0..f.data.high: f[i] = 2 * i
|
||||||
|
|
||||||
|
echo f.second[1]
|
||||||
|
|
||||||
|
#echo `second[]`(f,1)
|
||||||
|
# this is the only way I could use it, but not what I expected
|
||||||
|
|
||||||
30
tests/run/tgenericconverter.nim
Normal file
30
tests/run/tgenericconverter.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
discard """
|
||||||
|
output: '''666
|
||||||
|
666'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# test the new generic converters:
|
||||||
|
|
||||||
|
type
|
||||||
|
TFoo2[T] = object
|
||||||
|
x: T
|
||||||
|
|
||||||
|
TFoo[T] = object
|
||||||
|
data: array[0..100, T]
|
||||||
|
|
||||||
|
converter toFoo[T](a: TFoo2[T]): TFoo[T] =
|
||||||
|
result.data[0] = a.x
|
||||||
|
|
||||||
|
proc p(a: TFoo[int]) =
|
||||||
|
echo a.data[0]
|
||||||
|
|
||||||
|
proc q[T](a: TFoo[T]) =
|
||||||
|
echo a.data[0]
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
aa: TFoo2[int]
|
||||||
|
aa.x = 666
|
||||||
|
|
||||||
|
p aa
|
||||||
|
q aa
|
||||||
2
todo.txt
2
todo.txt
|
|
@ -2,8 +2,6 @@ version 0.9.2
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- overloading based on ASTs
|
- overloading based on ASTs
|
||||||
- implement generic converters
|
|
||||||
|
|
||||||
- implement ``partial`` pragma for partial evaluation: easily done with AST
|
- implement ``partial`` pragma for partial evaluation: easily done with AST
|
||||||
overloading
|
overloading
|
||||||
- ``hoist`` pragma for loop hoisting: can be easily done with
|
- ``hoist`` pragma for loop hoisting: can be easily done with
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ Compiler Additions
|
||||||
- The compiler can now warn about shadowed local variables. However, this needs
|
- The compiler can now warn about shadowed local variables. However, this needs
|
||||||
to be turned on explicitly via ``--warning[ShadowIdent]:on``.
|
to be turned on explicitly via ``--warning[ShadowIdent]:on``.
|
||||||
- The compiler now supports almost every pragma in a ``push`` pragma.
|
- The compiler now supports almost every pragma in a ``push`` pragma.
|
||||||
|
- Generic converters have been implemented.
|
||||||
|
|
||||||
|
|
||||||
Language Additions
|
Language Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue