From 0a11955284d7e988b5d3f5e961139829f3f635c1 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Thu, 15 Dec 2022 19:21:52 +0200 Subject: [PATCH] parser: support an unambiguous sizeof[T]() and isreftype[T]() (part 1) (#16684) --- doc/docs.md | 2 +- vlib/v/ast/ast.v | 16 +-- vlib/v/checker/checker.v | 12 +++ .../tests/unknown_sizeof_type_err_a.out | 8 +- .../tests/unknown_sizeof_type_err_a.vv | 6 +- .../tests/unknown_sizeof_type_err_b.out | 8 +- .../tests/unknown_sizeof_type_err_b.vv | 6 +- vlib/v/fmt/fmt.v | 36 +++++-- vlib/v/parser/expr.v | 100 +++++++++++------- 9 files changed, 128 insertions(+), 66 deletions(-) diff --git a/doc/docs.md b/doc/docs.md index 2e96c002fa..4054d42e87 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -6468,4 +6468,4 @@ Assignment Operators += -= *= /= %= &= |= ^= >>= <<= >>>= -``` +``` \ No newline at end of file diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index b90f0aba22..08dee21cb4 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1591,19 +1591,21 @@ pub mut: pub struct SizeOf { pub: - is_type bool - pos token.Pos + guessed_type bool // a legacy `sizeof( GuessedType )` => a deprecation notice, suggesting `v fmt -w .` => `sizeof[ Type ]()` + is_type bool + pos token.Pos pub mut: - expr Expr // checker uses this to set typ + expr Expr // checker uses this to set typ, when !is_type typ Type } pub struct IsRefType { pub: - is_type bool - pos token.Pos + guessed_type bool // a legacy `isreftype( GuessedType )` => a deprecation notice, suggesting `v fmt -w .` => `isreftype[ Type ]()` + is_type bool + pos token.Pos pub mut: - expr Expr // checker uses this to set typ + expr Expr // checker uses this to set typ, when !is_type typ Type } @@ -1629,7 +1631,7 @@ pub: is_type bool pos token.Pos pub mut: - expr Expr // checker uses this to set typ + expr Expr // checker uses this to set typ, when !is_type typ Type } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 8e97bb9aa7..711587025d 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2520,12 +2520,16 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type { if !node.is_type { node.typ = c.expr(node.expr) } + // c.deprecate_old_isreftype_and_sizeof_of_a_guessed_type(node.guessed_type, + // node.typ, node.pos, 'sizeof') return ast.u32_type } ast.IsRefType { if !node.is_type { node.typ = c.expr(node.expr) } + // c.deprecate_old_isreftype_and_sizeof_of_a_guessed_type(node.guessed_type, + // node.typ, node.pos, 'isreftype') return ast.bool_type } ast.OffsetOf { @@ -4395,3 +4399,11 @@ fn semicolonize(main string, details string) string { } return '${main}; ${details}' } + +fn (mut c Checker) deprecate_old_isreftype_and_sizeof_of_a_guessed_type(is_guessed_type bool, typ ast.Type, pos token.Pos, label string) { + if is_guessed_type { + styp := c.table.type_to_str(typ) + c.note('`${label}(${styp})` is deprecated. Use `v fmt -w .` to convert it to `${label}[${styp}]()` instead.', + pos) + } +} diff --git a/vlib/v/checker/tests/unknown_sizeof_type_err_a.out b/vlib/v/checker/tests/unknown_sizeof_type_err_a.out index 5c6e6cb7de..628c64e40b 100644 --- a/vlib/v/checker/tests/unknown_sizeof_type_err_a.out +++ b/vlib/v/checker/tests/unknown_sizeof_type_err_a.out @@ -1,6 +1,6 @@ vlib/v/checker/tests/unknown_sizeof_type_err_a.vv:14:34: cgen error: unknown type `T` - 12 | println("size of Abc: ${sizeof(Abc)}") - 13 | println("size of Xyz: ${sizeof(Xyz)}") - 14 | println("size of Test: ${sizeof(T)}") - | ^ + 12 | println('size of Abc: ${sizeof[Abc]()}') + 13 | println('size of Xyz: ${sizeof[Xyz]()}') + 14 | println('size of Test: ${sizeof[T]()}') + | ~~ 15 | } diff --git a/vlib/v/checker/tests/unknown_sizeof_type_err_a.vv b/vlib/v/checker/tests/unknown_sizeof_type_err_a.vv index dd15843501..a66db113ca 100644 --- a/vlib/v/checker/tests/unknown_sizeof_type_err_a.vv +++ b/vlib/v/checker/tests/unknown_sizeof_type_err_a.vv @@ -9,7 +9,7 @@ struct Xyz { type Test = Abc | Xyz fn main() { - println("size of Abc: ${sizeof(Abc)}") - println("size of Xyz: ${sizeof(Xyz)}") - println("size of Test: ${sizeof(T)}") + println('size of Abc: ${sizeof[Abc]()}') + println('size of Xyz: ${sizeof[Xyz]()}') + println('size of Test: ${sizeof[T]()}') } diff --git a/vlib/v/checker/tests/unknown_sizeof_type_err_b.out b/vlib/v/checker/tests/unknown_sizeof_type_err_b.out index 7daa009254..f6c51c4444 100644 --- a/vlib/v/checker/tests/unknown_sizeof_type_err_b.out +++ b/vlib/v/checker/tests/unknown_sizeof_type_err_b.out @@ -1,6 +1,6 @@ vlib/v/checker/tests/unknown_sizeof_type_err_b.vv:14:34: cgen error: unknown type `Zabc` - 12 | println("size of Abc: ${sizeof(Abc)}") - 13 | println("size of Xyz: ${sizeof(Xyz)}") - 14 | println("size of Test: ${sizeof(Zabc)}") - | ~~~~ + 12 | println('size of Abc: ${sizeof[Abc]()}') + 13 | println('size of Xyz: ${sizeof[Xyz]()}') + 14 | println('size of Test: ${sizeof[Zabc]()}') + | ~~~~~ 15 | } diff --git a/vlib/v/checker/tests/unknown_sizeof_type_err_b.vv b/vlib/v/checker/tests/unknown_sizeof_type_err_b.vv index 154f406b06..49a6622c53 100644 --- a/vlib/v/checker/tests/unknown_sizeof_type_err_b.vv +++ b/vlib/v/checker/tests/unknown_sizeof_type_err_b.vv @@ -9,7 +9,7 @@ struct Xyz { type Test = Abc | Xyz fn main() { - println("size of Abc: ${sizeof(Abc)}") - println("size of Xyz: ${sizeof(Xyz)}") - println("size of Test: ${sizeof(Zabc)}") + println('size of Abc: ${sizeof[Abc]()}') + println('size of Xyz: ${sizeof[Xyz]()}') + println('size of Test: ${sizeof[Zabc]()}') } diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index c628550214..eca38a7611 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -2572,23 +2572,43 @@ pub fn (mut f Fmt) selector_expr(node ast.SelectorExpr) { } pub fn (mut f Fmt) size_of(node ast.SizeOf) { - f.write('sizeof(') + f.write('sizeof') if node.is_type { + // keep the old form for now + f.write('(') f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias)) - } else { - f.expr(node.expr) + f.write(')') + return + } + if node.is_type { + f.write('[') + f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias)) + f.write(']()') + } else { + f.write('(') + f.expr(node.expr) + f.write(')') } - f.write(')') } pub fn (mut f Fmt) is_ref_type(node ast.IsRefType) { - f.write('isreftype(') + f.write('isreftype') if node.is_type { + // keep the old form for now + f.write('(') f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias)) - } else { - f.expr(node.expr) + f.write(')') + return + } + if node.is_type { + f.write('[') + f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias)) + f.write(']()') + } else { + f.write('(') + f.expr(node.expr) + f.write(')') } - f.write(')') } pub fn (mut f Fmt) sql_expr(node ast.SqlExpr) { diff --git a/vlib/v/parser/expr.v b/vlib/v/parser/expr.v index ac19d7a4a5..05533e1520 100644 --- a/vlib/v/parser/expr.v +++ b/vlib/v/parser/expr.v @@ -236,57 +236,85 @@ pub fn (mut p Parser) check_expr(precedence int) !ast.Expr { .key_sizeof, .key_isreftype { is_reftype := p.tok.kind == .key_isreftype p.next() // sizeof - p.check(.lpar) - pos := p.tok.pos() - mut is_known_var := p.mark_var_as_used(p.tok.lit) - || p.table.global_scope.known_const(p.mod + '.' + p.tok.lit) - //|| p.table.known_fn(p.mod + '.' + p.tok.lit) - // assume `mod.` prefix leads to a type - mut is_type := p.known_import(p.tok.lit) || p.tok.kind.is_start_of_type() - || (p.tok.lit.len > 0 && p.tok.lit[0].is_capital()) - if p.tok.lit in ['c', 'r'] && p.peek_tok.kind == .string { - is_known_var = false - is_type = false - } - if is_known_var || !is_type { - expr := p.expr(0) + if p.tok.kind == .lsbr { + // parse sizeof[T]() and isreftype[T]() without guessing: + p.check(.lsbr) + mut type_pos := p.tok.pos() + typ := p.parse_type() + type_pos = type_pos.extend(p.tok.pos()) + p.check(.rsbr) + p.check(.lpar) + p.check(.rpar) if is_reftype { node = ast.IsRefType{ - is_type: false - expr: expr - pos: pos + is_type: true + typ: typ + pos: type_pos } } else { node = ast.SizeOf{ - is_type: false - expr: expr - pos: pos + is_type: true + typ: typ + pos: type_pos } } } else { - if p.tok.kind == .name { - p.register_used_import(p.tok.lit) + p.check(.lpar) + pos := p.tok.pos() + mut is_known_var := p.mark_var_as_used(p.tok.lit) + || p.table.global_scope.known_const(p.mod + '.' + p.tok.lit) + //|| p.table.known_fn(p.mod + '.' + p.tok.lit) + // assume `mod.` prefix leads to a type + mut is_type := p.known_import(p.tok.lit) + || p.tok.kind.is_start_of_type() + || (p.tok.lit.len > 0 && p.tok.lit[0].is_capital()) + + if p.tok.lit in ['c', 'r'] && p.peek_tok.kind == .string { + is_known_var = false + is_type = false } - save_expr_mod := p.expr_mod - p.expr_mod = '' - arg_type := p.parse_type() - p.expr_mod = save_expr_mod - if is_reftype { - node = ast.IsRefType{ - is_type: true - typ: arg_type - pos: pos + if is_known_var || !is_type { + expr := p.expr(0) + if is_reftype { + node = ast.IsRefType{ + is_type: false + expr: expr + pos: pos + } + } else { + node = ast.SizeOf{ + is_type: false + expr: expr + pos: pos + } } } else { - node = ast.SizeOf{ - is_type: true - typ: arg_type - pos: pos + if p.tok.kind == .name { + p.register_used_import(p.tok.lit) + } + save_expr_mod := p.expr_mod + p.expr_mod = '' + arg_type := p.parse_type() + p.expr_mod = save_expr_mod + if is_reftype { + node = ast.IsRefType{ + guessed_type: true + is_type: true + typ: arg_type + pos: pos + } + } else { + node = ast.SizeOf{ + guessed_type: true + is_type: true + typ: arg_type + pos: pos + } } } + p.check(.rpar) } - p.check(.rpar) } .key_dump { spos := p.tok.pos()