Repository navigation
Conversation
This was referenced Sep 25, 2026
kasimte
added a commit
to kasimte/kani
that referenced
this pull request
Sep 30, 2026
…king#4865) Contracts on a trait method whose type carries a concrete generic argument — `<CStr as Index<RangeFrom<usize>>>::index`, or a concrete instantiation of a generic self type — failed to resolve with `MissingTraitImpl`. `resolve_ty` returned the definition's identity type (`RangeFrom<usize>` came back as `RangeFrom<Idx>`), so the arguments written in the path were parsed but never applied. This PR applies them, in `resolve_ty`'s `Type::Path` arm, via the new `instantiate_path_args`. ## Verification The tests live in the standard `tests/kani` and `tests/expected` suites (CI runs them); each has a definite outcome: | test (`-Zfunction-contracts`) | expect | |---|---| | `tests/kani/FunctionContracts/generic_argument_instantiation.rs` | **6 targets verify.** A primitive argument resolved before (regression guard); the five generic shapes resolve *only* with this change — a generic argument, a generic self type (associated-type return, `where`-bounded method), a concrete DST self, a generic `impl` at a concrete instantiation, and a type with a lifetime parameter beside a type parameter (lifetime erased). | | `tests/expected/function-contract/generic_arg_unimplemented.rs` | **still fails `MissingTraitImpl`** *(expected-output test — this diagnostic is the pass)* — `<S as Generic<Wrap<u16>>>::generic` is genuinely not implemented, so valid targets resolve without over-resolving invalid ones. | | `tests/expected/function-contract/generic_method_unimplemented.rs` | **still fails `MissingTraitImpl`** *(expected-output test — this diagnostic is the pass)* — a trait method with its own generic parameter (`fn compute<T>`) is out of scope (see below). | Confirmed on nightly-2026-09-22 (Kani 0.68.0, CBMC 6.11.0): all six verify; with the fix reverted, the generic targets fail to resolve while the primitive resolves. The `cross_module_multiple_impls` (7/7), `multiple_inherent_impls` (3/3), and resolver unit (41/41) suites are unchanged. Mechanism: this is the "trait functions with generic parameters" limitation described in [model-checking#1997](model-checking#1997 (comment)). The trait's arguments already reach trait-impl resolution, but each came back uninstantiated from `resolve_ty`, and full `Instance::resolve` cannot match a concrete impl from a free parameter. Making the arguments concrete fixes that; any shape that cannot be resolved (const-generic arguments, omitted defaulted parameters) keeps the old uninstantiated type, so nothing that resolved before changes. No partial-resolution machinery is needed — with concrete arguments, the existing full resolution matches. These are not hypothetical. An iterator adapter's `__iterator_get_unchecked` (a generic self type) is another std-library method of this shape: the Challenge 16 and Challenge 24 submissions ([model-checking/verify-rust-std#549](model-checking/verify-rust-std#549), [model-checking/verify-rust-std#689](model-checking/verify-rust-std#689)) disclose it and fall back to `kani::assume` mirror harnesses. What this change reaches there: closure-free adapters resolve (`Cloned`, `Zip`); `Map`/`Filter` do not, since `fn`/closure types aren't supported by `resolve_ty`. Challenge 24's `<vec::IntoIter<u8> as Iterator>::__iterator_get_unchecked` resolves only with the allocator written out (`IntoIter<u8, std::alloc::Global>`, which needs `allocator_api`): omitted trailing parameters with declared defaults are not filled and keep the uninstantiated type. Related to model-checking#1997 — this handles a type carrying concrete generic arguments: a generic trait argument, or a generic self type instantiated to concrete types, against a concrete or generic `impl`. A trait method with its own generic parameter still fails to resolve — that parameter is not part of the path, so nothing here binds it. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
wodex1nhaoIeng
pushed a commit
to wodex1nhaoIeng/kani
that referenced
this pull request
Oct 2, 2026
…el-checking#4915) A `proof_for_contract` target that omits a trailing generic parameter with a declared default failed to resolve with `MissingTraitImpl`. For example `<Vec<u8> as Trait>::m`, or the natural spelling of `<vec::IntoIter<u8> as Iterator>::__iterator_get_unchecked`, a target in the Challenge 24 submission (model-checking/verify-rust-std#689); both omit the allocator parameter. The parameter-count check kept the uninstantiated type instead of filling the default. This PR fills an omitted trailing parameter from its declared default, instantiated with the arguments so far, matching what rustc does for omitted arguments. The logic lives in `default_type_arg`, called from `instantiate_path_args`'s substitution loop. A path written with no generic arguments at all (a bare `Wrapper` for `struct Wrapper<T = u8>`) is treated as an empty argument list, so an all-defaulted type resolves too. Parenthesized arguments keep the uninstantiated type. ## Verification | test (`-Zfunction-contracts`) | expect | |---|---| | `tests/kani/FunctionContracts/generic_default_argument_fill.rs` | **5 targets verify.** A std container default (`Vec<u8>` fills `A = Global`); a sibling impl with a distinct postcondition (`Vec<u16>`), so each harness only verifies if resolution picks its own impl; a default referencing an earlier parameter (`Pair<T, U = T>` at `Pair<u8>` fills `U = u8`); the explicit spelling (`Vec<u16, std::alloc::Global>`) unchanged; and an all-defaulted type written with no argument list (`AllDefault` for `struct AllDefault<T = u8>`) fills `T = u8`. | | `tests/expected/function-contract/generic_default_missing_required.rs` | **still fails `MissingTraitImpl`** *(expected-output test; this diagnostic is the pass)*. `NoDefault<u8>` omits a parameter with no default, so only declared defaults are filled. | | `tests/expected/function-contract/generic_default_missing_bare.rs` | **still fails `MissingTraitImpl`** *(expected-output test; this diagnostic is the pass)*. `NoDefaultBare` written with no argument list omits a parameter with no default, so the no-arguments path still keeps the uninstantiated type. | | `tests/expected/function-contract/generic_default_const_param.rs` | **still fails `MissingTraitImpl`** *(expected-output test; this diagnostic is the pass)*. `WithConst<u8>` omits a defaulted **const** parameter; only defaulted type parameters are filled, so the const default is not filled and the target keeps the uninstantiated type. | The four original targets were confirmed locally when this PR was first submitted (`generic_default_argument_fill` 4/4, the two negatives failing `MissingTraitImpl`, resolver suites unchanged at `generic_argument_instantiation` 6, `cross_module_multiple_impls` 7, `multiple_inherent_impls` 3). This revision adds the no-arguments case (`check_all_parameters_defaulted`) and the `generic_default_missing_bare` negative; CI runs the full suite on the pinned toolchain. Scope: type parameters only. A const parameter (with or without a default), and any argument that cannot be resolved, keep the uninstantiated type, as before. Defaults are instantiated structurally (no normalization), matching how `resolve_ty` already hands `tcx.type_of` results forward. Resolves model-checking#4914. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
feliperodri
requested changes
Nov 3, 2026
feliperodri
left a comment
Member
There was a problem hiding this comment.
Challenge 24 requires: "The verification must be unbounded---it must hold for slices of arbitrary length." That requirement is final. A Kani solution will only be accepted if it is unbounded in the input size for every required function. This PR still verifies at least part of the challenge with bounded harnesses (kani::unwind bounds and/or fixed-size inputs), so I'm requesting changes until every required function is verified without a bound on the input size.
This branch has not been deployed
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.
Towards #285. Kani harnesses for Challenge 24: Verify the safety of
Vecfunctions part 2.47 harnesses cover all 22 listed functions —
Vec::IntoIter(14) and thespec_*helpers it routes through (spec_extend,spec_from_iter/_nested,spec_from_elem,from_elem,extract_if). Each runs the real shipped body (no#[cfg(kani)]rewrite, noassume(false)on a real branch), at symbolic length where tractable, and asserts the observable effect, not just absence of UB. All pass viascripts/run-kani.shat Kani6ce55b9/ CBMC 6.11, with 29kani::coverwitnesses. Additive, +976/−0 across 7 files.advance_by(k)→Okiffk <= len;foldvisits exactlylen)__iterator_get_uncheckedsafety contractproof_for_contractatu8/Globaland[u8; 3]/Global(Upstream below)try_foldshort-circuits in aDropvariant (a double-drop would be caught);extract_if::nextwrites through the real pointersame_allocationinvariant the havoced heap-pointer loops need)TGeneric
T(#734). On the size/align-branch axis the ruling asks about:IntoIter's 14 functions consume an already-builtVecand have nosize_of/align_of-gated branch (nothing to reach). The one such branch in thespec_*callees (min_non_zero_cap) is reached at thesize == 1arm (Vec<u8>); its larger arms are reached only by growing throughextend_desugared— a Challenge 23 function, not one of this challenge's 22, and object-bits-walled on its realloc path besides — disclosed in-code. Because element access is typed pointer arithmetic, representative types span the layout properties it depends on:u8,()(ZST),#[repr(align(16))],[u8; 3](odd stride), and aDroptoken.Upstream Kani.
__iterator_get_uncheckedlives in a generic trait impl; naming the allocator explicitly resolves it as aproof_for_contracttarget via our merged fix kani#4865 (instantiate path generic arguments during type resolution). The harnesses verify its shipped#[requires(i < self.len())]+kani::modifies(self)contract directly.Beyond fresh iterators, 13 harnesses re-check the surface from arbitrary reachable states — a symbolic number of elements consumed from each end via
advance_by/advance_back_by, results checked against a pre-conversion snapshot.Residual bounds, each noted in-code:
extract_if::nextand the defaultfrom_iterexceed--object-bits 12at larger sizes; theDrop-token harnesses fix size 4 (per-element-identical obligations); element-by-element growth routes through Challenge 23'sextend_desugared/extend_with, not claimed here.Verify with
scripts/run-kani.sh(standard-Zflags,--object-bits 12), scoped to thevec::{into_iter,extract_if,spec_*}::verifyharnesses; 47 verified, 0 failures.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.