[v3] Fix global state in Collector.IsVoidAlias predicate (#4941)

* Accept obscure update to package-lock.json

* Make global state local in Collector.IsVoidAlias predicate

* Add protection against potential nil dereference

* Update test data

* Fix typo in doc comment

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update UNRELEASED_CHANGELOG.md

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Fabio Massaioli 2026-02-02 10:44:56 +01:00 committed by GitHub
commit 04d99e376c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 17 additions and 187 deletions

View file

@ -29,6 +29,8 @@ After processing, the content will be moved to the main changelog and this file
- Make menus to be displayed on Windows OS in `v3\examples\dialogs` by @ndianabasi
- Fix race condition causing TypeError during page reload (#4872) by @ddmoney420
- Fix incorrect output from binding generator tests by removing global state in the `Collector.IsVoidAlias()` method (#4941) by @fbbdev
## Deprecated
<!-- Soon-to-be removed features -->

View file

@ -4,6 +4,7 @@ import (
"go/ast"
"go/types"
"sync"
"sync/atomic"
"github.com/wailsapp/wails/v3/internal/flags"
"github.com/wailsapp/wails/v3/internal/generator/config"
@ -42,6 +43,8 @@ type Collector struct {
// events holds collected information about registered custom events.
events *EventMap
// appVoidType caches the application.Void named type that stands in for the void TS type.
appVoidType atomic.Value
systemPaths *config.SystemPaths
options *flags.GenerateBindingsOptions

View file

@ -2,12 +2,8 @@ package collect
import (
"go/types"
"sync/atomic"
)
// appVoidType caches the application.Void named type that stands in for the void TS type.
var appVoidType atomic.Value
// IsVoidAlias returns true when the given type or object is the application.Void named type that stands in for the void TS type.
func (collector *Collector) IsVoidAlias(typOrObj any) bool {
var obj types.Object
@ -20,11 +16,11 @@ func (collector *Collector) IsVoidAlias(typOrObj any) bool {
return false
}
if vt := appVoidType.Load(); obj == vt {
if vt := collector.appVoidType.Load(); vt != nil && obj == vt {
return true
} else if vt == nil && obj.Name() == "Void" && obj.Pkg().Path() == collector.systemPaths.ApplicationPackage { // Check name before package to fail fast
} else if vt == nil && obj.Name() == "Void" && obj.Pkg() != nil && obj.Pkg().Path() == collector.systemPaths.ApplicationPackage { // Check name before package to fail fast
// Cache void alias for faster checking
appVoidType.Store(obj)
collector.appVoidType.Store(obj)
return true
}

View file

@ -15,9 +15,6 @@ import * as events_only$0 from "./generator/testcases/events_only/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as more$0 from "./generator/testcases/no_bindings_here/more/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as application$0 from "../pkg/application/models.js";
function configure() {
Object.freeze(Object.assign($Create.Events, {

View file

@ -14,16 +14,13 @@ import type * as events_only$0 from "./generator/testcases/events_only/models.js
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as application$0 from "../pkg/application/models.js";
declare module "/wails/runtime.js" {
namespace Events {
interface CustomEvents {
"events_only:class": events_only$0.SomeClass;
"events_only:map": { [_: string]: number[] };
"events_only:nodata": application$0.Void;
"events_only:nodata": void;
"events_only:other": more$0.StringPtr[];
"events_only:string": string;
"interface": json$0.Marshaler;

View file

@ -1,11 +0,0 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
import * as $models from "./models.js";
/**
* Void will be translated by the binding generator to the TypeScript type 'void'.
* It can be used as an event data type to register events that must not have any associated data.
* @typedef {$models.Void} Void
*/

View file

@ -1,13 +0,0 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import { Create as $Create } from "/wails/runtime.js";
/**
* Void will be translated by the binding generator to the TypeScript type 'void'.
* It can be used as an event data type to register events that must not have any associated data.
* @typedef {any} Void
*/

View file

@ -1,7 +1,6 @@
[warn] /testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int
[warn] /testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int
[warn] /testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors
[warn] /testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called
[warn] /testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored`

View file

@ -14,16 +14,13 @@ import type * as events_only$0 from "./generator/testcases/events_only/models.js
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as application$0 from "../pkg/application/models.js";
declare module "/wails/runtime.js" {
namespace Events {
interface CustomEvents {
"events_only:class": events_only$0.SomeClass;
"events_only:map": { [_: string]: number[] | null } | null;
"events_only:nodata": application$0.Void;
"events_only:nodata": void;
"events_only:other": more$0.StringPtr[] | null;
"events_only:string": string;
"interface": json$0.Marshaler;

View file

@ -1,11 +0,0 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
import * as $models from "./models.js";
/**
* Void will be translated by the binding generator to the TypeScript type 'void'.
* It can be used as an event data type to register events that must not have any associated data.
* @typedef {$models.Void} Void
*/

View file

@ -1,13 +0,0 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* Void will be translated by the binding generator to the TypeScript type 'void'.
* It can be used as an event data type to register events that must not have any associated data.
* @typedef {any} Void
*/
// In interface mode, this file is likely to contain just comments.
// We add a dummy export statement to ensure it is recognised as an ES module.
export {};

View file

@ -1,7 +1,6 @@
[warn] /testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int
[warn] /testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int
[warn] /testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors
[warn] /testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called
[warn] /testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored`

View file

@ -14,16 +14,13 @@ import type * as events_only$0 from "./generator/testcases/events_only/models.js
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as application$0 from "../pkg/application/models.js";
declare module "/wails/runtime.js" {
namespace Events {
interface CustomEvents {
"events_only:class": events_only$0.SomeClass;
"events_only:map": { [_: string]: number[] | null } | null;
"events_only:nodata": application$0.Void;
"events_only:nodata": void;
"events_only:other": more$0.StringPtr[] | null;
"events_only:string": string;
"interface": json$0.Marshaler;

View file

@ -1,11 +0,0 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
import * as $models from "./models.js";
/**
* Void will be translated by the binding generator to the TypeScript type 'void'.
* It can be used as an event data type to register events that must not have any associated data.
* @typedef {$models.Void} Void
*/

View file

@ -1,13 +0,0 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* Void will be translated by the binding generator to the TypeScript type 'void'.
* It can be used as an event data type to register events that must not have any associated data.
* @typedef {any} Void
*/
// In interface mode, this file is likely to contain just comments.
// We add a dummy export statement to ensure it is recognised as an ES module.
export {};

View file

@ -1,7 +1,6 @@
[warn] /testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int
[warn] /testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int
[warn] /testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors
[warn] /testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called
[warn] /testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored`

View file

@ -15,9 +15,6 @@ import * as events_only$0 from "./generator/testcases/events_only/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as more$0 from "./generator/testcases/no_bindings_here/more/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as application$0 from "../pkg/application/models.js";
function configure() {
Object.freeze(Object.assign($Create.Events, {

View file

@ -14,16 +14,13 @@ import type * as events_only$0 from "./generator/testcases/events_only/models.js
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as application$0 from "../pkg/application/models.js";
declare module "/wails/runtime.js" {
namespace Events {
interface CustomEvents {
"events_only:class": events_only$0.SomeClass;
"events_only:map": { [_: string]: number[] };
"events_only:nodata": application$0.Void;
"events_only:nodata": void;
"events_only:other": more$0.StringPtr[];
"events_only:string": string;
"interface": json$0.Marshaler;

View file

@ -1,6 +0,0 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export type {
Void
} from "./models.js";

View file

@ -1,12 +0,0 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import { Create as $Create } from "/wails/runtime.js";
/**
* Void will be translated by the binding generator to the TypeScript type 'void'.
* It can be used as an event data type to register events that must not have any associated data.
*/
export type Void = any;

View file

@ -1,7 +1,6 @@
[warn] /testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int
[warn] /testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int
[warn] /testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors
[warn] /testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called
[warn] /testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored`

View file

@ -15,9 +15,6 @@ import * as events_only$0 from "./generator/testcases/events_only/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as more$0 from "./generator/testcases/no_bindings_here/more/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as application$0 from "../pkg/application/models.js";
function configure() {
Object.freeze(Object.assign($Create.Events, {

View file

@ -14,16 +14,13 @@ import type * as events_only$0 from "./generator/testcases/events_only/models.js
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as application$0 from "../pkg/application/models.js";
declare module "/wails/runtime.js" {
namespace Events {
interface CustomEvents {
"events_only:class": events_only$0.SomeClass;
"events_only:map": { [_: string]: number[] };
"events_only:nodata": application$0.Void;
"events_only:nodata": void;
"events_only:other": more$0.StringPtr[];
"events_only:string": string;
"interface": json$0.Marshaler;

View file

@ -1,6 +0,0 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export type {
Void
} from "./models.js";

View file

@ -1,12 +0,0 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import { Create as $Create } from "/wails/runtime.js";
/**
* Void will be translated by the binding generator to the TypeScript type 'void'.
* It can be used as an event data type to register events that must not have any associated data.
*/
export type Void = any;

View file

@ -1,7 +1,6 @@
[warn] /testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int
[warn] /testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int
[warn] /testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors
[warn] /testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called
[warn] /testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored`

View file

@ -14,16 +14,13 @@ import type * as events_only$0 from "./generator/testcases/events_only/models.js
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as application$0 from "../pkg/application/models.js";
declare module "/wails/runtime.js" {
namespace Events {
interface CustomEvents {
"events_only:class": events_only$0.SomeClass;
"events_only:map": { [_: string]: number[] | null } | null;
"events_only:nodata": application$0.Void;
"events_only:nodata": void;
"events_only:other": more$0.StringPtr[] | null;
"events_only:string": string;
"interface": json$0.Marshaler;

View file

@ -1,6 +0,0 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export type {
Void
} from "./models.js";

View file

@ -1,8 +0,0 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* Void will be translated by the binding generator to the TypeScript type 'void'.
* It can be used as an event data type to register events that must not have any associated data.
*/
export type Void = any;

View file

@ -1,7 +1,6 @@
[warn] /testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int
[warn] /testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int
[warn] /testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors
[warn] /testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called
[warn] /testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored`

View file

@ -14,16 +14,13 @@ import type * as events_only$0 from "./generator/testcases/events_only/models.js
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as more$0 from "./generator/testcases/no_bindings_here/more/models.js";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import type * as application$0 from "../pkg/application/models.js";
declare module "/wails/runtime.js" {
namespace Events {
interface CustomEvents {
"events_only:class": events_only$0.SomeClass;
"events_only:map": { [_: string]: number[] | null } | null;
"events_only:nodata": application$0.Void;
"events_only:nodata": void;
"events_only:other": more$0.StringPtr[] | null;
"events_only:string": string;
"interface": json$0.Marshaler;

View file

@ -1,6 +0,0 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export type {
Void
} from "./models.js";

View file

@ -1,8 +0,0 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* Void will be translated by the binding generator to the TypeScript type 'void'.
* It can be used as an event data type to register events that must not have any associated data.
*/
export type Void = any;

View file

@ -1,7 +1,6 @@
[warn] /testcases/complex_json/main.go:127:2: event 'collision' has one of multiple definitions here with data type map[string]int
[warn] /testcases/events_only/events.go:20:2: event 'collision' has one of multiple definitions here with data type int
[warn] /testcases/events_only/events.go:21:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/events.go:25:2: data type github.com/wailsapp/wails/v3/pkg/application.Void for event 'events_only:nodata' is a non-empty interface: emitting events from the frontend with data other than `null` is not supported by encoding/json and will likely result in runtime errors
[warn] /testcases/events_only/other.go:10:5: `application.RegisterEvent` is instantiated here but not called
[warn] /testcases/events_only/other.go:13:2: `application.RegisterEvent` called here with non-constant event name
[warn] /testcases/events_only/other.go:17:2: data type []T for event 'parametric' contains unresolved type parameters and will be ignored`

View file

@ -1675,6 +1675,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.8",
"picocolors": "^1.1.1",
@ -2226,6 +2227,7 @@
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"