checker: implement if smartcast multi conds (part 1) (#10477)
							parent
							
								
									d56219a986
								
							
						
					
					
						commit
						1dca06495d
					
				| 
						 | 
				
			
			@ -4658,19 +4658,15 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type {
 | 
			
		|||
				c.ensure_type_exists(node.typ, node.pos) or {}
 | 
			
		||||
				if !c.table.sumtype_has_variant(node.expr_type, node.typ) {
 | 
			
		||||
					c.error('cannot cast `$expr_type_sym.name` to `$type_sym.name`', node.pos)
 | 
			
		||||
					// c.error('only $info.variants can be casted to `$typ`', node.pos)
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				mut s := 'cannot cast non-sum type `$expr_type_sym.name` using `as`'
 | 
			
		||||
				if type_sym.kind == .sum_type {
 | 
			
		||||
					s += ' - use e.g. `${type_sym.name}(some_expr)` instead.'
 | 
			
		||||
				}
 | 
			
		||||
				c.error(s, node.pos)
 | 
			
		||||
				// mut s := 'cannot cast non-sum type `$expr_type_sym.name` using `as`'
 | 
			
		||||
				// if type_sym.kind == .sum_type {
 | 
			
		||||
				// 	s += ' - use e.g. `${type_sym.name}(some_expr)` instead.'
 | 
			
		||||
				// }
 | 
			
		||||
				// c.error(s, node.pos)
 | 
			
		||||
			}
 | 
			
		||||
			if expr_type_sym.kind == .sum_type {
 | 
			
		||||
				return node.typ
 | 
			
		||||
			}
 | 
			
		||||
			return node.typ.to_ptr()
 | 
			
		||||
			return node.typ
 | 
			
		||||
		}
 | 
			
		||||
		ast.Assoc {
 | 
			
		||||
			v := node.scope.find_var(node.var_name) or { panic(err) }
 | 
			
		||||
| 
						 | 
				
			
			@ -6038,50 +6034,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
 | 
			
		|||
			c.skip_flags = cur_skip_flags
 | 
			
		||||
		} else {
 | 
			
		||||
			// smartcast sumtypes and interfaces when using `is`
 | 
			
		||||
			pos := branch.cond.position()
 | 
			
		||||
			if branch.cond is ast.InfixExpr {
 | 
			
		||||
				if branch.cond.op == .key_is {
 | 
			
		||||
					right_expr := branch.cond.right
 | 
			
		||||
					right_type := match right_expr {
 | 
			
		||||
						ast.TypeNode {
 | 
			
		||||
							right_expr.typ
 | 
			
		||||
						}
 | 
			
		||||
						ast.None {
 | 
			
		||||
							ast.none_type_idx
 | 
			
		||||
						}
 | 
			
		||||
						else {
 | 
			
		||||
							c.error('invalid type `$right_expr`', right_expr.position())
 | 
			
		||||
							ast.Type(0)
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if right_type != ast.Type(0) {
 | 
			
		||||
						left_sym := c.table.get_type_symbol(branch.cond.left_type)
 | 
			
		||||
						expr_type := c.expr(branch.cond.left)
 | 
			
		||||
						if left_sym.kind == .interface_ {
 | 
			
		||||
							c.type_implements(right_type, expr_type, pos)
 | 
			
		||||
						} else if !c.check_types(right_type, expr_type) {
 | 
			
		||||
							expect_str := c.table.type_to_str(right_type)
 | 
			
		||||
							expr_str := c.table.type_to_str(expr_type)
 | 
			
		||||
							c.error('cannot use type `$expect_str` as type `$expr_str`',
 | 
			
		||||
								pos)
 | 
			
		||||
						}
 | 
			
		||||
						if (branch.cond.left is ast.Ident || branch.cond.left is ast.SelectorExpr)
 | 
			
		||||
							&& branch.cond.right is ast.TypeNode {
 | 
			
		||||
							is_variable := if mut branch.cond.left is ast.Ident {
 | 
			
		||||
								branch.cond.left.kind == .variable
 | 
			
		||||
							} else {
 | 
			
		||||
								true
 | 
			
		||||
							}
 | 
			
		||||
							if is_variable {
 | 
			
		||||
								if left_sym.kind in [.interface_, .sum_type] {
 | 
			
		||||
									c.smartcast(branch.cond.left, branch.cond.left_type,
 | 
			
		||||
										right_type, mut branch.scope)
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			c.smartcast_if_conds(branch.cond, mut branch.scope)
 | 
			
		||||
			c.stmts(branch.stmts)
 | 
			
		||||
		}
 | 
			
		||||
		if expr_required {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,10 +5,10 @@ vlib/v/checker/tests/is_type_invalid.vv:14:12: error: `IoS` has no variant `byte
 | 
			
		|||
      |               ~~
 | 
			
		||||
   15 |         println('not cool')
 | 
			
		||||
   16 |     }
 | 
			
		||||
vlib/v/checker/tests/is_type_invalid.vv:18:5: error: `Cat` doesn't implement method `speak` of interface `Animal`
 | 
			
		||||
vlib/v/checker/tests/is_type_invalid.vv:18:7: error: `Cat` doesn't implement method `speak` of interface `Animal`
 | 
			
		||||
   16 |     }
 | 
			
		||||
   17 |     a := Animal(Dog{})
 | 
			
		||||
   18 |     if a is Cat {
 | 
			
		||||
      |        ~~~~~~~~
 | 
			
		||||
      |          ~~
 | 
			
		||||
   19 |         println('not cool either')
 | 
			
		||||
   20 |     }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,28 +0,0 @@
 | 
			
		|||
vlib/v/checker/tests/sum.vv:5:8: error: cannot cast non-sum type `int` using `as`
 | 
			
		||||
    3 | fn non_sum() {
 | 
			
		||||
    4 |     v := 4
 | 
			
		||||
    5 |     _ = v as rune
 | 
			
		||||
      |           ~~
 | 
			
		||||
    6 |     _ = v as Var
 | 
			
		||||
    7 | }
 | 
			
		||||
vlib/v/checker/tests/sum.vv:6:8: error: cannot cast non-sum type `int` using `as` - use e.g. `Var(some_expr)` instead.
 | 
			
		||||
    4 |     v := 4
 | 
			
		||||
    5 |     _ = v as rune
 | 
			
		||||
    6 |     _ = v as Var
 | 
			
		||||
      |           ~~
 | 
			
		||||
    7 | }
 | 
			
		||||
    8 |
 | 
			
		||||
vlib/v/checker/tests/sum.vv:10:7: error: cannot cast `rune` to `Var`
 | 
			
		||||
    8 | 
 | 
			
		||||
    9 | fn sum() {
 | 
			
		||||
   10 |     _ := Var(`J`)
 | 
			
		||||
      |          ~~~~~~~~
 | 
			
		||||
   11 |     mut s2 := Var('')
 | 
			
		||||
   12 |     s2 = true
 | 
			
		||||
vlib/v/checker/tests/sum.vv:12:7: error: cannot assign to `s2`: expected `Var`, not `bool`
 | 
			
		||||
   10 |     _ := Var(`J`)
 | 
			
		||||
   11 |     mut s2 := Var('')
 | 
			
		||||
   12 |     s2 = true
 | 
			
		||||
      |          ~~~~
 | 
			
		||||
   13 |     _ = s2
 | 
			
		||||
   14 | }
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
type Var = int | string
 | 
			
		||||
 | 
			
		||||
fn non_sum() {
 | 
			
		||||
	v := 4
 | 
			
		||||
	_ = v as rune
 | 
			
		||||
	_ = v as Var
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn sum() {
 | 
			
		||||
	_ := Var(`J`)
 | 
			
		||||
	mut s2 := Var('')
 | 
			
		||||
	s2 = true
 | 
			
		||||
	_ = s2
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -301,8 +301,8 @@ fn (f Fmt) should_insert_newline_before_node(node ast.Node, prev_node ast.Node)
 | 
			
		|||
	prev_line_nr := prev_node.position().last_line
 | 
			
		||||
	// The nodes are Stmts
 | 
			
		||||
	if node is ast.Stmt && prev_node is ast.Stmt {
 | 
			
		||||
		stmt := node as ast.Stmt
 | 
			
		||||
		prev_stmt := prev_node as ast.Stmt
 | 
			
		||||
		stmt := node
 | 
			
		||||
		prev_stmt := prev_node
 | 
			
		||||
		// Force a newline after a block of HashStmts
 | 
			
		||||
		if prev_stmt is ast.HashStmt && stmt !is ast.HashStmt && stmt !is ast.ExprStmt {
 | 
			
		||||
			return true
 | 
			
		||||
| 
						 | 
				
			
			@ -1662,8 +1662,7 @@ pub fn (mut f Fmt) call_args(args []ast.CallArg) {
 | 
			
		|||
	}
 | 
			
		||||
	for i, arg in args {
 | 
			
		||||
		if i == args.len - 1 && arg.expr is ast.StructInit {
 | 
			
		||||
			struct_expr := arg.expr as ast.StructInit
 | 
			
		||||
			if struct_expr.typ == ast.void_type {
 | 
			
		||||
			if arg.expr.typ == ast.void_type {
 | 
			
		||||
				f.use_short_fn_args = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -2477,7 +2476,7 @@ pub fn (mut f Fmt) prefix_expr_cast_expr(node ast.Expr) {
 | 
			
		|||
	mut is_pe_amp_ce := false
 | 
			
		||||
	if node is ast.PrefixExpr {
 | 
			
		||||
		if node.right is ast.CastExpr && node.op == .amp {
 | 
			
		||||
			mut ce := node.right as ast.CastExpr
 | 
			
		||||
			mut ce := node.right
 | 
			
		||||
			ce.typname = f.table.get_type_symbol(ce.typ).name
 | 
			
		||||
			is_pe_amp_ce = true
 | 
			
		||||
			f.expr(ce)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6422,6 +6422,8 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
 | 
			
		|||
			variant_sym := g.table.get_type_symbol(variant)
 | 
			
		||||
			g.as_cast_type_names[idx] = variant_sym.name
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		g.expr(node.expr)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
struct Empty {}
 | 
			
		||||
 | 
			
		||||
struct SourcePosition {
 | 
			
		||||
	source_line   u32
 | 
			
		||||
	source_column u32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SourcePositionType = Empty | SourcePosition
 | 
			
		||||
type NameIndexType = Empty | u32
 | 
			
		||||
 | 
			
		||||
struct GenPosition {
 | 
			
		||||
	gen_line   u32
 | 
			
		||||
	gen_column u32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Mapping {
 | 
			
		||||
	GenPosition
 | 
			
		||||
	sources_ind     u32
 | 
			
		||||
	names_ind       NameIndexType
 | 
			
		||||
	source_position SourcePositionType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn ok(mapping_a Mapping, mapping_b Mapping) bool {
 | 
			
		||||
	if mapping_a.source_position is SourcePosition && mapping_b.source_position is SourcePosition {
 | 
			
		||||
		return mapping_a.source_position.source_line != mapping_b.source_position.source_line
 | 
			
		||||
			|| mapping_a.source_position.source_column != mapping_b.source_position.source_column
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_if_smartcast_multi_conds() {
 | 
			
		||||
	a := Mapping{
 | 
			
		||||
		source_position: SourcePosition{
 | 
			
		||||
			source_line: 11
 | 
			
		||||
			source_column: 22
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	b := Mapping{
 | 
			
		||||
		source_position: SourcePosition{
 | 
			
		||||
			source_line: 22
 | 
			
		||||
			source_column: 11
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	ret := ok(a, b)
 | 
			
		||||
	println(ret)
 | 
			
		||||
	assert ret
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue