Skip to content

Restore MatchTypeNoCases warning with correct source position#25470

Open
dancewithheart wants to merge 7 commits intoscala:mainfrom
dancewithheart:fix/matchtype-no-cases-warning
Open

Restore MatchTypeNoCases warning with correct source position#25470
dancewithheart wants to merge 7 commits intoscala:mainfrom
dancewithheart:fix/matchtype-no-cases-warning

Conversation

@dancewithheart
Copy link

@dancewithheart dancewithheart commented Mar 9, 2026

Fixes #24753
Fixes #23822

LLM usage

Moderately - used to help navigate the codebase and draft the initial approach.

Testing

Tested locally with:

  • sbt --error "testCompilation 23822"
  • sbt --error "testCompilation 12974"
  • sbt --error "testCompilation i12049"
  • sbt --error "testCompilation matchtype-seq"

Change

Restore emission of MatchTypeNoCases in TypeComparer.matchCases
when match type reduction reaches the no-match branch.

The warning is emitted only when:

  • a real source position exists
  • positions are being read
  • the owner is a term
  • the scrutinee is not an intermediate TypeVar
  • the compiler is in typer
  • no errors have already been reported

This avoids repeated internal warnings while restoring the user-visible diagnostic.

Examples:

  • tests/warn/12974.scala
  • tests/warn/i23822.scala

I'm trying to sign the Scala CLA at : https://contribute.akka.io/cla/scala but ATM I get HTTP 500.

Signed-off-by: Piotr Paradzinski <dancingwithopenheart@gmail.com>
@Gedochao
Copy link
Contributor

Gedochao commented Mar 9, 2026

I also trying to sign the Scala CLA at : https://contribute.akka.io/cla/scala but ATM I get HTTP 500.

It seems there is a bug with the CLA service, as the CLA check seems to be passing.
I think this has been reported before.
cc @SethTisue @lrytz

…n that filters warnings:

- os.exists => only warn when there is a real source position
- Mode.ReadPositions => avoid internal/speculative contexts
- ctx.owner.isTerm => prefer user-facing term-level situations
- !TypeVar => skip unstable intermediate typing states

Signed-off-by: Piotr Paradzinski <dancingwithopenheart@gmail.com>
@dancewithheart
Copy link
Author

Replaced de-duplicate check using Set, with condition:

  • pos.exists => only a real source position
  • Mode.ReadPositions => only when positions are being read (not in internal contexts)
  • ctx.owner.isTerm => only term-level
  • !TypeVar => no intermediate TypeVar states

This solves failing tests for sbt "testCompilation matchtype-seq"

…sTyper && !ctx.reporter.hasErrors

Signed-off-by: Piotr Paradzinski <dancingwithopenheart@gmail.com>
@lrytz
Copy link
Member

lrytz commented Mar 10, 2026

It seems there is a bug with the CLA service, as the CLA check seems to be passing.

Right, I think this was reported before. People see an http 500, but the signature is still recorded. https://contribute.akka.io/contribute/cla/scala/check/dancewithheart

@dancewithheart dancewithheart changed the title WIP: restore MatchTypeNoCases warning on no-match reduction path Restore MatchTypeNoCases warning with correct source position Mar 12, 2026
@dancewithheart dancewithheart marked this pull request as ready for review March 12, 2026 15:45
@Gedochao Gedochao requested a review from bracevac March 16, 2026 07:20
// Emit warn for user-facing term-level typing, and avoid intermediate / redundant reports
val doEmit =
pos.exists
&& ctx.mode.is(Mode.ReadPositions)
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't look right. The mode is used when reading source positions from tasty. When we just compile from source, this will not trigger.
You can see this with sbt "scalac tests/warn/i23822.scala‎ (NO warning) vs. sbt "scalac -Xsemanticdb tests/warn/i23822.scala‎ (shows warning).

Copy link
Author

Choose a reason for hiding this comment

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

Thank you for explanation 🙇‍♂️
Removed this condition - locally tests are passing and warning is emitted with Xsemanticdb and without.

