top-down type inference, implements rfc 149 (#20091)
* micro implementation of rfc 149 refs https://github.com/nim-lang/RFCs/issues/149 * number/array/seq literals, more statements * try fix number literal alias issue * renew expectedType with if/case/try branch types * fix (nerf) index type handling and float typed int * use typeAllowed * tweaks + const test (tested locally) [skip ci] * fill out more of the checklist * more literals, change @ order, type conversions Not copying the full call tree before the typedesc call check in `semIndirectOp` is also a small performance improvement. * disable self-conversion warning * revert type conversions (maybe separate op later) * deal with CI for now (seems unrelated), try enums * workaround CI different way * proper fix * again * see sizes * lol * overload selection, simplify int literal -> float * range, new @ solution, try use fitNode for nil * use new magic * try fix ranges, new magic, deal with #20193 * add documentation, support templates Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
parent
2dcfd73260
commit
0014b9c48e
17 changed files with 599 additions and 199 deletions
195
tests/types/ttopdowninference.nim
Normal file
195
tests/types/ttopdowninference.nim
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
block:
|
||||
var s: seq[string] = (discard; @[])
|
||||
|
||||
var x: set[char] =
|
||||
if true:
|
||||
try:
|
||||
case 1
|
||||
of 1:
|
||||
if false:
|
||||
{'4'}
|
||||
else:
|
||||
block:
|
||||
s.add "a"
|
||||
{}
|
||||
else: {'3'}
|
||||
except: {'2'}
|
||||
else: {'1'}
|
||||
doAssert x is set[char]
|
||||
doAssert x == {}
|
||||
doAssert s == @["a"]
|
||||
|
||||
x = {'a', 'b'}
|
||||
doAssert x == {'a', 'b'}
|
||||
|
||||
x = (s.add "b"; {})
|
||||
doAssert x == {}
|
||||
doAssert s == @["a", "b"]
|
||||
|
||||
let x2: set[byte] = {1}
|
||||
doAssert x2 == {1u8}
|
||||
|
||||
block:
|
||||
let x3: array[0..2, byte] = [1, 2, 3]
|
||||
#let x4: openarray[byte] = [1, 2, 3]
|
||||
#let x5: openarray[byte] = @[1, 2, 3]
|
||||
let x6: seq[byte] = @[1, 2, 3]
|
||||
let x7: seq[seq[float32]] = @[@[1, 2, 3], @[4.3, 5, 6]]
|
||||
type ABC = enum a, b, c
|
||||
let x8: array[ABC, byte] = [1, 2, 3]
|
||||
doAssert x8[a] == 1
|
||||
doAssert x8[a] + x8[b] == x8[c]
|
||||
|
||||
const x9: array[-2..2, float] = [0, 1, 2, 3, 4]
|
||||
let x10: array[ABC, byte] = block:
|
||||
{.gcsafe.}:
|
||||
[a: 1, b: 2, c: 3]
|
||||
proc `@`(x: float): float = x + 1
|
||||
doAssert @1 == 2
|
||||
let x11: seq[byte] = system.`@`([1, 2, 3])
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: BiggestInt
|
||||
var foo: Foo
|
||||
foo.x = case true
|
||||
of true: ord(1)
|
||||
else: 0
|
||||
foo.x = if true: ord(1) else: 0
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: (float, seq[(byte, seq[byte])])
|
||||
|
||||
let foo = Foo(x: (1, @{2: @[], 3: @[4, 5]}))
|
||||
doAssert foo.x == (1.0, @{2u8: @[], 3u8: @[4u8, 5]})
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: tuple[a: float, b: seq[(byte, seq[byte])]]
|
||||
|
||||
let foo = Foo(x: (a: 1, b: @{2: @[3, 4], 5: @[]}))
|
||||
doAssert foo.x == (1.0, @{2u8: @[3u8, 4], 5u8: @[]})
|
||||
|
||||
block:
|
||||
proc foo(): seq[float] = @[1]
|
||||
|
||||
let fooLamb = proc(): seq[float] = @[1]
|
||||
|
||||
doAssert foo() == fooLamb()
|
||||
|
||||
block:
|
||||
type Foo[T] = float32
|
||||
|
||||
let x: seq[Foo[int32]] = @[1]
|
||||
|
||||
block:
|
||||
type Foo = ref object
|
||||
type Bar[T] = ptr object
|
||||
|
||||
let x1: seq[Foo] = @[nil]
|
||||
let x2: seq[Bar[int]] = @[nil]
|
||||
let x3: seq[cstring] = @[nil]
|
||||
|
||||
block:
|
||||
let x: seq[cstring] = @["abc", nil, "def"]
|
||||
doAssert x.len == 3
|
||||
doAssert x[0] == cstring"abc"
|
||||
doAssert x[1].isNil
|
||||
doAssert x[2] == "def".cstring
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: tuple[a: float, b: seq[(byte, seq[cstring])]]
|
||||
|
||||
let foo = Foo(x: (a: 1, b: @{2: @[nil, "abc"]}))
|
||||
doAssert foo.x == (1.0, @{2u8: @[cstring nil, cstring "abc"]})
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: tuple[a: float, b: seq[(byte, seq[ptr int])]]
|
||||
|
||||
let foo = Foo(x: (a: 1, b: @{2: @[nil, nil]}))
|
||||
doAssert foo.x == (1.0, @{2u8: @[(ptr int)(nil), nil]})
|
||||
|
||||
when false: # unsupported
|
||||
block: # type conversion
|
||||
let x = seq[(cstring, float32)](@{"abc": 1.0, "def": 2.0})
|
||||
doAssert x[0] == (cstring"abc", 1.0'f32)
|
||||
doAssert x[1] == (cstring"def", 2.0'f32)
|
||||
|
||||
block: # enum
|
||||
type Foo {.pure.} = enum a
|
||||
type Bar {.pure.} = enum a, b, c
|
||||
|
||||
var s: seq[Bar] = @[a, b, c]
|
||||
|
||||
block: # overload selection
|
||||
proc foo(x, y: int): int = x + y + 1
|
||||
proc foo(x: int): int = x - 1
|
||||
var s: seq[proc (x, y: int): int] = @[nil, foo, foo]
|
||||
var s2: seq[int]
|
||||
for a in s:
|
||||
if not a.isNil: s2.add(a(1, 2))
|
||||
doAssert s2 == @[4, 4]
|
||||
|
||||
block: # with generics?
|
||||
proc foo(x, y: int): int = x + y + 1
|
||||
proc foo(x: int): int = x - 1
|
||||
proc bar[T](x, y: T): T = x - y
|
||||
var s: seq[proc (x, y: int): int] = @[nil, foo, foo, bar]
|
||||
var s2: seq[int]
|
||||
for a in s:
|
||||
if not a.isNil: s2.add(a(1, 2))
|
||||
doAssert s2 == @[4, 4, -1]
|
||||
proc foo(x, y: float): float = x + y + 1.0
|
||||
var s3: seq[proc (x, y: float): float] = @[nil, foo, foo, bar]
|
||||
var s4: seq[float]
|
||||
for a in s3:
|
||||
if not a.isNil: s4.add(a(1, 2))
|
||||
doAssert s4 == @[4.0, 4, -1]
|
||||
|
||||
block: # range types
|
||||
block:
|
||||
let x: set[range[1u8..5u8]] = {1, 3}
|
||||
doAssert x == {range[1u8..5u8](1), 3}
|
||||
doAssert $x == "{1, 3}"
|
||||
block:
|
||||
let x: seq[set[range[1u8..5u8]]] = @[{1, 3}]
|
||||
doAssert x == @[{range[1u8..5u8](1), 3}]
|
||||
doAssert $x[0] == "{1, 3}"
|
||||
block:
|
||||
let x: seq[range[1u8..5u8]] = @[1, 3]
|
||||
doAssert x == @[range[1u8..5u8](1), 3]
|
||||
doAssert $x == "@[1, 3]"
|
||||
block: # already worked before, make sure it still works
|
||||
let x: set[range['a'..'e']] = {'a', 'c'}
|
||||
doAssert x == {range['a'..'e']('a'), 'c'}
|
||||
doAssert $x == "{'a', 'c'}"
|
||||
block: # extended
|
||||
let x: seq[set[range['a'..'e']]] = @[{'a', 'c'}]
|
||||
doAssert x[0] == {range['a'..'e']('a'), 'c'}
|
||||
doAssert $x == "@[{'a', 'c'}]"
|
||||
block:
|
||||
type Foo = object
|
||||
x: (range[1u8..5u8], seq[(range[1f32..5f32], seq[range['a'..'e']])])
|
||||
|
||||
let foo = Foo(x: (1, @{2: @[], 3: @['c', 'd']}))
|
||||
doAssert foo.x == (range[1u8..5u8](1u8), @{range[1f32..5f32](2f32): @[], 3f32: @[range['a'..'e']('c'), 'd']})
|
||||
block:
|
||||
type Foo = object
|
||||
x: (range[1u8..5u8], seq[(range[1f32..5f32], seq[set[range['a'..'e']]])])
|
||||
|
||||
let foo = Foo(x: (1, @{2: @[], 3: @[{'c', 'd'}]}))
|
||||
doAssert foo.x == (range[1u8..5u8](1u8), @{range[1f32..5f32](2f32): @[], 3f32: @[{range['a'..'e']('c'), 'd'}]})
|
||||
|
||||
block: # templates
|
||||
template foo: untyped = (1, 2, "abc")
|
||||
let x: (float, byte, cstring) = foo()
|
||||
doAssert x[0] == float(1)
|
||||
doAssert x[1] == byte(2)
|
||||
doAssert x[2] == cstring("abc")
|
||||
let (a, b, c) = x
|
||||
doAssert a == float(1)
|
||||
doAssert b == byte(2)
|
||||
doAssert c == cstring("abc")
|
||||
Loading…
Add table
Add a link
Reference in a new issue