From 071d6dbb22dfdf99a9be32f0cb6c826895c48b19 Mon Sep 17 00:00:00 2001 From: Stefnotch Date: Sun, 19 Apr 2026 14:12:00 +0200 Subject: [PATCH 01/25] Add glob imports --- Imports.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/Imports.md b/Imports.md index 4988291..eb927ca 100644 --- a/Imports.md +++ b/Imports.md @@ -22,6 +22,9 @@ import my::geom::sphere::{ draw, default_radius as foobar }; // Imports a whole module. Use it with `bevy_ui::name` import bevy_ui; + +// Import all items defined in the bevy prelude +import bevy::prelude::*; ``` These can then be used anywhere in the source code. @@ -74,6 +77,7 @@ import_relative: import_path_or_item: | ident '::' (import_collection | import_path_or_item) | ident ('as' ident)? +| '*' import_collection: | '{' (import_path_or_item) (',' (import_path_or_item))* ','? '}' @@ -91,6 +95,8 @@ An item import imports a single item. The item can be renamed with the `as` keyw An import collection imports multiple items, and allows for nested imports. +A wildcard import imports all items from a module, but does not import further modules. + ### Import resolution algorithm To resolve the import, the recursive structure is flattened out. This means turning every `import_collection` into multiple separate imports, ending with the items. @@ -111,8 +117,9 @@ Then, one iterates over each segment from left to right, and looks it up one by 2. We take that as the "current module". 3. We repeatedly look at the next segment. 1. Item in current module: Take that item. We must be at the last segment, otherwise it's an error. - 2. (Else if re-exported or inline module in current module: We continue with that module.) - 3. Else go to `current module path/ident.wesl` + 2. Wildcard import: Take all items in the current module. + 3. (Else if re-exported or inline module in current module: We continue with that module.) + 4. Else go to `current module path/ident.wesl` * File found: We take that file as the current module. * File not found: We assume an empty module as the current module, and continue with that. * (Re-exporting changes the path.) @@ -123,7 +130,7 @@ The absolute path of the `super` module is always known, since the first loaded Once the import has been resolved, the last segment, or its alias, is brought into scope. -The order of the scopes is "user declarations and imported items > package names > predeclared items". +The order of the scopes is "user declarations and imported items > wildcard import > package names > predeclared items". This lets WGSL add more predeclared items without breaking existing WESL code. Package names can shadow predeclared items, but we recommend that authors avoid doing that. @@ -245,6 +252,53 @@ const b = a + 1; Basic linker implementations do not need to check for this. Generating broken code and letting the underlying shader compiler throw an error is fine. +## Wildcard Imports + +Wildcard imports are used to import a whole set of items into the current module. They are lower priority than local names and explicit imports to reduce the chance of breaking changes if the wildcard-imported module changes. Wildcard imported modules are eagerly loaded, since they need to be checked before accessing any predeclared items. + +When multiple wildcard imports are used, name clashes are possible. + +```wesl +import foo::*; // exports clashing_name +import bar::*; // exports clashing_name +``` + +The name clash is ignored until the item is used. +TODO: Or should it immediately result in a warning, even if the variables are unused? + +### Wildcard imports from libraries + +For libraries, we distinguish between modules that were designed for wildcard imports and modules that were not. +Library authors generally expect that adding a new item is not a breaking change. Wildcard imports are a surprising edge case. + +WESL detects the edge cases and will emit a diagnostic. This makes upholding semver guarantees significantly easier. + +When the library module is called `prelude`, it is a module designed for wildcards. Adding a new item to it is a semver breaking change. +Wildcard importing from it is always allowed. (When we add exports, we will make this controllable instead of only giving special treatment to the `prelude`.) + +Other library modules are not designed for wildcards. If another wildcard import exists, then an `wildcard_import` [diagnostic](https://www.w3.org/TR/WGSL/#diagnostics) at the error level will be emitted. + +Modules in the same package can always be wildcard imported. Changing your own code has no impact on semver. + +Examples + +```wesl +// Allowed, since it is the only import in the current module +import lygia::math::*; +``` + +```wesl +// Allowed, since it is designed for wildcards +import bevy::color::prelude::*; + +// Allowed, same package +import package::utils::*; + +// Requires opt-in +@diagnostic(off, wildcard_import) +import lygia::math::*; +``` + ## Directives Under discussion, see: From 0e146af42891f3e85d35063453ffdcbc75beb22b Mon Sep 17 00:00:00 2001 From: Stefnotch Date: Wed, 22 Apr 2026 15:58:29 +0200 Subject: [PATCH 02/25] Update glob imports --- Imports.md | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/Imports.md b/Imports.md index eb927ca..f3b6dfe 100644 --- a/Imports.md +++ b/Imports.md @@ -131,7 +131,6 @@ The absolute path of the `super` module is always known, since the first loaded Once the import has been resolved, the last segment, or its alias, is brought into scope. The order of the scopes is "user declarations and imported items > wildcard import > package names > predeclared items". -This lets WGSL add more predeclared items without breaking existing WESL code. Package names can shadow predeclared items, but we recommend that authors avoid doing that. ### Example @@ -266,17 +265,34 @@ import bar::*; // exports clashing_name The name clash is ignored until the item is used. TODO: Or should it immediately result in a warning, even if the variables are unused? -### Wildcard imports from libraries +### Diagnostics for best practices -For libraries, we distinguish between modules that were designed for wildcard imports and modules that were not. -Library authors generally expect that adding a new item is not a breaking change. Wildcard imports are a surprising edge case. +Many ecosystems rely on semantic versioning for updating libraries. This applies to both direct and transitive dependencies. Updating to the latest patch releases should be easy and safe. -WESL detects the edge cases and will emit a diagnostic. This makes upholding semver guarantees significantly easier. +Library authors generally expect that adding a new item is not a breaking change. Wildcard imports that result in name clashes are a surprising edge case. Therefore, we want to reduce the risk of accidental name clashes. -When the library module is called `prelude`, it is a module designed for wildcards. Adding a new item to it is a semver breaking change. -Wildcard importing from it is always allowed. (When we add exports, we will make this controllable instead of only giving special treatment to the `prelude`.) +Name clashes can happen either in user code or in library code. If it happens in library code, it can be significantly harder to resolve the issue. -Other library modules are not designed for wildcards. If another wildcard import exists, then an `wildcard_import` [diagnostic](https://www.w3.org/TR/WGSL/#diagnostics) at the error level will be emitted. +A secondary, similar issue is that wildcards can result in accidental shadowing of predeclared identifiers. +One especially insideous scenario is when user code targets an unstable Naga feature. + +```wesl +import my_lib::*; + +const x = unstable_thing(); +``` + +Then, a library which does not know about the Naga feature could add an item with the same name. + +To reduce the odds of these cases, we recommend the following diagnostics. + +1. Emit a warning [diagnostic](https://www.w3.org/TR/WGSL/#diagnostics) named `builtin_shadowing` if an top level item is declared that is known to conflict with a predeclared identifier. This also helps in the non-library case. + +2. Emit a warning [diagnostic](https://www.w3.org/TR/WGSL/#diagnostics) named `wildcard_import` if there are multiple wildcard imports from libraries and at least one is not designed for wildcards. + +For this, we distinguish between modules that were designed for wildcard imports and modules that were not. When the library module is called `prelude`, it is a module designed for wildcards. Adding a new item to it is a semver breaking change. Therefore, wildcard importing from it is always allowed. (When we add exports, we will make this controllable instead of only giving special treatment to the `prelude`.) + +Other library modules may cause issues and should not be combined with other wildcard imports. Modules in the same package can always be wildcard imported. Changing your own code has no impact on semver. @@ -299,6 +315,18 @@ import package::utils::*; import lygia::math::*; ``` +### Modeling the WGSL predeclared identifiers + +One mental model for WGSL predeclared identifiers is that they're a wildcard import, which is implicitly added to every WGSL file. + +```wesl +// imports all the predeclared identifiers +import all_wgsl_items::*; +``` + +This wildcard import has a strictly lower priority than all other wildcard imports. This lets WGSL add more predeclared items without breaking existing WESL code. Package names can also shadow predeclared items, but we recommend that authors avoid doing that. + + ## Directives Under discussion, see: From 3232a886181ae86deb8bbb06eec65c698691e0f1 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Fri, 1 May 2026 18:32:11 -0700 Subject: [PATCH 03/25] revise around @wildcardable, more cleanups - `@wildcardable` directive. publishers can mark any module not just `prelude` - `builtin_shadow` moves to publish time warning (and dropped -ing suffix) - write out scope precedence levels and error vs. warning cases. - add @stefnotch's wildcard expansion idea as future work work for publishing tool to protect against transitive version skew --- Imports.md | 173 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 127 insertions(+), 46 deletions(-) diff --git a/Imports.md b/Imports.md index f3b6dfe..062ee59 100644 --- a/Imports.md +++ b/Imports.md @@ -23,8 +23,9 @@ import my::geom::sphere::{ draw, default_radius as foobar }; // Imports a whole module. Use it with `bevy_ui::name` import bevy_ui; -// Import all items defined in the bevy prelude +// Import all items from another module import bevy::prelude::*; +import wgsl_test::prelude::*; ``` These can then be used anywhere in the source code. @@ -95,7 +96,20 @@ An item import imports a single item. The item can be renamed with the `as` keyw An import collection imports multiple items, and allows for nested imports. -A wildcard import imports all items from a module, but does not import further modules. +A wildcard import imports all top-level declarations from a module. Submodule names and submodule contents are not imported. + +WESL also extends WGSL's `global_directive` rule with a `module_attribute` form (used by `@wildcardable`; see [Wildcard imports](#wildcard-imports)): + +```ebnf +global_directive: +| ... // existing WGSL forms +| module_attribute + +module_attribute: +| '@' ident ';' +``` + +The `@` prefix avoids conflict with WGSL identifiers. ### Import resolution algorithm @@ -128,9 +142,7 @@ Then, one iterates over each segment from left to right, and looks it up one by To get an absolute path to a module, one follows the algorithm above. In step 1, one takes the known absolute path of the `super` module, or the package. The absolute path of the `super` module is always known, since the first loaded WESL file must always be the root module, and children are only discovered from there. -Once the import has been resolved, the last segment, or its alias, is brought into scope. - -The order of the scopes is "user declarations and imported items > wildcard import > package names > predeclared items". +Once the import has been resolved, the last segment, or its `as` alias, is brought into scope. ### Example @@ -251,81 +263,150 @@ const b = a + 1; Basic linker implementations do not need to check for this. Generating broken code and letting the underlying shader compiler throw an error is fine. -## Wildcard Imports +## Wildcard imports -Wildcard imports are used to import a whole set of items into the current module. They are lower priority than local names and explicit imports to reduce the chance of breaking changes if the wildcard-imported module changes. Wildcard imported modules are eagerly loaded, since they need to be checked before accessing any predeclared items. +Wildcard imports bring all items from another module into the importing module's +scope. -When multiple wildcard imports are used, name clashes are possible. +By default, users can wildcard import: +- from any other module in the local package, and +- from any external library module where the library author has added a + `@wildcardable` directive. ```wesl -import foo::*; // exports clashing_name -import bar::*; // exports clashing_name -``` - -The name clash is ignored until the item is used. -TODO: Or should it immediately result in a warning, even if the variables are unused? - -### Diagnostics for best practices +// wildcard import from a @wildcardable external +import bevy::prelude::*; +import wgsl_test::prelude::*; -Many ecosystems rely on semantic versioning for updating libraries. This applies to both direct and transitive dependencies. Updating to the latest patch releases should be easy and safe. +// wildcard import from within the local package +import package::utils::*; +import super::fun::*; +``` -Library authors generally expect that adding a new item is not a breaking change. Wildcard imports that result in name clashes are a surprising edge case. Therefore, we want to reduce the risk of accidental name clashes. +Advanced users who wish to import from external package modules that are not +marked as `@wildcardable` can annotate the import statement with +`@diagnostic(off, wildcard_import)`, accepting the increased risk of name +clashes if the upstream module adds items in a future version. -Name clashes can happen either in user code or in library code. If it happens in library code, it can be significantly harder to resolve the issue. +### `@wildcardable` directive -A secondary, similar issue is that wildcards can result in accidental shadowing of predeclared identifiers. -One especially insideous scenario is when user code targets an unstable Naga feature. +Library authors mark modules they intend for library consumers to wildcard +import with `@wildcardable`: ```wesl -import my_lib::*; +// math.wesl (in a library) +@wildcardable; -const x = unstable_thing(); +fn dot2(a: vec2f, b: vec2f) -> f32 { return a.x*b.x + a.y*b.y; } +fn cross2(a: vec2f, b: vec2f) -> f32 { return a.x*b.y - a.y*b.x; } ``` -Then, a library which does not know about the Naga feature could add an item with the same name. +`@wildcardable` is a module attribute (see [Grammar](#grammar)). It must +appear after any imports and before any global declarations, and applies only +to the module it appears in. -To reduce the odds of these cases, we recommend the following diagnostics. +### Recommendations for `@wildcardable` modules -1. Emit a warning [diagnostic](https://www.w3.org/TR/WGSL/#diagnostics) named `builtin_shadowing` if an top level item is declared that is known to conflict with a predeclared identifier. This also helps in the non-library case. +**Curate carefully.** A `@wildcardable` module is a public API contract in a +shared namespace. Every item you add is one your downstream users may collide +with. -2. Emit a warning [diagnostic](https://www.w3.org/TR/WGSL/#diagnostics) named `wildcard_import` if there are multiple wildcard imports from libraries and at least one is not designed for wildcards. +**Compose with re-exports.** See [Re-exports](#re-exports) (TBD) to collect +items from other modules into a single `@wildcardable` module for user +convenience. -For this, we distinguish between modules that were designed for wildcard imports and modules that were not. When the library module is called `prelude`, it is a module designed for wildcards. Adding a new item to it is a semver breaking change. Therefore, wildcard importing from it is always allowed. (When we add exports, we will make this controllable instead of only giving special treatment to the `prelude`.) +**Add hesitantly.** Additions to a `@wildcardable` module are semver minor +version bumps but can break users who have local declarations or import other +preludes. +- **Bundle** additions into a major release when one is upcoming. +- **Document** additions clearly in changelogs so downstream users debugging + unexpected name resolution can trace them. -Other library modules may cause issues and should not be combined with other wildcard imports. +**Avoid generic names.** Prefer domain-specific names. Common names like +`Buffer`, `Config`, `Result`, `Vec`, etc. are more likely to collide with user +applications. -Modules in the same package can always be wildcard imported. Changing your own code has no impact on semver. +**Don't shadow WGSL builtins.** Names like `vec3`, `clamp`, `inverseSqrt` have +expected semantics that oughtn't be implicitly overridden with wildcards. +Similarly, avoid experimental Naga/Dawn/Safari builtins. +- WESL publishing tools should warn when a `@wildcardable` module exports an + item that shadows a WGSL builtin. Suppress with + `@diagnostic(off, builtin_shadow)` if the shadow is intentional. +- If a future WGSL update adds a conflicting builtin name, plan to update the + `@wildcardable` module to rename the conflicting item. -Examples +### Library-to-library wildcard imports + +Libraries that wildcard import from other libraries raise special concerns. If a +user's package manager chooses a newer version of the imported-from library, +the user may see a conflict in library code they don't expect to modify. + +WESL library publishing tools will address this by expanding wildcards to named +imports in the published version of the module: ```wesl -// Allowed, since it is the only import in the current module -import lygia::math::*; +// source +import bevy::prelude::*; ``` ```wesl -// Allowed, since it is designed for wildcards -import bevy::color::prelude::*; +// published artifact +import bevy::prelude::{Color, Mesh, Transform, /* snapshot at publish time */}; +``` -// Allowed, same package -import package::utils::*; +Until WESL packaging tools implement this expansion, library authors should +avoid wildcard imports from external libraries they don't control. -// Requires opt-in -@diagnostic(off, wildcard_import) -import lygia::math::*; -``` +## Import errors and warnings -### Modeling the WGSL predeclared identifiers +WESL emits errors for name collisions and for external wildcards from unmarked +modules, and warnings for shadowing that could surprise readers. Genuine +collisions cannot be suppressed; other diagnostics are suppressible via +`@diagnostic`. (The table below covers compile-time diagnostics; publish-time +diagnostics are introduced in the relevant subsections.) -One mental model for WGSL predeclared identifiers is that they're a wildcard import, which is implicitly added to every WGSL file. +| Situation | Behavior | +| --- | --- | +| Local declaration conflicts with named import | Error | +| Named import conflicts with named import | Error | +| Wildcard import conflicts with wildcard import (when name is referenced) | Error | +| Wildcard import from a non-`@wildcardable` external module | Error (`wildcard_import`); suppressible | +| Local declaration or named import shadows a wildcard-imported name | Warning (`wildcard_shadow`); suppressible | + +When multiple wildcard imports are in scope, the same name may be exported by +more than one module: ```wesl -// imports all the predeclared identifiers -import all_wgsl_items::*; +import foo::*; // exports clashing_zap +import bar::*; // exports clashing_zap ``` -This wildcard import has a strictly lower priority than all other wildcard imports. This lets WGSL add more predeclared items without breaking existing WESL code. Package names can also shadow predeclared items, but we recommend that authors avoid doing that. +If `foo::clashing_zap` and `bar::clashing_zap` re-export the same item, there's +no conflict. Otherwise the potential conflict is dormant unless `clashing_zap` +is referenced. + +### Scope precedence + +When a name could resolve to items at multiple precedence levels, the +highest-precedence one wins. The table above describes whether such a resolution +is silent, produces a warning, or produces an error. + +1. user declarations +2. named imports (non-wildcard) +3. wildcard-imported names +4. package names +5. predeclared items (WGSL builtins) + +Package names can shadow predeclared items, but we recommend that authors avoid +doing that. + +## Forward compatibility with WGSL predeclared identifiers +Predeclared items have the lowest priority in scope resolution (see +[Scope precedence](#scope-precedence)). WGSL can add new predeclared items in +future spec revisions without breaking existing WESL code: any name already +bound by a user declaration, named import, wildcard import, or package continues +to resolve as before. ## Directives Under discussion, see: From ae5693092745619688f6b72c25d13a8904cac911 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 5 May 2026 21:43:53 -0700 Subject: [PATCH 04/25] move wildcardable motivation and advanced mode higher --- Imports.md | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/Imports.md b/Imports.md index 062ee59..30cb379 100644 --- a/Imports.md +++ b/Imports.md @@ -268,11 +268,22 @@ Basic linker implementations do not need to check for this. Generating broken co Wildcard imports bring all items from another module into the importing module's scope. -By default, users can wildcard import: -- from any other module in the local package, and +Users can wildcard import: +- from any other module in the local package. - from any external library module where the library author has added a `@wildcardable` directive. +Wildcard importing brings some stability risk when the imported module adds to +its API. The newly introduced names may conflict with other names in the +importer's namespace (from local definitions and other imports), leading to +compiler warnings or errors. To help mitigate this risk, WESL provides a +`@wildcardable` annotation that library authors can place on modules that are +designed for wildcard importing. + +Advanced users who wish to wildcard import from external modules not marked as +`@wildcardable` can do so by annotating the import statement with +`@diagnostic(off, wildcard_import)`, accepting some additional upgrade risk. + ```wesl // wildcard import from a @wildcardable external import bevy::prelude::*; @@ -283,11 +294,6 @@ import package::utils::*; import super::fun::*; ``` -Advanced users who wish to import from external package modules that are not -marked as `@wildcardable` can annotate the import statement with -`@diagnostic(off, wildcard_import)`, accepting the increased risk of name -clashes if the upstream module adds items in a future version. - ### `@wildcardable` directive Library authors mark modules they intend for library consumers to wildcard @@ -307,21 +313,20 @@ to the module it appears in. ### Recommendations for `@wildcardable` modules -**Curate carefully.** A `@wildcardable` module is a public API contract in a -shared namespace. Every item you add is one your downstream users may collide -with. - -**Compose with re-exports.** See [Re-exports](#re-exports) (TBD) to collect -items from other modules into a single `@wildcardable` module for user -convenience. +Because every name in a `@wildcardable` module is a potential collision in +importer code, library authors should curate these modules carefully. **Add hesitantly.** Additions to a `@wildcardable` module are semver minor version bumps but can break users who have local declarations or import other -preludes. +`@wildcardable` modules. - **Bundle** additions into a major release when one is upcoming. - **Document** additions clearly in changelogs so downstream users debugging unexpected name resolution can trace them. +**Compose with re-exports.** See [Re-exports](#re-exports) (TBD) to collect +items from other modules into a single `@wildcardable` module for user +convenience. + **Avoid generic names.** Prefer domain-specific names. Common names like `Buffer`, `Config`, `Result`, `Vec`, etc. are more likely to collide with user applications. From 216457c2cd6a17364bba45ef24c040a4e1a9c122 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 5 May 2026 21:47:46 -0700 Subject: [PATCH 05/25] move builtin_shadow to client side warning --- Imports.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Imports.md b/Imports.md index 30cb379..a327dd4 100644 --- a/Imports.md +++ b/Imports.md @@ -334,9 +334,6 @@ applications. **Don't shadow WGSL builtins.** Names like `vec3`, `clamp`, `inverseSqrt` have expected semantics that oughtn't be implicitly overridden with wildcards. Similarly, avoid experimental Naga/Dawn/Safari builtins. -- WESL publishing tools should warn when a `@wildcardable` module exports an - item that shadows a WGSL builtin. Suppress with - `@diagnostic(off, builtin_shadow)` if the shadow is intentional. - If a future WGSL update adds a conflicting builtin name, plan to update the `@wildcardable` module to rename the conflicting item. @@ -367,8 +364,7 @@ avoid wildcard imports from external libraries they don't control. WESL emits errors for name collisions and for external wildcards from unmarked modules, and warnings for shadowing that could surprise readers. Genuine collisions cannot be suppressed; other diagnostics are suppressible via -`@diagnostic`. (The table below covers compile-time diagnostics; publish-time -diagnostics are introduced in the relevant subsections.) +`@diagnostic`. | Situation | Behavior | | --- | --- | @@ -377,6 +373,7 @@ diagnostics are introduced in the relevant subsections.) | Wildcard import conflicts with wildcard import (when name is referenced) | Error | | Wildcard import from a non-`@wildcardable` external module | Error (`wildcard_import`); suppressible | | Local declaration or named import shadows a wildcard-imported name | Warning (`wildcard_shadow`); suppressible | +| Wildcard import shadows a WGSL builtin | Warning (`builtin_shadow`); suppressible | When multiple wildcard imports are in scope, the same name may be exported by more than one module: From 8fcb4a7ab35f92211c5872bffbd64ba95a32d94d Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 5 May 2026 21:57:27 -0700 Subject: [PATCH 06/25] rm forward compatibility section just add sentence in the precedence section also drop the packag names can shadow line iit's clear enough from the table --- Imports.md | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Imports.md b/Imports.md index a327dd4..f51aa7f 100644 --- a/Imports.md +++ b/Imports.md @@ -399,16 +399,9 @@ is silent, produces a warning, or produces an error. 4. package names 5. predeclared items (WGSL builtins) -Package names can shadow predeclared items, but we recommend that authors avoid -doing that. - -## Forward compatibility with WGSL predeclared identifiers - -Predeclared items have the lowest priority in scope resolution (see -[Scope precedence](#scope-precedence)). WGSL can add new predeclared items in -future spec revisions without breaking existing WESL code: any name already -bound by a user declaration, named import, wildcard import, or package continues -to resolve as before. +Predeclared items rank lowest so that future WGSL spec revisions can add new +builtins without breaking existing WESL code: any name already bound at a +higher level continues to resolve as before. ## Directives Under discussion, see: From f4940e2f4b48fbf809e9d56e009e306aa0ceb672 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 5 May 2026 22:02:10 -0700 Subject: [PATCH 07/25] no waffling about library publish tool expansion --- Imports.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Imports.md b/Imports.md index f51aa7f..ce503e4 100644 --- a/Imports.md +++ b/Imports.md @@ -343,7 +343,7 @@ Libraries that wildcard import from other libraries raise special concerns. If a user's package manager chooses a newer version of the imported-from library, the user may see a conflict in library code they don't expect to modify. -WESL library publishing tools will address this by expanding wildcards to named +WESL library publishing tools address this by expanding wildcards to named imports in the published version of the module: ```wesl @@ -356,9 +356,6 @@ import bevy::prelude::*; import bevy::prelude::{Color, Mesh, Transform, /* snapshot at publish time */}; ``` -Until WESL packaging tools implement this expansion, library authors should -avoid wildcard imports from external libraries they don't control. - ## Import errors and warnings WESL emits errors for name collisions and for external wildcards from unmarked From a1ec6c8c0957db09016e059e04af943dc162bd0a Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 5 May 2026 22:11:58 -0700 Subject: [PATCH 08/25] change wgsl_test module to 'expect' to make clear that other names than 'prelude' are allowable --- Imports.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Imports.md b/Imports.md index ce503e4..5fbf3a1 100644 --- a/Imports.md +++ b/Imports.md @@ -25,7 +25,7 @@ import bevy_ui; // Import all items from another module import bevy::prelude::*; -import wgsl_test::prelude::*; +import wgsl_test::expect::*; ``` These can then be used anywhere in the source code. @@ -287,7 +287,7 @@ Advanced users who wish to wildcard import from external modules not marked as ```wesl // wildcard import from a @wildcardable external import bevy::prelude::*; -import wgsl_test::prelude::*; +import wgsl_test::expect::*; // wildcard import from within the local package import package::utils::*; From b758d9593b7d6daa0ac530c78f7341399726b811 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 5 May 2026 22:46:43 -0700 Subject: [PATCH 09/25] add supressible diagnostics section --- Imports.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Imports.md b/Imports.md index 5fbf3a1..e8c3156 100644 --- a/Imports.md +++ b/Imports.md @@ -281,8 +281,8 @@ compiler warnings or errors. To help mitigate this risk, WESL provides a designed for wildcard importing. Advanced users who wish to wildcard import from external modules not marked as -`@wildcardable` can do so by annotating the import statement with -`@diagnostic(off, wildcard_import)`, accepting some additional upgrade risk. +`@wildcardable` can do so by suppressing `wildcard_import` (see +[Suppressible diagnostics](#suppressible-diagnostics)). ```wesl // wildcard import from a @wildcardable external @@ -333,7 +333,8 @@ applications. **Don't shadow WGSL builtins.** Names like `vec3`, `clamp`, `inverseSqrt` have expected semantics that oughtn't be implicitly overridden with wildcards. -Similarly, avoid experimental Naga/Dawn/Safari builtins. +Similarly, avoid experimental Naga/Dawn/Safari builtins. Consumers of the +module will see a `builtin_shadow` warning at the import site. - If a future WGSL update adds a conflicting builtin name, plan to update the `@wildcardable` module to rename the conflicting item. @@ -384,6 +385,22 @@ If `foo::clashing_zap` and `bar::clashing_zap` re-export the same item, there's no conflict. Otherwise the potential conflict is dormant unless `clashing_zap` is referenced. +### Suppressible diagnostics + +- **`wildcard_import`** fires on a wildcard import from an external module not + marked `@wildcardable`. Suppress with `@diagnostic(off, wildcard_import)` on + the import statement to accept the upgrade risk that future versions of the + imported module may add conflicting names. + +- **`wildcard_shadow`** fires when a local declaration or named import shadows a + name brought in by a wildcard import. The local wins by precedence (see + [Scope precedence](#scope-precedence)). + +- **`builtin_shadow`** fires when a wildcard import shadows a WGSL builtin such + as `vec3` or `clamp`. Suppress at the import site if the override is + intentional; the suppression itself documents documents to readers that the + builtins have changed semantics. + ### Scope precedence When a name could resolve to items at multiple precedence levels, the From abfb0e73a637df434a4beb0ff537a419e393c3bd Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 5 May 2026 22:49:30 -0700 Subject: [PATCH 10/25] fix outline level for scope precedence --- Imports.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Imports.md b/Imports.md index e8c3156..bbeb8b5 100644 --- a/Imports.md +++ b/Imports.md @@ -401,7 +401,7 @@ is referenced. intentional; the suppression itself documents documents to readers that the builtins have changed semantics. -### Scope precedence +## Scope precedence When a name could resolve to items at multiple precedence levels, the highest-precedence one wins. The table above describes whether such a resolution From 81e06f4433f28b3553f38cb1a3c7ecb50263e31a Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Wed, 6 May 2026 07:56:32 -0700 Subject: [PATCH 11/25] restore builtin_shadow publisher side check also add note that builtin_shadow client side check is only when referenced --- Imports.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Imports.md b/Imports.md index bbeb8b5..dacbe1e 100644 --- a/Imports.md +++ b/Imports.md @@ -333,8 +333,12 @@ applications. **Don't shadow WGSL builtins.** Names like `vec3`, `clamp`, `inverseSqrt` have expected semantics that oughtn't be implicitly overridden with wildcards. -Similarly, avoid experimental Naga/Dawn/Safari builtins. Consumers of the -module will see a `builtin_shadow` warning at the import site. +Similarly, avoid experimental Naga/Dawn/Safari builtins. +- WESL publishing tools should warn when a `@wildcardable` module exports an + item that shadows a WGSL builtin. Suppress with + `@diagnostic(off, builtin_shadow)` if the shadow is intentional. +- Consumers of the module will also see a `builtin_shadow` warning at the + import site. - If a future WGSL update adds a conflicting builtin name, plan to update the `@wildcardable` module to rename the conflicting item. @@ -371,7 +375,7 @@ collisions cannot be suppressed; other diagnostics are suppressible via | Wildcard import conflicts with wildcard import (when name is referenced) | Error | | Wildcard import from a non-`@wildcardable` external module | Error (`wildcard_import`); suppressible | | Local declaration or named import shadows a wildcard-imported name | Warning (`wildcard_shadow`); suppressible | -| Wildcard import shadows a WGSL builtin | Warning (`builtin_shadow`); suppressible | +| Wildcard import shadows a WGSL builtin (when name is referenced) | Warning (`builtin_shadow`) on the import; suppressible | When multiple wildcard imports are in scope, the same name may be exported by more than one module: @@ -396,10 +400,11 @@ is referenced. name brought in by a wildcard import. The local wins by precedence (see [Scope precedence](#scope-precedence)). -- **`builtin_shadow`** fires when a wildcard import shadows a WGSL builtin such +- **`builtin_shadow`** fires on a wildcard import when a referenced name in the + module resolves to a wildcard-imported item that shadows a WGSL builtin such as `vec3` or `clamp`. Suppress at the import site if the override is - intentional; the suppression itself documents documents to readers that the - builtins have changed semantics. + intentional; the suppression itself documents to readers that the builtins + have changed semantics. ## Scope precedence From 7d4bfd0bf19687bc350132b02ff427a911cc87df Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Wed, 6 May 2026 08:45:03 -0700 Subject: [PATCH 12/25] clarify wildcard clash case --- Imports.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Imports.md b/Imports.md index dacbe1e..20fd7bd 100644 --- a/Imports.md +++ b/Imports.md @@ -378,16 +378,20 @@ collisions cannot be suppressed; other diagnostics are suppressible via | Wildcard import shadows a WGSL builtin (when name is referenced) | Warning (`builtin_shadow`) on the import; suppressible | When multiple wildcard imports are in scope, the same name may be exported by -more than one module: +more than one module. The potential conflict is dormant unless the name is +referenced; referencing it is an error: ```wesl import foo::*; // exports clashing_zap -import bar::*; // exports clashing_zap +import bar::*; // exports a different clashing_zap + +fn main() { + let x = clashing_zap(); // error: ambiguous between foo::clashing_zap and bar::clashing_zap +} ``` -If `foo::clashing_zap` and `bar::clashing_zap` re-export the same item, there's -no conflict. Otherwise the potential conflict is dormant unless `clashing_zap` -is referenced. +The fix is to disambiguate with a named import (`import foo::clashing_zap;`) or +[inline module path](#inline-usage) (`foo::clashing_zap()`). ### Suppressible diagnostics From 9e46adf2b7210e2317923f6f1e38eae7af554280 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Wed, 6 May 2026 08:57:01 -0700 Subject: [PATCH 13/25] clarify precedence means wildcard updates are also safe --- Imports.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Imports.md b/Imports.md index 20fd7bd..ccf1a51 100644 --- a/Imports.md +++ b/Imports.md @@ -423,8 +423,13 @@ is silent, produces a warning, or produces an error. 5. predeclared items (WGSL builtins) Predeclared items rank lowest so that future WGSL spec revisions can add new -builtins without breaking existing WESL code: any name already bound at a -higher level continues to resolve as before. +builtins without breaking existing shaders: any name already bound at a higher +level continues to resolve as before. Wildcard-imported names rank below user +declarations and named imports for the analogous reason: additions to a +`@wildcardable` module won't silently change resolution at call sites that +already have a local or named binding for the same name. Wildcard imports do not +bring in package names (only top-level declarations of the imported module), so +a wildcard cannot shadow a package. ## Directives Under discussion, see: From 2a21505f3fe00a8b803564e9e106c8454b736bb7 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Sun, 10 May 2026 12:50:20 -0700 Subject: [PATCH 14/25] switch to `@wildcardable module;` syntax - add `attribute*` to `import_statement` so `@diagnostic` is grammatical on imports - `module` becomes a reserved keyword --- Imports.md | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Imports.md b/Imports.md index ccf1a51..15f93d9 100644 --- a/Imports.md +++ b/Imports.md @@ -70,7 +70,7 @@ translation_unit: | import_statement* global_directive* global_decl* import_statement: -| 'import' import_relative? (import_collection | import_path_or_item) ';' +| attribute* 'import' import_relative? (import_collection | import_path_or_item) ';' import_relative: | 'package' '::' | 'super' '::' ('super' '::')* @@ -86,7 +86,7 @@ import_collection: Where `translation_unit` and `ident` are defined in the WGSL grammar. `ident`s must not be current WGSL keywords. `ident`s also must not be -current WESL keywords: `as`, `import`, `package`, `super`, or `self`. +current WESL keywords: `as`, `import`, `module`, `package`, `super`, or `self`. Reserved words that are not current keywords are allowed, but not recommended. @@ -98,19 +98,17 @@ An import collection imports multiple items, and allows for nested imports. A wildcard import imports all top-level declarations from a module. Submodule names and submodule contents are not imported. -WESL also extends WGSL's `global_directive` rule with a `module_attribute` form (used by `@wildcardable`; see [Wildcard imports](#wildcard-imports)): +WESL also extends WGSL's `global_directive` rule with a `module_declaration` form, used by `@wildcardable` (see [Wildcard imports](#wildcard-imports)) and reserved for future module-level metadata. `attribute` is the WGSL attribute rule. ```ebnf global_directive: | ... // existing WGSL forms -| module_attribute +| module_declaration -module_attribute: -| '@' ident ';' +module_declaration: +| attribute* 'module' ';' ``` -The `@` prefix avoids conflict with WGSL identifiers. - ### Import resolution algorithm To resolve the import, the recursive structure is flattened out. This means turning every `import_collection` into multiple separate imports, ending with the items. @@ -271,7 +269,7 @@ scope. Users can wildcard import: - from any other module in the local package. - from any external library module where the library author has added a - `@wildcardable` directive. + `@wildcardable` annotation. Wildcard importing brings some stability risk when the imported module adds to its API. The newly introduced names may conflict with other names in the @@ -294,22 +292,22 @@ import package::utils::*; import super::fun::*; ``` -### `@wildcardable` directive +### `@wildcardable` annotation Library authors mark modules they intend for library consumers to wildcard -import with `@wildcardable`: +import with `@wildcardable module;`: ```wesl // math.wesl (in a library) -@wildcardable; +@wildcardable module; fn dot2(a: vec2f, b: vec2f) -> f32 { return a.x*b.x + a.y*b.y; } fn cross2(a: vec2f, b: vec2f) -> f32 { return a.x*b.y - a.y*b.x; } ``` -`@wildcardable` is a module attribute (see [Grammar](#grammar)). It must -appear after any imports and before any global declarations, and applies only -to the module it appears in. +`@wildcardable` is an attribute on a module declaration (see [Grammar](#grammar)). +The module declaration must appear after any imports and before any global +declarations, and applies only to the module it appears in. ### Recommendations for `@wildcardable` modules From 1a46cd8829d8478a7f73fe6e64c353404a1ebadb Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Sun, 10 May 2026 12:50:25 -0700 Subject: [PATCH 15/25] add ImportsDesign explainer - rationale for @wildcardable syntax - rationale for @wildcardable design --- ImportsDesign.md | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 ImportsDesign.md diff --git a/ImportsDesign.md b/ImportsDesign.md new file mode 100644 index 0000000..bedd2e6 --- /dev/null +++ b/ImportsDesign.md @@ -0,0 +1,95 @@ +# Imports Design + +This document records design decisions behind WESL's import system. The +normative spec lives in [Imports.md](Imports.md). + +## Why the `@wildcardable module;` form? + +`@wildcardable` is module-level metadata. WESL will likely want module-level +annotations for other module-scoped features, and libraries and users will want +a place to attach their own metadata to a whole module. A general-purpose syntax +for module metadata avoids inventing one ad-hoc form per feature. + +The syntax pairs an attribute list with a `module` declaration: + +- **`@`-prefixed attributes** match the existing item-level convention + (`@group`, `@binding`, `@if`, `@diagnostic`, ...). Module-level metadata uses + the same `@name` form, so users learn one annotation convention rather than + two, and the `@` always attaches to the element it precedes. +- **The `module` keyword** anchors the attributes to a declaration, but the + keyword is still usable for potential module-level features. For example, + syntax like `module(...)`, `module foo::bar`, or `module { ... }` is still + available for future use. + +See [`@wildcardable` annotation](Imports.md#wildcardable-annotation) for the +normative spec. + +## Aren't wildcards an anti-pattern? + +Many language communities discourage wildcard imports. TypeScript, Go, Zig, and +Carbon disallow wildcards entirely or restrict them to narrow cases. Java and +Rust permit them syntactically but discourage broad use by convention; Rust's +`prelude` modules are one curated pattern in that style. The general concerns +are practical: + +- **Readability.** Direct imports make it obvious where a name comes from. + Wildcards push that work onto the reader, the language server, or the + compiler's name-resolution diagnostics. +- **API stability.** Adding a public item to a wildcard-imported module can + conflict with downstream declarations or with other wildcard imports. Stacked + wildcards across a dependency tree can create conflicts the end user neither + caused nor can easily fix. + +The WESL environment adds further concerns: + +- **Cross-ecosystem publishing.** WESL libraries can be published into multiple + host ecosystems (npm, crates, etc.), and the language's stability rules have + to work for all of them. npm in particular treats minor/patch breakage as an + upstream bug, so wildcard-driven conflicts on additive package updates would + be read there as buggy packages, not as users accepting a WESL-specific + tradeoff. The defaults can't be split per-ecosystem; even libraries that + aren't actively cross-published inherit the same rules. +- **Mixed-language ownership.** In host applications, dependency updates are + often routine maintenance handled by someone other than the shader author. A + wildcard conflict can land on a teammate who did not cause it and may not be + best positioned to fix shader-side breakage. +- **Shader test coverage.** Shader test coverage is often thinner than + application-code coverage, and some failures are visual or runtime-dependent. + Fewer tests and WGSL's comparatively small type system mean that wildcard + conflicts are less likely to be caught at the moment a dependency is updated. +- **Single namespace.** WGSL has a single namespace for types and values, and no + namespace construct or object-style surface to limit the scope of wildcarded + names after import. There are fewer places for names to coexist harmlessly. + +These concerns motivate guardrails for WESL wildcard defaults. + +## Wildcards in WESL: when to allow, when to gate + +WESL keeps wildcards available because some libraries are designed to feel +pervasive. Game engines, test frameworks, and math libraries expect a +domain-specific API where prefixing every call with `test::expect::` or similar +would obscure the shader rather than help it. Concise import syntax matters even +where an IDE can autocomplete: not every editor has a language server, and long +import blocks add noise regardless of how they were typed. + +But the concerns in +[Aren't wildcards an anti-pattern?](#arent-wildcards-an-anti-pattern) still +apply, especially across package boundaries. WESL's defaults try to keep the +benefits while limiting the risk: + +- **Not every public module suits wildcards.** Modules with a fast-growing API + or with generic names (`Buffer`, `Result`) are fine to import by name but + hazardous to wildcard. +- **Authors can signal which modules are curated for wildcards.** An explicit + `@wildcardable` marker lets library authors tell consumers (and tools) which + modules they've designed for wildcard use. It also gives tooling a hook for + lints around generic names, builtin shadowing, churn-prone additions, etc. +- **Defaults shape the ecosystem.** Red/yellow squiggles and linter messages + teach safe wildcard practice to new and part-time shader authors more reliably + than community blogs or documentation. +- **Advanced users are not blocked.** Within a package, wildcard imports are + unrestricted; externally, wildcard-importing a non-`@wildcardable` module is + possible via + [standard diagnostic controls](Imports.md#suppressible-diagnostics). The + default tunes the path of least resistance, but doesn't block users who + intentionally accept the risk. From b58f43bdbe58b38e168bce6e9a41c45ab15738ee Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 12 May 2026 15:54:13 -0700 Subject: [PATCH 16/25] direct imports are more traceable and whether that's more readable depends on how many there are. --- ImportsDesign.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImportsDesign.md b/ImportsDesign.md index bedd2e6..414469c 100644 --- a/ImportsDesign.md +++ b/ImportsDesign.md @@ -32,7 +32,7 @@ Rust permit them syntactically but discourage broad use by convention; Rust's `prelude` modules are one curated pattern in that style. The general concerns are practical: -- **Readability.** Direct imports make it obvious where a name comes from. +- **Traceability.** Direct imports make it obvious where a name comes from. Wildcards push that work onto the reader, the language server, or the compiler's name-resolution diagnostics. - **API stability.** Adding a public item to a wildcard-imported module can From 983259ddd1e135fae3ef7ed01dc5f46eec30a1a8 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 12 May 2026 15:55:21 -0700 Subject: [PATCH 17/25] clarify at most one 'module' per file --- Imports.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Imports.md b/Imports.md index 15f93d9..2feb8eb 100644 --- a/Imports.md +++ b/Imports.md @@ -109,6 +109,8 @@ module_declaration: | attribute* 'module' ';' ``` +A file may have at most one `module` declaration. + ### Import resolution algorithm To resolve the import, the recursive structure is flattened out. This means turning every `import_collection` into multiple separate imports, ending with the items. From eb455ad702a83e04c0c1c576c9fb51416874ca60 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 12 May 2026 15:56:18 -0700 Subject: [PATCH 18/25] rm client side builtin_shadow for separate PR --- Imports.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Imports.md b/Imports.md index 2feb8eb..8b90939 100644 --- a/Imports.md +++ b/Imports.md @@ -336,9 +336,7 @@ expected semantics that oughtn't be implicitly overridden with wildcards. Similarly, avoid experimental Naga/Dawn/Safari builtins. - WESL publishing tools should warn when a `@wildcardable` module exports an item that shadows a WGSL builtin. Suppress with - `@diagnostic(off, builtin_shadow)` if the shadow is intentional. -- Consumers of the module will also see a `builtin_shadow` warning at the - import site. + `@diagnostic(off, builtin_shadow)` in the module if the shadow is intentional. - If a future WGSL update adds a conflicting builtin name, plan to update the `@wildcardable` module to rename the conflicting item. @@ -375,7 +373,6 @@ collisions cannot be suppressed; other diagnostics are suppressible via | Wildcard import conflicts with wildcard import (when name is referenced) | Error | | Wildcard import from a non-`@wildcardable` external module | Error (`wildcard_import`); suppressible | | Local declaration or named import shadows a wildcard-imported name | Warning (`wildcard_shadow`); suppressible | -| Wildcard import shadows a WGSL builtin (when name is referenced) | Warning (`builtin_shadow`) on the import; suppressible | When multiple wildcard imports are in scope, the same name may be exported by more than one module. The potential conflict is dormant unless the name is @@ -402,13 +399,13 @@ The fix is to disambiguate with a named import (`import foo::clashing_zap;`) or - **`wildcard_shadow`** fires when a local declaration or named import shadows a name brought in by a wildcard import. The local wins by precedence (see - [Scope precedence](#scope-precedence)). + [Scope precedence](#scope-precedence)). Suppress with + `@diagnostic(off, wildcard_shadow)` on the shadowing declaration or import. -- **`builtin_shadow`** fires on a wildcard import when a referenced name in the - module resolves to a wildcard-imported item that shadows a WGSL builtin such - as `vec3` or `clamp`. Suppress at the import site if the override is - intentional; the suppression itself documents to readers that the builtins - have changed semantics. +- **`builtin_shadow`** fires in WESL publishing tools when a `@wildcardable` + module exports an item that shadows a WGSL builtin such as `vec3` or `clamp`. + Suppress with `@diagnostic(off, builtin_shadow)` in the module if the override + is intentional. ## Scope precedence From fa9e8373e6a7241d70ae2e7d2b40f9cfdde27d63 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 12 May 2026 17:21:47 -0700 Subject: [PATCH 19/25] clarify where wildcard_shadow appears --- Imports.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Imports.md b/Imports.md index 8b90939..7baa2b7 100644 --- a/Imports.md +++ b/Imports.md @@ -397,10 +397,11 @@ The fix is to disambiguate with a named import (`import foo::clashing_zap;`) or the import statement to accept the upgrade risk that future versions of the imported module may add conflicting names. -- **`wildcard_shadow`** fires when a local declaration or named import shadows a - name brought in by a wildcard import. The local wins by precedence (see - [Scope precedence](#scope-precedence)). Suppress with - `@diagnostic(off, wildcard_shadow)` on the shadowing declaration or import. +- **`wildcard_shadow`** fires on a local declaration or named import that + shadows a name brought in by a wildcard import. The local wins by precedence + (see [Scope precedence](#scope-precedence)). Suppress with + `@diagnostic(off, wildcard_shadow)` on that shadowing declaration or import + statement. - **`builtin_shadow`** fires in WESL publishing tools when a `@wildcardable` module exports an item that shadows a WGSL builtin such as `vec3` or `clamp`. From 946d64dbb75b2a11471fa4ed7fec1c84046ccd8b Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Tue, 12 May 2026 17:37:04 -0700 Subject: [PATCH 20/25] clarify error location in table --- Imports.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Imports.md b/Imports.md index 7baa2b7..089e8c8 100644 --- a/Imports.md +++ b/Imports.md @@ -371,8 +371,8 @@ collisions cannot be suppressed; other diagnostics are suppressible via | Local declaration conflicts with named import | Error | | Named import conflicts with named import | Error | | Wildcard import conflicts with wildcard import (when name is referenced) | Error | -| Wildcard import from a non-`@wildcardable` external module | Error (`wildcard_import`); suppressible | -| Local declaration or named import shadows a wildcard-imported name | Warning (`wildcard_shadow`); suppressible | +| Wildcard import from a non-`@wildcardable` external module | Error (`wildcard_import`) on the import; suppressible | +| Local declaration or named import shadows a wildcard-imported name | Warning (`wildcard_shadow`) on the shadowing declaration; suppressible | When multiple wildcard imports are in scope, the same name may be exported by more than one module. The potential conflict is dormant unless the name is From ca3c45b1bb18c675ae33bf1bf0c324f3300ff87c Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Wed, 24 Jun 2026 21:01:19 -0700 Subject: [PATCH 21/25] @! syntax for module attributes as in: `@!wildcardable;` --- Imports.md | 56 ++++++++++++++++++++++++------------------------ ImportsDesign.md | 25 ++++++++++----------- 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/Imports.md b/Imports.md index 089e8c8..4ed3e44 100644 --- a/Imports.md +++ b/Imports.md @@ -86,7 +86,7 @@ import_collection: Where `translation_unit` and `ident` are defined in the WGSL grammar. `ident`s must not be current WGSL keywords. `ident`s also must not be -current WESL keywords: `as`, `import`, `module`, `package`, `super`, or `self`. +current WESL keywords: `as`, `import`, `package`, `super`, or `self`. Reserved words that are not current keywords are allowed, but not recommended. @@ -98,18 +98,22 @@ An import collection imports multiple items, and allows for nested imports. A wildcard import imports all top-level declarations from a module. Submodule names and submodule contents are not imported. -WESL also extends WGSL's `global_directive` rule with a `module_declaration` form, used by `@wildcardable` (see [Wildcard imports](#wildcard-imports)) and reserved for future module-level metadata. `attribute` is the WGSL attribute rule. +WESL also extends WGSL's `global_directive` rule with a *module attribute*: a `@!`-prefixed attribute that carries module-level metadata. It is used by `@!wildcardable` (see [Wildcard imports](#wildcard-imports)) and reserved for future module-level metadata. ```ebnf global_directive: | ... // existing WGSL forms -| module_declaration +| module_attribute_directive -module_declaration: -| attribute* 'module' ';' +module_attribute_directive: +| '@' '!' ident_pattern_token argument_expression_list? ';' ``` -A file may have at most one `module` declaration. +A module attribute is written like a WGSL `attribute` with a `!` immediately +after the `@`, and is terminated with `;`; `ident_pattern_token` and +`argument_expression_list` are the WGSL rules. Like other global directives, +module attributes appear after any imports and before any global declarations, +and apply to the module they appear in. ### Import resolution algorithm @@ -271,21 +275,21 @@ scope. Users can wildcard import: - from any other module in the local package. - from any external library module where the library author has added a - `@wildcardable` annotation. + `@!wildcardable` annotation. Wildcard importing brings some stability risk when the imported module adds to its API. The newly introduced names may conflict with other names in the importer's namespace (from local definitions and other imports), leading to compiler warnings or errors. To help mitigate this risk, WESL provides a -`@wildcardable` annotation that library authors can place on modules that are +`@!wildcardable` annotation that library authors can place on modules that are designed for wildcard importing. Advanced users who wish to wildcard import from external modules not marked as -`@wildcardable` can do so by suppressing `wildcard_import` (see +`@!wildcardable` can do so by suppressing `wildcard_import` (see [Suppressible diagnostics](#suppressible-diagnostics)). ```wesl -// wildcard import from a @wildcardable external +// wildcard import from a @!wildcardable external import bevy::prelude::*; import wgsl_test::expect::*; @@ -294,37 +298,33 @@ import package::utils::*; import super::fun::*; ``` -### `@wildcardable` annotation +### `@!wildcardable` annotation Library authors mark modules they intend for library consumers to wildcard -import with `@wildcardable module;`: +import with the `@!wildcardable;` module attribute (see [Grammar](#grammar)): ```wesl // math.wesl (in a library) -@wildcardable module; +@!wildcardable; fn dot2(a: vec2f, b: vec2f) -> f32 { return a.x*b.x + a.y*b.y; } fn cross2(a: vec2f, b: vec2f) -> f32 { return a.x*b.y - a.y*b.x; } ``` -`@wildcardable` is an attribute on a module declaration (see [Grammar](#grammar)). -The module declaration must appear after any imports and before any global -declarations, and applies only to the module it appears in. +### Recommendations for `@!wildcardable` modules -### Recommendations for `@wildcardable` modules - -Because every name in a `@wildcardable` module is a potential collision in +Because every name in a `@!wildcardable` module is a potential collision in importer code, library authors should curate these modules carefully. -**Add hesitantly.** Additions to a `@wildcardable` module are semver minor +**Add hesitantly.** Additions to a `@!wildcardable` module are semver minor version bumps but can break users who have local declarations or import other -`@wildcardable` modules. +`@!wildcardable` modules. - **Bundle** additions into a major release when one is upcoming. - **Document** additions clearly in changelogs so downstream users debugging unexpected name resolution can trace them. **Compose with re-exports.** See [Re-exports](#re-exports) (TBD) to collect -items from other modules into a single `@wildcardable` module for user +items from other modules into a single `@!wildcardable` module for user convenience. **Avoid generic names.** Prefer domain-specific names. Common names like @@ -334,11 +334,11 @@ applications. **Don't shadow WGSL builtins.** Names like `vec3`, `clamp`, `inverseSqrt` have expected semantics that oughtn't be implicitly overridden with wildcards. Similarly, avoid experimental Naga/Dawn/Safari builtins. -- WESL publishing tools should warn when a `@wildcardable` module exports an +- WESL publishing tools should warn when a `@!wildcardable` module exports an item that shadows a WGSL builtin. Suppress with `@diagnostic(off, builtin_shadow)` in the module if the shadow is intentional. - If a future WGSL update adds a conflicting builtin name, plan to update the - `@wildcardable` module to rename the conflicting item. + `@!wildcardable` module to rename the conflicting item. ### Library-to-library wildcard imports @@ -371,7 +371,7 @@ collisions cannot be suppressed; other diagnostics are suppressible via | Local declaration conflicts with named import | Error | | Named import conflicts with named import | Error | | Wildcard import conflicts with wildcard import (when name is referenced) | Error | -| Wildcard import from a non-`@wildcardable` external module | Error (`wildcard_import`) on the import; suppressible | +| Wildcard import from a non-`@!wildcardable` external module | Error (`wildcard_import`) on the import; suppressible | | Local declaration or named import shadows a wildcard-imported name | Warning (`wildcard_shadow`) on the shadowing declaration; suppressible | When multiple wildcard imports are in scope, the same name may be exported by @@ -393,7 +393,7 @@ The fix is to disambiguate with a named import (`import foo::clashing_zap;`) or ### Suppressible diagnostics - **`wildcard_import`** fires on a wildcard import from an external module not - marked `@wildcardable`. Suppress with `@diagnostic(off, wildcard_import)` on + marked `@!wildcardable`. Suppress with `@diagnostic(off, wildcard_import)` on the import statement to accept the upgrade risk that future versions of the imported module may add conflicting names. @@ -403,7 +403,7 @@ The fix is to disambiguate with a named import (`import foo::clashing_zap;`) or `@diagnostic(off, wildcard_shadow)` on that shadowing declaration or import statement. -- **`builtin_shadow`** fires in WESL publishing tools when a `@wildcardable` +- **`builtin_shadow`** fires in WESL publishing tools when a `@!wildcardable` module exports an item that shadows a WGSL builtin such as `vec3` or `clamp`. Suppress with `@diagnostic(off, builtin_shadow)` in the module if the override is intentional. @@ -424,7 +424,7 @@ Predeclared items rank lowest so that future WGSL spec revisions can add new builtins without breaking existing shaders: any name already bound at a higher level continues to resolve as before. Wildcard-imported names rank below user declarations and named imports for the analogous reason: additions to a -`@wildcardable` module won't silently change resolution at call sites that +`@!wildcardable` module won't silently change resolution at call sites that already have a local or named binding for the same name. Wildcard imports do not bring in package names (only top-level declarations of the imported module), so a wildcard cannot shadow a package. diff --git a/ImportsDesign.md b/ImportsDesign.md index 414469c..1a395db 100644 --- a/ImportsDesign.md +++ b/ImportsDesign.md @@ -3,25 +3,22 @@ This document records design decisions behind WESL's import system. The normative spec lives in [Imports.md](Imports.md). -## Why the `@wildcardable module;` form? +## Why the `@!` module attribute form? -`@wildcardable` is module-level metadata. WESL will likely want module-level +`@!wildcardable` is module-level metadata. WESL will likely want module-level annotations for other module-scoped features, and libraries and users will want a place to attach their own metadata to a whole module. A general-purpose syntax for module metadata avoids inventing one ad-hoc form per feature. -The syntax pairs an attribute list with a `module` declaration: +`@!wildcardable` mirrors the item-level attribute convention (`@group`, +`@binding`, `@if`, `@diagnostic`, ...), but the `!` marks the attribute as +scoped to the whole module. Unlike an item attribute, it doesn't attach to a +following element, so a trailing `;` terminates it. -- **`@`-prefixed attributes** match the existing item-level convention - (`@group`, `@binding`, `@if`, `@diagnostic`, ...). Module-level metadata uses - the same `@name` form, so users learn one annotation convention rather than - two, and the `@` always attaches to the element it precedes. -- **The `module` keyword** anchors the attributes to a declaration, but the - keyword is still usable for potential module-level features. For example, - syntax like `module(...)`, `module foo::bar`, or `module { ... }` is still - available for future use. +Module attributes sit below the imports so that they can use imported +names (for example a hypothetical `@!play_version(2);`). -See [`@wildcardable` annotation](Imports.md#wildcardable-annotation) for the +See [`@!wildcardable` annotation](Imports.md#wildcardable-annotation) for the normative spec. ## Aren't wildcards an anti-pattern? @@ -81,14 +78,14 @@ benefits while limiting the risk: or with generic names (`Buffer`, `Result`) are fine to import by name but hazardous to wildcard. - **Authors can signal which modules are curated for wildcards.** An explicit - `@wildcardable` marker lets library authors tell consumers (and tools) which + `@!wildcardable` marker lets library authors tell consumers (and tools) which modules they've designed for wildcard use. It also gives tooling a hook for lints around generic names, builtin shadowing, churn-prone additions, etc. - **Defaults shape the ecosystem.** Red/yellow squiggles and linter messages teach safe wildcard practice to new and part-time shader authors more reliably than community blogs or documentation. - **Advanced users are not blocked.** Within a package, wildcard imports are - unrestricted; externally, wildcard-importing a non-`@wildcardable` module is + unrestricted; externally, wildcard-importing a non-`@!wildcardable` module is possible via [standard diagnostic controls](Imports.md#suppressible-diagnostics). The default tunes the path of least resistance, but doesn't block users who From 66df0b7282e2df2375511e2bbc84b42f3e316f51 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Wed, 1 Jul 2026 23:11:58 -0700 Subject: [PATCH 22/25] revise based on PR feedback --- Imports.md | 82 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/Imports.md b/Imports.md index 4ed3e44..4cfaa60 100644 --- a/Imports.md +++ b/Imports.md @@ -334,9 +334,8 @@ applications. **Don't shadow WGSL builtins.** Names like `vec3`, `clamp`, `inverseSqrt` have expected semantics that oughtn't be implicitly overridden with wildcards. Similarly, avoid experimental Naga/Dawn/Safari builtins. -- WESL publishing tools should warn when a `@!wildcardable` module exports an - item that shadows a WGSL builtin. Suppress with - `@diagnostic(off, builtin_shadow)` in the module if the shadow is intentional. +- The `builtin_shadow` diagnostic flags this (see + [Suppressible diagnostics](#suppressible-diagnostics)). - If a future WGSL update adds a conflicting builtin name, plan to update the `@!wildcardable` module to rename the conflicting item. @@ -346,8 +345,15 @@ Libraries that wildcard import from other libraries raise special concerns. If a user's package manager chooses a newer version of the imported-from library, the user may see a conflict in library code they don't expect to modify. -WESL library publishing tools address this by expanding wildcards to named -imports in the published version of the module: +Cross-package wildcard imports in library code +trigger the `library_wildcard` diagnostic, a suppressible error. Library +authors can suppress the diagnostic with +`@diagnostic(off, library_wildcard)` on the import statement, e.g. when +wildcard importing from external packages they control. + +**Optional: publish-time wildcard expansion.** Library publishing tools may +also offer to expand wildcards to named imports in the published version of a +module, snapshotting the names at publish time: ```wesl // source @@ -359,6 +365,9 @@ import bevy::prelude::*; import bevy::prelude::{Color, Mesh, Transform, /* snapshot at publish time */}; ``` +Expansion pins the imported names so that a newer version of the imported-from +library can't introduce conflicts into already-published code. + ## Import errors and warnings WESL emits errors for name collisions and for external wildcards from unmarked @@ -372,11 +381,15 @@ collisions cannot be suppressed; other diagnostics are suppressible via | Named import conflicts with named import | Error | | Wildcard import conflicts with wildcard import (when name is referenced) | Error | | Wildcard import from a non-`@!wildcardable` external module | Error (`wildcard_import`) on the import; suppressible | -| Local declaration or named import shadows a wildcard-imported name | Warning (`wildcard_shadow`) on the shadowing declaration; suppressible | +| Cross-package wildcard import in library code | Error (`library_wildcard`) on the import; suppressible | +| Local declaration or named import shadows a wildcard-imported name | Warning (`wildcard_shadow`) on the shadowing declaration or import; suppressible | +| `@!wildcardable` module exports an item shadowing a WGSL builtin | Warning (`builtin_shadow`) in the exporting module; suppressible | When multiple wildcard imports are in scope, the same name may be exported by -more than one module. The potential conflict is dormant unless the name is -referenced; referencing it is an error: +more than one module. If every wildcard resolves the name to the same +declaration, references are unambiguous and no error occurs. A name that could +refer to two different declarations is a dormant conflict: an error occurs +only where the name is referenced: ```wesl import foo::*; // exports clashing_zap @@ -395,39 +408,48 @@ The fix is to disambiguate with a named import (`import foo::clashing_zap;`) or - **`wildcard_import`** fires on a wildcard import from an external module not marked `@!wildcardable`. Suppress with `@diagnostic(off, wildcard_import)` on the import statement to accept the upgrade risk that future versions of the - imported module may add conflicting names. - -- **`wildcard_shadow`** fires on a local declaration or named import that - shadows a name brought in by a wildcard import. The local wins by precedence - (see [Scope precedence](#scope-precedence)). Suppress with - `@diagnostic(off, wildcard_shadow)` on that shadowing declaration or import - statement. - -- **`builtin_shadow`** fires in WESL publishing tools when a `@!wildcardable` - module exports an item that shadows a WGSL builtin such as `vec3` or `clamp`. - Suppress with `@diagnostic(off, builtin_shadow)` in the module if the override - is intentional. + imported module may add conflicting names. The suppression has no effect on + an import from a `@!wildcardable` module, where the diagnostic never fires. + +- **`wildcard_shadow`** is a warning that fires on a local declaration or named + import that shadows a name brought in by a wildcard import. The shadowing is + allowed: the local declaration or named import wins by precedence + (see [Scope precedence](#scope-precedence)). Suppressing the warning with + `@diagnostic(off, wildcard_shadow)` on the shadowing declaration or import + statement changes only the reporting, not the resolution. + +- **`library_wildcard`** is a suppressible error that fires on a cross-package + wildcard import in library code (see + [Library-to-library wildcard imports](#library-to-library-wildcard-imports)). + Suppress with `@diagnostic(off, library_wildcard)` on the import statement. + +- **`builtin_shadow`** fires on a `@!wildcardable` module that exports an item + shadowing a WGSL builtin such as `vec3` or `clamp`. Suppress with + `@diagnostic(off, builtin_shadow)` in the module if the override is + intentional. ## Scope precedence When a name could resolve to items at multiple precedence levels, the -highest-precedence one wins. The table above describes whether such a resolution -is silent, produces a warning, or produces an error. +highest-precedence one wins. The table in +[Import errors and warnings](#import-errors-and-warnings) describes whether +such a resolution is silent, produces a warning, or produces an error. + +1. user declarations and named imports (non-wildcard) +2. wildcard-imported names +3. package names +4. predeclared items (WGSL builtins) -1. user declarations -2. named imports (non-wildcard) -3. wildcard-imported names -4. package names -5. predeclared items (WGSL builtins) +User declarations and named imports share the top precedence level: a conflict +between them is an error, so at most one candidate can exist at that level. Predeclared items rank lowest so that future WGSL spec revisions can add new builtins without breaking existing shaders: any name already bound at a higher level continues to resolve as before. Wildcard-imported names rank below user declarations and named imports for the analogous reason: additions to a `@!wildcardable` module won't silently change resolution at call sites that -already have a local or named binding for the same name. Wildcard imports do not -bring in package names (only top-level declarations of the imported module), so -a wildcard cannot shadow a package. +already have a local or named binding for the same name. Wildcard imports bring +in only the imported module's top-level declarations, not package names. ## Directives Under discussion, see: From 78ff4d1462f9e66c59ce0ae93fab078209b2c5aa Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Thu, 2 Jul 2026 15:41:27 -0700 Subject: [PATCH 23/25] rm some zero width characters --- Imports.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Imports.md b/Imports.md index 4cfaa60..34af42d 100644 --- a/Imports.md +++ b/Imports.md @@ -474,19 +474,19 @@ This only refers to the exact module that an element is in, and not any of the p Example: ```wgsl -​​​​// main.wesl: -​​​​import foo::bar; -​​​​fn main() { bar(); } - -​​​​// foo.wesl: -​​​​import zig::zag; -​​​​const_assert(1 > 0); // included in link because bar is used -​​​​fn bar() { } -​​​​fn miz() { zag() } - -​​​​// zig.wesl: -​​​​const_assert(2 < 0); // not included in link -​​​​fn zag() { } +// main.wesl: +import foo::bar; +fn main() { bar(); } + +// foo.wesl: +import zig::zag; +const_assert(1 > 0); // included in link because bar is used +fn bar() { } +fn miz() { zag() } + +// zig.wesl: +const_assert(2 < 0); // not included in link +fn zag() { } ``` Example From cb61e0c691b746694399a16086fae406887d2aac Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Thu, 2 Jul 2026 15:49:35 -0700 Subject: [PATCH 24/25] note prohibiting import *; --- Imports.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Imports.md b/Imports.md index 34af42d..76bc60d 100644 --- a/Imports.md +++ b/Imports.md @@ -96,7 +96,7 @@ An item import imports a single item. The item can be renamed with the `as` keyw An import collection imports multiple items, and allows for nested imports. -A wildcard import imports all top-level declarations from a module. Submodule names and submodule contents are not imported. +A wildcard import imports all top-level declarations from a module. Submodule names and submodule contents are not imported. A wildcard must follow a module path; a bare `import *;` is an error. WESL also extends WGSL's `global_directive` rule with a *module attribute*: a `@!`-prefixed attribute that carries module-level metadata. It is used by `@!wildcardable` (see [Wildcard imports](#wildcard-imports)) and reserved for future module-level metadata. From 9feb56601fadd18d5f3dcafb450c8a4bc6876bf2 Mon Sep 17 00:00:00 2001 From: lee mighdoll Date: Sun, 5 Jul 2026 21:31:23 -0700 Subject: [PATCH 25/25] revise based on latest k2d222 comments / agent review - rename diagnostic to cross_package_wildcard - rename diagnostic to unsuppored_wildcard - clarify suppression of builtin_shadow - clarify module level suppression generally - clarify that wildcards can be in import collections --- Imports.md | 66 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/Imports.md b/Imports.md index 76bc60d..a75c212 100644 --- a/Imports.md +++ b/Imports.md @@ -96,7 +96,7 @@ An item import imports a single item. The item can be renamed with the `as` keyw An import collection imports multiple items, and allows for nested imports. -A wildcard import imports all top-level declarations from a module. Submodule names and submodule contents are not imported. A wildcard must follow a module path; a bare `import *;` is an error. +A wildcard import imports all top-level declarations from a module. Submodule names and submodule contents are not imported. A wildcard must follow a module path; a bare `import *;` is an error. A wildcard may also appear as a member of an import collection, applying to the module path before the braces (see [Import resolution algorithm](#import-resolution-algorithm)). WESL also extends WGSL's `global_directive` rule with a *module attribute*: a `@!`-prefixed attribute that carries module-level metadata. It is used by `@!wildcardable` (see [Wildcard imports](#wildcard-imports)) and reserved for future module-level metadata. @@ -126,6 +126,17 @@ import a::c::d; import a::c::e as f; ``` +A wildcard may appear as a member of an import collection: +`import foo::{a::b, *};` becomes + +```wesl +import foo::a::b; +import foo::*; +``` + +The wildcard imports only `foo`'s own top-level declarations: the sibling +branch reaching into submodule `foo::a` doesn't widen it. + Then, one iterates over each segment from left to right, and looks it up one by one. 1. We start with the first segment. @@ -285,7 +296,7 @@ compiler warnings or errors. To help mitigate this risk, WESL provides a designed for wildcard importing. Advanced users who wish to wildcard import from external modules not marked as -`@!wildcardable` can do so by suppressing `wildcard_import` (see +`@!wildcardable` can do so by suppressing `unsupported_wildcard` (see [Suppressible diagnostics](#suppressible-diagnostics)). ```wesl @@ -346,9 +357,9 @@ user's package manager chooses a newer version of the imported-from library, the user may see a conflict in library code they don't expect to modify. Cross-package wildcard imports in library code -trigger the `library_wildcard` diagnostic, a suppressible error. Library +trigger the `cross_package_wildcard` diagnostic, a suppressible error. Library authors can suppress the diagnostic with -`@diagnostic(off, library_wildcard)` on the import statement, e.g. when +`@diagnostic(off, cross_package_wildcard)` on the import statement, e.g. when wildcard importing from external packages they control. **Optional: publish-time wildcard expansion.** Library publishing tools may @@ -370,8 +381,8 @@ library can't introduce conflicts into already-published code. ## Import errors and warnings -WESL emits errors for name collisions and for external wildcards from unmarked -modules, and warnings for shadowing that could surprise readers. Genuine +WESL emits errors for name collisions and for unsupported wildcard imports, +and warnings for shadowing that could surprise readers. Genuine collisions cannot be suppressed; other diagnostics are suppressible via `@diagnostic`. @@ -380,10 +391,10 @@ collisions cannot be suppressed; other diagnostics are suppressible via | Local declaration conflicts with named import | Error | | Named import conflicts with named import | Error | | Wildcard import conflicts with wildcard import (when name is referenced) | Error | -| Wildcard import from a non-`@!wildcardable` external module | Error (`wildcard_import`) on the import; suppressible | -| Cross-package wildcard import in library code | Error (`library_wildcard`) on the import; suppressible | +| Wildcard import from a non-`@!wildcardable` external module | Error (`unsupported_wildcard`) on the import; suppressible | +| Cross-package wildcard import in library code | Error (`cross_package_wildcard`) on the import; suppressible | | Local declaration or named import shadows a wildcard-imported name | Warning (`wildcard_shadow`) on the shadowing declaration or import; suppressible | -| `@!wildcardable` module exports an item shadowing a WGSL builtin | Warning (`builtin_shadow`) in the exporting module; suppressible | +| `@!wildcardable` module exports an item shadowing a WGSL builtin | Warning (`builtin_shadow`) on the shadowing declaration; suppressible | When multiple wildcard imports are in scope, the same name may be exported by more than one module. If every wildcard resolves the name to the same @@ -400,16 +411,23 @@ fn main() { } ``` -The fix is to disambiguate with a named import (`import foo::clashing_zap;`) or +The fix is to disambiguate with a named import (`import foo::clashing_zap;`, +or `import foo::{clashing_zap, *};` to keep the wildcard) or an [inline module path](#inline-usage) (`foo::clashing_zap()`). ### Suppressible diagnostics -- **`wildcard_import`** fires on a wildcard import from an external module not - marked `@!wildcardable`. Suppress with `@diagnostic(off, wildcard_import)` on - the import statement to accept the upgrade risk that future versions of the - imported module may add conflicting names. The suppression has no effect on - an import from a `@!wildcardable` module, where the diagnostic never fires. +Each diagnostic below can be suppressed at the site indicated with a +`@diagnostic` attribute, or module-wide with WGSL's +[global diagnostic directive](https://www.w3.org/TR/WGSL/#global-diagnostic-directive), +e.g. `diagnostic(off, wildcard_shadow);`. + +- **`unsupported_wildcard`** fires on a wildcard import from an external module + that doesn't support wildcard import (not marked `@!wildcardable`). Suppress + with `@diagnostic(off, unsupported_wildcard)` on the import statement to + accept the upgrade risk that future versions of the imported module may add + conflicting names. The suppression has no effect on an import from a + `@!wildcardable` module, where the diagnostic never fires. - **`wildcard_shadow`** is a warning that fires on a local declaration or named import that shadows a name brought in by a wildcard import. The shadowing is @@ -418,15 +436,17 @@ The fix is to disambiguate with a named import (`import foo::clashing_zap;`) or `@diagnostic(off, wildcard_shadow)` on the shadowing declaration or import statement changes only the reporting, not the resolution. -- **`library_wildcard`** is a suppressible error that fires on a cross-package - wildcard import in library code (see +- **`cross_package_wildcard`** is a suppressible error that fires on a + cross-package wildcard import in library code (see [Library-to-library wildcard imports](#library-to-library-wildcard-imports)). - Suppress with `@diagnostic(off, library_wildcard)` on the import statement. - -- **`builtin_shadow`** fires on a `@!wildcardable` module that exports an item - shadowing a WGSL builtin such as `vec3` or `clamp`. Suppress with - `@diagnostic(off, builtin_shadow)` in the module if the override is - intentional. + Suppress with `@diagnostic(off, cross_package_wildcard)` on the import + statement. + +- **`builtin_shadow`** is a warning that fires in a `@!wildcardable` module, + on a top-level declaration whose name shadows a WGSL builtin such as `vec3` + or `clamp`, whether or not any module wildcard imports it. Suppress with + `@diagnostic(off, builtin_shadow)` on the offending declaration if the + override is intentional. ## Scope precedence