Skip to content

Commit

Permalink
fixes #24451; concept matching generic body (#24458)
Browse files Browse the repository at this point in the history
I think this might not be a comprehensive solution to dealing with
`tyGenericBody` but we take a step forward
#24451
  • Loading branch information
Graveflo authored Nov 22, 2024
1 parent 33e455c commit 08c2a17
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 7 deletions.
23 changes: 16 additions & 7 deletions compiler/concepts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ 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 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 =
## 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
Expand Down Expand Up @@ -117,9 +124,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
result = false
if a.kind == tyGenericInst and a.genericHead.kind == tyGenericBody:
if sameType(f.genericHead, a.genericHead) and f.kidsLen == a.kidsLen-1:
for i in FirstGenericParamAt ..< f.kidsLen:
if not matchType(c, f[i], a[i], m): return false
return true
result = matchKids(c, f, a, m, start=FirstGenericParamAt)
of tyGenericParam:
let ak = a.skipTypes({tyVar, tySink, tyLent, tyOwned})
if ak.kind in {tyTypeDesc, tyStatic} and not isSelf(ak):
Expand Down Expand Up @@ -151,7 +156,6 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
else:
result = false
#echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)

of tyVar, tySink, tyLent, tyOwned:
# modifiers in the concept must be there in the actual implementation
# too but not vice versa.
Expand All @@ -177,15 +181,20 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
m.potentialImplementation = oldPotentialImplementation
if not result:
m.inferred.setLen oldLen
of tyGenericBody:
var ak = a
if a.kind == tyGenericBody:
ak = last(a)
result = matchType(c, last(f), ak, m)
of tyCompositeTypeClass:
result = matchType(c, last(f), a, m)
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
tyGenericInst:
# ^ XXX Rewrite this logic, it's more complex than it needs to be.
result = false
let ak = a.skipTypes(ignorableForArgType - {f.kind})
if ak.kind == f.kind and f.kidsLen == ak.kidsLen:
for i in 0..<ak.kidsLen:
if not matchType(c, f[i], ak[i], m): return false
return true
result = matchKids(c, f, ak, m)
of tyOr:
let oldLen = m.inferred.len
if a.kind == tyOr:
Expand Down
41 changes: 41 additions & 0 deletions tests/concepts/tconceptsv2.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
discard """
action: "run"
output: '''
B[system.int]
A[system.string]
'''
"""

block: # issue #24451
type
A = object
x: int
B[T] = object
b: T
AConcept = concept
proc implementation(s: var Self, p1: B[int])

proc implementation(r: var A, p1: B[int])=
echo typeof(p1)

proc accept(r: var AConcept)=
r.implementation(B[int]())

var a = A()
a.accept()

block: # typeclass
type
A[T] = object
x: int
AConcept = concept
proc implementation(s: Self)

proc implementation(r: A) =
echo typeof(r)

proc accept(r: AConcept) =
r.implementation()

var a = A[string]()
a.accept()

0 comments on commit 08c2a17

Please sign in to comment.