Autoharness: per-parameter and trait-impl-derived generic instantiation - #4706
Open
tautschnig wants to merge 4 commits into
Open
Autoharness: per-parameter and trait-impl-derived generic instantiation#4706tautschnig wants to merge 4 commits into
tautschnig wants to merge 4 commits into
Conversation
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>
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>
Extend the generic-instantiation search in three ways, found by evaluating autoharness on the top-100 crates.io crates, where ~8,700 functions were skipped because no candidate type satisfied their trait bounds: 1. Widen the primitive candidate list with u8, i64, u64, f64 and f32; float candidates alone unlock the numerous Float/FloatCore-bounded functions in num-traits and its dependents. 2. Search per-parameter candidate combinations (after the cheap uniform pass), so functions whose parameters need different types, e.g. fn cast<T: Float, U: PrimInt>, are instantiated. The search is capped at 256 trait-solver queries per function. 3. Derive additional per-parameter candidates from the concrete implementations of the traits each parameter is bound by (capped at 16 per parameter), so parameters bound by crate-local traits can be instantiated with the crate's own types implementing them. 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
Stacked on #4679 (first commit; review only the last commit).
The top-100 crates.io evaluation (#3832) showed ~8,700 functions skipped as "Generic Function: no candidate type satisfies the function's trait bounds". This PR extends the instantiation search in three ways:
u8,i64,u64,f64,f32. The float candidates alone unlock the numerousFloat/FloatCore-bounded functions in num-traits and its dependents.fn cast<T: Float, U: PrimInt>) are instantiated. Capped at 256 trait-solver queries per function.Measured impact (with
--bounded-arguments,-j 16): num-traits 75 generic skips → 0 (2,107 → 2,154 harnesses; every public function now harnessed); serde_json 594 → 276; syn 167 → 41.Testing
cargo_autoharness_genericsgains cases for each capability: a float-only trait bound (halve::<f64>), a crate-local trait satisfied only by a struct (frob_it::<Widget>), and parameters needing different types (mixed::<f64, Widget>);needs_exotic(trait with no impls) remains skipped with the updated message. Full script-based autoharness suite passes.Towards #3832.
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.