80
80
# or when the explain pragma is used. may be
81
81
# triggered with an idetools command in the
82
82
# future.
83
- inheritancePenalty: int # to prefer closest father object type
83
+ # to prefer closest father object type
84
+ inheritancePenalty: int
84
85
firstMismatch* : MismatchInfo # mismatch info for better error messages
85
86
diagnosticsEnabled* : bool
86
87
95
96
96
97
const
97
98
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
99
+ maxInheritancePenalty = high (int ) div 2
98
100
99
101
proc markUsed * (c: PContext ; info: TLineInfo , s: PSym ; checkStyle = true )
100
102
proc markOwnerModuleAsUsed * (c: PContext ; s: PSym )
@@ -107,7 +109,7 @@ proc initCandidateAux(ctx: PContext,
107
109
convMatches: 0 , intConvMatches: 0 , genericMatches: 0 ,
108
110
state: csEmpty, firstMismatch: MismatchInfo (),
109
111
callee: callee, call: nil , baseTypeMatch: false ,
110
- genericConverter: false , inheritancePenalty: 0
112
+ genericConverter: false , inheritancePenalty: - 1
111
113
)
112
114
113
115
proc initCandidate * (ctx: PContext , callee: PType ): TCandidate =
@@ -287,6 +289,15 @@ proc writeMatches*(c: TCandidate) =
287
289
echo " conv matches: " , c.convMatches
288
290
echo " inheritance: " , c.inheritancePenalty
289
291
292
+ proc cmpInheritancePenalty (a, b: int ): int =
293
+ var eb = b
294
+ var ea = a
295
+ if b < 0 :
296
+ eb = maxInheritancePenalty # defacto max penalty
297
+ if a < 0 :
298
+ ea = maxInheritancePenalty
299
+ eb - ea
300
+
290
301
proc cmpCandidates * (a, b: TCandidate , isFormal= true ): int =
291
302
result = a.exactMatches - b.exactMatches
292
303
if result != 0 : return
@@ -298,8 +309,7 @@ proc cmpCandidates*(a, b: TCandidate, isFormal=true): int =
298
309
if result != 0 : return
299
310
result = a.convMatches - b.convMatches
300
311
if result != 0 : return
301
- # the other way round because of other semantics:
302
- result = b.inheritancePenalty - a.inheritancePenalty
312
+ result = cmpInheritancePenalty (a.inheritancePenalty, b.inheritancePenalty)
303
313
if result != 0 : return
304
314
if isFormal:
305
315
# check for generic subclass relation
@@ -588,10 +598,9 @@ proc recordRel(c: var TCandidate, f, a: PType, flags: TTypeRelFlags): TTypeRelat
588
598
let firstField = if f.kind == tyTuple: 0
589
599
else : 1
590
600
for _, ff, aa in tupleTypePairs (f, a):
591
- let oldInheritancePenalty = c.inheritancePenalty
592
601
var m = typeRel (c, ff, aa, flags)
593
602
if m < isSubtype: return isNone
594
- if m == isSubtype and c.inheritancePenalty > oldInheritancePenalty :
603
+ if m == isSubtype and aa.kind != tyNil and c.inheritancePenalty > - 1 :
595
604
# we can't process individual element type conversions from a
596
605
# type conversion for the whole tuple
597
606
# subtype relations need type conversions when inheritance is used
@@ -1388,12 +1397,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
1388
1397
reduceToBase (a)
1389
1398
if effectiveArgType.kind == tyObject:
1390
1399
if sameObjectTypes (f, effectiveArgType):
1400
+ c.inheritancePenalty = 0
1391
1401
result = isEqual
1392
1402
# elif tfHasMeta in f.flags: result = recordRel(c, f, a)
1393
1403
elif trIsOutParam notin flags:
1394
- var depth = isObjectSubtype (c, effectiveArgType, f, nil )
1395
- if depth > 0 :
1396
- inc (c.inheritancePenalty, depth)
1404
+ c.inheritancePenalty = isObjectSubtype (c, effectiveArgType, f, nil )
1405
+ if c.inheritancePenalty > 0 :
1397
1406
result = isSubtype
1398
1407
of tyDistinct:
1399
1408
a = a.skipTypes ({tyOwned, tyGenericInst, tyRange})
@@ -1562,7 +1571,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
1562
1571
if aAsObject.kind == tyObject and trIsOutParam notin flags:
1563
1572
let baseType = aAsObject.base
1564
1573
if baseType != nil :
1565
- c.inheritancePenalty += 1
1574
+ inc c.inheritancePenalty, 1 + int (c.inheritancePenalty < 0 )
1566
1575
let ret = typeRel (c, f, baseType, flags)
1567
1576
return if ret in {isEqual,isGeneric}: isSubtype else : ret
1568
1577
@@ -1659,7 +1668,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
1659
1668
depth = - 1
1660
1669
1661
1670
if depth >= 0 :
1662
- c.inheritancePenalty += depth
1671
+ inc c.inheritancePenalty, depth + int (c.inheritancePenalty < 0 )
1663
1672
# bug #4863: We still need to bind generic alias crap, so
1664
1673
# we cannot return immediately:
1665
1674
result = if depth == 0 : isGeneric else : isSubtype
@@ -1677,19 +1686,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
1677
1686
considerPreviousT:
1678
1687
result = isNone
1679
1688
let oldInheritancePenalty = c.inheritancePenalty
1680
- var maxInheritance = 0
1689
+ var minInheritance = maxInheritancePenalty
1681
1690
for branch in f.kids:
1682
- c.inheritancePenalty = 0
1691
+ c.inheritancePenalty = - 1
1683
1692
let x = typeRel (c, branch, aOrig, flags)
1684
- maxInheritance = max (maxInheritance, c.inheritancePenalty)
1685
- # 'or' implies maximum matching result:
1686
- if x > result : result = x
1693
+ if x >= result :
1694
+ if c.inheritancePenalty > - 1 :
1695
+ minInheritance = min (minInheritance, c.inheritancePenalty)
1696
+ result = x
1687
1697
if result >= isIntConv:
1698
+ if minInheritance < maxInheritancePenalty:
1699
+ c.inheritancePenalty = oldInheritancePenalty + minInheritance
1688
1700
if result > isGeneric: result = isGeneric
1689
1701
bindingRet result
1690
1702
else :
1691
1703
result = isNone
1692
- c.inheritancePenalty = oldInheritancePenalty + maxInheritance
1693
1704
of tyNot:
1694
1705
considerPreviousT:
1695
1706
if typeRel (c, f.elementType, aOrig, flags) != isNone:
@@ -1799,18 +1810,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
1799
1810
else :
1800
1811
# check if 'T' has a constraint as in 'proc p[T: Constraint](x: T)'
1801
1812
if f.len > 0 and f[0 ].kind != tyNone:
1802
- let oldInheritancePenalty = c.inheritancePenalty
1803
1813
result = typeRel (c, f[0 ], a, flags + {trDontBind, trBindGenericParam})
1804
1814
if doBindGP and result notin {isNone, isGeneric}:
1805
1815
let concrete = concreteType (c, a, f)
1806
1816
if concrete == nil : return isNone
1807
1817
put (c, f, concrete)
1808
- # bug #6526
1809
1818
if result in {isEqual, isSubtype}:
1810
- # 'T: Class' is a *better* match than just 'T'
1811
- # but 'T: Subclass' is even better:
1812
- c.inheritancePenalty = oldInheritancePenalty - c.inheritancePenalty -
1813
- 100 * ord (result == isEqual)
1814
1819
result = isGeneric
1815
1820
elif a.kind == tyTypeDesc:
1816
1821
# somewhat special typing rule, the following is illegal:
@@ -1843,7 +1848,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
1843
1848
elif x.kind == tyGenericParam:
1844
1849
result = isGeneric
1845
1850
else :
1851
+ # This is the bound type - can't benifit from these tallies
1852
+ let
1853
+ inheritancePenaltyOld = c.inheritancePenalty
1846
1854
result = typeRel (c, x, a, flags) # check if it fits
1855
+ c.inheritancePenalty = inheritancePenaltyOld
1847
1856
if result > isGeneric: result = isGeneric
1848
1857
of tyStatic:
1849
1858
let prev = idTableGet (c.bindings, f)
@@ -2256,8 +2265,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
2256
2265
inc (m.genericMatches)
2257
2266
if arg.typ == nil :
2258
2267
result = arg
2259
- elif skipTypes (arg.typ, abstractVar- {tyTypeDesc}).kind == tyTuple or
2260
- m.inheritancePenalty > oldInheritancePenalty:
2268
+ elif skipTypes (arg.typ, abstractVar- {tyTypeDesc}).kind == tyTuple or cmpInheritancePenalty (oldInheritancePenalty, m.inheritancePenalty) > 0 :
2261
2269
result = implicitConv (nkHiddenSubConv, f, arg, m, c)
2262
2270
elif arg.typ.isEmptyContainer:
2263
2271
result = arg.copyTree
0 commit comments