fixes #2229
This commit is contained in:
parent
3adcad1b5d
commit
cac259cdfb
3 changed files with 200 additions and 180 deletions
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
24
tests/overload/tsymtabchange_during_or.nim
Normal file
24
tests/overload/tsymtabchange_during_or.nim
Normal 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
|
||||||
|
))
|
||||||
Loading…
Add table
Add a link
Reference in a new issue