Skip to content

Describe toolchain provider and macro contracts - #940

Draft
tamird wants to merge 74 commits into
bazelbuild:mainfrom
tamird:type-contracts
Draft

tamird wants to merge 74 commits into
bazelbuild:mainfrom
tamird:type-contracts

Conversation

@tamird

@tamird tamird commented Oct 16, 2026 •

Copy link
Copy Markdown

Add colocated .bzli interfaces 1 for toolchain configuration helpers, toolchain providers, variable descriptors, legacy conversion, argument formatting, provider collection, and the tool and tool-map macros. The interface syntax is experimental. The provider declarations describe complete values produced by these implementations; partially populated direct provider construction remains outside the contract.

The configuration helpers preserve recursive flag groups, nullable fields, and fixed type-name discriminators. ActionConfigInfo also accepts the legacy config_name argument. List validation passes the existing list type tag directly instead of allocating empty witness lists.

The interface for LEGACY_FILE_GROUPS describes the eight file-group names and the action labels collected under each name. The C++ binary implementation returns a list[ProviderInstance] so test runners can append their own providers to it. Provider collection uses typed target accessors, including Target.files for normalized default outputs. Legacy conversion and collection annotate the mutable accumulator fields while preserving ordering. Formatting error paths return an empty placeholder after the injected test callback records an error, so an unrelated operation on None does not hide the intended failure; native fail still terminates.

The tool macros check their fixed attributes and forward canonical common-attribute schemas supplied by sty's native rule declarations. The executable variant also accepts binary attributes. Tool-map contracts preserve prebound string and Label key types. The tool's src attribute is required before its implementation indexes the target.

C++ autoconfiguration checks the dispatcher, the shared helpers, and the Unix implementation. The shared interface derives accepted environment values from Bazel's repository context. Unix configuration reports a missing compiler or Darwin libtool and omits unavailable optional programs from the generated tool map. The Windows entry point has a signature for dispatcher calls; its body remains outside this selection.

The private documentation helper forwards the keywords declared by the native documentation rule. Both BUILD packages that use it are checked with the helper.

The variable implementation checks the leaf, element, and struct variants of its recursive descriptor dictionaries. Its factories and lookup share the descriptor types carried by VariableInfo. A scoped suppression records the type erased by JSON decoding across the private rule boundary.

CompilationArtifactsInfo exposes four fields, each of which may be None. The companion checks its initializer against that contract. This includes #967, which fixes header-only construction.

The public interfaces are exported in stubs.toml. sty also discovers companions beside the selected sources, including private test helpers. The workspace uses the matching implementation and interfaces from bazelbuild/bazel-skylib#641.

The configuration and compatibility extensions declare when they return metadata and when they return None. The draft includes #960, which switches the compatibility proxy to the public Bazel Features flag.

The configuration requires complete function annotations and fully static inferred values, rejects explicit Any, bare generics, unsound assignments or returns, blanket ignores, possibly unresolved references, possibly missing attributes, and division by zero, and enables strict generic narrowing.

The GitHub Actions job 2 gates the selected implementations and publishes advisory findings for every tracked .bzl file. It checks the cross-repository fixture as Bazel installs it. Missing inputs and incomplete checks fail the job in both modes. The native_cc_common re-export has one scoped exception for private native members absent from Bazel's type metadata; callers still check the members they use.

Prepared by OpenAI's Codex on behalf of @tamird.

@tamird
tamird marked this pull request as draft October 16, 2026 15:20
@tamird tamird changed the title Type toolchain configuration providers Describe toolchain provider and macro contracts Oct 18, 2026
@tamird
tamird force-pushed the type-contracts branch 5 times, most recently from 1b8a555 to d3af802 Compare October 22, 2026 06:19
tamird added 19 commits October 23, 2026 11:18
Describe the configuration helpers and their complete provider results
in a colocated sty interface. Preserve nominal provider identities,
recursive flag groups, nullable fields, and fixed type_name values.
Map the toolchain configuration implementations to their colocated
bzli interfaces so sty can check them using the repository configuration.
Run the declared implementations through the pinned sty action on pull
requests and main. Keep diagnostics available as workflow artifacts while
the experimental checker runs as an advisory step.
Use the checker revision with protobuf's retained linker-array
sentinel, allowing its Bazel build to complete on Linux.
Describe the remaining validation helpers and require parameter and
return annotations, complete generic arguments, and sound annotated
assignments and returns. Reject explicit Any in these interfaces.