*/
val pos = ctx.source.atSpan(ctx.owner.span)
val isStableScrut = !scrut.isInstanceOf[TypeVar]
val noErrorYet = !ctx.reporter.hasErrors
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this will suppress the warning if there is any other unrelated error in the same file. Maybe drop this?

Copy link
Author

Choose a reason for hiding this comment

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

Removing this condition, breaks tests/neg/i12049.scala. On top of existing errors:

-- [E007] Type Mismatch Error: tests/neg/i12049.scala:14:17 --------------------
14 |val y3: String = ??? : Last[Int *: Int *: Boolean *: String *: EmptyTuple]  // error
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                 Found:    Last[EmptyTuple]
   |                 Required: String
   |
   |                 Note: a match type could not be fully reduced:
   |
   |                   trying to reduce  Last[EmptyTuple]
   |                   failed since selector EmptyTuple
   |                   matches none of the cases
   |
   |                     case _ *: _ *: t => Last[t]
   |                     case t *: EmptyTuple => t
   |
   | longer explanation available when compiling with `-explain`
-- [E007] Type Mismatch Error: tests/neg/i12049.scala:22:20 --------------------
22 |val z3: (A, B, A) = ??? : Reverse[(A, B, A)] // error
   |                    ^^^^^^^^^^^^^^^^^^^^^^^^
   | Found:    Tuple.Concat[Reverse[A *: EmptyTuple.type], (B, A)]
   | Required: (A, B, A)
   |
   | Note: a match type could not be fully reduced:
   |
   |   trying to reduce  Tuple.Concat[Reverse[A *: EmptyTuple.type], (B, A)]
   |   trying to reduce  Reverse[A *: EmptyTuple.type]
   |   failed since selector A *: EmptyTuple.type
   |   matches none of the cases
   |
   |     case t1 *: t2 *: ts => Tuple.Concat[Reverse[ts], (t2, t1)]
   |     case EmptyTuple => EmptyTuple
   |
   | longer explanation available when compiling with `-explain`

there are new warnings enabled by this PR - but they feel redundant:

-- [E184] Type Warning: tests/neg/i12049.scala:14:4 ----------------------------
14 |val y3: String = ??? : Last[Int *: Int *: Boolean *: String *: EmptyTuple]  // error
   |    ^
   |    Match type reduction failed since selector EmptyTuple
   |    matches none of the cases
   |
   |        case _ *: _ *: t => Last[t]
   |        case t *: EmptyTuple => t
-- [E184] Type Warning: tests/neg/i12049.scala:22:4 ----------------------------
22 |val z3: (A, B, A) = ??? : Reverse[(A, B, A)] // error
   |    ^
   |    Match type reduction failed since selector A *: EmptyTuple.type
   |    matches none of the cases
   |
   |        case t1 *: t2 *: ts => Tuple.Concat[Reverse[ts], (t2, t1)]
   |        case EmptyTuple => EmptyTuple

One way would be to update tests/neg/i12049.check, I am investigating.

Copy link
Author

Choose a reason for hiding this comment

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

I removed the hasErrors condition, following the review feedback.

My current understanding is, that to suppress extra warnings in tests/neg/i12049 more information from higher-level typing / reporting paths are needed.

I was able to suppress extra warnings in i12049 when I inspected the stack trace:

  val fromInferredRhs =
    stack.exists(ste =>
      ste.getMethodName == "rhsType$1" ||
      ste.getMethodName == "cookedRhsType$1" ||
      ste.getMethodName == "inferredResultType" ||
      ste.getMethodName == "typedAheadExpr$$anonfun$1" ||
      ste.getMethodName == "typedAheadType$$anonfun$1"
    )

this suggest more information needs to be passed from caller site.

My proposition is to:

Signed-off-by: Piotr Paradzinski <dancingwithopenheart@gmail.com>
Signed-off-by: Piotr Paradzinski <dancingwithopenheart@gmail.com>
@dancewithheart dancewithheart requested a review from bracevac March 17, 2026 10:59
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.

MatchTypeNoCases is no longer emitted Match type reduction does not fail even if selector matches none of the cases

4 participants