From 21b6e359af51c4c7b7f52c90dc3b863b66715962 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 23:03:27 +0300 Subject: [PATCH] orm: fix errors and panics when using anonymous structs (fixes #23299) --- vlib/v/checker/orm.v | 20 +++++++++++++++++++ .../v/checker/tests/orm_anon_struct_field.out | 7 +++++++ vlib/v/checker/tests/orm_anon_struct_field.vv | 17 ++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 vlib/v/checker/tests/orm_anon_struct_field.out create mode 100644 vlib/v/checker/tests/orm_anon_struct_field.vv diff --git a/vlib/v/checker/orm.v b/vlib/v/checker/orm.v index dc70c86b1..a6ddcdf02 100644 --- a/vlib/v/checker/orm.v +++ b/vlib/v/checker/orm.v @@ -548,6 +548,11 @@ fn (mut c Checker) fetch_and_check_orm_fields(info ast.Struct, pos token.Pos, ta field.pos) continue } + if c.orm_field_uses_anon_struct(field_typ) { + c.orm_error('field `${field.name}` uses an anonymous struct type, which ORM does not support; use a named struct, or skip it with `@[skip]` or `@[sql: \'-\']`', + field.pos) + continue + } field_sym := c.table.sym(field_typ) final_field_typ := c.table.final_type(field_typ) is_primitive := final_field_typ.is_string() || final_field_typ.is_bool() @@ -596,6 +601,21 @@ fn (mut c Checker) fetch_and_check_orm_fields(info ast.Struct, pos token.Pos, ta return fields } +fn (c &Checker) orm_field_uses_anon_struct(field_typ ast.Type) bool { + final_field_typ := c.table.final_type(field_typ.clear_flag(.option)) + field_sym := c.table.sym(final_field_typ) + if field_sym.kind == .struct && field_sym.info is ast.Struct && field_sym.info.is_anon { + return true + } + if field_sym.kind != .array { + return false + } + array_info := field_sym.array_info() + elem_typ := c.table.final_type(array_info.elem_type.clear_flag(.option)) + elem_sym := c.table.sym(elem_typ) + return elem_sym.kind == .struct && elem_sym.info is ast.Struct && elem_sym.info.is_anon +} + // check_sql_value_expr_is_comptime_with_natural_number_or_expr_with_int_type checks that an expression is compile-time // and contains an integer greater than or equal to zero or it is a runtime expression with an integer type. fn (mut c Checker) check_sql_value_expr_is_comptime_with_natural_number_or_expr_with_int_type(mut expr ast.Expr, diff --git a/vlib/v/checker/tests/orm_anon_struct_field.out b/vlib/v/checker/tests/orm_anon_struct_field.out new file mode 100644 index 000000000..14db2fb45 --- /dev/null +++ b/vlib/v/checker/tests/orm_anon_struct_field.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/orm_anon_struct_field.vv:5:2: error: ORM: field `name` uses an anonymous struct type, which ORM does not support; use a named struct, or skip it with `@[skip]` or `@[sql: '-']` + 3 | struct Foo { + 4 | id int @[primary; serial] + 5 | name struct { + | ~~~~~~~~~~~~~ + 6 | id int @[primary; serial] + 7 | first string diff --git a/vlib/v/checker/tests/orm_anon_struct_field.vv b/vlib/v/checker/tests/orm_anon_struct_field.vv new file mode 100644 index 000000000..decd3156b --- /dev/null +++ b/vlib/v/checker/tests/orm_anon_struct_field.vv @@ -0,0 +1,17 @@ +import db.sqlite + +struct Foo { + id int @[primary; serial] + name struct { + id int @[primary; serial] + first string + last string + } +} + +fn main() { + db := sqlite.connect(':memory:')! + sql db { + create table Foo + }! +} -- 2.39.5