builtin: change IError `msg` and `code` to methods + fix vlib, add a deprecation notice for the old usages (#13041)

pull/13440/head
Tim Basel 2022-02-11 14:52:33 +01:00 committed by GitHub
parent 61024d4b75
commit 9d0a5942ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 493 additions and 324 deletions

View File

@ -14,41 +14,85 @@ pub fn panic(s string) {
// IError holds information about an error instance
pub interface IError {
// >> Hack to allow old style custom error implementations
// TODO: remove once deprecation period for `IError` methods has ended
msg string
code int
code int // <<
msg() string
code() int
}
// Error is the default implementation of IError, that is returned by e.g. `error()`
pub fn (err IError) str() string {
return match err {
None__ {
'none'
}
Error {
err.msg()
}
MessageError {
err.msg()
}
else {
// >> Hack to allow old style custom error implementations
// TODO: can be removed once the checker 'hacks' are merged (so `vc` has them included)
if !isnil(err.msg) {
'$err.type_name(): $err.msg'
} else {
// <<
'$err.type_name(): $err.msg()'
}
}
}
}
// Error is the empty default implementation of `IError`.
pub struct Error {
// >> Hack to allow old style custom error implementations
// TODO: can be removed once the checker 'hacks' are merged (so `vc` has them included)
msg string
code int
/// <<
}
pub fn (err Error) msg() string {
return ''
}
pub fn (err Error) code() int {
return 0
}
// MessageError is the default implementation of the `IError` interface that is returned by the `error()` function
struct MessageError {
pub:
msg string
code int
}
pub fn (err MessageError) msg() string {
return err.msg
}
pub fn (err MessageError) code() int {
return err.code
}
pub const none__ = IError(&None__{})
struct None__ {
msg string
code int
Error
}
fn (_ None__) str() string {
return 'none'
}
pub const none__ = IError(None__{'', 0})
pub struct Option {
state byte
err IError = none__
}
pub fn (err IError) str() string {
return match err {
None__ { 'none' }
Error { err.msg }
else { 'Error: $err.msg' }
}
}
pub fn (o Option) str() string {
if o.state == 0 {
return 'Option{ ok }'
@ -69,7 +113,7 @@ fn trace_error(x string) {
[inline]
pub fn error(message string) IError {
// trace_error(message)
return &Error{
return &MessageError{
msg: message
}
}
@ -79,7 +123,7 @@ pub fn error(message string) IError {
[inline]
pub fn error_with_code(message string, code int) IError {
// trace_error('$message | code: $code')
return &Error{
return &MessageError{
msg: message
code: code
}

View File

@ -8,7 +8,6 @@ struct C.IError {
[unsafe]
pub fn (ie &IError) free() {
unsafe {
ie.msg.free()
cie := &C.IError(ie)
free(cie._object)
}

View File

@ -5,30 +5,79 @@ module builtin
// IError holds information about an error instance
pub interface IError {
// >> Hack to allow old style custom error implementations
// TODO: remove once deprecation period for `IError` methods has ended
msg string
code int
code int // <<
msg() string
code() int
}
// Error is the default implementation of IError, that is returned by e.g. `error()`
pub fn (err IError) str() string {
return match err {
None__ {
'none'
}
Error {
err.msg()
}
MessageError {
err.msg()
}
else {
// >> Hack to allow old style custom error implementations
// TODO: can be removed once the checker 'hacks' are merged (so `vc` has them included)
if !isnil(err.msg) {
'$err.type_name(): $err.msg'
} else {
// <<
'$err.type_name(): $err.msg()'
}
}
}
}
// Error is the empty default implementation of `IError`.
pub struct Error {
// >> Hack to allow old style custom error implementations
// TODO: can be removed once the checker 'hacks' are merged (so `vc` has them included)
msg string
code int
/// <<
}
pub fn (err Error) msg() string {
return ''
}
pub fn (err Error) code() int {
return 0
}
// MessageError is the default implementation of the `IError` interface that is returned by the `error()` function
struct MessageError {
pub:
msg string
code int
}
pub fn (err IError) str() string {
return match err {
None__ { 'none' }
Error { err.msg }
else { '$err.type_name(): $err.msg' }
}
pub fn (err MessageError) msg() string {
return err.msg
}
pub fn (err MessageError) code() int {
return err.code
}
[unsafe]
pub fn (err &MessageError) free() {
unsafe { err.msg.free() }
}
const none__ = IError(&None__{})
struct None__ {
msg string
code int
Error
}
fn (_ None__) str() string {
@ -45,7 +94,7 @@ fn trace_error(x string) {
[inline]
pub fn error(message string) IError {
trace_error(message)
return &Error{
return &MessageError{
msg: message
}
}
@ -55,7 +104,7 @@ pub fn error(message string) IError {
[inline]
pub fn error_with_code(message string, code int) IError {
trace_error('$message | code: $code')
return &Error{
return &MessageError{
msg: message
code: code
}
@ -78,16 +127,6 @@ fn opt_ok(data voidptr, mut option Option, size int) {
}
}
[unsafe]
pub fn (e &Error) free() {
unsafe { e.msg.free() }
}
[unsafe]
pub fn (n &None__) free() {
unsafe { n.msg.free() }
}
pub fn (_ none) str() string {
return 'none'
}

View File

@ -6,6 +6,6 @@ fn test_crypto_bcrypt() {
bcrypt.compare_hash_and_password('password'.bytes(), hash.bytes()) or { panic(err) }
bcrypt.compare_hash_and_password('password2'.bytes(), hash.bytes()) or {
assert err == error('mismatched hash and password')
assert err.msg() == 'mismatched hash and password'
}
}

View File

@ -5,6 +5,9 @@
module rand
struct ReadError {
msg string = 'crypto.rand.read() error reading random bytes'
code int
Error
}
pub fn (err ReadError) msg() string {
return 'crypto.rand.read() error reading random bytes'
}

View File

@ -11,23 +11,28 @@ pub:
}
struct UnkownFlagError {
msg string
code int
Error
flag string
}
struct MinimumArgsCountError {
msg string
code int
fn (err UnkownFlagError) msg() string {
return 'Unknown flag `$err.flag`'
}
struct MaximumArgsCountError {
msg string
code int
struct ArgsCountError {
Error
got int
want int
}
struct NoArgsExpectedError {
msg string
code int
fn (err ArgsCountError) msg() string {
if err.want == 0 {
return 'Expected no arguments, but got $err.got'
} else if err.got > err.want {
return 'Expected at most $err.want arguments, but got $err.got'
} else {
return 'Expected at least $err.want arguments, but got $err.got'
}
}
// free frees the resources associated with a given Flag
@ -616,24 +621,27 @@ pub fn (mut fs FlagParser) finalize() ?[]string {
for a in remaining {
if (a.len >= 2 && a[..2] == '--') || (a.len == 2 && a[0] == `-`) {
return IError(&UnkownFlagError{
msg: 'Unknown flag `$a`'
flag: a
})
}
}
}
if remaining.len < fs.min_free_args && fs.min_free_args > 0 {
return IError(&MinimumArgsCountError{
msg: 'Expected at least $fs.min_free_args arguments, but given $remaining.len'
return IError(&ArgsCountError{
want: fs.min_free_args
got: remaining.len
})
}
if remaining.len > fs.max_free_args && fs.max_free_args > 0 {
return IError(&MaximumArgsCountError{
msg: 'Expected at most $fs.max_free_args arguments, but given $remaining.len'
return IError(&ArgsCountError{
want: fs.max_free_args
got: remaining.len
})
}
if remaining.len > 0 && fs.max_free_args == 0 && fs.min_free_args == 0 {
return IError(&NoArgsExpectedError{
msg: 'Expected no arguments, but given $remaining.len'
return IError(&ArgsCountError{
want: 0
got: remaining.len
})
}
remaining << fs.all_after_dashdash
@ -647,7 +655,7 @@ pub fn (mut fs FlagParser) finalize() ?[]string {
// you want more control over the error handling.
pub fn (mut fs FlagParser) remaining_parameters() []string {
return fs.finalize() or {
eprintln(err.msg)
eprintln(err.msg())
println(fs.usage())
exit(1)
}

View File

@ -137,7 +137,7 @@ fn test_finalize_returns_error_for_unknown_flags_long() {
mut fp := flag.new_flag_parser(['--known', '--unknown'])
fp.bool('known', 0, false, '')
finalized := fp.finalize() or {
assert err.msg == 'Unknown flag `--unknown`'
assert err.msg() == 'Unknown flag `--unknown`'
return
}
assert finalized.len < 0 // expect error to be returned
@ -147,7 +147,7 @@ fn test_finalize_returns_error_for_unknown_flags_short() {
mut fp := flag.new_flag_parser(['--known', '-x'])
fp.bool('known', 0, false, '')
finalized := fp.finalize() or {
assert err.msg == 'Unknown flag `-x`'
assert err.msg() == 'Unknown flag `-x`'
return
}
assert finalized.len < 0 // expect error to be returned
@ -210,7 +210,7 @@ fn test_error_for_to_few_free_args() ? {
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
fp1.limit_free_args(5, 6) ?
args := fp1.finalize() or {
assert err.msg.starts_with('Expected at least 5 arguments')
assert err.msg().starts_with('Expected at least 5 arguments')
return
}
assert args.len < 0 // expect an error and need to use args
@ -220,7 +220,7 @@ fn test_error_for_to_much_free_args() ? {
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
fp1.limit_free_args(1, 2) ?
args := fp1.finalize() or {
assert err.msg.starts_with('Expected at most 2 arguments')
assert err.msg().starts_with('Expected at most 2 arguments')
return
}
assert args.len < 0 // expect an error and need to use args
@ -230,7 +230,7 @@ fn test_could_expect_no_free_args() ? {
mut fp1 := flag.new_flag_parser(['a'])
fp1.limit_free_args(0, 0) ?
args := fp1.finalize() or {
assert err.msg.starts_with('Expected no arguments')
assert err.msg().starts_with('Expected no arguments')
return
}
assert args.len < 0 // expect an error and need to use args

View File

@ -24,7 +24,7 @@ pub fn temp_file(tfo TempFileOptions) ?(os.File, string) {
' could not create temporary file in "$d". Please ensure write permissions.')
}
d = d.trim_right(os.path_separator)
prefix, suffix := prefix_and_suffix(tfo.pattern) or { return error(@FN + ' ' + err.msg) }
prefix, suffix := prefix_and_suffix(tfo.pattern) or { return error(@FN + ' $err.msg()') }
for retry := 0; retry < util.retries; retry++ {
path := os.join_path(d, prefix + random_number() + suffix)
mut mode := 'rw+'
@ -57,7 +57,7 @@ pub fn temp_dir(tdo TempFileOptions) ?string {
' could not create temporary directory "$d". Please ensure write permissions.')
}
d = d.trim_right(os.path_separator)
prefix, suffix := prefix_and_suffix(tdo.pattern) or { return error(@FN + ' ' + err.msg) }
prefix, suffix := prefix_and_suffix(tdo.pattern) or { return error(@FN + ' $err.msg()') }
for retry := 0; retry < util.retries; retry++ {
path := os.join_path(d, prefix + random_number() + suffix)
os.mkdir_all(path) or { continue }

View File

@ -14,7 +14,7 @@ mut:
fn test_json_decode_fails_to_decode_unrecognised_array_of_dicts() {
data := '[{"twins":[{"id":123,"seed":"abcde","pubkey":"xyzasd"},{"id":456,"seed":"dfgdfgdfgd","pubkey":"skjldskljh45sdf"}]}]'
json.decode(TestTwins, data) or {
assert err.msg == "expected field 'twins' is missing"
assert err.msg() == "expected field 'twins' is missing"
return
}
assert false

View File

@ -333,7 +333,7 @@ fn test_errors() {
data := '{"countries":[{"cities":[{"name":"London"},{"name":"Manchester"}],"name":"UK"},{"cities":{"name":"Donlon"},"name":"KU"}],"users":{"Foo":{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"little foo"},"Boo":{"age":20,"nums":[5,3,1],"lastName":"Smith","IsRegistered":false,"type":4,"pet_animals":"little boo"}},"extra":{"2":{"n1":2,"n2":4,"n3":8,"n4":16},"3":{"n1":3,"n2":9,"n3":27,"n4":81}}}'
json.decode(Data, data) or {
println(err)
assert err.msg.starts_with('Json element is not an array:')
assert err.msg().starts_with('Json element is not an array:')
return
}
assert false
@ -342,7 +342,7 @@ fn test_errors() {
data := '{"countries":[{"cities":[{"name":"London"},{"name":"Manchester"}],"name":"UK"},{"cities":[{"name":"Donlon"},{"name":"Termanches"}],"name":"KU"}],"users":[{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"little foo"},{"age":20,"nums":[5,3,1],"lastName":"Smith","IsRegistered":false,"type":4,"pet_animals":"little boo"}],"extra":{"2":{"n1":2,"n2":4,"n3":8,"n4":16},"3":{"n1":3,"n2":9,"n3":27,"n4":81}}}'
json.decode(Data, data) or {
println(err)
assert err.msg.starts_with('Json element is not an object:')
assert err.msg().starts_with('Json element is not an object:')
return
}
assert false

View File

@ -20,8 +20,7 @@ pub enum ConnectionFlag {
}
struct SQLError {
msg string
code int
MessageError
}
// TODO: Documentation

View File

@ -21,7 +21,7 @@ pub const (
)
pub fn socket_error_message(potential_code int, s string) ?int {
return socket_error(potential_code) or { return error('$err.msg; $s') }
return socket_error(potential_code) or { return error('$err.msg(); $s') }
}
pub fn socket_error(potential_code int) ?int {

View File

@ -627,18 +627,25 @@ fn (mut h Header) add_key(key string) {
// Custom error struct for invalid header tokens
struct HeaderKeyError {
msg string
Error
code int
header string
invalid_char byte
}
pub fn (err HeaderKeyError) msg() string {
return "Invalid header key: '$err.header'"
}
pub fn (err HeaderKeyError) code() int {
return err.code
}
// is_valid checks if the header token contains all valid bytes
fn is_valid(header string) ? {
for _, c in header {
if int(c) >= 128 || !is_token(c) {
return IError(HeaderKeyError{
msg: "Invalid header key: '$header'"
code: 1
header: header
invalid_char: c
@ -647,7 +654,6 @@ fn is_valid(header string) ? {
}
if header.len == 0 {
return IError(HeaderKeyError{
msg: "Invalid header key: '$header'"
code: 2
header: header
invalid_char: 0

View File

@ -261,15 +261,20 @@ pub:
}
pub struct UnexpectedExtraAttributeError {
pub:
msg string
code int
Error
attributes []string
}
pub fn (err UnexpectedExtraAttributeError) msg() string {
return 'Encountered unexpected extra attributes: $err.attributes'
}
pub struct MultiplePathAttributesError {
pub:
msg string = 'Expected at most one path attribute'
code int
Error
}
pub fn (err MultiplePathAttributesError) msg() string {
return 'Expected at most one path attribute'
}
// multipart_form_body converts form and file data into a multipart/form

View File

@ -48,7 +48,7 @@ pub fn (mut s Server) listen_and_serve() ? {
break
}
mut conn := s.listener.accept() or {
if err.msg != 'net: op timed out' {
if err.msg() != 'net: op timed out' {
eprintln('accept() failed: $err; skipping')
}
continue

View File

@ -21,13 +21,13 @@ mut:
pub fn dial_tcp(address string) ?&TcpConn {
addrs := resolve_addrs_fuzzy(address, .tcp) or {
return error('$err.msg; could not resolve address $address in dial_tcp')
return error('$err.msg(); could not resolve address $address in dial_tcp')
}
// Very simple dialer
for addr in addrs {
mut s := new_tcp_socket(addr.family()) or {
return error('$err.msg; could not create new tcp socket in dial_tcp')
return error('$err.msg(); could not create new tcp socket in dial_tcp')
}
s.connect(addr) or {
// Connection failed
@ -215,10 +215,10 @@ mut:
}
pub fn listen_tcp(family AddrFamily, saddr string) ?&TcpListener {
s := new_tcp_socket(family) or { return error('$err.msg; could not create new socket') }
s := new_tcp_socket(family) or { return error('$err.msg(); could not create new socket') }
addrs := resolve_addrs(saddr, family, .tcp) or {
return error('$err.msg; could not resolve address $saddr')
return error('$err.msg(); could not resolve address $saddr')
}
// TODO(logic to pick here)

View File

@ -410,7 +410,7 @@ fn split_by_scheme(rawurl string) ?[]string {
}
fn get_scheme(rawurl string) ?string {
split := split_by_scheme(rawurl) or { return err.msg }
split := split_by_scheme(rawurl) or { return err.msg() }
return split[0]
}
@ -593,9 +593,9 @@ fn parse_host(host string) ?string {
// We do impose some restrictions on the zone, to avoid stupidity
// like newlines.
if zone := host[..i].index('%25') {
host1 := unescape(host[..zone], .encode_host) or { return err.msg }
host2 := unescape(host[zone..i], .encode_zone) or { return err.msg }
host3 := unescape(host[i..], .encode_host) or { return err.msg }
host1 := unescape(host[..zone], .encode_host) or { return err.msg() }
host2 := unescape(host[zone..i], .encode_zone) or { return err.msg() }
host3 := unescape(host[i..], .encode_host) or { return err.msg() }
return host1 + host2 + host3
}
if idx := host.last_index(':') {
@ -606,7 +606,7 @@ fn parse_host(host string) ?string {
}
}
}
h := unescape(host, .encode_host) or { return err.msg }
h := unescape(host, .encode_host) or { return err.msg() }
return h
// host = h
// return host

View File

@ -122,7 +122,7 @@ fn (mut s Server) serve_client(mut c Client) ? {
}
s.setup_callbacks(mut server_client)
c.listen() or {
s.logger.error(err.msg)
s.logger.error(err.msg())
return err
}
}

View File

@ -478,22 +478,28 @@ pub fn (mut f File) flush() {
C.fflush(f.cfile)
}
pub struct ErrFileNotOpened {
msg string = 'os: file not opened'
code int
pub struct FileNotOpenedError {
Error
}
pub struct ErrSizeOfTypeIs0 {
msg string = 'os: size of type is 0'
code int
pub fn (err FileNotOpenedError) msg() string {
return 'os: file not opened'
}
pub struct SizeOfTypeIs0Error {
Error
}
pub fn (err SizeOfTypeIs0Error) msg() string {
return 'os: size of type is 0'
}
fn error_file_not_opened() IError {
return IError(&ErrFileNotOpened{})
return IError(&FileNotOpenedError{})
}
fn error_size_of_type_0() IError {
return IError(&ErrSizeOfTypeIs0{})
return IError(&SizeOfTypeIs0Error{})
}
// read_struct reads a single struct of type `T`

View File

@ -273,7 +273,7 @@ fn test_write_raw_at_negative_pos() ? {
if _ := f.write_raw_at(another_point, -1) {
assert false
}
f.write_raw_at(another_point, -234) or { assert err.msg == 'Invalid argument' }
f.write_raw_at(another_point, -234) or { assert err.msg() == 'Invalid argument' }
f.close()
}
@ -328,7 +328,7 @@ fn test_read_raw_at_negative_pos() ? {
if _ := f.read_raw_at<Point>(-1) {
assert false
}
f.read_raw_at<Point>(-234) or { assert err.msg == 'Invalid argument' }
f.read_raw_at<Point>(-234) or { assert err.msg() == 'Invalid argument' }
f.close()
}

View File

@ -150,12 +150,12 @@ pub fn rmdir_all(path string) ? {
for item in items {
fullpath := join_path_single(path, item)
if is_dir(fullpath) && !is_link(fullpath) {
rmdir_all(fullpath) or { ret_err = err.msg }
rmdir_all(fullpath) or { ret_err = err.msg() }
} else {
rm(fullpath) or { ret_err = err.msg }
rm(fullpath) or { ret_err = err.msg() }
}
}
rmdir(path) or { ret_err = err.msg }
rmdir(path) or { ret_err = err.msg() }
if ret_err.len > 0 {
return error(ret_err)
}
@ -404,13 +404,16 @@ fn executable_fallback() string {
return exepath
}
pub struct ErrExecutableNotFound {
msg string = 'os: failed to find executable'
code int
pub struct ExecutableNotFoundError {
Error
}
pub fn (err ExecutableNotFoundError) msg() string {
return 'os: failed to find executable'
}
fn error_failed_to_find_executable() IError {
return IError(&ErrExecutableNotFound{})
return IError(&ExecutableNotFoundError{})
}
// find_exe_path walks the environment PATH, just like most shell do, it returns

View File

@ -35,7 +35,7 @@ fn test_open_file() {
filename := './test1.txt'
hello := 'hello world!'
os.open_file(filename, 'r+', 0o666) or {
assert err.msg == 'No such file or directory'
assert err.msg() == 'No such file or directory'
os.File{}
}
mut file := os.open_file(filename, 'w+', 0o666) or { panic(err) }
@ -51,7 +51,7 @@ fn test_open_file_binary() {
filename := './test1.dat'
hello := 'hello \n world!'
os.open_file(filename, 'r+', 0o666) or {
assert err.msg == 'No such file or directory'
assert err.msg() == 'No such file or directory'
os.File{}
}
mut file := os.open_file(filename, 'wb+', 0o666) or { panic(err) }

View File

@ -20,7 +20,7 @@ fn test_signal_opt_invalid_argument() {
assert false
}
os.signal_opt(.kill, default_handler) or {
assert err.msg == 'Invalid argument'
assert err.msg() == 'Invalid argument'
assert err.code == 22
}
}

View File

@ -29,14 +29,8 @@ struct Range {
comparator_sets []ComparatorSet
}
struct InvalidComparatorCountError {
msg string
code int
}
struct InvalidComparatorFormatError {
msg string
code int
MessageError
}
fn (r Range) satisfies(ver Version) bool {

View File

@ -20,13 +20,20 @@ pub enum Increment {
}
struct EmptyInputError {
msg string = 'Empty input'
code int
Error
}
pub fn (err EmptyInputError) msg() string {
return 'Empty input'
}
struct InvalidVersionFormatError {
msg string
code int
Error
input string
}
pub fn (err InvalidVersionFormatError) msg() string {
return 'Invalid version format for input "$err.input"'
}
// * Constructor.
@ -38,7 +45,7 @@ pub fn from(input string) ?Version {
raw_version := parse(input)
version := raw_version.validate() or {
return IError(&InvalidVersionFormatError{
msg: 'Invalid version format for input "$input"'
input: input
})
}
return version

View File

@ -33,8 +33,7 @@ struct Stmt {
}
struct SQLError {
msg string
code int
MessageError
}
//

View File

@ -14,7 +14,7 @@ fn do_rec_calc_send(chs []chan i64, mut sem sync.Semaphore) {
mut msg := ''
for {
mut s := get_val_from_chan(chs[0]) or {
msg = err.msg
msg = err.msg()
break
}
s++

View File

@ -4,13 +4,16 @@
module time
pub struct TimeParseError {
msg string
Error
code int
}
pub fn (err TimeParseError) msg() string {
return 'Invalid time format code: $err.code'
}
fn error_invalid_time(code int) IError {
return TimeParseError{
msg: 'Invalid time format code: $code'
code: code
}
}

View File

@ -477,14 +477,14 @@ fn (c Checker) check_quoted_escapes(q ast.Quoted) ? {
c.check_unicode_escape(s.text[pos..pos + 11]) or {
st := s.state()
return error(@MOD + '.' + @STRUCT + '.' + @FN +
' escaped Unicode is invalid. $err.msg.capitalize() ($st.line_nr,$st.col) in ...${c.excerpt(q.pos)}...')
' escaped Unicode is invalid. $err.msg().capitalize() ($st.line_nr,$st.col) in ...${c.excerpt(q.pos)}...')
}
} else {
pos := s.state().pos
c.check_unicode_escape(s.text[pos..]) or {
st := s.state()
return error(@MOD + '.' + @STRUCT + '.' + @FN +
' escaped Unicode is invalid. $err.msg.capitalize() ($st.line_nr,$st.col) in ...${c.excerpt(q.pos)}...')
' escaped Unicode is invalid. $err.msg().capitalize() ($st.line_nr,$st.col) in ...${c.excerpt(q.pos)}...')
}
}
}

View File

@ -47,7 +47,7 @@ pub fn (c Config) read_input() ?string {
if os.is_file(c.file_path) {
text = os.read_file(c.file_path) or {
return error(@MOD + '.' + @STRUCT + '.' + @FN +
' Could not read "$c.file_path": "$err.msg"')
' Could not read "$c.file_path": "$err.msg()"')
}
}
return text

View File

@ -55,7 +55,7 @@ pub fn new_scanner(config Config) ?&Scanner {
if os.is_file(file_path) {
text = os.read_file(file_path) or {
return error(@MOD + '.' + @STRUCT + '.' + @FN +
' Could not read "$file_path": "$err.msg"')
' Could not read "$file_path": "$err.msg()"')
}
}
mut s := &Scanner{

View File

@ -155,12 +155,12 @@ fn test_alexcrichton_toml_rs() ? {
v_normalized_json := run([jq, '-S', '-f "$jq_normalize_path"', v_toml_json_path]) or {
contents := os.read_file(v_toml_json_path) ?
panic(err.msg + '\n$contents')
panic(err.msg() + '\n$contents')
}
alexcrichton_normalized_json := run([jq, '-S', '-f "$jq_normalize_path"',
alexcrichton_toml_json_path]) or {
contents := os.read_file(v_toml_json_path) ?
panic(err.msg + '\n$contents')
panic(err.msg() + '\n$contents')
}
assert alexcrichton_normalized_json == v_normalized_json
@ -199,7 +199,7 @@ fn test_alexcrichton_toml_rs() ? {
assert false
} else {
if !hide_oks {
println(' $err.msg')
println(' $err.msg()')
}
assert true
}

View File

@ -141,11 +141,11 @@ fn test_burnt_sushi_tomltest() ? {
v_normalized_json := run([jq, '-S', '-f "$jq_normalize_path"', v_toml_json_path]) or {
contents := os.read_file(v_toml_json_path) ?
panic(err.msg + '\n$contents')
panic(err.msg() + '\n$contents')
}
bs_normalized_json := run([jq, '-S', '-f "$jq_normalize_path"', bs_toml_json_path]) or {
contents := os.read_file(v_toml_json_path) ?
panic(err.msg + '\n$contents')
panic(err.msg() + '\n$contents')
}
assert bs_normalized_json == v_normalized_json
@ -182,7 +182,7 @@ fn test_burnt_sushi_tomltest() ? {
assert false
} else {
if !hide_oks {
println(' $err.msg')
println(' $err.msg()')
}
assert true
}

View File

@ -181,7 +181,7 @@ fn test_iarna_toml_spec_tests() ? {
// NOTE there's known errors with the python convertion method.
// For now we just ignore them as it's a broken tool - not a wrong test-case.
// Uncomment this print to see/check them.
// eprintln(err.msg + '\n$contents')
// eprintln(err.msg() + '\n$contents')
e++
println('ERR [${i + 1}/$valid_test_files.len] "$valid_test_file" EXCEPTION [$e/$valid_value_exceptions.len]...')
continue
@ -208,12 +208,12 @@ fn test_iarna_toml_spec_tests() ? {
v_normalized_json := run([jq, '-S', '-f "$jq_normalize_path"', v_toml_json_path]) or {
contents := os.read_file(v_toml_json_path) ?
panic(err.msg + '\n$contents')
panic(err.msg() + '\n$contents')
}
cmd := [jq, '-S', '-f "$jq_normalize_path"', iarna_toml_json_path]
iarna_normalized_json := run(cmd) or {
contents := os.read_file(v_toml_json_path) ?
panic(err.msg + '\n$contents\n\ncmd: ${cmd.join(' ')}')
panic(err.msg() + '\n$contents\n\ncmd: ${cmd.join(' ')}')
}
assert iarna_normalized_json == v_normalized_json
@ -250,7 +250,7 @@ fn test_iarna_toml_spec_tests() ? {
assert false
} else {
if !hide_oks {
println(' $err.msg')
println(' $err.msg()')
}
assert true
}

View File

@ -37,13 +37,13 @@ fn test_toml_with_bom() {
// Re-cycle bad_toml_doc
mut bad_toml_doc := empty_toml_document
bad_toml_doc = toml.parse(toml_text_with_utf16_bom) or {
println(' $err.msg')
println(' $err.msg()')
assert true
empty_toml_document
}
bad_toml_doc = toml.parse(toml_text_with_utf32_bom) or {
println(' $err.msg')
println(' $err.msg()')
assert true
empty_toml_document
}

View File

@ -183,7 +183,6 @@ pub:
pub struct StringInterLiteral {
pub:
vals []string
exprs []Expr
fwidths []int
precisions []int
pluss []bool
@ -191,6 +190,7 @@ pub:
fmt_poss []token.Pos
pos token.Pos
pub mut:
exprs []Expr
expr_types []Type
fmts []byte
need_fmts []bool // an explicit non-default fmt required, e.g. `x`

View File

@ -69,7 +69,7 @@ pub fn new_builder(pref &pref.Preferences) Builder {
pref: pref
table: table
checker: checker.new_checker(table, pref)
transformer: transformer.new_transformer(pref)
transformer: transformer.new_transformer_with_table(table, pref)
compiled_dir: compiled_dir
cached_msvc: msvc
}

View File

@ -36,11 +36,12 @@ pub fn compile_c(mut b builder.Builder) {
pub fn gen_c(mut b builder.Builder, v_files []string) string {
b.front_and_middle_stages(v_files) or {
if err.code != 9999 {
builder.verror(err.msg)
if err.code() != 9999 {
builder.verror(err.msg())
}
return ''
}
util.timing_start('C GEN')
res := c.gen(b.parsed_files, b.table, b.pref)
util.timing_measure('C GEN')

View File

@ -22,7 +22,7 @@ pub fn compile(command string, pref &pref.Preferences, backend_cb FnBackend) {
}
os.is_writable_folder(output_folder) or {
// An early error here, is better than an unclear C error later:
verror(err.msg)
verror(err.msg())
}
// Construct the V object from command line arguments
mut b := new_builder(pref)

View File

@ -181,7 +181,7 @@ fn (mut b Builder) rebuild_cached_module(vexe string, imp_path string) string {
}
b.v_build_module(vexe, imp_path)
rebuilded_o := b.pref.cache_manager.exists('.o', imp_path) or {
panic('could not rebuild cache module for $imp_path, error: $err.msg')
panic('could not rebuild cache module for $imp_path, error: $err.msg()')
}
return rebuilded_o
}

View File

@ -535,7 +535,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
node.pos)
}
} else {
c.error('cannot assign to `$left`: $err.msg', right.pos())
c.error('cannot assign to `$left`: $err.msg()', right.pos())
}
}
}

View File

@ -612,7 +612,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
if left_sym.kind !in [.sum_type, .interface_] {
elem_type := right_final.array_info().elem_type
c.check_expected(left_type, elem_type) or {
c.error('left operand to `$node.op` does not match the array element type: $err.msg',
c.error('left operand to `$node.op` does not match the array element type: $err.msg()',
left_right_pos)
}
}
@ -620,7 +620,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
.map {
map_info := right_final.map_info()
c.check_expected(left_type, map_info.key_type) or {
c.error('left operand to `$node.op` does not match the map key type: $err.msg',
c.error('left operand to `$node.op` does not match the map key type: $err.msg()',
left_right_pos)
}
node.left_type = map_info.key_type
@ -1306,6 +1306,15 @@ fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos to
// Verify methods
for imethod in imethods {
method := c.table.find_method_with_embeds(typ_sym, imethod.name) or {
// >> Hack to allow old style custom error implementations
// TODO: remove once deprecation period for `IError` methods has ended
if inter_sym.name == 'IError' && (imethod.name == 'msg' || imethod.name == 'code') {
c.note("`$styp` doesn't implement method `$imethod.name` of interface `$inter_sym.name`. The usage of fields is being deprecated in favor of methods.",
pos)
continue
}
// <<
typ_sym.find_method_with_generic_parent(imethod.name) or {
c.error("`$styp` doesn't implement method `$imethod.name` of interface `$inter_sym.name`",
pos)
@ -1343,8 +1352,15 @@ fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos to
}
// voidptr is an escape hatch, it should be allowed to be passed
if utyp != ast.voidptr_type {
c.error("`$styp` doesn't implement field `$ifield.name` of interface `$inter_sym.name`",
pos)
// >> Hack to allow old style custom error implementations
// TODO: remove once deprecation period for `IError` methods has ended
if inter_sym.name == 'IError' && (ifield.name == 'msg' || ifield.name == 'code') {
// do nothing, necessary warnings are already printed
} else {
// <<
c.error("`$styp` doesn't implement field `$ifield.name` of interface `$inter_sym.name`",
pos)
}
}
}
inter_sym.info.types << utyp
@ -1571,15 +1587,15 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
has_field = true
mut embed_types := []ast.Type{}
field, embed_types = c.table.find_field_from_embeds(sym, field_name) or {
if err.msg != '' {
c.error(err.msg, node.pos)
if err.msg() != '' {
c.error(err.msg(), node.pos)
}
has_field = false
ast.StructField{}, []ast.Type{}
}
node.from_embed_types = embed_types
if sym.kind in [.aggregate, .sum_type] {
unknown_field_msg = err.msg
unknown_field_msg = err.msg()
}
}
if !c.inside_unsafe {
@ -1600,8 +1616,8 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
has_field = true
mut embed_types := []ast.Type{}
field, embed_types = c.table.find_field_from_embeds(gs, field_name) or {
if err.msg != '' {
c.error(err.msg, node.pos)
if err.msg() != '' {
c.error(err.msg(), node.pos)
}
has_field = false
ast.StructField{}, []ast.Type{}
@ -1636,6 +1652,20 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
suggestion := util.new_suggestion(field_name, sym.info.fields.map(it.name))
c.error(suggestion.say(unknown_field_msg), node.pos)
}
// >> Hack to allow old style custom error implementations
// TODO: remove once deprecation period for `IError` methods has ended
if sym.name == 'IError' && (field_name == 'msg' || field_name == 'code') {
method := c.table.find_method(sym, field_name) or {
c.error('invalid `IError` interface implementation: $err', node.pos)
return ast.void_type
}
c.note('the `.$field_name` field on `IError` is deprecated, use `.${field_name}()` instead.',
node.pos)
return method.return_type
}
// <<<
c.error(unknown_field_msg, node.pos)
}
return ast.void_type
@ -2128,7 +2158,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
if flag.contains('@VROOT') {
// c.note(checker.vroot_is_deprecated_message, node.pos)
vroot := util.resolve_vmodroot(flag.replace('@VROOT', '@VMODROOT'), c.file.path) or {
c.error(err.msg, node.pos)
c.error(err.msg(), node.pos)
return
}
node.val = 'include $vroot'
@ -2143,7 +2173,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
}
if flag.contains('@VMODROOT') {
vroot := util.resolve_vmodroot(flag, c.file.path) or {
c.error(err.msg, node.pos)
c.error(err.msg(), node.pos)
return
}
node.val = 'include $vroot'
@ -2152,7 +2182,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
}
if flag.contains('\$env(') {
env := util.resolve_env_value(flag, true) or {
c.error(err.msg, node.pos)
c.error(err.msg(), node.pos)
return
}
node.main = env
@ -2171,15 +2201,15 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
'--cflags --libs $node.main'.split(' ')
}
mut m := pkgconfig.main(args) or {
c.error(err.msg, node.pos)
c.error(err.msg(), node.pos)
return
}
cflags := m.run() or {
c.error(err.msg, node.pos)
c.error(err.msg(), node.pos)
return
}
c.table.parse_cflag(cflags, c.mod, c.pref.compile_defines_all) or {
c.error(err.msg, node.pos)
c.error(err.msg(), node.pos)
return
}
}
@ -2189,7 +2219,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
if flag.contains('@VROOT') {
// c.note(checker.vroot_is_deprecated_message, node.pos)
flag = util.resolve_vmodroot(flag.replace('@VROOT', '@VMODROOT'), c.file.path) or {
c.error(err.msg, node.pos)
c.error(err.msg(), node.pos)
return
}
}
@ -2199,13 +2229,13 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
}
if flag.contains('@VMODROOT') {
flag = util.resolve_vmodroot(flag, c.file.path) or {
c.error(err.msg, node.pos)
c.error(err.msg(), node.pos)
return
}
}
if flag.contains('\$env(') {
flag = util.resolve_env_value(flag, true) or {
c.error(err.msg, node.pos)
c.error(err.msg(), node.pos)
return
}
}
@ -2219,7 +2249,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
}
// println('adding flag "$flag"')
c.table.parse_cflag(flag, c.mod, c.pref.compile_defines_all) or {
c.error(err.msg, node.pos)
c.error(err.msg(), node.pos)
}
}
else {
@ -3016,14 +3046,6 @@ pub fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
typ: typ
is_optional: is_optional
}
if typ == ast.error_type && c.expected_type == ast.string_type
&& !c.using_new_err_struct && !c.inside_selector_expr
&& !c.inside_println_arg && !c.file.mod.name.contains('v.')
&& !c.is_builtin_mod {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <- TODO: remove; this prevents a failure in the `performance-regressions` CI job
c.warn('string errors are deprecated; use `err.msg` instead',
node.pos)
}
// if typ == ast.t_type {
// sym := c.table.sym(c.cur_generic_type)
// println('IDENT T unresolved $node.name typ=$sym.name')

View File

@ -12,7 +12,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
node.left_type = c.expr(node.left)
if node.is_env {
env_value := util.resolve_env_value("\$env('$node.args_var')", false) or {
c.error(err.msg, node.env_pos)
c.error(err.msg(), node.env_pos)
return ast.string_type
}
node.env_value = env_value
@ -476,7 +476,7 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) bool {
left_type := c.expr(cond.left)
right_type := c.expr(cond.right)
expr := c.find_definition(cond.left) or {
c.error(err.msg, cond.left.pos)
c.error(err.msg(), cond.left.pos)
return false
}
if !c.check_types(right_type, left_type) {
@ -558,7 +558,7 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) bool {
return false
}
expr := c.find_obj_definition(cond.obj) or {
c.error(err.msg, cond.pos)
c.error(err.msg(), cond.pos)
return false
}
if !c.check_types(typ, ast.bool_type) {
@ -573,7 +573,7 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) bool {
ast.ComptimeCall {
if cond.is_pkgconfig {
mut m := pkgconfig.main([cond.args_var]) or {
c.error(err.msg, cond.pos)
c.error(err.msg(), cond.pos)
return true
}
m.run() or { return true }

View File

@ -22,7 +22,7 @@ pub fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
default_typ := c.check_expr_opt_call(default_expr, c.expr(default_expr))
node.default_type = default_typ
c.check_expected(default_typ, node.elem_type) or {
c.error(err.msg, default_expr.pos())
c.error(err.msg(), default_expr.pos())
}
}
if node.has_len {
@ -117,7 +117,7 @@ pub fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
}
if expr !is ast.TypeNode {
c.check_expected(typ, elem_type) or {
c.error('invalid array element: $err.msg', expr.pos())
c.error('invalid array element: $err.msg()', expr.pos())
}
}
}

View File

@ -894,7 +894,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
continue
}
}
c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos)
c.error('$err.msg() in argument ${i + 1} to `$fn_name`', call_arg.pos)
}
// Warn about automatic (de)referencing, which will be removed soon.
if func.language != .c && !c.inside_unsafe && typ.nr_muls() != param.typ.nr_muls()
@ -936,7 +936,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
continue
}
c.check_expected_call_arg(utyp, unwrap_typ, node.language, call_arg) or {
c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos)
c.error('$err.msg() in argument ${i + 1} to `$fn_name`', call_arg.pos)
}
}
}
@ -1143,8 +1143,8 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
has_method = true
mut embed_types := []ast.Type{}
method, embed_types = c.table.find_method_from_embeds(left_sym, method_name) or {
if err.msg != '' {
c.error(err.msg, node.pos)
if err.msg() != '' {
c.error(err.msg(), node.pos)
}
has_method = false
ast.Fn{}, []ast.Type{}
@ -1156,7 +1156,7 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
}
if left_sym.kind == .aggregate {
// the error message contains the problematic type
unknown_method_msg = err.msg
unknown_method_msg = err.msg()
}
}
if has_method {
@ -1285,7 +1285,7 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
// continue
// }
if got_arg_typ != ast.void_type {
c.error('$err.msg in argument ${i + 1} to `${left_sym.name}.$method_name`',
c.error('$err.msg() in argument ${i + 1} to `${left_sym.name}.$method_name`',
arg.pos)
}
}
@ -1432,7 +1432,7 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
c.check_expected_call_arg(targ, c.unwrap_generic(exp_arg_typ), node.language,
arg) or {
if targ != ast.void_type {
c.error('$err.msg in argument ${i + 1} to `${left_sym.name}.$method_name`',
c.error('$err.msg() in argument ${i + 1} to `${left_sym.name}.$method_name`',
arg.pos)
}
}
@ -1666,7 +1666,7 @@ fn (mut c Checker) map_builtin_method_call(mut node ast.CallExpr, left_type ast.
info := left_sym.info as ast.Map
arg_type := c.expr(node.args[0].expr)
c.check_expected_call_arg(arg_type, info.key_type, node.language, node.args[0]) or {
c.error('$err.msg in argument 1 to `Map.delete`', node.args[0].pos)
c.error('$err.msg() in argument 1 to `Map.delete`', node.args[0].pos)
}
}
else {}

View File

@ -203,7 +203,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
}
for st in branch.stmts {
// must not contain C statements
st.check_c_expr() or { c.error('`if` expression branch has $err.msg', st.pos) }
st.check_c_expr() or { c.error('`if` expression branch has $err.msg()', st.pos) }
}
}
if mut branch.cond is ast.IfGuardExpr {

View File

@ -41,7 +41,7 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
for st in branch.stmts[0..branch.stmts.len - 1] {
// must not contain C statements
st.check_c_expr() or {
c.error('`match` expression branch has $err.msg', st.pos)
c.error('`match` expression branch has $err.msg()', st.pos)
}
}
} else if ret_type != ast.void_type {

View File

@ -81,7 +81,7 @@ pub fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
}
}
} else {
c.error('incompatible initializer for field `$field.name`: $err.msg',
c.error('incompatible initializer for field `$field.name`: $err.msg()',
field.default_expr.pos())
}
}
@ -300,7 +300,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
}
} else if expr_type != ast.void_type && expr_type_sym.kind != .placeholder {
c.check_expected(c.unwrap_generic(expr_type), c.unwrap_generic(field_info.typ)) or {
c.error('cannot assign to field `$field_info.name`: $err.msg',
c.error('cannot assign to field `$field_info.name`: $err.msg()',
field.pos)
}
}

View File

@ -11,7 +11,7 @@ fn test_get_parent_mod_on_root_folder() {
// TODO: add an equivalent windows check for c:\
$if !windows {
assert '---' == get_parent_mod('/') or {
assert err.msg == 'root folder reached'
assert err.msg() == 'root folder reached'
'---'
}
}
@ -20,7 +20,7 @@ fn test_get_parent_mod_on_root_folder() {
fn test_get_parent_mod_current_folder() {
// TODO: this should may be return '' reliably on windows too:
// assert '' == get_parent_mod('.') or {
// assert err.msg == 'No V files found.'
// assert err.msg() == 'No V files found.'
// '---'
// }
}
@ -34,7 +34,7 @@ fn test_get_parent_mod_on_temp_dir() ? {
fn test_get_parent_mod_normal_cases() ? {
assert '---' == get_parent_mod(os.join_path(@VMODROOT, 'vlib/v')) or {
assert err.msg == 'No V files found.'
assert err.msg() == 'No V files found.'
'---'
}
// TODO: WTF?

View File

@ -67,7 +67,7 @@ fn test_fmt() {
continue
}
vfmt_result_file := os.join_path(tmpfolder, 'vfmt_run_over_$ifilename')
os.write_file(vfmt_result_file, result_ocontent) or { panic(err.msg) }
os.write_file(vfmt_result_file, result_ocontent) or { panic(err) }
eprintln(diff.color_compare_files(diff_cmd, opath, vfmt_result_file))
continue
}
@ -75,7 +75,7 @@ fn test_fmt() {
eprintln(fmt_bench.step_message_ok(vrelpath))
}
restore_bin2v_placeholder() or {
eprintln('failed restoring vbin2v_keep.vv placeholder: $err.msg')
eprintln('failed restoring vbin2v_keep.vv placeholder: $err.msg()')
}
fmt_bench.stop()
eprintln(term.h_divider('-'))
@ -90,7 +90,7 @@ fn prepare_bin2v_file(mut fmt_bench benchmark.Benchmark) {
fmt_bench.step()
write_bin2v_keep_content() or {
fmt_bench.fail()
eprintln(fmt_bench.step_message_fail('Failed preparing bin2v_keep.vv: $err.msg'))
eprintln(fmt_bench.step_message_fail('Failed preparing bin2v_keep.vv: $err.msg()'))
return
}
fmt_bench.ok()

View File

@ -34,13 +34,13 @@ fn branches_are_struct_inits() {
fn branches_are_call_exprs_with_or_blocks() {
match 'a' {
'b' { foo() or { panic(err.msg) } }
'b' { foo() or { panic(err) } }
}
match 'a' {
'b' {
foo() or {
// do stuff
panic(err.msg)
panic(err)
}
}
}
@ -48,7 +48,7 @@ fn branches_are_call_exprs_with_or_blocks() {
'b' {
foo() or {
another_stmt()
panic(err.msg)
panic(err)
}
}
}

View File

@ -51,8 +51,7 @@ fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
}
struct UnsupportedAssertCtempTransform {
msg string
code int
Error
}
const unsupported_ctemp_assert_transform = IError(UnsupportedAssertCtempTransform{})

View File

@ -6122,11 +6122,12 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
} else if or_block.kind == .propagate {
if g.file.mod.name == 'main' && (isnil(g.fn_decl) || g.fn_decl.is_main) {
// In main(), an `opt()?` call is sugar for `opt() or { panic(err) }`
err_msg := 'IError_name_table[${cvar_name}.err._typ]._method_msg(${cvar_name}.err._object)'
if g.pref.is_debug {
paline, pafile, pamod, pafn := g.panic_debug_info(or_block.pos)
g.writeln('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), *${cvar_name}.err.msg );')
g.writeln('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), $err_msg );')
} else {
g.writeln('\tpanic_optional_not_set(*${cvar_name}.err.msg);')
g.writeln('\tpanic_optional_not_set( $err_msg );')
}
} else if !isnil(g.fn_decl) && g.fn_decl.is_test {
g.gen_failing_error_propagation_for_test_fn(or_block, cvar_name)
@ -6899,6 +6900,16 @@ static inline __shared__$interface_name ${shared_fn_name}(__shared__$cctype* x)
methods_struct.writeln('\t\t._method_${c_name(method.name)} = (void*) $method_call,')
}
}
// >> Hack to allow old style custom error implementations
// TODO: remove once deprecation period for `IError` methods has ended
// fix MSVC not handling empty struct inits
if methods.len == 0 && interface_name == 'IError' {
methods_struct.writeln('\t\t._method_msg = NULL,')
methods_struct.writeln('\t\t._method_code = NULL,')
}
// <<
if g.pref.build_mode != .build_module {
methods_struct.writeln('\t},')
}

View File

@ -166,19 +166,21 @@ pub fn (mut g Gen) write_tests_definitions() {
pub fn (mut g Gen) gen_failing_error_propagation_for_test_fn(or_block ast.OrExpr, cvar_name string) {
// in test_() functions, an `opt()?` call is sugar for
// `or { cb_propagate_test_error(@LINE, @FILE, @MOD, @FN, err.msg) }`
// `or { cb_propagate_test_error(@LINE, @FILE, @MOD, @FN, err.msg() ) }`
// and the test is considered failed
paline, pafile, pamod, pafn := g.panic_debug_info(or_block.pos)
g.writeln('\tmain__TestRunner_name_table[test_runner._typ]._method_fn_error(test_runner._object, $paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), *(${cvar_name}.err.msg) );')
err_msg := 'IError_name_table[${cvar_name}.err._typ]._method_msg(${cvar_name}.err._object)'
g.writeln('\tmain__TestRunner_name_table[test_runner._typ]._method_fn_error(test_runner._object, $paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), $err_msg );')
g.writeln('\tlongjmp(g_jump_buffer, 1);')
}
pub fn (mut g Gen) gen_failing_return_error_for_test_fn(return_stmt ast.Return, cvar_name string) {
// in test_() functions, a `return error('something')` is sugar for
// `or { err := error('something') cb_propagate_test_error(@LINE, @FILE, @MOD, @FN, err.msg) return err }`
// `or { err := error('something') cb_propagate_test_error(@LINE, @FILE, @MOD, @FN, err.msg() ) return err }`
// and the test is considered failed
paline, pafile, pamod, pafn := g.panic_debug_info(return_stmt.pos)
g.writeln('\tmain__TestRunner_name_table[test_runner._typ]._method_fn_error(test_runner._object, $paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), *(${cvar_name}.err.msg) );')
err_msg := 'IError_name_table[${cvar_name}.err._typ]._method_msg(${cvar_name}.err._object)'
g.writeln('\tmain__TestRunner_name_table[test_runner._typ]._method_fn_error(test_runner._object, $paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), $err_msg );')
g.writeln('\tlongjmp(g_jump_buffer, 1);')
}

View File

@ -320,7 +320,7 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) bool {
}
ast.PostfixExpr {
ifdef := g.comptime_if_to_ifdef((cond.expr as ast.Ident).name, true) or {
verror(err.msg)
verror(err.msg())
return false
}
g.write('defined($ifdef)')

View File

@ -74,7 +74,7 @@ fn (mut g JsGen) comptime_if_cond(cond ast.Expr, pkg_exist bool) bool {
}
ast.PostfixExpr {
ifdef := g.comptime_if_to_ifdef((cond.expr as ast.Ident).name, true) or {
verror(err.msg)
verror(err.msg())
return false
}
g.write('$ifdef')

View File

@ -1057,8 +1057,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
}
struct UnsupportedAssertCtempTransform {
msg string
code int
Error
}
const unsupported_ctemp_assert_transform = IError(UnsupportedAssertCtempTransform{})

View File

@ -218,7 +218,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
if op == .decl_assign {
// a, b := a + 1, b
for r in right {
p.check_undefined_variables(left, r) or { return p.error_with_pos(err.msg, pos) }
p.check_undefined_variables(left, r) or { return p.error_with_pos(err.msg(), pos) }
}
} else if left.len > 1 {
// a, b = b, a

View File

@ -32,6 +32,7 @@ pub fn (mut p Parser) parse_array_type(expecting token.Kind) ast.Type {
fixed_size = const_field.expr.val.int()
} else {
if mut const_field.expr is ast.InfixExpr {
// QUESTION: this should most likely no be done in the parser, right?
mut t := transformer.new_transformer(p.pref)
folded_expr := t.infix_expr(mut const_field.expr)

View File

@ -41,7 +41,7 @@ fn (mut p Parser) sql_expr() ast.Expr {
if e.right is ast.Ident {
if !p.scope.known_var(e.right.name) {
p.check_undefined_variables([e.left], e.right) or {
return p.error_with_pos(err.msg, e.right.pos)
return p.error_with_pos(err.msg(), e.right.pos)
}
}
}

View File

@ -21,7 +21,9 @@ fn test_dependency_resolution_fails_correctly() {
mut errors := []string{}
for pc in pc_files {
pcname := os.file_name(pc).replace('.pc', '')
pkgconfig.load(pcname, use_default_paths: false, path: samples_dir) or { errors << err.msg }
pkgconfig.load(pcname, use_default_paths: false, path: samples_dir) or {
errors << err.msg()
}
}
assert errors.len < pc_files.len
assert errors == ['could not resolve dependency xyz-unknown-package']

View File

@ -110,7 +110,7 @@ pub fn new_scanner_file(file_path string, comments_mode CommentsMode, pref &pref
verror('$file_path is not a file')
}
raw_text := util.read_file(file_path) or {
verror(err.msg)
verror(err.msg())
return voidptr(0)
}
mut s := &Scanner{

View File

@ -44,7 +44,7 @@ const return_types = [
ReturnType{
name: '?'
init: "error('an error')"
assertion: " or { assert err.msg == 'an error' return }\npanic('got no error')"
assertion: " or { assert err.msg() == 'an error' return }\npanic('got no error')"
no_assert_kw: true
},
ReturnType{

View File

@ -51,7 +51,7 @@ fn test_multiple_ret() {
// none case
wrapper1 := fn () (string, string) {
res2_1, res2_2 := split_to_two('') or {
assert err.msg == ''
assert err.msg() == ''
return 'replaced', 'val'
}
return res2_1, res2_2
@ -63,7 +63,7 @@ fn test_multiple_ret() {
// error case
wrapper2 := fn () (string, string) {
res3_1, res3_2 := split_to_two('fishhouse') or {
assert err.msg == 'error'
assert err.msg() == 'error'
return 'replaced', 'val'
}
return res3_1, res3_2

View File

@ -26,7 +26,7 @@ fn test_if_expr_of_optional() {
if _ := foo3() {
assert false
} else {
assert err.msg == 'foo3 error'
assert err.msg() == 'foo3 error'
}
a4 := foo4() or { panic('error') }

View File

@ -3,7 +3,7 @@ import os
fn main() {
vexe := os.getenv('VEXE')
vroot := os.dir(vexe)
mut files := os.ls(vroot) or { panic(err.msg) }
mut files := os.ls(vroot) or { panic(err) }
files.sort()
for file in files {
if file.ends_with('.md') {

View File

@ -12,7 +12,7 @@ fn test_lhs_option() {
}
fn ret_no_opt(n int) int {
return f(n) or { panic(err.msg) }
return f(n) or { panic(err) }
}
fn test_opt_return_no_opt() {

View File

@ -7,11 +7,11 @@ fn test_err_with_code() {
assert false
_ := w
} else {
assert err.msg == 'hi'
assert err.msg() == 'hi'
assert err.code == 137
}
v := opt_err_with_code() or {
assert err.msg == 'hi'
assert err.msg() == 'hi'
assert err.code == 137
return
}
@ -25,7 +25,7 @@ fn opt_err() ?string {
fn test_err() {
v := opt_err() or {
assert err.msg == 'hi'
assert err.msg() == 'hi'
return
}
assert false
@ -74,7 +74,7 @@ fn test_if_else_opt() {
if _ := err_call(false) {
assert false
} else {
assert err.msg.len != 0
assert err.msg().len != 0
}
}
@ -151,12 +151,12 @@ fn test_or_return() {
if _ := or_return_error() {
assert false
} else {
assert err.msg.len != 0
assert err.msg().len != 0
}
if _ := or_return_none() {
assert false
} else {
assert err.msg.len == 0
assert err.msg().len == 0
}
}
@ -283,7 +283,7 @@ fn test_optional_void_return_types_of_anon_fn() {
}
f(0) or {
assert err.msg == '0'
assert err.msg() == '0'
return
}
}
@ -304,7 +304,7 @@ fn test_option_void_return_types_of_anon_fn_in_struct() {
}
foo.f(0) or {
assert err.msg == '0'
assert err.msg() == '0'
return
}
}

View File

@ -5,7 +5,7 @@ fn foo() ? {
fn test_optional_void() {
foo() or {
println(err)
assert err.msg == 'something'
assert err.msg() == 'something'
return
}
}
@ -17,7 +17,7 @@ fn bar() ? {
fn test_optional_void_only_question() {
bar() or {
println(err)
assert err.msg == 'bar error'
assert err.msg() == 'bar error'
return
}
}
@ -38,12 +38,12 @@ fn option_void(a int) ? {
fn test_optional_void_with_return() {
option_void(0) or {
println(err)
assert err.msg == 'zero error'
assert err.msg() == 'zero error'
return
}
option_void(-1) or {
println(err)
assert err.msg == 'zero error'
assert err.msg() == 'zero error'
return
}
assert true

View File

@ -15,7 +15,7 @@ fn test_all_v_prod_files() {
bmark.step()
fres := runner.run_prod_file(options.wd, options.vexec, file) or {
bmark.fail()
eprintln(bmark.step_message_fail(err.msg))
eprintln(bmark.step_message_fail(err.msg()))
assert false
continue
}

View File

@ -83,7 +83,7 @@ fn worker_repl(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
session.bmark.fail()
tls_bench.fail()
os.rmdir_all(tfolder) or { panic(err) }
eprintln(tls_bench.step_message_fail(err.msg))
eprintln(tls_bench.step_message_fail(err.msg()))
assert false
return pool.no_result
}

View File

@ -35,7 +35,7 @@ pub fn full_path_to_v(dirs_in int) string {
}
fn diff_files(file_result string, file_expected string) string {
diffcmd := diff.find_working_diff_command() or { return err.msg }
diffcmd := diff.find_working_diff_command() or { return err.msg() }
return diff.color_compare_files(diffcmd, file_result, file_expected)
}

View File

@ -374,7 +374,7 @@ fn test_fields_anon_fn_with_optional_void_return_type() {
}
}
foo.f() or { assert err.msg == 'oops' }
foo.f() or { assert err.msg() == 'oops' }
foo.g() or { assert false }
}

View File

@ -38,7 +38,7 @@ fn test_decode() {
assert data.dependencies[0] == 'hello'
assert data.unknown['test'][0] == 'foo'
vmod.decode('') or {
assert err.msg == 'vmod: no content.'
assert err.msg() == 'vmod: no content.'
exit(0)
}
}

View File

@ -8,6 +8,9 @@ pub struct Transformer {
pref &pref.Preferences
pub mut:
index &IndexState
table &ast.Table = 0
mut:
is_assert bool
}
pub fn new_transformer(pref &pref.Preferences) &Transformer {
@ -20,6 +23,12 @@ pub fn new_transformer(pref &pref.Preferences) &Transformer {
}
}
pub fn new_transformer_with_table(table &ast.Table, pref &pref.Preferences) &Transformer {
mut transformer := new_transformer(pref)
transformer.table = table
return transformer
}
pub fn (mut t Transformer) transform_files(ast_files []&ast.File) {
for i in 0 .. ast_files.len {
mut file := unsafe { ast_files[i] }
@ -104,57 +113,6 @@ pub fn (mut t Transformer) find_mut_self_assign(node ast.AssignStmt) {
// even if mutable we can be sure than `a[1] = a[2] is safe
}
pub fn (mut t Transformer) find_assert_len(mut node ast.InfixExpr) ast.Expr {
if !t.pref.is_prod {
return node
}
right := t.expr(mut node.right)
match right {
ast.IntegerLiteral {
left := t.expr(mut node.left)
if left is ast.SelectorExpr {
len := right.val.int()
if left.field_name == 'len' {
match node.op {
.eq { // ==
t.index.safe_access(left.expr.str(), len - 1)
}
.ge { // >=
t.index.safe_access(left.expr.str(), len - 1)
}
.gt { // >
t.index.safe_access(left.expr.str(), len)
}
else {}
}
}
}
}
ast.SelectorExpr {
left := t.expr(mut node.left)
if left is ast.IntegerLiteral {
len := left.val.int()
if right.field_name == 'len' {
match node.op {
.eq { // ==
t.index.safe_access(right.expr.str(), len - 1)
}
.le { // <=
t.index.safe_access(right.expr.str(), len - 1)
}
.lt { // <
t.index.safe_access(right.expr.str(), len)
}
else {}
}
}
}
}
else {}
}
return node
}
pub fn (mut t Transformer) check_safe_array(mut node ast.IndexExpr) {
if !t.pref.is_prod {
return
@ -212,14 +170,7 @@ pub fn (mut t Transformer) stmt(mut node ast.Stmt) ast.Stmt {
ast.NodeError {}
ast.AsmStmt {}
ast.AssertStmt {
match mut node.expr {
ast.InfixExpr {
node.expr = t.find_assert_len(mut node.expr)
}
else {
node.expr = t.expr(mut node.expr)
}
}
return t.assert_stmt(mut node)
}
ast.AssignStmt {
t.find_new_array_len(node)
@ -312,9 +263,7 @@ pub fn (mut t Transformer) stmt(mut node ast.Stmt) ast.Stmt {
}
ast.Import {}
ast.InterfaceDecl {
for mut field in node.fields {
field.default_expr = t.expr(mut field.default_expr)
}
return t.interface_decl(mut node)
}
ast.Module {}
ast.Return {
@ -333,6 +282,63 @@ pub fn (mut t Transformer) stmt(mut node ast.Stmt) ast.Stmt {
return node
}
pub fn (mut t Transformer) assert_stmt(mut node ast.AssertStmt) ast.Stmt {
t.is_assert = true
node.expr = t.expr(mut node.expr)
if !t.pref.is_prod {
return node
}
if mut node.expr is ast.InfixExpr {
right := node.expr.right
match right {
ast.IntegerLiteral {
left := node.expr.left
if left is ast.SelectorExpr {
len := right.val.int()
if left.field_name == 'len' {
match node.expr.op {
.eq { // ==
t.index.safe_access(left.expr.str(), len - 1)
}
.ge { // >=
t.index.safe_access(left.expr.str(), len - 1)
}
.gt { // >
t.index.safe_access(left.expr.str(), len)
}
else {}
}
}
}
}
ast.SelectorExpr {
left := node.expr.left
if left is ast.IntegerLiteral {
len := left.val.int()
if right.field_name == 'len' {
match node.expr.op {
.eq { // ==
t.index.safe_access(right.expr.str(), len - 1)
}
.le { // <=
t.index.safe_access(right.expr.str(), len - 1)
}
.lt { // <
t.index.safe_access(right.expr.str(), len)
}
else {}
}
}
}
}
else {}
}
}
t.is_assert = false
return node
}
pub fn (mut t Transformer) expr_stmt_if_expr(mut node ast.IfExpr) ast.Expr {
mut stop_index, mut unreachable_branches := -1, []int{cap: node.branches.len}
if node.is_comptime {
@ -497,6 +503,14 @@ pub fn (mut t Transformer) for_stmt(mut node ast.ForStmt) ast.Stmt {
return node
}
pub fn (mut t Transformer) interface_decl(mut node ast.InterfaceDecl) ast.Stmt {
for mut field in node.fields {
field.default_expr = t.expr(mut field.default_expr)
}
return node
}
pub fn (mut t Transformer) expr(mut node ast.Expr) ast.Expr {
match mut node {
ast.AnonFn {
@ -629,6 +643,11 @@ pub fn (mut t Transformer) expr(mut node ast.Expr) ast.Expr {
ast.SqlExpr {
return t.sql_expr(mut node)
}
ast.StringInterLiteral {
for mut expr in node.exprs {
expr = t.expr(mut expr)
}
}
ast.StructInit {
node.update_expr = t.expr(mut node.update_expr)
for mut field in node.fields {
@ -661,7 +680,7 @@ pub fn (mut t Transformer) infix_expr(mut node ast.InfixExpr) ast.Expr {
pos.extend(node.pos)
pos.extend(node.right.pos())
if t.pref.is_debug {
if t.pref.is_debug || t.is_assert { // never optimize assert statements
return node
} else {
match mut node.left {

View File

@ -34,7 +34,7 @@ fn parse_attrs(name string, attrs []string) ?([]http.Method, string) {
}
if x.len > 0 {
return IError(http.UnexpectedExtraAttributeError{
msg: 'Encountered unexpected extra attributes: $x'
attributes: x
})
}
if methods.len == 0 {

View File

@ -68,7 +68,7 @@ fn assert_common_headers(received string) {
fn test_a_simple_tcp_client_can_connect_to_the_vweb_server() {
received := simple_tcp_client(path: '/') or {
assert err.msg == ''
assert err.msg() == ''
return
}
assert_common_headers(received)
@ -79,7 +79,7 @@ fn test_a_simple_tcp_client_can_connect_to_the_vweb_server() {
fn test_a_simple_tcp_client_simple_route() {
received := simple_tcp_client(path: '/simple') or {
assert err.msg == ''
assert err.msg() == ''
return
}
assert_common_headers(received)
@ -92,7 +92,7 @@ fn test_a_simple_tcp_client_zero_content_length() {
// tests that sending a content-length header of 0 doesn't hang on a read timeout
watch := time.new_stopwatch(auto_start: true)
simple_tcp_client(path: '/', headers: 'Content-Length: 0\r\n\r\n') or {
assert err.msg == ''
assert err.msg() == ''
return
}
assert watch.elapsed() < 1 * time.second
@ -100,7 +100,7 @@ fn test_a_simple_tcp_client_zero_content_length() {
fn test_a_simple_tcp_client_html_page() {
received := simple_tcp_client(path: '/html_page') or {
assert err.msg == ''
assert err.msg() == ''
return
}
assert_common_headers(received)
@ -230,7 +230,7 @@ $contents\r
fn test_http_client_shutdown_does_not_work_without_a_cookie() {
x := http.get('http://$localserver/shutdown') or {
assert err.msg == ''
assert err.msg() == ''
return
}
assert x.status() == .not_found
@ -247,7 +247,7 @@ fn testsuite_end() {
'skey': 'superman'
}
) or {
assert err.msg == ''
assert err.msg() == ''
return
}
assert x.status() == .ok

View File

@ -255,7 +255,7 @@ pub fn (mut ctx Context) json_pretty<T>(j T) Result {
pub fn (mut ctx Context) file(f_path string) Result {
ext := os.file_ext(f_path)
data := os.read_file(f_path) or {
eprint(err.msg)
eprint(err.msg())
ctx.server_error(500)
return Result{}
}
@ -417,7 +417,7 @@ pub fn run_at<T>(global_app &T, host string, port int) {
request_app.Context = global_app.Context // copy the context ref that contains static files map etc
mut conn := l.accept() or {
// failures should not panic
eprintln('accept() failed with error: $err.msg')
eprintln('accept() failed with error: $err.msg()')
continue
}
go handle_conn<T>(mut conn, mut request_app, routes)

View File

@ -22,13 +22,11 @@ mut:
}
struct InvalidTokenError {
msg string
code int
MessageError
}
struct UnknownTokenError {
msg string
code int
MessageError
}
fn (mut p Parser) next() {

View File

@ -43,7 +43,7 @@ fn test_raw_decode_null() ? {
fn test_raw_decode_invalid() ? {
raw_decode('1z') or {
assert err.msg == '[x.json2] invalid token `z` (0:17)'
assert err.msg() == '[x.json2] invalid token `z` (0:17)'
return
}
assert false