Use the checker revision that implements these policies. Native
provider/ctx signatures and empty type exemplars still prevent enabling
the non-static-type rule.
The configuration helpers allocated empty lists only to recover their
runtime type name through _check_same_type. Call _check_right_type with
that name directly. This preserves validation and error messages while
avoiding an unconstrained list element type in the helper calls.
Declare the optional compiler attribute read by profile correction
flags. Its presence guard permits contexts without that field, while a
supplied compiler must be a string. Enable the remaining static-type
check for the toolchain helper implementation and its interface.

with ';' will be ignored, and an empty message aborts the commit. ; ;
Date:      Fri Oct 16 23:48:33 2026 +0200 ; ; interactive rebase in
progress; onto 60e8a51 ; Last commands done (4 commands done): ;    pick
f8475ae # Check list types without allocating witnesses ;    reword
eec4d89 # Require static toolchain helper types ; Next command to do (1
remaining command): ;    pick 6ddc086 # Update sty for static native
contracts ; You are currently editing a commit while rebasing branch
'codex/toolchain-type-contracts' on '60e8a51'. ; ; Changes to be
committed: ;       modified:   cc/cc_toolchain_config_lib.bzli ;
modified:   sty.toml ;
Select the checker revision that infers registered callback contexts
and preserves Bazel collection, provider, and attribute types. Its
interface validation also checks generated callable values against
their declared signatures.
The type-check configuration left generic narrowing in its gradual
mode. Enable strict narrowing so runtime container checks retain opaque
element types and mutations require evidence of the element type.
Use the checker revision with native callable proofs and generic
inference fixes for the selected source interfaces.
The injectable fail callback records errors and returns during unit
tests. Unsupported build settings and targets without a single file
then continued with None, causing an unrelated join or membership error.
Return an empty placeholder after reporting those failures so the test
wrapper can observe the original message. Native fail still terminates
before the placeholder is reached.
The implementation indexed the source target's DefaultInfo even when the
macro's default None was forwarded. Make the keyword and the underlying
rule attribute required so missing inputs fail before that provider
lookup. Existing calls supplying a source retain their behavior.
Describe the provider values used by toolchain collection, formatting,
and legacy conversion in source-owned interfaces. Use typed target
accessors for collectors, retain mutable accumulator element types, and
copy tool inputs once before adding the executable.

Check the tool and tool-map macros with native common-attribute schemas.
Export the interfaces in a stub package and consume Skylib's provider
contracts from its reviewed draft revision.

Require the selected implementation checks to pass in CI, audit transitive
loads, and reject blanket ignores, possibly unresolved references, and
division by zero alongside the existing static-type requirements.
The generated API table still displayed None as the src default after
cc_tool began requiring it. Regenerate the table from the source
declaration.
The tool-map macro only iterates and indexes its input mapping. A union
key annotation rejected prebound string-keyed maps because Mapping keys
are invariant.

Bind the key type separately within the accepted string-or-Label domain
so callers retain their existing mapping types.
Reject accesses to attributes that are not present on every accepted
value. The checker now models optional download-result fields, so this
rule also covers native values whose fields depend on runtime inputs or
the host version.

Update the pinned sty revision to include these native contracts and the
corresponding diagnostics.
Pin sty to a revision that selects the source of each configured
local interface. Let sty.toml define the checked implementations
while preserving the transitive load audit.
Update the pinned checker and reject unused, invalid, or unscoped
suppressions so comments cannot silently disable the configured checks.
Describe the string and mapping contracts beside their implementations.
Select both files in the enforcing job so the declared contracts and
their bodies are checked together.
The manifest identified its own source as version 0.0.0, which would
reject released modules with a different Bazel-resolved version. Omit
the source table so the interfaces bind to their own Bazel repository.

Select that manifest locally so implementation checks and downstream
users consume the same mappings.
Describe shared C++ configuration helpers and check their direct
repository-rule consumer. Keep generic fallback and environment
contracts in the exported interface, and add simple signatures to the
source. Mark the fatal helper as non-returning and remove unreachable
code.

Use a checker that understands WORKSPACE toolchain registration and
generic provider-key lookup, so the wider existing selection remains
enforced. The which contract remains nullable for non-null fallbacks
because a narrower overload cannot yet be validated.
VariableInfo erases its descriptor to object, so consumers cannot
check nested fields or the lookup implementation. Describe the leaf,
element, and struct variants and validate variables.bzl against that
contract.

