From 0e6f0c1de0b30c9032f5c14d6ef5c243ff0611a6 Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 25 May 2021 11:15:05 +0800 Subject: [PATCH] checker: check generic struct init without type parameter (#10193) --- vlib/v/checker/checker.v | 8 +++ .../tests/generics_struct_init_err.out | 14 ++++ .../checker/tests/generics_struct_init_err.vv | 69 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 vlib/v/checker/tests/generics_struct_init_err.out create mode 100644 vlib/v/checker/tests/generics_struct_init_err.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index a1be5da57f..2a28281e1c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -690,6 +690,14 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { struct_init.typ = c.expected_type } } + struct_sym := c.table.get_type_symbol(struct_init.typ) + if struct_sym.info is ast.Struct { + if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0 + && c.cur_concrete_types.len == 0 { + c.error('generic struct init must specify type parameter, e.g. Foo', + struct_init.pos) + } + } utyp := c.unwrap_generic_struct(struct_init.typ, c.table.cur_fn.generic_names, c.cur_concrete_types) c.ensure_type_exists(utyp, struct_init.pos) or {} type_sym := c.table.get_type_symbol(utyp) diff --git a/vlib/v/checker/tests/generics_struct_init_err.out b/vlib/v/checker/tests/generics_struct_init_err.out new file mode 100644 index 0000000000..c55c33618d --- /dev/null +++ b/vlib/v/checker/tests/generics_struct_init_err.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/generics_struct_init_err.vv:58:8: error: generic struct init must specify type parameter, e.g. Foo + 56 | ret = holder_call_12(neg, 3) + 57 | assert ret == -3 + 58 | ret = FnHolder1{neg}.call(4) + | ~~~~~~~~~~~~~~ + 59 | assert ret == -4 + 60 | +vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: generic struct init must specify type parameter, e.g. Foo + 65 | ret = holder_call_22(neg, 5) + 66 | assert ret == -5 + 67 | ret = FnHolder2{neg}.call(6) + | ~~~~~~~~~~~~~~ + 68 | assert ret == -6 + 69 | } diff --git a/vlib/v/checker/tests/generics_struct_init_err.vv b/vlib/v/checker/tests/generics_struct_init_err.vv new file mode 100644 index 0000000000..41167992e7 --- /dev/null +++ b/vlib/v/checker/tests/generics_struct_init_err.vv @@ -0,0 +1,69 @@ +fn neg(a int) int { + return -a +} + +struct FnHolder1 { + func T +} + +fn (self FnHolder1) call(a int) int { + return self.func(a) +} + +struct FnHolder2 { + func fn (int) int +} + +fn (self FnHolder2) call(a int) int { + return self.func(a) +} + +fn holder_call_1(func T, a int) int { + h := FnHolder1{func} + return h.call(a) +} + +fn holder_call_2(func T, a int) int { + h := FnHolder2{func} + return h.call(a) +} + +fn holder_call_11(func T, a int) int { + f := func + h := FnHolder1{f} + return h.call(a) +} + +fn holder_call_21(func T, a int) int { + f := func + h := FnHolder2{f} + return h.call(a) +} + +fn holder_call_12(func T, a int) int { + return FnHolder1{func}.call(a) +} + +fn holder_call_22(func T, a int) int { + return FnHolder2{func}.call(a) +} + +fn main() { + mut ret := holder_call_1(neg, 1) + assert ret == -1 + ret = holder_call_11(neg, 2) + assert ret == -2 + ret = holder_call_12(neg, 3) + assert ret == -3 + ret = FnHolder1{neg}.call(4) + assert ret == -4 + + ret = holder_call_2(neg, 3) + assert ret == -3 + ret = holder_call_21(neg, 4) + assert ret == -4 + ret = holder_call_22(neg, 5) + assert ret == -5 + ret = FnHolder2{neg}.call(6) + assert ret == -6 +}