gen: add callconv attribute for fn and type (#14027)
parent
5905590e78
commit
68401d9dc8
57
doc/docs.md
57
doc/docs.md
|
@ -40,7 +40,7 @@ NB: You can also pass one of `-gcc`, `-msvc`, `-clang` to `make.bat` instead,
|
||||||
if you do prefer to use a different C compiler, but -tcc is small, fast, and
|
if you do prefer to use a different C compiler, but -tcc is small, fast, and
|
||||||
easy to install (V will download a prebuilt binary automatically).
|
easy to install (V will download a prebuilt binary automatically).
|
||||||
|
|
||||||
For C compiler downloads and more info, see
|
For C compiler downloads and more info, see
|
||||||
[here](https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Windows).
|
[here](https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Windows).
|
||||||
|
|
||||||
It is recommended to add this folder to the PATH of your environment variables.
|
It is recommended to add this folder to the PATH of your environment variables.
|
||||||
|
@ -843,7 +843,7 @@ println(nums.cap) // "3" or greater
|
||||||
nums = [] // The array is now empty
|
nums = [] // The array is now empty
|
||||||
println(nums.len) // "0"
|
println(nums.len) // "0"
|
||||||
```
|
```
|
||||||
`data` is a field (of type `voidptr`) with the address of the first
|
`data` is a field (of type `voidptr`) with the address of the first
|
||||||
element. This is for low-level [`unsafe`](#memory-unsafe-code) code.
|
element. This is for low-level [`unsafe`](#memory-unsafe-code) code.
|
||||||
|
|
||||||
Note that the fields are read-only and can't be modified by the user.
|
Note that the fields are read-only and can't be modified by the user.
|
||||||
|
@ -892,7 +892,7 @@ for i in 0 .. 1000 {
|
||||||
```
|
```
|
||||||
Note: The above code uses a [range `for`](#range-for) statement.
|
Note: The above code uses a [range `for`](#range-for) statement.
|
||||||
|
|
||||||
You can initialize the array by accessing the `it` variable which gives
|
You can initialize the array by accessing the `it` variable which gives
|
||||||
the index as shown here:
|
the index as shown here:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
|
@ -1022,7 +1022,7 @@ upper_fn := words.map(fn (w string) string {
|
||||||
println(upper_fn) // ['HELLO', 'WORLD']
|
println(upper_fn) // ['HELLO', 'WORLD']
|
||||||
```
|
```
|
||||||
|
|
||||||
`it` is a builtin variable which refers to the element currently being
|
`it` is a builtin variable which refers to the element currently being
|
||||||
processed in filter/map methods.
|
processed in filter/map methods.
|
||||||
|
|
||||||
Additionally, `.any()` and `.all()` can be used to conveniently test
|
Additionally, `.any()` and `.all()` can be used to conveniently test
|
||||||
|
@ -1035,8 +1035,8 @@ println(nums.all(it >= 2)) // false
|
||||||
```
|
```
|
||||||
|
|
||||||
There are further built-in methods for arrays:
|
There are further built-in methods for arrays:
|
||||||
* `a.repeat(n)` concatenates the array elements `n` times
|
* `a.repeat(n)` concatenates the array elements `n` times
|
||||||
* `a.insert(i, val)` inserts a new element `val` at index `i` and
|
* `a.insert(i, val)` inserts a new element `val` at index `i` and
|
||||||
shifts all following elements to the right
|
shifts all following elements to the right
|
||||||
* `a.insert(i, [3, 4, 5])` inserts several elements
|
* `a.insert(i, [3, 4, 5])` inserts several elements
|
||||||
* `a.prepend(val)` inserts a value at the beginning, equivalent to `a.insert(0, val)`
|
* `a.prepend(val)` inserts a value at the beginning, equivalent to `a.insert(0, val)`
|
||||||
|
@ -1052,7 +1052,7 @@ There are further built-in methods for arrays:
|
||||||
* `a.pop()` removes the last element and returns it
|
* `a.pop()` removes the last element and returns it
|
||||||
* `a.reverse()` makes a new array with the elements of `a` in reverse order
|
* `a.reverse()` makes a new array with the elements of `a` in reverse order
|
||||||
* `a.reverse_in_place()` reverses the order of elements in `a`
|
* `a.reverse_in_place()` reverses the order of elements in `a`
|
||||||
* `a.join(joiner)` concatenates an array of strings into one string
|
* `a.join(joiner)` concatenates an array of strings into one string
|
||||||
using `joiner` string as a separator
|
using `joiner` string as a separator
|
||||||
|
|
||||||
See also [vlib/arrays](https://modules.vlang.io/arrays.html).
|
See also [vlib/arrays](https://modules.vlang.io/arrays.html).
|
||||||
|
@ -1185,7 +1185,7 @@ println(b) // [7, 3]
|
||||||
|
|
||||||
V supports array and string slices with negative indexes.
|
V supports array and string slices with negative indexes.
|
||||||
Negative indexing starts from the end of the array towards the start,
|
Negative indexing starts from the end of the array towards the start,
|
||||||
for example `-3` is equal to `array.len - 3`.
|
for example `-3` is equal to `array.len - 3`.
|
||||||
Negative slices have a different syntax from normal slices, i.e. you need
|
Negative slices have a different syntax from normal slices, i.e. you need
|
||||||
to add a `gate` between the array name and the square bracket: `a#[..-3]`.
|
to add a `gate` between the array name and the square bracket: `a#[..-3]`.
|
||||||
The `gate` specifies that this is a different type of slice and remember that
|
The `gate` specifies that this is a different type of slice and remember that
|
||||||
|
@ -2223,7 +2223,7 @@ button.Size = Size{
|
||||||
If multiple embedded structs have methods or fields with the same name, or if methods or fields
|
If multiple embedded structs have methods or fields with the same name, or if methods or fields
|
||||||
with the same name are defined in the struct, you can call methods or assign to variables in
|
with the same name are defined in the struct, you can call methods or assign to variables in
|
||||||
the embedded struct like `button.Size.area()`.
|
the embedded struct like `button.Size.area()`.
|
||||||
When you do not specify the embedded struct name, the method of the outermost struct will be
|
When you do not specify the embedded struct name, the method of the outermost struct will be
|
||||||
targeted.
|
targeted.
|
||||||
|
|
||||||
## Unions
|
## Unions
|
||||||
|
@ -2951,7 +2951,7 @@ a convenience for writing `s.xyz()` instead of `xyz(s)`.
|
||||||
N.B. This feature is NOT a "default implementation" like in C#.
|
N.B. This feature is NOT a "default implementation" like in C#.
|
||||||
|
|
||||||
For example, if a struct `cat` is wrapped in an interface `a`, that has
|
For example, if a struct `cat` is wrapped in an interface `a`, that has
|
||||||
implemented a method with the same name `speak`, as a method implemented by
|
implemented a method with the same name `speak`, as a method implemented by
|
||||||
the struct, and you do `a.speak()`, *only* the interface method is called:
|
the struct, and you do `a.speak()`, *only* the interface method is called:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
|
@ -3491,13 +3491,13 @@ Above, `http.get` returns a `?http.Response`. `resp` is only in scope for the fi
|
||||||
|
|
||||||
## Custom error types
|
## Custom error types
|
||||||
|
|
||||||
V gives you the ability to define custom error types through the `IError` interface.
|
V gives you the ability to define custom error types through the `IError` interface.
|
||||||
The interface requires two methods: `msg() string` and `code() int`. Every type that
|
The interface requires two methods: `msg() string` and `code() int`. Every type that
|
||||||
implements these methods can be used as an error.
|
implements these methods can be used as an error.
|
||||||
|
|
||||||
When defining a custom error type it is recommended to embed the builtin `Error` default
|
When defining a custom error type it is recommended to embed the builtin `Error` default
|
||||||
implementation. This provides an empty default implementation for both required methods,
|
implementation. This provides an empty default implementation for both required methods,
|
||||||
so you only have to implement what you really need, and may provide additional utility
|
so you only have to implement what you really need, and may provide additional utility
|
||||||
functions in the future.
|
functions in the future.
|
||||||
|
|
||||||
```v
|
```v
|
||||||
|
@ -4112,8 +4112,8 @@ memory manually. (See [attributes](#attributes)).
|
||||||
_Note: right now autofree is hidden behind the -autofree flag. It will be enabled by
|
_Note: right now autofree is hidden behind the -autofree flag. It will be enabled by
|
||||||
default in V 0.3. If autofree is not used, V programs will leak memory._
|
default in V 0.3. If autofree is not used, V programs will leak memory._
|
||||||
|
|
||||||
Note 2: Autofree is still WIP. Until it stabilises and becomes the default, please
|
Note 2: Autofree is still WIP. Until it stabilises and becomes the default, please
|
||||||
compile your long running processes with `-gc boehm`, which will use the
|
compile your long running processes with `-gc boehm`, which will use the
|
||||||
Boehm-Demers-Weiser conservative garbage collector, to free the memory, that your
|
Boehm-Demers-Weiser conservative garbage collector, to free the memory, that your
|
||||||
programs leak, at runtime.
|
programs leak, at runtime.
|
||||||
|
|
||||||
|
@ -4702,7 +4702,7 @@ Modules are up to date.
|
||||||
at the top of all files in your module. For `mymodule.v`:
|
at the top of all files in your module. For `mymodule.v`:
|
||||||
```v
|
```v
|
||||||
module mymodule
|
module mymodule
|
||||||
|
|
||||||
pub fn hello_world() {
|
pub fn hello_world() {
|
||||||
println('Hello World!')
|
println('Hello World!')
|
||||||
}
|
}
|
||||||
|
@ -5745,11 +5745,11 @@ fn main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
Build this example with `v -live message.v`.
|
Build this example with `v -live message.v`.
|
||||||
|
|
||||||
You can also run this example with `v -live run message.v`.
|
You can also run this example with `v -live run message.v`.
|
||||||
Make sure that in command you use a path to a V's file,
|
Make sure that in command you use a path to a V's file,
|
||||||
**not** a path to a folder (like `v -live run .`) -
|
**not** a path to a folder (like `v -live run .`) -
|
||||||
in that case you need to modify content of a folder (add new file, for example),
|
in that case you need to modify content of a folder (add new file, for example),
|
||||||
because changes in *message.v* will have no effect.
|
because changes in *message.v* will have no effect.
|
||||||
|
|
||||||
Functions that you want to be reloaded must have `[live]` attribute
|
Functions that you want to be reloaded must have `[live]` attribute
|
||||||
|
@ -5978,10 +5978,15 @@ fn custom_allocations() {
|
||||||
struct C.Foo {
|
struct C.Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used in Win32 API code when you need to pass callback function
|
// Used to add a custom calling convention to a function, available calling convention: stdcall, fastcall and cdecl.
|
||||||
[windows_stdcall]
|
// This list aslo apply for type aliases (see below).
|
||||||
|
[callconv: "stdcall"]
|
||||||
fn C.DefWindowProc(hwnd int, msg int, lparam int, wparam int)
|
fn C.DefWindowProc(hwnd int, msg int, lparam int, wparam int)
|
||||||
|
|
||||||
|
// Used to add a custom calling convention to a function type aliases.
|
||||||
|
[callconv: "fastcall"]
|
||||||
|
type FastFn = fn (int) bool
|
||||||
|
|
||||||
// Windows only:
|
// Windows only:
|
||||||
// If a default graphics library is imported (ex. gg, ui), then the graphical window takes
|
// If a default graphics library is imported (ex. gg, ui), then the graphical window takes
|
||||||
// priority and no console window is created, effectively disabling println() statements.
|
// priority and no console window is created, effectively disabling println() statements.
|
||||||
|
|
|
@ -1152,6 +1152,7 @@ pub:
|
||||||
pos token.Pos
|
pos token.Pos
|
||||||
type_pos token.Pos
|
type_pos token.Pos
|
||||||
comments []Comment
|
comments []Comment
|
||||||
|
attrs []Attr // attributes of type declaration
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle this differently
|
// TODO: handle this differently
|
||||||
|
|
|
@ -1290,6 +1290,7 @@ pub fn (mut f Fmt) alias_type_decl(node ast.AliasTypeDecl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut f Fmt) fn_type_decl(node ast.FnTypeDecl) {
|
pub fn (mut f Fmt) fn_type_decl(node ast.FnTypeDecl) {
|
||||||
|
f.attrs(node.attrs)
|
||||||
if node.is_pub {
|
if node.is_pub {
|
||||||
f.write('pub ')
|
f.write('pub ')
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
[callconv: 'stdcall']
|
||||||
|
fn C.DefWindowProc(hwnd int, msg int, lparam int, wparam int)
|
||||||
|
|
||||||
|
[callconv: 'stdcall']
|
||||||
|
type FastFn = fn (int) bool
|
||||||
|
|
||||||
|
[callconv: 'fastcall']
|
||||||
|
fn zzz(x int, y int) int {
|
||||||
|
return x + y * 2
|
||||||
|
}
|
|
@ -96,6 +96,7 @@ mut:
|
||||||
is_json_fn bool // inside json.encode()
|
is_json_fn bool // inside json.encode()
|
||||||
is_js_call bool // for handling a special type arg #1 `json.decode(User, ...)`
|
is_js_call bool // for handling a special type arg #1 `json.decode(User, ...)`
|
||||||
is_fn_index_call bool
|
is_fn_index_call bool
|
||||||
|
is_cc_msvc bool // g.pref.ccompiler == 'msvc'
|
||||||
vlines_path string // set to the proper path for generating #line directives
|
vlines_path string // set to the proper path for generating #line directives
|
||||||
optionals map[string]string // to avoid duplicates
|
optionals map[string]string // to avoid duplicates
|
||||||
done_optionals shared []string // to avoid duplicates
|
done_optionals shared []string // to avoid duplicates
|
||||||
|
@ -258,6 +259,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
||||||
inner_loop: &ast.EmptyStmt{}
|
inner_loop: &ast.EmptyStmt{}
|
||||||
field_data_type: ast.Type(table.find_type_idx('FieldData'))
|
field_data_type: ast.Type(table.find_type_idx('FieldData'))
|
||||||
init: strings.new_builder(100)
|
init: strings.new_builder(100)
|
||||||
|
is_cc_msvc: pref.ccompiler == 'msvc'
|
||||||
}
|
}
|
||||||
// anon fn may include assert and thus this needs
|
// anon fn may include assert and thus this needs
|
||||||
// to be included before any test contents are written
|
// to be included before any test contents are written
|
||||||
|
@ -557,6 +559,7 @@ fn cgen_process_one_file_cb(p &pool.PoolProcessor, idx int, wid int) &Gen {
|
||||||
done_optionals: global_g.done_optionals
|
done_optionals: global_g.done_optionals
|
||||||
is_autofree: global_g.pref.autofree
|
is_autofree: global_g.pref.autofree
|
||||||
referenced_fns: global_g.referenced_fns
|
referenced_fns: global_g.referenced_fns
|
||||||
|
is_cc_msvc: global_g.is_cc_msvc
|
||||||
}
|
}
|
||||||
g.gen_file()
|
g.gen_file()
|
||||||
return g
|
return g
|
||||||
|
@ -1343,14 +1346,35 @@ pub fn (mut g Gen) write_fn_typesymbol_declaration(sym ast.TypeSymbol) {
|
||||||
if !info.has_decl && (not_anon || is_fn_sig) && !func.return_type.has_flag(.generic)
|
if !info.has_decl && (not_anon || is_fn_sig) && !func.return_type.has_flag(.generic)
|
||||||
&& !has_generic_arg {
|
&& !has_generic_arg {
|
||||||
fn_name := sym.cname
|
fn_name := sym.cname
|
||||||
g.type_definitions.write_string('typedef ${g.typ(func.return_type)} (*$fn_name)(')
|
|
||||||
|
mut call_conv := ''
|
||||||
|
mut msvc_call_conv := ''
|
||||||
|
for attr in func.attrs {
|
||||||
|
match attr.name {
|
||||||
|
'callconv' {
|
||||||
|
if g.is_cc_msvc {
|
||||||
|
msvc_call_conv = '__$attr.arg '
|
||||||
|
} else {
|
||||||
|
call_conv = '$attr.arg'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
call_conv_attribute_suffix := if call_conv.len != 0 {
|
||||||
|
'__attribute__(($call_conv))'
|
||||||
|
} else {
|
||||||
|
''
|
||||||
|
}
|
||||||
|
|
||||||
|
g.type_definitions.write_string('typedef ${g.typ(func.return_type)} ($msvc_call_conv*$fn_name)(')
|
||||||
for i, param in func.params {
|
for i, param in func.params {
|
||||||
g.type_definitions.write_string(g.typ(param.typ))
|
g.type_definitions.write_string(g.typ(param.typ))
|
||||||
if i < func.params.len - 1 {
|
if i < func.params.len - 1 {
|
||||||
g.type_definitions.write_string(',')
|
g.type_definitions.write_string(',')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.type_definitions.writeln(');')
|
g.type_definitions.writeln(')$call_conv_attribute_suffix;')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2148,10 +2148,13 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
|
||||||
'windows_stdcall' {
|
'windows_stdcall' {
|
||||||
// windows attributes (msvc/mingw)
|
// windows attributes (msvc/mingw)
|
||||||
// prefixed by windows to indicate they're for advanced users only and not really supported by V.
|
// prefixed by windows to indicate they're for advanced users only and not really supported by V.
|
||||||
fn_attrs += '__stdcall '
|
fn_attrs += call_convention_attribute('stdcall', g.is_cc_msvc)
|
||||||
}
|
}
|
||||||
'_fastcall' {
|
'_fastcall' {
|
||||||
fn_attrs += '__fastcall '
|
fn_attrs += call_convention_attribute('fastcall', g.is_cc_msvc)
|
||||||
|
}
|
||||||
|
'callconv' {
|
||||||
|
fn_attrs += call_convention_attribute(attr.arg, g.is_cc_msvc)
|
||||||
}
|
}
|
||||||
'console' {
|
'console' {
|
||||||
g.force_main_console = true
|
g.force_main_console = true
|
||||||
|
@ -2163,3 +2166,7 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
|
||||||
}
|
}
|
||||||
return fn_attrs
|
return fn_attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn call_convention_attribute(cconvention string, is_cc_msvc bool) string {
|
||||||
|
return if is_cc_msvc { '__$cconvention ' } else { '__attribute__(($cconvention)) ' }
|
||||||
|
}
|
||||||
|
|
|
@ -185,18 +185,60 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
mut comments := []ast.Comment{}
|
mut comments := []ast.Comment{}
|
||||||
for fna in p.attrs {
|
for fna in p.attrs {
|
||||||
match fna.name {
|
match fna.name {
|
||||||
'noreturn' { is_noreturn = true }
|
'noreturn' {
|
||||||
'manualfree' { is_manualfree = true }
|
is_noreturn = true
|
||||||
'deprecated' { is_deprecated = true }
|
}
|
||||||
'direct_array_access' { is_direct_arr = true }
|
'manualfree' {
|
||||||
'keep_args_alive' { is_keep_alive = true }
|
is_manualfree = true
|
||||||
'export' { is_exported = true }
|
}
|
||||||
'wasm_export' { is_exported = true }
|
'deprecated' {
|
||||||
'unsafe' { is_unsafe = true }
|
is_deprecated = true
|
||||||
'trusted' { is_trusted = true }
|
}
|
||||||
'c2v_variadic' { is_c2v_variadic = true }
|
'direct_array_access' {
|
||||||
'use_new' { is_ctor_new = true }
|
is_direct_arr = true
|
||||||
'markused' { is_markused = true }
|
}
|
||||||
|
'keep_args_alive' {
|
||||||
|
is_keep_alive = true
|
||||||
|
}
|
||||||
|
'export' {
|
||||||
|
is_exported = true
|
||||||
|
}
|
||||||
|
'wasm_export' {
|
||||||
|
is_exported = true
|
||||||
|
}
|
||||||
|
'unsafe' {
|
||||||
|
is_unsafe = true
|
||||||
|
}
|
||||||
|
'trusted' {
|
||||||
|
is_trusted = true
|
||||||
|
}
|
||||||
|
'c2v_variadic' {
|
||||||
|
is_c2v_variadic = true
|
||||||
|
}
|
||||||
|
'use_new' {
|
||||||
|
is_ctor_new = true
|
||||||
|
}
|
||||||
|
'markused' {
|
||||||
|
is_markused = true
|
||||||
|
}
|
||||||
|
'windows_stdcall' {
|
||||||
|
// TODO: uncomment after bootstrapping and replacing usages in builtin
|
||||||
|
// p.note_with_pos('windows_stdcall has been deprecated, it will be an error soon', p.tok.pos())
|
||||||
|
}
|
||||||
|
'_fastcall' {
|
||||||
|
// TODO: uncomment after bootstrapping and replacing usages in builtin
|
||||||
|
// p.note_with_pos('_fastcall has been deprecated, it will be an error soon', p.tok.pos())
|
||||||
|
}
|
||||||
|
'callconv' {
|
||||||
|
if !fna.has_arg {
|
||||||
|
p.error_with_pos('callconv attribute is present but its value is missing',
|
||||||
|
p.prev_tok.pos())
|
||||||
|
}
|
||||||
|
if fna.arg !in ['stdcall', 'fastcall', 'cdecl'] {
|
||||||
|
p.error_with_pos('unsupported calling convention, supported are stdcall, fastcall and cdecl',
|
||||||
|
p.prev_tok.pos())
|
||||||
|
}
|
||||||
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,6 +229,23 @@ pub fn (mut p Parser) parse_multi_return_type() ast.Type {
|
||||||
pub fn (mut p Parser) parse_fn_type(name string) ast.Type {
|
pub fn (mut p Parser) parse_fn_type(name string) ast.Type {
|
||||||
// p.warn('parse fn')
|
// p.warn('parse fn')
|
||||||
p.check(.key_fn)
|
p.check(.key_fn)
|
||||||
|
|
||||||
|
for attr in p.attrs {
|
||||||
|
match attr.name {
|
||||||
|
'callconv' {
|
||||||
|
if !attr.has_arg {
|
||||||
|
p.error_with_pos('callconv attribute is present but its value is missing',
|
||||||
|
p.prev_tok.pos())
|
||||||
|
}
|
||||||
|
if attr.arg !in ['stdcall', 'fastcall', 'cdecl'] {
|
||||||
|
p.error_with_pos('unsupported calling convention, supported are stdcall, fastcall and cdecl',
|
||||||
|
p.prev_tok.pos())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mut has_generic := false
|
mut has_generic := false
|
||||||
line_nr := p.tok.line_nr
|
line_nr := p.tok.line_nr
|
||||||
args, _, is_variadic := p.fn_args()
|
args, _, is_variadic := p.fn_args()
|
||||||
|
@ -255,6 +272,7 @@ pub fn (mut p Parser) parse_fn_type(name string) ast.Type {
|
||||||
return_type: return_type
|
return_type: return_type
|
||||||
return_type_pos: return_type_pos
|
return_type_pos: return_type_pos
|
||||||
is_method: false
|
is_method: false
|
||||||
|
attrs: p.attrs
|
||||||
}
|
}
|
||||||
// MapFooFn typedefs are manually added in cheaders.v
|
// MapFooFn typedefs are manually added in cheaders.v
|
||||||
// because typedefs get generated after the map struct is generated
|
// because typedefs get generated after the map struct is generated
|
||||||
|
|
|
@ -3579,6 +3579,8 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||||
p.table.sym(fn_type).is_pub = is_pub
|
p.table.sym(fn_type).is_pub = is_pub
|
||||||
type_pos = type_pos.extend(p.tok.pos())
|
type_pos = type_pos.extend(p.tok.pos())
|
||||||
comments = p.eat_comments(same_line: true)
|
comments = p.eat_comments(same_line: true)
|
||||||
|
attrs := p.attrs
|
||||||
|
p.attrs = []
|
||||||
return ast.FnTypeDecl{
|
return ast.FnTypeDecl{
|
||||||
name: fn_name
|
name: fn_name
|
||||||
is_pub: is_pub
|
is_pub: is_pub
|
||||||
|
@ -3586,6 +3588,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||||
pos: decl_pos
|
pos: decl_pos
|
||||||
type_pos: type_pos
|
type_pos: type_pos
|
||||||
comments: comments
|
comments: comments
|
||||||
|
attrs: attrs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sum_variants << p.parse_sum_type_variants()
|
sum_variants << p.parse_sum_type_variants()
|
||||||
|
|
Loading…
Reference in New Issue