Autoharness: support generic functions - #4679
Open
tautschnig wants to merge 3 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds support for generating automatic harnesses for generic functions by selecting a single monomorphic instantiation per function (based on a fixed primitive candidate list and trait-bound satisfaction via the trait solver), and updates related metadata, docs, and script-based tests to reflect the new behavior.
Changes:
- Instantiate generic functions for
autoharnessusing primitive candidates and trait-solver checking; erase lifetimes and keep skipping const generics/unsatisfiable bounds. - Fix contract-harness metadata to store the definition-level target function name (to match contract metadata lookup behavior).
- Add/refresh script-based tests and documentation for generic-function autoharness behavior and output.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/script-based-pre/cargo_autoharness_include/src/lib.rs | Updates include test source comment to reflect generic instantiation behavior. |
| tests/script-based-pre/cargo_autoharness_include/include.expected | Updates expected output to include instantiated generic function verification. |
| tests/script-based-pre/cargo_autoharness_generics/src/lib.rs | Adds new script-based test crate covering generic instantiation cases and edge cases. |
| tests/script-based-pre/cargo_autoharness_generics/generics.sh | Adds script to run cargo kani autoharness with contracts enabled for the new test. |
| tests/script-based-pre/cargo_autoharness_generics/generics.expected | Adds expected summary lines for generic instantiation successes/failure and skips. |
| tests/script-based-pre/cargo_autoharness_generics/config.yml | Registers the new script-based test (expects failure exit code due to intentional bug). |
| tests/script-based-pre/cargo_autoharness_generics/Cargo.toml | Adds manifest for the new test crate. |
| tests/script-based-pre/cargo_autoharness_filter/src/lib.rs | Adjusts filter test inputs to include a generic function now expected to be harnessed. |
| tests/script-based-pre/cargo_autoharness_filter/filter.expected | Updates expected output counts and entries to include instantiated generic function. |
| tests/script-based-pre/cargo_autoharness_exclude/src/lib.rs | Updates exclude test source comment to reflect generic instantiation behavior. |
| tests/script-based-pre/cargo_autoharness_exclude/exclude.expected | Updates expected output to include instantiated generic function verification. |
| kani-compiler/src/main.rs | Adds rustc_infer / rustc_trait_selection extern crates required for trait-solver usage. |
| kani-compiler/src/kani_middle/metadata.rs | Switches contract harness metadata to use definition-level target function names. |
| kani-compiler/src/kani_middle/codegen_units.rs | Implements generic instantiation candidate selection and predicate checking for autoharness eligibility. |
| docs/src/reference/experimental/autoharness.md | Documents the new “single-instantiation” behavior and its underapproximation implications. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+481
to
+485
| if let Ok(instance) = Instance::resolve(def, &args) | ||
| && instance.has_body() | ||
| { | ||
| return Some(instance); | ||
| } |
Previously, autoharness skipped all generic functions. Now, it generates a harness for a single monomorphic instantiation: each type parameter is substituted with the first candidate from a fixed list of primitive types (i32, u32, usize, bool, char) such that all of the function's trait bounds are satisfied, checked with the trait solver (rustc_trait_selection::ObligationCtxt). Lifetime parameters are erased. Functions whose bounds no candidate satisfies, or with const generic parameters, are still skipped as 'Generic Function'. The generated harness's name reflects the chosen instantiation (e.g. foo::<i32>), making explicit that verification covers only that instantiation; the documentation spells out this underapproximation. Functions with any number of type, lifetime, and (unsupported) const parameters are handled, including methods of generic impl blocks, impl-Trait arguments, and functions with contracts. For contract harnesses, harness metadata now stores the definition-level name of the target function rather than the instantiated one, since gen_contracts_metadata matches it against definition-level ContractedFunction names. This addresses the 'Generics' item of the automatic harness generation tracking issue, the last unchecked entry together with the invariants and pointers work. Towards model-checking#3832 Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Rather than the single 'Generic Function' skip reason, attach a detail explaining what prevented instantiation: const generic parameters, or that no candidate type satisfies the function's trait bounds. This makes the skipped-functions table actionable and allows corpus evaluations to classify the generic-function gap precisely. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
tautschnig
force-pushed
the
autoharness-generics
branch
from
July 29, 2026 00:37
525b08a to
52aceef
Compare
Instantiate usize const generic parameters (by far the most common case, e.g. array lengths) with the value 2, alongside the existing type-parameter instantiation; the summary table shows the chosen value as part of the instantiated name (e.g. with_const::<2>). Non-usize const parameters are still skipped, now with a precise reason; the check consults the internal generics since the public identity arguments do not carry the parameter's type. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Autoharness now generates harnesses for generic functions. For each generic function, it verifies a single monomorphic instantiation: every type parameter is substituted with the first candidate from a fixed list of primitive types (
i32,u32,usize,bool,char) such that all of the function's trait bounds are satisfied — checked properly with the trait solver (rustc_trait_selection::ObligationCtxt) — and lifetime parameters are erased. Functions whose bounds no candidate satisfies (e.g. bounds on user traits with no primitive impls) and functions with const generic parameters are still skipped with the existing "Generic Function" reason.This handles arbitrary numbers of generic parameters, methods of generic impl blocks (whose impl-level parameters are instantiated too),
impl Traitargument position (anonymous type parameters), and generic functions with contracts. For contract harnesses, the harness metadata now stores the definition-level name of the target function rather than the instantiated one, sincegen_contracts_metadatamatchestarget_fnagainst definition-levelContractedFunctionnames (this previously had no observable effect because generic functions never reached that code path).Design note on soundness of the reported result: verifying
foo::<i32>is an underapproximation offoo's behaviors for all instantiations. The summary table makes this explicit by displaying the instantiated name (foo::<i32>), and the documentation spells out that a successful result covers only the chosen instantiation. Verifying one instantiation per function (rather than a set) keeps verification cost proportional to crate size; extending this to user-configurable instantiation sets is possible follow-up work.Testing
New script-based test
cargo_autoharness_genericscovering: unbounded and bounded type parameters, bound-driven candidate selection (impl Into<u64> + Copycorrectly skipsi32and picksu32), multiple type parameters, lifetimes, methods of generic impl blocks, a generic function with a contract (verified asproof_for_contract), a genuine bug found at the chosen instantiation (arithmetic overflow), and graceful skipping of unsatisfiable bounds and const generics.Updated
cargo_autoharness_filter/include/excludetests, whose generic example functions are now instantiated and verified instead of skipped.Manually verified no regressions in all
autoharnessandautoderivescript-based tests andkani-compilerunit tests.Note: the two functions previously used to exercise multi-parameter generics in a prototype branch ICE'd the compiler ("type parameter
U/#1out of range"); both are covered by the new test and verify correctly.Towards #3832 (ticks the "Generics" box, the last unchecked entry together with #4677 and #4678).
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.