fix infinite recursion in typeRel (#15241)
* fix generic constraints Co-authored-by: James Osborn <osborn@Jamess-MacBook-Pro.local>
This commit is contained in:
parent
c57023f324
commit
e56d50d747
2 changed files with 104 additions and 56 deletions
|
|
@ -82,6 +82,7 @@ type
|
||||||
TTypeRelFlag* = enum
|
TTypeRelFlag* = enum
|
||||||
trDontBind
|
trDontBind
|
||||||
trNoCovariance
|
trNoCovariance
|
||||||
|
trBindGenericParam # bind tyGenericParam even with trDontBind
|
||||||
|
|
||||||
TTypeRelFlags* = set[TTypeRelFlag]
|
TTypeRelFlags* = set[TTypeRelFlag]
|
||||||
|
|
||||||
|
|
@ -1034,7 +1035,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
if aOrig.kind == tyInferred:
|
if aOrig.kind == tyInferred:
|
||||||
let prev = aOrig.previouslyInferred
|
let prev = aOrig.previouslyInferred
|
||||||
if prev != nil:
|
if prev != nil:
|
||||||
return typeRel(c, f, prev)
|
return typeRel(c, f, prev, flags)
|
||||||
else:
|
else:
|
||||||
var candidate = f
|
var candidate = f
|
||||||
|
|
||||||
|
|
@ -1055,7 +1056,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
result = typeRel(c, aOrig.base, candidate)
|
result = typeRel(c, aOrig.base, candidate, flags)
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
c.inferredTypes.add aOrig
|
c.inferredTypes.add aOrig
|
||||||
aOrig.add candidate
|
aOrig.add candidate
|
||||||
|
|
@ -1072,16 +1073,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
# situation when nkDotExpr are rotated to nkDotCalls
|
# situation when nkDotExpr are rotated to nkDotCalls
|
||||||
|
|
||||||
if aOrig.kind in {tyAlias, tySink}:
|
if aOrig.kind in {tyAlias, tySink}:
|
||||||
return typeRel(c, f, lastSon(aOrig))
|
return typeRel(c, f, lastSon(aOrig), flags)
|
||||||
|
|
||||||
if a.kind == tyGenericInst and
|
if a.kind == tyGenericInst and
|
||||||
skipTypes(f, {tyVar, tyLent, tySink}).kind notin {
|
skipTypes(f, {tyVar, tyLent, tySink}).kind notin {
|
||||||
tyGenericBody, tyGenericInvocation,
|
tyGenericBody, tyGenericInvocation,
|
||||||
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
||||||
return typeRel(c, f, lastSon(a))
|
return typeRel(c, f, lastSon(a), flags)
|
||||||
|
|
||||||
if a.isResolvedUserTypeClass:
|
if a.isResolvedUserTypeClass:
|
||||||
return typeRel(c, f, a.lastSon)
|
return typeRel(c, f, a.lastSon, flags)
|
||||||
|
|
||||||
template bindingRet(res) =
|
template bindingRet(res) =
|
||||||
if doBind:
|
if doBind:
|
||||||
|
|
@ -1092,7 +1093,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
template considerPreviousT(body: untyped) =
|
template considerPreviousT(body: untyped) =
|
||||||
var prev = PType(idTableGet(c.bindings, f))
|
var prev = PType(idTableGet(c.bindings, f))
|
||||||
if prev == nil: body
|
if prev == nil: body
|
||||||
else: return typeRel(c, prev, a)
|
else: return typeRel(c, prev, a, flags)
|
||||||
|
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyOr:
|
of tyOr:
|
||||||
|
|
@ -1126,7 +1127,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
# 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, flags)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# negative type classes are essentially infinite,
|
# negative type classes are essentially infinite,
|
||||||
|
|
@ -1158,7 +1159,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
of tyRange:
|
of tyRange:
|
||||||
if a.kind == f.kind:
|
if a.kind == f.kind:
|
||||||
if f.base.kind == tyNone: return isGeneric
|
if f.base.kind == tyNone: return isGeneric
|
||||||
result = typeRel(c, base(f), base(a))
|
result = typeRel(c, base(f), base(a), flags)
|
||||||
# bugfix: accept integer conversions here
|
# bugfix: accept integer conversions here
|
||||||
#if result < isGeneric: result = isNone
|
#if result < isGeneric: result = isNone
|
||||||
if result notin {isNone, isGeneric}:
|
if result notin {isNone, isGeneric}:
|
||||||
|
|
@ -1189,7 +1190,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
of tyFloat64: result = handleFloatRange(f, a)
|
of tyFloat64: result = handleFloatRange(f, a)
|
||||||
of tyFloat128: result = handleFloatRange(f, a)
|
of tyFloat128: result = handleFloatRange(f, a)
|
||||||
of tyVar, tyLent:
|
of tyVar, tyLent:
|
||||||
if aOrig.kind == f.kind: result = typeRel(c, f.base, aOrig.base)
|
if aOrig.kind == f.kind: result = typeRel(c, f.base, aOrig.base, flags)
|
||||||
else: result = typeRel(c, f.base, aOrig, flags + {trNoCovariance})
|
else: result = typeRel(c, f.base, aOrig, flags + {trNoCovariance})
|
||||||
subtypeCheck()
|
subtypeCheck()
|
||||||
of tyArray:
|
of tyArray:
|
||||||
|
|
@ -1211,7 +1212,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
if f[0].kind != tyGenericParam and aa.kind == tyEmpty:
|
if f[0].kind != tyGenericParam and aa.kind == tyEmpty:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, ff, aa)
|
result = typeRel(c, ff, aa, flags)
|
||||||
|
|
||||||
if result < isGeneric:
|
if result < isGeneric:
|
||||||
if nimEnableCovariance and
|
if nimEnableCovariance and
|
||||||
|
|
@ -1232,7 +1233,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
else: discard
|
else: discard
|
||||||
of tyUncheckedArray:
|
of tyUncheckedArray:
|
||||||
if a.kind == tyUncheckedArray:
|
if a.kind == tyUncheckedArray:
|
||||||
result = typeRel(c, base(f), base(a))
|
result = typeRel(c, base(f), base(a), flags)
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
else: discard
|
else: discard
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
|
|
@ -1240,13 +1241,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
# handle varargs[stmt] which is the same as varargs[typed]:
|
# handle varargs[stmt] which is the same as varargs[typed]:
|
||||||
if f.kind == tyVarargs:
|
if f.kind == tyVarargs:
|
||||||
if tfVarargs in a.flags:
|
if tfVarargs in a.flags:
|
||||||
return typeRel(c, f.base, a.lastSon)
|
return typeRel(c, f.base, a.lastSon, flags)
|
||||||
if f[0].kind == tyTyped: return
|
if f[0].kind == tyTyped: return
|
||||||
|
|
||||||
template matchArrayOrSeq(aBase: PType) =
|
template matchArrayOrSeq(aBase: PType) =
|
||||||
let ff = f.base
|
let ff = f.base
|
||||||
let aa = aBase
|
let aa = aBase
|
||||||
let baseRel = typeRel(c, ff, aa)
|
let baseRel = typeRel(c, ff, aa, flags)
|
||||||
if baseRel >= isGeneric:
|
if baseRel >= isGeneric:
|
||||||
result = isConvertible
|
result = isConvertible
|
||||||
elif nimEnableCovariance and
|
elif nimEnableCovariance and
|
||||||
|
|
@ -1257,7 +1258,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
|
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = typeRel(c, base(f), base(a))
|
result = typeRel(c, base(f), base(a), flags)
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
of tyArray:
|
of tyArray:
|
||||||
if (f[0].kind != tyGenericParam) and (a[1].kind == tyEmpty):
|
if (f[0].kind != tyGenericParam) and (a[1].kind == tyEmpty):
|
||||||
|
|
@ -1272,7 +1273,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
if f[0].kind == tyChar:
|
if f[0].kind == tyChar:
|
||||||
result = isConvertible
|
result = isConvertible
|
||||||
elif f[0].kind == tyGenericParam and a.len > 0 and
|
elif f[0].kind == tyGenericParam and a.len > 0 and
|
||||||
typeRel(c, base(f), base(a)) >= isGeneric:
|
typeRel(c, base(f), base(a), flags) >= isGeneric:
|
||||||
result = isConvertible
|
result = isConvertible
|
||||||
else: discard
|
else: discard
|
||||||
of tySequence:
|
of tySequence:
|
||||||
|
|
@ -1283,7 +1284,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
else:
|
else:
|
||||||
let ff = f[0]
|
let ff = f[0]
|
||||||
let aa = a[0]
|
let aa = a[0]
|
||||||
result = typeRel(c, ff, aa)
|
result = typeRel(c, ff, aa, flags)
|
||||||
if result < isGeneric:
|
if result < isGeneric:
|
||||||
if nimEnableCovariance and
|
if nimEnableCovariance and
|
||||||
trNoCovariance notin flags and
|
trNoCovariance notin flags and
|
||||||
|
|
@ -1302,7 +1303,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
if f[0].kind == tyNone:
|
if f[0].kind == tyNone:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f[0], x)
|
result = typeRel(c, f[0], x, flags)
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
elif a.kind == tyGenericParam:
|
elif a.kind == tyGenericParam:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
@ -1329,16 +1330,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
if a.kind == tyDistinct:
|
if a.kind == tyDistinct:
|
||||||
if sameDistinctTypes(f, a): result = isEqual
|
if sameDistinctTypes(f, a): result = isEqual
|
||||||
#elif f.base.kind == tyAnything: result = isGeneric # issue 4435
|
#elif f.base.kind == tyAnything: result = isGeneric # issue 4435
|
||||||
elif c.coerceDistincts: result = typeRel(c, f.base, a)
|
elif c.coerceDistincts: result = typeRel(c, f.base, a, flags)
|
||||||
elif a.kind == tyNil and f.base.kind in NilableTypes:
|
elif a.kind == tyNil and f.base.kind in NilableTypes:
|
||||||
result = f.allowsNil # XXX remove this typing rule, it is not in the spec
|
result = f.allowsNil # XXX remove this typing rule, it is not in the spec
|
||||||
elif c.coerceDistincts: result = typeRel(c, f.base, a)
|
elif c.coerceDistincts: result = typeRel(c, f.base, a, flags)
|
||||||
of tySet:
|
of tySet:
|
||||||
if a.kind == tySet:
|
if a.kind == tySet:
|
||||||
if f[0].kind != tyGenericParam and a[0].kind == tyEmpty:
|
if f[0].kind != tyGenericParam and a[0].kind == tyEmpty:
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f[0], a[0])
|
result = typeRel(c, f[0], a[0], flags)
|
||||||
if result <= isConvertible:
|
if result <= isConvertible:
|
||||||
result = isNone # BUGFIX!
|
result = isNone # BUGFIX!
|
||||||
of tyPtr, tyRef:
|
of tyPtr, tyRef:
|
||||||
|
|
@ -1347,7 +1348,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
# ptr[R, T] can be passed to ptr[T], but not the other way round:
|
# ptr[R, T] can be passed to ptr[T], but not the other way round:
|
||||||
if a.len < f.len: return isNone
|
if a.len < f.len: return isNone
|
||||||
for i in 0..<f.len-1:
|
for i in 0..<f.len-1:
|
||||||
if typeRel(c, f[i], a[i]) == isNone: return isNone
|
if typeRel(c, f[i], a[i], flags) == isNone: return isNone
|
||||||
result = typeRel(c, f.lastSon, a.lastSon, flags + {trNoCovariance})
|
result = typeRel(c, f.lastSon, a.lastSon, flags + {trNoCovariance})
|
||||||
subtypeCheck()
|
subtypeCheck()
|
||||||
if result <= isIntConv: result = isNone
|
if result <= isIntConv: result = isNone
|
||||||
|
|
@ -1363,7 +1364,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
of tyOwned:
|
of tyOwned:
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyOwned:
|
of tyOwned:
|
||||||
result = typeRel(c, lastSon(f), lastSon(a))
|
result = typeRel(c, lastSon(f), lastSon(a), flags)
|
||||||
of tyNil: result = f.allowsNil
|
of tyNil: result = f.allowsNil
|
||||||
else: discard
|
else: discard
|
||||||
of tyPointer:
|
of tyPointer:
|
||||||
|
|
@ -1419,7 +1420,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
if a.kind == f.kind: result = isEqual
|
if a.kind == f.kind: result = isEqual
|
||||||
|
|
||||||
of tyAlias, tySink:
|
of tyAlias, tySink:
|
||||||
result = typeRel(c, lastSon(f), a)
|
result = typeRel(c, lastSon(f), a, flags)
|
||||||
|
|
||||||
of tyGenericInst:
|
of tyGenericInst:
|
||||||
var prev = PType(idTableGet(c.bindings, f))
|
var prev = PType(idTableGet(c.bindings, f))
|
||||||
|
|
@ -1452,7 +1453,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
ff.kind notin {tyRef, tyPtr} and res == isSubtype
|
ff.kind notin {tyRef, tyPtr} and res == isSubtype
|
||||||
else:
|
else:
|
||||||
tfContravariant in paramFlags and
|
tfContravariant in paramFlags and
|
||||||
typeRel(c, aa, ff) == isSubtype
|
typeRel(c, aa, ff, flags) == isSubtype
|
||||||
if hasCovariance:
|
if hasCovariance:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -1461,7 +1462,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
else:
|
else:
|
||||||
let fKind = rootf.lastSon.kind
|
let fKind = rootf.lastSon.kind
|
||||||
if fKind in {tyAnd, tyOr}:
|
if fKind in {tyAnd, tyOr}:
|
||||||
result = typeRel(c, lastSon(f), a)
|
result = typeRel(c, lastSon(f), a, flags)
|
||||||
if result != isNone: put(c, f, a)
|
if result != isNone: put(c, f, a)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -1479,13 +1480,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
let baseType = aAsObject.base
|
let baseType = aAsObject.base
|
||||||
if baseType != nil:
|
if baseType != nil:
|
||||||
c.inheritancePenalty += 1
|
c.inheritancePenalty += 1
|
||||||
let ret = typeRel(c, f, baseType)
|
let ret = typeRel(c, f, baseType, flags)
|
||||||
return if ret in {isEqual,isGeneric}: isSubtype else: ret
|
return if ret in {isEqual,isGeneric}: isSubtype else: ret
|
||||||
|
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
assert lastSon(origF) != nil
|
assert lastSon(origF) != nil
|
||||||
result = typeRel(c, lastSon(origF), a)
|
result = typeRel(c, lastSon(origF), a, flags)
|
||||||
if result != isNone and a.kind != tyNil:
|
if result != isNone and a.kind != tyNil:
|
||||||
put(c, f, a)
|
put(c, f, a)
|
||||||
|
|
||||||
|
|
@ -1495,7 +1496,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
bindingRet isGeneric
|
bindingRet isGeneric
|
||||||
let ff = lastSon(f)
|
let ff = lastSon(f)
|
||||||
if ff != nil:
|
if ff != nil:
|
||||||
result = typeRel(c, ff, a)
|
result = typeRel(c, ff, a, flags)
|
||||||
|
|
||||||
of tyGenericInvocation:
|
of tyGenericInvocation:
|
||||||
var x = a.skipGenericAlias
|
var x = a.skipGenericAlias
|
||||||
|
|
@ -1509,12 +1510,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
c.calleeSym.kind in {skProc, skFunc} and c.call != nil and not preventHack:
|
c.calleeSym.kind in {skProc, skFunc} and c.call != nil and not preventHack:
|
||||||
let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
|
let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
|
||||||
#echo "inferred ", typeToString(inst), " for ", f
|
#echo "inferred ", typeToString(inst), " for ", f
|
||||||
return typeRel(c, inst, a)
|
return typeRel(c, inst, a, flags)
|
||||||
|
|
||||||
if x.kind == tyGenericInvocation:
|
if x.kind == tyGenericInvocation:
|
||||||
if f[0] == x[0]:
|
if f[0] == x[0]:
|
||||||
for i in 1..<f.len:
|
for i in 1..<f.len:
|
||||||
let tr = typeRel(c, f[i], x[i])
|
let tr = typeRel(c, f[i], x[i], flags)
|
||||||
if tr <= isSubtype: return
|
if tr <= isSubtype: return
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
elif x.kind == tyGenericInst and f[0] == x[0] and
|
elif x.kind == tyGenericInst and f[0] == x[0] and
|
||||||
|
|
@ -1522,7 +1523,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
for i in 1..<f.len:
|
for i in 1..<f.len:
|
||||||
if x[i].kind == tyGenericParam:
|
if x[i].kind == tyGenericParam:
|
||||||
internalError(c.c.graph.config, "wrong instantiated type!")
|
internalError(c.c.graph.config, "wrong instantiated type!")
|
||||||
elif typeRel(c, f[i], x[i]) <= isSubtype:
|
elif typeRel(c, f[i], x[i], flags) <= isSubtype:
|
||||||
# Workaround for regression #4589
|
# Workaround for regression #4589
|
||||||
if f[i].kind != tyTypeDesc: return
|
if f[i].kind != tyTypeDesc: return
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
@ -1535,7 +1536,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
var depth = -1
|
var depth = -1
|
||||||
if fobj != nil and aobj != nil and askip == fskip:
|
if fobj != nil and aobj != nil and askip == fskip:
|
||||||
depth = isObjectSubtype(c, aobj, fobj, f)
|
depth = isObjectSubtype(c, aobj, fobj, f)
|
||||||
result = typeRel(c, genericBody, x)
|
result = typeRel(c, genericBody, x, flags)
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
# see tests/generics/tgeneric3.nim for an example that triggers this
|
# see tests/generics/tgeneric3.nim for an example that triggers this
|
||||||
# piece of code:
|
# piece of code:
|
||||||
|
|
@ -1578,7 +1579,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
result = isEqual
|
result = isEqual
|
||||||
for branch in f.sons:
|
for branch in f.sons:
|
||||||
let x = typeRel(c, branch, aOrig)
|
let x = typeRel(c, branch, aOrig, flags)
|
||||||
if x < isSubtype: return isNone
|
if x < isSubtype: return isNone
|
||||||
# 'and' implies minimum matching result:
|
# 'and' implies minimum matching result:
|
||||||
if x < result: result = x
|
if x < result: result = x
|
||||||
|
|
@ -1592,7 +1593,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
var maxInheritance = 0
|
var maxInheritance = 0
|
||||||
for branch in f.sons:
|
for branch in f.sons:
|
||||||
c.inheritancePenalty = 0
|
c.inheritancePenalty = 0
|
||||||
let x = typeRel(c, branch, aOrig)
|
let x = typeRel(c, branch, aOrig, flags)
|
||||||
maxInheritance = max(maxInheritance, c.inheritancePenalty)
|
maxInheritance = max(maxInheritance, c.inheritancePenalty)
|
||||||
|
|
||||||
# 'or' implies maximum matching result:
|
# 'or' implies maximum matching result:
|
||||||
|
|
@ -1607,7 +1608,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
of tyNot:
|
of tyNot:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
for branch in f.sons:
|
for branch in f.sons:
|
||||||
if typeRel(c, branch, aOrig) != isNone:
|
if typeRel(c, branch, aOrig, flags) != isNone:
|
||||||
return isNone
|
return isNone
|
||||||
|
|
||||||
bindingRet isGeneric
|
bindingRet isGeneric
|
||||||
|
|
@ -1635,7 +1636,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
|
|
||||||
of tyUserTypeClassInst, tyUserTypeClass:
|
of tyUserTypeClassInst, tyUserTypeClass:
|
||||||
if f.isResolvedUserTypeClass:
|
if f.isResolvedUserTypeClass:
|
||||||
result = typeRel(c, f.lastSon, a)
|
result = typeRel(c, f.lastSon, a, flags)
|
||||||
else:
|
else:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
if aOrig == f: return isEqual
|
if aOrig == f: return isEqual
|
||||||
|
|
@ -1655,16 +1656,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
for i in 1..<rootf.len-1:
|
for i in 1..<rootf.len-1:
|
||||||
let ff = rootf[i]
|
let ff = rootf[i]
|
||||||
let aa = roota[i]
|
let aa = roota[i]
|
||||||
result = typeRel(c, ff, aa)
|
result = typeRel(c, ff, aa, flags)
|
||||||
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
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, rootf.lastSon, a)
|
result = typeRel(c, rootf.lastSon, a, flags)
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
put(c, f, a)
|
put(c, f, a)
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
|
let doBindGP = doBind or trBindGenericParam in flags
|
||||||
var x = PType(idTableGet(c.bindings, f))
|
var x = PType(idTableGet(c.bindings, f))
|
||||||
if x == nil:
|
if x == nil:
|
||||||
if c.callee.kind == tyGenericBody and not c.typedescMatched:
|
if c.callee.kind == tyGenericBody and not c.typedescMatched:
|
||||||
|
|
@ -1686,10 +1688,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
aa = lastSon(aa)
|
aa = lastSon(aa)
|
||||||
if aa.kind == tyGenericParam:
|
if aa.kind == tyGenericParam:
|
||||||
return isGeneric
|
return isGeneric
|
||||||
result = typeRel(c, f.base, aa)
|
result = typeRel(c, f.base, aa, flags)
|
||||||
if result > isGeneric: result = isGeneric
|
if result > isGeneric: result = isGeneric
|
||||||
elif c.isNoCall:
|
elif c.isNoCall:
|
||||||
if doBind:
|
if doBindGP:
|
||||||
let concrete = concreteType(c, a, f)
|
let concrete = concreteType(c, a, f)
|
||||||
if concrete == nil: return isNone
|
if concrete == nil: return isNone
|
||||||
put(c, f, concrete)
|
put(c, f, concrete)
|
||||||
|
|
@ -1700,8 +1702,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
# check if 'T' has a constraint as in 'proc p[T: Constraint](x: T)'
|
# check if 'T' has a constraint as in 'proc p[T: Constraint](x: T)'
|
||||||
if f.len > 0 and f[0].kind != tyNone:
|
if f.len > 0 and f[0].kind != tyNone:
|
||||||
let oldInheritancePenalty = c.inheritancePenalty
|
let oldInheritancePenalty = c.inheritancePenalty
|
||||||
result = typeRel(c, f[0], a, flags + {trDontBind})
|
result = typeRel(c, f[0], a, flags + {trDontBind,trBindGenericParam})
|
||||||
if doBind and result notin {isNone, isGeneric}:
|
if doBindGP and result notin {isNone, isGeneric}:
|
||||||
let concrete = concreteType(c, a, f)
|
let concrete = concreteType(c, a, f)
|
||||||
if concrete == nil: return isNone
|
if concrete == nil: return isNone
|
||||||
put(c, f, concrete)
|
put(c, f, concrete)
|
||||||
|
|
@ -1729,7 +1731,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
concrete = concreteType(c, a, f)
|
concrete = concreteType(c, a, f)
|
||||||
if concrete == nil:
|
if concrete == nil:
|
||||||
return isNone
|
return isNone
|
||||||
if doBind:
|
if doBindGP:
|
||||||
put(c, f, concrete)
|
put(c, f, concrete)
|
||||||
elif result > isGeneric:
|
elif result > isGeneric:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
@ -1738,14 +1740,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
elif x.kind == tyGenericParam:
|
elif x.kind == tyGenericParam:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, x, a) # check if it fits
|
result = typeRel(c, x, a, flags) # check if it fits
|
||||||
if result > isGeneric: result = isGeneric
|
if result > isGeneric: result = isGeneric
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
let prev = PType(idTableGet(c.bindings, f))
|
let prev = PType(idTableGet(c.bindings, f))
|
||||||
if prev == nil:
|
if prev == nil:
|
||||||
if aOrig.kind == tyStatic:
|
if aOrig.kind == tyStatic:
|
||||||
if f.base.kind != tyNone:
|
if f.base.kind != tyNone:
|
||||||
result = typeRel(c, f.base, a)
|
result = typeRel(c, f.base, a, flags)
|
||||||
if result != isNone and f.n != nil:
|
if result != isNone and f.n != nil:
|
||||||
if not exprStructuralEquivalent(f.n, aOrig.n):
|
if not exprStructuralEquivalent(f.n, aOrig.n):
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
@ -1753,7 +1755,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
if result != isNone: put(c, f, aOrig)
|
if result != isNone: put(c, f, aOrig)
|
||||||
elif aOrig.n != nil and aOrig.n.typ != nil:
|
elif aOrig.n != nil and aOrig.n.typ != nil:
|
||||||
result = if f.base.kind != tyNone: typeRel(c, f.lastSon, aOrig.n.typ)
|
result = if f.base.kind != tyNone:
|
||||||
|
typeRel(c, f.lastSon, aOrig.n.typ, flags)
|
||||||
else: isGeneric
|
else: isGeneric
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
var boundType = newTypeWithSons(c.c, tyStatic, @[aOrig.n.typ])
|
var boundType = newTypeWithSons(c.c, tyStatic, @[aOrig.n.typ])
|
||||||
|
|
@ -1763,22 +1766,22 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
result = isNone
|
result = isNone
|
||||||
elif prev.kind == tyStatic:
|
elif prev.kind == tyStatic:
|
||||||
if aOrig.kind == tyStatic:
|
if aOrig.kind == tyStatic:
|
||||||
result = typeRel(c, prev.lastSon, a)
|
result = typeRel(c, prev.lastSon, a, flags)
|
||||||
if result != isNone and prev.n != nil:
|
if result != isNone and prev.n != nil:
|
||||||
if not exprStructuralEquivalent(prev.n, aOrig.n):
|
if not exprStructuralEquivalent(prev.n, aOrig.n):
|
||||||
result = isNone
|
result = isNone
|
||||||
else: result = isNone
|
else: result = isNone
|
||||||
else:
|
else:
|
||||||
# XXX endless recursion?
|
# XXX endless recursion?
|
||||||
#result = typeRel(c, prev, aOrig)
|
#result = typeRel(c, prev, aOrig, flags)
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
of tyInferred:
|
of tyInferred:
|
||||||
let prev = f.previouslyInferred
|
let prev = f.previouslyInferred
|
||||||
if prev != nil:
|
if prev != nil:
|
||||||
result = typeRel(c, prev, a)
|
result = typeRel(c, prev, a, flags)
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f.base, a)
|
result = typeRel(c, f.base, a, flags)
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
c.inferredTypes.add f
|
c.inferredTypes.add f
|
||||||
f.add a
|
f.add a
|
||||||
|
|
@ -1798,15 +1801,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
elif f.base.kind == tyNone:
|
elif f.base.kind == tyNone:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f.base, a.base)
|
result = typeRel(c, f.base, a.base, flags)
|
||||||
|
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
put(c, f, a)
|
put(c, f, a)
|
||||||
else:
|
else:
|
||||||
if tfUnresolved in f.flags:
|
if tfUnresolved in f.flags:
|
||||||
result = typeRel(c, prev.base, a)
|
result = typeRel(c, prev.base, a, flags)
|
||||||
elif a.kind == tyTypeDesc:
|
elif a.kind == tyTypeDesc:
|
||||||
result = typeRel(c, prev.base, a.base)
|
result = typeRel(c, prev.base, a.base, flags)
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
|
|
@ -1824,15 +1827,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
let reevaluated = tryResolvingStaticExpr(c, f.n)
|
let reevaluated = tryResolvingStaticExpr(c, f.n)
|
||||||
case reevaluated.typ.kind
|
case reevaluated.typ.kind
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
result = typeRel(c, a, reevaluated.typ.base)
|
result = typeRel(c, a, reevaluated.typ.base, flags)
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
result = typeRel(c, a, reevaluated.typ.base)
|
result = typeRel(c, a, reevaluated.typ.base, flags)
|
||||||
if result != isNone and reevaluated.typ.n != nil:
|
if result != isNone and reevaluated.typ.n != nil:
|
||||||
if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
|
if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
# bug #14136: other types are just like 'tyStatic' here:
|
# bug #14136: other types are just like 'tyStatic' here:
|
||||||
result = typeRel(c, a, reevaluated.typ)
|
result = typeRel(c, a, reevaluated.typ, flags)
|
||||||
if result != isNone and reevaluated.typ.n != nil:
|
if result != isNone and reevaluated.typ.n != nil:
|
||||||
if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
|
if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
|
||||||
|
|
@ -425,6 +425,7 @@ block:
|
||||||
template t0(x: Bar[int]): int = 1
|
template t0(x: Bar[int]): int = 1
|
||||||
template t0(x: Foo[bool or int]): int = 10
|
template t0(x: Foo[bool or int]): int = 10
|
||||||
template t0(x: Bar[bool or int]): int = 11
|
template t0(x: Bar[bool or int]): int = 11
|
||||||
|
#template t0[T:bool or int](x: Bar[T]): int = 11
|
||||||
template t0[T](x: Foo[T]): int = 20
|
template t0[T](x: Foo[T]): int = 20
|
||||||
template t0[T](x: Bar[T]): int = 21
|
template t0[T](x: Bar[T]): int = 21
|
||||||
proc p0(x: Foo[int]): int = 0
|
proc p0(x: Foo[int]): int = 0
|
||||||
|
|
@ -461,3 +462,47 @@ block:
|
||||||
doAssert(p0(g) == 20)
|
doAssert(p0(g) == 20)
|
||||||
doAssert(p0(h) == 21)
|
doAssert(p0(h) == 21)
|
||||||
doAssert(p0(i) == 21)
|
doAssert(p0(i) == 21)
|
||||||
|
|
||||||
|
#type
|
||||||
|
# f0 = proc(x:Foo)
|
||||||
|
|
||||||
|
|
||||||
|
block:
|
||||||
|
type
|
||||||
|
TilesetCT[n: static[int]] = distinct int
|
||||||
|
TilesetRT = int
|
||||||
|
Tileset = TilesetCT | TilesetRT
|
||||||
|
|
||||||
|
func prepareTileset(tileset: var Tileset) = discard
|
||||||
|
|
||||||
|
func prepareTileset(tileset: Tileset): Tileset =
|
||||||
|
result = tileset
|
||||||
|
result.prepareTileset
|
||||||
|
|
||||||
|
var parsedTileset: TilesetRT
|
||||||
|
prepareTileset(parsedTileset)
|
||||||
|
|
||||||
|
|
||||||
|
block:
|
||||||
|
proc p1[T,U: SomeInteger|SomeFloat](x: T, y: U): int|float =
|
||||||
|
when T is SomeInteger and U is SomeInteger:
|
||||||
|
result = int(x) + int(y)
|
||||||
|
else:
|
||||||
|
result = float(x) + float(y)
|
||||||
|
doAssert(p1(1,2) == 3)
|
||||||
|
doAssert(p1(1.0,2) == 3.0)
|
||||||
|
doAssert(p1(1,2.0) == 3.0)
|
||||||
|
doAssert(p1(1.0,2.0) == 3.0)
|
||||||
|
|
||||||
|
type Foo[T,U] = U
|
||||||
|
template F[T,U](t: typedesc[T], x: U): untyped = Foo[T,U](x)
|
||||||
|
proc p2[T; U,V:Foo[T,SomeNumber]](x: U, y: V): T =
|
||||||
|
T(x) + T(y)
|
||||||
|
#proc p2[T; U:Foo[T,SomeNumber], V:Foo[not T,SomeNumber]](x: U, y: V): T =
|
||||||
|
# T(x) + T(y)
|
||||||
|
doAssert(p2(F(int,1),F(int,2)) == 3)
|
||||||
|
doAssert(p2(F(float,1),F(float,2)) == 3.0)
|
||||||
|
doAssert(p2(F(float,1),F(float,2.0)) == 3.0)
|
||||||
|
doAssert(p2(F(float,1.0),F(float,2)) == 3.0)
|
||||||
|
doAssert(p2(F(float,1.0),F(float,2.0)) == 3.0)
|
||||||
|
#doAssert(p2(F(float,1),F(int,2.0)) == 3.0)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue