Repository navigation
Generate concrete generic entry signatures - #3911
Draft
Ian Davis (idavis) wants to merge 1 commit into
Draft
Ian Davis (idavis) wants to merge 1 commit into
Ian Davis (idavis) wants to merge 1 commit into
Conversation
Ian Davis (idavis)
added this pull request to stack #3892
October 7, 2026 18:39
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.
Summary
Fixes generated entry points for parameterless generic operations.
Previously, the generated call could omit generic arguments or use the operation body’s result type as the callee type. This left the entry call ill-typed or generic during lowering and monomorphization.
The branch now:
Unit;The branch fixes bugs where automatically generated calls to generic entry operations could:
Main;1. Generated generic entries missing type arguments
A parameterless generic
Mainhas no call arguments from which to infer'T.Previously, the generated call could reference
Mainwith an empty generic-argument list, leaving a reachable generic callable after entry generation.The branch generates the equivalent of
Main<Unit>().2. Generated callees receiving the wrong callable type
The generated callee was previously typed using the operation body’s result type rather than its arrow type.
The callee must have type:
not merely
Int.The branch constructs the concrete callable signature and uses its output type for the call expression.
3. Generic result types remaining unresolved
The result type may itself contain a generic parameter:
The generated entry must have a concrete result type even though execution always fails.
The branch instantiates
'TasUnit, producing a concreteUnit => Unitentry signature.4. Unused generic parameters preventing compilation
A generic parameter can be absent from both the input and output:
There is no source-level type evidence for
'T, but it also has no effect on the operation’s behavior.The branch consistently defaults such parameters to
Unit, allowing QIR generation and execution to proceed.5. Satisfiable bounds not being applied to generated entries
A default is valid only when it satisfies the declared bounds.
Because
Unitsatisfies these bounds, the generated entry can safely instantiate'TasUnit.The branch validates the default through the frontend constraint solver before generating the call.
6. Unsatisfied bounds producing malformed entries
Unitdoes not satisfy every class constraint:Previously, entry generation could leave an unresolved generic call or fail later during specialization.
The branch rejects this entry immediately with a targeted diagnostic explaining that no concrete generated-entry type satisfies
'T’s bounds.7. Dependent bounds being accepted without validation
One type parameter’s bound may depend on another:
Defaulting both parameters to
Unitwould requireUnitto implementIterable[Unit], which it does not.The branch validates the complete default argument vector, including dependent bound payloads, and rejects this entry.
8. The wrong generic parameter being blamed
With multiple parameters, an earlier default may be valid while a later one is not:
UnitsatisfiesEqbut notAdd.The branch attributes the entry-point diagnostic to
'U, the parameter whose default violates its bounds.9. Defaulting an unselected generic
MainAn explicitly attributed entry point should take precedence over an unrelated generic callable named
Main.The invalid
Unitdefault forMain<'T : Add>is irrelevant becauseRunis the selected entry.The branch applies generated-entry defaulting only to the callable actually chosen as the entry point.
10. Overriding type evidence in an explicit entry expression
The special
Unitdefault applies only when the compiler must synthesize an entry call.An explicit call still uses ordinary Q# type inference:
This call provides no argument or expected-result evidence for
'T, so it must still report a type-inference error.The branch does not apply generated-entry defaults to explicit entry expressions.
Conversely, an explicit call with evidence retains that evidence:
This remains an
Intinstantiation rather than inheriting the generated-entryUnitpolicy.11. Generic arguments being lost during HIR-to-FIR lowering
The generated HIR entry may be correct but still fail if its concrete generic arguments disappear during lowering.
The generated call to
Main<Unit>must reach FIR with itsUnitargument intact so monomorphization can create and call the concrete entry specialization.The branch verifies that the argument survives lowering and is consumed by monomorphization.
12. Entry defaults contaminating nested generic calls
Defaulting the entry’s
'TtoUnitmust not overwrite generic arguments inferred for calls inside the entry.The required instantiations are:
Main<Unit>; andIdentity<Int>.The branch preserves each call’s independently inferred generic arguments.
13. Entry defaults contaminating foreign generic calls
The same isolation is required across package boundaries.
The entry defaults to
Main<Unit>, while the library call remainsIdentity<Int>and is specialized in the library package.14. Entry typing errors masking user failures
A valid generic entry that explicitly fails should reach the user’s failure:
Previously, malformed generated typing or incomplete specialization could fail before execution reached this statement.
The branch ensures the generated
Main<Unit>call is concrete, allowing the original failure and its source span to be reported across interpreter and QIR paths.