| 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 | |
| 9 | interface Processor[T] { |
| 10 | process(val T) T |
| 11 | } |
| 12 | |
| 13 | struct Doubler[T] { |
| 14 | factor T |
| 15 | } |
| 16 | |
| 17 | fn (d &Doubler[T]) process(val T) T { |
| 18 | return val * d.factor |
| 19 | } |
| 20 | |
| 21 | struct Negator[T] { |
| 22 | offset T |
| 23 | } |
| 24 | |
| 25 | fn (n &Negator[T]) process(val T) T { |
| 26 | return -val + n.offset |
| 27 | } |
| 28 | |
| 29 | fn make_doubler[T](factor T) Processor[T] { |
| 30 | return Processor[T](&Doubler[T]{ |
| 31 | factor: factor |
| 32 | }) |
| 33 | } |
| 34 | |
| 35 | fn make_negator[T](offset T) Processor[T] { |
| 36 | return Processor[T](&Negator[T]{ |
| 37 | offset: offset |
| 38 | }) |
| 39 | } |
| 40 | |
| 41 | struct Pipeline[T] { |
| 42 | mut: |
| 43 | processors []Processor[T] |
| 44 | } |
| 45 | |
| 46 | fn (mut p Pipeline[T]) add_doubler(factor T) { |
| 47 | p.processors << make_doubler[T](factor) |
| 48 | } |
| 49 | |
| 50 | fn (mut p Pipeline[T]) add_negator(offset T) { |
| 51 | p.processors << make_negator[T](offset) |
| 52 | } |
| 53 | |
| 54 | fn (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 | |
| 62 | fn 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 | |