From c757e69c463f7da7b5655d561bc2aa672c055fd0 Mon Sep 17 00:00:00 2001 From: saem Date: Sat, 30 Jul 2022 16:03:03 -0700 Subject: [PATCH] internals: sigmatch comments and code style No behaviour changes, a few things should be more clear. Added some `ast.newSymNode` overloads for convenience. --- compiler/ast/ast.nim | 19 +- compiler/ast/types.nim | 17 +- compiler/sem/sigmatch.nim | 781 +++++++++++++++++++++++++------------- 3 files changed, 543 insertions(+), 274 deletions(-) diff --git a/compiler/ast/ast.nim b/compiler/ast/ast.nim index 04cf8d4025e..ebe61c51d3e 100644 --- a/compiler/ast/ast.nim +++ b/compiler/ast/ast.nim @@ -200,17 +200,18 @@ proc newSymNode2*(sym: PSym, info: TLineInfo): PNode = result.typ = sym.typ result.info = info -proc newSymNode*(sym: PSym): PNode = - result = newNode(nkSym) +proc newSymNodeIT*(sym: PSym, info: TLineInfo, typ: PType): PNode = + ## create a new sym node with the supplied `info` and `typ` + result = newNodeIT(nkSym, info, typ) result.sym = sym - result.typ = sym.typ - result.info = sym.info -proc newSymNode*(sym: PSym, info: TLineInfo): PNode = - result = newNode(nkSym) - result.sym = sym - result.typ = sym.typ - result.info = info +proc newSymNode*(sym: PSym, info: TLineInfo): PNode {.inline.} = + ## create a new sym node from `sym` with its type and supplied `info` + result = newSymNodeIT(sym, info, sym.typ) + +proc newSymNode*(sym: PSym): PNode {.inline.} = + ## create a new sym node from `sym` with its info and type + result = newSymNode(sym, sym.info) proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode = result = newNode(kind) diff --git a/compiler/ast/types.nim b/compiler/ast/types.nim index 63d45d685fe..bf37eb50722 100644 --- a/compiler/ast/types.nim +++ b/compiler/ast/types.nim @@ -1163,13 +1163,20 @@ proc skipConvTakeType*(n: PNode): PNode = result.typ = n.typ proc isEmptyContainer*(t: PType): bool = + ## true if the type is considered a container and is empty, otherwise false. + ## container types are untyped, nil, `array/seq/set/etc[T]` with an emtpy + ## type for `T`. case t.kind - of tyUntyped, tyNil: result = true - of tyArray: result = t[1].kind == tyEmpty + of tyUntyped, tyNil: + true + of tyArray: + t[1].kind == tyEmpty of tySet, tySequence, tyOpenArray, tyVarargs: - result = t[0].kind == tyEmpty - of tyGenericInst, tyAlias, tySink: result = isEmptyContainer(t.lastSon) - else: result = false + t[0].kind == tyEmpty + of tyGenericInst, tyAlias, tySink: + isEmptyContainer(t.lastSon) + else: + false proc takeType*(formal, arg: PType; g: ModuleGraph; idgen: IdGenerator): PType = # param: openArray[string] = [] diff --git a/compiler/sem/sigmatch.nim b/compiler/sem/sigmatch.nim index a05619d6bfd..0f9ac10779b 100644 --- a/compiler/sem/sigmatch.nim +++ b/compiler/sem/sigmatch.nim @@ -21,6 +21,7 @@ import idents, trees, lineinfos, + errorreporting, errorhandling, reports, ], @@ -992,9 +993,11 @@ typeRel can be used to establish various relationships between types: case f.kind of tyGenericParam: var prev = PType(idTableGet(c.bindings, f)) - if prev != nil: candidate = prev + if prev != nil: + candidate = prev of tyFromExpr: let computedType = tryResolvingStaticExpr(c, f.n).typ + case computedType.kind of tyTypeDesc: candidate = computedType.base @@ -1055,8 +1058,11 @@ typeRel can be used to establish various relationships between types: result = isGeneric for branch in a.sons: let x = typeRel(c, f, branch, flags + {trDontBind}) - if x == isNone: return isNone - if x < result: result = x + if x == isNone: + result = isNone + break + elif x < result: + result = x return result of tyAnd: @@ -1071,7 +1077,8 @@ typeRel can be used to establish various relationships between types: return isNone of tyIterable: - if f.kind != tyIterable: return isNone + if f.kind != tyIterable: + return isNone of tyNot: case f.kind of tyNot: @@ -1088,8 +1095,8 @@ typeRel can be used to establish various relationships between types: else: isNone of tyAnything: - if f.kind == tyAnything: return isGeneric - else: return isNone + return if f.kind == tyAnything: isGeneric + else: isNone of tyUserTypeClass, tyUserTypeClassInst: if c.c.matchedConcept != nil and c.c.matchedConcept.depth <= 4: @@ -1099,18 +1106,25 @@ typeRel can be used to establish various relationships between types: let x = typeRel(c, a, f, flags + {trDontBind}) if x >= isGeneric: return isGeneric - else: discard + else: + discard case f.kind of tyEnum: - if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual - elif sameEnumTypes(f, skipTypes(a, {tyRange})): result = isSubtype + if a.kind == f.kind and sameEnumTypes(f, a): + result = isEqual + elif sameEnumTypes(f, skipTypes(a, {tyRange})): + result = isSubtype of tyBool, tyChar: - if a.kind == f.kind: result = isEqual - elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype + if a.kind == f.kind: + result = isEqual + elif skipTypes(a, {tyRange}).kind == f.kind: + result = isSubtype of tyRange: if a.kind == f.kind: - if f.base.kind == tyNone: return isGeneric + if f.base.kind == tyNone: + return isGeneric + result = typeRel(c, base(f), base(a), flags) # bugfix: accept integer conversions here #if result < isGeneric: result = isNone @@ -1142,29 +1156,39 @@ typeRel can be used to establish various relationships between types: of tyFloat64: result = handleFloatRange(f, a) of tyFloat128: result = handleFloatRange(f, a) of tyVar, tyLent: - if aOrig.kind == f.kind: result = typeRel(c, f.base, aOrig.base, flags) - else: result = typeRel(c, f.base, aOrig, flags + {trNoCovariance}) + result = + if aOrig.kind == f.kind: + typeRel(c, f.base, aOrig.base, flags) + else: + typeRel(c, f.base, aOrig, flags + {trNoCovariance}) + subtypeCheck() of tyArray: case a.kind of tyArray: - var fRange = f[0] - var aRange = a[0] + var + fRange = f[0] + aRange = a[0] + if fRange.kind == tyGenericParam: - var prev = PType(idTableGet(c.bindings, fRange)) + let prev = PType(idTableGet(c.bindings, fRange)) if prev == nil: put(c, fRange, a[0]) fRange = a else: fRange = prev - let ff = f[1].skipTypes({tyTypeDesc}) - # This typeDesc rule is wrong, see bug #7331 - let aa = a[1] #.skipTypes({tyTypeDesc}) - - if f[0].kind != tyGenericParam and aa.kind == tyEmpty: - result = isGeneric - else: - result = typeRel(c, ff, aa, flags) + + let + ff = f[1].skipTypes({tyTypeDesc}) + aa = a[1] #.skipTypes({tyTypeDesc}) + # This typeDesc rule is wrong, see: + # https://github.com/nim-lang/nim/issues/7331 + + result = + if f[0].kind != tyGenericParam and aa.kind == tyEmpty: + isGeneric + else: + typeRel(c, ff, aa, flags) if result < isGeneric: if nimEnableCovariance and @@ -1182,24 +1206,29 @@ typeRel can be used to establish various relationships between types: else: if lengthOrd(c.c.config, fRange) != lengthOrd(c.c.config, aRange): result = isNone - else: discard + else: + discard of tyUncheckedArray: if a.kind == tyUncheckedArray: result = typeRel(c, base(f), base(a), flags) - if result < isGeneric: result = isNone - else: discard + if result < isGeneric: + result = isNone + else: + discard of tyOpenArray, tyVarargs: # varargs[untyped] is special too but handled earlier. So we only need to # handle varargs[typed]: if f.kind == tyVarargs: if tfVarargs in a.flags: return typeRel(c, f.base, a.lastSon, flags) - if f[0].kind == tyTyped: return + if f[0].kind == tyTyped: + return template matchArrayOrSeq(aBase: PType) = - let ff = f.base - let aa = aBase - let baseRel = typeRel(c, ff, aa, flags) + let + ff = f.base + aa = aBase + baseRel = typeRel(c, ff, aa, flags) if baseRel >= isGeneric: result = isConvertible elif nimEnableCovariance and @@ -1211,7 +1240,8 @@ typeRel can be used to establish various relationships between types: case a.kind of tyOpenArray, tyVarargs: result = typeRel(c, base(f), base(a), flags) - if result < isGeneric: result = isNone + if result < isGeneric: + result = isNone of tyArray: if (f[0].kind != tyGenericParam) and (a[1].kind == tyEmpty): return isSubtype @@ -1227,15 +1257,17 @@ typeRel can be used to establish various relationships between types: elif f[0].kind == tyGenericParam and a.len > 0 and typeRel(c, base(f), base(a), flags) >= isGeneric: result = isConvertible - else: discard + else: + discard of tySequence: case a.kind of tySequence: if (f[0].kind != tyGenericParam) and (a[0].kind == tyEmpty): result = isSubtype else: - let ff = f[0] - let aa = a[0] + let + ff = f[0] + aa = a[0] result = typeRel(c, ff, aa, flags) if result < isGeneric: if nimEnableCovariance and @@ -1247,16 +1279,24 @@ typeRel can be used to establish various relationships between types: result = isNone elif tfNotNil in f.flags and tfNotNil notin a.flags: result = isNilConversion - of tyNil: result = isNone - else: discard + of tyNil: + result = isNone + else: + discard of tyOrdinal: if isOrdinalType(a, allowEnumWithHoles = optNimV1Emulation in c.c.config.globalOptions): - var x = if a.kind == tyOrdinal: a[0] else: a + var x = + if a.kind == tyOrdinal: + a[0] + else: + a + if f[0].kind == tyNone: result = isGeneric else: result = typeRel(c, f[0], x, flags) - if result < isGeneric: result = isNone + if result < isGeneric: + result = isNone elif a.kind == tyGenericParam: result = isGeneric of tyForward: @@ -1264,9 +1304,11 @@ typeRel can be used to establish various relationships between types: result = isNone of tyNil: skipOwned(a) - if a.kind == f.kind: result = isEqual + if a.kind == f.kind: + result = isEqual of tyTuple: - if a.kind == tyTuple: result = recordRel(c, f, a) + if a.kind == tyTuple: + result = recordRel(c, f, a) of tyObject: if a.kind == tyObject: if sameObjectTypes(f, a): @@ -1280,12 +1322,16 @@ typeRel can be used to establish various relationships between types: of tyDistinct: a = a.skipTypes({tyOwned, tyGenericInst, tyRange}) if a.kind == tyDistinct: - if sameDistinctTypes(f, a): result = isEqual - #elif f.base.kind == tyAnything: result = isGeneric # issue 4435 - elif c.coerceDistincts: result = typeRel(c, f.base, a, flags) + if sameDistinctTypes(f, a): + result = isEqual + #elif f.base.kind == tyAnything: + # result = isGeneric # see https://github.com/nim-lang/nim/issues/4435 + elif c.coerceDistincts: + result = typeRel(c, f.base, a, flags) elif a.kind == tyNil and f.base.kind in NilableTypes: result = f.allowsNil # XXX remove this typing rule, it is not in the spec - elif c.coerceDistincts: result = typeRel(c, f.base, a, flags) + elif c.coerceDistincts: + result = typeRel(c, f.base, a, flags) of tySet: if a.kind == tySet: if f[0].kind != tyGenericParam and a[0].kind == tyEmpty: @@ -1303,16 +1349,24 @@ typeRel can be used to establish various relationships between types: skipOwned(a) if a.kind == f.kind: # ptr[R, T] can be passed to ptr[T], but not the other way round: - if a.len < f.len: return isNone + if a.len < f.len: + return isNone + for i in 0.. isGeneric: result = isGeneric + if x < result: + result = x + if result > isGeneric: + result = isGeneric bindingRet result of tyOr: @@ -1570,9 +1654,11 @@ typeRel can be used to establish various relationships between types: maxInheritance = max(maxInheritance, c.inheritancePenalty) # 'or' implies maximum matching result: - if x > result: result = x + if x > result: + result = x if result >= isSubtype: - if result > isGeneric: result = isGeneric + if result > isGeneric: + result = isGeneric bindingRet result else: result = isNone @@ -1595,10 +1681,12 @@ typeRel can be used to establish various relationships between types: of tyBuiltInTypeClass: considerPreviousT: - let targetKind = f[0].kind - let effectiveArgType = a.skipTypes({tyRange, tyGenericInst, - tyBuiltInTypeClass, tyAlias, tySink, tyOwned}) - let typeClassMatches = targetKind == effectiveArgType.kind and + let + targetKind = f[0].kind + effectiveArgType = a.skipTypes({tyRange, tyGenericInst, + tyBuiltInTypeClass, tyAlias, + tySink, tyOwned}) + typeClassMatches = targetKind == effectiveArgType.kind and not effectiveArgType.isEmptyContainer if typeClassMatches or (targetKind in {tyProc, tyPointer} and effectiveArgType.kind == tyNil): @@ -1612,11 +1700,15 @@ typeRel can be used to establish various relationships between types: result = typeRel(c, f.lastSon, a, flags) else: considerPreviousT: - if aOrig == f: return isEqual + if aOrig == f: + return isEqual + var matched = matchUserTypeClass(c, f, aOrig) + if matched != nil: bindConcreteTypeToUserTypeClass(matched, a) - if doBind: put(c, f, matched) + if doBind: + put(c, f, matched) result = isGeneric elif a.len > 0 and a.lastSon == f: # Needed for checking `Y` == `Addable` in the following @@ -1632,15 +1724,19 @@ typeRel can be used to establish various relationships between types: of tyCompositeTypeClass: considerPreviousT: - let roota = a.skipGenericAlias - let rootf = f.lastSon.skipGenericAlias + let + roota = a.skipGenericAlias + rootf = f.lastSon.skipGenericAlias if a.kind == tyGenericInst and roota.base == rootf.base: for i in 1.. isGeneric: result = isGeneric + if result > isGeneric: + result = isGeneric elif c.isNoCall: if doBindGP: let concrete = concreteType(c, a, f) @@ -1870,13 +1967,14 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate, proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, c: PContext): PNode = result = newNodeI(kind, arg.info) - if containsGenericType(f): - if not m.hasFauxMatch: - result.typ = getInstantiatedType(c, arg, m, f).skipTypes({tySink}) + result.typ = + if containsGenericType(f): + if not m.hasFauxMatch: + getInstantiatedType(c, arg, m, f).skipTypes({tySink}) + else: + errorType(c) else: - result.typ = errorType(c) - else: - result.typ = f.skipTypes({tySink}) + f.skipTypes({tySink}) c.graph.config.internalAssert(result.typ != nil, arg.info, "implicitConv") @@ -1884,107 +1982,139 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, result.add arg proc isLValue(c: PContext; n: PNode): bool {.inline.} = - let aa = isAssignable(nil, n) - case aa + case isAssignable(nil, n) of arLValue, arLocalLValue, arStrange: - result = true + true of arDiscriminant: - result = c.inUncheckedAssignSection > 0 + c.inUncheckedAssignSection > 0 else: - result = false + false proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, arg: PNode): PNode = result = nil + for i in 0.. 1: m.callee.n[1].sym else: nil # current routine parameter - container: PNode = nil # constructed container - let firstArgBlock = findFirstArgBlock(m, n) + formal = if formalLen > 1: m.callee.n[1].sym else: nil + ## current routine parameter + container: PNode = nil + ## container (arg list, bracket, ...) to store intermediaries + while a < n.len: c.openShadowScope - if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped: + # untyped varargs + if a >= formalLen - 1 and # last or finished passing args + f < formalLen and # still have more formal params + m.callee.n[f].typ.isVarargsUntyped: # current formal is varargs untped + formal = m.callee.n[f].sym incl(marker, formal.position) - if n[a].kind == nkHiddenStdConv: + case n[a].kind + of nkHiddenStdConv: + # if there is a conversion we, "steal" its container and pass it along doAssert n[a][0].kind == nkEmpty and n[a][1].kind in {nkBracket, nkArgList} - # Steal the container and pass it along + # xxx: is reusing the converted call arg's container sound? setSon(m.call, formal.position + 1, n[a][1]) else: + # make sure we have a container for the varargs if container.isNil: container = newNodeIT(nkArgList, n[a].info, arrayConstr(c, n.info)) setSon(m.call, formal.position + 1, container) else: incrIndexType(container.typ) + container.add n[a] - elif n[a].kind == nkExprEqExpr: + elif n[a].kind == nkExprEqExpr: # named params `foo(bar = "baz")` # named param + + # assume it's wrong, then prove it correct m.error.firstMismatch.kind = kUnknownNamedParam + # check if m.callee has such a param: prepareNamedParam(n[a], c) + if n[a].kind == nkError or n[a][0].kind != nkIdent: localReport(c.config, n[a].info, reportAst( rsemExpectedIdentifier, n[a], str = "named parameter has to be an identifier" )) - noMatch() + formal = getNamedParamFromList(m.callee.n, n[a][0].ident) - if formal == nil or formal.isError: + + if formal.isNil or formal.isError: # no error message! noMatch() + if containsOrIncl(marker, formal.position): m.error.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): + # bug https://github.com/nim-lang/nim/issues/3836 for why that is not + # sound (other overload with different parameter names could match + # later on) + # + # xxx: with nkError this is likely no longer an issue when false: localReport(n[a].info, errCannotBindXTwice, formal.name.s) noMatch() + m.baseTypeMatch = false m.typedescMatched = false n[a][1] = prepareOperand(c, formal.typ, n[a][1]) n[a].typ = n[a][1].typ arg = paramTypesMatch(m, formal.typ, n[a].typ, n[a][1]) m.error.firstMismatch.kind = kTypeMismatch + if arg == nil or arg.isErrorLike: noMatch() - elif n[a][1].isErrorLike: + elif n[a][1].isErrorLike: # named param's value is an error noMatchDueToError() - checkConstraint(n[a][1]) + + checkConstraint(n[a][1]) # will update `m` with info + if m.baseTypeMatch: #assert(container == nil) container = newNodeIT(nkBracket, n[a].info, arrayConstr(c, arg)) container.add arg setSon(m.call, formal.position + 1, container) - if f != formalLen - 1: container = nil + if f != formalLen - 1: # not the last formal param + container = nil # xxx: is this more vararg stuff? else: setSon(m.call, formal.position + 1, arg) + inc f - else: - # unnamed param + else: # unnamed param `foo("baz")` if f >= formalLen: # too many arguments? if tfVarargs in m.callee.flags: # is ok... but don't increment any counters... # we have no formal here to snoop at: n[a] = prepareOperand(c, n[a]) - if skipTypes(n[a].typ, abstractVar-{tyTypeDesc}).kind==tyString: + + case skipTypes(n[a].typ, abstractVar-{tyTypeDesc}).kind + of tyString: + # implicit conversion string -> cstring m.call.add implicitConv(nkHiddenStdConv, - getSysType(c.graph, n[a].info, tyCstring), - copyTree(n[a]), m, c) + getSysType(c.graph, n[a].info, tyCstring), + copyTree(n[a]), m, c) else: m.call.add copyTree(n[a]) - elif formal != nil and formal.typ.kind == tyVarargs: + elif formal != nil and formal.typ.kind == tyVarargs: # extra varargs m.error.firstMismatch.kind = kTypeMismatch # beware of the side-effects in 'prepareOperand'! So only do it for # varargs matching. See tests/metatype/tstatic_overloading. @@ -2482,13 +2695,16 @@ proc matchesAux(c: PContext, n: PNode, m: var TCandidate, marker: var IntSet) = m.typedescMatched = false incl(marker, formal.position) n[a] = prepareOperand(c, formal.typ, n[a]) - arg = paramTypesMatch(m, formal.typ, n[a].typ, - n[a]) - if arg != nil and arg.kind != nkError and m.baseTypeMatch and container != nil: + arg = paramTypesMatch(m, formal.typ, n[a].typ, n[a]) + + if arg != nil and arg.kind != nkError and # valid argument + m.baseTypeMatch and # match type in `varargs[T]` + container != nil: # container must exist + container.add arg incrIndexType(container.typ) checkConstraint(n[a]) - elif n[a].isErrorLike: + elif n[a].isErrorLike: # invalid operand noMatchDueToError() else: noMatch() @@ -2496,50 +2712,66 @@ proc matchesAux(c: PContext, n: PNode, m: var TCandidate, marker: var IntSet) = m.error.firstMismatch.kind = kExtraArg noMatch() else: - c.config.internalAssert(m.callee.n[f].kind == nkSym, n[a].info, "matches") - if a >= firstArgBlock: f = max(f, m.callee.n.len - (n.len - a)) + c.config.internalAssert(m.callee.n[f].kind == nkSym, n[a].info, + "matches") + + if a >= firstArgBlock: + f = max(f, m.callee.n.len - (n.len - a)) + formal = m.callee.n[f].sym m.error.firstMismatch.kind = kTypeMismatch + + # both positional and named argument for the same formal if containsOrIncl(marker, formal.position) and container.isNil: m.error.firstMismatch.kind = kPositionalAlreadyGiven - # positional param already in namedParams: (see above remark) - when false: localReport(n[a].info, errCannotBindXTwice, formal.name.s) + # positional param already in namedParams, see named param handling + # above for additional remarks about `errCannotBindXTwice` + # + # xxx: shouldn't be an issue with nkError + when false: + localReport(n[a].info, errCannotBindXTwice, formal.name.s) noMatch() - if formal.typ.isVarargsUntyped: + if formal.typ.isVarargsUntyped: # first untyped varargs param if container.isNil: container = newNodeIT(nkArgList, n[a].info, arrayConstr(c, n.info)) setSon(m.call, formal.position + 1, container) else: incrIndexType(container.typ) + container.add n[a] - else: + else: # additional varargs or other param + + # xxx: this code and the unnamed/varargs handling above are near + # identical, should revise the overall logic and deduplicate + m.baseTypeMatch = false m.typedescMatched = false n[a] = prepareOperand(c, formal.typ, n[a]) - arg = paramTypesMatch(m, formal.typ, n[a].typ, - n[a]) + arg = paramTypesMatch(m, formal.typ, n[a].typ, n[a]) - if arg == nil or arg.isErrorLike: + if arg == nil or arg.isErrorLike: # invalid arg noMatch() - elif n[a].isErrorLike: + elif n[a].isErrorLike: # invalid operand noMatchDueToError() - if m.baseTypeMatch: + + if m.baseTypeMatch: # var args assert formal.typ.kind == tyVarargs - #assert(container == nil) + if container.isNil: container = newNodeIT(nkBracket, n[a].info, arrayConstr(c, arg)) container.typ.flags.incl tfVarargs else: incrIndexType(container.typ) + container.add 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: + # pick the formal from the end, so a regular param can follow a + # varargs: 'foo(x: int, y: varargs[typed], blk: untyped): typed' f = max(f, formalLen - n.len + a + 1) - elif formal.typ.kind != tyVarargs or container == nil: + elif formal.typ.kind != tyVarargs or container == nil: # regular arg setSon(m.call, formal.position + 1, arg) inc f container = nil @@ -2547,8 +2779,7 @@ proc matchesAux(c: PContext, n: PNode, m: var TCandidate, marker: var IntSet) = # we end up here if the argument can be converted into the varargs # formal (e.g. seq[T] -> varargs[T]) but we have already instantiated # a container - #assert arg.kind == nkHiddenStdConv # for 'nim check' - # this assertion can be off + localReport(c.config, n[a].info, SemReport( kind: rsemCannotConvertTypes, @@ -2556,14 +2787,18 @@ proc matchesAux(c: PContext, n: PNode, m: var TCandidate, marker: var IntSet) = formal = formal.typ, actual = n[a].typ)])) noMatch() + checkConstraint(n[a]) - if m.state == csMatch and not (m.calleeSym != nil and m.calleeSym.kind in {skTemplate, skMacro}): + if m.state == csMatch and + not (m.calleeSym != nil and m.calleeSym.kind in {skTemplate, skMacro}): c.mergeShadowScope else: c.closeShadowScope inc a + + # xxx: what??? # for some edge cases (see tdont_return_unowned_from_owned test case) m.error.firstMismatch.pos = a m.error.firstMismatch.formal = formal @@ -2581,28 +2816,42 @@ proc partialMatch*(c: PContext, n: PNode, m: var TCandidate) = proc matches*(c: PContext, n: PNode, m: var TCandidate) = addInNimDebugUtils(c.config, "matches", n, m) + if m.magic in {mArrGet, mArrPut}: m.state = csMatch m.call = n + # Note the following doesn't work as it would produce ambiguities. - # Instead we patch system.nim, see bug #8049. + # We hack system.nim instead: https://github.com/nim-lang/nim/issues/8049. + # xxx: shouldn't this be a generic match and not an exact one, then? when false: inc m.genericMatches inc m.exactMatches + return + var marker = initIntSet() matchesAux(c, n, m, marker) - if m.state == csNoMatch: return + + if m.state == csNoMatch: + return + # check that every formal parameter got a value: for f in 1.. 1: t.sons.setLen 1 + if t.len > 1: + t.sons.setLen 1 proc argtypeMatches*(c: PContext, f, a: PType, fromHlo = false): bool = var m = newCandidate(c, f)