doh, forgot to add all files in the previous commit
This commit is contained in:
parent
597ea08815
commit
a802d72452
4 changed files with 65 additions and 15 deletions
|
|
@ -270,7 +270,8 @@ type
|
||||||
sfDiscardable, # returned value may be discarded implicitly
|
sfDiscardable, # returned value may be discarded implicitly
|
||||||
sfOverriden, # proc is overriden
|
sfOverriden, # proc is overriden
|
||||||
sfGenSym # symbol is 'gensym'ed; do not add to symbol table
|
sfGenSym # symbol is 'gensym'ed; do not add to symbol table
|
||||||
sfCovariant # covariant generic param
|
sfCovariant # covariant generic param mimicing seq/array type
|
||||||
|
sfStrongCovariant # covariant generic param mimicing ptr type
|
||||||
sfContravariant # contravariant generic param
|
sfContravariant # contravariant generic param
|
||||||
|
|
||||||
TSymFlags* = set[TSymFlag]
|
TSymFlags* = set[TSymFlag]
|
||||||
|
|
|
||||||
|
|
@ -429,7 +429,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
for i in 1..sonsLen(n)-1:
|
for i in 1..sonsLen(n)-1:
|
||||||
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
|
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
|
||||||
let arg = n[i].typ
|
let arg = n[i].typ
|
||||||
let tm = typeRel(m, formal, arg, true)
|
let tm = typeRel(m, formal, arg)
|
||||||
if tm in {isNone, isConvertible}: return nil
|
if tm in {isNone, isConvertible}: return nil
|
||||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||||
newInst.typ.flags.excl tfUnresolved
|
newInst.typ.flags.excl tfUnresolved
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,9 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||||
let n = if n[0].kind == nkBracket: n[0] else: n
|
let n = if n[0].kind == nkBracket: n[0] else: n
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
var t = semTypeNode(c, n.lastSon, nil)
|
var t = semTypeNode(c, n.lastSon, nil)
|
||||||
|
if c.inGenericContext > 0:
|
||||||
|
if t.sym != nil and sfCovariant in t.sym.flags:
|
||||||
|
t.sym.flags.incl sfStrongCovariant
|
||||||
if t.kind == tyTypeDesc and tfUnresolved notin t.flags:
|
if t.kind == tyTypeDesc and tfUnresolved notin t.flags:
|
||||||
t = t.base
|
t = t.base
|
||||||
result = newOrPrevType(kind, prev, c)
|
result = newOrPrevType(kind, prev, c)
|
||||||
|
|
@ -1590,9 +1593,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
if paramName.kind in {nkInTy, nkOutTy}:
|
if paramName.kind in {nkInTy, nkOutTy}:
|
||||||
if father == nil or sfImportc notin father.sym.flags:
|
if father == nil or sfImportc notin father.sym.flags:
|
||||||
localError(paramName.info, errInOutFlagNotExtern)
|
localError(paramName.info, errInOutFlagNotExtern)
|
||||||
paramName = paramName[0]
|
|
||||||
covarianceFlag = if paramName.kind == nkInTy: sfContravariant
|
covarianceFlag = if paramName.kind == nkInTy: sfContravariant
|
||||||
else: sfCovariant
|
else: sfCovariant
|
||||||
|
paramName = paramName[0]
|
||||||
|
|
||||||
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
|
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
|
||||||
newSymG(skGenericParam, paramName, c).linkTo(finalType)
|
newSymG(skGenericParam, paramName, c).linkTo(finalType)
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,12 @@ type
|
||||||
mutabilityProblem*: uint8 # tyVar mismatch
|
mutabilityProblem*: uint8 # tyVar mismatch
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
|
||||||
|
TTypeRelFlag* = enum
|
||||||
|
trDontBind
|
||||||
|
trNoCovariance
|
||||||
|
|
||||||
|
TTypeRelFlags* = set[TTypeRelFlag]
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
isNone, isConvertible,
|
isNone, isConvertible,
|
||||||
isIntConv,
|
isIntConv,
|
||||||
|
|
@ -296,7 +302,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
||||||
add(result, argTypeToString(arg, prefer))
|
add(result, argTypeToString(arg, prefer))
|
||||||
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,
|
||||||
|
flags: TTypeRelFlags = {}): TTypeRelation
|
||||||
|
|
||||||
proc concreteType(c: TCandidate, t: PType): PType =
|
proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyNil:
|
of tyNil:
|
||||||
|
|
@ -860,7 +868,28 @@ template subtypeCheck() =
|
||||||
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
|
||||||
|
# this proc is always called for a pair of matching types
|
||||||
|
assert f.kind == a.kind
|
||||||
|
|
||||||
|
template baseTypesCheck(lhs, rhs: PType): bool =
|
||||||
|
lhs.kind notin {tyPtr, tyRef, tyVar} and
|
||||||
|
typeRel(c, lhs, rhs, {trNoCovariance}) == isSubtype
|
||||||
|
|
||||||
|
case f.kind
|
||||||
|
of tyRef, tyPtr:
|
||||||
|
return baseTypesCheck(f.base, a.base)
|
||||||
|
of tyGenericInst:
|
||||||
|
let body = f.base
|
||||||
|
return body == a.base and
|
||||||
|
a.sonsLen == 3 and
|
||||||
|
sfStrongCovariant in body.sons[0].sym.flags and
|
||||||
|
baseTypesCheck(f.sons[1], a.sons[1])
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
|
flags: TTypeRelFlags = {}): 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
|
||||||
|
|
@ -927,6 +956,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = isEqual
|
result = isEqual
|
||||||
return
|
return
|
||||||
|
|
||||||
|
template doBind: bool = trDontBind notin flags
|
||||||
|
|
||||||
# var and static arguments match regular modifier-free types
|
# var and static arguments match regular modifier-free types
|
||||||
var a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
|
var a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
|
||||||
# XXX: Theoretically, maybeSkipDistinct could be called before we even
|
# XXX: Theoretically, maybeSkipDistinct could be called before we even
|
||||||
|
|
@ -963,7 +994,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
|
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
let x = typeRel(c, f, branch, false)
|
let x = typeRel(c, f, branch, flags + {trDontBind})
|
||||||
if x == isNone: return isNone
|
if x == isNone: return isNone
|
||||||
if x < result: result = x
|
if x < result: result = x
|
||||||
return
|
return
|
||||||
|
|
@ -974,7 +1005,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# seq[Sortable and Iterable] vs seq[Sortable]
|
# seq[Sortable and Iterable] vs seq[Sortable]
|
||||||
# only one match is enough
|
# only one match is enough
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
let x = typeRel(c, f, branch, false)
|
let x = typeRel(c, f, branch, flags + {trDontBind})
|
||||||
if x != isNone:
|
if x != isNone:
|
||||||
return if x >= isGeneric: isGeneric else: x
|
return if x >= isGeneric: isGeneric else: x
|
||||||
return isNone
|
return isNone
|
||||||
|
|
@ -1001,7 +1032,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyUserTypeClass, tyUserTypeClassInst:
|
of tyUserTypeClass, tyUserTypeClassInst:
|
||||||
# consider this: 'var g: Node' *within* a concept where 'Node'
|
# consider this: 'var g: Node' *within* a concept where 'Node'
|
||||||
# is a concept too (tgraph)
|
# is a concept too (tgraph)
|
||||||
let x = typeRel(c, a, f, false)
|
let x = typeRel(c, a, f, flags + {trDontBind})
|
||||||
if x >= isGeneric:
|
if x >= isGeneric:
|
||||||
return isGeneric
|
return isGeneric
|
||||||
else: discard
|
else: discard
|
||||||
|
|
@ -1047,7 +1078,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyFloat128: result = handleFloatRange(f, a)
|
of tyFloat128: result = handleFloatRange(f, a)
|
||||||
of tyVar:
|
of tyVar:
|
||||||
if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
|
if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
|
||||||
else: result = typeRel(c, f.base, aOrig)
|
else: result = typeRel(c, f.base, aOrig, flags + {trNoCovariance})
|
||||||
subtypeCheck()
|
subtypeCheck()
|
||||||
of tyArray:
|
of tyArray:
|
||||||
case a.kind
|
case a.kind
|
||||||
|
|
@ -1163,7 +1194,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if a.len < f.len: return isNone
|
if a.len < f.len: return isNone
|
||||||
for i in 0..f.len-2:
|
for i in 0..f.len-2:
|
||||||
if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
|
if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
|
||||||
result = typeRel(c, f.lastSon, a.lastSon)
|
result = typeRel(c, f.lastSon, a.lastSon, flags + {trNoCovariance})
|
||||||
subtypeCheck()
|
subtypeCheck()
|
||||||
if result <= isConvertible: result = isNone
|
if result <= isConvertible: result = isNone
|
||||||
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||||
|
|
@ -1235,15 +1266,30 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
var m = c
|
var m = c
|
||||||
if a.kind == tyGenericInst:
|
if a.kind == tyGenericInst:
|
||||||
if roota.base == rootf.base:
|
if roota.base == rootf.base:
|
||||||
|
let nextFlags = flags + {trNoCovariance}
|
||||||
|
var hasCovariance = false
|
||||||
for i in 1 .. rootf.sonsLen-2:
|
for i in 1 .. rootf.sonsLen-2:
|
||||||
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, nextFlags)
|
||||||
if result notin {isEqual, isGeneric}: return isNone
|
if result notin {isEqual, isGeneric}:
|
||||||
# if ff.kind == tyRange and result != isEqual: return isNone
|
if trNoCovariance notin flags and ff.kind == aa.kind:
|
||||||
|
let paramFlags = rootf.base.sons[i-1].sym.flags
|
||||||
|
hasCovariance =
|
||||||
|
if sfCovariant in paramFlags:
|
||||||
|
if sfStrongCovariant in paramFlags:
|
||||||
|
ff.kind notin {tyRef, tyPtr} and result == isSubtype
|
||||||
|
else:
|
||||||
|
isCovariantPtr(c, ff, aa)
|
||||||
|
else:
|
||||||
|
sfContravariant in paramFlags and
|
||||||
|
typeRel(c, aa, ff) == isSubtype
|
||||||
|
if hasCovariance:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return isNone
|
||||||
if prev == nil: put(c, f, a)
|
if prev == nil: put(c, f, a)
|
||||||
result = isGeneric
|
result = if hasCovariance: isGeneric else: isGeneric
|
||||||
else:
|
else:
|
||||||
let fKind = rootf.lastSon.kind
|
let fKind = rootf.lastSon.kind
|
||||||
if fKind in {tyAnd, tyOr}:
|
if fKind in {tyAnd, tyOr}:
|
||||||
|
|
@ -1455,7 +1501,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
|
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
|
||||||
result = typeRel(c, f.lastSon, a, false)
|
result = typeRel(c, f.lastSon, a, flags + {trDontBind})
|
||||||
if doBind and result notin {isNone, isGeneric}:
|
if doBind and result notin {isNone, isGeneric}:
|
||||||
let concrete = concreteType(c, a)
|
let concrete = concreteType(c, a)
|
||||||
if concrete == nil: return isNone
|
if concrete == nil: return isNone
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue