Fix 21013 wildcard match types#25885
Draft
bracevac wants to merge 3 commits intoscala:mainfrom
Draft
Conversation
Substituting a wildcard (`?`) for a type parameter of a match type alias is unsound whenever that parameter appears outside the match scrutinee — either in a case pattern (where substitution can make the pattern spuriously match anything), a case body (where the wildcard loses the relationship between multiple occurrences), or the declared upper bound. The exemption for match aliases in `isUnreducibleWild` (added in 6871cff for scala#9999) was too permissive and allowed constructions such as `type M1[K] = Double match { case K => Int }` applied as `M1[?]` to reduce to `Int`, even though `M1[Int]` does not reduce. This is the classic `type U[X] = (X, X); type V = U[?]` unsoundness lifted to match types. Refine the exemption so only parameters used exclusively in the scrutinee are soundly substitutable with a wildcard. The `Reducer` treats `MatchCase` arguments as nested positions so wildcard substitutions in pattern/body positions no longer reduce away the surrounding application, letting `isUnreducibleWild` flag it. Fixes scala#21013
Document the rule that a match type alias applied to a wildcard is legal only when each wildcarded parameter occurs solely in the scrutinee. Mirrors the compiler check added for scala#21013.
The previous commit's `!isMatchAlias` guard still fired on `AppliedType(HKTypeLambda, args)` produced by the reducer, rejecting direct `M[?]` even when the wildcard was sound (param only in the scrutinee). Look up the underlying `HKTypeLambda` from either a `TypeRef` to a `MatchAlias` or a bare `HKTypeLambda` tycon, and reject only when the wildcarded parameter occurs outside the scrutinee. Add tests/pos/i21013.scala exercising direct `M[?]`, bounded wildcards, and wildcards nested in other type constructors.
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.
Fixes #21013
type M[X] = S match { ... }applied to a wildcard was accepted even when the substitution was unsound:6871cff88eexempted match aliases fromisUnreducibleWildwholesale. That's too permissive: substituting?for a match-alias type parameter is only sound when the parameter appears exclusively in the scrutinee. In a pattern, case body, or declared upper bound, it reproduces thetype U[X] = (X, X); type V = U[?]unsoundness.Fix
Reducer(TypeApplications.scala) — treatMatchCasearguments as nested positions so top-levelapplyArgno longer substitutes a wildcard into a pattern or body. UnderMode.AllowLambdaWildcardApplytheAppliedTypeis preserved forisUnreducibleWildto flag.isUnreducibleWild(Types.scala) — narrow the exemption: exempt only when every wildcard argument is passed to a parameter that occurs solely in the scrutinee.Covers both
AppliedType(HKTypeLambda, args)from the reducer andAppliedType(TypeRef, args)from e.g. or-type approximation inTypeOps.Spec
New paragraph in
docs/_spec/03-types.md§Match Types stating the restriction.How much have you relied on LLM-based tools in this contribution?
Extensively
How was the solution tested?
New automated tests (including the issue's reproducer, if applicable)