diff options
author | Zahary Karadjov <zahary@gmail.com> | 2013-05-26 11:14:03 +0300 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2013-05-26 13:59:39 +0300 |
commit | 46813bbe4e1423181521d4792b9af7593f48fa1f (patch) | |
tree | 8a56266270506f483ba93c71ac34d491b6f2e4dd /compiler | |
parent | bfff1ac8b2435595351194f6c4b1268d38301401 (diff) | |
download | Nim-46813bbe4e1423181521d4792b9af7593f48fa1f.tar.gz |
static and default params for generics
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/semstmts.nim | 3 | ||||
-rw-r--r-- | compiler/semtypes.nim | 129 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 19 |
4 files changed, 92 insertions, 61 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index e35bf25ef..174c3f94b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -674,6 +674,8 @@ type # for record types a nkRecord node # for enum types a list of symbols # for tyInt it can be the int literal + # for procs and tyGenericBody, it's the + # formal param list # else: unused destructor*: PSym # destructor. warning: nil here may not necessary # mean that there is no destructor. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b63c20548..9ae8aaca6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -710,7 +710,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = # TGObj[T] = object # 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 # 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 diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index c975abb26..351794435 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -794,29 +794,44 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType = proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = 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: LocalError(n.info, errCannotInstantiateX, s.name.s) return newOrPrevType(tyError, prev, c) - elif s.typ.kind != tyGenericBody: - isConcrete = false - elif sonsLen(n) != sonsLen(s.typ): - LocalError(n.info, errWrongNumberOfArguments) - return newOrPrevType(tyError, prev, c) - addSonSkipIntLit(result, s.typ) - # iterate over arguments: - for i in countup(1, sonsLen(n)-1): - var elem = semGenericParamInInvokation(c, n.sons[i]) - if containsGenericType(elem): isConcrete = false - #if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false - if elem.isNil: rawAddSon(result, elem) - else: addSonSkipIntLit(result, elem) - if isConcrete: - if s.ast == nil: - LocalError(n.info, errCannotInstantiateX, s.name.s) - result = newOrPrevType(tyError, prev, c) - else: - result = instGenericContainer(c, n, result) + elif s.typ.kind == tyForward: + for i in countup(1, sonsLen(n)-1): + var elem = semGenericParamInInvokation(c, n.sons[i]) + addToResult(elem) + else: + internalAssert s.typ.kind == tyGenericBody + + var m = newCandidate(s, n) + matches(c, n, copyTree(n), m) + + if m.state != csMatch: + LocalError(n.info, errWrongNumberOfArguments) + return newOrPrevType(tyError, prev, c) + + var isConcrete = true + + for i in 1 .. <m.call.len: + let typ = m.call[i].typ.skipTypes({tyTypeDesc}) + 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 = var n = semExprWithType(c, n, {efDetermineType}) @@ -1018,57 +1033,61 @@ proc processMagicType(c: PContext, m: PSym) = of mPNimrodNode: nil else: LocalError(m.info, errTypeExpected) -proc semGenericConstraints(c: PContext, n: PNode, result: PType) = - var x = semTypeNode(c, n, nil) +proc semGenericConstraints(c: PContext, x: PType): PType = if x.kind in StructuralEquivTypes and ( sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}): - x = newConstraint(c, x.kind) - result.addSonSkipIntLit(x) + result = newConstraint(c, x.kind) + else: + result = newTypeWithSons(c, tyGenericParam, @[x]) proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = result = copyNode(n) if n.kind != nkGenericParams: illFormedAst(n) 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] if a.kind != nkIdentDefs: illFormedAst(n) - var L = sonsLen(a) - var def = a.sons[L-1] + let L = a.len + var def = a{-1} + let constraint = a{-2} var typ: PType - if a.sons[L-2].kind != nkEmpty: - typ = newTypeS(tyGenericParam, c) - semGenericConstraints(c, a.sons[L-2], typ) - if sonsLen(typ) == 1 and typ.sons[0].kind == tyTypeDesc: - typ = typ.sons[0] - elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c) - else: typ = nil - for j in countup(0, L-3): - var s: PSym + + if constraint.kind != nkEmpty: + typ = semTypeNode(c, constraint, nil) + if typ.kind != tyExpr or typ.len == 0: + if typ.len == 0 and typ.kind == tyTypeDesc: + typ = newTypeS(tyGenericParam, c) + else: + typ = semGenericConstraints(c, typ) + + if def.kind != nkEmpty: + def = semConstExpr(c, def) if typ == nil: - s = newSymG(skType, a.sons[j], c) - s.typ = newTypeS(tyGenericParam, c) + if def.typ.kind != tyTypeDesc: + typ = newTypeWithSons(c, tyExpr, @[def.typ]) else: - case typ.kind - of tyTypeDesc: - s = newSymG(skType, a.sons[j], c) - s.typ = newTypeS(tyGenericParam, c) + 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: - #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 + newSymG(skGenericParam, a.sons[j], c).linkTo(finalType) else: - # This handles cases like proc foo[t: tuple] - # XXX: we want to turn that into a type class - s = newSymG(skType, a.sons[j], c) - s.typ = typ + newSymG(skType, a.sons[j], c).linkTo(finalType) if def.kind != nkEmpty: s.ast = def - s.typ.sym = s if father != nil: addSonSkipIntLit(father, s.typ) - s.position = position - inc position + s.position = result.len addSon(result, newSymNode(s)) if sfGenSym notin s.flags: addDecl(c, s) + diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 4ca3e9d43..048067a44 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -84,6 +84,9 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode, #debug(formalTypeParam) 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) = a.exactMatches = b.exactMatches a.subtypeMatches = b.subtypeMatches @@ -861,16 +864,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode, else: m.state = csNoMatch return - - var f = 1 # iterates over formal parameters - var a = 1 # iterates over the actual given arguments - m.state = csMatch # until proven otherwise + + var + # iterates over formal parameters + 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.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])) var container: PNode = nil # constructed container var formal: PSym = nil + while a < n.len: if n.sons[a].kind == nkExprEqExpr: # named param |