diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 8011ee9e95..6a35dbd4a6 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -310,10 +310,7 @@ pub: is_mut bool is_global bool is_volatile bool - // is_deprecated bool - deprecation_msg string - deprecated_after string pub mut: default_expr Expr default_expr_typ Type diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 8cd14fac60..a2db1f1093 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -4,7 +4,6 @@ [has_globals] module ast -import time import v.cflag import v.token import v.util @@ -41,8 +40,8 @@ pub mut: gostmts int // how many `go` statements there were in the parsed files. // When table.gostmts > 0, __VTHREADS__ is defined, which can be checked with `$if threads {` enum_decls map[string]EnumDecl - mdeprecated_msg map[string]string // module deprecation message - mdeprecated_after map[string]time.Time // module deprecation date + module_deprecated map[string]bool + module_attrs map[string][]Attr // module attributes builtin_pub_fns map[string]bool pointer_size int // cache for type_to_str_using_aliases @@ -319,15 +318,6 @@ pub fn (t &Table) known_fn(name string) bool { return true } -pub fn (mut t Table) mark_module_as_deprecated(mname string, message string) { - t.mdeprecated_msg[mname] = message - t.mdeprecated_after[mname] = time.now() -} - -pub fn (mut t Table) mark_module_as_deprecated_after(mname string, after_date string) { - t.mdeprecated_after[mname] = time.parse_iso8601(after_date) or { time.now() } -} - pub fn (mut t Table) register_fn(new_fn Fn) { t.fns[new_fn.name] = new_fn if new_fn.is_pub && new_fn.mod == 'builtin' { diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 83fa231661..f033d20a41 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -109,7 +109,7 @@ pub enum TypeFlag { /* To save precious TypeFlag bits the 4 possible ShareTypes are coded in the two - bits `shared` and `atomic_or_rw` (see sharetype_from_flags() below). +bits `shared` and `atomic_or_rw` (see sharetype_from_flags() below). */ pub enum ShareType { mut_t diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 55008bfdd3..4ba88021ba 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1234,15 +1234,7 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { } field_sym := c.table.sym(field.typ) if field.is_deprecated && is_used_outside { - now := time.now() - mut after_time := now - if field.deprecated_after != '' { - after_time = time.parse_iso8601(field.deprecated_after) or { - c.error('invalid time format', field.pos) - now - } - } - c.deprecate('field', field_name, field.deprecation_msg, now, after_time, node.pos) + c.deprecate('field', field_name, field.attrs, node.pos) } if field_sym.kind in [.sum_type, .interface_] { if !prevent_sum_type_unwrapping_once { @@ -1943,10 +1935,8 @@ fn (mut c Checker) import_stmt(node ast.Import) { } c.error('module `$node.mod` has no constant or function `$sym.name`', sym.pos) } - if after_time := c.table.mdeprecated_after[node.mod] { - now := time.now() - deprecation_message := c.table.mdeprecated_msg[node.mod] - c.deprecate('module', node.mod, deprecation_message, now, after_time, node.pos) + if c.table.module_deprecated[node.mod] { + c.deprecate('module', node.mod, c.table.module_attrs[node.mod], node.pos) } } @@ -3866,3 +3856,42 @@ pub fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ ast.Type, what stri pos) } } + +fn (mut c Checker) deprecate(kind string, name string, attrs []ast.Attr, pos token.Pos) { + mut deprecation_message := '' + now := time.now() + mut after_time := now + for attr in attrs { + if attr.name == 'deprecated' && attr.arg != '' { + deprecation_message = attr.arg + } + if attr.name == 'deprecated_after' && attr.arg != '' { + after_time = time.parse_iso8601(attr.arg) or { + c.error('invalid time format', attr.pos) + now + } + } + } + start_message := '$kind `$name`' + error_time := after_time.add_days(180) + if error_time < now { + c.error(semicolonize('$start_message has been deprecated since $after_time.ymmdd()', + deprecation_message), pos) + } else if after_time < now { + c.warn(semicolonize('$start_message has been deprecated since $after_time.ymmdd(), it will be an error after $error_time.ymmdd()', + deprecation_message), pos) + } else if after_time == now { + c.warn(semicolonize('$start_message has been deprecated', deprecation_message), + pos) + } else { + c.note(semicolonize('$start_message will be deprecated after $after_time.ymmdd(), and will become an error after $error_time.ymmdd()', + deprecation_message), pos) + } +} + +fn semicolonize(main string, details string) string { + if details == '' { + return main + } + return '$main; $details' +} diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 2219379458..c65edbdcd4 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -2,7 +2,6 @@ module checker import v.ast import v.pref -import time import v.util import v.token @@ -725,7 +724,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) c.error('function `$func.name` is private', node.pos) } if !isnil(c.table.cur_fn) && !c.table.cur_fn.is_deprecated && func.is_deprecated { - c.deprecate_fnmethod('function', func.name, func, node) + c.deprecate('function', func.name, func.attrs, node.pos) } if func.is_unsafe && !c.inside_unsafe && (func.language != .c || (func.name[2] in [`m`, `s`] && func.mod == 'builtin')) { @@ -1479,7 +1478,7 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { node.pos) } if !isnil(c.table.cur_fn) && !c.table.cur_fn.is_deprecated && method.is_deprecated { - c.deprecate_fnmethod('method', '${left_sym.name}.$method.name', method, node) + c.deprecate('method', '${left_sym.name}.$method.name', method.attrs, node.pos) } c.set_node_expected_arg_types(mut node, method) if is_method_from_embed { @@ -1628,49 +1627,6 @@ fn (mut c Checker) set_node_expected_arg_types(mut node ast.CallExpr, func &ast. } } -fn (mut c Checker) deprecate_fnmethod(kind string, name string, the_fn ast.Fn, node ast.CallExpr) { - mut deprecation_message := '' - now := time.now() - mut after_time := now - for attr in the_fn.attrs { - if attr.name == 'deprecated' && attr.arg != '' { - deprecation_message = attr.arg - } - if attr.name == 'deprecated_after' && attr.arg != '' { - after_time = time.parse_iso8601(attr.arg) or { - c.error('invalid time format', attr.pos) - now - } - } - } - c.deprecate(kind, name, deprecation_message, now, after_time, node.pos) -} - -fn (mut c Checker) deprecate(kind string, name string, deprecation_message string, now time.Time, after_time time.Time, pos token.Pos) { - start_message := '$kind `$name`' - error_time := after_time.add_days(180) - if error_time < now { - c.error(semicolonize('$start_message has been deprecated since $after_time.ymmdd()', - deprecation_message), pos) - } else if after_time < now { - c.warn(semicolonize('$start_message has been deprecated since $after_time.ymmdd(), it will be an error after $error_time.ymmdd()', - deprecation_message), pos) - } else if after_time == now { - c.warn(semicolonize('$start_message has been deprecated', deprecation_message), - pos) - } else { - c.note(semicolonize('$start_message will be deprecated after $after_time.ymmdd(), and will become an error after $error_time.ymmdd()', - deprecation_message), pos) - } -} - -fn semicolonize(main string, details string) string { - if details == '' { - return main - } - return '$main; $details' -} - fn (mut c Checker) post_process_generic_fns() { // Loop thru each generic function concrete type. // Check each specific fn instantiation. diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 1f321e3012..6e0cbf091a 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -3145,15 +3145,11 @@ fn (mut p Parser) module_decl() ast.Module { name_pos: name_pos } if !is_skipped { + p.table.module_attrs[p.mod] = module_attrs for ma in module_attrs { match ma.name { - 'deprecated' { - // [deprecated: 'use a replacement'] - p.table.mark_module_as_deprecated(p.mod, ma.arg) - } - 'deprecated_after' { - // [deprecated_after: '2027-12-30'] - p.table.mark_module_as_deprecated_after(p.mod, ma.arg) + 'deprecated', 'deprecated_after' { + p.table.module_deprecated[p.mod] = true } 'manualfree' { p.is_manualfree = true diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 1a929efc1b..2978119304 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -186,8 +186,6 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { field_start_pos := p.tok.pos() mut is_field_volatile := false mut is_field_deprecated := false - mut field_deprecation_msg := '' - mut field_deprecated_after := '' if p.tok.kind == .key_volatile { p.next() is_field_volatile = true @@ -254,16 +252,8 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { // attrs are stored in `p.attrs` p.attributes() for fa in p.attrs { - match fa.name { - 'deprecated' { - // [deprecated: 'use a replacement'] - is_field_deprecated = true - field_deprecation_msg = fa.arg - } - 'deprecated_after' { - field_deprecated_after = fa.arg - } - else {} + if fa.name == 'deprecated' { + is_field_deprecated = true } } } @@ -297,8 +287,6 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { is_global: is_field_global is_volatile: is_field_volatile is_deprecated: is_field_deprecated - deprecation_msg: field_deprecation_msg - deprecated_after: field_deprecated_after } } // save embeds as table fields too, it will be used in generation phase @@ -317,8 +305,6 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { is_global: is_field_global is_volatile: is_field_volatile is_deprecated: is_field_deprecated - deprecation_msg: field_deprecation_msg - deprecated_after: field_deprecated_after } p.attrs = [] i++