diff options
author | Araq <rumpf_a@web.de> | 2012-12-05 22:03:36 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-12-05 22:03:36 +0100 |
commit | 38ab30d153f7ae3b1b2b74329092ffb7ca781ead (patch) | |
tree | d39dc114db80ccdd50534dbf26f9133ef119405a /compiler | |
parent | 7171ae62cb94bf5e7ed426ec0679e4247c993121 (diff) | |
download | Nim-38ab30d153f7ae3b1b2b74329092ffb7ca781ead.tar.gz |
implemented generic converters
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/semcall.nim | 12 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 4 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 19 |
3 files changed, 30 insertions, 5 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim index a5107bf64..962e4d3cc 100755 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -84,6 +84,16 @@ proc resolveOverloads(c: PContext, n, orig: PNode, getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym), 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 = assert x.state == csMatch 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) return result = x.call + if x.genericConverter: + instantiateGenericConverters(c, result, x) result.sons[0] = newSymNode(finalCallee, result.sons[0].info) result.typ = finalCallee.typ.sons[0] diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d68d0da1a..c5b226004 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -869,8 +869,8 @@ proc semMethod(c: PContext, n: PNode): PNode = proc semConverterDef(c: PContext, n: PNode): PNode = if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter") checkSonsLen(n, bodyPos + 1) - if n.sons[genericParamsPos].kind != nkEmpty: - LocalError(n.info, errNoGenericParamsAllowedForX, "converter") + #if n.sons[genericParamsPos].kind != nkEmpty: + # LocalError(n.info, errNoGenericParamsAllowedForX, "converter") result = semProcAux(c, n, skConverter, converterPragmas) var s = result.sons[namePos].sym var t = s.typ diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 8913b6d5d..c48434eb7 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -33,6 +33,8 @@ type baseTypeMatch: bool # needed for conversions from T to openarray[T] # for example proxyMatch*: bool # to prevent instantiations + genericConverter*: bool # true if a generic converter needs to + # be instantiated inheritancePenalty: int # to prefer closest father object type TTypeRelation* = enum # order is important! @@ -57,6 +59,7 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} = c.callee = callee c.call = nil c.baseTypeMatch = false + c.genericConverter = false c.inheritancePenalty = 0 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): var src = c.converters[i].typ.sons[1] var dest = c.converters[i].typ.sons[0] - if (typeRel(m, f, dest) == isEqual) and - (typeRel(m, src, a) == isEqual): + # for generic type converters we need to check 'src <- a' before + # '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]) var s = newSymNode(c.converters[i]) s.typ = c.converters[i].typ s.info = arg.info - result = newNodeIT(nkHiddenCallConv, arg.info, s.typ.sons[0]) + result = newNodeIT(nkHiddenCallConv, arg.info, dest) addSon(result, s) addSon(result, copyTree(arg)) inc(m.convMatches) + m.genericConverter = srca == isGeneric or destIsGeneric return proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, |