Skip to content

Match query type variables against concrete types#488

Merged
thomashoneyman merged 2 commits into
masterfrom
type-search-variables
Jul 6, 2026
Merged

Match query type variables against concrete types#488
thomashoneyman merged 2 commits into
masterfrom
type-search-variables

Conversation

@thomashoneyman

@thomashoneyman thomashoneyman commented Jul 6, 2026

Copy link
Copy Markdown
Member

Fixes #395. Supersedes #396 — the approach is @klntsky's; this builds on that patch and addresses the ranking comments raised in that PR.

Problem

A type search for a -> HTMLElement returns no concrete results, while _ -> HTMLElement matches functions like HTMLAnchorElement -> HTMLElement. compareTypes had no case for a query-side type variable against a concrete type, so such comparisons fell through to Nothing.

The approach in 396

#396 made a query variable match any concrete type, but this had two related issues:

  • Query a -> a would score Int -> String identically to identity — repeated variables lose their consistency constraint, because the typeVarPenalty machinery never sees var-to-concrete matches.
  • Query a -> b would rank Int -> Int (score 0) strictly above forall x. x -> x (score 3) — an arbitrary concrete function beating the closest polymorphic match.

The blocker at the time was penalty headroom, but since then Pursuit has added it control: calculate scales structural scores by 10, leaving room for penalties smaller than one structural unit.

This change

A query variable matches any concrete type, as wildcards do, except:

  • each instantiation charges a flat penalty of 1, so results that unify with the query directly always rank first, and instantiation stays far cheaper than generalization (10+);
  • the instantiation is recorded as a (variable, rendered type) pair and fed through the existing typeVarPenalty, so repeated query variables must be instantiated consistently.

The resulting gradient for query a -> a: x -> x (0) < Int -> Int (2) < Int -> String (3). For #395's query, forall e. (...) => e -> HTMLElement ranks at 0 and concrete HTMLAnchorElement -> HTMLElement right behind at 1.

A type search for `a -> HTMLElement` previously returned no concrete
results where `_ -> HTMLElement` matched functions like
`HTMLAnchorElement -> HTMLElement`, because compareTypes had no case for
a query-side type variable against a concrete type (#395).

Query variables now match any concrete type, as wildcards do, except
that each instantiation charges a penalty of 1 - less than a single
unit of structural mismatch (10) - so results that unify with the query
directly still rank first. Each instantiation is also recorded against
the variable's name and fed through typeVarPenalty, so repeated query
variables must be instantiated consistently: for the query `a -> a`,
`Int -> Int` ranks above `Int -> String`.

Existing comparisons are unaffected: no previously-matching clause
changed, so current rankings only gain new, lower-ranked results.

Also fixes the compareTypes doc examples, which had a typo (parseType
s2 twice) and a stale expected score predating the 10x score scaling.

Based on #396 by @klntsky.
@thomashoneyman thomashoneyman merged commit c0e65c4 into master Jul 6, 2026
1 check passed
@thomashoneyman thomashoneyman deleted the type-search-variables branch July 6, 2026 13:44
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.

a -> HTMLElement and _ -> HTMLElement have different results

1 participant