Skip to content

Commit

Permalink
checker, cgen: fix printing smartcast interface variable (fix #18886) (
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyi98 committed Sep 17, 2023
1 parent e6ba687 commit ec0d5dd
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 10 deletions.
9 changes: 7 additions & 2 deletions vlib/v/checker/checker.v
Expand Up @@ -119,7 +119,7 @@ mut:
need_recheck_generic_fns bool // need recheck generic fns because there are cascaded nested generic fn
inside_sql bool // to handle sql table fields pseudo variables
inside_selector_expr bool
inside_println_arg bool
inside_casting_to_str bool
inside_decl_rhs bool
inside_if_guard bool // true inside the guard condition of `if x := opt() {}`
inside_assign bool
Expand Down Expand Up @@ -173,7 +173,7 @@ fn (mut c Checker) reset_checker_state_at_start_of_new_file() {
c.loop_label = ''
c.using_new_err_struct = false
c.inside_selector_expr = false
c.inside_println_arg = false
c.inside_casting_to_str = false
c.inside_decl_rhs = false
c.inside_if_guard = false
}
Expand Down Expand Up @@ -3528,6 +3528,11 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
typ = c.expr(mut obj.expr)
}
}
if c.inside_casting_to_str && obj.orig_type != 0
&& c.table.sym(obj.orig_type).kind == .interface_
&& c.table.sym(obj.smartcasts.last()).kind != .interface_ {
typ = typ.deref()
}
is_option := typ.has_flag(.option) || typ.has_flag(.result)
|| node.or_expr.kind != .absent
node.kind = .variable
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/checker/fn.v
Expand Up @@ -570,7 +570,7 @@ fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
}

fn (mut c Checker) builtin_args(mut node ast.CallExpr, fn_name string, func ast.Fn) {
c.inside_println_arg = true
c.inside_casting_to_str = true
c.expected_type = ast.string_type
node.args[0].typ = c.expr(mut node.args[0].expr)
arg := node.args[0]
Expand All @@ -582,7 +582,7 @@ fn (mut c Checker) builtin_args(mut node ast.CallExpr, fn_name string, func ast.
node.pos)
}
c.fail_if_unreadable(arg.expr, arg.typ, 'argument to print')
c.inside_println_arg = false
c.inside_casting_to_str = false
node.return_type = ast.void_type
c.set_node_expected_arg_types(mut node, func)

Expand Down
6 changes: 3 additions & 3 deletions vlib/v/checker/str.v
Expand Up @@ -41,8 +41,8 @@ fn (mut c Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) u8 {
}

fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type {
inside_println_arg_save := c.inside_println_arg
c.inside_println_arg = true
inside_casting_to_str_save := c.inside_casting_to_str
c.inside_casting_to_str = true
for i, mut expr in node.exprs {
mut ftyp := c.expr(mut expr)
if c.is_comptime_var(expr) {
Expand Down Expand Up @@ -118,7 +118,7 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type {
c.error('cannot call `str()` method recursively', expr.pos())
}
}
c.inside_println_arg = inside_println_arg_save
c.inside_casting_to_str = inside_casting_to_str_save
return ast.string_type
}

Expand Down
5 changes: 5 additions & 0 deletions vlib/v/gen/c/cgen.v
Expand Up @@ -146,6 +146,7 @@ mut:
inside_const_opt_or_res bool
inside_lambda bool
inside_cinit bool
inside_casting_to_str bool
last_tmp_call_var []string
loop_depth int
ternary_names map[string]string
Expand Down Expand Up @@ -4436,6 +4437,10 @@ fn (mut g Gen) ident(node ast.Ident) {
g.write('(')
if obj_sym.kind == .sum_type && !is_auto_heap {
g.write('*')
} else if g.inside_casting_to_str && node.obj.orig_type != 0
&& g.table.sym(node.obj.orig_type).kind == .interface_
&& g.table.sym(node.obj.smartcasts.last()).kind != .interface_ {
g.write('*')
}
}
for i, typ in node.obj.smartcasts {
Expand Down
10 changes: 10 additions & 0 deletions vlib/v/gen/c/fn.v
Expand Up @@ -1656,6 +1656,10 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
mut print_auto_str := false
if is_print && (node.args[0].typ != ast.string_type
|| g.comptime_for_method.len > 0 || g.is_comptime_var(node.args[0].expr)) {
g.inside_casting_to_str = true
defer {
g.inside_casting_to_str = false
}
mut typ := node.args[0].typ
if g.is_comptime_var(node.args[0].expr) {
ctyp := g.get_comptime_var_type(node.args[0].expr)
Expand Down Expand Up @@ -1724,6 +1728,12 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
}
}
if !print_auto_str {
if is_print {
g.inside_casting_to_str = true
defer {
g.inside_casting_to_str = false
}
}
if g.pref.is_debug && node.name == 'panic' {
paline, pafile, pamod, pafn := g.panic_debug_info(node.pos)
g.write('panic_debug(${paline}, tos3("${pafile}"), tos3("${pamod}"), tos3("${pafn}"), ')
Expand Down
5 changes: 5 additions & 0 deletions vlib/v/gen/c/str_intp.v
Expand Up @@ -236,6 +236,11 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int, fmts []u8) {

fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
// fn (mut g Gen) str_int2(node ast.StringInterLiteral) {
inside_casting_to_str_old := g.inside_casting_to_str
g.inside_casting_to_str = true
defer {
g.inside_casting_to_str = inside_casting_to_str_old
}
mut node_ := unsafe { node }
mut fmts := node_.fmts.clone()
for i, mut expr in node_.exprs {
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/tests/cast_to_empty_interface_test.v
Expand Up @@ -2,8 +2,8 @@ interface Any {}

fn thing(any Any) string {
return match any {
int { 'int${*any:17}' }
f64 { 'f64${*any:20}' }
int { 'int${any:17}' }
f64 { 'f64${any:20}' }
else { 'literal type tag?${any:10}' }
}
}
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/tests/empty_interface_test.v
Expand Up @@ -10,5 +10,5 @@ fn print_out(x Any) string {

fn test_empty_interface() {
ret := print_out('12345')
assert ret == '&12345'
assert ret == '12345'
}
25 changes: 25 additions & 0 deletions vlib/v/tests/print_smartcast_interface_variable_test.v
@@ -0,0 +1,25 @@
interface Any {}

fn do(v Any) string {
match v {
int {
println('> integer answer: ${2 * v}')
return '${2 * v}'
}
string {
println('> string answer: ${v}, len: ${v.len}')
return '${v}'
}
else {
return ''
}
}
}

fn test_printing_smartcast_interface_variable() {
s1 := do(123)
assert s1 == '246'

s2 := do('abc')
assert s2 == 'abc'
}

0 comments on commit ec0d5dd

Please sign in to comment.