all: new function `isreftype(T)` to know if `T` contains pointers (#10438)

pull/10444/head
Uwe Krüger 2021-06-13 05:26:13 +02:00 committed by GitHub
parent 4a59316600
commit 2ac39d9112
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 147 additions and 20 deletions

View File

@ -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'))

View File

@ -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 {

View File

@ -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)
}

View File

@ -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 ')

View File

@ -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))')

View File

@ -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 {

View File

@ -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 {

View File

@ -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)

View File

@ -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<T>() string {
if isreftype(T) {
return 'ref'
} else {
return 'no ref'
}
}
fn test_generic_ref() {
assert check_ref<f64>() == 'no ref'
assert check_ref<S3>() == '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
}

View File

@ -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'