From 2ac39d9112fdd8011682b742201996ce9091a620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Sun, 13 Jun 2021 05:26:13 +0200 Subject: [PATCH] all: new function `isreftype(T)` to know if `T` contains pointers (#10438) --- cmd/tools/vast/vast.v | 13 ++++++++ vlib/v/ast/ast.v | 25 ++++++++++----- vlib/v/checker/checker.v | 6 ++++ vlib/v/fmt/fmt.v | 13 ++++++++ vlib/v/gen/c/cgen.v | 9 ++++++ vlib/v/gen/js/js.v | 2 +- vlib/v/markused/walker.v | 2 +- vlib/v/parser/pratt.v | 37 ++++++++++++++++------ vlib/v/tests/isreftype_test.v | 58 +++++++++++++++++++++++++++++++++++ vlib/v/token/token.v | 2 ++ 10 files changed, 147 insertions(+), 20 deletions(-) create mode 100644 vlib/v/tests/isreftype_test.v diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index 7826262c6b..a1535812f2 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -979,6 +979,9 @@ fn (t Tree) expr(expr ast.Expr) &Node { ast.SizeOf { return t.size_of(expr) } + ast.IsRefType { + return t.is_ref_type(expr) + } ast.PrefixExpr { return t.prefix_expr(expr) } @@ -1225,6 +1228,16 @@ fn (t Tree) size_of(node ast.SizeOf) &Node { return obj } +fn (t Tree) is_ref_type(node ast.IsRefType) &Node { + mut obj := new_object() + obj.add('ast_type', t.string_node('IsRefType')) + obj.add('is_type', t.bool_node(node.is_type)) + obj.add('typ', t.type_node(node.typ)) + obj.add('expr', t.expr(node.expr)) + obj.add('pos', t.position(node.pos)) + return obj +} + fn (t Tree) prefix_expr(node ast.PrefixExpr) &Node { mut obj := new_object() obj.add('ast_type', t.string_node('PrefixExpr')) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index a9cb23136c..88b3b821af 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -12,10 +12,10 @@ pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral | CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ComptimeSelector | ConcatExpr | DumpExpr | EmptyExpr | EnumVal | FloatLiteral | GoExpr | - Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | - MapInit | MatchExpr | NodeError | None | OffsetOf | OrExpr | ParExpr | PostfixExpr | - PrefixExpr | RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | - StringLiteral | StructInit | TypeNode | TypeOf | UnsafeExpr + Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | IsRefType | + Likely | LockExpr | MapInit | MatchExpr | NodeError | None | OffsetOf | OrExpr | ParExpr | + PostfixExpr | PrefixExpr | RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | + StringInterLiteral | StringLiteral | StructInit | TypeNode | TypeOf | UnsafeExpr pub type Stmt = AsmStmt | AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | DeferStmt | EmptyStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | @@ -1338,6 +1338,15 @@ pub mut: typ Type } +pub struct IsRefType { +pub: + is_type bool + expr Expr // checker uses this to set typ + pos token.Position +pub mut: + typ Type +} + pub struct OffsetOf { pub: struct_type Type @@ -1516,10 +1525,10 @@ pub fn (expr Expr) position() token.Position { } NodeError, ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, ChanInit, CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector, - EnumVal, DumpExpr, FloatLiteral, GoExpr, Ident, IfExpr, IntegerLiteral, Likely, LockExpr, - MapInit, MatchExpr, None, OffsetOf, OrExpr, ParExpr, PostfixExpr, PrefixExpr, RangeExpr, - SelectExpr, SelectorExpr, SizeOf, SqlExpr, StringInterLiteral, StringLiteral, StructInit, - TypeNode, TypeOf, UnsafeExpr { + EnumVal, DumpExpr, FloatLiteral, GoExpr, Ident, IfExpr, IntegerLiteral, IsRefType, Likely, + LockExpr, MapInit, MatchExpr, None, OffsetOf, OrExpr, ParExpr, PostfixExpr, PrefixExpr, + RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr, StringInterLiteral, StringLiteral, + StructInit, TypeNode, TypeOf, UnsafeExpr { return expr.pos } IndexExpr { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index d2b46412c7..db52b7d05c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -4833,6 +4833,12 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type { } return ast.u32_type } + ast.IsRefType { + if !node.is_type { + node.typ = c.expr(node.expr) + } + return ast.bool_type + } ast.OffsetOf { return c.offset_of(node) } diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index dc1063989e..ef148c8bce 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -601,6 +601,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) { ast.SizeOf { f.size_of(node) } + ast.IsRefType { + f.is_ref_type(node) + } ast.SqlExpr { f.sql_expr(node) } @@ -2321,6 +2324,16 @@ pub fn (mut f Fmt) size_of(node ast.SizeOf) { f.write(')') } +pub fn (mut f Fmt) is_ref_type(node ast.IsRefType) { + f.write('isreftype(') + if node.is_type { + f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias)) + } else { + f.expr(node.expr) + } + f.write(')') +} + pub fn (mut f Fmt) sql_expr(node ast.SqlExpr) { // sql app.db { select from Contributor where repo == id && user == 0 } f.write('sql ') diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 0c8854fbd7..fc04e0e0d2 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3303,6 +3303,15 @@ fn (mut g Gen) expr(node ast.Expr) { styp := g.typ(node_typ) g.write('/*SizeOf*/ sizeof(${util.no_dots(styp)})') } + ast.IsRefType { + node_typ := g.unwrap_generic(node.typ) + sym := g.table.get_type_symbol(node_typ) + if sym.language == .v && sym.kind in [.placeholder, .any] { + g.error('unknown type `$sym.name`', node.pos) + } + is_ref_type := g.contains_ptr(node_typ) + g.write('/*IsRefType*/ $is_ref_type') + } ast.OffsetOf { styp := g.typ(node.struct_type) g.write('/*OffsetOf*/ (u32)(__offsetof(${util.no_dots(styp)}, $node.field))') diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 1f72e2d35e..fefe9da739 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -637,7 +637,7 @@ fn (mut g JsGen) expr(node ast.Expr) { ast.SelectorExpr { g.gen_selector_expr(node) } - ast.SizeOf { + ast.SizeOf, ast.IsRefType { // TODO } ast.OffsetOf { diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index d78de8a790..65ae2ca118 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -298,7 +298,7 @@ fn (mut w Walker) expr(node ast.Expr) { w.expr(node.high) } } - ast.SizeOf { + ast.SizeOf, ast.IsRefType { w.expr(node.expr) } ast.StringInterLiteral { diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index a97089e285..9acf319bf0 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -190,7 +190,8 @@ pub fn (mut p Parser) check_expr(precedence int) ?ast.Expr { pos: pos } } - .key_sizeof { + .key_sizeof, .key_isreftype { + is_reftype := p.tok.kind == .key_isreftype p.next() // sizeof p.check(.lpar) pos := p.tok.position() @@ -198,10 +199,18 @@ pub fn (mut p Parser) check_expr(precedence int) ?ast.Expr { // assume mod. prefix leads to a type if is_known_var || !(p.known_import(p.tok.lit) || p.tok.kind.is_start_of_type()) { expr := p.expr(0) - node = ast.SizeOf{ - is_type: false - expr: expr - pos: pos + 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 { if p.tok.kind == .name { @@ -209,12 +218,20 @@ pub fn (mut p Parser) check_expr(precedence int) ?ast.Expr { } save_expr_mod := p.expr_mod p.expr_mod = '' - sizeof_type := p.parse_type() + arg_type := p.parse_type() p.expr_mod = save_expr_mod - node = ast.SizeOf{ - is_type: true - typ: sizeof_type - pos: pos + if is_reftype { + node = ast.IsRefType{ + is_type: true + typ: arg_type + pos: pos + } + } else { + node = ast.SizeOf{ + is_type: true + typ: arg_type + pos: pos + } } } p.check(.rpar) diff --git a/vlib/v/tests/isreftype_test.v b/vlib/v/tests/isreftype_test.v new file mode 100644 index 0000000000..d097138b07 --- /dev/null +++ b/vlib/v/tests/isreftype_test.v @@ -0,0 +1,58 @@ +struct S1 { + p voidptr +} + +struct S2 { + i int +} + +struct S3 { + x &S2 + y int +} + +struct S4 { + x S2 +mut: + y f64 +} + +struct S5 { + S3 + a f32 +} + +fn test_isreftype() { + assert isreftype(S1) == true + assert isreftype(S2) == false + assert isreftype(S3) == true + assert isreftype(S4) == false + assert isreftype(S5) == true + assert isreftype(f64) == false + assert isreftype([]f64) == true + assert isreftype([3]int) == false +} + +fn check_ref() string { + if isreftype(T) { + return 'ref' + } else { + return 'no ref' + } +} + +fn test_generic_ref() { + assert check_ref() == 'no ref' + assert check_ref() == 'ref' +} + +fn test_expression_ref() { + mut a := S3{ + x: &S2{} + } + b := S4{} + c := 32.5 * 6 + assert isreftype(a) == true + assert isreftype(b) == false + assert isreftype(c) == false +} diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index 727e39e4ff..119dcf01fa 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -111,6 +111,7 @@ pub enum Kind { key_return key_select key_sizeof + key_isreftype key_likely key_unlikely key_offsetof @@ -267,6 +268,7 @@ fn build_token_str() []string { s[Kind.key_return] = 'return' s[Kind.key_module] = 'module' s[Kind.key_sizeof] = 'sizeof' + s[Kind.key_isreftype] = 'isreftype' s[Kind.key_likely] = '_likely_' s[Kind.key_unlikely] = '_unlikely_' s[Kind.key_go] = 'go'