1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: ban unsafe pointer/fn comparison (#14462)

This commit is contained in:
Vincenzo Palazzo 2022-05-20 17:30:16 +02:00 committed by GitHub
parent d81fbb1ccd
commit 17bba712bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 111 additions and 68 deletions

View File

@ -207,7 +207,7 @@ fn change_detection_loop(ocontext &Context) {
}
fn (mut context Context) kill_pgroup() {
if context.child_process == 0 {
if unsafe { context.child_process == 0 } {
return
}
if context.child_process.is_alive() {

View File

@ -95,7 +95,7 @@ pub fn (mut s System) explode(x f32, y f32) {
pub fn (mut s System) free() {
for p in s.pool {
if p == 0 {
if unsafe { p == 0 } {
print(ptr_str(p) + ' ouch')
continue
}
@ -103,7 +103,7 @@ pub fn (mut s System) free() {
}
s.pool.clear()
for p in s.bin {
if p == 0 {
if unsafe { p == 0 } {
print(ptr_str(p) + ' ouch')
continue
}

View File

@ -32,9 +32,10 @@ mut:
[unsafe]
fn vmemory_block_new(prev &VMemoryBlock, at_least isize) &VMemoryBlock {
mut v := unsafe { &VMemoryBlock(C.calloc(1, sizeof(VMemoryBlock))) }
if prev != 0 {
if unsafe { prev != 0 } {
v.id = prev.id + 1
}
v.previous = prev
block_size := if at_least < prealloc_block_size { prealloc_block_size } else { at_least }
v.start = unsafe { C.malloc(block_size) }
@ -79,7 +80,7 @@ fn prealloc_vcleanup() {
// The second loop however should *not* allocate at all.
mut nr_mallocs := i64(0)
mut mb := g_memory_block
for mb != 0 {
for unsafe { mb != 0 } {
nr_mallocs += mb.mallocs
eprintln('> freeing mb.id: ${mb.id:3} | cap: ${mb.cap:7} | rem: ${mb.remaining:7} | start: ${voidptr(mb.start)} | current: ${voidptr(mb.current)} | diff: ${u64(mb.current) - u64(mb.start):7} bytes | mallocs: $mb.mallocs')
mb = mb.previous

View File

@ -53,7 +53,7 @@ pub fn (cmd Command) str() string {
res << ' cb execute: $cmd.execute'
res << ' cb pre_execute: $cmd.pre_execute'
res << ' cb post_execute: $cmd.post_execute'
if cmd.parent == 0 {
if unsafe { cmd.parent == 0 } {
res << ' parent: &Command(0)'
} else {
res << ' parent: &Command{$cmd.parent.name ...}'

View File

@ -49,7 +49,7 @@ pub fn print_help_for_command(help_cmd Command) ? {
}
print(cmd.help_message())
} else {
if help_cmd.parent != 0 {
if unsafe { help_cmd.parent != 0 } {
print(help_cmd.parent.help_message())
}
}

View File

@ -41,7 +41,7 @@ pub fn print_manpage_for_command(man_cmd Command) ? {
}
print(cmd.manpage())
} else {
if man_cmd.parent != 0 {
if unsafe { man_cmd.parent != 0 } {
print(man_cmd.parent.manpage())
}
}
@ -55,7 +55,7 @@ pub fn (cmd Command) manpage() string {
mdoc += '.Os\n.Sh NAME\n.Nm ${cmd.full_name().replace(' ', '-')}\n.Nd $cmd.description\n'
mdoc += '.Sh SYNOPSIS\n'
mdoc += '.Nm $cmd.root().name\n'
if cmd.parent != 0 {
if unsafe { cmd.parent != 0 } {
mut parents := []Command{}
if !cmd.parent.is_root() {
parents.prepend(cmd.parent)
@ -96,7 +96,7 @@ pub fn (cmd Command) manpage() string {
}
if cmd.commands.len > 0 {
mdoc += '.Nm $cmd.root().name\n'
if cmd.parent != 0 {
if unsafe { cmd.parent != 0 } {
mut parents := []Command{}
if !cmd.parent.is_root() {
parents.prepend(cmd.parent)
@ -158,7 +158,7 @@ pub fn (cmd Command) manpage() string {
if cmd.commands.len > 0 {
mdoc += '.Sh SEE ALSO\n'
mut cmds := []string{}
if cmd.parent != 0 {
if unsafe { cmd.parent != 0 } {
cmds << cmd.parent.full_name().replace(' ', '-')
}
for c in cmd.commands {

View File

@ -76,13 +76,13 @@ pub fn (mut bst BSTree<T>) insert(value T) bool {
// insert_helper walks the tree and inserts the given node.
fn (mut bst BSTree<T>) insert_helper(mut node BSTreeNode<T>, value T) bool {
if node.value < value {
if node.right != 0 && node.right.is_init {
if unsafe { node.right != 0 } && node.right.is_init {
return bst.insert_helper(mut node.right, value)
}
node.right = new_node(node, value)
return true
} else if node.value > value {
if node.left != 0 && node.left.is_init {
if unsafe { node.left != 0 } && node.left.is_init {
return bst.insert_helper(mut node.left, value)
}
node.left = new_node(node, value)
@ -99,7 +99,7 @@ pub fn (bst &BSTree<T>) contains(value T) bool {
// contains_helper is a helper function to walk the tree, and return
// the absence or presence of the `value`.
fn (bst &BSTree<T>) contains_helper(node &BSTreeNode<T>, value T) bool {
if node == 0 || !node.is_init {
if unsafe { node == 0 } || !node.is_init {
return false
}
if node.value < value {
@ -124,12 +124,12 @@ fn (mut bst BSTree<T>) remove_helper(mut node BSTreeNode<T>, value T, left bool)
return false
}
if node.value == value {
if node.left != 0 && node.left.is_init {
if unsafe { node.left != 0 } && node.left.is_init {
// In order to remove the element we need to bring up as parent the max of the
// left sub-tree.
mut max_node := bst.get_max_from_right(node.left)
node.bind(mut max_node, true)
} else if node.right != 0 && node.right.is_init {
} else if unsafe { node.right != 0 } && node.right.is_init {
// Bring up the element with the minimum value in the right sub-tree.
mut min_node := bst.get_min_from_left(node.right)
node.bind(mut min_node, false)
@ -153,11 +153,11 @@ fn (mut bst BSTree<T>) remove_helper(mut node BSTreeNode<T>, value T, left bool)
// get_max_from_right returns the max element of the BST following the right branch.
fn (bst &BSTree<T>) get_max_from_right(node &BSTreeNode<T>) &BSTreeNode<T> {
if node == 0 {
if unsafe { node == 0 } {
return new_none_node<T>(false)
}
right_node := node.right
if right_node == 0 || !right_node.is_init {
if unsafe { right_node == 0 } || !right_node.is_init {
return node
}
return bst.get_max_from_right(right_node)
@ -165,11 +165,11 @@ fn (bst &BSTree<T>) get_max_from_right(node &BSTreeNode<T>) &BSTreeNode<T> {
// get_min_from_left returns the min element of the BST by following the left branch.
fn (bst &BSTree<T>) get_min_from_left(node &BSTreeNode<T>) &BSTreeNode<T> {
if node == 0 {
if unsafe { node == 0 } {
return new_none_node<T>(false)
}
left_node := node.left
if left_node == 0 || !left_node.is_init {
if unsafe { left_node == 0 } || !left_node.is_init {
return node
}
return bst.get_min_from_left(left_node)
@ -177,7 +177,7 @@ fn (bst &BSTree<T>) get_min_from_left(node &BSTreeNode<T>) &BSTreeNode<T> {
// is_empty checks if the BST is empty
pub fn (bst &BSTree<T>) is_empty() bool {
return bst.root == 0
return unsafe { bst.root == 0 }
}
// in_order_traversal traverses the BST in order, and returns the result as an array.
@ -189,7 +189,7 @@ pub fn (bst &BSTree<T>) in_order_traversal() []T {
// in_order_traversal_helper helps traverse the BST, and accumulates the result in the `result` array.
fn (bst &BSTree<T>) in_order_traversal_helper(node &BSTreeNode<T>, mut result []T) {
if node == 0 || !node.is_init {
if unsafe { node == 0 } || !node.is_init {
return
}
bst.in_order_traversal_helper(node.left, mut result)
@ -207,7 +207,7 @@ pub fn (bst &BSTree<T>) post_order_traversal() []T {
// post_order_traversal_helper is a helper function that traverses the BST in post order,
// accumulating the result in an array.
fn (bst &BSTree<T>) post_order_traversal_helper(node &BSTreeNode<T>, mut result []T) {
if node == 0 || !node.is_init {
if unsafe { node == 0 } || !node.is_init {
return
}
@ -226,7 +226,7 @@ pub fn (bst &BSTree<T>) pre_order_traversal() []T {
// pre_order_traversal_helper is a helper function to traverse the BST
// in pre order and accumulates the results in an array.
fn (bst &BSTree<T>) pre_order_traversal_helper(node &BSTreeNode<T>, mut result []T) {
if node == 0 || !node.is_init {
if unsafe { node == 0 } || !node.is_init {
return
}
result << node.value
@ -236,7 +236,7 @@ fn (bst &BSTree<T>) pre_order_traversal_helper(node &BSTreeNode<T>, mut result [
// get_node is a helper method to ge the internal rapresentation of the node with the `value`.
fn (bst &BSTree<T>) get_node(node &BSTreeNode<T>, value T) &BSTreeNode<T> {
if node == 0 || !node.is_init {
if unsafe { node == 0 } || !node.is_init {
return new_none_node<T>(false)
}
if node.value == value {

View File

@ -251,7 +251,7 @@ pub fn (mut list DoublyLinkedList<T>) delete(idx int) {
pub fn (list DoublyLinkedList<T>) str() string {
mut result_array := []T{}
mut node := list.head
for node != 0 {
for unsafe { node != 0 } {
result_array << node.data
node = node.next
}

View File

@ -29,11 +29,11 @@ pub fn (list LinkedList<T>) first() ?T {
// last returns the last element of the linked list
pub fn (list LinkedList<T>) last() ?T {
if list.head == 0 {
if unsafe { list.head == 0 } {
return error('Linked list is empty')
} else {
mut node := list.head
for node.next != 0 {
for unsafe { node.next != 0 } {
node = node.next
}
return node.data
@ -42,12 +42,12 @@ pub fn (list LinkedList<T>) last() ?T {
// index returns the element at the given index of the linked list
pub fn (list LinkedList<T>) index(idx int) ?T {
if list.head == 0 {
if unsafe { list.head == 0 } {
return error('Linked list is empty')
} else {
mut node := list.head
mut iterations := 0
for node.next != 0 && iterations < idx {
for unsafe { node.next != 0 } && iterations < idx {
node = node.next
iterations++
}
@ -64,12 +64,12 @@ pub fn (mut list LinkedList<T>) push(item T) {
new_node := &ListNode<T>{
data: item
}
if list.head == 0 {
if unsafe { list.head == 0 } {
// first node case
list.head = new_node
} else {
mut node := list.head
for node.next != 0 {
for unsafe { node.next != 0 } {
node = node.next
}
node.next = new_node
@ -79,17 +79,17 @@ pub fn (mut list LinkedList<T>) push(item T) {
// pop removes the last element of the linked list
pub fn (mut list LinkedList<T>) pop() ?T {
if list.head == 0 {
if unsafe { list.head == 0 } {
return error('Linked list is empty')
}
mut node := list.head
mut to_return := node.data
if node.next == 0 {
if unsafe { node.next == 0 } {
// first node case
// set to null
list.head = voidptr(0)
} else {
for node.next.next != 0 {
for unsafe { node.next.next != 0 } {
node = node.next
}
to_return = node.next.data
@ -102,7 +102,7 @@ pub fn (mut list LinkedList<T>) pop() ?T {
// shift removes the first element of the linked list
pub fn (mut list LinkedList<T>) shift() ?T {
if list.head == 0 {
if unsafe { list.head == 0 } {
return error('Linked list is empty')
} else {
list.len -= 1
@ -149,7 +149,7 @@ pub fn (mut list LinkedList<T>) prepend(item T) {
pub fn (list LinkedList<T>) str() string {
mut result_array := []T{}
mut node := list.head
for node != 0 {
for unsafe { node != 0 } {
result_array << node.data
node = node.next
}

View File

@ -32,7 +32,7 @@ fn test_access_parent() {
mut dom := parse(generate_temp_html())
div_tags := dom.get_tag('div')
parent := div_tags[0].parent
assert parent != 0
assert unsafe { parent != 0 }
for div_tag in div_tags {
assert div_tag.parent == parent
}

View File

@ -176,7 +176,7 @@ fn (mut p Process) win_write_string(idx int, s string) {
fn (mut p Process) win_read_string(idx int, maxbytes int) (string, int) {
mut wdata := &WProcess(p.wdata)
if wdata == 0 {
if unsafe { wdata == 0 } {
return '', 0
}
mut rhandle := &u32(0)
@ -207,7 +207,7 @@ fn (mut p Process) win_read_string(idx int, maxbytes int) (string, int) {
fn (mut p Process) win_slurp(idx int) string {
mut wdata := &WProcess(p.wdata)
if wdata == 0 {
if unsafe { wdata == 0 } {
return ''
}
mut rhandle := &u32(0)

View File

@ -645,7 +645,7 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
unsafe {
*subscr[i].prev = subscr[i].nxt
}
if subscr[i].nxt != 0 {
if unsafe { subscr[i].nxt != 0 } {
subscr[i].nxt.prev = subscr[i].prev
// just in case we have missed a semaphore during restore
subscr[i].nxt.sem.post()
@ -659,7 +659,7 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
unsafe {
*subscr[i].prev = subscr[i].nxt
}
if subscr[i].nxt != 0 {
if unsafe { subscr[i].nxt != 0 } {
subscr[i].nxt.prev = subscr[i].prev
subscr[i].nxt.sem.post()
}

View File

@ -21,7 +21,7 @@ mut:
}
fn restore_terminal_state() {
if ui.ctx_ptr != 0 {
if unsafe { ui.ctx_ptr != 0 } {
if ui.ctx_ptr.cfg.use_alternate_buffer {
// clear the terminal and set the cursor to the origin
print('\x1b[2J\x1b[3J')
@ -84,7 +84,7 @@ pub fn init(cfg Config) &Context {
for code in ctx.cfg.reset {
os.signal_opt(code, fn (_ os.Signal) {
mut c := ui.ctx_ptr
if c != 0 {
if unsafe { c != 0 } {
c.cleanup()
}
exit(0)

View File

@ -44,7 +44,7 @@ fn restore_terminal_state_signal(_ os.Signal) {
fn restore_terminal_state() {
termios_reset()
mut c := ctx_ptr
if c != 0 {
if unsafe { c != 0 } {
c.paused = true
load_title()
}
@ -121,7 +121,7 @@ fn (mut ctx Context) termios_setup() ? {
os.signal_opt(.tstp, restore_terminal_state_signal) or {}
os.signal_opt(.cont, fn (_ os.Signal) {
mut c := ctx_ptr
if c != 0 {
if unsafe { c != 0 } {
c.termios_setup() or { panic(err) }
c.window_height, c.window_width = get_terminal_size()
mut event := &Event{
@ -136,7 +136,7 @@ fn (mut ctx Context) termios_setup() ? {
for code in ctx.cfg.reset {
os.signal_opt(code, fn (_ os.Signal) {
mut c := ctx_ptr
if c != 0 {
if unsafe { c != 0 } {
c.cleanup()
}
exit(0)
@ -145,7 +145,7 @@ fn (mut ctx Context) termios_setup() ? {
os.signal_opt(.winch, fn (_ os.Signal) {
mut c := ctx_ptr
if c != 0 {
if unsafe { c != 0 } {
c.window_height, c.window_width = get_terminal_size()
mut event := &Event{
@ -200,7 +200,7 @@ fn termios_reset() {
C.tcsetattr(C.STDIN_FILENO, C.TCSAFLUSH, &ui.termios_at_startup)
print('\x1b[?1003l\x1b[?1006l\x1b[?25h')
c := ctx_ptr
if c != 0 && c.cfg.use_alternate_buffer {
if unsafe { c != 0 } && c.cfg.use_alternate_buffer {
print('\x1b[?1049l')
}
os.flush()
@ -267,7 +267,7 @@ fn (mut ctx Context) parse_events() {
ctx.shift(1)
}
}
if event != 0 {
if unsafe { event != 0 } {
ctx.event(event)
nr_iters = 0
}

View File

@ -547,6 +547,15 @@ pub fn (t &Table) type_kind(typ Type) Kind {
return t.sym(typ).kind
}
pub fn (t &Table) type_is_for_pointer_arithmetic(typ Type) bool {
typ_sym := t.sym(typ)
if typ_sym.kind == .struct_ {
return false
} else {
return typ.is_any_kind_of_pointer() || typ.is_int_valptr()
}
}
pub enum Kind {
placeholder
void

View File

@ -592,6 +592,13 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
}
c.error('infix expr: cannot use `$right_sym.name` (right expression) as `$left_sym.name`',
left_right_pos)
} else if left_type.is_ptr() {
for_ptr_op := c.table.type_is_for_pointer_arithmetic(left_type)
if left_sym.language == .v && !c.inside_unsafe && !for_ptr_op && right_type.is_int() {
sugg := ' (you can use it inside an `unsafe` block)'
c.error('infix expr: cannot use `$right_sym.name` (right expression) as `$left_sym.name` $sugg',
left_right_pos)
}
}
/*
if (node.left is ast.InfixExpr &&

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/checker_comparison_between_obj_and_int.vv:10:5: error: infix expr: cannot use `int literal` (right expression) as `Foo` (you can use it inside an `unsafe` block)
8 |
9 | fn insert_helper(mut node Foo) {
10 | if node == 0 {
| ~~~~~~~~~
11 | }
12 | }

View File

@ -0,0 +1,14 @@
struct Foo {}
// inside a unsafe block it is valid
fn insert_helper_unsafe(mut node Foo) {
if unsafe { node == 0 } {
}
}
fn insert_helper(mut node Foo) {
if node == 0 {
}
}
fn main() {}

View File

@ -288,7 +288,7 @@ fn (mut g Gen) comptime_if(node ast.IfExpr) {
}
} else {
// Only wrap the contents in {} if we're inside a function, not on the top level scope
should_create_scope := g.fn_decl != 0
should_create_scope := unsafe { g.fn_decl != 0 }
if should_create_scope {
g.writeln('{')
}

View File

@ -717,7 +717,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
g.checker_bug('CallExpr.receiver_type is 0 in method_call', node.pos)
}
mut unwrapped_rec_type := node.receiver_type
if g.cur_fn != 0 && g.cur_fn.generic_names.len > 0 { // in generic fn
if unsafe { g.cur_fn != 0 } && g.cur_fn.generic_names.len > 0 { // in generic fn
unwrapped_rec_type = g.unwrap_generic(node.receiver_type)
} else { // in non-generic fn
sym := g.table.sym(node.receiver_type)

View File

@ -18,7 +18,8 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
} else if sym.kind == .map {
g.index_of_map(node, sym)
} else if sym.kind == .string && !node.left_type.is_ptr() {
is_direct_array_access := (g.fn_decl != 0 && g.fn_decl.is_direct_arr) || node.is_direct
is_direct_array_access := (unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr)
|| node.is_direct
if is_direct_array_access {
g.expr(node.left)
g.write('.str[ ')
@ -174,7 +175,8 @@ fn (mut g Gen) index_of_array(node ast.IndexExpr, sym ast.TypeSymbol) {
// `vals[i].field = x` is an exception and requires `array_get`:
// `(*(Val*)array_get(vals, i)).field = x;`
if g.is_assign_lhs && node.is_setter {
is_direct_array_access := (g.fn_decl != 0 && g.fn_decl.is_direct_arr) || node.is_direct
is_direct_array_access := (unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr)
|| node.is_direct
is_op_assign := g.assign_op != .assign && info.elem_type != ast.string_type
if is_direct_array_access {
g.write('(($elem_type_str*)')
@ -233,7 +235,8 @@ fn (mut g Gen) index_of_array(node ast.IndexExpr, sym ast.TypeSymbol) {
}
}
} else {
is_direct_array_access := (g.fn_decl != 0 && g.fn_decl.is_direct_arr) || node.is_direct
is_direct_array_access := (unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr)
|| node.is_direct
// do not clone inside `opt_ok(opt_ok(&(string[]) {..})` before returns
needs_clone := info.elem_type == ast.string_type_idx && g.is_autofree && !(g.inside_return
&& g.fn_decl.return_type.has_flag(.optional)) && !g.is_assign_lhs
@ -335,7 +338,7 @@ fn (mut g Gen) index_of_fixed_array(node ast.IndexExpr, sym ast.TypeSymbol) {
g.expr(node.left)
}
g.write('[')
direct := g.fn_decl != 0 && g.fn_decl.is_direct_arr
direct := unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr
if (direct || node.index is ast.IntegerLiteral) || g.pref.translated {
g.expr(node.index)
} else {

View File

@ -91,7 +91,8 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
typ := g.table.final_sym(node.cond_type)
if node.is_sum_type {
g.match_expr_sumtype(node, is_expr, cond_var, tmp_var)
} else if typ.kind == .enum_ && g.loop_depth == 0 && node.branches.len > 5 && g.fn_decl != 0 { // do not optimize while in top-level
} else if typ.kind == .enum_ && g.loop_depth == 0 && node.branches.len > 5
&& unsafe { g.fn_decl != 0 } { // do not optimize while in top-level
g.match_expr_switch(node, is_expr, cond_var, tmp_var, typ)
} else {
g.match_expr_classic(node, is_expr, cond_var, tmp_var)

View File

@ -16,7 +16,7 @@ fn (mut g Gen) unwrap_generic(typ ast.Type) ast.Type {
non-mut to make sure no one else can accidentally mutates the table.
*/
mut muttable := unsafe { &ast.Table(g.table) }
if t_typ := muttable.resolve_generic_to_concrete(typ, if g.cur_fn != 0 {
if t_typ := muttable.resolve_generic_to_concrete(typ, if unsafe { g.cur_fn != 0 } {
g.cur_fn.generic_names
} else {
[]string{}

View File

@ -45,7 +45,7 @@ fn (mut g JsGen) js_mname(name_ string) string {
''
}
}
} else if g.ns == 0 {
} else if unsafe { g.ns == 0 } {
name
} else if ns == g.ns.name {
name.split('.').last()
@ -222,7 +222,7 @@ fn (mut g JsGen) method_call(node ast.CallExpr) {
g.get_str_fn(rec_type)
}
mut unwrapped_rec_type := node.receiver_type
if g.fn_decl != 0 && g.fn_decl.generic_names.len > 0 { // in generic fn
if unsafe { g.fn_decl != 0 } && g.fn_decl.generic_names.len > 0 { // in generic fn
unwrapped_rec_type = g.unwrap_generic(node.receiver_type)
} else { // in non-generic fn
sym := g.table.sym(node.receiver_type)

View File

@ -412,7 +412,7 @@ fn (g &JsGen) get_all_test_function_names() []string {
}
pub fn (mut g JsGen) enter_namespace(name string) {
if g.namespaces[name] == 0 {
if unsafe { g.namespaces[name] == 0 } {
// create a new namespace
ns := &Namespace{
name: name
@ -521,7 +521,7 @@ pub fn (mut g JsGen) dec_indent() {
[inline]
pub fn (mut g JsGen) write(s string) {
if g.ns == 0 {
if unsafe { g.ns == 0 } {
verror('g.write: not in a namespace')
}
g.gen_indent()
@ -530,7 +530,7 @@ pub fn (mut g JsGen) write(s string) {
[inline]
pub fn (mut g JsGen) writeln(s string) {
if g.ns == 0 {
if unsafe { g.ns == 0 } {
verror('g.writeln: not in a namespace')
}
g.gen_indent()
@ -2449,7 +2449,8 @@ fn (mut g JsGen) match_expr(node ast.MatchExpr) {
typ := g.table.final_sym(node.cond_type)
if node.is_sum_type {
g.match_expr_sumtype(node, is_expr, cond_var, tmp_var)
} else if typ.kind == .enum_ && !g.inside_loop && node.branches.len > 5 && g.fn_decl != 0 { // do not optimize while in top-level
} else if typ.kind == .enum_ && !g.inside_loop && node.branches.len > 5
&& unsafe { g.fn_decl != 0 } { // do not optimize while in top-level
g.match_expr_switch(node, is_expr, cond_var, tmp_var, typ)
} else {
g.match_expr_classic(node, is_expr, cond_var, tmp_var)
@ -3691,7 +3692,7 @@ fn (mut g JsGen) unwrap_generic(typ ast.Type) ast.Type {
non-mut to make sure no one else can accidentally mutates the table.
*/
mut muttable := unsafe { &ast.Table(g.table) }
if t_typ := muttable.resolve_generic_to_concrete(typ, if g.fn_decl != 0 {
if t_typ := muttable.resolve_generic_to_concrete(typ, if unsafe { g.fn_decl != 0 } {
g.fn_decl.generic_names
} else {
[]string{}

View File

@ -93,7 +93,7 @@ pub fn (mut m Main) run() ?string {
}
res += pcdep.description
}
if pc != 0 {
if unsafe { pc != 0 } {
pc.extend(pcdep)?
} else {
pc = pcdep

View File

@ -15,7 +15,7 @@ pub fn list_new<T>() List<T> {
pub fn (mut l List<T>) add(value T) {
mut node := &ListNode<T>{value, 0}
if l.head == 0 {
if unsafe { l.head == 0 } {
l.head = node
} else {
node.next = l.head

View File

@ -56,7 +56,7 @@ fn test_struct_pointer_casts_with_field_selectors() {
// &Struct cast and selecting .x
assert true
}
if &&Struct(pss) != 0 {
if unsafe { &&Struct(pss) != 0 } {
// &&Struct
assert true
}