Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions compiler/concepts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,22 @@ proc conceptsMatch(c: PContext, fc, ac: PType; m: var MatchCon): MatchKind =
return mkNoMatch
return mkSubset

proc isObjectSubtype(f, a: PType): bool =
var t = a
result = false
while t != nil:
t = t.baseClass
if t == nil:
break
t = t.skipTypes({tyPtr,tyRef})
if t == nil:
break
if t.kind != tyObject:
break
if sameObjectTypes(f, t):
result = true
break

proc matchType(c: PContext; fo, 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
Expand Down Expand Up @@ -327,6 +343,8 @@ proc matchType(c: PContext; fo, ao: PType; m: var MatchCon): bool =
result = a.base.sym == f.sym
else:
result = sameType(f, a)
if not result and f.kind == tyObject and a.kind == tyObject:
result = isObjectSubtype(f, a)
of tyEmpty, tyString, tyCstring, tyPointer, tyNil, tyUntyped, tyTyped, tyVoid:
result = a.skipTypes(ignorableForArgType).kind == f.kind
of tyBool, tyChar, tyInt..tyUInt64:
Expand Down
6 changes: 6 additions & 0 deletions doc/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -3008,6 +3008,12 @@ is more specific
2. if the concept is being compared with another concept the result is deferred to [Concept subset matching]
3. in any other case the concept is less specific then it's competitor

Currently, the concept evaluation mechanism evaluates to a successful match on the first acceptable candidate
for each defined binding. This has a couple of notable effects:

- generic parameters are fulfilled by the first candidate match even if other candidates would also match and bind different parameters
- inheritable objects match as they do in normal overload resolution except the "depth" is not accounted for, because that would require calculating the minimum depth of any matching binding


Concept subset matching
-------------------------
Expand Down
15 changes: 15 additions & 0 deletions tests/concepts/tconceptsv2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -585,3 +585,18 @@ block:
discard

assert (ref AObj[int]) is C

block:
type
C = concept
proc x(a:Self, x: int)
StreamObj = object of RootObj
Stream = ref StreamObj
MemMapFileStreamObj = object of Stream
MemMapFileStream = ref MemMapFileStreamObj

proc x(a: Stream, x: int) = discard
proc spring(x: C) = discard

let test = MemMapFileStream()
spring(test)