quite messy implementation of generic lambdas, needs reworking; fixes #715

This commit is contained in:
Zahary Karadjov 2014-02-17 00:59:18 +02:00
commit 9dd753f218
9 changed files with 87 additions and 27 deletions

View file

@ -333,6 +333,7 @@ proc myOpen(module: PSym): PPassContext =
c.semOperand = semOperand c.semOperand = semOperand
c.semConstBoolExpr = semConstBoolExpr c.semConstBoolExpr = semConstBoolExpr
c.semOverloadedCall = semOverloadedCall c.semOverloadedCall = semOverloadedCall
c.semInferredLambda = semInferredLambda
c.semGenerateInstance = generateInstance c.semGenerateInstance = generateInstance
c.semTypeNode = semTypeNode c.semTypeNode = semTypeNode
pushProcCon(c, module) pushProcCon(c, module)

View file

@ -81,6 +81,7 @@ type
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
filter: TSymKinds): PNode {.nimcall.} filter: TSymKinds): PNode {.nimcall.}
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.} semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable, semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym info: TLineInfo): PSym
includedFiles*: TIntSet # used to detect recursive include files includedFiles*: TIntSet # used to detect recursive include files

View file

@ -1829,8 +1829,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = symChoice(c, n, s, scClosed) result = symChoice(c, n, s, scClosed)
if result.kind == nkSym: if result.kind == nkSym:
markIndirect(c, result.sym) markIndirect(c, result.sym)
if isGenericRoutine(result.sym): # if isGenericRoutine(result.sym):
localError(n.info, errInstantiateXExplicitely, s.name.s) # localError(n.info, errInstantiateXExplicitely, s.name.s)
of nkSym: of nkSym:
# because of the changed symbol binding, this does not mean that we # because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again! # don't have to check the symbol for semantics here again!

View file

@ -766,7 +766,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
proc checkForMetaFields(n: PNode) = proc checkForMetaFields(n: PNode) =
template checkMeta(t) = template checkMeta(t) =
if t.isMetaType and tfGenericTypeParam notin t.flags: if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
localError(n.info, errTIsNotAConcreteType, t.typeToString) localError(n.info, errTIsNotAConcreteType, t.typeToString)
case n.kind case n.kind
@ -779,8 +779,9 @@ proc checkForMetaFields(n: PNode) =
case t.kind case t.kind
of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef, of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
tyProc, tyGenericInvokation, tyGenericInst: tyProc, tyGenericInvokation, tyGenericInst:
for s in t.sons: let start = ord(t.kind in {tyGenericInvokation, tyGenericInst})
checkMeta(s) for i in start .. <t.sons.len:
checkMeta(t.sons[i])
else: else:
checkMeta(t) checkMeta(t)
else: else:
@ -907,12 +908,19 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
s = n[namePos].sym s = n[namePos].sym
pushOwner(s) pushOwner(s)
openScope(c) openScope(c)
var gp: PNode
if n.sons[genericParamsPos].kind != nkEmpty: if n.sons[genericParamsPos].kind != nkEmpty:
illFormedAst(n) # process parameters: n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
gp = n.sons[genericParamsPos]
else:
gp = newNodeI(nkGenericParams, n.info)
if n.sons[paramsPos].kind != nkEmpty: if n.sons[paramsPos].kind != nkEmpty:
var gp = newNodeI(nkGenericParams, n.info)
semParamList(c, n.sons[paramsPos], gp, s) semParamList(c, n.sons[paramsPos], gp, s)
paramsTypeCheck(c, s.typ) # paramsTypeCheck(c, s.typ)
if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty:
# we have a list of implicit type parameters:
n.sons[genericParamsPos] = gp
else: else:
s.typ = newTypeS(tyProc, c) s.typ = newTypeS(tyProc, c)
rawAddSon(s.typ, nil) rawAddSon(s.typ, nil)
@ -924,6 +932,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s) localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
#if efDetermineType notin flags: #if efDetermineType notin flags:
# XXX not good enough; see tnamedparamanonproc.nim # XXX not good enough; see tnamedparamanonproc.nim
if n.sons[genericParamsPos].kind == nkEmpty:
pushProcCon(c, s) pushProcCon(c, s)
addResult(c, s.typ.sons[0], n.info, skProc) addResult(c, s.typ.sons[0], n.info, skProc)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
@ -937,6 +946,34 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
popOwner() popOwner()
result.typ = s.typ result.typ = s.typ
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
var n = n
n = replaceTypesInBody(c, pt, n)
result = n
n.sons[genericParamsPos] = emptyNode
n.sons[paramsPos] = n.typ.n
openScope(c)
var s = n.sons[namePos].sym
addParams(c, n.typ.n, skProc)
pushProcCon(c, s)
addResult(c, n.typ.sons[0], n.info, skProc)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym)
addResultNode(c, n)
popProcCon(c)
closeScope(c)
s.ast = result
# alternative variant (not quite working):
# var prc = arg[0].sym
# let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
# result = inferred.ast
# result.kind = arg.kind
proc activate(c: PContext, n: PNode) = proc activate(c: PContext, n: PNode) =
# XXX: This proc is part of my plan for getting rid of # XXX: This proc is part of my plan for getting rid of
# forward declarations. stay tuned. # forward declarations. stay tuned.

