Repository navigation
Infer return-only generic type arguments from context - #13
Merged
mitchellnemitz merged 8 commits intoJul 24, 2026
Merged
Conversation
Thread the contextual expected type into generic call checking and bind still-unbound type parameters by unifying the declared return type against it. Covers FR-001/FR-002/FR-004a/FR-005/SC-001. Also updates the pre-existing TestGenericCannotInferReturnOnly (generics_test.go): its `let xs: int[] = make()` case is now exactly the scenario this feature makes inferable, so the case is changed to a discarded call (no context) to keep asserting the still-uninferable no-context case; not in the plan's named file list but required to avoid a regression in the full package run. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Locks FR-004b..e and SC-002/SC-003/SC-004. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Locks FR-002/FR-003/FR-005/FR-006/FR-009/FR-010 and SC-007/SC-008/SC-009/SC-010. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix plan test-fixture defects surfaced at grounding (feature behavior is
correct; only the assertions were wrong):
- ExplicitArgsWinOverContext: array type renders as [int]/[string], not
int[]/string[]; align the expected substring.
- WantWithTypeVar{Errors,ExplicitOK}: 'wrap' is a reserved builtin
(builtins.go); rename the fixture fn to 'wraplist'.
- AnnotationStillRequired: a let without a type annotation is rejected at
parse time (before Check), so assert parser.Parse errors rather than
checking info.Errors via check() (which fatals on parse error).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Byte-identity (SC-005), numeric monomorphization + violation (SC-006), comparable erasure + violation (SC-014), FR-008. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Return-only inference across positions, identical under dash/ash/bash/zsh. SC-005 (runtime), SC-011, SC-013, SI-001. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update the generics inference note and CHANGELOG. FR-011. SC-011 audit: grep for identifier[Type](...) explicit-type-argument call sites across all *.wisp files outside docs/ found ~20 sites (identity[int], empty_list[int], add[float]/add[int], box.identity[int]/box.empty[string], json.decode[int|float|bool|string]), all confined to testdata/golden/ (including the call_type_args* and call_type_args_qualified fixtures, left untouched) and examples/ function declarations; every hit lives in a surface already compiled by go test/the golden suite, so no over-broad simplification was applied and a regression would have failed Task 7. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…turn Adversarial implementation review (Significant, lens A+B): SC-005 requires byte-identity for every SC-001..004 position, but array-element had only a type-check test and the golden fixture covers dict-value (not array-element); the per-position codegen comment was inaccurate. Add direct inferred-vs-explicit byte-identity cases for array-element and dict-value and correct the comment. Also close the SC-010 Minor: assert parameter and return-type annotations stay grammar-mandatory (parse errors), not just the let case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mitchellnemitz
deleted the
impl-2026-07-24-context-directed-type-inference
branch
July 24, 2026 16:55
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.
Summary
A generic function call now infers the type parameters its value arguments leave unbound from the call site's expected type. A return-only type parameter no longer has to be restated as an explicit type argument:
This is a type-checker-only change. The compiled shell is byte-identical to the explicit-type-argument form, so no runtime or codegen behavior changes; the only difference is that programs which previously required explicit type arguments now also compile without them.
How it works
The checker already computes an expected type and threads it to the
let/final/return/assignment/array-literal/dict-literal positions. The one place that discarded it was the call-expression case inexprType. This forwards that expected type through the call chain intocheckGenericUserCall, and after value arguments have bound what they can (before the cannot-infer error), unifies the callee's declared return type against the expected type to bind any still-unbound type parameter.Precedence holds: value arguments bind first and always win; an explicit type-argument list disables context inference entirely; an expected type that itself carries an unresolved type variable is not concrete and does not drive inference. A context type that contradicts a value-argument binding reuses the existing unify-conflict error rather than a new error kind.
Inference positions
let/final binding, return, concretely-typed call argument, assignment RHS, and array-element / dict-value. Field-assignment and index-assignment RHS also infer, because those handlers already thread the target type as context; that behavior is locked by tests rather than special-cased away.
Boundaries (unchanged)
Variable, parameter, and return-type annotations stay mandatory. An unpinned type parameter is still an error (no defaulting). A nested call whose enclosing parameter is itself an unbound type variable, e.g.
identity(empty_list()), still needs explicit type arguments.Tests
gofmt,go vet, andgo test ./...clean; thebuild-testandgoldenCI jobs pass locally under act.