|
|
|
@ -2886,19 +2886,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|
|
|
|
c.in_for_count--
|
|
|
|
|
}
|
|
|
|
|
ast.ForStmt {
|
|
|
|
|
c.in_for_count++
|
|
|
|
|
prev_loop_label := c.loop_label
|
|
|
|
|
c.expected_type = table.bool_type
|
|
|
|
|
typ := c.expr(node.cond)
|
|
|
|
|
if !node.is_inf && typ.idx() != table.bool_type_idx && !c.pref.translated {
|
|
|
|
|
c.error('non-bool used as for condition', node.pos)
|
|
|
|
|
}
|
|
|
|
|
// TODO: update loop var type
|
|
|
|
|
// how does this work currenly?
|
|
|
|
|
c.check_loop_label(node.label, node.pos)
|
|
|
|
|
c.stmts(node.stmts)
|
|
|
|
|
c.loop_label = prev_loop_label
|
|
|
|
|
c.in_for_count--
|
|
|
|
|
c.for_stmt(mut node)
|
|
|
|
|
}
|
|
|
|
|
ast.GlobalDecl {
|
|
|
|
|
for field in node.fields {
|
|
|
|
@ -3884,60 +3872,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym table.TypeS
|
|
|
|
|
} else {
|
|
|
|
|
expr_type = expr_types[0].typ
|
|
|
|
|
}
|
|
|
|
|
match mut node.cond {
|
|
|
|
|
ast.SelectorExpr {
|
|
|
|
|
mut is_mut := false
|
|
|
|
|
mut sum_type_casts := []table.Type{}
|
|
|
|
|
expr_sym := c.table.get_type_symbol(node.cond.expr_type)
|
|
|
|
|
if field := c.table.struct_find_field(expr_sym, node.cond.field_name) {
|
|
|
|
|
if field.is_mut {
|
|
|
|
|
root_ident := node.cond.root_ident()
|
|
|
|
|
if v := branch.scope.find_var(root_ident.name) {
|
|
|
|
|
is_mut = v.is_mut
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if field := branch.scope.find_struct_field(node.cond.expr_type,
|
|
|
|
|
node.cond.field_name) {
|
|
|
|
|
sum_type_casts << field.sum_type_casts
|
|
|
|
|
}
|
|
|
|
|
// smartcast either if the value is immutable or if the mut argument is explicitly given
|
|
|
|
|
if !is_mut || node.cond.is_mut {
|
|
|
|
|
sum_type_casts << expr_type
|
|
|
|
|
branch.scope.register_struct_field(ast.ScopeStructField{
|
|
|
|
|
struct_type: node.cond.expr_type
|
|
|
|
|
name: node.cond.field_name
|
|
|
|
|
typ: node.cond_type
|
|
|
|
|
sum_type_casts: sum_type_casts
|
|
|
|
|
pos: node.cond.pos
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ast.Ident {
|
|
|
|
|
mut is_mut := false
|
|
|
|
|
mut sum_type_casts := []table.Type{}
|
|
|
|
|
mut is_already_casted := false
|
|
|
|
|
if node.cond.obj is ast.Var {
|
|
|
|
|
v := node.cond.obj as ast.Var
|
|
|
|
|
is_mut = v.is_mut
|
|
|
|
|
sum_type_casts << v.sum_type_casts
|
|
|
|
|
is_already_casted = v.pos.pos == node.cond.pos.pos
|
|
|
|
|
}
|
|
|
|
|
// smartcast either if the value is immutable or if the mut argument is explicitly given
|
|
|
|
|
if (!is_mut || node.cond.is_mut) && !is_already_casted {
|
|
|
|
|
sum_type_casts << expr_type
|
|
|
|
|
branch.scope.register(ast.Var{
|
|
|
|
|
name: node.cond.name
|
|
|
|
|
typ: node.cond_type
|
|
|
|
|
pos: node.cond.pos
|
|
|
|
|
is_used: true
|
|
|
|
|
is_mut: node.cond.is_mut
|
|
|
|
|
sum_type_casts: sum_type_casts
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {}
|
|
|
|
|
}
|
|
|
|
|
c.smartcast_sumtype(node.cond, node.cond_type, expr_type, mut branch.scope)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -4017,6 +3952,63 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym table.TypeS
|
|
|
|
|
c.error(err_details, node.pos)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// smartcast takes the expression with the current type which should be smartcasted to the target type in the given scope
|
|
|
|
|
fn (c Checker) smartcast_sumtype(expr ast.Expr, cur_type table.Type, to_type table.Type, mut scope ast.Scope) {
|
|
|
|
|
match mut expr {
|
|
|
|
|
ast.SelectorExpr {
|
|
|
|
|
mut is_mut := false
|
|
|
|
|
mut sum_type_casts := []table.Type{}
|
|
|
|
|
expr_sym := c.table.get_type_symbol(expr.expr_type)
|
|
|
|
|
if field := c.table.struct_find_field(expr_sym, expr.field_name) {
|
|
|
|
|
if field.is_mut {
|
|
|
|
|
root_ident := expr.root_ident()
|
|
|
|
|
if v := scope.find_var(root_ident.name) {
|
|
|
|
|
is_mut = v.is_mut
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if field := scope.find_struct_field(expr.expr_type, expr.field_name) {
|
|
|
|
|
sum_type_casts << field.sum_type_casts
|
|
|
|
|
}
|
|
|
|
|
// smartcast either if the value is immutable or if the mut argument is explicitly given
|
|
|
|
|
if !is_mut || expr.is_mut {
|
|
|
|
|
sum_type_casts << to_type
|
|
|
|
|
scope.register_struct_field(ast.ScopeStructField{
|
|
|
|
|
struct_type: expr.expr_type
|
|
|
|
|
name: expr.field_name
|
|
|
|
|
typ: cur_type
|
|
|
|
|
sum_type_casts: sum_type_casts
|
|
|
|
|
pos: expr.pos
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ast.Ident {
|
|
|
|
|
mut is_mut := false
|
|
|
|
|
mut sum_type_casts := []table.Type{}
|
|
|
|
|
mut is_already_casted := false
|
|
|
|
|
if expr.obj is ast.Var {
|
|
|
|
|
v := expr.obj as ast.Var
|
|
|
|
|
is_mut = v.is_mut
|
|
|
|
|
sum_type_casts << v.sum_type_casts
|
|
|
|
|
is_already_casted = v.pos.pos == expr.pos.pos
|
|
|
|
|
}
|
|
|
|
|
// smartcast either if the value is immutable or if the mut argument is explicitly given
|
|
|
|
|
if (!is_mut || expr.is_mut) && !is_already_casted {
|
|
|
|
|
sum_type_casts << to_type
|
|
|
|
|
scope.register(ast.Var{
|
|
|
|
|
name: expr.name
|
|
|
|
|
typ: cur_type
|
|
|
|
|
pos: expr.pos
|
|
|
|
|
is_used: true
|
|
|
|
|
is_mut: expr.is_mut
|
|
|
|
|
sum_type_casts: sum_type_casts
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn (mut c Checker) select_expr(mut node ast.SelectExpr) table.Type {
|
|
|
|
|
node.is_expr = c.expected_type != table.void_type
|
|
|
|
|
node.expected_type = c.expected_type
|
|
|
|
@ -4114,6 +4106,45 @@ pub fn (mut c Checker) unsafe_expr(mut node ast.UnsafeExpr) table.Type {
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
|
|
|
|
|
c.in_for_count++
|
|
|
|
|
prev_loop_label := c.loop_label
|
|
|
|
|
c.expected_type = table.bool_type
|
|
|
|
|
typ := c.expr(node.cond)
|
|
|
|
|
if !node.is_inf && typ.idx() != table.bool_type_idx && !c.pref.translated {
|
|
|
|
|
c.error('non-bool used as for condition', node.pos)
|
|
|
|
|
}
|
|
|
|
|
if node.cond is ast.InfixExpr {
|
|
|
|
|
infix := node.cond
|
|
|
|
|
if infix.op == .key_is {
|
|
|
|
|
if (infix.left is ast.Ident ||
|
|
|
|
|
infix.left is ast.SelectorExpr) &&
|
|
|
|
|
infix.right is ast.Type {
|
|
|
|
|
right_expr := infix.right as ast.Type
|
|
|
|
|
is_variable := if mut infix.left is ast.Ident {
|
|
|
|
|
infix.left.kind == .variable
|
|
|
|
|
} else {
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
left_type := c.expr(infix.left)
|
|
|
|
|
left_sym := c.table.get_type_symbol(left_type)
|
|
|
|
|
if is_variable {
|
|
|
|
|
if left_sym.kind == .sum_type {
|
|
|
|
|
c.smartcast_sumtype(infix.left, infix.left_type, right_expr.typ, mut
|
|
|
|
|
node.scope)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// TODO: update loop var type
|
|
|
|
|
// how does this work currenly?
|
|
|
|
|
c.check_loop_label(node.label, node.pos)
|
|
|
|
|
c.stmts(node.stmts)
|
|
|
|
|
c.loop_label = prev_loop_label
|
|
|
|
|
c.in_for_count--
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
|
|
|
|
if_kind := if node.is_comptime { '\$if' } else { 'if' }
|
|
|
|
|
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 {
|
|
|
|
|
} else {
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
// Register shadow variable or `as` variable with actual type
|
|
|
|
|
if is_variable {
|
|
|
|
|
// TODO: merge this code with match_expr because it has the same logic implemented
|
|
|
|
|
if left_sym.kind in [.interface_, .sum_type] {
|
|
|
|
|
if infix.left is ast.Ident && left_sym.kind == .interface_ {
|
|
|
|
|
// TODO: rewrite interface smartcast
|
|
|
|
|
left := infix.left as ast.Ident
|
|
|
|
|
mut is_mut := false
|
|
|
|
|
if mut infix.left is ast.Ident {
|
|
|
|
|
mut sum_type_casts := []table.Type{}
|
|
|
|
|
if v := branch.scope.find_var(infix.left.name) {
|
|
|
|
|
if v := branch.scope.find_var(left.name) {
|
|
|
|
|
is_mut = v.is_mut
|
|
|
|
|
sum_type_casts << v.sum_type_casts
|
|
|
|
|
}
|
|
|
|
|
if left_sym.kind == .sum_type {
|
|
|
|
|
// smartcast either if the value is immutable or if the mut argument is explicitly given
|
|
|
|
|
if !is_mut || infix.left.is_mut {
|
|
|
|
|
sum_type_casts << right_expr.typ
|
|
|
|
|
branch.scope.register(ast.Var{
|
|
|
|
|
name: infix.left.name
|
|
|
|
|
typ: infix.left_type
|
|
|
|
|
sum_type_casts: sum_type_casts
|
|
|
|
|
pos: infix.left.pos
|
|
|
|
|
is_used: true
|
|
|
|
|
is_mut: is_mut
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
} else if left_sym.kind == .interface_ {
|
|
|
|
|
branch.scope.register(ast.Var{
|
|
|
|
|
name: infix.left.name
|
|
|
|
|
name: left.name
|
|
|
|
|
typ: right_expr.typ.to_ptr()
|
|
|
|
|
sum_type_casts: sum_type_casts
|
|
|
|
|
pos: infix.left.pos
|
|
|
|
|
pos: left.pos
|
|
|
|
|
is_used: true
|
|
|
|
|
is_mut: is_mut
|
|
|
|
|
})
|
|
|
|
|
// TODO: remove that later @danieldaeschle
|
|
|
|
|
// TODO: needs to be removed
|
|
|
|
|
node.branches[i].smartcast = true
|
|
|
|
|
}
|
|
|
|
|
} else if mut infix.left is ast.SelectorExpr {
|
|
|
|
|
mut sum_type_casts := []table.Type{}
|
|
|
|
|
expr_sym := c.table.get_type_symbol(infix.left.expr_type)
|
|
|
|
|
if field := c.table.struct_find_field(expr_sym, infix.left.field_name) {
|
|
|
|
|
if field.is_mut {
|
|
|
|
|
root_ident := infix.left.root_ident()
|
|
|
|
|
if root_ident.obj is ast.Var {
|
|
|
|
|
is_mut = root_ident.obj.is_mut
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if field := branch.scope.find_struct_field(infix.left.expr_type,
|
|
|
|
|
infix.left.field_name) {
|
|
|
|
|
sum_type_casts << field.sum_type_casts
|
|
|
|
|
}
|
|
|
|
|
// smartcast either if the value is immutable or if the mut argument is explicitly given
|
|
|
|
|
if (!is_mut || infix.left.is_mut) && left_sym.kind == .sum_type {
|
|
|
|
|
sum_type_casts << right_expr.typ
|
|
|
|
|
branch.scope.register_struct_field(ast.ScopeStructField{
|
|
|
|
|
struct_type: infix.left.expr_type
|
|
|
|
|
name: infix.left.field_name
|
|
|
|
|
typ: infix.left_type
|
|
|
|
|
sum_type_casts: sum_type_casts
|
|
|
|
|
pos: infix.left.pos
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
c.smartcast_sumtype(infix.left, infix.left_type, right_expr.typ, mut
|
|
|
|
|
branch.scope)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|