pub struct AnalysisOptions {
pub host_manifest: Option<HostManifest>,
pub external_check: ExternalCheckSeverity,
pub semantic_type_check: SemanticTypeDiagnosticSeverity,
pub dialect: Dialect,
pub types: Option<TypePolicy>,
pub lints: LintPolicy,
pub emit_debug_info: bool,
pub conventions: Option<String>,
}Expand description
Tooling options for analysis: the registered host manifest and the severity policy for its external checks. Defaults to no manifest.
PartialEq/Eq + serde are the #1306 requirement: AnalysisOptions is
the resolved-policy slot of the serializable, content-addressed
Environment input value,
so the whole Environment can be hashed, cached on, and diffed.
Fields§
§host_manifest: Option<HostManifest>The registered host-capability manifest, if any.
external_check: ExternalCheckSeveritySeverity policy for manifest-driven external diagnostics.
semantic_type_check: SemanticTypeDiagnosticSeveritySeverity policy for unknown-semantic-type diagnostics (E040).
Defaults to Tolerant (the #339/#527 default-tolerant path); raise to
Error to re-enable strict checking with no manifest registered
(#532).
dialect: DialectT1b compiler dialect: gates brink-extension syntax (blocks, sigil
literals, indexing). Defaults to StrictInk — an authoring-time/
tooling input only, mount-time (CLI flag) in T1b-1; project-file
config is out of scope (docs/t1b-surface-spec.md §1, #368 precedent).
types: Option<TypePolicy>TM-3 typed-mode policy (docs/typed-mode-spec.md §1). None means
“the project never said” — the effective policy is then keyed on the
dialect via resolve_type_policy (issue #1127, ruled 2026-07-19):
Brink → Strict, StrictInk → Gradual (forever — the oracle
corpus is anchored to it). Some(_) is an explicit choice (CLI flag,
brink.toml, editor API) and always wins. Read the effective policy
via AnalysisOptions::type_policy, never this field directly.
Strict requires dialect = Brink (a config error otherwise,
E064) and turns on Unknown/Conflicted-escape errors, the
boundary annotation-firewall exemption, and auto-wires E063
(annotation-vs-inference mismatch) into production. Authoring-time/
tooling input only — never embedded in .inkb, mirroring dialect.
lints: LintPolicyResolved [lints] policy (issue #1160): per-code severity overrides
plus deny-warnings. LintPolicy::default() (empty overrides,
deny_warnings: false) is a no-op — every diagnostic keeps its
brink_ir::DiagnosticCode::severity default, byte-identical to
pre-#1160 behavior. Resolved once, here, via
AnalysisOptions::apply_project_config — read through
effective_severity, never this field directly.
emit_debug_info: boolD6 (docs/debugger-spec.md §1.2/§2, issue #3184): emit the
SectionKind::DebugInfo bytecode-offset → source-range section.
Mount-time/authoring-time input only, mirroring dialect/types —
never embedded in .inkb when false (the default): a
release-exported story never carries this flag’s effect, per the
ship-policy ruling that keeps every release artifact byte-identical
regardless of this field. true for a dev/studio compile or the
CLI’s explicit brink compile --debug-info flag.
conventions: Option<String>brink.toml’s [project] conventions pointer (docs/prose-dialect-spec.md
§3.4), if set: a built-in preset name or a project-relative path to
the project’s conventions module. None means no conventions
module is configured. Consumed by the confinement check (issue
#1844, E169) that requires pattern-claiming @[convention(claims = "…", order = N)] handlers to live in the one file this names — resolving the
pointer against real project/module identity needs brink-db’s
path machinery, so this crate only carries the raw string through,
the same posture Self::types/Self::dialect have toward their
own project-file-authored values. Authoring-time/tooling input
only, mirroring every other AnalysisOptions field — never embedded
in .inkb.
Renamed from elements by issue #2180 (the key predates the split
of @[element] from @[convention], docs/decision-log.md’s
2026-08-03 ruling). brink-project-config::ProjectConfig still
accepts the old [project] elements spelling as a deprecated,
warning-emitting alias — see ProjectConfig::conventions’s own
doc comment — but by the time a ProjectConfig reaches
Self::apply_project_config the two keys have already been
reconciled into that one field, so there is nothing alias-specific
for this crate to do.
A preset-shaped value (issue #1874) is validated by
Self::apply_project_config against the closed built-in-preset
set before it lands here — an unrecognized bare name never
reaches this field (a ConfigWarning is returned instead), the same
“invalid entries never make it into the resolved policy” posture
[lints]’s [validate_lint_code] gate uses. A path-shaped value is
never rejected by that check (see
is_path_shaped_conventions_pointer).
Implementations§
Source§impl AnalysisOptions
impl AnalysisOptions
Sourcepub fn type_policy(&self) -> TypePolicy
pub fn type_policy(&self) -> TypePolicy
The effective types policy for this options set — the one
resolution seam (issue #1127): an explicit Self::types wins;
otherwise the dialect-keyed default from resolve_type_policy.
Sourcepub fn apply_project_config(
&mut self,
config: &ProjectConfig,
dialect_overridden: bool,
types_overridden: bool,
) -> Vec<ConfigWarning>
pub fn apply_project_config( &mut self, config: &ProjectConfig, dialect_overridden: bool, types_overridden: bool, ) -> Vec<ConfigWarning>
Apply a parsed brink.toml ProjectConfig onto these options,
honoring the #1005 precedence rule: explicit API calls / CLI flags
override the file. dialect_overridden/types_overridden tell this
whether the caller already has an explicit value for that field (a CLI
flag the user actually passed, an editor session’s own
set_language_dialect/set_type_policy call, …) — when true, that
field is left untouched regardless of what the file says. The file only
ever supplies a default.
For dialect/types, fields the file doesn’t set are also left
untouched, so self should already carry whatever it would have
without a config file (typically AnalysisOptions::default()).
lints does not follow this rule — see below.
lints/deny-warnings (issue #1160) have their own override
mechanism — Self::apply_lint_overrides, the CLI-flag/editor-API
tier used by brink compile, brink ide, brink-lsp’s
initializationOptions, and the wasm EditorSession — but unlike
dialect/types that tier is applied as a second, separate call
rather than an _overridden parameter here, so this call always
resolves [lints] from config first: the file’s [lints] table
is the sole source of truth for what this call sets on
AnalysisOptions::lints, and it replaces self.lints wholesale
with the policy resolved from
config (a code missing from config.lints, or an absent [lints]
table entirely, resolves to no override for that code; a missing
deny-warnings resolves to false) rather than merging config’s
entries key-by-key into whatever self.lints already held.
This differs from dialect/types’ “unset means untouched” rule
above deliberately (issue #1397): those fields are one-shot,
CLI-flag-style choices where “unset” genuinely means “the file
doesn’t have an opinion, leave whatever’s already resolved alone”.
[lints], in contrast, is a table a long-lived caller (the editor
session re-applies brink.toml on every change; see
brink-web’s EditorSession::apply_parsed_config) re-resolves from
scratch each time it calls this — merge semantics meant a code
deleted from brink.toml (or an editor-supplied config) left its
previously-applied override permanently stuck, since nothing ever
removed it from AnalysisOptions::lints. Replacing wholesale is
safe for every caller: apply_lint_overrides (the CLI/API tier) is
always documented to run after this, on top of whatever it just
resolved, and no caller relies on this call preserving lint state
this one didn’t itself just set — self.lints at call time is
always a fresh AnalysisOptions::default() (CLI, LSP, brink ide,
the editor session’s own throwaway AnalysisOptions, or bevy-brink
via brink-environment::resolve_options); see the Invariant section
below for why every caller constructs fresh rather than reusing a
prior call’s output.
brink-project-config doesn’t know the real DiagnosticCode set
(kept dependency-free, #1234), so it accepts any string key under
[lints] without validation. This is the point that resolves a
key against the real code set (this crate owns DiagnosticCode)
and decides which codes are actually overridable: a key that isn’t a
real code, or names a code whose default severity IS Error
(never reachable through effective_severity’s hard-error
exemption anyway — see its doc comment), is not included in the
replaced AnalysisOptions::lints and instead earns a returned
ConfigWarning, the same “warn, never silently drop” channel
unknown top-level/[project] keys already use. Every call site that
already loops over brink_project_config::parse_str’s own warnings
should loop over these the same way. (Issue #3447: [fix] keys get
the same code-set gate below, via validate_fix_code — [fix] has
no overridability concept of its own, so that gate only rejects
codes the compiler has never heard of.)
Lives here rather than in brink-project-config so that crate needs no
workspace dependencies and can publish standalone (#1234) — it owns the
policy types, this crate owns applying them to its own options.
§Invariant: self must be fresh
[lints] would be safe to apply onto a self mutated by a prior
call — full replace, not merge, is exactly what makes that safe (see
above). dialect/types are not: their “unset means untouched”
rule means whatever self.dialect/self.types already held before
this call would silently survive untouched if config (and the
_overridden flags) don’t set them. No caller relies on that today
— there is no exception. Every production call site starts each call
from a freshly-constructed AnalysisOptions::default():
brink-cli’s brink ide; brink-lsp’s resolve_language_options
(called fresh both from initialize and repeatedly from
Backend::reload_brink_toml on every brink.toml edit — the
repeat-call case this invariant is actually about); brink-web’s
EditorSession::apply_parsed_config, via its own throwaway
AnalysisOptions::default() (it never reuses a mutated self —
dialect/types are applied directly to the session elsewhere, not
through this method); and — the one every mount funnels through —
brink-environment::resolve_options, called fresh inside every
Project::load).
bevy-brink never calls this method directly; it reaches it solely
through resolve_options. Reusing a mutated self would let a
later, unrelated compile silently inherit an earlier one’s resolved
dialect/types whenever its own brink.toml doesn’t set them,
breaking the determinism a caller doing repeat compiles (e.g.
bevy-brink’s InkLoader on every asset (re)load) depends on.
Nothing in this method’s signature enforces starting fresh — it
takes &mut self, so it can’t tell “fresh” apart from “reused”.
This is a documented invariant rather than a compiler-checked one
because enforcing it in the type (e.g. an associated constructor
like fn from_project_config(config, dialect_overridden, types_overridden) -> (Self, Vec<ConfigWarning>) that owns
construction) would mean touching all four production call sites
plus the ~15 brink-analyzer unit tests that call
apply_project_config directly on an already-constructed options
— not because any caller needs &mut self reuse; see
resolve_options/repeat_compiles_do_not_leak_options_across_project_load_calls
in brink-environment for where the fresh-start invariant is
actually pinned end-to-end.
Sourcepub fn apply_lint_overrides(
&mut self,
overrides: &BTreeMap<String, LintLevel>,
deny_warnings: Option<bool>,
) -> Vec<ConfigWarning>
pub fn apply_lint_overrides( &mut self, overrides: &BTreeMap<String, LintLevel>, deny_warnings: Option<bool>, ) -> Vec<ConfigWarning>
Apply explicit CLI/API per-code lint-level overrides on top of
whatever Self::apply_project_config already resolved (the
default, then a discovered brink.toml) — the top of the CLI/API > file > default precedence stack (#1005), completing the “natural
follow-up” Self::apply_project_config’s own doc comment flags:
[lints]/deny-warnings previously had no override source at all
(issue #1373). Call this after apply_project_config, if the
caller applies both — an entry here replaces whatever the file set
for the same code, and deny_warnings: Some(_) replaces the file’s
deny-warnings wholesale, mirroring dialect/types’ own
*_overridden handling above.
Runs every code through the exact same [validate_lint_code] gate
apply_project_config’s [lints] handling uses — a key that isn’t a
real DiagnosticCode, or names a code whose default severity
IS Error, is never merged into Self::lints and instead
earns a returned ConfigWarning on the same “warn, never silently
drop” channel (#1160’s overridability constraint applies identically
to a CLI/API-set code as to a brink.toml-set one).
Trait Implementations§
Source§impl Clone for AnalysisOptions
impl Clone for AnalysisOptions
Source§fn clone(&self) -> AnalysisOptions
fn clone(&self) -> AnalysisOptions
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for AnalysisOptions
impl Debug for AnalysisOptions
Source§impl Default for AnalysisOptions
impl Default for AnalysisOptions
Source§fn default() -> AnalysisOptions
fn default() -> AnalysisOptions
Source§impl<'de> Deserialize<'de> for AnalysisOptions
impl<'de> Deserialize<'de> for AnalysisOptions
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for AnalysisOptions
Source§impl PartialEq for AnalysisOptions
impl PartialEq for AnalysisOptions
Source§impl Serialize for AnalysisOptions
impl Serialize for AnalysisOptions
impl StructuralPartialEq for AnalysisOptions
Auto Trait Implementations§
impl Freeze for AnalysisOptions
impl RefUnwindSafe for AnalysisOptions
impl Send for AnalysisOptions
impl Sync for AnalysisOptions
impl Unpin for AnalysisOptions
impl UnsafeUnpin for AnalysisOptions
impl UnwindSafe for AnalysisOptions
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.