Skip to main content

AnalysisOptions

Struct AnalysisOptions 

Source
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: ExternalCheckSeverity

Severity policy for manifest-driven external diagnostics.

§semantic_type_check: SemanticTypeDiagnosticSeverity

Severity 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: Dialect

T1b 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): BrinkStrict, StrictInkGradual (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: LintPolicy

Resolved [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: bool

D6 (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/typesnever 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

Source

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.

Source

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 selfdialect/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.

Source

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

Source§

fn clone(&self) -> AnalysisOptions

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AnalysisOptions

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for AnalysisOptions

Source§

fn default() -> AnalysisOptions

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for AnalysisOptions

Source§

fn deserialize<__D>( __deserializer: __D, ) -> Result<AnalysisOptions, <__D as Deserializer<'de>>::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for AnalysisOptions

Source§

impl PartialEq for AnalysisOptions

Source§

fn eq(&self, other: &AnalysisOptions) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for AnalysisOptions

Source§

fn serialize<__S>( &self, __serializer: __S, ) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for AnalysisOptions

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Lookup<T> for T

Source§

fn into_owned(self) -> T

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more