diff options
Diffstat (limited to 'compiler/sigmatch.nim')
-rw-r--r-- | compiler/sigmatch.nim | 88 |
1 files changed, 55 insertions, 33 deletions
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 103608afc..828d25fe8 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -12,19 +12,29 @@ import intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, - magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees, + magicsys, idents, lexer, options, parampatterns, strutils, trees, linter, lineinfos, lowerings, modulegraphs when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler): import docgen type + MismatchKind* = enum + kUnknown, kAlreadyGiven, kUnknownNamedParam, kTypeMismatch, kVarNeeded, + kMissingParam, kExtraArg + + MismatchInfo* = object + kind*: MismatchKind # reason for mismatch + arg*: int # position of provided arguments that mismatches + formal*: PSym # parameter that mismatches against provided argument + # its position can differ from `arg` because of varargs + TCandidateState* = enum csEmpty, csMatch, csNoMatch CandidateError* = object sym*: PSym - unmatchedVarParam*, firstMismatch*: int + firstMismatch*: MismatchInfo diagnostics*: seq[string] enabled*: bool @@ -56,7 +66,6 @@ type # a distrinct type typedescMatched*: bool isNoCall*: bool # misused for generic type instantiations C[T] - mutabilityProblem*: uint8 # tyVar mismatch inferredTypes: seq[PType] # inferred types during the current signature # matching. they will be reset if the matching # is not successful. may replace the bindings @@ -70,8 +79,7 @@ type # triggered with an idetools command in the # future. inheritancePenalty: int # to prefer closest father object type - firstMismatch*: int # position of the first type mismatch for - # better error messages + firstMismatch*: MismatchInfo # mismatch info for better error messages diagnosticsEnabled*: bool TTypeRelFlag* = enum @@ -112,6 +120,7 @@ proc initCandidateAux(ctx: PContext, c.intConvMatches = 0 c.genericMatches = 0 c.state = csEmpty + c.firstMismatch = MismatchInfo() c.callee = callee c.call = nil c.baseTypeMatch = false @@ -2280,42 +2289,47 @@ template isVarargsUntyped(x): untyped = proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var IntSet) = + var + a = 1 # iterates over the actual given arguments + f = if m.callee.kind != tyGenericBody: 1 + else: 0 # iterates over formal parameters + arg: PNode # current prepared argument + formal: PSym # current routine parameter + + template noMatch() = + m.state = csNoMatch + m.firstMismatch.arg = a + m.firstMismatch.formal = formal + template checkConstraint(n: untyped) {.dirty.} = if not formal.constraint.isNil: if matchNodeKinds(formal.constraint, n): # better match over other routines with no such restriction: inc(m.genericMatches, 100) else: - m.state = csNoMatch + noMatch() return if formal.typ.kind == tyVar: let argConverter = if arg.kind == nkHiddenDeref: arg[0] else: arg if argConverter.kind == nkHiddenCallConv: if argConverter.typ.kind != tyVar: - m.state = csNoMatch - m.mutabilityProblem = uint8(f-1) + m.firstMismatch.kind = kVarNeeded + noMatch() return elif not n.isLValue: - m.state = csNoMatch - m.mutabilityProblem = uint8(f-1) + m.firstMismatch.kind = kVarNeeded + noMatch() return - var - # iterates over formal parameters - f = if m.callee.kind != tyGenericBody: 1 - else: 0 - # iterates over the actual given arguments - a = 1 - arg: PNode # current prepared argument - m.state = csMatch # until proven otherwise + m.firstMismatch = MismatchInfo() m.call = newNodeI(n.kind, n.info) m.call.typ = base(m.callee) # may be nil var formalLen = m.callee.n.len addSon(m.call, copyTree(n.sons[0])) var container: PNode = nil # constructed container - var formal: PSym = if formalLen > 1: m.callee.n.sons[1].sym else: nil + formal = if formalLen > 1: m.callee.n.sons[1].sym else: nil while a < n.len: if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped: @@ -2336,26 +2350,26 @@ proc matchesAux(c: PContext, n, nOrig: PNode, addSon(container, n.sons[a]) elif n.sons[a].kind == nkExprEqExpr: # named param + m.firstMismatch.kind = kUnknownNamedParam # check if m.callee has such a param: prepareNamedParam(n.sons[a], c) if n.sons[a].sons[0].kind != nkIdent: localError(c.config, n.sons[a].info, "named parameter has to be an identifier") - m.state = csNoMatch - m.firstMismatch = -a + noMatch() return formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1) if formal == nil: # no error message! - m.state = csNoMatch - m.firstMismatch = -a + noMatch() return if containsOrIncl(marker, formal.position): + m.firstMismatch.kind = kAlreadyGiven # already in namedParams, so no match # we used to produce 'errCannotBindXTwice' here but see # bug #3836 of why that is not sound (other overload with # different parameter names could match later on): when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) - m.state = csNoMatch + noMatch() return m.baseTypeMatch = false m.typedescMatched = false @@ -2363,9 +2377,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, n.sons[a].typ = n.sons[a].sons[1].typ arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, n.sons[a].sons[1], n.sons[a].sons[1]) + m.firstMismatch.kind = kTypeMismatch if arg == nil: - m.state = csNoMatch - m.firstMismatch = a + noMatch() return checkConstraint(n.sons[a].sons[1]) if m.baseTypeMatch: @@ -2392,6 +2406,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, else: addSon(m.call, copyTree(n.sons[a])) elif formal != nil and formal.typ.kind == tyVarargs: + m.firstMismatch.kind = kTypeMismatch # beware of the side-effects in 'prepareOperand'! So only do it for # varargs matching. See tests/metatype/tstatic_overloading. m.baseTypeMatch = false @@ -2405,20 +2420,24 @@ proc matchesAux(c: PContext, n, nOrig: PNode, incrIndexType(container.typ) checkConstraint(n.sons[a]) else: - m.state = csNoMatch + noMatch() return else: - m.state = csNoMatch + m.firstMismatch.kind = kExtraArg + noMatch() return else: if m.callee.n.sons[f].kind != nkSym: internalError(c.config, n.sons[a].info, "matches") + noMatch() return formal = m.callee.n.sons[f].sym + m.firstMismatch.kind = kTypeMismatch if containsOrIncl(marker, formal.position) and container.isNil: + m.firstMismatch.kind = kAlreadyGiven # already in namedParams: (see above remark) when false: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) - m.state = csNoMatch + noMatch() return if formal.typ.isVarargsUntyped: @@ -2435,8 +2454,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, n.sons[a], nOrig.sons[a]) if arg == nil: - m.state = csNoMatch - m.firstMismatch = f + noMatch() return if m.baseTypeMatch: assert formal.typ.kind == tyVarargs @@ -2465,10 +2483,13 @@ proc matchesAux(c: PContext, n, nOrig: PNode, # this assertion can be off localError(c.config, n.sons[a].info, "cannot convert $1 to $2" % [ typeToString(n.sons[a].typ), typeToString(formal.typ) ]) - m.state = csNoMatch + noMatch() return checkConstraint(n.sons[a]) inc(a) + # for some edge cases (see tdont_return_unowned_from_owned test case) + m.firstMismatch.arg = a + m.firstMismatch.formal = formal proc semFinishOperands*(c: PContext, n: PNode) = # this needs to be called to ensure that after overloading resolution every @@ -2510,7 +2531,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = else: # no default value m.state = csNoMatch - m.firstMismatch = f + m.firstMismatch.kind = kMissingParam + m.firstMismatch.formal = formal break else: if formal.ast.kind == nkEmpty: |