v2 / vlib / v / tests / generics / generics_interface_cross_module_recheck_test.v
69 lines · 57 sloc · 1.58 KB · f7544e3484f4afb29d56a2e3cfcab9502092559d
Raw
1// Tests that methods of generic structs implementing generic interfaces
2// are properly type-checked when the struct is instantiated indirectly
3// (e.g. through a function that constructs the struct and returns it as
4// the interface type). Previously, generic_insts_to_concrete() would
5// register concrete types for these methods only after the checker's
6// post_process_generic_fns loop had already finished, causing cgen to
7// attempt code generation for unchecked AST nodes.
8
9interface Processor[T] {
10 process(val T) T
11}
12
13struct Doubler[T] {
14 factor T
15}
16
17fn (d &Doubler[T]) process(val T) T {
18 return val * d.factor
19}
20
21struct Negator[T] {
22 offset T
23}
24
25fn (n &Negator[T]) process(val T) T {
26 return -val + n.offset
27}
28
29fn make_doubler[T](factor T) Processor[T] {
30 return Processor[T](&Doubler[T]{
31 factor: factor
32 })
33}
34
35fn make_negator[T](offset T) Processor[T] {
36 return Processor[T](&Negator[T]{
37 offset: offset
38 })
39}
40
41struct Pipeline[T] {
42mut:
43 processors []Processor[T]
44}
45
46fn (mut p Pipeline[T]) add_doubler(factor T) {
47 p.processors << make_doubler[T](factor)
48}
49
50fn (mut p Pipeline[T]) add_negator(offset T) {
51 p.processors << make_negator[T](offset)
52}
53
54fn (p &Pipeline[T]) run(val T) T {
55 mut result := val
56 for proc in p.processors {
57 result = proc.process(result)
58 }
59 return result
60}
61
62fn test_generic_interface_cross_module_recheck() {
63 mut p := Pipeline[f64]{}
64 // Only add_doubler is called; add_negator is never called.
65 // But Negator[f64] still gets instantiated via generic_insts_to_concrete
66 // and its process method must be properly type-checked.
67 p.add_doubler(3.0)
68 assert p.run(5.0) == 15.0
69}
70