diff options
Diffstat (limited to 'compiler/sigmatch.nim')
-rw-r--r-- | compiler/sigmatch.nim | 110 |
1 files changed, 66 insertions, 44 deletions
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 38340ffb7..5c8a3bc58 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -99,9 +99,12 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, c.calleeSym = callee if callee.kind in skProcKinds and calleeScope == -1: if callee.originatingModule == ctx.module: - let rootSym = if sfFromGeneric notin callee.flags: callee - else: callee.owner - c.calleeScope = rootSym.scope.depthLevel + c.calleeScope = 2 + var owner = callee + while true: + owner = owner.skipGenericOwner + if owner.kind == skModule: break + inc c.calleeScope else: c.calleeScope = 1 else: @@ -499,6 +502,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, param.typ = makeTypeDesc(c, typ) addDecl(c, param) + #echo "A ", param.name.s, " ", typeToString(param.typ), " ", param.kind for param in body.n[0]: var @@ -507,30 +511,19 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, if param.kind == nkVarTy: dummyName = param[0] - dummyType = if a.kind != tyVar: makeVarType(c, a) - else: a + dummyType = if a.kind != tyVar: makeVarType(c, a) else: a else: dummyName = param dummyType = a internalAssert dummyName.kind == nkIdent - var dummyParam = newSym(skType, dummyName.ident, body.sym, body.sym.info) + var dummyParam = newSym(skVar, dummyName.ident, body.sym, body.sym.info) dummyParam.typ = dummyType addDecl(c, dummyParam) + #echo "B ", dummyName.ident.s, " ", typeToString(dummyType), " ", dummyparam.kind var checkedBody = c.semTryExpr(c, body.n[3].copyTree) - #m.errors = bufferedMsgs - clearBufferedMsgs() if checkedBody == nil: return isNone - - if checkedBody.kind == nkStmtList: - for stmt in checkedBody: - case stmt.kind - of nkReturnStmt: discard - of nkTypeSection: discard - of nkConstDef: discard - else: discard - return isGeneric proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool = @@ -902,14 +895,27 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return result = isGeneric else: - result = typeRel(c, f.sons[0], x) + let genericBody = f.sons[0] + result = typeRel(c, genericBody, x) if result != isNone: + # see tests/generics/tgeneric3.nim for an example that triggers this + # piece of code: + # + # proc internalFind[T,D](n: PNode[T,D], key: T): ref TItem[T,D] + # proc internalPut[T,D](ANode: ref TNode[T,D], Akey: T, Avalue: D, + # Oldvalue: var D): ref TNode[T,D] + # var root = internalPut[int, int](nil, 312, 312, oldvalue) + # var it1 = internalFind(root, 312) # cannot instantiate: 'D' + # # we steal the generic parameters from the tyGenericBody: for i in countup(1, sonsLen(f) - 1): - var x = PType(idTableGet(c.bindings, f.sons[0].sons[i - 1])) - if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}: + var x = PType(idTableGet(c.bindings, genericBody.sons[i-1])) + if x == nil: + discard "maybe fine (for eg. a==tyNil)" + elif x.kind in {tyGenericInvocation, tyGenericParam}: internalError("wrong instantiated type!") - put(c.bindings, f.sons[i], x) + else: + put(c.bindings, f.sons[i], x) of tyAnd: considerPreviousT: @@ -1102,8 +1108,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = localError(f.n.info, errTypeExpected) result = isNone + of tyNone: + if a.kind == tyNone: result = isEqual else: - internalAssert false + internalError " unknown type kind " & $f.kind proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation = var m: TCandidate @@ -1197,6 +1205,17 @@ proc isEmptyContainer*(t: PType): bool = of tyGenericInst: result = isEmptyContainer(t.lastSon) else: result = false +proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) = + case r + of isConvertible, isIntConv: inc(m.convMatches, convMatch) + of isSubtype, isSubrange: inc(m.subtypeMatches) + of isGeneric, isInferred: inc(m.genericMatches) + of isFromIntLit: inc(m.intConvMatches, 256) + of isInferredConvertible: + inc(m.convMatches) + of isEqual: inc(m.exactMatches) + of isNone: discard + proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, argSemantized, argOrig: PNode): PNode = var @@ -1237,18 +1256,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, if r != isNone and m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}: - # XXX: duplicating this is ugly, maybe we should move this + # XXX: duplicating this is ugly, but we cannot (!) move this # directly into typeRel using return-like templates - case r - of isConvertible, isIntConv: inc(m.convMatches) - of isSubtype, isSubrange: inc(m.subtypeMatches) - of isGeneric, isInferred: inc(m.genericMatches) - of isFromIntLit: inc(m.intConvMatches, 256) - of isInferredConvertible: - inc(m.convMatches) - of isEqual: inc(m.exactMatches) - of isNone: discard - + incMatches(m, r) if f.kind == tyStmt: return arg elif f.kind == tyTypeDesc: @@ -1363,20 +1373,23 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, z.calleeSym = arg.sons[i].sym #if arg.sons[i].sym.name.s == "cmp": # ggDebug = true - # echo "CALLLEEEEEEEE ", typeToString(z.callee) - var r = typeRel(z, f, arg.sons[i].typ) + # echo "CALLLEEEEEEEE A ", typeToString(z.callee) + # XXX this is still all wrong: (T, T) should be 2 generic matches + # and (int, int) 2 exact matches, etc. Essentially you cannot call + # typeRel here and expect things to work! + let r = typeRel(z, f, arg.sons[i].typ) + incMatches(z, r, 2) #if arg.sons[i].sym.name.s == "cmp": # and arg.info.line == 606: # echo "M ", r, " ", arg.info, " ", typeToString(arg.sons[i].sym.typ) - # debug arg.sons[i].sym # writeMatches(z) if r != isNone: + z.state = csMatch case x.state of csEmpty, csNoMatch: x = z best = i - x.state = csMatch of csMatch: - var cmp = cmpCandidates(x, z) + let cmp = cmpCandidates(x, z) if cmp < 0: best = i x = z @@ -1399,6 +1412,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], argOrig) + proc setSon(father: PNode, at: int, son: PNode) = if sonsLen(father) <= at: setLen(father.sons, at + 1) father.sons[at] = son @@ -1410,9 +1424,12 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode = # a.typ == nil is valid result = a elif a.typ.isNil: + # XXX This is unsound! 'formal' can differ from overloaded routine to + # overloaded routine! let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator} - elif formal.kind == tyStmt: {efDetermineType, efWantStmt} - else: {efDetermineType} + else: {efDetermineType, efAllowStmt} + #elif formal.kind == tyStmt: {efDetermineType, efWantStmt} + #else: {efDetermineType} result = c.semOperand(c, a, flags) else: result = a @@ -1524,7 +1541,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, copyTree(n.sons[a]), m, c)) else: addSon(m.call, copyTree(n.sons[a])) - elif formal != nil: + elif formal != nil and formal.typ.kind == tyVarargs: + # beware of the side-effects in 'prepareOperand'! So only do it for + # varags matching. See tests/metatype/tstatic_overloading. m.baseTypeMatch = false n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, @@ -1616,12 +1635,15 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool = # instantiate generic converters for that result = res != nil -proc instDeepCopy*(c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {. - procvar.} = +proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; + op: TTypeAttachedOp): PSym {.procvar.} = var m: TCandidate initCandidate(c, m, dc.typ) var f = dc.typ.sons[1] - if f.kind in {tyRef, tyPtr}: f = f.lastSon + if op == attachedDeepCopy: + if f.kind in {tyRef, tyPtr}: f = f.lastSon + else: + if f.kind == tyVar: f = f.lastSon if typeRel(m, f, t) == isNone: localError(info, errGenerated, "cannot instantiate 'deepCopy'") else: |