Skip to content

Conversation

@dolio
Copy link
Contributor

@dolio dolio commented Jan 6, 2026

This PR fixes some backwards subtyping checks for patterns.

The code was systematically checking that

pattern type <: scrutinee type

However, this is actually wrong. If the scrutinee type is a subtype of the pattern type, that is fine, because you could promote the scrutinee to the type of the pattern. This matters e.g. when matching on something with type

 forall x. T

against patterns of type T[x := U]. Doing so would fail previously.

I think that the pattern language was too limited previously to cause any actual problems. Attempts to do something erroneous would run into the fact that leaves of the pattern checking problem would always be checks like:

T <: a
a <: T

These both solve identically, by instantiating the variable a to the more elaborate type T. There were also a few obstacles that happened to save us, like Request being invariant in the ability list. So, the previous implementation ended up behaving as would pattern matching with equality checks rather than subtyping checks.

I also needed to tweak the pattern coverage checker, because it wasn't set up to handle treating forall x. T as having patterns as T, so it would complain that you aren't actually covering everything.

Transcripts pass, but I'll probably do some more testing tomorrow, and add a regression test.

Fixes #6018

The code was systematically checking that

  pattern type <: scrutinee type

However, this is actually wrong. If the scrutinee type is a _subtype_ of
the pattern type, that is fine, because you could promote the scrutinee to
the type of the pattern. This matters e.g. when matching on something with
type

   forall x. T

against patterns of type T[x := U]. Doing so would fail previously.

I think that the pattern language was too limited previously to cause any
actual problems. Attempts to do something erroneous would run into the fact
that leaves of the pattern checking problem would always be checks like:

  T <: a, a <: T

These both solve identically, by instantiating the variable a to the more
elaborate type T. There were also a few obstacles that happened to save us,
like `Request` being invariant in the ability list. So, the previous
implementation ended up behaving as would pattern matching with equality
checks rather than subtyping checks.
@dolio dolio requested review from aryairani and pchiusano January 6, 2026 00:55
Copy link
Member

@pchiusano pchiusano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch

@aryairani
Copy link
Contributor

@dolio With the new transcript, would you say this is ready to merge?

@dolio
Copy link
Contributor Author

dolio commented Jan 7, 2026

Yeah, I think so.

There was one case I was concerned about, because I didn't change it (no subtype call). But I think it was actually correct already.

@aryairani aryairani merged commit 8dc4354 into trunk Jan 8, 2026
31 checks passed
@aryairani aryairani deleted the fix/pattern-checking branch January 8, 2026 00:36
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.

Tuple (,) syntax doesn't work with existentials

3 participants