@@ -104,6 +104,7 @@ mut:
104104 is_void_expr_stmt bool // ExprStmt whose result is discarded
105105 is_arraymap_set bool // map or array set value state
106106 is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&u8(unsafe { nil })` etc
107+ is_direct_amp_as_cast bool // direct `&(expr as Type)` operand; consumed by AsCast codegen
107108 is_sql bool // Inside `sql db{}` statement, generating sql instead of C (e.g. `and` instead of `&&` etc)
108109 is_shared bool // for initialization of hidden mutex in `[rw]shared` literals
109110 is_vlines_enabled bool // is it safe to generate #line directives when -g is passed
@@ -6518,12 +6519,24 @@ fn (mut g Gen) expr(node_ ast.Expr) {
65186519 // where the receiver is already a pointer in C), the `&` and the
65196520 // implicit dereference cancel out, so emit neither.
65206521 is_amp_auto_deref := node.op == .amp && node.right.is_auto_deref_var()
6522+ mut is_as_cast_ptr := false
65216523 if !g.is_option_auto_heap {
65226524 has_slice_call = node.op == .amp && node.right is ast.IndexExpr
65236525 && node.right.index is ast.RangeExpr
6526+ if node.op == .amp && tmp_var == '' {
6527+ mut right_expr := node.right
6528+ if right_expr is ast.ParExpr {
6529+ right_expr = right_expr.expr
6530+ }
6531+ if right_expr is ast.AsCast {
6532+ if g.as_cast_will_use_ptr(right_expr) {
6533+ is_as_cast_ptr = true
6534+ }
6535+ }
6536+ }
65246537 if has_slice_call {
65256538 g.write('ADDR(${g.styp(node.right_type)}, ')
6526- } else if !is_amp_auto_deref {
6539+ } else if !is_amp_auto_deref && !is_as_cast_ptr {
65276540 g.write(node.op.str())
65286541 }
65296542 }
@@ -6552,7 +6565,10 @@ fn (mut g Gen) expr(node_ ast.Expr) {
65526565 g.write('(')
65536566 }
65546567 if tmp_var == '' {
6568+ old_is_direct_amp_as_cast := g.is_direct_amp_as_cast
6569+ g.is_direct_amp_as_cast = is_as_cast_ptr
65556570 g.expr(node.right)
6571+ g.is_direct_amp_as_cast = old_is_direct_amp_as_cast
65566572 } else {
65576573 g.write(tmp_var)
65586574 }
@@ -12838,10 +12854,10 @@ fn (mut g Gen) as_cast_option_payload_expr_from_expr(typ ast.Type, expr ast.Expr
1283812854 return g.as_cast_option_payload_expr(typ, g.expr_string(expr), false)
1283912855}
1284012856
12841-fn (mut g Gen) write_as_cast_call_start(styp string, sym ast.TypeSymbol) {
12857+fn (mut g Gen) write_as_cast_call_start(styp string, sym ast.TypeSymbol, is_direct_amp bool) {
1284212858 if sym.info is ast.FnType {
1284312859 g.write('(${styp})')
12844- } else if g.inside_smartcast {
12860+ } else if g.inside_smartcast || is_direct_amp {
1284512861 g.write('(${styp}*)')
1284612862 } else {
1284712863 g.write('*(${styp}*)')
@@ -12909,7 +12925,27 @@ fn as_cast_operand_needs_tmp_eval(expr ast.Expr) bool {
1290912925 }
1291012926}
1291112927
12928+fn (mut g Gen) as_cast_will_use_ptr(node ast.AsCast) bool {
12929+ unwrapped_node_typ := g.unwrap_generic(node.typ)
12930+ unwrapped_expr_type := g.unwrap_generic(node.expr_type)
12931+ expr_type_without_option := unwrapped_expr_type.clear_flag(.option)
12932+ expr_type_sym := g.table.sym(unwrapped_expr_type)
12933+ if expr_type_sym.kind == .sum_type && expr_type_without_option == unwrapped_node_typ {
12934+ return false
12935+ }
12936+ if expr_type_sym.info is ast.SumType
12937+ || (expr_type_sym.info is ast.Interface && node.expr_type != node.typ) {
12938+ return true
12939+ }
12940+ return false
12941+}
12942+
1291212943fn (mut g Gen) as_cast(node ast.AsCast) {
12944+ is_direct_amp := g.is_direct_amp_as_cast
12945+ g.is_direct_amp_as_cast = false
12946+ defer {
12947+ g.is_direct_amp_as_cast = is_direct_amp
12948+ }
1291312949 // Make sure the sum type can be cast to this type (the types
1291412950 // are the same), otherwise panic.
1291512951 unwrapped_node_typ := g.unwrap_generic(node.typ)
@@ -12980,7 +13016,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
1298013016 }
1298113017 obj_expr := '(${expr_str})${dot}_${payload_sym.cname}'
1298213018 tag_expr := '(${expr_str})${dot}_typ'
12983- g.write_as_cast_call_start(styp, sym)
13019+ g.write_as_cast_call_start(styp, sym, is_direct_amp)
1298413020 g.write_as_cast_call(obj_expr, tag_expr, sidx, index_exprs)
1298513021 if !g.is_cc_msvc {
1298613022 g.write('; })')
@@ -12993,7 +13029,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
1299313029 }
1299413030 obj_expr := '(${expr_str})${dot}_${payload_sym.cname}'
1299513031 tag_expr := '(${expr_str})${dot}_typ'
12996- g.write_as_cast_call_start(styp, sym)
13032+ g.write_as_cast_call_start(styp, sym, is_direct_amp)
1299713033 g.write_as_cast_call(obj_expr, tag_expr, sidx, index_exprs)
1299813034 }
1299913035
@@ -13069,7 +13105,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
1306913105 }
1307013106 obj_expr := '${tmp_var}${dot}_${payload_sym.cname}'
1307113107 tag_expr := 'v_typeof_interface_idx_${expr_type_sym.cname}(${tmp_var}${dot}_typ)'
13072- g.write_as_cast_call_start(styp, sym)
13108+ g.write_as_cast_call_start(styp, sym, is_direct_amp)
1307313109 g.write_as_cast_call(obj_expr, tag_expr, sidx, index_exprs)
1307413110 if !g.is_cc_msvc {
1307513111 g.write('; })')
@@ -13078,7 +13114,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
1307813114 expr_str := g.expr_string(node.expr)
1307913115 obj_expr := '(${expr_str})${dot}_${payload_sym.cname}'
1308013116 tag_expr := 'v_typeof_interface_idx_${expr_type_sym.cname}((${expr_str})${dot}_typ)'
13081- g.write_as_cast_call_start(styp, sym)
13117+ g.write_as_cast_call_start(styp, sym, is_direct_amp)
1308213118 g.write_as_cast_call(obj_expr, tag_expr, sidx, index_exprs)
1308313119 }
1308413120
@@ -15,6 +15,8 @@ mut:
1515 val int
1616}
1717
18+type FooBarSum = Bar | Foo
19+
1820fn test_main() {
1921 mut fbs := []&FooBar{}
2022 fbs << &Foo{1}
@@ -22,6 +24,12 @@ fn test_main() {
2224 println(a)
2325 b := &(fbs.last() as Foo)
2426 println(b)
27+ fb := fbs[0]
28+ field_ptr := &((fb as Foo).val)
29+ assert *field_ptr == 1
30+ sum := FooBarSum(Foo{2})
31+ sum_field_ptr := &((sum as Foo).val)
32+ assert *sum_field_ptr == 2
2533 arr1 := [(fbs.last() as Foo)]
2634 arr2 := [&(fbs.last() as Foo)]
2735 arr3 := [&(get_foo_bar() as Foo)]