View file

@ -29,6 +29,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
localError(info, errVarVarTypeNotAllowed) localError(info, errVarVarTypeNotAllowed)
elif computeSize(t) == szIllegalRecursion: elif computeSize(t) == szIllegalRecursion:
localError(info, errIllegalRecursionInTypeX, typeToString(t)) localError(info, errIllegalRecursionInTypeX, typeToString(t))
when false: when false:
if t.kind == tyObject and t.sons[0] != nil: if t.kind == tyObject and t.sons[0] != nil:
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
@ -409,14 +410,22 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
else: discard else: discard
proc initTypeVars(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars =
initIdTable(result.symMap)
copyIdTable(result.typeMap, pt)
initIdTable(result.localCache)
result.info = info
result.c = p
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode): PNode =
var cl = initTypeVars(p, pt, n.info)
pushInfoContext(n.info)
result = replaceTypeVarsN(cl, n)
popInfoContext()
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo, proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
t: PType): PType = t: PType): PType =
var cl: TReplTypeVars var cl = initTypeVars(p, pt, info)
initIdTable(cl.symMap)
copyIdTable(cl.typeMap, pt)
initIdTable(cl.localCache)
cl.info = info
cl.c = p
pushInfoContext(info) pushInfoContext(info)
result = replaceTypeVarsT(cl, t) result = replaceTypeVarsT(cl, t)
popInfoContext() popInfoContext()

View file

@ -1039,9 +1039,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
#result = copyTree(arg) #result = copyTree(arg)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isInferred, isInferredConvertible: of isInferred, isInferredConvertible:
var prc = if arg.kind in nkLambdaKinds: arg[0].sym if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
else: arg.sym result = c.semInferredLambda(c, m.bindings, arg)
let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info) else:
let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info)
result = newSymNode(inferred, arg.info) result = newSymNode(inferred, arg.info)
if r == isInferredConvertible: if r == isInferredConvertible:
result = implicitConv(nkHiddenStdConv, f, result, m, c) result = implicitConv(nkHiddenStdConv, f, result, m, c)

View file

@ -1042,7 +1042,8 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
of tyEmpty: of tyEmpty:
result = taField in flags result = taField in flags
of tyTypeClasses: of tyTypeClasses:
result = true result = tfGenericTypeParam in t.flags or
taField notin flags
of tyGenericBody, tyGenericParam, tyGenericInvokation, of tyGenericBody, tyGenericParam, tyGenericInvokation,
tyNone, tyForward, tyFromExpr, tyFieldAccessor: tyNone, tyForward, tyFromExpr, tyFieldAccessor:
result = false result = false

View file

@ -0,0 +1,10 @@
discard """
output: "10\n10"
"""
proc test(x: proc (a, b: int): int) =
echo x(5, 5)
test(proc (a, b): auto = a + b)
test do (a, b) -> auto: a + b

View file

@ -1,7 +1,7 @@
discard """ discard """
cmd: "nimrod check $# $#" cmd: "nimrod check $# $#"
msg: "'proc' is not a concrete type" msg: "'proc' is not a concrete type"
msg: "'seq[Foo]' is not a concrete type." msg: "'Foo' is not a concrete type."
msg: "invalid type: 'TBaseMed'" msg: "invalid type: 'TBaseMed'"
""" """