1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker/cgen: interface smart casts

This commit is contained in:
Alexander Medvednikov 2020-08-24 11:10:11 +02:00
parent 912bc8bca1
commit d547f74cb0
3 changed files with 19 additions and 17 deletions

View File

@ -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) 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 { if branch.cond is ast.InfixExpr {
infix := branch.cond as ast.InfixExpr infix := branch.cond as ast.InfixExpr
if infix.op == .key_is && 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 // Register shadow variable or `as` variable with actual type
if is_variable { if is_variable {
left_sym := c.table.get_type_symbol(infix.left_type) 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 is_mut := false
mut scope := c.file.scope.innermost(branch.body_pos.pos) mut scope := c.file.scope.innermost(branch.body_pos.pos)
if infix.left is ast.Ident as infix_left { if infix.left is ast.Ident as infix_left {

View File

@ -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) got_sym := g.table.get_type_symbol(got_type)
if expected_is_ptr && got_is_ptr { if expected_is_ptr && got_is_ptr {
exp_der_styp := g.typ(expected_deref_type) 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.expr(expr)
g.write(', .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))') g.write(', .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))')
} else if expected_is_ptr { } else if expected_is_ptr {
exp_der_styp := g.typ(expected_deref_type) 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.expr(expr)
g.write('}, sizeof($got_styp)), .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))') g.write('}, sizeof($got_styp)), .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))')
} else if got_is_ptr { } 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.expr(expr)
g.write(', .typ = $got_idx /* $got_sym.name */}') g.write(', .typ = $got_idx /* $got_sym.name */}')
} else { } 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.expr(expr)
g.write('}, sizeof($got_styp)), .typ = $got_idx /* $got_sym.name */}') 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) g.expr(node.cond)
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' } dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
g.write(dot_or_ptr) g.write(dot_or_ptr)
g.writeln('obj; // ST it') g.writeln('_object; // ST it')
if node.var_name.len > 0 { if node.var_name.len > 0 {
// for now we just copy it // for now we just copy it
g.writeln('\t$it_type* $node.var_name = it;') g.writeln('\t$it_type* $node.var_name = it;')
@ -2788,7 +2788,7 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
} else { } else {
g.write('.') g.write('.')
} }
g.writeln('obj;') g.writeln('_object;')
g.writeln('\t$it_type* $branch.left_as_name = _sc_tmp_$branch.pos.pos;') g.writeln('\t$it_type* $branch.left_as_name = _sc_tmp_$branch.pos.pos;')
} }
g.stmts(branch.stmts) 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('// | ${sv:4d} = ${g.typ(sv):-20s}')
} }
g.type_definitions.writeln('typedef struct {') 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(' int typ;')
g.type_definitions.writeln('} $name;') g.type_definitions.writeln('} $name;')
g.type_definitions.writeln('') g.type_definitions.writeln('')
@ -4704,7 +4704,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
g.write('/* as */ ($styp*)__as_cast(') g.write('/* as */ ($styp*)__as_cast(')
g.expr(node.expr) g.expr(node.expr)
g.write(dot) g.write(dot)
g.write('obj, ') g.write('_object, ')
g.expr(node.expr) g.expr(node.expr)
g.write(dot) g.write(dot)
g.write('typ, /*expected:*/$node.typ)') g.write('typ, /*expected:*/$node.typ)')

View File

@ -23,7 +23,7 @@ fn (c &Cat) speak(s string) {
} }
fn (c Cat) name_detailed(pet_name string) 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) { 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 { 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) { fn (mut d Dog) set_breed(new string) {
@ -67,10 +67,12 @@ fn perform_speak(a Animal) {
assert name == 'Dog' || name == 'Cat' assert name == 'Dog' || name == 'Cat'
if a is Dog { if a is Dog {
assert name == 'Dog' assert name == 'Dog'
assert a.breed == 'Labrador Retriever' // test smart casting
println(a.breed)
} }
println(a.name()) println(a.name())
println('Got animal of type: ${typeof(a)}') // TODO: get implementation type (if possible) 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) { fn perform_speak_on_ptr(a &Animal) {
@ -78,12 +80,12 @@ fn perform_speak_on_ptr(a &Animal) {
assert true assert true
name := a.name() name := a.name()
assert name == 'Dog' || name == 'Cat' assert name == 'Dog' || name == 'Cat'
// if a is Dog { if a is Dog {
// assert name == 'Dog' assert name == 'Dog'
// } }
println(a.name()) println(a.name())
println('Got animal of type: ${typeof(a)}') // TODO: get implementation type (if possible) 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() { fn test_perform_speak() {