diff options
author | Jacek Sieka <arnetheduck@gmail.com> | 2016-08-25 22:59:51 +0800 |
---|---|---|
committer | Jacek Sieka <arnetheduck@gmail.com> | 2016-08-25 22:59:51 +0800 |
commit | db2f96daba9c04db2f24cb783c79fb37799cd9ea (patch) | |
tree | 567beb43c7e4549abfcae1ea66e5232d7525e001 /compiler/sigmatch.nim | |
parent | 3116744c86f37ac4e4e5fec3d6d1635304ed717f (diff) | |
parent | 84a09d2f5b0866491e55fef0fef541e8cc548852 (diff) | |
download | Nim-db2f96daba9c04db2f24cb783c79fb37799cd9ea.tar.gz |
Merge remote-tracking branch 'origin/devel' into initallocator-fix
Diffstat (limited to 'compiler/sigmatch.nim')
-rw-r--r-- | compiler/sigmatch.nim | 214 |
1 files changed, 152 insertions, 62 deletions
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 82f878932..ec429968c 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -22,7 +22,7 @@ type TCandidateState* = enum csEmpty, csMatch, csNoMatch - CandidateErrors* = seq[PSym] + CandidateErrors* = seq[(PSym,int)] TCandidate* = object c*: PContext exactMatches*: int # also misused to prefer iters over procs @@ -49,6 +49,7 @@ type # a distrinct type typedescMatched*: bool isNoCall*: bool # misused for generic type instantiations C[T] + mutabilityProblem*: uint8 # tyVar mismatch inheritancePenalty: int # to prefer closest father object type errors*: CandidateErrors # additional clarifications to be displayed to the # user if overload resolution fails @@ -96,8 +97,8 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) = c.calleeSym = nil initIdTable(c.bindings) -proc put(t: var TIdTable, key, val: PType) {.inline.} = - idTablePut(t, key, val.skipIntLit) +proc put(c: var TCandidate, key, val: PType) {.inline.} = + idTablePut(c.bindings, key, val.skipIntLit) proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, binding: PNode, calleeScope = -1) = @@ -129,7 +130,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, bound = makeTypeDesc(ctx, bound) else: bound = bound.skipTypes({tyTypeDesc}) - put(c.bindings, formalTypeParam, bound) + put(c, formalTypeParam, bound) proc newCandidate*(ctx: PContext, callee: PSym, binding: PNode, calleeScope = -1): TCandidate = @@ -220,13 +221,14 @@ proc cmpCandidates*(a, b: TCandidate): int = if result != 0: return result = a.convMatches - b.convMatches if result != 0: return - result = a.calleeScope - b.calleeScope - if result != 0: return # the other way round because of other semantics: result = b.inheritancePenalty - a.inheritancePenalty if result != 0: return # prefer more specialized generic over more general generic: result = complexDisambiguation(a.callee, b.callee) + # only as a last resort, consider scoping: + if result != 0: return + result = a.calleeScope - b.calleeScope proc writeMatches*(c: TCandidate) = writeLine(stdout, "exact matches: " & $c.exactMatches) @@ -242,6 +244,8 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string = for i in 1 .. <arg.len: result.add(" | ") result.add typeToString(arg[i].typ, prefer) + elif arg.typ == nil: + result = "void" else: result = arg.typ.typeToString(prefer) @@ -253,15 +257,16 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1; if n.sons[i].kind == nkExprEqExpr: add(result, renderTree(n.sons[i].sons[0])) add(result, ": ") - if arg.typ.isNil: + if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}: + # XXX we really need to 'tryExpr' here! arg = c.semOperand(c, n.sons[i].sons[1]) n.sons[i].typ = arg.typ n.sons[i].sons[1] = arg else: - if arg.typ.isNil: + if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}: arg = c.semOperand(c, n.sons[i]) n.sons[i] = arg - if arg.typ.kind == tyError: return + if arg.typ != nil and arg.typ.kind == tyError: return add(result, argTypeToString(arg, prefer)) if i != sonsLen(n) - 1: add(result, ", ") @@ -360,6 +365,50 @@ proc isObjectSubtype(a, f: PType): int = if t != nil: result = depth +type + SkippedPtr = enum skippedNone, skippedRef, skippedPtr + +proc skipToObject(t: PType; skipped: var SkippedPtr): PType = + var r = t + # we're allowed to skip one level of ptr/ref: + var ptrs = 0 + while r != nil: + case r.kind + of tyGenericInvocation: + r = r.sons[0] + of tyRef: + inc ptrs + skipped = skippedRef + r = r.lastSon + of tyPtr: + inc ptrs + skipped = skippedPtr + r = r.lastSon + of tyGenericBody, tyGenericInst: + r = r.lastSon + else: + break + if r.kind == tyObject and ptrs <= 1: result = r + +proc isGenericSubtype(a, f: PType, d: var int): bool = + assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody} + var askip = skippedNone + var fskip = skippedNone + var t = a.skipToObject(askip) + let r = f.skipToObject(fskip) + if r == nil: return false + var depth = 0 + # XXX sameObjectType can return false here. Need to investigate + # why that is but sameObjectType does way too much work here anyway. + while t != nil and r.sym != t.sym and askip == fskip: + t = t.sons[0] + if t != nil: t = t.skipToObject(askip) + else: break + inc depth + if t != nil and askip == fskip: + d = depth + result = true + proc minRel(a, b: TTypeRelation): TTypeRelation = if a <= b: result = a else: result = b @@ -513,7 +562,7 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = proc matchUserTypeClass*(c: PContext, m: var TCandidate, ff, a: PType): TTypeRelation = var body = ff.skipTypes({tyUserTypeClassInst}) - if c.inTypeClass > 20: + if c.inTypeClass > 4: localError(body.n[3].info, $body.n[3] & " too nested for type matching") return isNone @@ -531,7 +580,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, typ = ff.sons[i] param: PSym - template paramSym(kind): expr = + template paramSym(kind): untyped = newSym(kind, typeParamName, body.sym, body.sym.info) case typ.kind @@ -598,6 +647,10 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode): PNode = let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil) result = c.c.semExpr(c.c, instantiated) +template subtypeCheck() = + if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}: + result = isNone + proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # typeRel can be used to establish various relationships between types: # @@ -619,7 +672,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = assert(f != nil) if f.kind == tyExpr: - if aOrig != nil: put(c.bindings, f, aOrig) + if aOrig != nil: put(c, f, aOrig) return isGeneric assert(aOrig != nil) @@ -640,10 +693,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = template bindingRet(res) = if doBind: let bound = aOrig.skipTypes({tyRange}).skipIntLit - if doBind: put(c.bindings, f, bound) + put(c, f, bound) return res - template considerPreviousT(body: stmt) {.immediate.} = + template considerPreviousT(body: untyped) = var prev = PType(idTableGet(c.bindings, f)) if prev == nil: body else: return typeRel(c, prev, a) @@ -737,6 +790,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyVar: if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base) else: result = typeRel(c, f.base, aOrig) + subtypeCheck() of tyArray, tyArrayConstr: # tyArrayConstr cannot happen really, but # we wanna be safe here @@ -746,7 +800,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if fRange.kind == tyGenericParam: var prev = PType(idTableGet(c.bindings, fRange)) if prev == nil: - put(c.bindings, fRange, a.sons[0]) + put(c, fRange, a.sons[0]) fRange = a else: fRange = prev @@ -764,7 +818,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # we must correct for the off-by-one discrepancy between # ranges and static params: replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1) - put(c.bindings, rangeStaticT, replacementT) + put(c, rangeStaticT, replacementT) return isGeneric let len = tryResolvingStaticExpr(c, fRange.n[1]) @@ -851,6 +905,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if sameDistinctTypes(f, a): result = isEqual elif f.base.kind == tyAnything: result = isGeneric elif c.coerceDistincts: result = typeRel(c, f.base, a) + elif a.kind == tyNil and f.base.kind in NilableTypes: + result = f.allowsNil elif c.coerceDistincts: result = typeRel(c, f.base, a) of tySet: if a.kind == tySet: @@ -867,6 +923,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = for i in 0..f.len-2: if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone result = typeRel(c, f.lastSon, a.lastSon) + subtypeCheck() if result <= isConvertible: result = isNone elif tfNotNil in f.flags and tfNotNil notin a.flags: result = isNilConversion @@ -921,8 +978,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isConvertible else: discard - of tyEmpty: - if a.kind == tyEmpty: result = isEqual + of tyEmpty, tyVoid: + if a.kind == f.kind: result = isEqual of tyGenericInst: result = typeRel(c, lastSon(f), a) @@ -932,21 +989,26 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if a.kind == tyGenericInst and a.sons[0] == f: bindingRet isGeneric let ff = lastSon(f) - if ff != nil: result = typeRel(c, ff, a) + if ff != nil: + result = typeRel(c, ff, a) of tyGenericInvocation: var x = a.skipGenericAlias + var depth = 0 if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody: #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation") # simply no match for now: discard elif x.kind == tyGenericInst and - (f.sons[0] == x.sons[0]) and + ((f.sons[0] == x.sons[0]) or isGenericSubtype(x, f, depth)) and (sonsLen(x) - 1 == sonsLen(f)): for i in countup(1, sonsLen(f) - 1): if x.sons[i].kind == tyGenericParam: internalError("wrong instantiated type!") - elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return + elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: + # Workaround for regression #4589 + if f.sons[i].kind != tyTypeDesc: return + c.inheritancePenalty += depth result = isGeneric else: let genericBody = f.sons[0] @@ -963,13 +1025,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # # we steal the generic parameters from the tyGenericBody: for i in countup(1, sonsLen(f) - 1): - var x = PType(idTableGet(c.bindings, genericBody.sons[i-1])) + let 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!") else: - put(c.bindings, f.sons[i], x) + put(c, f.sons[i], x) of tyAnd: considerPreviousT: @@ -979,6 +1041,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if x < isSubtype: return isNone # 'and' implies minimum matching result: if x < result: result = x + if result > isGeneric: result = isGeneric bindingRet result of tyOr: @@ -989,6 +1052,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # 'or' implies maximum matching result: if x > result: result = x if result >= isSubtype: + if result > isGeneric: result = isGeneric bindingRet result else: result = isNone @@ -1005,7 +1069,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = considerPreviousT: var concrete = concreteType(c, a) if concrete != nil and doBind: - put(c.bindings, f, concrete) + put(c, f, concrete) return isGeneric of tyBuiltInTypeClass: @@ -1013,7 +1077,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = let targetKind = f.sons[0].kind if targetKind == a.skipTypes({tyRange, tyGenericInst}).kind or (targetKind in {tyProc, tyPointer} and a.kind == tyNil): - put(c.bindings, f, a) + put(c, f, a) return isGeneric else: return isNone @@ -1022,7 +1086,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = considerPreviousT: result = matchUserTypeClass(c.c, c, f, aOrig) if result == isGeneric: - put(c.bindings, f, a) + put(c, f, a) of tyCompositeTypeClass: considerPreviousT: @@ -1038,7 +1102,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = else: result = typeRel(c, rootf.lastSon, a) if result != isNone: - put(c.bindings, f, a) + put(c, f, a) result = isGeneric of tyGenericParam: var x = PType(idTableGet(c.bindings, f)) @@ -1072,7 +1136,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if doBind and result notin {isNone, isGeneric}: let concrete = concreteType(c, a) if concrete == nil: return isNone - put(c.bindings, f, concrete) + put(c, f, concrete) else: result = isGeneric @@ -1086,7 +1150,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if concrete == nil: return isNone if doBind: - put(c.bindings, f, concrete) + put(c, f, concrete) elif result > isGeneric: result = isGeneric elif a.kind == tyEmpty: @@ -1105,7 +1169,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if result != isNone and f.n != nil: if not exprStructuralEquivalent(f.n, aOrig.n): result = isNone - if result != isNone: put(c.bindings, f, aOrig) + if result != isNone: put(c, f, aOrig) else: result = isNone elif prev.kind == tyStatic: @@ -1133,7 +1197,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = typeRel(c, f.base, a.base) if result != isNone: - put(c.bindings, f, a) + put(c, f, a) else: if tfUnresolved in f.flags: result = typeRel(c, prev.base, a) @@ -1151,7 +1215,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyStmt: if aOrig != nil and tfOldSchoolExprStmt notin f.flags: - put(c.bindings, f, aOrig) + put(c, f, aOrig) result = isGeneric of tyProxy: @@ -1256,6 +1320,13 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, if r == isGeneric: result.typ = getInstantiatedType(c, arg, m, base(f)) m.baseTypeMatch = true + # bug #4545: allow the call to go through a 'var T': + let vt = result.sons[0].typ.sons[1] + if vt.kind == tyVar: + let x = result.sons[1] + let va = newNodeIT(nkHiddenAddr, x.info, vt) + va.add x + result.sons[1] = va proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) = case r @@ -1399,7 +1470,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}: result = implicitConv(nkHiddenSubConv, f, arg, m, c) of isNone: - # do not do this in ``typeRel`` as it then can't infere T in ``ref T``: + # do not do this in ``typeRel`` as it then can't infer T in ``ref T``: if a.kind in {tyProxy, tyUnknown}: inc(m.genericMatches) m.fauxMatch = a.kind @@ -1420,6 +1491,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, m.baseTypeMatch = true else: result = userConvMatch(c, m, base(f), a, arg) + if result != nil: m.baseTypeMatch = true proc paramTypesMatch*(m: var TCandidate, f, a: PType, arg, argOrig: PNode): PNode = @@ -1532,13 +1604,13 @@ proc incrIndexType(t: PType) = assert t.kind == tyArrayConstr inc t.sons[0].n.sons[1].intVal -template isVarargsUntyped(x): expr = +template isVarargsUntyped(x): untyped = x.kind == tyVarargs and x.sons[0].kind == tyExpr and tfOldSchoolExprStmt notin x.sons[0].flags proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var IntSet) = - template checkConstraint(n: expr) {.immediate, dirty.} = + template checkConstraint(n: untyped) {.dirty.} = if not formal.constraint.isNil: if matchNodeKinds(formal.constraint, n): # better match over other routines with no such restriction: @@ -1549,6 +1621,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, if formal.typ.kind == tyVar: if not n.isLValue: m.state = csNoMatch + m.mutabilityProblem = uint8(f-1) return var @@ -1568,6 +1641,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, while a < n.len: if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped: + incl(marker, formal.position) if container.isNil: container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info)) setSon(m.call, formal.position + 1, container) @@ -1630,6 +1704,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, # beware of the side-effects in 'prepareOperand'! So only do it for # varargs matching. See tests/metatype/tstatic_overloading. m.baseTypeMatch = false + incl(marker, formal.position) n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, n.sons[a], nOrig.sons[a]) @@ -1653,30 +1728,39 @@ proc matchesAux(c: PContext, n, nOrig: PNode, when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) m.state = csNoMatch return - m.baseTypeMatch = false - n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) - var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, - n.sons[a], nOrig.sons[a]) - if arg == nil: - m.state = csNoMatch - return - if m.baseTypeMatch: - #assert(container == nil) + + if formal.typ.isVarargsUntyped: if container.isNil: - container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) + container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, n.info)) + setSon(m.call, formal.position + 1, container) else: incrIndexType(container.typ) - addSon(container, arg) - setSon(m.call, formal.position + 1, - implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) - #if f != formalLen - 1: container = nil - - # pick the formal from the end, so that 'x, y, varargs, z' works: - f = max(f, formalLen - n.len + a + 1) + addSon(container, n.sons[a]) else: - setSon(m.call, formal.position + 1, arg) - inc(f) - container = nil + m.baseTypeMatch = false + n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) + var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, + n.sons[a], nOrig.sons[a]) + if arg == nil: + m.state = csNoMatch + return + if m.baseTypeMatch: + #assert(container == nil) + if container.isNil: + container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) + else: + incrIndexType(container.typ) + addSon(container, arg) + setSon(m.call, formal.position + 1, + implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) + #if f != formalLen - 1: container = nil + + # pick the formal from the end, so that 'x, y, varargs, z' works: + f = max(f, formalLen - n.len + a + 1) + else: + setSon(m.call, formal.position + 1, arg) + inc(f) + container = nil checkConstraint(n.sons[a]) inc(a) @@ -1707,15 +1791,18 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = if formal.ast == nil: if formal.typ.kind == tyVarargs: var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info)) - addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ, - container, m, c)) + setSon(m.call, formal.position + 1, + implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) else: # no default value m.state = csNoMatch break else: # use default value: - setSon(m.call, formal.position + 1, copyTree(formal.ast)) + var def = copyTree(formal.ast) + if def.kind == nkNilLit: + def = implicitConv(nkHiddenStdConv, formal.typ, def, m, c) + setSon(m.call, formal.position + 1, def) inc(f) proc argtypeMatches*(c: PContext, f, a: PType): bool = @@ -1728,16 +1815,19 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool = result = res != nil proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; - op: TTypeAttachedOp): PSym {.procvar.} = + op: TTypeAttachedOp; col: int): PSym {.procvar.} = var m: TCandidate initCandidate(c, m, dc.typ) - var f = dc.typ.sons[1] + if col >= dc.typ.len: + localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'") + return nil + var f = dc.typ.sons[col] 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'") + localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'") else: result = c.semGenerateInstance(c, dc, m.bindings, info) assert sfFromGeneric in result.flags @@ -1745,7 +1835,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; include suggest when not declared(tests): - template tests(s: stmt) {.immediate.} = discard + template tests(s: untyped) = discard tests: var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo()) |