Expose the macro's existing actions keyword so its other forwarded
arguments use Bazel's common rule schema. Isolate the private rule's
JSON round trip in a typed decoder; its writer establishes the
invariant that deserialization cannot prove.

Pin the checker revision that preserves recursive dictionary types
through the lookup loop.
A C++ rule can pass framework include paths into a compilation context
and return that context in CcInfo. Both arguments had unknown types, so
callers could not be checked across these API boundaries.

Record their existing domains on the Starlark implementations selected
by Bazel 9.
Describe collection inputs with Collection while preserving their
depset, selector and nullable alternatives. Refresh the advisory sty
pin and its Skylib contracts together.

Keep source comments compatible with supported Bazel versions, and
link native context, metadata and depset annotation gaps at their
use sites. Generic source signatures also require type parameters.
tamird added 20 commits October 24, 2026 08:24
Check the rules and providers reexported from the Bazel compatibility
repository, along with the shared library hint provider. Select the test
feature names, macro tags, and platform goldens used by the toolchain tests.
The generators build two distinct kinds of provider. Describe their
platforms, tool paths, and name collections so callers can distinguish
feature lists from action configuration lists. Give the empty flag
arms the same element type as their nonempty alternatives.
Declare the archive lookup as (name, path) or (None, None), and
describe the attributes used to generate the imported library. Include
the interface in the cc source filegroup.
cc_configure has no parameters. Give the public macro the same signature so an extra argument fails at the entry point.
Declare the two public macros and include their interface in the rules_cc package.
Declare the provider results of the two rule implementations and the string paths used by their test expectations. The rule declarations already supply their implementation contexts.
The public flag already describes when the proxy must load the rules_cc implementations. Use it so the proxy does not duplicate the prerelease version boundary or import private version helpers.
Declare the results of the configuration extension and compatibility repository callbacks. Their native registrations supply the context for checking the implementations. Export the companion alongside the WORKSPACE helper and include the extension source in the advisory check.
Describe the fields the initializer stores and the include paths it
collects from its input providers. Only a readable strict_include is
required, so both ObjcInfo and compatible structs can supply those
paths.

Ship the companion with its source and check the initializer in the
existing advisory workflow.
Declare the generator's DefaultInfo result and the label inputs accepted
by the comparison macro. Check the test package so its BUILD calls and
the implementation are covered together.
Keep the required compiler and Darwin libtool errors at the lookup, and
collect the four optional tool paths without emitting an entry for a
missing executable. Declare the tool and flag helpers next to their
implementation and select the Unix configuration in the advisory check.
The package-private helper forwards its arguments to starlark_doc_extract
when that rule exists. Derive its keywords from the native declaration
and check the two BUILD files that use it.
CompilationArtifactsInfo accepts headers independently of sources. When
only headers are supplied, srcs is None and looking for compilable files
fails. Search an empty sequence in that case so the headers can be
returned without an archive.
Compilable sources need an archive factory. Report the missing argument
when such sources are present, instead of calling archive() on None.
The provider always has four fields, but their values depend on which
inputs the caller supplies. Describe these fields and check the
initializer against the same contract.
Check every tracked .bzl in a separate advisory pass alongside the
existing strict selection. Use the target that loads the cross-repository
fixture so its imports resolve in the installed repository.

The checker also exposes partial type metadata in Bazel's bundled C++
namespace. Scope the exception to its re-export; callers still check
projected members and unused exceptions remain errors.
The test rule appends its selected runner's providers to the list it
receives from cc_binary_impl. Inferring the list from its first four
entries rejects valid launcher and runner providers.

Declare the common provider instance type at the list literal. Pin the
checker that accepts native and user-defined providers here while
rejecting a structured value such as ctx.outputs.
The compatibility macro uses the names in LEGACY_FILE_GROUPS as label
attributes when it calls cc_toolchain. A string-keyed dictionary loses
the distinction between the eight generated labels and common arguments
such as tags.

Declare the eight action lists beside their definition and register the
interface for consumers. Pin the checker that tracks the remaining
keywords after the macro removes visibility with dict.pop.
Use sty's finite attribute names when checking calls to the native C++
toolchain rule. This lets the checker reject a misspelled keyword after
the macro combines generated file-group labels with caller arguments.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant