From c58b04bcbfad593c60e3849dfb7df3b2a1d7fc7d Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 17 Jun 2021 17:27:31 +0800 Subject: [PATCH] checker: implement if smartcast multi conds (part 2) (#10487) --- vlib/v/checker/checker.v | 24 +++++++++++------------- vlib/v/checker/tests/sum.out | 28 ++++++++++++++++++++++++++++ vlib/v/checker/tests/sum.vv | 14 ++++++++++++++ vlib/v/gen/c/comptime.v | 2 +- vlib/v/gen/js/js.v | 3 +-- vlib/v/gen/js/sourcemap/mappings.v | 8 ++++---- vlib/v/parser/sql.v | 3 +-- 7 files changed, 60 insertions(+), 22 deletions(-) create mode 100644 vlib/v/checker/tests/sum.out create mode 100644 vlib/v/checker/tests/sum.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 552b4a57bf..cdc8df6954 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2922,8 +2922,7 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { if field_name.len > 0 && field_name[0].is_capital() && sym.info is ast.Struct && sym.language == .v { // x.Foo.y => access the embedded struct - sym_info := sym.info as ast.Struct - for embed in sym_info.embeds { + for embed in sym.info.embeds { embed_sym := c.table.get_type_symbol(embed) if embed_sym.embed_name() == field_name { node.typ = embed @@ -4271,7 +4270,6 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) { if infix.op == .key_is { if (infix.left is ast.Ident || infix.left is ast.SelectorExpr) && infix.right is ast.TypeNode { - right_expr := infix.right as ast.TypeNode is_variable := if mut infix.left is ast.Ident { infix.left.kind == .variable } else { @@ -4281,7 +4279,8 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) { left_sym := c.table.get_type_symbol(left_type) if is_variable { if left_sym.kind in [.sum_type, .interface_] { - c.smartcast(infix.left, infix.left_type, right_expr.typ, mut node.scope) + c.smartcast(infix.left, infix.left_type, infix.right.typ, mut + node.scope) } } } @@ -4667,12 +4666,12 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type { 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) } - } 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) + } else if node.expr_type != node.typ { + 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) } return node.typ } @@ -5998,7 +5997,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { } else if branch.cond.right is ast.TypeNode && left is ast.TypeNode && sym.kind == .interface_ { // is interface - checked_type := c.unwrap_generic((left as ast.TypeNode).typ) + checked_type := c.unwrap_generic(left.typ) should_skip = !c.table.type_implements_interface(checked_type, got_type) } else if left is ast.TypeNode { @@ -6187,8 +6186,7 @@ fn (mut c Checker) comp_if_branch(cond ast.Expr, pos token.Position) bool { .key_is, .not_is { if cond.left is ast.TypeNode && cond.right is ast.TypeNode { // `$if Foo is Interface {` - type_node := cond.right as ast.TypeNode - sym := c.table.get_type_symbol(type_node.typ) + sym := c.table.get_type_symbol(cond.right.typ) if sym.kind != .interface_ { c.expr(cond.left) // c.error('`$sym.name` is not an interface', cond.right.position()) diff --git a/vlib/v/checker/tests/sum.out b/vlib/v/checker/tests/sum.out new file mode 100644 index 0000000000..5c92692ca7 --- /dev/null +++ b/vlib/v/checker/tests/sum.out @@ -0,0 +1,28 @@ +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 | } diff --git a/vlib/v/checker/tests/sum.vv b/vlib/v/checker/tests/sum.vv new file mode 100644 index 0000000000..6796a2e58f --- /dev/null +++ b/vlib/v/checker/tests/sum.vv @@ -0,0 +1,14 @@ +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 +} diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 54462a4998..e6c29a1889 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -325,7 +325,7 @@ fn (mut g Gen) comp_if_cond(cond ast.Expr) bool { interface_sym := g.table.get_type_symbol(got_type) if interface_sym.info is ast.Interface { // q := g.table.get_type_symbol(interface_sym.info.types[0]) - checked_type := g.unwrap_generic((left as ast.TypeNode).typ) + checked_type := g.unwrap_generic(left.typ) // TODO PERF this check is run twice (also in the checker) // store the result in a field is_true := g.table.type_implements_interface(checked_type, diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index fefe9da739..f9b83faced 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -850,8 +850,7 @@ fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) { for field in it.fields { g.write('$field.name: ') if field.has_expr && field.expr is ast.IntegerLiteral { - e := field.expr as ast.IntegerLiteral - i = e.val.int() + i = field.expr.val.int() } g.writeln('$i,') i++ diff --git a/vlib/v/gen/js/sourcemap/mappings.v b/vlib/v/gen/js/sourcemap/mappings.v index 71ba0c031b..dfe1318798 100644 --- a/vlib/v/gen/js/sourcemap/mappings.v +++ b/vlib/v/gen/js/sourcemap/mappings.v @@ -150,8 +150,8 @@ fn compare_by_generated_positions_inflated(mapping_a Mapping, mapping_b Mapping) if mapping_a.source_position.type_name() == mapping_b.source_position.type_name() && mapping_b.source_position is SourcePosition { - if - (mapping_a.source_position as SourcePosition).source_line != (mapping_b.source_position as SourcePosition).source_line || (mapping_a.source_position as SourcePosition).source_column != (mapping_b.source_position as SourcePosition).source_column { + if 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 true } } else { @@ -161,8 +161,8 @@ fn compare_by_generated_positions_inflated(mapping_a Mapping, mapping_b Mapping) } if mapping_a.names_ind.type_name() == mapping_b.names_ind.type_name() - && mapping_a.names_ind is IndexNumber { - return (mapping_a.names_ind as IndexNumber) != (mapping_b.names_ind as IndexNumber) + && mapping_a.names_ind is IndexNumber && mapping_b.names_ind is IndexNumber { + return mapping_a.names_ind != mapping_b.names_ind } else { return mapping_a.names_ind.type_name() != mapping_b.names_ind.type_name() } diff --git a/vlib/v/parser/sql.v b/vlib/v/parser/sql.v index 6587614565..28a71570db 100644 --- a/vlib/v/parser/sql.v +++ b/vlib/v/parser/sql.v @@ -34,8 +34,7 @@ fn (mut p Parser) sql_expr() ast.Expr { if !is_count && where_expr is ast.InfixExpr { e := where_expr as ast.InfixExpr if e.op == .eq && e.left is ast.Ident { - ident := e.left as ast.Ident - if ident.name == 'id' { + if e.left.name == 'id' { query_one = true } }