Skip to content

Commit

Permalink
recursion handle
Browse files Browse the repository at this point in the history
  • Loading branch information
Graveflo committed Nov 27, 2024
1 parent 71402c3 commit 9220274
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 8 deletions.
27 changes: 19 additions & 8 deletions compiler/concepts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type
magic: TMagic ## mArrGet and mArrPut is wrong in system.nim and
## cannot be fixed that easily.
## Thus we special case it here.
concpt: PType

proc existingBinding(m: MatchCon; key: PType): PType =
## checks if we bound the type variable 'key' already to some
Expand Down Expand Up @@ -174,13 +175,23 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
result = ak.kind == f.kind or ak.kind == tyOrdinal or
(ak.kind == tyGenericParam and ak.hasElementType and ak.elementType.kind == tyOrdinal)
of tyConcept:
let oldLen = m.inferred.len
let oldPotentialImplementation = m.potentialImplementation
m.potentialImplementation = a
result = conceptMatchNode(c, f.n.lastSon, m)
m.potentialImplementation = oldPotentialImplementation
if not result:
m.inferred.setLen oldLen
if a.kind == tyConcept and f.n == a.n:
result = true
elif m.concpt.size == szIllegalRecursion:
result = false
else:
let oldLen = m.inferred.len
let oldPotentialImplementation = m.potentialImplementation
m.potentialImplementation = a
m.concpt.size = szIllegalRecursion
let oldConcept = m.concpt
m.concpt = f
result = conceptMatchNode(c, f.n.lastSon, m)
m.potentialImplementation = oldPotentialImplementation
m.concpt = oldConcept
m.concpt.size = szUnknownSize
if not result:
m.inferred.setLen oldLen
of tyGenericBody:
var ak = a
if a.kind == tyGenericBody:
Expand Down Expand Up @@ -344,7 +355,7 @@ 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!
var m = MatchCon(inferred: @[], potentialImplementation: arg)
var m = MatchCon(inferred: @[], potentialImplementation: arg, concpt: concpt)
result = conceptMatchNode(c, concpt.n.lastSon, m)
if result:
for (a, b) in m.inferred:
Expand Down
36 changes: 36 additions & 0 deletions tests/concepts/tconceptsv2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,39 @@ block: # composite typeclass matching

var a = BufferImpl()
launch(a)

block: # simple recursion
type
Buffer = concept
proc put(s: var Self, i: auto)
proc second(s: Self)
Writable = concept
proc put(w: var Buffer, s: Self)
BufferImpl[T: static int] = object
WritableImpl = object

proc launch(a: var Buffer, b: Writable)= discard
proc put(x: var BufferImpl, i: object)= discard
proc second(x: BufferImpl)= discard
proc put(x: var Buffer, y: WritableImpl)= discard

var a = BufferImpl[5]()
launch(a, WritableImpl())

block: # more complex recursion
type
Buffer = concept
proc put(s: var Self, i: auto)
proc second(s: Self)
Writable = concept
proc put(w: var Buffer, s: Self)
BufferImpl[T: static int] = object
WritableImpl = object

proc launch(a: var Buffer, b: Writable)= discard
proc put(x: var BufferImpl, i: object)= discard
proc second(x: BufferImpl)= discard
proc put(x: var Buffer, y: WritableImpl)= discard

var a = BufferImpl[5]()
launch(a, WritableImpl())

0 comments on commit 9220274

Please sign in to comment.