quite messy implementation of generic lambdas, needs reworking; fixes #715
This commit is contained in:
parent
9a41db7d7a
commit
9dd753f218
9 changed files with 87 additions and 27 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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!
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
var gp: PNode
|
||||||
illFormedAst(n) # process parameters:
|
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||||
|
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,12 +932,13 @@ 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
|
||||||
pushProcCon(c, s)
|
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||||
addResult(c, s.typ.sons[0], n.info, skProc)
|
pushProcCon(c, s)
|
||||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
addResult(c, s.typ.sons[0], n.info, skProc)
|
||||||
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||||
addResultNode(c, n)
|
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
||||||
popProcCon(c)
|
addResultNode(c, n)
|
||||||
|
popProcCon(c)
|
||||||
sideEffectsCheck(c, s)
|
sideEffectsCheck(c, s)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errImplOfXexpected, s.name.s)
|
localError(n.info, errImplOfXexpected, s.name.s)
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -1039,10 +1039,11 @@ 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:
|
||||||
result = newSymNode(inferred, arg.info)
|
let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, 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)
|
||||||
of isGeneric:
|
of isGeneric:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
10
tests/generics/tgenericlambda.nim
Normal file
10
tests/generics/tgenericlambda.nim
Normal 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
|
||||||
|
|
@ -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'"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue