From d547f74cb042566e5fd33224c047232e19f91f3d Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Mon, 24 Aug 2020 11:10:11 +0200 Subject: [PATCH] checker/cgen: interface smart casts --- vlib/v/checker/checker.v | 4 ++-- vlib/v/gen/cgen.v | 16 ++++++++-------- vlib/v/tests/interface_test.v | 16 +++++++++------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 536cc1298e..1357d66f63 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2983,7 +2983,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type { c.error('non-bool type `$typ_sym.source_name` used as if condition', branch.pos) } } - // smartcast sumtypes when using `is` + // smartcast sumtypes and interfaces when using `is` if branch.cond is ast.InfixExpr { infix := branch.cond as ast.InfixExpr if infix.op == .key_is && @@ -2994,7 +2994,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type { // Register shadow variable or `as` variable with actual type if is_variable { left_sym := c.table.get_type_symbol(infix.left_type) - if left_sym.kind == .sum_type && branch.left_as_name.len > 0 { + if left_sym.kind in [.sum_type, .interface_] && branch.left_as_name.len > 0 { mut is_mut := false mut scope := c.file.scope.innermost(branch.body_pos.pos) if infix.left is ast.Ident as infix_left { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 7a5a46f76e..259ea6b649 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1134,20 +1134,20 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type, expected_type table.Type) got_sym := g.table.get_type_symbol(got_type) if expected_is_ptr && got_is_ptr { exp_der_styp := g.typ(expected_deref_type) - g.write('/* sum type cast */ ($exp_styp) memdup(&($exp_der_styp){.obj = ') + g.write('/* sum type cast */ ($exp_styp) memdup(&($exp_der_styp){._object = ') g.expr(expr) g.write(', .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))') } else if expected_is_ptr { exp_der_styp := g.typ(expected_deref_type) - g.write('/* sum type cast */ ($exp_styp) memdup(&($exp_der_styp){.obj = memdup(&($got_styp[]) {') + g.write('/* sum type cast */ ($exp_styp) memdup(&($exp_der_styp){._object = memdup(&($got_styp[]) {') g.expr(expr) g.write('}, sizeof($got_styp)), .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))') } else if got_is_ptr { - g.write('/* sum type cast */ ($exp_styp) {.obj = ') + g.write('/* sum type cast */ ($exp_styp) {._object = ') g.expr(expr) g.write(', .typ = $got_idx /* $got_sym.name */}') } else { - g.write('/* sum type cast */ ($exp_styp) {.obj = memdup(&($got_styp[]) {') + g.write('/* sum type cast */ ($exp_styp) {._object = memdup(&($got_styp[]) {') g.expr(expr) g.write('}, sizeof($got_styp)), .typ = $got_idx /* $got_sym.name */}') } @@ -2604,7 +2604,7 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) { g.expr(node.cond) dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' } g.write(dot_or_ptr) - g.writeln('obj; // ST it') + g.writeln('_object; // ST it') if node.var_name.len > 0 { // for now we just copy it g.writeln('\t$it_type* $node.var_name = it;') @@ -2788,7 +2788,7 @@ fn (mut g Gen) if_expr(node ast.IfExpr) { } else { g.write('.') } - g.writeln('obj;') + g.writeln('_object;') g.writeln('\t$it_type* $branch.left_as_name = _sc_tmp_$branch.pos.pos;') } g.stmts(branch.stmts) @@ -3773,7 +3773,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) { g.type_definitions.writeln('// | ${sv:4d} = ${g.typ(sv):-20s}') } g.type_definitions.writeln('typedef struct {') - g.type_definitions.writeln(' void* obj;') + g.type_definitions.writeln(' void* _object;') g.type_definitions.writeln(' int typ;') g.type_definitions.writeln('} $name;') g.type_definitions.writeln('') @@ -4704,7 +4704,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) { g.write('/* as */ ($styp*)__as_cast(') g.expr(node.expr) g.write(dot) - g.write('obj, ') + g.write('_object, ') g.expr(node.expr) g.write(dot) g.write('typ, /*expected:*/$node.typ)') diff --git a/vlib/v/tests/interface_test.v b/vlib/v/tests/interface_test.v index 3e4d3160d2..67c5f09374 100644 --- a/vlib/v/tests/interface_test.v +++ b/vlib/v/tests/interface_test.v @@ -23,7 +23,7 @@ fn (c &Cat) speak(s string) { } fn (c Cat) name_detailed(pet_name string) string { - return '$pet_name the ${typeof(c)}, breed:${c.breed}' + return '$pet_name the ${typeof(c)}, breed:$c.breed' } fn (mut c Cat) set_breed(new string) { @@ -46,7 +46,7 @@ fn (d Dog) name() string { } fn (d Dog) name_detailed(pet_name string) string { - return '$pet_name the ${typeof(d)}, breed:${d.breed}' + return '$pet_name the ${typeof(d)}, breed:$d.breed' } fn (mut d Dog) set_breed(new string) { @@ -67,10 +67,12 @@ fn perform_speak(a Animal) { assert name == 'Dog' || name == 'Cat' if a is Dog { assert name == 'Dog' + assert a.breed == 'Labrador Retriever' // test smart casting + println(a.breed) } println(a.name()) println('Got animal of type: ${typeof(a)}') // TODO: get implementation type (if possible) - // assert a is Dog || a is Cat // TODO: enable when available + assert a is Dog || a is Cat } fn perform_speak_on_ptr(a &Animal) { @@ -78,12 +80,12 @@ fn perform_speak_on_ptr(a &Animal) { assert true name := a.name() assert name == 'Dog' || name == 'Cat' - // if a is Dog { - // assert name == 'Dog' - // } + if a is Dog { + assert name == 'Dog' + } println(a.name()) println('Got animal of type: ${typeof(a)}') // TODO: get implementation type (if possible) - // assert a is Dog || a is Cat // TODO: enable when available + assert a is Dog || a is Cat } fn test_perform_speak() {