diff --git a/vlib/builtin/option.v b/vlib/builtin/option.v index a83518e1a0..96f29f1a8b 100644 --- a/vlib/builtin/option.v +++ b/vlib/builtin/option.v @@ -3,74 +3,66 @@ // that can be found in the LICENSE file. module builtin -struct OptionBase { - ok bool - is_none bool - error string - ecode int - // Data is trailing after ecode - // and is not included in here but in the - // derived Option_xxx types +// IError holds information about an error instance +pub interface IError { + msg string + code int } -// `fn foo() ?Foo { return foo }` => `fn foo() ?Foo { return opt_ok(foo); }` -fn opt_ok2(data voidptr, mut option OptionBase, size int) { +// Error is the default implementation of IError, that is returned by e.g. `error()` +pub struct Error { +pub: + msg string + code int +} + +pub struct Option3 { + state byte + err IError +} + +[inline] +fn (e IError) str() string { + return e.msg +} + +fn opt_ok3(data voidptr, mut option Option3, size int) { unsafe { - *option = OptionBase{ - ok: true - } - // use ecode to get the end of OptionBase and then memcpy into it - C.memcpy(byteptr(&option.ecode) + sizeof(int), data, size) + *option = Option3{} + // use err to get the end of Option3 and then memcpy into it + C.memcpy(byteptr(&option.err) + sizeof(IError), data, size) } } -// Option is the old option type used for bootstrapping -struct Option { - ok bool - is_none bool - error string - ecode int -} - -// str returns the string representation of the Option. -pub fn (o Option) str() string { - if o.ok && !o.is_none { +pub fn (o Option3) str() string { + if o.state == 0 { return 'Option{ ok }' } - if o.is_none { + if o.state == 1 { return 'Option{ none }' } - return 'Option{ error: "$o.error" }' + return 'Option{ err: "$o.err" }' } -// opt_none is used internally when returning `none`. -fn opt_none() Option { - return Option{ - ok: false - is_none: true +[inline] +pub fn error3(message string) IError { + return &Error{ + msg: message } } -// error returns an optional containing the error given in `message`. -// `if ouch { return error('an error occurred') }` -pub fn error(message string) Option { - return Option{ - ok: false - is_none: false - error: message +pub fn error_with_code3(message string, code int) IError { + return &Error { + msg: message + code: code } } -// error_with_code returns an optional containing both error `message` and error `code`. -// `if ouch { return error_with_code('an error occurred',1) }` -pub fn error_with_code(message string, code int) Option { - return Option{ - ok: false - is_none: false - error: message - ecode: code - } -} +//////////////////////////////////////// + +// these are just here temporarily to avoid breaking the compiler; they will be removed soon +pub fn error(a string) Option2 { return {} } +pub fn error_with_code(a string, b int) Option2 { return {} } // Option2 is the base of V's new internal optional return system. struct Option2 { @@ -81,13 +73,6 @@ struct Option2 { // derived Option2_xxx types } -// Error holds information about an error instance -pub struct Error { -pub: - msg string - code int -} - [inline] fn (e Error) str() string { // TODO: this should probably have a better str method, @@ -104,15 +89,14 @@ fn opt_ok(data voidptr, mut option Option2, size int) { } } -// /* pub fn (o Option2) str() string { if o.state == 0 { - return 'Option2{ ok }' + return 'Option{ ok }' } if o.state == 1 { - return 'Option2{ none }' + return 'Option{ none }' } - return 'Option2{ err: "$o.err" }' + return 'Option{ err: "$o.err" }' } // error returns an optional containing the error given in `message`. @@ -137,4 +121,3 @@ pub fn error_with_code2(message string, code int) Option2 { } } } -// */ diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 840ee489f2..23fead181a 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2387,7 +2387,7 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) { return_stmt.types = got_types // allow `none` & `error (Option)` return types for function that returns optional if exp_is_optional - && got_types[0].idx() in [table.none_type_idx, table.error_type_idx, c.table.type_idxs['Option'], c.table.type_idxs['Option2']] { + && got_types[0].idx() in [table.none_type_idx, table.error_type_idx, c.table.type_idxs['Option'], c.table.type_idxs['Option2'], c.table.type_idxs['Option3']] { return } if expected_types.len > 0 && expected_types.len != got_types.len { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 86558acecc..ad887d3fd2 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -552,9 +552,6 @@ fn (mut g Gen) base_type(t table.Type) string { if nr_muls > 0 { styp += strings.repeat(`*`, nr_muls) } - // if styp == 'Option' { - // return 'Option2' - // } return styp } @@ -591,7 +588,6 @@ fn (g &Gen) optional_type_text(styp string, base string) string { } fn (mut g Gen) register_optional(t table.Type) string { - // g.typedefs2.writeln('typedef Option $x;') styp, base := g.optional_type_name(t) if styp !in g.optionals { g.typedefs2.writeln('typedef struct $styp $styp;') @@ -736,6 +732,9 @@ fn (g &Gen) type_sidx(t table.Type) string { // pub fn (mut g Gen) write_typedef_types() { for typ in g.table.types { + if typ.name in c.builtins { + continue + } match typ.kind { .alias { parent := unsafe { &g.table.types[typ.parent_idx] } @@ -755,16 +754,7 @@ pub fn (mut g Gen) write_typedef_types() { g.type_definitions.writeln('typedef array $typ.cname;') } .interface_ { - info := typ.info as table.Interface - g.type_definitions.writeln('typedef struct {') - g.type_definitions.writeln('\tvoid* _object;') - g.type_definitions.writeln('\tint _interface_idx;') - for field in info.fields { - styp := g.typ(field.typ) - cname := c_name(field.name) - g.type_definitions.writeln('\t$styp* $cname;') - } - g.type_definitions.writeln('} ${c_name(typ.name)};') + g.write_interface_typesymbol_declaration(typ) } .chan { if typ.name != 'chan' { @@ -799,6 +789,19 @@ static inline void __${typ.cname}_pushval($typ.cname ch, $el_stype val) { } } +pub fn (mut g Gen) write_interface_typesymbol_declaration(sym table.TypeSymbol) { + info := sym.info as table.Interface + g.type_definitions.writeln('typedef struct {') + g.type_definitions.writeln('\tvoid* _object;') + g.type_definitions.writeln('\tint _interface_idx;') + for field in info.fields { + styp := g.typ(field.typ) + cname := c_name(field.name) + g.type_definitions.writeln('\t$styp* $cname;') + } + g.type_definitions.writeln('} ${c_name(sym.name)};\n') +} + pub fn (mut g Gen) write_fn_typesymbol_declaration(sym table.TypeSymbol) { info := sym.info as table.FnType func := info.func @@ -908,7 +911,7 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) { g.skip_stmt_pos = true if stmt is ast.ExprStmt { sym := g.table.get_type_symbol(stmt.typ) - if sym.name in ['Option', 'Option2'] || stmt.expr is ast.None { + if sym.name in ['Option2', 'Option3'] || stmt.expr is ast.None { tmp := g.new_tmp_var() g.write('Option2 $tmp = ') g.expr(stmt.expr) @@ -4336,7 +4339,7 @@ fn (mut g Gen) return_statement(node ast.Return) { if fn_return_is_optional { optional_none := node.exprs[0] is ast.None ftyp := g.typ(node.types[0]) - mut is_regular_option := ftyp in ['Option', 'Option2'] + mut is_regular_option := ftyp in ['Option2', 'Option3'] if optional_none || is_regular_option { tmp := g.new_tmp_var() g.write('Option2 $tmp = ') @@ -4453,7 +4456,7 @@ fn (mut g Gen) return_statement(node ast.Return) { node.types[0].has_flag(.optional) } } - if fn_return_is_optional && !expr_type_is_opt && return_sym.name !in ['Option', 'Option2'] { + if fn_return_is_optional && !expr_type_is_opt && return_sym.name !in ['Option2', 'Option3'] { styp := g.base_type(g.fn_decl.return_type) opt_type := g.typ(g.fn_decl.return_type) // Create a tmp for this option @@ -4608,9 +4611,6 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, val string, typ ta // Initialize more complex consts in `void _vinit/2{}` // (C doesn't allow init expressions that can't be resolved at compile time). mut styp := g.typ(typ) - if styp == 'Option' { - styp = 'Option2' - } cname := '_const_$name' g.definitions.writeln('$styp $cname; // inited later') if cname == '_const_os__args' { @@ -4996,7 +4996,7 @@ fn (mut g Gen) write_init_function() { } const ( - builtins = ['string', 'array', 'KeyValue', 'DenseArray', 'map', 'Option', 'Error', 'Option2'] + builtins = ['string', 'array', 'DenseArray', 'map', 'Error', 'IError', 'Option2', 'Option3'] ) fn (mut g Gen) write_builtin_types() { @@ -5004,7 +5004,12 @@ fn (mut g Gen) write_builtin_types() { // builtin types need to be on top // everything except builtin will get sorted for builtin_name in c.builtins { - builtin_types << g.table.types[g.table.type_idxs[builtin_name]] + sym := g.table.types[g.table.type_idxs[builtin_name]] + if sym.kind == .interface_ { + g.write_interface_typesymbol_declaration(sym) + } else { + builtin_types << sym + } } g.write_types(builtin_types) }