mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
v: implement interface embedding (#9935)
This commit is contained in:
parent
3363c3ef65
commit
4b818fa2be
@ -260,18 +260,31 @@ pub:
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub struct InterfaceEmbedding {
|
||||
pub:
|
||||
name string
|
||||
typ Type
|
||||
pos token.Position
|
||||
comments []Comment
|
||||
}
|
||||
|
||||
pub struct InterfaceDecl {
|
||||
pub:
|
||||
name string
|
||||
typ Type
|
||||
name_pos token.Position
|
||||
language Language
|
||||
field_names []string
|
||||
is_pub bool
|
||||
methods []FnDecl
|
||||
mut_pos int // mut:
|
||||
fields []StructField
|
||||
pos token.Position
|
||||
pre_comments []Comment
|
||||
pub mut:
|
||||
methods []FnDecl
|
||||
fields []StructField
|
||||
//
|
||||
ifaces []InterfaceEmbedding
|
||||
are_ifaces_expanded bool
|
||||
}
|
||||
|
||||
pub struct StructInitField {
|
||||
@ -352,7 +365,6 @@ pub struct FnDecl {
|
||||
pub:
|
||||
name string
|
||||
mod string
|
||||
params []Param
|
||||
is_deprecated bool
|
||||
is_pub bool
|
||||
is_variadic bool
|
||||
@ -379,6 +391,7 @@ pub:
|
||||
attrs []Attr
|
||||
skip_gen bool // this function doesn't need to be generated (for example [if foo])
|
||||
pub mut:
|
||||
params []Param
|
||||
stmts []Stmt
|
||||
defer_stmts []DeferStmt
|
||||
return_type Type
|
||||
|
@ -19,6 +19,7 @@ pub mut:
|
||||
cflags []cflag.CFlag
|
||||
redefined_fns []string
|
||||
fn_generic_types map[string][][]Type // for generic functions
|
||||
interfaces map[int]InterfaceDecl
|
||||
cmod_prefix string // needed for ast.type_to_str(Type) while vfmt; contains `os.`
|
||||
is_fmt bool
|
||||
used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||
@ -60,7 +61,6 @@ pub fn (t &Table) panic(message string) {
|
||||
|
||||
pub struct Fn {
|
||||
pub:
|
||||
params []Param
|
||||
return_type Type
|
||||
is_variadic bool
|
||||
language Language
|
||||
@ -77,8 +77,12 @@ pub:
|
||||
mod string
|
||||
ctdefine string // compile time define. "myflag", when [if myflag] tag
|
||||
attrs []Attr
|
||||
//
|
||||
pos token.Position
|
||||
return_type_pos token.Position
|
||||
pub mut:
|
||||
name string
|
||||
params []Param
|
||||
source_fn voidptr // set in the checker, while processing fn declarations
|
||||
usages int
|
||||
}
|
||||
@ -96,9 +100,24 @@ pub:
|
||||
name string
|
||||
is_mut bool
|
||||
is_auto_rec bool
|
||||
typ Type
|
||||
type_pos token.Position
|
||||
is_hidden bool // interface first arg
|
||||
pub mut:
|
||||
typ Type
|
||||
}
|
||||
|
||||
pub fn (f Fn) new_method_with_receiver_type(new_type Type) Fn {
|
||||
mut new_method := f
|
||||
new_method.params = f.params.clone()
|
||||
new_method.params[0].typ = new_type
|
||||
return new_method
|
||||
}
|
||||
|
||||
pub fn (f FnDecl) new_method_with_receiver_type(new_type Type) FnDecl {
|
||||
mut new_method := f
|
||||
new_method.params = f.params.clone()
|
||||
new_method.params[0].typ = new_type
|
||||
return new_method
|
||||
}
|
||||
|
||||
fn (p &Param) equals(o &Param) bool {
|
||||
@ -213,6 +232,10 @@ pub fn (mut t Table) register_fn(new_fn Fn) {
|
||||
t.fns[new_fn.name] = new_fn
|
||||
}
|
||||
|
||||
pub fn (mut t Table) register_interface(idecl InterfaceDecl) {
|
||||
t.interfaces[idecl.typ] = idecl
|
||||
}
|
||||
|
||||
pub fn (mut t TypeSymbol) register_method(new_fn Fn) int {
|
||||
// returns a method index, stored in the ast.FnDecl
|
||||
// for faster lookup in the checker's fn_decl method
|
||||
|
@ -734,6 +734,7 @@ pub mut:
|
||||
types []Type
|
||||
fields []StructField
|
||||
methods []Fn
|
||||
ifaces []Type
|
||||
}
|
||||
|
||||
pub struct Enum {
|
||||
|
@ -360,25 +360,152 @@ pub fn (mut c Checker) sum_type_decl(node ast.SumTypeDecl) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) interface_decl(decl ast.InterfaceDecl) {
|
||||
c.check_valid_pascal_case(decl.name, 'interface name', decl.pos)
|
||||
for method in decl.methods {
|
||||
if decl.language == .v {
|
||||
c.check_valid_snake_case(method.name, 'method name', method.pos)
|
||||
}
|
||||
c.ensure_type_exists(method.return_type, method.return_type_pos) or { return }
|
||||
for param in method.params {
|
||||
c.ensure_type_exists(param.typ, param.pos) or { return }
|
||||
}
|
||||
pub fn (mut c Checker) expand_iface_embeds(idecl &ast.InterfaceDecl, level int, iface_embeds []ast.InterfaceEmbedding) []ast.InterfaceEmbedding {
|
||||
// eprintln('> expand_iface_embeds: idecl.name: $idecl.name | level: $level | iface_embeds.len: $iface_embeds.len')
|
||||
if level > 100 {
|
||||
c.error('too many interface embedding levels: $level, for interface `$idecl.name`',
|
||||
idecl.pos)
|
||||
return []
|
||||
}
|
||||
for i, field in decl.fields {
|
||||
if decl.language == .v {
|
||||
c.check_valid_snake_case(field.name, 'field name', field.pos)
|
||||
if iface_embeds.len == 0 {
|
||||
return []
|
||||
}
|
||||
mut res := map[int]ast.InterfaceEmbedding{}
|
||||
mut ares := []ast.InterfaceEmbedding{}
|
||||
for ie in iface_embeds {
|
||||
if iface_decl := c.table.interfaces[ie.typ] {
|
||||
mut list := iface_decl.ifaces
|
||||
if !iface_decl.are_ifaces_expanded {
|
||||
list = c.expand_iface_embeds(idecl, level + 1, iface_decl.ifaces)
|
||||
c.table.interfaces[ie.typ].ifaces = list
|
||||
c.table.interfaces[ie.typ].are_ifaces_expanded = true
|
||||
}
|
||||
for partial in list {
|
||||
res[partial.typ] = partial
|
||||
}
|
||||
}
|
||||
c.ensure_type_exists(field.typ, field.pos) or { return }
|
||||
for j in 0 .. i {
|
||||
if field.name == decl.fields[j].name {
|
||||
c.error('field name `$field.name` duplicate', field.pos)
|
||||
res[ie.typ] = ie
|
||||
}
|
||||
for _, v in res {
|
||||
ares << v
|
||||
}
|
||||
return ares
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) interface_decl(mut decl ast.InterfaceDecl) {
|
||||
c.check_valid_pascal_case(decl.name, 'interface name', decl.pos)
|
||||
mut decl_sym := c.table.get_type_symbol(decl.typ)
|
||||
if mut decl_sym.info is ast.Interface {
|
||||
if decl.ifaces.len > 0 {
|
||||
all_ifaces := c.expand_iface_embeds(decl, 0, decl.ifaces)
|
||||
// eprintln('> decl.name: $decl.name | decl.ifaces.len: $decl.ifaces.len | all_ifaces: $all_ifaces.len')
|
||||
decl.ifaces = all_ifaces
|
||||
mut emnames := map[string]int{}
|
||||
mut emnames_ds := map[string]bool{}
|
||||
mut emnames_ds_info := map[string]bool{}
|
||||
mut efnames := map[string]int{}
|
||||
mut efnames_ds_info := map[string]bool{}
|
||||
for i, m in decl.methods {
|
||||
emnames[m.name] = i
|
||||
emnames_ds[m.name] = true
|
||||
emnames_ds_info[m.name] = true
|
||||
}
|
||||
for i, f in decl.fields {
|
||||
efnames[f.name] = i
|
||||
efnames_ds_info[f.name] = true
|
||||
}
|
||||
//
|
||||
for iface in all_ifaces {
|
||||
isym := c.table.get_type_symbol(iface.typ)
|
||||
if isym.kind != .interface_ {
|
||||
c.error('interface `$decl.name` tries to embed `$isym.name`, but `$isym.name` is not an interface, but `$isym.kind`',
|
||||
iface.pos)
|
||||
continue
|
||||
}
|
||||
for f in isym.info.fields {
|
||||
if !efnames_ds_info[f.name] {
|
||||
efnames_ds_info[f.name] = true
|
||||
decl_sym.info.fields << f
|
||||
}
|
||||
}
|
||||
for m in isym.info.methods {
|
||||
if !emnames_ds_info[m.name] {
|
||||
emnames_ds_info[m.name] = true
|
||||
decl_sym.info.methods << m.new_method_with_receiver_type(decl.typ)
|
||||
}
|
||||
}
|
||||
for m in isym.methods {
|
||||
if !emnames_ds[m.name] {
|
||||
emnames_ds[m.name] = true
|
||||
decl_sym.methods << m.new_method_with_receiver_type(decl.typ)
|
||||
}
|
||||
}
|
||||
if iface_decl := c.table.interfaces[iface.typ] {
|
||||
for f in iface_decl.fields {
|
||||
if f.name in efnames {
|
||||
// already existing method name, check for conflicts
|
||||
ifield := decl.fields[efnames[f.name]]
|
||||
if field := c.table.find_field_with_embeds(isym, f.name) {
|
||||
if ifield.typ != field.typ {
|
||||
exp := c.table.type_to_str(ifield.typ)
|
||||
got := c.table.type_to_str(field.typ)
|
||||
c.error('embedded interface `$iface_decl.name` conflicts existing field: `$ifield.name`, expecting type: `$exp`, got type: `$got`',
|
||||
ifield.pos)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
efnames[f.name] = decl.fields.len
|
||||
decl.fields << f
|
||||
}
|
||||
}
|
||||
for m in iface_decl.methods {
|
||||
if m.name in emnames {
|
||||
// already existing field name, check for conflicts
|
||||
imethod := decl.methods[emnames[m.name]]
|
||||
if em_fn := decl_sym.find_method(imethod.name) {
|
||||
if m_fn := isym.find_method(m.name) {
|
||||
msg := c.table.is_same_method(m_fn, em_fn)
|
||||
if msg.len > 0 {
|
||||
em_sig := c.table.fn_signature(em_fn, skip_receiver: true)
|
||||
m_sig := c.table.fn_signature(m_fn, skip_receiver: true)
|
||||
c.error('embedded interface `$iface_decl.name` causes conflict: $msg, for interface method `$em_sig` vs `$m_sig`',
|
||||
imethod.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
emnames[m.name] = decl.methods.len
|
||||
mut new_method := m.new_method_with_receiver_type(decl.typ)
|
||||
new_method.pos = iface.pos
|
||||
decl.methods << new_method
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, method in decl.methods {
|
||||
if decl.language == .v {
|
||||
c.check_valid_snake_case(method.name, 'method name', method.pos)
|
||||
}
|
||||
c.ensure_type_exists(method.return_type, method.return_type_pos) or { return }
|
||||
for param in method.params {
|
||||
c.ensure_type_exists(param.typ, param.pos) or { return }
|
||||
}
|
||||
for j in 0 .. i {
|
||||
if method.name == decl.methods[j].name {
|
||||
c.error('duplicate method name `$method.name`', method.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, field in decl.fields {
|
||||
if decl.language == .v {
|
||||
c.check_valid_snake_case(field.name, 'field name', field.pos)
|
||||
}
|
||||
c.ensure_type_exists(field.typ, field.pos) or { return }
|
||||
for j in 0 .. i {
|
||||
if field.name == decl.fields[j].name {
|
||||
c.error('field name `$field.name` duplicate', field.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3660,7 +3787,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
||||
c.import_stmt(node)
|
||||
}
|
||||
ast.InterfaceDecl {
|
||||
c.interface_decl(node)
|
||||
c.interface_decl(mut node)
|
||||
}
|
||||
ast.Module {
|
||||
c.mod = node.name
|
||||
@ -6319,6 +6446,11 @@ pub fn (mut c Checker) warn(s string, pos token.Position) {
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) error(message string, pos token.Position) {
|
||||
$if checker_exit_on_first_error ? {
|
||||
eprintln('\n\n>> checker error: $message, pos: $pos')
|
||||
print_backtrace()
|
||||
exit(1)
|
||||
}
|
||||
if c.pref.translated && message.starts_with('mismatched types') {
|
||||
// TODO move this
|
||||
return
|
||||
|
@ -0,0 +1,7 @@
|
||||
vlib/v/checker/tests/interface_too_many_embedding_levels.vv:9:1: error: too many interface embedding levels: 101, for interface `I103`
|
||||
7 | }
|
||||
8 |
|
||||
9 | interface I103 {
|
||||
| ~~~~~~~~~~~~~~~~
|
||||
10 | I102
|
||||
11 | }
|
431
vlib/v/checker/tests/interface_too_many_embedding_levels.vv
Normal file
431
vlib/v/checker/tests/interface_too_many_embedding_levels.vv
Normal file
@ -0,0 +1,431 @@
|
||||
interface I1 {
|
||||
I0
|
||||
}
|
||||
|
||||
interface I2 {
|
||||
I1
|
||||
}
|
||||
|
||||
interface I103 {
|
||||
I102
|
||||
}
|
||||
|
||||
interface I102 {
|
||||
I101
|
||||
}
|
||||
|
||||
interface I101 {
|
||||
I100
|
||||
}
|
||||
|
||||
interface I3 {
|
||||
I2
|
||||
}
|
||||
|
||||
interface I4 {
|
||||
I3
|
||||
}
|
||||
|
||||
interface I5 {
|
||||
I4
|
||||
}
|
||||
|
||||
interface I6 {
|
||||
I5
|
||||
}
|
||||
|
||||
interface I7 {
|
||||
I6
|
||||
}
|
||||
|
||||
interface I8 {
|
||||
I7
|
||||
}
|
||||
|
||||
interface I9 {
|
||||
I8
|
||||
}
|
||||
|
||||
interface I10 {
|
||||
I9
|
||||
}
|
||||
|
||||
interface I11 {
|
||||
I10
|
||||
}
|
||||
|
||||
interface I12 {
|
||||
I11
|
||||
}
|
||||
|
||||
interface I13 {
|
||||
I12
|
||||
}
|
||||
|
||||
interface I14 {
|
||||
I13
|
||||
}
|
||||
|
||||
interface I15 {
|
||||
I14
|
||||
}
|
||||
|
||||
interface I16 {
|
||||
I15
|
||||
}
|
||||
|
||||
interface I17 {
|
||||
I16
|
||||
}
|
||||
|
||||
interface I18 {
|
||||
I17
|
||||
}
|
||||
|
||||
interface I19 {
|
||||
I18
|
||||
}
|
||||
|
||||
interface I20 {
|
||||
I19
|
||||
}
|
||||
|
||||
interface I21 {
|
||||
I20
|
||||
}
|
||||
|
||||
interface I22 {
|
||||
I21
|
||||
}
|
||||
|
||||
interface I23 {
|
||||
I22
|
||||
}
|
||||
|
||||
interface I24 {
|
||||
I23
|
||||
}
|
||||
|
||||
interface I25 {
|
||||
I24
|
||||
}
|
||||
|
||||
interface I26 {
|
||||
I25
|
||||
}
|
||||
|
||||
interface I27 {
|
||||
I26
|
||||
}
|
||||
|
||||
interface I28 {
|
||||
I27
|
||||
}
|
||||
|
||||
interface I29 {
|
||||
I28
|
||||
}
|
||||
|
||||
interface I30 {
|
||||
I29
|
||||
}
|
||||
|
||||
interface I31 {
|
||||
I30
|
||||
}
|
||||
|
||||
interface I32 {
|
||||
I31
|
||||
}
|
||||
|
||||
interface I33 {
|
||||
I32
|
||||
}
|
||||
|
||||
interface I34 {
|
||||
I33
|
||||
}
|
||||
|
||||
interface I35 {
|
||||
I34
|
||||
}
|
||||
|
||||
interface I36 {
|
||||
I35
|
||||
}
|
||||
|
||||
interface I37 {
|
||||
I36
|
||||
}
|
||||
|
||||
interface I38 {
|
||||
I37
|
||||
}
|
||||
|
||||
interface I39 {
|
||||
I38
|
||||
}
|
||||
|
||||
interface I40 {
|
||||
I39
|
||||
}
|
||||
|
||||
interface I41 {
|
||||
I40
|
||||
}
|
||||
|
||||
interface I42 {
|
||||
I41
|
||||
}
|
||||
|
||||
interface I43 {
|
||||
I42
|
||||
}
|
||||
|
||||
interface I44 {
|
||||
I43
|
||||
}
|
||||
|
||||
interface I45 {
|
||||
I44
|
||||
}
|
||||
|
||||
interface I46 {
|
||||
I45
|
||||
}
|
||||
|
||||
interface I47 {
|
||||
I46
|
||||
}
|
||||
|
||||
interface I48 {
|
||||
I47
|
||||
}
|
||||
|
||||
interface I49 {
|
||||
I48
|
||||
}
|
||||
|
||||
interface I50 {
|
||||
I49
|
||||
}
|
||||
|
||||
interface I51 {
|
||||
I50
|
||||
}
|
||||
|
||||
interface I52 {
|
||||
I51
|
||||
}
|
||||
|
||||
interface I53 {
|
||||
I52
|
||||
}
|
||||
|
||||
interface I54 {
|
||||
I53
|
||||
}
|
||||
|
||||
interface I55 {
|
||||
I54
|
||||
}
|
||||
|
||||
interface I56 {
|
||||
I55
|
||||
}
|
||||
|
||||
interface I57 {
|
||||
I56
|
||||
}
|
||||
|
||||
interface I58 {
|
||||
I57
|
||||
}
|
||||
|
||||
interface I59 {
|
||||
I58
|
||||
}
|
||||
|
||||
interface I60 {
|
||||
I59
|
||||
}
|
||||
|
||||
interface I61 {
|
||||
I60
|
||||
}
|
||||
|
||||
interface I62 {
|
||||
I61
|
||||
}
|
||||
|
||||
interface I63 {
|
||||
I62
|
||||
}
|
||||
|
||||
interface I64 {
|
||||
I63
|
||||
}
|
||||
|
||||
interface I65 {
|
||||
I64
|
||||
}
|
||||
|
||||
interface I66 {
|
||||
I65
|
||||
}
|
||||
|
||||
interface I67 {
|
||||
I66
|
||||
}
|
||||
|
||||
interface I68 {
|
||||
I67
|
||||
}
|
||||
|
||||
interface I69 {
|
||||
I68
|
||||
}
|
||||
|
||||
interface I70 {
|
||||
I69
|
||||
}
|
||||
|
||||
interface I71 {
|
||||
I70
|
||||
}
|
||||
|
||||
interface I72 {
|
||||
I71
|
||||
}
|
||||
|
||||
interface I73 {
|
||||
I72
|
||||
}
|
||||
|
||||
interface I74 {
|
||||
I73
|
||||
}
|
||||
|
||||
interface I75 {
|
||||
I74
|
||||
}
|
||||
|
||||
interface I76 {
|
||||
I75
|
||||
}
|
||||
|
||||
interface I77 {
|
||||
I76
|
||||
}
|
||||
|
||||
interface I78 {
|
||||
I77
|
||||
}
|
||||
|
||||
interface I79 {
|
||||
I78
|
||||
}
|
||||
|
||||
interface I80 {
|
||||
I79
|
||||
}
|
||||
|
||||
interface I81 {
|
||||
I80
|
||||
}
|
||||
|
||||
interface I82 {
|
||||
I81
|
||||
}
|
||||
|
||||
interface I83 {
|
||||
I82
|
||||
}
|
||||
|
||||
interface I84 {
|
||||
I83
|
||||
}
|
||||
|
||||
interface I85 {
|
||||
I84
|
||||
}
|
||||
|
||||
interface I86 {
|
||||
I85
|
||||
}
|
||||
|
||||
interface I87 {
|
||||
I86
|
||||
}
|
||||
|
||||
interface I88 {
|
||||
I87
|
||||
}
|
||||
|
||||
interface I89 {
|
||||
I88
|
||||
}
|
||||
|
||||
interface I90 {
|
||||
I89
|
||||
}
|
||||
|
||||
interface I91 {
|
||||
I90
|
||||
}
|
||||
|
||||
interface I92 {
|
||||
I91
|
||||
}
|
||||
|
||||
interface I93 {
|
||||
I92
|
||||
}
|
||||
|
||||
interface I94 {
|
||||
I93
|
||||
}
|
||||
|
||||
interface I95 {
|
||||
I94
|
||||
}
|
||||
|
||||
interface I96 {
|
||||
I95
|
||||
}
|
||||
|
||||
interface I97 {
|
||||
I96
|
||||
}
|
||||
|
||||
interface I98 {
|
||||
I97
|
||||
}
|
||||
|
||||
interface I99 {
|
||||
I98
|
||||
}
|
||||
|
||||
interface I100 {
|
||||
I99
|
||||
}
|
||||
|
||||
interface I0 {
|
||||
m999() int
|
||||
}
|
||||
|
||||
struct Abc {
|
||||
x int = 123
|
||||
}
|
||||
|
||||
fn (s Abc) m999() int {
|
||||
return 999
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := Abc{}
|
||||
dump(a)
|
||||
i := I103(a)
|
||||
dump(i)
|
||||
assert i.m999() == 999
|
||||
}
|
@ -1180,6 +1180,11 @@ pub fn (mut f Fmt) interface_decl(node ast.InterfaceDecl) {
|
||||
f.writeln('')
|
||||
}
|
||||
f.comments_after_last_field(node.pre_comments)
|
||||
for iface in node.ifaces {
|
||||
f.write('\t$iface.name')
|
||||
f.comments(iface.comments, inline: true, has_nl: false, level: .indent)
|
||||
f.writeln('')
|
||||
}
|
||||
for i, field in node.fields {
|
||||
if i == node.mut_pos {
|
||||
f.writeln('mut:')
|
||||
|
@ -6386,9 +6386,9 @@ $staticprefix inline $interface_name I_${cctype}_to_Interface_${interface_name}(
|
||||
// .speak = Cat_speak
|
||||
mut method_call := '${cctype}_$method.name'
|
||||
if !method.params[0].typ.is_ptr() {
|
||||
// inline void Cat_speak_method_wrapper(Cat c) { return Cat_speak(*c); }
|
||||
methods_wrapper.write_string('static inline ${g.typ(method.return_type)}')
|
||||
methods_wrapper.write_string(' ${method_call}_method_wrapper(')
|
||||
// inline void Cat_speak_Interface_Animal_method_wrapper(Cat c) { return Cat_speak(*c); }
|
||||
iwpostfix := '_Interface_${interface_name}_method_wrapper'
|
||||
methods_wrapper.write_string('static inline ${g.typ(method.return_type)} $method_call${iwpostfix}(')
|
||||
//
|
||||
params_start_pos := g.out.len
|
||||
mut params := method.params.clone()
|
||||
@ -6406,8 +6406,8 @@ $staticprefix inline $interface_name I_${cctype}_to_Interface_${interface_name}(
|
||||
}
|
||||
methods_wrapper.writeln('${method_call}(*${fargs.join(', ')});')
|
||||
methods_wrapper.writeln('}')
|
||||
// .speak = Cat_speak_method_wrapper
|
||||
method_call += '_method_wrapper'
|
||||
// .speak = Cat_speak_Interface_Animal_method_wrapper
|
||||
method_call += iwpostfix
|
||||
}
|
||||
if g.pref.build_mode != .build_module {
|
||||
methods_struct.writeln('\t\t._method_${c_name(method.name)} = (void*) $method_call,')
|
||||
|
@ -483,7 +483,24 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||
mut methods := []ast.FnDecl{cap: 20}
|
||||
mut is_mut := false
|
||||
mut mut_pos := -1
|
||||
mut ifaces := []ast.InterfaceEmbedding{}
|
||||
for p.tok.kind != .rcbr && p.tok.kind != .eof {
|
||||
if p.tok.kind == .name && p.tok.lit.len > 0 && p.tok.lit[0].is_capital() {
|
||||
iface_pos := p.tok.position()
|
||||
iface_name := p.tok.lit
|
||||
iface_type := p.parse_type()
|
||||
comments := p.eat_comments({})
|
||||
ifaces << ast.InterfaceEmbedding{
|
||||
name: iface_name
|
||||
typ: iface_type
|
||||
pos: iface_pos
|
||||
comments: comments
|
||||
}
|
||||
if p.tok.kind == .rcbr {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
if p.tok.kind == .key_mut {
|
||||
if is_mut {
|
||||
p.error_with_pos('redefinition of `mut` section', p.tok.position())
|
||||
@ -498,6 +515,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||
method_start_pos := p.tok.position()
|
||||
line_nr := p.tok.line_nr
|
||||
name := p.check_name()
|
||||
|
||||
if name == 'type_name' {
|
||||
p.error_with_pos('cannot override built-in method `type_name`', method_start_pos)
|
||||
return ast.InterfaceDecl{}
|
||||
@ -545,6 +563,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||
tmethod := ast.Fn{
|
||||
name: name
|
||||
params: args
|
||||
pos: method.pos
|
||||
return_type: method.return_type
|
||||
is_variadic: is_variadic
|
||||
is_pub: true
|
||||
@ -581,19 +600,24 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||
}
|
||||
}
|
||||
}
|
||||
info.ifaces = ifaces.map(it.typ)
|
||||
ts.info = info
|
||||
p.top_level_statement_end()
|
||||
p.check(.rcbr)
|
||||
pos = pos.extend_with_last_line(p.prev_tok.position(), p.prev_tok.line_nr)
|
||||
return ast.InterfaceDecl{
|
||||
res := ast.InterfaceDecl{
|
||||
name: interface_name
|
||||
language: language
|
||||
typ: typ
|
||||
fields: fields
|
||||
methods: methods
|
||||
ifaces: ifaces
|
||||
is_pub: is_pub
|
||||
pos: pos
|
||||
pre_comments: pre_comments
|
||||
mut_pos: mut_pos
|
||||
name_pos: name_pos
|
||||
}
|
||||
p.table.register_interface(res)
|
||||
return res
|
||||
}
|
||||
|
@ -24,6 +24,9 @@ pub fn (prefs &Preferences) should_compile_filtered_files(dir string, files_ []s
|
||||
if prefs.backend != .js && !prefs.should_compile_asm(file) {
|
||||
continue
|
||||
}
|
||||
if file.starts_with('.#') {
|
||||
continue
|
||||
}
|
||||
if file.contains('_d_') {
|
||||
if prefs.compile_defines_all.len == 0 {
|
||||
continue
|
||||
|
415
vlib/v/tests/interface_embedding_deep_nesting_test.v
Normal file
415
vlib/v/tests/interface_embedding_deep_nesting_test.v
Normal file
@ -0,0 +1,415 @@
|
||||
interface I99 {
|
||||
I98
|
||||
}
|
||||
|
||||
interface I1 {
|
||||
I0
|
||||
}
|
||||
|
||||
interface I2 {
|
||||
I1
|
||||
}
|
||||
|
||||
interface I3 {
|
||||
I2
|
||||
}
|
||||
|
||||
interface I4 {
|
||||
I3
|
||||
}
|
||||
|
||||
interface I5 {
|
||||
I4
|
||||
}
|
||||
|
||||
interface I6 {
|
||||
I5
|
||||
}
|
||||
|
||||
interface I7 {
|
||||
I6
|
||||
}
|
||||
|
||||
interface I8 {
|
||||
I7
|
||||
}
|
||||
|
||||
interface I9 {
|
||||
I8
|
||||
}
|
||||
|
||||
interface I10 {
|
||||
I9
|
||||
}
|
||||
|
||||
interface I11 {
|
||||
I10
|
||||
}
|
||||
|
||||
interface I12 {
|
||||
I11
|
||||
}
|
||||
|
||||
interface I13 {
|
||||
I12
|
||||
}
|
||||
|
||||
interface I14 {
|
||||
I13
|
||||
}
|
||||
|
||||
interface I15 {
|
||||
I14
|
||||
}
|
||||
|
||||
interface I16 {
|
||||
I15
|
||||
}
|
||||
|
||||
interface I17 {
|
||||
I16
|
||||
}
|
||||
|
||||
interface I18 {
|
||||
I17
|
||||
}
|
||||
|
||||
interface I19 {
|
||||
I18
|
||||
}
|
||||
|
||||
interface I20 {
|
||||
I19
|
||||
}
|
||||
|
||||
interface I21 {
|
||||
I20
|
||||
}
|
||||
|
||||
interface I22 {
|
||||
I21
|
||||
}
|
||||
|
||||
interface I23 {
|
||||
I22
|
||||
}
|
||||
|
||||
interface I24 {
|
||||
I23
|
||||
}
|
||||
|
||||
interface I25 {
|
||||
I24
|
||||
}
|
||||
|
||||
interface I26 {
|
||||
I25
|
||||
}
|
||||
|
||||
interface I27 {
|
||||
I26
|
||||
}
|
||||
|
||||
interface I28 {
|
||||
I27
|
||||
}
|
||||
|
||||
interface I29 {
|
||||
I28
|
||||
}
|
||||
|
||||
interface I30 {
|
||||
I29
|
||||
}
|
||||
|
||||
interface I31 {
|
||||
I30
|
||||
}
|
||||
|
||||
interface I32 {
|
||||
I31
|
||||
}
|
||||
|
||||
interface I33 {
|
||||
I32
|
||||
}
|
||||
|
||||
interface I34 {
|
||||
I33
|
||||
}
|
||||
|
||||
interface I35 {
|
||||
I34
|
||||
}
|
||||
|
||||
interface I36 {
|
||||
I35
|
||||
}
|
||||
|
||||
interface I37 {
|
||||
I36
|
||||
}
|
||||
|
||||
interface I38 {
|
||||
I37
|
||||
}
|
||||
|
||||
interface I39 {
|
||||
I38
|
||||
}
|
||||
|
||||
interface I40 {
|
||||
I39
|
||||
}
|
||||
|
||||
interface I41 {
|
||||
I40
|
||||
}
|
||||
|
||||
interface I42 {
|
||||
I41
|
||||
}
|
||||
|
||||
interface I43 {
|
||||
I42
|
||||
}
|
||||
|
||||
interface I44 {
|
||||
I43
|
||||
}
|
||||
|
||||
interface I45 {
|
||||
I44
|
||||
}
|
||||
|
||||
interface I46 {
|
||||
I45
|
||||
}
|
||||
|
||||
interface I47 {
|
||||
I46
|
||||
}
|
||||
|
||||
interface I48 {
|
||||
I47
|
||||
}
|
||||
|
||||
interface I49 {
|
||||
I48
|
||||
}
|
||||
|
||||
interface I50 {
|
||||
I49
|
||||
}
|
||||
|
||||
interface I51 {
|
||||
I50
|
||||
}
|
||||
|
||||
interface I52 {
|
||||
I51
|
||||
}
|
||||
|
||||
interface I53 {
|
||||
I52
|
||||
}
|
||||
|
||||
interface I54 {
|
||||
I53
|
||||
}
|
||||
|
||||
interface I55 {
|
||||
I54
|
||||
}
|
||||
|
||||
interface I56 {
|
||||
I55
|
||||
}
|
||||
|
||||
interface I57 {
|
||||
I56
|
||||
}
|
||||
|
||||
interface I58 {
|
||||
I57
|
||||
}
|
||||
|
||||
interface I59 {
|
||||
I58
|
||||
}
|
||||
|
||||
interface I60 {
|
||||
I59
|
||||
}
|
||||
|
||||
interface I61 {
|
||||
I60
|
||||
}
|
||||
|
||||
interface I62 {
|
||||
I61
|
||||
}
|
||||
|
||||
interface I63 {
|
||||
I62
|
||||
}
|
||||
|
||||
interface I64 {
|
||||
I63
|
||||
}
|
||||
|
||||
interface I65 {
|
||||
I64
|
||||
}
|
||||
|
||||
interface I66 {
|
||||
I65
|
||||
}
|
||||
|
||||
interface I67 {
|
||||
I66
|
||||
}
|
||||
|
||||
interface I68 {
|
||||
I67
|
||||
}
|
||||
|
||||
interface I69 {
|
||||
I68
|
||||
}
|
||||
|
||||
interface I70 {
|
||||
I69
|
||||
}
|
||||
|
||||
interface I71 {
|
||||
I70
|
||||
}
|
||||
|
||||
interface I72 {
|
||||
I71
|
||||
}
|
||||
|
||||
interface I73 {
|
||||
I72
|
||||
}
|
||||
|
||||
interface I74 {
|
||||
I73
|
||||
}
|
||||
|
||||
interface I75 {
|
||||
I74
|
||||
}
|
||||
|
||||
interface I76 {
|
||||
I75
|
||||
}
|
||||
|
||||
interface I77 {
|
||||
I76
|
||||
}
|
||||
|
||||
interface I78 {
|
||||
I77
|
||||
}
|
||||
|
||||
interface I79 {
|
||||
I78
|
||||
}
|
||||
|
||||
interface I80 {
|
||||
I79
|
||||
}
|
||||
|
||||
interface I81 {
|
||||
I80
|
||||
}
|
||||
|
||||
interface I82 {
|
||||
I81
|
||||
}
|
||||
|
||||
interface I83 {
|
||||
I82
|
||||
}
|
||||
|
||||
interface I84 {
|
||||
I83
|
||||
}
|
||||
|
||||
interface I85 {
|
||||
I84
|
||||
}
|
||||
|
||||
interface I86 {
|
||||
I85
|
||||
}
|
||||
|
||||
interface I87 {
|
||||
I86
|
||||
}
|
||||
|
||||
interface I88 {
|
||||
I87
|
||||
}
|
||||
|
||||
interface I89 {
|
||||
I88
|
||||
}
|
||||
|
||||
interface I90 {
|
||||
I89
|
||||
}
|
||||
|
||||
interface I91 {
|
||||
I90
|
||||
}
|
||||
|
||||
interface I92 {
|
||||
I91
|
||||
}
|
||||
|
||||
interface I93 {
|
||||
I92
|
||||
}
|
||||
|
||||
interface I94 {
|
||||
I93
|
||||
}
|
||||
|
||||
interface I95 {
|
||||
I94
|
||||
}
|
||||
|
||||
interface I96 {
|
||||
I95
|
||||
}
|
||||
|
||||
interface I97 {
|
||||
I96
|
||||
}
|
||||
|
||||
interface I98 {
|
||||
I97
|
||||
}
|
||||
|
||||
interface I0 {
|
||||
m999() int
|
||||
}
|
||||
|
||||
struct Abc {
|
||||
x int = 123
|
||||
}
|
||||
|
||||
fn (s Abc) m999() int {
|
||||
return 999
|
||||
}
|
||||
|
||||
fn test_deep_nested_interface_embeddings() {
|
||||
a := Abc{}
|
||||
dump(a)
|
||||
i := I99(a)
|
||||
dump(i)
|
||||
assert i.m999() == 999
|
||||
}
|
78
vlib/v/tests/interface_embedding_recursive_test.v
Normal file
78
vlib/v/tests/interface_embedding_recursive_test.v
Normal file
@ -0,0 +1,78 @@
|
||||
// This test orders the interface definitions intentionally
|
||||
// in such a way that interface `Re` is first, and `Fe` is
|
||||
// last. The goal is testing that the embedding expansion
|
||||
// works independently from the source order, and that both
|
||||
// can be checked/compiled/used at the same time.
|
||||
interface Re {
|
||||
I1
|
||||
I2
|
||||
m_ie() int
|
||||
}
|
||||
|
||||
interface I1 {
|
||||
I0
|
||||
m1() int
|
||||
}
|
||||
|
||||
interface I2 {
|
||||
I0
|
||||
m2() int
|
||||
}
|
||||
|
||||
interface I0 {
|
||||
m0() int
|
||||
}
|
||||
|
||||
interface Fe {
|
||||
I1
|
||||
I2
|
||||
m_ie() int
|
||||
}
|
||||
|
||||
struct StructIE {
|
||||
x int = 456
|
||||
}
|
||||
|
||||
fn (s StructIE) m0() int {
|
||||
println(@METHOD)
|
||||
return 0
|
||||
}
|
||||
|
||||
fn (s StructIE) m1() int {
|
||||
println(@METHOD)
|
||||
return 1
|
||||
}
|
||||
|
||||
fn (s StructIE) m2() int {
|
||||
println(@METHOD)
|
||||
return 2
|
||||
}
|
||||
|
||||
fn (s StructIE) m_ie() int {
|
||||
println(@METHOD)
|
||||
return 3
|
||||
}
|
||||
|
||||
fn test_ie_recursive_forward() {
|
||||
i := Fe(StructIE{})
|
||||
eprintln(i)
|
||||
assert 0 == i.m0()
|
||||
assert 1 == i.m1()
|
||||
assert 2 == i.m2()
|
||||
assert 3 == i.m_ie()
|
||||
if i is StructIE {
|
||||
assert i.x == 456
|
||||
}
|
||||
}
|
||||
|
||||
fn test_ie_recursive_backward() {
|
||||
i := Re(StructIE{})
|
||||
eprintln(i)
|
||||
assert 0 == i.m0()
|
||||
assert 1 == i.m1()
|
||||
assert 2 == i.m2()
|
||||
assert 3 == i.m_ie()
|
||||
if i is StructIE {
|
||||
assert i.x == 456
|
||||
}
|
||||
}
|
56
vlib/v/tests/interface_embedding_test.v
Normal file
56
vlib/v/tests/interface_embedding_test.v
Normal file
@ -0,0 +1,56 @@
|
||||
interface WalkerTalker {
|
||||
// Abc
|
||||
Walker // adsas
|
||||
// zxczxc
|
||||
Talker // xyzdef
|
||||
// asdasdas
|
||||
nspeeches int
|
||||
}
|
||||
|
||||
interface Talker {
|
||||
nspeeches int
|
||||
talk(msg string)
|
||||
}
|
||||
|
||||
interface Walker {
|
||||
nsteps int
|
||||
walk(newx int, newy int)
|
||||
}
|
||||
|
||||
struct Abc {
|
||||
mut:
|
||||
x int
|
||||
y int
|
||||
phrases []string
|
||||
nsteps int = 1000
|
||||
nspeeches int = 1000
|
||||
}
|
||||
|
||||
fn (mut s Abc) talk(msg string) {
|
||||
s.phrases << msg
|
||||
s.nspeeches++
|
||||
}
|
||||
|
||||
fn (mut s Abc) walk(x int, y int) {
|
||||
s.x = x
|
||||
s.y = y
|
||||
s.nsteps++
|
||||
}
|
||||
|
||||
fn test_walker_talker() {
|
||||
mut wt := WalkerTalker(Abc{
|
||||
x: 1
|
||||
y: 1
|
||||
phrases: ['hi']
|
||||
})
|
||||
wt.talk('my name is Wally')
|
||||
wt.walk(100, 100)
|
||||
if mut wt is Abc {
|
||||
dump(wt)
|
||||
assert wt.x == 100
|
||||
assert wt.y == 100
|
||||
assert wt.phrases.last().ends_with('Wally')
|
||||
assert wt.nspeeches == 1001
|
||||
assert wt.nsteps == 1001
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user