Revert "Revert "static and default params for generics""
This reverts commit 0662ec4a43.
This commit is contained in:
parent
ea54aa386c
commit
f760bc243b
4 changed files with 95 additions and 64 deletions
|
|
@ -686,6 +686,8 @@ type
|
||||||
# for record types a nkRecord node
|
# for record types a nkRecord node
|
||||||
# for enum types a list of symbols
|
# for enum types a list of symbols
|
||||||
# for tyInt it can be the int literal
|
# for tyInt it can be the int literal
|
||||||
|
# for procs and tyGenericBody, it's the
|
||||||
|
# formal param list
|
||||||
# else: unused
|
# else: unused
|
||||||
destructor*: PSym # destructor. warning: nil here may not necessary
|
destructor*: PSym # destructor. warning: nil here may not necessary
|
||||||
# mean that there is no destructor.
|
# mean that there is no destructor.
|
||||||
|
|
|
||||||
|
|
@ -721,7 +721,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
# TGObj[T] = object
|
# TGObj[T] = object
|
||||||
# TAlias[T] = TGObj[T]
|
# TAlias[T] = TGObj[T]
|
||||||
#
|
#
|
||||||
a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
|
s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
|
||||||
|
a.sons[1] = s.typ.n
|
||||||
s.typ.size = -1 # could not be computed properly
|
s.typ.size = -1 # could not be computed properly
|
||||||
# we fill it out later. For magic generics like 'seq', it won't be filled
|
# we fill it out later. For magic generics like 'seq', it won't be filled
|
||||||
# so we use tyEmpty instead of nil to not crash for strange conversions
|
# so we use tyEmpty instead of nil to not crash for strange conversions
|
||||||
|
|
|
||||||
|
|
@ -806,29 +806,44 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
|
||||||
|
|
||||||
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
result = newOrPrevType(tyGenericInvokation, prev, c)
|
result = newOrPrevType(tyGenericInvokation, prev, c)
|
||||||
var isConcrete = true
|
addSonSkipIntLit(result, s.typ)
|
||||||
|
|
||||||
|
template addToResult(typ) =
|
||||||
|
if typ.isNil:
|
||||||
|
InternalAssert false
|
||||||
|
rawAddSon(result, typ)
|
||||||
|
else: addSonSkipIntLit(result, typ)
|
||||||
|
|
||||||
if s.typ == nil:
|
if s.typ == nil:
|
||||||
LocalError(n.info, errCannotInstantiateX, s.name.s)
|
LocalError(n.info, errCannotInstantiateX, s.name.s)
|
||||||
return newOrPrevType(tyError, prev, c)
|
return newOrPrevType(tyError, prev, c)
|
||||||
elif s.typ.kind != tyGenericBody:
|
elif s.typ.kind == tyForward:
|
||||||
isConcrete = false
|
for i in countup(1, sonsLen(n)-1):
|
||||||
elif sonsLen(n) != sonsLen(s.typ):
|
var elem = semGenericParamInInvokation(c, n.sons[i])
|
||||||
LocalError(n.info, errWrongNumberOfArguments)
|
addToResult(elem)
|
||||||
return newOrPrevType(tyError, prev, c)
|
else:
|
||||||
addSonSkipIntLit(result, s.typ)
|
internalAssert s.typ.kind == tyGenericBody
|
||||||
# iterate over arguments:
|
|
||||||
for i in countup(1, sonsLen(n)-1):
|
var m = newCandidate(s, n)
|
||||||
var elem = semGenericParamInInvokation(c, n.sons[i])
|
matches(c, n, copyTree(n), m)
|
||||||
if containsGenericType(elem): isConcrete = false
|
|
||||||
#if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false
|
if m.state != csMatch:
|
||||||
if elem.isNil: rawAddSon(result, elem)
|
LocalError(n.info, errWrongNumberOfArguments)
|
||||||
else: addSonSkipIntLit(result, elem)
|
return newOrPrevType(tyError, prev, c)
|
||||||
if isConcrete:
|
|
||||||
if s.ast == nil:
|
var isConcrete = true
|
||||||
LocalError(n.info, errCannotInstantiateX, s.name.s)
|
|
||||||
result = newOrPrevType(tyError, prev, c)
|
for i in 1 .. <m.call.len:
|
||||||
else:
|
let typ = m.call[i].typ.skipTypes({tyTypeDesc})
|
||||||
result = instGenericContainer(c, n, result)
|
if containsGenericType(typ): isConcrete = false
|
||||||
|
addToResult(typ)
|
||||||
|
|
||||||
|
if isConcrete:
|
||||||
|
if s.ast == nil:
|
||||||
|
LocalError(n.info, errCannotInstantiateX, s.name.s)
|
||||||
|
result = newOrPrevType(tyError, prev, c)
|
||||||
|
else:
|
||||||
|
result = instGenericContainer(c, n, result)
|
||||||
|
|
||||||
proc semTypeExpr(c: PContext, n: PNode): PType =
|
proc semTypeExpr(c: PContext, n: PNode): PType =
|
||||||
var n = semExprWithType(c, n, {efDetermineType})
|
var n = semExprWithType(c, n, {efDetermineType})
|
||||||
|
|
@ -1032,57 +1047,61 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||||
of mPNimrodNode: nil
|
of mPNimrodNode: nil
|
||||||
else: LocalError(m.info, errTypeExpected)
|
else: LocalError(m.info, errTypeExpected)
|
||||||
|
|
||||||
proc semGenericConstraints(c: PContext, n: PNode, result: PType) =
|
proc semGenericConstraints(c: PContext, x: PType): PType =
|
||||||
var x = semTypeNode(c, n, nil)
|
|
||||||
if x.kind in StructuralEquivTypes and (
|
if x.kind in StructuralEquivTypes and (
|
||||||
sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
|
sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
|
||||||
x = newConstraint(c, x.kind)
|
result = newConstraint(c, x.kind)
|
||||||
result.addSonSkipIntLit(x)
|
else:
|
||||||
|
result = newTypeWithSons(c, tyGenericParam, @[x])
|
||||||
|
|
||||||
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
if n.kind != nkGenericParams:
|
if n.kind != nkGenericParams:
|
||||||
illFormedAst(n)
|
illFormedAst(n)
|
||||||
return
|
return
|
||||||
var position = 0
|
for i in countup(0, sonsLen(n)-1):
|
||||||
for i in countup(0, sonsLen(n)-1):
|
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind != nkIdentDefs: illFormedAst(n)
|
if a.kind != nkIdentDefs: illFormedAst(n)
|
||||||
var L = sonsLen(a)
|
let L = a.len
|
||||||
var def = a.sons[L-1]
|
var def = a{-1}
|
||||||
|
let constraint = a{-2}
|
||||||
var typ: PType
|
var typ: PType
|
||||||
if a.sons[L-2].kind != nkEmpty:
|
|
||||||
typ = newTypeS(tyGenericParam, c)
|
if constraint.kind != nkEmpty:
|
||||||
semGenericConstraints(c, a.sons[L-2], typ)
|
typ = semTypeNode(c, constraint, nil)
|
||||||
if sonsLen(typ) == 1 and typ.sons[0].kind == tyTypeDesc:
|
if typ.kind != tyExpr or typ.len == 0:
|
||||||
typ = typ.sons[0]
|
if typ.len == 0 and typ.kind == tyTypeDesc:
|
||||||
elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
|
typ = newTypeS(tyGenericParam, c)
|
||||||
else: typ = nil
|
|
||||||
for j in countup(0, L-3):
|
|
||||||
var s: PSym
|
|
||||||
if typ == nil:
|
|
||||||
s = newSymG(skType, a.sons[j], c)
|
|
||||||
s.typ = newTypeS(tyGenericParam, c)
|
|
||||||
else:
|
|
||||||
case typ.kind
|
|
||||||
of tyTypeDesc:
|
|
||||||
s = newSymG(skType, a.sons[j], c)
|
|
||||||
s.typ = newTypeS(tyGenericParam, c)
|
|
||||||
of tyExpr:
|
|
||||||
#echo "GENERIC EXPR ", a.info.toFileLineCol
|
|
||||||
# not a type param, but an expression
|
|
||||||
# proc foo[x: expr](bar: int) what is this?
|
|
||||||
s = newSymG(skGenericParam, a.sons[j], c)
|
|
||||||
s.typ = typ
|
|
||||||
else:
|
else:
|
||||||
# This handles cases like proc foo[t: tuple]
|
typ = semGenericConstraints(c, typ)
|
||||||
# XXX: we want to turn that into a type class
|
|
||||||
s = newSymG(skType, a.sons[j], c)
|
if def.kind != nkEmpty:
|
||||||
s.typ = typ
|
def = semConstExpr(c, def)
|
||||||
|
if typ == nil:
|
||||||
|
if def.typ.kind != tyTypeDesc:
|
||||||
|
typ = newTypeWithSons(c, tyExpr, @[def.typ])
|
||||||
|
else:
|
||||||
|
if not containsGenericType(def.typ):
|
||||||
|
def = fitNode(c, typ, def)
|
||||||
|
|
||||||
|
if typ == nil:
|
||||||
|
typ = newTypeS(tyGenericParam, c)
|
||||||
|
|
||||||
|
for j in countup(0, L-3):
|
||||||
|
let finalType = if j == 0: typ
|
||||||
|
else: copyType(typ, typ.owner, false)
|
||||||
|
# it's important the we create an unique
|
||||||
|
# type for each generic param. the index
|
||||||
|
# of the parameter will be stored in the
|
||||||
|
# attached symbol.
|
||||||
|
var s = case finalType.kind
|
||||||
|
of tyExpr:
|
||||||
|
newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
|
||||||
|
else:
|
||||||
|
newSymG(skType, a.sons[j], c).linkTo(finalType)
|
||||||
if def.kind != nkEmpty: s.ast = def
|
if def.kind != nkEmpty: s.ast = def
|
||||||
s.typ.sym = s
|
|
||||||
if father != nil: addSonSkipIntLit(father, s.typ)
|
if father != nil: addSonSkipIntLit(father, s.typ)
|
||||||
s.position = position
|
s.position = result.len
|
||||||
inc position
|
|
||||||
addSon(result, newSymNode(s))
|
addSon(result, newSymNode(s))
|
||||||
if sfGenSym notin s.flags: addDecl(c, s)
|
if sfGenSym notin s.flags: addDecl(c, s)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,9 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
|
||||||
#debug(formalTypeParam)
|
#debug(formalTypeParam)
|
||||||
put(c.bindings, formalTypeParam, binding[i].typ)
|
put(c.bindings, formalTypeParam, binding[i].typ)
|
||||||
|
|
||||||
|
proc newCandidate*(callee: PSym, binding: PNode, calleeScope = -1): TCandidate =
|
||||||
|
initCandidate(result, callee, binding, calleeScope)
|
||||||
|
|
||||||
proc copyCandidate(a: var TCandidate, b: TCandidate) =
|
proc copyCandidate(a: var TCandidate, b: TCandidate) =
|
||||||
a.exactMatches = b.exactMatches
|
a.exactMatches = b.exactMatches
|
||||||
a.subtypeMatches = b.subtypeMatches
|
a.subtypeMatches = b.subtypeMatches
|
||||||
|
|
@ -909,16 +912,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
else:
|
else:
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
|
|
||||||
var f = 1 # iterates over formal parameters
|
var
|
||||||
var a = 1 # iterates over the actual given arguments
|
# iterates over formal parameters
|
||||||
m.state = csMatch # until proven otherwise
|
f = if m.callee.kind != tyGenericBody: 1
|
||||||
|
else: 0
|
||||||
|
# iterates over the actual given arguments
|
||||||
|
a = 1
|
||||||
|
|
||||||
|
m.state = csMatch # until proven otherwise
|
||||||
m.call = newNodeI(n.kind, n.info)
|
m.call = newNodeI(n.kind, n.info)
|
||||||
m.call.typ = base(m.callee) # may be nil
|
m.call.typ = base(m.callee) # may be nil
|
||||||
var formalLen = sonsLen(m.callee.n)
|
var formalLen = m.callee.n.len
|
||||||
addSon(m.call, copyTree(n.sons[0]))
|
addSon(m.call, copyTree(n.sons[0]))
|
||||||
var container: PNode = nil # constructed container
|
var container: PNode = nil # constructed container
|
||||||
var formal: PSym = nil
|
var formal: PSym = nil
|
||||||
|
|
||||||
while a < n.len:
|
while a < n.len:
|
||||||
if n.sons[a].kind == nkExprEqExpr:
|
if n.sons[a].kind == nkExprEqExpr:
|
||||||
# named param
|
# named param
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue