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:
SirOlaf
2023-08-03 22:49:52 +02:00
committed by GitHub
parent 6b913b4741
commit 8d8d75706c
6 changed files with 288 additions and 11 deletions

View 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]