Files
Nim/tests/concepts/t26147.nim
pacien bd32dab561 concepts: fix generic concept devaluation skipped in typeRel (#26164)
Fix and tests for issues #26147 case A.
See individual commit messages.

Checked on the full test suite: no new failure with respect to devel as
baseline.
2026-09-10 08:49:43 +02:00

94 lines
2.5 KiB
Nim

discard """
action: run
"""
type Indexable[T] = concept
proc `[]`(a: Self; index: int): T
proc len(a: Self): int
iterator items[T; I: Indexable[T]](indexable: I): T =
for index in 0 ..< indexable.len:
yield indexable[index]
type Dummy[T] = distinct seq[T]
proc `[]`[T](d: Dummy[T], i: int): T = seq[T](d)[i]
proc len[T](d: Dummy[T]): int = seq[T](d).len
var acc = 0
for x in Dummy(@[1, 2, 3]):
acc += x
doAssert acc == 6
# Inferred concept parameters are resolved through the implementation's own
# generic bindings before being exported to the surrounding routine.
type
Elem[T] = object
value: T
NestedDummy[T] = ref object
data: seq[T]
proc `[]`[T](d: NestedDummy[T], i: int): Elem[T] =
Elem[T](value: d.data[i])
proc len[T](d: NestedDummy[T]): int = d.data.len
iterator directItems[T](indexable: Indexable[T]): T =
for index in 0 ..< indexable.len:
yield indexable[index]
var nestedAcc = 0
for x in NestedDummy[int](data: @[4, 5, 6]):
nestedAcc += x.value
doAssert nestedAcc == 15
var directNestedAcc = 0
for x in directItems(NestedDummy[int](data: @[7, 8, 9])):
directNestedAcc += x.value
doAssert directNestedAcc == 24
# All dependent parameters inferred while checking a concept constraint must
# be propagated to the constrained routine.
type
KeyValue[K, V] = concept
proc key(x: Self): K
proc value(x: Self): V
Pair[K, V] = object
k: K
v: V
proc key[K, V](x: Pair[K, V]): K = x.k
proc value[K, V](x: Pair[K, V]): V = x.v
proc unpack[K, V; P: KeyValue[K, V]](x: P): (K, V) =
(x.key, x.value)
let pair = Pair[int, string](k: 7, v: "seven")
doAssert unpack(pair) == (7, "seven")
doAssert not compiles(unpack[string, int](pair))
proc unpackBoth[K1, V1, K2, V2;
P1: KeyValue[K1, V1]; P2: KeyValue[K2, V2]](
x: P1; y: P2): ((K1, V1), (K2, V2)) =
(unpack(x), unpack(y))
let otherPair = Pair[string, float](k: "eight", v: 8.0)
doAssert unpackBoth(pair, otherPair) == ((7, "seven"), ("eight", 8.0))
# A concrete `items` overload must win over one declared over a concept that
# the type happens to satisfy, and not generate an "ambiguous call".
type OverloadDummy[T] = ref object
data: seq[T]
proc `[]`[T](d: OverloadDummy[T], i: int): T = d.data[i]
proc len[T](d: OverloadDummy[T]): int = d.data.len
iterator items[T](d: OverloadDummy[T]): T =
# deliberately distinguishable from the concept-provided iterator
for i in 0 ..< d.len:
yield d.data[i] * 10
var overloadAcc: seq[int] = @[]
for x in OverloadDummy[int](data: @[1, 2, 3]):
overloadAcc.add x
doAssert overloadAcc == @[10, 20, 30]