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

checker, cgen: fix interface embedding smartcast (fix #13296) (#15127)

This commit is contained in:
yuyi 2022-07-19 21:36:16 +08:00 committed by GitHub
parent 0afa2f76c8
commit 041e90b2e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 89 additions and 28 deletions

View File

@ -197,7 +197,7 @@ const (
amortization = 0.95 amortization = 0.95
) )
fn get_webgl() (&JS.HTMLCanvasElement, JS.WebGLRenderingContext) { fn get_webgl() (JS.HTMLCanvasElement, JS.WebGLRenderingContext) {
JS.console.log(dom.document) JS.console.log(dom.document)
elem := dom.document.getElementById('myCanvas'.str) or { panic('cannot get canvas') } elem := dom.document.getElementById('myCanvas'.str) or { panic('cannot get canvas') }
match elem { match elem {

View File

@ -1,6 +1,6 @@
import js.dom import js.dom
fn get_canvas(elem JS.HTMLElement) &JS.HTMLCanvasElement { fn get_canvas(elem JS.HTMLElement) JS.HTMLCanvasElement {
match elem { match elem {
JS.HTMLCanvasElement { JS.HTMLCanvasElement {
return elem return elem

View File

@ -294,7 +294,7 @@ pub mut:
// *before* the current event was different // *before* the current event was different
} }
fn get_canvas(elem JS.HTMLElement) &JS.HTMLCanvasElement { fn get_canvas(elem JS.HTMLElement) JS.HTMLCanvasElement {
match elem { match elem {
JS.HTMLCanvasElement { JS.HTMLCanvasElement {
return elem return elem

View File

@ -2903,7 +2903,11 @@ pub fn (mut c Checker) concat_expr(mut node ast.ConcatExpr) ast.Type {
// smartcast takes the expression with the current type which should be smartcasted to the target type in the given scope // smartcast takes the expression with the current type which should be smartcasted to the target type in the given scope
fn (mut c Checker) smartcast(expr_ ast.Expr, cur_type ast.Type, to_type_ ast.Type, mut scope ast.Scope) { fn (mut c Checker) smartcast(expr_ ast.Expr, cur_type ast.Type, to_type_ ast.Type, mut scope ast.Scope) {
sym := c.table.sym(cur_type) sym := c.table.sym(cur_type)
to_type := if sym.kind == .interface_ { to_type_.ref() } else { to_type_ } to_type := if sym.kind == .interface_ && c.table.sym(to_type_).kind != .interface_ {
to_type_.ref()
} else {
to_type_
}
mut expr := unsafe { expr_ } mut expr := unsafe { expr_ }
match mut expr { match mut expr {
ast.SelectorExpr { ast.SelectorExpr {

View File

@ -311,8 +311,6 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) {
if left_sym.kind == .interface_ { if left_sym.kind == .interface_ {
if right_sym.kind != .interface_ { if right_sym.kind != .interface_ {
c.type_implements(right_type, expr_type, node.pos) c.type_implements(right_type, expr_type, node.pos)
} else {
return
} }
} else if !c.check_types(right_type, expr_type) && left_sym.kind != .sum_type { } else if !c.check_types(right_type, expr_type) && left_sym.kind != .sum_type {
expect_str := c.table.type_to_str(right_type) expect_str := c.table.type_to_str(right_type)

View File

@ -3331,15 +3331,22 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
g.write('*') g.write('*')
} }
cast_sym := g.table.sym(g.unwrap_generic(typ)) cast_sym := g.table.sym(g.unwrap_generic(typ))
if i != 0 { if field_sym.kind == .interface_ && cast_sym.kind == .interface_ {
dot := if field.typ.is_ptr() { '->' } else { '.' } ptr := '*'.repeat(field.typ.nr_muls())
sum_type_deref_field += ')$dot' dot := if node.expr_type.is_ptr() { '->' } else { '.' }
} g.write('I_${field_sym.cname}_as_I_${cast_sym.cname}($ptr$node.expr$dot$node.field_name))')
if cast_sym.info is ast.Aggregate { return
agg_sym := g.table.sym(cast_sym.info.types[g.aggregate_type_idx])
sum_type_deref_field += '_$agg_sym.cname'
} else { } else {
sum_type_deref_field += '_$cast_sym.cname' if i != 0 {
dot := if field.typ.is_ptr() { '->' } else { '.' }
sum_type_deref_field += ')$dot'
}
if cast_sym.info is ast.Aggregate {
agg_sym := g.table.sym(cast_sym.info.types[g.aggregate_type_idx])
sum_type_deref_field += '_$agg_sym.cname'
} else {
sum_type_deref_field += '_$cast_sym.cname'
}
} }
} }
} }
@ -3894,19 +3901,24 @@ fn (mut g Gen) ident(node ast.Ident) {
} }
for i, typ in node.obj.smartcasts { for i, typ in node.obj.smartcasts {
cast_sym := g.table.sym(g.unwrap_generic(typ)) cast_sym := g.table.sym(g.unwrap_generic(typ))
mut is_ptr := false if obj_sym.kind == .interface_ && cast_sym.kind == .interface_ {
if i == 0 { ptr := '*'.repeat(node.obj.typ.nr_muls())
g.write(name) g.write('I_${obj_sym.cname}_as_I_${cast_sym.cname}($ptr$node.name)')
if node.obj.orig_type.is_ptr() {
is_ptr = true
}
}
dot := if is_ptr || is_auto_heap { '->' } else { '.' }
if cast_sym.info is ast.Aggregate {
sym := g.table.sym(cast_sym.info.types[g.aggregate_type_idx])
g.write('${dot}_$sym.cname')
} else { } else {
g.write('${dot}_$cast_sym.cname') mut is_ptr := false
if i == 0 {
g.write(name)
if node.obj.orig_type.is_ptr() {
is_ptr = true
}
}
dot := if is_ptr || is_auto_heap { '->' } else { '.' }
if cast_sym.info is ast.Aggregate {
sym := g.table.sym(cast_sym.info.types[g.aggregate_type_idx])
g.write('${dot}_$sym.cname')
} else {
g.write('${dot}_$cast_sym.cname')
}
} }
g.write(')') g.write(')')
} }

View File

@ -0,0 +1,47 @@
// Common interface to all error custom types.
interface ESpeaker {
IError
speak() string
}
// One custom error implementation.
struct MyError {
// Mandatory fields from IError.
msg string
code int
// Custom field.
blah string
}
// Interface implementation for this example custom type.
fn (e MyError) speak() string {
return e.blah
}
fn (e MyError) msg() string {
return e.msg
}
fn (e MyError) code() int {
return e.code
}
// An example function that returns a custom error.
fn foo() ?string {
return IError(MyError{
msg: 'foo'
blah: 'world'
})
}
fn test_interface_embedding_smartcast() {
x := foo() or {
if err is ESpeaker {
err.speak()
} else {
'undefined'
}
}
println(x)
assert x == 'world'
}

View File

@ -34,8 +34,8 @@ mut:
fn (mut w Window) init() { fn (mut w Window) init() {
for wd in w.initables { for wd in w.initables {
if mut wd is Container { if wd is Container {
mut c := wd as Container mut c := unsafe { wd }
c.layout() c.layout()
} }
} }