@@ -2886,19 +2886,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
28862886 c.in_for_count--
28872887 }
28882888 ast.ForStmt {
2889- c.in_for_count++
2890- prev_loop_label := c.loop_label
2891- c.expected_type = table.bool_type
2892- typ := c.expr (node.cond)
2893- if ! node.is_inf && typ.idx () != table.bool_type_idx && ! c.pref.translated {
2894- c.error ('non-bool used as for condition' , node.pos)
2895- }
2896- // TODO: update loop var type
2897- // how does this work currenly?
2898- c.check_loop_label (node.label, node.pos)
2899- c.stmts (node.stmts)
2900- c.loop_label = prev_loop_label
2901- c.in_for_count--
2889+ c.for_stmt (mut node)
29022890 }
29032891 ast.GlobalDecl {
29042892 for field in node.fields {
@@ -3884,60 +3872,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym table.TypeS
38843872 } else {
38853873 expr_type = expr_types[0 ].typ
38863874 }
3887- match mut node.cond {
3888- ast.SelectorExpr {
3889- mut is_mut := false
3890- mut sum_type_casts := []table.Type{}
3891- expr_sym := c.table.get_type_symbol (node.cond.expr_type)
3892- if field := c.table.struct_find_field (expr_sym, node.cond.field_name) {
3893- if field.is_mut {
3894- root_ident := node.cond.root_ident ()
3895- if v := branch.scope.find_var (root_ident.name) {
3896- is_mut = v.is_mut
3897- }
3898- }
3899- }
3900- if field := branch.scope.find_struct_field (node.cond.expr_type,
3901- node.cond.field_name) {
3902- sum_type_casts << field.sum_type_casts
3903- }
3904- // smartcast either if the value is immutable or if the mut argument is explicitly given
3905- if ! is_mut || node.cond.is_mut {
3906- sum_type_casts << expr_type
3907- branch.scope.register_struct_field (ast.ScopeStructField{
3908- struct_type: node.cond.expr_type
3909- name: node.cond.field_name
3910- typ: node.cond_type
3911- sum_type_casts: sum_type_casts
3912- pos: node.cond.pos
3913- })
3914- }
3915- }
3916- ast.Ident {
3917- mut is_mut := false
3918- mut sum_type_casts := []table.Type{}
3919- mut is_already_casted := false
3920- if node.cond.obj is ast.Var {
3921- v := node.cond.obj as ast.Var
3922- is_mut = v.is_mut
3923- sum_type_casts << v.sum_type_casts
3924- is_already_casted = v.pos.pos == node.cond.pos.pos
3925- }
3926- // smartcast either if the value is immutable or if the mut argument is explicitly given
3927- if (! is_mut || node.cond.is_mut) && ! is_already_casted {
3928- sum_type_casts << expr_type
3929- branch.scope.register (ast.Var{
3930- name: node.cond.name
3931- typ: node.cond_type
3932- pos: node.cond.pos
3933- is_used: true
3934- is_mut: node.cond.is_mut
3935- sum_type_casts: sum_type_casts
3936- })
3937- }
3938- }
3939- else {}
3940- }
3875+ c.smartcast_sumtype (node.cond, node.cond_type, expr_type, mut branch.scope)
39413876 }
39423877 }
39433878 }
@@ -4017,6 +3952,63 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym table.TypeS
40173952 c.error (err_details, node.pos)
40183953}
40193954
3955+ // smartcast takes the expression with the current type which should be smartcasted to the target type in the given scope
3956+ fn (c Checker) smartcast_sumtype (expr ast.Expr, cur_type table.Type, to_type table.Type, mut scope ast.Scope) {
3957+ match mut expr {
3958+ ast.SelectorExpr {
3959+ mut is_mut := false
3960+ mut sum_type_casts := []table.Type{}
3961+ expr_sym := c.table.get_type_symbol (expr.expr_type)
3962+ if field := c.table.struct_find_field (expr_sym, expr.field_name) {
3963+ if field.is_mut {
3964+ root_ident := expr.root_ident ()
3965+ if v := scope.find_var (root_ident.name) {
3966+ is_mut = v.is_mut
3967+ }
3968+ }
3969+ }
3970+ if field := scope.find_struct_field (expr.expr_type, expr.field_name) {
3971+ sum_type_casts << field.sum_type_casts
3972+ }
3973+ // smartcast either if the value is immutable or if the mut argument is explicitly given
3974+ if ! is_mut || expr.is_mut {
3975+ sum_type_casts << to_type
3976+ scope.register_struct_field (ast.ScopeStructField{
3977+ struct_type: expr.expr_type
3978+ name: expr.field_name
3979+ typ: cur_type
3980+ sum_type_casts: sum_type_casts
3981+ pos: expr.pos
3982+ })
3983+ }
3984+ }
3985+ ast.Ident {
3986+ mut is_mut := false
3987+ mut sum_type_casts := []table.Type{}
3988+ mut is_already_casted := false
3989+ if expr.obj is ast.Var {
3990+ v := expr.obj as ast.Var
3991+ is_mut = v.is_mut
3992+ sum_type_casts << v.sum_type_casts
3993+ is_already_casted = v.pos.pos == expr.pos.pos
3994+ }
3995+ // smartcast either if the value is immutable or if the mut argument is explicitly given
3996+ if (! is_mut || expr.is_mut) && ! is_already_casted {
3997+ sum_type_casts << to_type
3998+ scope.register (ast.Var{
3999+ name: expr.name
4000+ typ: cur_type
4001+ pos: expr.pos
4002+ is_used: true
4003+ is_mut: expr.is_mut
4004+ sum_type_casts: sum_type_casts
4005+ })
4006+ }
4007+ }
4008+ else {}
4009+ }
4010+ }
4011+
40204012pub fn (mut c Checker) select_expr (mut node ast.SelectExpr) table.Type {
40214013 node.is_expr = c.expected_type != table.void_type
40224014 node.expected_type = c.expected_type
@@ -4114,6 +4106,45 @@ pub fn (mut c Checker) unsafe_expr(mut node ast.UnsafeExpr) table.Type {
41144106 return t
41154107}
41164108
4109+ fn (mut c Checker) for_stmt (mut node ast.ForStmt) {
4110+ c.in_for_count++
4111+ prev_loop_label := c.loop_label
4112+ c.expected_type = table.bool_type
4113+ typ := c.expr (node.cond)
4114+ if ! node.is_inf && typ.idx () != table.bool_type_idx && ! c.pref.translated {
4115+ c.error ('non-bool used as for condition' , node.pos)
4116+ }
4117+ if node.cond is ast.InfixExpr {
4118+ infix := node.cond
4119+ if infix.op == .key_is {
4120+ if (infix.left is ast.Ident ||
4121+ infix.left is ast.SelectorExpr ) &&
4122+ infix.right is ast.Type {
4123+ right_expr := infix.right as ast.Type
4124+ is_variable := if mut infix.left is ast.Ident {
4125+ infix.left.kind == .variable
4126+ } else {
4127+ true
4128+ }
4129+ left_type := c.expr (infix.left)
4130+ left_sym := c.table.get_type_symbol (left_type)
4131+ if is_variable {
4132+ if left_sym.kind == .sum_type {
4133+ c.smartcast_sumtype (infix.left, infix.left_type, right_expr.typ, mut
4134+ node.scope)
4135+ }
4136+ }
4137+ }
4138+ }
4139+ }
4140+ // TODO: update loop var type
4141+ // how does this work currenly?
4142+ c.check_loop_label (node.label, node.pos)
4143+ c.stmts (node.stmts)
4144+ c.loop_label = prev_loop_label
4145+ c.in_for_count--
4146+ }
4147+
41174148pub fn (mut c Checker) if_expr (mut node ast.IfExpr) table.Type {
41184149 if_kind := if node.is_comptime { '\$ if' } else { 'if' }
41194150 expr_required := c.expected_type != table.void_type
@@ -4167,68 +4198,30 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
41674198 } else {
41684199 true
41694200 }
4170- // Register shadow variable or `as` variable with actual type
41714201 if is_variable {
4172- // TODO: merge this code with match_expr because it has the same logic implemented
41734202 if left_sym.kind in [.interface_, .sum_type] {
4174- mut is_mut := false
4175- if mut infix.left is ast.Ident {
4203+ if infix.left is ast.Ident && left_sym.kind == .interface_ {
4204+ // TODO: rewrite interface smartcast
4205+ left := infix.left as ast.Ident
4206+ mut is_mut := false
41764207 mut sum_type_casts := []table.Type{}
4177- if v := branch.scope.find_var (infix. left.name) {
4208+ if v := branch.scope.find_var (left.name) {
41784209 is_mut = v.is_mut
41794210 sum_type_casts << v.sum_type_casts
41804211 }
4181- if left_sym.kind == .sum_type {
4182- // smartcast either if the value is immutable or if the mut argument is explicitly given
4183- if ! is_mut || infix.left.is_mut {
4184- sum_type_casts << right_expr.typ
4185- branch.scope.register (ast.Var{
4186- name: infix.left.name
4187- typ: infix.left_type
4188- sum_type_casts: sum_type_casts
4189- pos: infix.left.pos
4190- is_used: true
4191- is_mut: is_mut
4192- })
4193- }
4194- } else if left_sym.kind == .interface_ {
4195- branch.scope.register (ast.Var{
4196- name: infix.left.name
4197- typ: right_expr.typ.to_ptr ()
4198- sum_type_casts: sum_type_casts
4199- pos: infix.left.pos
4200- is_used: true
4201- is_mut: is_mut
4202- })
4203- // TODO: remove that later @danieldaeschle
4204- node.branches[i].smartcast = true
4205- }
4206- } else if mut infix.left is ast.SelectorExpr {
4207- mut sum_type_casts := []table.Type{}
4208- expr_sym := c.table.get_type_symbol (infix.left.expr_type)
4209- if field := c.table.struct_find_field (expr_sym, infix.left.field_name) {
4210- if field.is_mut {
4211- root_ident := infix.left.root_ident ()
4212- if root_ident.obj is ast.Var {
4213- is_mut = root_ident.obj.is_mut
4214- }
4215- }
4216- }
4217- if field := branch.scope.find_struct_field (infix.left.expr_type,
4218- infix.left.field_name) {
4219- sum_type_casts << field.sum_type_casts
4220- }
4221- // smartcast either if the value is immutable or if the mut argument is explicitly given
4222- if (! is_mut || infix.left.is_mut) && left_sym.kind == .sum_type {
4223- sum_type_casts << right_expr.typ
4224- branch.scope.register_struct_field (ast.ScopeStructField{
4225- struct_type: infix.left.expr_type
4226- name: infix.left.field_name
4227- typ: infix.left_type
4228- sum_type_casts: sum_type_casts
4229- pos: infix.left.pos
4230- })
4231- }
4212+ branch.scope.register (ast.Var{
4213+ name: left.name
4214+ typ: right_expr.typ.to_ptr ()
4215+ sum_type_casts: sum_type_casts
4216+ pos: left.pos
4217+ is_used: true
4218+ is_mut: is_mut
4219+ })
4220+ // TODO: needs to be removed
4221+ node.branches[i].smartcast = true
4222+ } else {
4223+ c.smartcast_sumtype (infix.left, infix.left_type, right_expr.typ, mut
4224+ branch.scope)
42324225 }
42334226 }
42344227 }
0 commit comments