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
)
fn get_webgl() (&JS.HTMLCanvasElement, JS.WebGLRenderingContext) {
fn get_webgl() (JS.HTMLCanvasElement, JS.WebGLRenderingContext) {
JS.console.log(dom.document)
elem := dom.document.getElementById('myCanvas'.str) or { panic('cannot get canvas') }
match elem {

View File

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

View File

@ -294,7 +294,7 @@ pub mut:
// *before* the current event was different
}
fn get_canvas(elem JS.HTMLElement) &JS.HTMLCanvasElement {
fn get_canvas(elem JS.HTMLElement) JS.HTMLCanvasElement {
match elem {
JS.HTMLCanvasElement {
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
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)
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_ }
match mut expr {
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 right_sym.kind != .interface_ {
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 {
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('*')
}
cast_sym := g.table.sym(g.unwrap_generic(typ))
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'
if field_sym.kind == .interface_ && cast_sym.kind == .interface_ {
ptr := '*'.repeat(field.typ.nr_muls())
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))')
return
} 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 {
cast_sym := g.table.sym(g.unwrap_generic(typ))
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')
if obj_sym.kind == .interface_ && cast_sym.kind == .interface_ {
ptr := '*'.repeat(node.obj.typ.nr_muls())
g.write('I_${obj_sym.cname}_as_I_${cast_sym.cname}($ptr$node.name)')
} 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(')')
}

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() {
for wd in w.initables {
if mut wd is Container {
mut c := wd as Container
if wd is Container {
mut c := unsafe { wd }
c.layout()
}
}