From bc76d3b61f496e216e51c6454e3317e13d586f7c Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 22 Apr 2026 17:01:16 +0300 Subject: [PATCH] checker: more fixes --- vlib/v/ast/ast.v | 19 ++++++++++--------- vlib/v/checker/assign.v | 12 +++++++----- vlib/v/checker/checker.v | 29 ++++++++++++++++------------- vlib/v/checker/comptime.v | 3 +-- vlib/v/checker/fn.v | 7 +------ vlib/v/checker/return.v | 3 +-- 6 files changed, 36 insertions(+), 37 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 06a3ba1d8..393533b91 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1003,15 +1003,16 @@ pub: is_inherited bool has_inherited bool pub mut: - is_arg bool // fn args should not be autofreed - is_auto_deref bool - is_unwrapped bool // ct type smartcast unwrapped - is_index_var bool // index loop var - expr Expr - typ Type - generic_typ Type // original generic declaration type; reused for later concrete instantiations - orig_type Type // original sumtype type; 0 if it's not a sumtype - smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed + is_arg bool // fn args should not be autofreed + is_auto_deref bool + is_unwrapped bool // ct type smartcast unwrapped + is_assignment_smartcast bool // smartcast introduced by assigning a non-option value to an option variable + is_index_var bool // index loop var + expr Expr + typ Type + generic_typ Type // original generic declaration type; reused for later concrete instantiations + orig_type Type // original sumtype type; 0 if it's not a sumtype + smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed // TODO: move this to a real docs site later // 10 <- original type (orig_type) // [11, 12, 13] <- cast order (smartcasts) diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index 4f43da831..489e910af 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -85,11 +85,12 @@ fn (mut c Checker) reset_option_assignment_smartcast(mut expr ast.Ident, left_ty if var := expr.scope.find_var(expr.name) { expr.scope.objects[expr.name] = ast.Var{ ...var - typ: left_type - pos: var.pos - orig_type: ast.no_type - smartcasts: []ast.Type{} - is_unwrapped: false + typ: left_type + pos: var.pos + orig_type: ast.no_type + smartcasts: []ast.Type{} + is_assignment_smartcast: false + is_unwrapped: false } } } @@ -113,6 +114,7 @@ fn (mut c Checker) update_option_assignment_smartcast(mut expr ast.Expr, left_ty c.smartcast(mut expr, left_type, left_type.clear_flag(.option), mut expr.scope, false, true, false, true) if mut scope_var := expr.scope.find_var(expr.name) { + scope_var.is_assignment_smartcast = true scope_var.pos = original_pos } } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 190dbfaea..086ef66bb 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -4693,12 +4693,7 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type { type_sym := c.table.sym(c.unwrap_generic(node.typ)) if mut node.expr is ast.Ident { if mut node.expr.obj is ast.Var { - ident_typ := if node.expr.obj.smartcasts.len > 0 { - c.exposed_smartcast_type(node.expr.obj.orig_type, - node.expr.obj.smartcasts.last(), node.expr.obj.is_mut) - } else { - node.expr.obj.typ - } + ident_typ := c.visible_var_type_for_read(node.expr.obj) if !node.typ.has_flag(.option) && ident_typ.has_flag(.option) && node.expr.or_expr.kind == .absent { c.error('variable `${node.expr.name}` is an Option, it must be unwrapped first', @@ -4839,16 +4834,14 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type { } else if node.expr.obj is ast.Var { var_obj := node.expr.obj as ast.Var if var_obj.smartcasts.len > 0 { - node.expr_type = c.unwrap_generic(c.exposed_smartcast_type(var_obj.orig_type, - var_obj.smartcasts.last(), var_obj.is_mut)) + node.expr_type = c.unwrap_generic(c.visible_var_type_for_read(var_obj)) } } } else if mut node.expr is ast.Ident { if node.expr.obj is ast.Var { var_obj := node.expr.obj as ast.Var if var_obj.smartcasts.len > 0 { - node.expr_type = c.unwrap_generic(c.exposed_smartcast_type(var_obj.orig_type, - var_obj.smartcasts.last(), var_obj.is_mut)) + node.expr_type = c.unwrap_generic(c.visible_var_type_for_read(var_obj)) } } } @@ -6289,8 +6282,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type { info_typ = current_var.typ } if current_var.smartcasts.len > 0 && !c.prevent_sum_type_unwrapping_once { - info_typ = c.exposed_smartcast_type(current_var.orig_type, - current_var.smartcasts.last(), current_var.is_mut) + info_typ = c.visible_var_type_for_read(current_var) } c.prevent_sum_type_unwrapping_once = false node.info = ast.IdentVar{ @@ -6372,7 +6364,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type { && !c.prevent_sum_type_unwrapping_once c.prevent_sum_type_unwrapping_once = false mut typ := if is_sum_type_cast { - c.exposed_smartcast_type(obj.orig_type, obj.smartcasts.last(), obj.is_mut) + c.visible_var_type_for_read(obj) } else { obj.typ } @@ -7177,6 +7169,17 @@ fn (c &Checker) is_orig_sumtype(expr ast.Expr) bool { return false } +@[inline] +fn (mut c Checker) visible_var_type_for_read(v ast.Var) ast.Type { + if v.smartcasts.len == 0 { + return v.typ + } + if v.is_assignment_smartcast && v.orig_type.has_flag(.option) { + return v.orig_type + } + return c.exposed_smartcast_type(v.orig_type, v.smartcasts.last(), v.is_mut) +} + @[inline] fn (mut c Checker) exposed_smartcast_type(orig_type ast.Type, smartcast_type ast.Type, is_mut bool) ast.Type { if is_mut || orig_type == 0 || smartcast_type == 0 || orig_type.is_ptr() { diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 06c2620cc..a792c526c 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -1243,8 +1243,7 @@ fn (mut c Checker) get_expr_type(cond ast.Expr) ast.Type { // var checked_type = c.unwrap_generic(var.typ) if var.smartcasts.len > 0 { - checked_type = c.unwrap_generic(c.exposed_smartcast_type(var.orig_type, - var.smartcasts.last(), var.is_mut)) + checked_type = c.unwrap_generic(c.visible_var_type_for_read(var)) } } return checked_type diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 20ddd69a0..a8dbeb33c 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1196,12 +1196,7 @@ fn (mut c Checker) anon_fn(mut node ast.AnonFn) ast.Type { c.error('original `${parent_var.name}` is immutable, declare it with `mut` to make it mutable', var.pos) } - ptyp := if parent_var.smartcasts.len > 0 { - c.exposed_smartcast_type(parent_var.orig_type, parent_var.smartcasts.last(), - parent_var.is_mut) - } else { - parent_var.typ - } + ptyp := c.visible_var_type_for_read(parent_var) node.has_ct_var = node.has_ct_var || var.name in [c.comptime.comptime_for_field_var, c.comptime.comptime_for_method_var] if declared_parent_typ != ast.no_type { diff --git a/vlib/v/checker/return.v b/vlib/v/checker/return.v index 4a0e559ab..4e0904891 100644 --- a/vlib/v/checker/return.v +++ b/vlib/v/checker/return.v @@ -114,8 +114,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) { } else { if mut expr is ast.Ident && expr.obj is ast.Var { if expr.obj.smartcasts.len > 0 { - typ = c.unwrap_generic(c.exposed_smartcast_type(expr.obj.orig_type, - expr.obj.smartcasts.last(), expr.obj.is_mut)) + typ = c.unwrap_generic(c.visible_var_type_for_read(expr.obj)) } if expr.obj.ct_type_var != .no_comptime { typ = c.type_resolver.get_type_or_default(expr, typ) -- 2.39.5