diff options
-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, 61 insertions, 92 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 174c3f94b..e35bf25ef 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -674,8 +674,6 @@ 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 9ae8aaca6..b63c20548 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -710,8 +710,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = # TGObj[T] = object # TAlias[T] = TGObj[T] # - s.typ.n = semGenericParamList(c, a.sons[1], s.typ) - a.sons[1] = s.typ.n + a.sons[1] = semGenericParamList(c, a.sons[1], s.typ) 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 351794435..c975abb26 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -794,44 +794,29 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType = proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = result = newOrPrevType(tyGenericInvokation, prev, c) - addSonSkipIntLit(result, s.typ) - - template addToResult(typ) = - if typ.isNil: - InternalAssert false - rawAddSon(result, typ) - else: addSonSkipIntLit(result, typ) - + var isConcrete = true if s.typ == nil: LocalError(n.info, errCannotInstantiateX, s.name.s) return newOrPrevType(tyError, prev, c) - 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) + 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) proc semTypeExpr(c: PContext, n: PNode): PType = var n = semExprWithType(c, n, {efDetermineType}) @@ -1033,61 +1018,57 @@ proc processMagicType(c: PContext, m: PSym) = of mPNimrodNode: nil else: LocalError(m.info, errTypeExpected) -proc semGenericConstraints(c: PContext, x: PType): PType = +proc semGenericConstraints(c: PContext, n: PNode, result: PType) = + var x = semTypeNode(c, n, nil) if x.kind in StructuralEquivTypes and ( sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}): - result = newConstraint(c, x.kind) - else: - result = newTypeWithSons(c, tyGenericParam, @[x]) + x = newConstraint(c, x.kind) + result.addSonSkipIntLit(x) proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = result = copyNode(n) if n.kind != nkGenericParams: illFormedAst(n) return - for i in countup(0, sonsLen(n)-1): + var position = 0 + for i in countup(0, sonsLen(n)-1): var a = n.sons[i] if a.kind != nkIdentDefs: illFormedAst(n) - let L = a.len - var def = a{-1} - let constraint = a{-2} + var L = sonsLen(a) + var def = a.sons[L-1] var typ: PType - - 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 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 typ == nil: - if def.typ.kind != tyTypeDesc: - typ = newTypeWithSons(c, tyExpr, @[def.typ]) + s = newSymG(skType, a.sons[j], c) + s.typ = newTypeS(tyGenericParam, c) 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 + case typ.kind + of tyTypeDesc: + s = newSymG(skType, a.sons[j], c) + s.typ = newTypeS(tyGenericParam, c) of tyExpr: - newSymG(skGenericParam, a.sons[j], c).linkTo(finalType) + #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: - newSymG(skType, a.sons[j], c).linkTo(finalType) + # 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 if def.kind != nkEmpty: s.ast = def + s.typ.sym = s if father != nil: addSonSkipIntLit(father, s.typ) - s.position = result.len + s.position = position + inc position addSon(result, newSymNode(s)) if sfGenSym notin s.flags: addDecl(c, s) - diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 048067a44..4ca3e9d43 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -84,9 +84,6 @@ 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 @@ -864,22 +861,16 @@ proc matchesAux(c: PContext, n, nOrig: PNode, else: m.state = csNoMatch return - - 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 + + var f = 1 # iterates over formal parameters + var a = 1 # iterates over the actual given arguments + m.state = csMatch # until proven otherwise m.call = newNodeI(n.kind, n.info) m.call.typ = base(m.callee) # may be nil - var formalLen = m.callee.n.len + var formalLen = sonsLen(m.callee.n) 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 |