Skip to content

Conversation

@Definisi
Copy link

@Definisi Definisi commented Dec 9, 2025

When calling addIndex(filter) where:

  • addIndex has type <A, B, C>(op: ((value: A) -> B, array: {A}) -> {C}) -> ...
  • filter has type <A, K>(predicate: (value: A) -> boolean, tbl: {[K]: A}) -> {A}

The type checker incorrectly reports:

No valid instantiation could be inferred for generic type parameter A.
It was expected to be at least: A and at most: A & C but these types are not compatible with one another.

This happens because the generics A, B, C from addIndex appear in the expected type's signature, and when checking if filter matches, the solver treats them as the same generics as filter's own A, causing a name collision.

Solution

The fix instantiates generics from the calling function with fresh types before performing subtyping when the expected argument type is a function type containing those generics. This ensures that generics from the outer scope don't conflict with generics from the actual function type being checked.

Specifically, in ConstraintSolver::tryDispatch for FunctionCallConstraint, when checking argument types with pushTypeInto, we now:

  1. Detect if the expected type is a function type containing generics from the calling function
  2. Instantiate those generics with fresh types (using freshType and freshTypePack)
  3. Use the instantiated type for subtyping checks

This prevents generic name collisions and allows correct type inference.

…efore subtyping

When checking if a function argument matches an expected function type
that contains generics from the calling function, instantiate those
generics with fresh types before performing subtyping. This prevents
generic name conflicts that lead to incompatible bounds errors.

For example, when calling addIndex(filter) where addIndex expects
op: ((value: A) -> B, array: {A}) -> {C} and filter has type
<A, K>(...), the generics A, B, C from addIndex are now instantiated
with fresh types before checking if filter matches, avoiding the
GenericBoundsMismatch error.
When instantiating generic packs in expected function types, ensure
freshTypePack is called with Polarity::Mixed to prevent assertion
failure in Generalization.cpp when checking isKnown(params.polarity).

Fixes the crash in thread_is_a_type test case.
When pushing expected types into function arguments, we should only
instantiate the calling function's generics with fresh types when the
argument is a lambda with its own generics. This prevents losing the
connection between generics and return types when the argument doesn't
have generics.

Fixes regression in infer_generic_function_function_argument_2 test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant