mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
Add experimental inferGenericTypes switch (#22317)
* Infer generic bindings * Simple test * Add t * Allow it to work for templates too * Fix some builds by putting bindings in a template * Fix builtins * Slightly more exotic seq test * Test value-based generics using array * Pass expectedType into buildBindings * Put buildBindings into a proc * Manual entry * Remove leftover ` * Improve language used in the manual * Experimental flag and fix basic constructors * Tiny commend cleanup * Move to experimental manual * Use 'kind' so tuples continue to fail like before * Explicitly disallow tuples * Table test and document tuples * Test type reduction * Disable inferGenericTypes check for CI tests * Remove tuple info in manual * Always reduce types. Testing CI * Fixes * Ignore tyGenericInst * Prevent binding already bound generic params * tyUncheckedArray * Few more types * Update manual and check for flag again * Update tests/generics/treturn_inference.nim * var candidate, remove flag check again for CI * Enable check once more --------- Co-authored-by: SirOlaf <> Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
139
tests/generics/treturn_inference.nim
Normal file
139
tests/generics/treturn_inference.nim
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
{.experimental: "inferGenericTypes".}
|
||||
|
||||
import std/tables
|
||||
|
||||
block:
|
||||
type
|
||||
MyOption[T, Z] = object
|
||||
x: T
|
||||
y: Z
|
||||
|
||||
proc none[T, Z](): MyOption[T, Z] =
|
||||
when T is int:
|
||||
result.x = 22
|
||||
when Z is float:
|
||||
result.y = 12.0
|
||||
|
||||
proc myGenericProc[T, Z](): MyOption[T, Z] =
|
||||
none() # implied by return type
|
||||
|
||||
let a = myGenericProc[int, float]()
|
||||
doAssert a.x == 22
|
||||
doAssert a.y == 12.0
|
||||
|
||||
let b: MyOption[int, float] = none() # implied by type of b
|
||||
doAssert b.x == 22
|
||||
doAssert b.y == 12.0
|
||||
|
||||
# Simple template based result with inferred type for errors
|
||||
block:
|
||||
type
|
||||
ResultKind {.pure.} = enum
|
||||
Ok
|
||||
Err
|
||||
|
||||
Result[T] = object
|
||||
case kind: ResultKind
|
||||
of Ok:
|
||||
data: T
|
||||
of Err:
|
||||
errmsg: cstring
|
||||
|
||||
template err[T](msg: static cstring): Result[T] =
|
||||
Result[T](kind : ResultKind.Err, errmsg : msg)
|
||||
|
||||
proc testproc(): Result[int] =
|
||||
err("Inferred error!") # implied by proc return
|
||||
let r = testproc()
|
||||
doAssert r.kind == ResultKind.Err
|
||||
doAssert r.errmsg == "Inferred error!"
|
||||
|
||||
# Builtin seq
|
||||
block:
|
||||
let x: seq[int] = newSeq(1)
|
||||
doAssert x is seq[int]
|
||||
doAssert x.len() == 1
|
||||
|
||||
type
|
||||
MyType[T, Z] = object
|
||||
x: T
|
||||
y: Z
|
||||
|
||||
let y: seq[MyType[int, float]] = newSeq(2)
|
||||
doAssert y is seq[MyType[int, float]]
|
||||
doAssert y.len() == 2
|
||||
|
||||
let z = MyType[seq[float], string](
|
||||
x : newSeq(3),
|
||||
y : "test"
|
||||
)
|
||||
doAssert z.x is seq[float]
|
||||
doAssert z.x.len() == 3
|
||||
doAssert z.y is string
|
||||
doAssert z.y == "test"
|
||||
|
||||
# array
|
||||
block:
|
||||
proc giveArray[N, T](): array[N, T] =
|
||||
for i in 0 .. N.high:
|
||||
result[i] = i
|
||||
var x: array[2, int] = giveArray()
|
||||
doAssert x == [0, 1]
|
||||
|
||||
# tuples
|
||||
block:
|
||||
proc giveTuple[T, Z]: (T, Z, T) = discard
|
||||
let x: (int, float, int) = giveTuple()
|
||||
doAssert x is (int, float, int)
|
||||
doAssert x == (0, 0.0, 0)
|
||||
|
||||
proc giveNamedTuple[T, Z]: tuple[a: T, b: Z] = discard
|
||||
let y: tuple[a: int, b: float] = giveNamedTuple()
|
||||
doAssert y is (int, float)
|
||||
doAssert y is tuple[a: int, b: float]
|
||||
doAssert y == (0, 0.0)
|
||||
|
||||
proc giveNestedTuple[T, Z]: ((T, Z), Z) = discard
|
||||
let z: ((int, float), float) = giveNestedTuple()
|
||||
doAssert z is ((int, float), float)
|
||||
doAssert z == ((0, 0.0), 0.0)
|
||||
|
||||
# nesting inside a generic type
|
||||
type MyType[T] = object
|
||||
x: T
|
||||
let a = MyType[(int, MyType[float])](x : giveNamedTuple())
|
||||
doAssert a.x is (int, MyType[float])
|
||||
|
||||
|
||||
# basic constructors
|
||||
block:
|
||||
type MyType[T] = object
|
||||
x: T
|
||||
|
||||
proc giveValue[T](): T =
|
||||
when T is int:
|
||||
12
|
||||
else:
|
||||
default(T)
|
||||
|
||||
let x = MyType[int](x : giveValue())
|
||||
doAssert x.x is int
|
||||
doAssert x.x == 12
|
||||
|
||||
let y = MyType[MyType[float]](x : MyType[float](x : giveValue()))
|
||||
doAssert y.x is MyType[float]
|
||||
doAssert y.x.x is float
|
||||
doAssert y.x.x == 0.0
|
||||
|
||||
# 'MyType[float]' is bound to 'T' directly
|
||||
# instead of mapping 'T' to 'float'
|
||||
let z = MyType[MyType[float]](x : giveValue())
|
||||
doAssert z.x is MyType[float]
|
||||
doAssert z.x.x == 0.0
|
||||
|
||||
type Foo = object
|
||||
x: Table[int, float]
|
||||
|
||||
let a = Foo(x: initTable())
|
||||
doAssert a.x is Table[int, float]
|
||||
Reference in New Issue
Block a user