From 714a6928a2103dd887b954a481ca19a325186651 Mon Sep 17 00:00:00 2001
From: Felipe Pena <felipensp@gmail.com>
Date: Sun, 19 Jan 2025 08:27:19 -0300
Subject: [PATCH] fix

---
 vlib/v/ast/ast.v         |  5 +++--
 vlib/v/ast/scope.v       | 10 ++++++++++
 vlib/v/checker/checker.v | 35 ++++++++++++++++++++++++-----------
 3 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v
index 355234d4f048e2..67ff7914e4d721 100644
--- a/vlib/v/ast/ast.v
+++ b/vlib/v/ast/ast.v
@@ -925,8 +925,9 @@ pub:
 	name        string
 	pos         token.Pos
 	typ         Type
-	smartcasts  []Type // nested sum types require nested smart casting, for that a list of types is needed
-	orig_type   Type   // original sumtype type; 0 if it's not a sumtype
+	orig_type   Type // original sumtype type; 0 if it's not a sumtype
+pub mut:
+	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/ast/scope.v b/vlib/v/ast/scope.v
index 127240c62494a8..9980befaca97d8 100644
--- a/vlib/v/ast/scope.v
+++ b/vlib/v/ast/scope.v
@@ -157,6 +157,16 @@ pub fn (mut s Scope) register_struct_field(name string, field ScopeStructField)
 	s.struct_fields[name] = field
 }
 
+pub fn (mut s Scope) register_or_update_struct_field(name string, field ScopeStructField) {
+	if mut f := s.struct_fields[name] {
+		if f.struct_type == field.struct_type && f.name == field.name {
+			s.struct_fields[name].smartcasts = field.smartcasts
+			return
+		}
+	}
+	s.struct_fields[name] = field
+}
+
 pub fn (mut s Scope) register(obj ScopeObject) {
 	if !(obj.name == '_' || obj.name in s.objects) {
 		s.objects[obj.name] = obj
diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v
index bcc65052a28d9b..91fbb3648569b0 100644
--- a/vlib/v/checker/checker.v
+++ b/vlib/v/checker/checker.v
@@ -4273,7 +4273,7 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
 			mut is_mut := false
 			mut smartcasts := []ast.Type{}
 			expr_sym := c.table.sym(expr.expr_type)
-			mut orig_type := 0
+			mut orig_type := ast.no_type
 			if field := c.table.find_field(expr_sym, expr.field_name) {
 				if field.is_mut {
 					if root_ident := expr.root_ident() {
@@ -4286,20 +4286,33 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
 					orig_type = field.typ
 				}
 			}
-			if field := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name) {
+			mut nested_unwrap := false
+			if mut field := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name) {
 				smartcasts << field.smartcasts
+				nested_unwrap = smartcasts.len > 1
 			}
 			// smartcast either if the value is immutable or if the mut argument is explicitly given
-			if !is_mut || expr.is_mut || is_option_unwrap {
+			if !is_mut || expr.is_mut || is_option_unwrap || orig_type.has_flag(.option) {
 				smartcasts << to_type
-				scope.register_struct_field(expr.expr.str(), ast.ScopeStructField{
-					struct_type: expr.expr_type
-					name:        expr.field_name
-					typ:         cur_type
-					smartcasts:  smartcasts
-					pos:         expr.pos
-					orig_type:   orig_type
-				})
+				if nested_unwrap {
+					scope.register_or_update_struct_field(expr.expr.str(), ast.ScopeStructField{
+						struct_type: expr.expr_type
+						name:        expr.field_name
+						typ:         cur_type
+						smartcasts:  smartcasts
+						pos:         expr.pos
+						orig_type:   orig_type
+					})
+				} else {
+					scope.register_struct_field(expr.expr.str(), ast.ScopeStructField{
+						struct_type: expr.expr_type
+						name:        expr.field_name
+						typ:         cur_type
+						smartcasts:  smartcasts
+						pos:         expr.pos
+						orig_type:   orig_type
+					})
+				}
 			} else {
 				c.smartcast_mut_pos = expr.pos
 			}