mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
couple cases of valid concept bindings (#24513)
see tests --------- Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
@@ -89,29 +89,52 @@ proc existingBinding(m: MatchCon; key: PType): PType =
|
||||
|
||||
proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool
|
||||
|
||||
proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool
|
||||
proc matchType(c: PContext; f, ao: PType; m: var MatchCon): bool
|
||||
|
||||
proc acceptsAllTypes(t: PType): bool=
|
||||
result = false
|
||||
if t.kind == tyAnything:
|
||||
result = true
|
||||
elif t.kind == tyGenericParam:
|
||||
if tfImplicitTypeParam in t.flags:
|
||||
result = true
|
||||
if not t.hasElementType or t.elementType.kind == tyNone:
|
||||
result = true
|
||||
|
||||
proc matchKids(c: PContext; f, a: PType; m: var MatchCon, start=0): bool=
|
||||
result = true
|
||||
for i in start..<f.kidsLen - ord(f.kind == tyGenericInst):
|
||||
if not matchType(c, f[i], a[i], m): return false
|
||||
|
||||
proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
proc matchType(c: PContext; f, ao: PType; m: var MatchCon): bool =
|
||||
## The heart of the concept matching process. 'f' is the formal parameter of some
|
||||
## routine inside the concept that we're looking for. 'a' is the formal parameter
|
||||
## of a routine that might match.
|
||||
const
|
||||
ignorableForArgType = {tyVar, tySink, tyLent, tyOwned, tyGenericInst, tyAlias, tyInferred}
|
||||
|
||||
var a = ao
|
||||
|
||||
case a.kind
|
||||
of tyGenericParam:
|
||||
let binding = m.existingBinding(a)
|
||||
if binding != nil:
|
||||
a = binding
|
||||
else:
|
||||
discard
|
||||
|
||||
case f.kind
|
||||
of tyAlias:
|
||||
result = matchType(c, f.skipModifier, a, m)
|
||||
of tyTypeDesc:
|
||||
if isSelf(f):
|
||||
#let oldLen = m.inferred.len
|
||||
result = matchType(c, a, m.potentialImplementation, m)
|
||||
#echo "self is? ", result, " ", a.kind, " ", a, " ", m.potentialImplementation, " ", m.potentialImplementation.kind
|
||||
#m.inferred.setLen oldLen
|
||||
#echo "A for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
|
||||
if m.magic in {mArrPut, mArrGet}:
|
||||
result = false
|
||||
if m.potentialImplementation.reduceToBase.kind in arrPutGetMagicApplies:
|
||||
m.inferred.add((a, last m.potentialImplementation))
|
||||
result = true
|
||||
else:
|
||||
result = matchType(c, a, m.potentialImplementation, m)
|
||||
else:
|
||||
if a.kind == tyTypeDesc and f.hasElementType == a.hasElementType:
|
||||
if f.hasElementType:
|
||||
@@ -120,7 +143,6 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
result = true # both lack it
|
||||
else:
|
||||
result = false
|
||||
|
||||
of tyGenericInvocation:
|
||||
result = false
|
||||
if a.kind == tyGenericInst and a.genericHead.kind == tyGenericBody:
|
||||
@@ -142,7 +164,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
|
||||
when logBindings: echo "A adding ", f, " ", ak
|
||||
m.inferred.add((f, ak))
|
||||
elif m.magic == mArrGet and ak.kind in {tyArray, tyOpenArray, tySequence, tyVarargs, tyCstring, tyString}:
|
||||
when logBindings: echo "B adding ", f, " ", lastSon ak
|
||||
when logBindings: echo "B adding ", f, " ", last ak
|
||||
m.inferred.add((f, last ak))
|
||||
result = true
|
||||
else:
|
||||
@@ -355,6 +377,8 @@ proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var LayeredIdTable
|
||||
## `C[S, T]` parent type that we look for. We need this because we need to store bindings
|
||||
## for 'S' and 'T' inside 'bindings' on a successful match. It is very important that
|
||||
## we do not add any bindings at all on an unsuccessful match!
|
||||
if arg.containsUnresolvedType:
|
||||
return false
|
||||
var m = MatchCon(inferred: @[], potentialImplementation: arg, concpt: concpt)
|
||||
result = conceptMatchNode(c, concpt.n.lastSon, m)
|
||||
if result:
|
||||
|
||||
@@ -595,45 +595,6 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
|
||||
else: result = isIntConv
|
||||
else: result = isNone
|
||||
|
||||
proc reduceToBase(f: PType): PType =
|
||||
#[
|
||||
Returns the lowest order (most general) type that that is compatible with the input.
|
||||
E.g.
|
||||
A[T] = ptr object ... A -> ptr object
|
||||
A[N: static[int]] = array[N, int] ... A -> array
|
||||
]#
|
||||
case f.kind:
|
||||
of tyGenericParam:
|
||||
if f.len <= 0 or f.skipModifier == nil:
|
||||
result = f
|
||||
else:
|
||||
result = reduceToBase(f.skipModifier)
|
||||
of tyGenericInvocation:
|
||||
result = reduceToBase(f.baseClass)
|
||||
of tyCompositeTypeClass, tyAlias:
|
||||
if not f.hasElementType or f.elementType == nil:
|
||||
result = f
|
||||
else:
|
||||
result = reduceToBase(f.elementType)
|
||||
of tyGenericInst:
|
||||
result = reduceToBase(f.skipModifier)
|
||||
of tyGenericBody:
|
||||
result = reduceToBase(f.typeBodyImpl)
|
||||
of tyUserTypeClass:
|
||||
if f.isResolvedUserTypeClass:
|
||||
result = f.base # ?? idk if this is right
|
||||
else:
|
||||
result = f.skipModifier
|
||||
of tyStatic, tyOwned, tyVar, tyLent, tySink:
|
||||
result = reduceToBase(f.base)
|
||||
of tyInferred:
|
||||
# This is not true "After a candidate type is selected"
|
||||
result = reduceToBase(f.base)
|
||||
of tyRange:
|
||||
result = f.elementType
|
||||
else:
|
||||
result = f
|
||||
|
||||
proc genericParamPut(c: var TCandidate; last, fGenericOrigin: PType) =
|
||||
if fGenericOrigin != nil and last.kind == tyGenericInst and
|
||||
last.kidsLen-1 == fGenericOrigin.kidsLen:
|
||||
|
||||
@@ -102,6 +102,9 @@ const
|
||||
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
|
||||
typedescPtrs* = abstractPtrs + {tyTypeDesc}
|
||||
typedescInst* = abstractInst + {tyTypeDesc, tyOwned, tyUserTypeClass}
|
||||
|
||||
# incorrect definition of `[]` and `[]=` for these types in system.nim
|
||||
arrPutGetMagicApplies* = {tyArray, tyOpenArray, tyString, tySequence, tyCstring, tyTuple}
|
||||
|
||||
proc invalidGenericInst*(f: PType): bool =
|
||||
result = f.kind == tyGenericInst and skipModifier(f) == nil
|
||||
@@ -2038,3 +2041,42 @@ proc genericRoot*(t: PType): PType =
|
||||
result = t.sym.typ
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc reduceToBase*(f: PType): PType =
|
||||
#[
|
||||
Returns the lowest order (most general) type that that is compatible with the input.
|
||||
E.g.
|
||||
A[T] = ptr object ... A -> ptr object
|
||||
A[N: static[int]] = array[N, int] ... A -> array
|
||||
]#
|
||||
case f.kind:
|
||||
of tyGenericParam:
|
||||
if f.len <= 0 or f.skipModifier == nil:
|
||||
result = f
|
||||
else:
|
||||
result = reduceToBase(f.skipModifier)
|
||||
of tyGenericInvocation:
|
||||
result = reduceToBase(f.baseClass)
|
||||
of tyCompositeTypeClass, tyAlias:
|
||||
if not f.hasElementType or f.elementType == nil:
|
||||
result = f
|
||||
else:
|
||||
result = reduceToBase(f.elementType)
|
||||
of tyGenericInst:
|
||||
result = reduceToBase(f.skipModifier)
|
||||
of tyGenericBody:
|
||||
result = reduceToBase(f.typeBodyImpl)
|
||||
of tyUserTypeClass:
|
||||
if f.isResolvedUserTypeClass:
|
||||
result = f.base # ?? idk if this is right
|
||||
else:
|
||||
result = f.skipModifier
|
||||
of tyStatic, tyOwned, tyVar, tyLent, tySink:
|
||||
result = reduceToBase(f.base)
|
||||
of tyInferred:
|
||||
# This is not true "After a candidate type is selected"
|
||||
result = reduceToBase(f.base)
|
||||
of tyRange:
|
||||
result = f.elementType
|
||||
else:
|
||||
result = f
|
||||
|
||||
@@ -5,6 +5,7 @@ B[system.int]
|
||||
A[system.string]
|
||||
A[array[0..0, int]]
|
||||
A[seq[int]]
|
||||
char
|
||||
'''
|
||||
"""
|
||||
import conceptsv2_helper
|
||||
@@ -128,3 +129,38 @@ block: # more complex recursion
|
||||
|
||||
var a = BufferImpl[5]()
|
||||
launch(a, WritableImpl())
|
||||
|
||||
block: # capture p1[T]
|
||||
type
|
||||
A[T] = object
|
||||
C = concept
|
||||
proc p1(x: Self, i: int): float
|
||||
|
||||
proc p1[T](a: A[T], idx: int): T = default(T)
|
||||
proc p(a: C): int = discard
|
||||
proc p[T](a: T):int = assert false
|
||||
|
||||
discard p(A[float]())
|
||||
|
||||
block: # mArrGet binding
|
||||
type
|
||||
ArrayLike[T] = concept
|
||||
proc len(x: Self): int
|
||||
proc `[]`(b: Self, i: int): T
|
||||
|
||||
proc p[T](a: ArrayLike[T]): int= discard
|
||||
discard p([1,2])
|
||||
|
||||
block:
|
||||
type
|
||||
A[T] = object
|
||||
ArrayLike[T] = concept
|
||||
proc len(x: Self): int
|
||||
proc `[]`(b: Self, i: int): T
|
||||
proc tell(s: Self, x: A[int])
|
||||
|
||||
proc tell(x: string, h: A[int])= discard
|
||||
|
||||
proc spring[T](w: ArrayLike[T])= echo T
|
||||
|
||||
spring("hi")
|
||||
|
||||
Reference in New Issue
Block a user