This commit is contained in:
Araq 2015-03-05 20:39:25 +01:00
commit cac259cdfb
3 changed files with 200 additions and 180 deletions

View file

@ -41,48 +41,55 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
best, alt: var TCandidate, best, alt: var TCandidate,
errors: var CandidateErrors) = errors: var CandidateErrors) =
var o: TOverloadIter var o: TOverloadIter
var sym = initOverloadIter(o, c, headSymbol) # thanks to the lazy semchecking for operands, we need to iterate over the
# symbol table *before* any call to 'initCandidate' which might invoke
# semExpr which might modify the symbol table in cases like
# 'init(a, 1, (var b = new(Type2); b))'.
var symx = initOverloadIter(o, c, headSymbol)
let symScope = o.lastOverloadScope let symScope = o.lastOverloadScope
var z: TCandidate var syms: seq[tuple[a: PSym, b: int]] = @[]
while symx != nil:
if symx.kind in filter: syms.add((symx, o.lastOverloadScope))
symx = nextOverloadIter(o, c, headSymbol)
if syms.len == 0: return
if sym == nil: return var z: TCandidate
initCandidate(c, best, sym, initialBinding, symScope) initCandidate(c, best, syms[0][0], initialBinding, symScope)
initCandidate(c, alt, sym, initialBinding, symScope) initCandidate(c, alt, syms[0][0], initialBinding, symScope)
best.state = csNoMatch best.state = csNoMatch
while sym != nil: for i in 0 .. <syms.len:
if sym.kind in filter: let sym = syms[i][0]
determineType(c, sym) determineType(c, sym)
initCandidate(c, z, sym, initialBinding, o.lastOverloadScope) initCandidate(c, z, sym, initialBinding, syms[i][1])
z.calleeSym = sym z.calleeSym = sym
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
# gDebug = true
matches(c, n, orig, z)
if errors != nil:
errors.safeAdd(sym)
if z.errors != nil:
for err in z.errors:
errors.add(err)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind in skIterators: inc(z.exactMatches, 200)
case best.state
of csEmpty, csNoMatch: best = z
of csMatch:
var cmp = cmpCandidates(best, z)
if cmp < 0: best = z # x is better than the best so far
elif cmp == 0: alt = z # x is as good as the best so far
else: discard
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140: #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
# gDebug = true # echo "Matches ", n.info, " ", typeToString(sym.typ)
matches(c, n, orig, z) # debug sym
if errors != nil: # writeMatches(z)
errors.safeAdd(sym) # for i in 1 .. <len(z.call):
if z.errors != nil: # z.call[i].typ.debug
for err in z.errors: # quit 1
errors.add(err)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind in skIterators: inc(z.exactMatches, 200)
case best.state
of csEmpty, csNoMatch: best = z
of csMatch:
var cmp = cmpCandidates(best, z)
if cmp < 0: best = z # x is better than the best so far
elif cmp == 0: alt = z # x is as good as the best so far
else: discard
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
# echo "Matches ", n.info, " ", typeToString(sym.typ)
# debug sym
# writeMatches(z)
# for i in 1 .. <len(z.call):
# z.call[i].typ.debug
# quit 1
sym = nextOverloadIter(o, c, headSymbol)
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
# Gives a detailed error message; this is separated from semOverloadedCall, # Gives a detailed error message; this is separated from semOverloadedCall,

View file

@ -10,7 +10,7 @@
## This module implements the signature matching for resolving ## This module implements the signature matching for resolving
## the call to overloaded procs, generic procs and operators. ## the call to overloaded procs, generic procs and operators.
import import
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees, magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
nimfix.pretty nimfix.pretty
@ -19,7 +19,7 @@ when not defined(noDocgen):
import docgen import docgen
type type
TCandidateState* = enum TCandidateState* = enum
csEmpty, csMatch, csNoMatch csEmpty, csMatch, csNoMatch
CandidateErrors* = seq[PSym] CandidateErrors* = seq[PSym]
@ -62,10 +62,10 @@ type
isGeneric, isGeneric,
isFromIntLit, # conversion *from* int literal; proven safe isFromIntLit, # conversion *from* int literal; proven safe
isEqual isEqual
const const
isNilConversion = isConvertible # maybe 'isIntConv' fits better? isNilConversion = isConvertible # maybe 'isIntConv' fits better?
proc markUsed*(info: TLineInfo, s: PSym) proc markUsed*(info: TLineInfo, s: PSym)
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
@ -128,7 +128,7 @@ proc newCandidate*(ctx: PContext, callee: PSym,
proc newCandidate*(ctx: PContext, callee: PType): TCandidate = proc newCandidate*(ctx: PContext, callee: PType): TCandidate =
initCandidate(ctx, result, callee) initCandidate(ctx, result, callee)
proc copyCandidate(a: var TCandidate, b: TCandidate) = proc copyCandidate(a: var TCandidate, b: TCandidate) =
a.c = b.c a.c = b.c
a.exactMatches = b.exactMatches a.exactMatches = b.exactMatches
a.subtypeMatches = b.subtypeMatches a.subtypeMatches = b.subtypeMatches
@ -176,7 +176,7 @@ proc complexDisambiguation(a, b: PType): int =
let bb = b.sons[1].sumGeneric let bb = b.sons[1].sumGeneric
var a = a var a = a
var b = b var b = b
if aa < bb: swap(a, b) if aa < bb: swap(a, b)
# all must be better # all must be better
for i in 2 .. <min(a.len, b.len): for i in 2 .. <min(a.len, b.len):
@ -203,7 +203,7 @@ proc cmpCandidates*(a, b: TCandidate): int =
# prefer more specialized generic over more general generic: # prefer more specialized generic over more general generic:
result = complexDisambiguation(a.callee, b.callee) result = complexDisambiguation(a.callee, b.callee)
proc writeMatches*(c: TCandidate) = proc writeMatches*(c: TCandidate) =
writeln(stdout, "exact matches: " & $c.exactMatches) writeln(stdout, "exact matches: " & $c.exactMatches)
writeln(stdout, "generic matches: " & $c.genericMatches) writeln(stdout, "generic matches: " & $c.genericMatches)
writeln(stdout, "subtype matches: " & $c.subtypeMatches) writeln(stdout, "subtype matches: " & $c.subtypeMatches)
@ -225,7 +225,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
result = "" result = ""
for i in countup(startIdx, n.len - 1): for i in countup(startIdx, n.len - 1):
var arg = n.sons[i] var arg = n.sons[i]
if n.sons[i].kind == nkExprEqExpr: if n.sons[i].kind == nkExprEqExpr:
add(result, renderTree(n.sons[i].sons[0])) add(result, renderTree(n.sons[i].sons[0]))
add(result, ": ") add(result, ": ")
if arg.typ.isNil: if arg.typ.isNil:
@ -241,9 +241,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
if i != sonsLen(n) - 1: add(result, ", ") if i != sonsLen(n) - 1: add(result, ", ")
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
proc concreteType(c: TCandidate, t: PType): PType = proc concreteType(c: TCandidate, t: PType): PType =
case t.kind case t.kind
of tyArrayConstr: of tyArrayConstr:
# make it an array # make it an array
result = newType(tyArray, t.owner) result = newType(tyArray, t.owner)
addSonSkipIntLit(result, t.sons[0]) # XXX: t.owner is wrong for ID! addSonSkipIntLit(result, t.sons[0]) # XXX: t.owner is wrong for ID!
@ -255,7 +255,7 @@ proc concreteType(c: TCandidate, t: PType): PType =
else: result = t else: result = t
of tyGenericParam, tyAnything: of tyGenericParam, tyAnything:
result = t result = t
while true: while true:
result = PType(idTableGet(c.bindings, t)) result = PType(idTableGet(c.bindings, t))
if result == nil: if result == nil:
break # it's ok, no match break # it's ok, no match
@ -267,15 +267,15 @@ proc concreteType(c: TCandidate, t: PType): PType =
result = t result = t
else: else:
result = t # Note: empty is valid here result = t # Note: empty is valid here
proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
if a.kind == f.kind: if a.kind == f.kind:
result = isEqual result = isEqual
else: else:
let ab = skipTypes(a, {tyRange}) let ab = skipTypes(a, {tyRange})
let k = ab.kind let k = ab.kind
if k == f.kind: result = isSubrange if k == f.kind: result = isSubrange
elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64, elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64,
tyUInt..tyUInt64} and tyUInt..tyUInt64} and
isIntLit(ab) and ab.n.intVal >= firstOrd(f) and isIntLit(ab) and ab.n.intVal >= firstOrd(f) and
ab.n.intVal <= lastOrd(f): ab.n.intVal <= lastOrd(f):
@ -286,7 +286,7 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
result = isIntConv result = isIntConv
elif k >= min and k <= max: elif k >= min and k <= max:
result = isConvertible result = isConvertible
elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64, elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64,
tyUInt8..tyUInt32} and tyUInt8..tyUInt32} and
a.n[0].intVal >= firstOrd(f) and a.n[0].intVal >= firstOrd(f) and
a.n[1].intVal <= lastOrd(f): a.n[1].intVal <= lastOrd(f):
@ -318,12 +318,12 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
if f.kind == tyFloat32: result = isConvertible if f.kind == tyFloat32: result = isConvertible
else: result = isIntConv else: result = isIntConv
else: result = isNone else: result = isNone
proc isObjectSubtype(a, f: PType): int = proc isObjectSubtype(a, f: PType): int =
var t = a var t = a
assert t.kind == tyObject assert t.kind == tyObject
var depth = 0 var depth = 0
while t != nil and not sameObjectTypes(f, t): while t != nil and not sameObjectTypes(f, t):
assert t.kind == tyObject assert t.kind == tyObject
t = t.sons[0] t = t.sons[0]
if t == nil: break if t == nil: break
@ -332,17 +332,17 @@ proc isObjectSubtype(a, f: PType): int =
if t != nil: if t != nil:
result = depth result = depth
proc minRel(a, b: TTypeRelation): TTypeRelation = proc minRel(a, b: TTypeRelation): TTypeRelation =
if a <= b: result = a if a <= b: result = a
else: result = b else: result = b
proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation = proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
result = isNone result = isNone
if sameType(f, a): result = isEqual if sameType(f, a): result = isEqual
elif sonsLen(a) == sonsLen(f): elif sonsLen(a) == sonsLen(f):
result = isEqual result = isEqual
let firstField = if f.kind == tyTuple: 0 let firstField = if f.kind == tyTuple: 0
else: 1 else: 1
for i in countup(firstField, sonsLen(f) - 1): for i in countup(firstField, sonsLen(f) - 1):
var m = typeRel(c, f.sons[i], a.sons[i]) var m = typeRel(c, f.sons[i], a.sons[i])
if m < isSubtype: return isNone if m < isSubtype: return isNone
@ -373,7 +373,7 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
# We are matching a generic proc (as proc param) # We are matching a generic proc (as proc param)
# to another generic type appearing in the proc # to another generic type appearing in the proc
# signature. There is a change that the target # signature. There is a change that the target
# type is already fully-determined, so we are # type is already fully-determined, so we are
# going to try resolve it # going to try resolve it
f = generateTypeInstance(c.c, c.bindings, c.call.info, f) f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
if f == nil or f.isMetaType: if f == nil or f.isMetaType:
@ -388,17 +388,17 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
if result <= isSubtype or inconsistentVarTypes(f, a): if result <= isSubtype or inconsistentVarTypes(f, a):
result = isNone result = isNone
if result == isEqual: if result == isEqual:
inc c.exactMatches inc c.exactMatches
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
case a.kind case a.kind
of tyProc: of tyProc:
if sonsLen(f) != sonsLen(a): return if sonsLen(f) != sonsLen(a): return
result = isEqual # start with maximum; also correct for no result = isEqual # start with maximum; also correct for no
# params at all # params at all
template checkParam(f, a) = template checkParam(f, a) =
result = minRel(result, procParamTypeRel(c, f, a)) result = minRel(result, procParamTypeRel(c, f, a))
if result == isNone: return if result == isNone: return
@ -407,7 +407,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
# return type! # return type!
for i in 1 .. <f.sonsLen: for i in 1 .. <f.sonsLen:
checkParam(f.sons[i], a.sons[i]) checkParam(f.sons[i], a.sons[i])
if f.sons[0] != nil: if f.sons[0] != nil:
if a.sons[0] != nil: if a.sons[0] != nil:
checkParam(f.sons[0], a.sons[0]) checkParam(f.sons[0], a.sons[0])
@ -487,14 +487,14 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
else: else:
param = paramSym skType param = paramSym skType
param.typ = makeTypeDesc(c, typ) param.typ = makeTypeDesc(c, typ)
addDecl(c, param) addDecl(c, param)
for param in body.n[0]: for param in body.n[0]:
var var
dummyName: PNode dummyName: PNode
dummyType: PType dummyType: PType
if param.kind == nkVarTy: if param.kind == nkVarTy:
dummyName = param[0] dummyName = param[0]
dummyType = if a.kind != tyVar: makeVarType(c, a) dummyType = if a.kind != tyVar: makeVarType(c, a)
@ -520,7 +520,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
of nkTypeSection: discard of nkTypeSection: discard
of nkConstDef: discard of nkConstDef: discard
else: discard else: discard
return isGeneric return isGeneric
proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool = proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
@ -554,7 +554,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# typeRel can be used to establish various relationships between types: # typeRel can be used to establish various relationships between types:
# #
# 1) When used with concrete types, it will check for type equivalence # 1) When used with concrete types, it will check for type equivalence
# or a subtype relationship. # or a subtype relationship.
# #
# 2) When used with a concrete type against a type class (such as generic # 2) When used with a concrete type against a type class (such as generic
# signature of a proc), it will check whether the concrete type is a member # signature of a proc), it will check whether the concrete type is a member
@ -569,7 +569,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = isNone result = isNone
assert(f != nil) assert(f != nil)
if f.kind == tyExpr: if f.kind == tyExpr:
if aOrig != nil: put(c.bindings, f, aOrig) if aOrig != nil: put(c.bindings, f, aOrig)
return isGeneric return isGeneric
@ -582,7 +582,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# start the param matching process. This could be done in `prepareOperand` # start the param matching process. This could be done in `prepareOperand`
# for example, but unfortunately `prepareOperand` is not called in certain # for example, but unfortunately `prepareOperand` is not called in certain
# situation when nkDotExpr are rotated to nkDotCalls # situation when nkDotExpr are rotated to nkDotCalls
if a.kind == tyGenericInst and if a.kind == tyGenericInst and
skipTypes(f, {tyVar}).kind notin { skipTypes(f, {tyVar}).kind notin {
tyGenericBody, tyGenericInvocation, tyGenericBody, tyGenericInvocation,
@ -626,9 +626,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# seq[!int] vs seq[!number] # seq[!int] vs seq[!number]
# seq[float] matches the first, but not the second # seq[float] matches the first, but not the second
# we must turn the problem around: # we must turn the problem around:
# is number a subset of int? # is number a subset of int?
return typeRel(c, a.lastSon, f.lastSon) return typeRel(c, a.lastSon, f.lastSon)
else: else:
# negative type classes are essentially infinite, # negative type classes are essentially infinite,
# so only the `any` type class is their superset # so only the `any` type class is their superset
@ -727,20 +727,20 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
result = typeRel(c, base(f), base(a)) result = typeRel(c, base(f), base(a))
if result < isGeneric: result = isNone if result < isGeneric: result = isNone
of tyArrayConstr: of tyArrayConstr:
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
result = isSubtype # [] is allowed here result = isSubtype # [] is allowed here
elif typeRel(c, base(f), a.sons[1]) >= isGeneric: elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
result = isSubtype result = isSubtype
of tyArray: of tyArray:
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
result = isSubtype result = isSubtype
elif typeRel(c, base(f), a.sons[1]) >= isGeneric: elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
result = isConvertible result = isConvertible
of tySequence: of tySequence:
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
result = isConvertible result = isConvertible
elif typeRel(c, base(f), a.sons[0]) >= isGeneric: elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
result = isConvertible result = isConvertible
else: discard else: discard
of tySequence: of tySequence:
@ -768,7 +768,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyForward: internalError("forward type in typeRel()") of tyForward: internalError("forward type in typeRel()")
of tyNil: of tyNil:
if a.kind == f.kind: result = isEqual if a.kind == f.kind: result = isEqual
of tyTuple: of tyTuple:
if a.kind == tyTuple: result = recordRel(c, f, a) if a.kind == tyTuple: result = recordRel(c, f, a)
of tyObject: of tyObject:
if a.kind == tyObject: if a.kind == tyObject:
@ -783,13 +783,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyDistinct: of tyDistinct:
if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual
elif c.coerceDistincts: result = typeRel(c, f.base, a) elif c.coerceDistincts: result = typeRel(c, f.base, a)
of tySet: of tySet:
if a.kind == tySet: if a.kind == tySet:
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
result = isSubtype result = isSubtype
else: else:
result = typeRel(c, f.sons[0], a.sons[0]) result = typeRel(c, f.sons[0], a.sons[0])
if result <= isConvertible: if result <= isConvertible:
result = isNone # BUGFIX! result = isNone # BUGFIX!
of tyPtr, tyRef: of tyPtr, tyRef:
if a.kind == f.kind: if a.kind == f.kind:
@ -823,9 +823,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if a.len == 1: result = isConvertible if a.len == 1: result = isConvertible
of tyCString: result = isConvertible of tyCString: result = isConvertible
else: discard else: discard
of tyString: of tyString:
case a.kind case a.kind
of tyString: of tyString:
if tfNotNil in f.flags and tfNotNil notin a.flags: if tfNotNil in f.flags and tfNotNil notin a.flags:
result = isNilConversion result = isNilConversion
else: else:
@ -848,7 +848,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyArray: of tyArray:
if (firstOrd(a.sons[0]) == 0) and if (firstOrd(a.sons[0]) == 0) and
(skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and (skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and
(a.sons[1].kind == tyChar): (a.sons[1].kind == tyChar):
result = isConvertible result = isConvertible
else: discard else: discard
@ -863,7 +863,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
let ff = rootf.sons[i] let ff = rootf.sons[i]
let aa = roota.sons[i] let aa = roota.sons[i]
result = typeRel(c, ff, aa) result = typeRel(c, ff, aa)
if result == isNone: return if result == isNone: return
if ff.kind == tyRange and result != isEqual: return isNone if ff.kind == tyRange and result != isEqual: return isNone
result = isGeneric result = isGeneric
# XXX See bug #2220. A[int] should match A[int] better than some generic X # XXX See bug #2220. A[int] should match A[int] better than some generic X
@ -883,13 +883,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation") #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
# simply no match for now: # simply no match for now:
discard discard
elif x.kind == tyGenericInst and elif x.kind == tyGenericInst and
(f.sons[0] == x.sons[0]) and (f.sons[0] == x.sons[0]) and
(sonsLen(x) - 1 == sonsLen(f)): (sonsLen(x) - 1 == sonsLen(f)):
for i in countup(1, sonsLen(f) - 1): for i in countup(1, sonsLen(f) - 1):
if x.sons[i].kind == tyGenericParam: if x.sons[i].kind == tyGenericParam:
internalError("wrong instantiated type!") 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: return
result = isGeneric result = isGeneric
else: else:
result = typeRel(c, f.sons[0], x) result = typeRel(c, f.sons[0], x)
@ -900,7 +900,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}: if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}:
internalError("wrong instantiated type!") internalError("wrong instantiated type!")
put(c.bindings, f.sons[i], x) put(c.bindings, f.sons[i], x)
of tyAnd: of tyAnd:
considerPreviousT: considerPreviousT:
for branch in f.sons: for branch in f.sons:
@ -914,7 +914,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
for branch in f.sons: for branch in f.sons:
if typeRel(c, branch, aOrig) >= isSubtype: if typeRel(c, branch, aOrig) >= isSubtype:
bindingRet isGeneric bindingRet isGeneric
return isNone return isNone
of tyNot: of tyNot:
@ -922,7 +922,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
for branch in f.sons: for branch in f.sons:
if typeRel(c, branch, aOrig) != isNone: if typeRel(c, branch, aOrig) != isNone:
return isNone return isNone
bindingRet isGeneric bindingRet isGeneric
of tyAnything: of tyAnything:
@ -961,7 +961,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if x == nil: if x == nil:
if c.callee.kind == tyGenericBody and if c.callee.kind == tyGenericBody and
f.kind == tyGenericParam and not c.typedescMatched: f.kind == tyGenericParam and not c.typedescMatched:
# XXX: The fact that generic types currently use tyGenericParam for # XXX: The fact that generic types currently use tyGenericParam for
# their parameters is really a misnomer. tyGenericParam means "match # their parameters is really a misnomer. tyGenericParam means "match
# any value" and what we need is "match any type", which can be encoded # any value" and what we need is "match any type", which can be encoded
# by a tyTypeDesc params. Unfortunately, this requires more substantial # by a tyTypeDesc params. Unfortunately, this requires more substantial
@ -1004,7 +1004,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = isGeneric result = isGeneric
else: else:
result = typeRel(c, x, a) # check if it fits result = typeRel(c, x, a) # check if it fits
of tyStatic: of tyStatic:
let prev = PType(idTableGet(c.bindings, f)) let prev = PType(idTableGet(c.bindings, f))
if prev == nil: if prev == nil:
@ -1034,12 +1034,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# when `f` is an unresolved typedesc, `a` could be any # when `f` is an unresolved typedesc, `a` could be any
# type, so we should not perform this check earlier # type, so we should not perform this check earlier
if a.kind != tyTypeDesc: return isNone if a.kind != tyTypeDesc: return isNone
if f.base.kind == tyNone: if f.base.kind == tyNone:
result = isGeneric result = isGeneric
else: else:
result = typeRel(c, f.base, a.base) result = typeRel(c, f.base, a.base)
if result != isNone: if result != isNone:
put(c.bindings, f, a) put(c.bindings, f, a)
else: else:
@ -1049,9 +1049,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = typeRel(c, prev.base, a.base) result = typeRel(c, prev.base, a.base)
else: else:
result = isNone result = isNone
of tyIter: of tyIter:
if a.kind == tyIter or if a.kind == tyIter or
(a.kind == tyProc and tfIterator in a.flags): (a.kind == tyProc and tfIterator in a.flags):
result = typeRel(c, f.base, a.base) result = typeRel(c, f.base, a.base)
else: else:
@ -1059,7 +1059,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyStmt: of tyStmt:
result = isGeneric result = isGeneric
of tyProxy: of tyProxy:
result = isEqual result = isEqual
@ -1078,11 +1078,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else: else:
localError(f.n.info, errTypeExpected) localError(f.n.info, errTypeExpected)
result = isNone result = isNone
else: else:
internalAssert false internalAssert false
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation = proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
var m: TCandidate var m: TCandidate
initCandidate(c, m, f) initCandidate(c, m, f)
result = typeRel(m, f, a) result = typeRel(m, f, a)
@ -1095,9 +1095,9 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
if result == nil: if result == nil:
internalError(arg.info, "getInstantiatedType") internalError(arg.info, "getInstantiatedType")
result = errorType(c) result = errorType(c)
proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
c: PContext): PNode = c: PContext): PNode =
result = newNodeI(kind, arg.info) result = newNodeI(kind, arg.info)
if containsGenericType(f): if containsGenericType(f):
if not m.hasFauxMatch: if not m.hasFauxMatch:
@ -1110,10 +1110,10 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
addSon(result, ast.emptyNode) addSon(result, ast.emptyNode)
addSon(result, arg) addSon(result, arg)
proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
arg: PNode): PNode = arg: PNode): PNode =
result = nil result = nil
for i in countup(0, len(c.converters) - 1): for i in countup(0, len(c.converters) - 1):
var src = c.converters[i].typ.sons[1] var src = c.converters[i].typ.sons[1]
var dest = c.converters[i].typ.sons[0] var dest = c.converters[i].typ.sons[0]
# for generic type converters we need to check 'src <- a' before # for generic type converters we need to check 'src <- a' before
@ -1121,12 +1121,12 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
# see tests/tgenericconverter: # see tests/tgenericconverter:
let srca = typeRel(m, src, a) let srca = typeRel(m, src, a)
if srca notin {isEqual, isGeneric}: continue if srca notin {isEqual, isGeneric}: continue
let destIsGeneric = containsGenericType(dest) let destIsGeneric = containsGenericType(dest)
if destIsGeneric: if destIsGeneric:
dest = generateTypeInstance(c, m.bindings, arg, dest) dest = generateTypeInstance(c, m.bindings, arg, dest)
let fdest = typeRel(m, f, dest) let fdest = typeRel(m, f, dest)
if fdest in {isEqual, isGeneric}: if fdest in {isEqual, isGeneric}:
markUsed(arg.info, c.converters[i]) markUsed(arg.info, c.converters[i])
var s = newSymNode(c.converters[i]) var s = newSymNode(c.converters[i])
s.typ = c.converters[i].typ s.typ = c.converters[i].typ
@ -1138,8 +1138,8 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
m.genericConverter = srca == isGeneric or destIsGeneric m.genericConverter = srca == isGeneric or destIsGeneric
return result return result
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
arg: PNode): PNode = arg: PNode): PNode =
# arg.typ can be nil in 'suggest': # arg.typ can be nil in 'suggest':
if isNil(arg.typ): return nil if isNil(arg.typ): return nil
@ -1181,12 +1181,12 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
arg = argSemantized arg = argSemantized
argType = argType argType = argType
c = m.c c = m.c
if tfHasStatic in fMaybeStatic.flags: if tfHasStatic in fMaybeStatic.flags:
# XXX: When implicit statics are the default # XXX: When implicit statics are the default
# this will be done earlier - we just have to # this will be done earlier - we just have to
# make sure that static types enter here # make sure that static types enter here
# XXX: weaken tyGenericParam and call it tyGenericPlaceholder # XXX: weaken tyGenericParam and call it tyGenericPlaceholder
# and finally start using tyTypedesc for generic types properly. # and finally start using tyTypedesc for generic types properly.
if argType.kind == tyGenericParam and tfWildcard in argType.flags: if argType.kind == tyGenericParam and tfWildcard in argType.flags:
@ -1205,11 +1205,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
arg.typ.sons = @[evaluated.typ] arg.typ.sons = @[evaluated.typ]
arg.typ.n = evaluated arg.typ.n = evaluated
argType = arg.typ argType = arg.typ
var var
a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor}) a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor})
else: argType else: argType
r = typeRel(m, f, a) r = typeRel(m, f, a)
if r != isNone and m.calleeSym != nil and if r != isNone and m.calleeSym != nil and
@ -1244,19 +1244,18 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
case r case r
of isConvertible: of isConvertible:
inc(m.convMatches) inc(m.convMatches)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) result = implicitConv(nkHiddenStdConv, f, arg, m, c)
of isIntConv: of isIntConv:
# I'm too lazy to introduce another ``*matches`` field, so we conflate # I'm too lazy to introduce another ``*matches`` field, so we conflate
# ``isIntConv`` and ``isIntLit`` here: # ``isIntConv`` and ``isIntLit`` here:
inc(m.intConvMatches) inc(m.intConvMatches)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) result = implicitConv(nkHiddenStdConv, f, arg, m, c)
of isSubtype: of isSubtype:
inc(m.subtypeMatches) inc(m.subtypeMatches)
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c) result = implicitConv(nkHiddenSubConv, f, arg, m, c)
of isSubrange: of isSubrange:
inc(m.subtypeMatches) inc(m.subtypeMatches)
#result = copyTree(arg) result = implicitConv(nkHiddenStdConv, f, arg, m, c)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isInferred, isInferredConvertible: of isInferred, isInferredConvertible:
inc(m.genericMatches) inc(m.genericMatches)
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds: if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
@ -1269,42 +1268,32 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
result = implicitConv(nkHiddenStdConv, f, result, m, c) result = implicitConv(nkHiddenStdConv, f, result, m, c)
of isGeneric: of isGeneric:
inc(m.genericMatches) inc(m.genericMatches)
when true: if arg.typ == nil:
if arg.typ == nil: result = arg
result = arg elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple: result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) elif arg.typ.isEmptyContainer:
elif arg.typ.isEmptyContainer: result = arg.copyTree
result = arg.copyTree
result.typ = getInstantiatedType(c, arg, m, f)
else:
result = arg
else:
# XXX Why is this ever necessary? arg's type should not be retrofitted
# to match formal's type in this way!
result = copyTree(arg)
result.typ = getInstantiatedType(c, arg, m, f) result.typ = getInstantiatedType(c, arg, m, f)
# BUG: f may not be the right key! else:
if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}: result = arg
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
# BUGFIX: use ``result.typ`` and not `f` here
of isFromIntLit: of isFromIntLit:
# too lazy to introduce another ``*matches`` field, so we conflate # too lazy to introduce another ``*matches`` field, so we conflate
# ``isIntConv`` and ``isIntLit`` here: # ``isIntConv`` and ``isIntLit`` here:
inc(m.intConvMatches, 256) inc(m.intConvMatches, 256)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) result = implicitConv(nkHiddenStdConv, f, arg, m, c)
of isEqual: of isEqual:
inc(m.exactMatches) inc(m.exactMatches)
result = copyTree(arg) result = arg
if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}: if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) result = implicitConv(nkHiddenStdConv, f, arg, m, c)
of isNone: 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 infere T in ``ref T``:
if a.kind in {tyProxy, tyUnknown}: if a.kind in {tyProxy, tyUnknown}:
inc(m.genericMatches) inc(m.genericMatches)
m.fauxMatch = a.kind m.fauxMatch = a.kind
return copyTree(arg) return arg
result = userConvMatch(c, m, f, a, arg) result = userConvMatch(c, m, f, a, arg)
# check for a base type match, which supports varargs[T] without [] # check for a base type match, which supports varargs[T] without []
# constructor in a call: # constructor in a call:
if result == nil and f.kind == tyVarargs: if result == nil and f.kind == tyVarargs:
@ -1325,7 +1314,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
arg, argOrig: PNode): PNode = arg, argOrig: PNode): PNode =
if arg == nil or arg.kind notin nkSymChoices: if arg == nil or arg.kind notin nkSymChoices:
result = paramTypesMatchAux(m, f, a, arg, argOrig) result = paramTypesMatchAux(m, f, a, arg, argOrig)
else: else:
# CAUTION: The order depends on the used hashing scheme. Thus it is # CAUTION: The order depends on the used hashing scheme. Thus it is
# incorrect to simply use the first fitting match. However, to implement # incorrect to simply use the first fitting match. However, to implement
# this correctly is inefficient. We have to copy `m` here to be able to # this correctly is inefficient. We have to copy `m` here to be able to
@ -1339,28 +1328,28 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
y.calleeSym = m.calleeSym y.calleeSym = m.calleeSym
z.calleeSym = m.calleeSym z.calleeSym = m.calleeSym
var best = -1 var best = -1
for i in countup(0, sonsLen(arg) - 1): for i in countup(0, sonsLen(arg) - 1):
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators: if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
copyCandidate(z, m) copyCandidate(z, m)
var r = typeRel(z, f, arg.sons[i].typ) var r = typeRel(z, f, arg.sons[i].typ)
if r != isNone: if r != isNone:
case x.state case x.state
of csEmpty, csNoMatch: of csEmpty, csNoMatch:
x = z x = z
best = i best = i
x.state = csMatch x.state = csMatch
of csMatch: of csMatch:
var cmp = cmpCandidates(x, z) var cmp = cmpCandidates(x, z)
if cmp < 0: if cmp < 0:
best = i best = i
x = z x = z
elif cmp == 0: elif cmp == 0:
y = z # z is as good as x y = z # z is as good as x
if x.state == csEmpty: if x.state == csEmpty:
result = nil result = nil
elif y.state == csMatch and cmpCandidates(x, y) == 0: elif y.state == csMatch and cmpCandidates(x, y) == 0:
if x.state != csMatch: if x.state != csMatch:
internalError(arg.info, "x.state is not csMatch") internalError(arg.info, "x.state is not csMatch")
# ambiguous: more than one symbol fits! # ambiguous: more than one symbol fits!
# See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
# anyway: # anyway:
@ -1373,7 +1362,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
argOrig) argOrig)
proc setSon(father: PNode, at: int, son: PNode) = proc setSon(father: PNode, at: int, son: PNode) =
if sonsLen(father) <= at: setLen(father.sons, at + 1) if sonsLen(father) <= at: setLen(father.sons, at + 1)
father.sons[at] = son father.sons[at] = son
@ -1417,7 +1406,7 @@ proc incrIndexType(t: PType) =
inc t.sons[0].n.sons[1].intVal inc t.sons[0].n.sons[1].intVal
proc matchesAux(c: PContext, n, nOrig: PNode, proc matchesAux(c: PContext, n, nOrig: PNode,
m: var TCandidate, marker: var IntSet) = m: var TCandidate, marker: var IntSet) =
template checkConstraint(n: expr) {.immediate, dirty.} = template checkConstraint(n: expr) {.immediate, dirty.} =
if not formal.constraint.isNil: if not formal.constraint.isNil:
if matchNodeKinds(formal.constraint, n): if matchNodeKinds(formal.constraint, n):
@ -1447,20 +1436,20 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
# named param # named param
# check if m.callee has such a param: # check if m.callee has such a param:
prepareNamedParam(n.sons[a]) prepareNamedParam(n.sons[a])
if n.sons[a].sons[0].kind != nkIdent: if n.sons[a].sons[0].kind != nkIdent:
localError(n.sons[a].info, errNamedParamHasToBeIdent) localError(n.sons[a].info, errNamedParamHasToBeIdent)
m.state = csNoMatch m.state = csNoMatch
return return
formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1) formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
if formal == nil: if formal == nil:
# no error message! # no error message!
m.state = csNoMatch m.state = csNoMatch
return return
if containsOrIncl(marker, formal.position): if containsOrIncl(marker, formal.position):
# already in namedParams: # already in namedParams:
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
m.state = csNoMatch m.state = csNoMatch
return return
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1]) n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
n.sons[a].typ = n.sons[a].sons[1].typ n.sons[a].typ = n.sons[a].sons[1].typ
@ -1470,7 +1459,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
m.state = csNoMatch m.state = csNoMatch
return return
checkConstraint(n.sons[a].sons[1]) checkConstraint(n.sons[a].sons[1])
if m.baseTypeMatch: if m.baseTypeMatch:
#assert(container == nil) #assert(container == nil)
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
addSon(container, arg) addSon(container, arg)
@ -1507,7 +1496,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
m.state = csNoMatch m.state = csNoMatch
return return
else: else:
if m.callee.n.sons[f].kind != nkSym: if m.callee.n.sons[f].kind != nkSym:
internalError(n.sons[a].info, "matches") internalError(n.sons[a].info, "matches")
return return
formal = m.callee.n.sons[f].sym formal = m.callee.n.sons[f].sym
@ -1515,7 +1504,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
# already in namedParams: # already in namedParams:
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
m.state = csNoMatch m.state = csNoMatch
return return
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
@ -1528,7 +1517,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
if container.isNil: if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
addSon(container, arg) addSon(container, arg)
setSon(m.call, formal.position + 1, setSon(m.call, formal.position + 1,
implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
#if f != formalLen - 1: container = nil #if f != formalLen - 1: container = nil
@ -1603,7 +1592,7 @@ when not declared(tests):
tests: tests:
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo()) var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
proc `|` (t1, t2: PType): PType = proc `|` (t1, t2: PType): PType =
result = newType(tyOr, dummyOwner) result = newType(tyOr, dummyOwner)
result.rawAddSon(t1) result.rawAddSon(t1)
@ -1624,12 +1613,12 @@ tests:
proc array(x: int, t: PType): PType = proc array(x: int, t: PType): PType =
result = newType(tyArray, dummyOwner) result = newType(tyArray, dummyOwner)
var n = newNodeI(nkRange, UnknownLineInfo()) var n = newNodeI(nkRange, UnknownLineInfo())
addSon(n, newIntNode(nkIntLit, 0)) addSon(n, newIntNode(nkIntLit, 0))
addSon(n, newIntNode(nkIntLit, x)) addSon(n, newIntNode(nkIntLit, x))
let range = newType(tyRange, dummyOwner) let range = newType(tyRange, dummyOwner)
result.rawAddSon(range) result.rawAddSon(range)
result.rawAddSon(t) result.rawAddSon(t)
@ -1664,7 +1653,7 @@ tests:
template no(x, y) = template no(x, y) =
test astToStr(x) & " is not " & astToStr(y): test astToStr(x) & " is not " & astToStr(y):
check typeRel(c, y, x) == isNone check typeRel(c, y, x) == isNone
yes seq(any), array(10, int) | seq(any) yes seq(any), array(10, int) | seq(any)
# Sure, seq[any] is directly included # Sure, seq[any] is directly included
@ -1672,16 +1661,16 @@ tests:
yes seq(int), seq(number) yes seq(int), seq(number)
# Sure, the int sequence is certainly # Sure, the int sequence is certainly
# part of the number sequences (and all sequences) # part of the number sequences (and all sequences)
no seq(any), seq(float) no seq(any), seq(float)
# Nope, seq[any] includes types that are not seq[float] (e.g. seq[int]) # Nope, seq[any] includes types that are not seq[float] (e.g. seq[int])
yes seq(int|string), seq(any) yes seq(int|string), seq(any)
# Sure # Sure
yes seq(int&string), seq(any) yes seq(int&string), seq(any)
# Again # Again
yes seq(int&string), seq(int) yes seq(int&string), seq(int)
# A bit more complicated # A bit more complicated
# seq[int&string] is not a real type, but it's analogous to # seq[int&string] is not a real type, but it's analogous to
@ -1690,23 +1679,23 @@ tests:
no seq(int|string), seq(int|float) no seq(int|string), seq(int|float)
# Nope, seq[string] is not included in not included in # Nope, seq[string] is not included in not included in
# the seq[int|float] set # the seq[int|float] set
no seq(!(int|string)), seq(string) no seq(!(int|string)), seq(string)
# A sequence that is neither seq[int] or seq[string] # A sequence that is neither seq[int] or seq[string]
# is obviously not seq[string] # is obviously not seq[string]
no seq(!int), seq(number) no seq(!int), seq(number)
# Now your head should start to hurt a bit # Now your head should start to hurt a bit
# A sequence that is not seq[int] is not necessarily a number sequence # A sequence that is not seq[int] is not necessarily a number sequence
# it could well be seq[string] for example # it could well be seq[string] for example
yes seq(!(int|string)), seq(!string) yes seq(!(int|string)), seq(!string)
# all sequnece types besides seq[int] and seq[string] # all sequnece types besides seq[int] and seq[string]
# are subset of all sequence types that are not seq[string] # are subset of all sequence types that are not seq[string]
no seq(!(int|string)), seq(!(string|TFoo)) no seq(!(int|string)), seq(!(string|TFoo))
# Nope, seq[TFoo] is included in the first set, but not in the second # Nope, seq[TFoo] is included in the first set, but not in the second
no seq(!string), seq(!number) no seq(!string), seq(!number)
# Nope, seq[int] in included in the first set, but not in the second # Nope, seq[int] in included in the first set, but not in the second
@ -1714,7 +1703,7 @@ tests:
yes seq(!int), seq(any) yes seq(!int), seq(any)
no seq(any), seq(!any) no seq(any), seq(!any)
no seq(!int), seq(!any) no seq(!int), seq(!any)
yes int, ordinal yes int, ordinal
no string, ordinal no string, ordinal

View file

@ -0,0 +1,24 @@
# bug #2229
type Type1 = object
id: int
type Type2 = object
id: int
proc init(self: var Type1, a: int, b: ref Type2) =
echo "1"
proc init(self: var Type2, a: int) =
echo """
Works when this proc commented out
Otherwise error:
test.nim(14, 4) Error: ambiguous call; both test.init(self: var Type1, a: int, b: ref Type2) and test.init(self: var Type1, a: int, b: ref Type2) match for: (Type1, int literal(1), ref Type2)
"""
var a: Type1
init(a, 1, (
var b = new(Type2);
b
))