Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport "Approximate MatchTypes with lub of case bodies, if non-recursive" to LTS #20972

Merged
merged 7 commits into from
Jul 3, 2024

Conversation

WojciechMazur
Copy link
Contributor

Backports #19761 to the LTS branch.

PR submitted by the release tooling.
[skip ci]

@WojciechMazur WojciechMazur changed the base branch from lts-19866 to lts-19838 July 2, 2024 21:49
Base automatically changed from lts-19838 to lts-3.3 July 3, 2024 08:37
@WojciechMazur
Copy link
Contributor Author

No regressions detected in the community build up to lts-19921.

Reference

@WojciechMazur WojciechMazur merged commit 8380eb7 into lts-3.3 Jul 3, 2024
19 checks passed
@WojciechMazur WojciechMazur deleted the lts-19761 branch July 3, 2024 08:37
@WojciechMazur
Copy link
Contributor Author

Due to problems with OpenCB infrastructure, we have not received information about regression in the https://github.com/fingo/spata - a match types heavy library which fails to build since 3.4.2-RC1-bin-20240229-9fe0111-NIGHTLY. It fails due to different reasons at different revisions of Scala compiler
Here's the reproducer of the failing code

import scala.deriving.Mirror
import scala.annotation.unused
import scala.compiletime.{constValue, erasedValue, *}

type Key = String & Singleton

trait StringParser[+A]

private inline def getLabels[T <: Tuple]: List[String] = inline erasedValue[T] match
  case _: EmptyTuple => Nil
  case _: (t *: ts) => constValue[t].toString :: getLabels[ts]

private inline def getTypes[T <: Tuple]: List[StringParser[?]] = inline erasedValue[T] match
  case _: EmptyTuple => Nil
  case _: (t *: ts) => summonInline[StringParser[t]] :: getTypes[ts]

import TypedRecord.*
final class TypedRecord[KS <: Tuple, VS <: Tuple](
  keys: KS,
  values: VS,
)(using @unused ev1: Tuple.Size[KS] =:= Tuple.Size[VS], @unused ev2: Tuple.Union[KS] <:< Key):

  inline def to[P <: Product](using
    m: Mirror.ProductOf[P],
    ev: Tuple.Union[Tuple.Zip[m.MirroredElemLabels, m.MirroredElemTypes]] <:< Tuple.Union[Tuple.Zip[KS, VS]]
  ): P =
    val labels = getLabels[m.MirroredElemLabels]
    val vals = labels.map(l => get(l, keys, values))
    m.fromProduct(Tuple.fromArray(vals.toArray)) // error here

  private def get[K <: Key, KS <: Tuple, VS <: Tuple](key: K, keys: KS, values: VS): Select[K, KS, VS] =
    val selected = (keys: @unchecked) match
      case `key` *: _ => getH(values)
      case _ *: tk => getT(key, tk, values)
    selected.asInstanceOf[Select[K, KS, VS]]

  private def getT[K <: Key, KS <: Tuple, VS <: Tuple](key: K, keys: KS, values: VS): SelectT[K, KS, VS] =
    (values: @unchecked) match
      case vs: (h *: t) => get(key, keys, vs.tail[h *: t])

  private def getH[VS <: Tuple](values: VS): SelectH[VS] =
    (values: @unchecked) match
      case vs: *:[h, t] => vs.head[h *: t]

object TypedRecord:
  type Select[K <: Key, KS <: Tuple, VS <: Tuple] = KS match
    case K *: ? => SelectH[VS]
    case h *: t => SelectT[K, t, VS]

  type SelectT[K <: Key, KS <: Tuple, VS <: Tuple] = VS match
    case ? *: tv => Select[K, KS, tv]

  type SelectH[VS <: Tuple] = VS match
    case h *: ? => h

This PR (both original and backport) made it fail with

-- [E172] Type Error: /Users/wmazur/projects/lts-scripts/test.scala:54:46 ------
54 |    m.fromProduct(Tuple.fromArray(vals.toArray))
   |                                              ^
   |No ClassTag available for T
   |
   |where:    T is a type variable with constraint >: TypedRecord.SelectH[VS] | TypedRecord.SelectT[String, t, VS]

The code can be tested using nightly version 3.3.4-RC1-bin-20240703-4126175-NIGHTLY

Before that change, the toArray was inferred to be toArray[Any] which even though it allowed for compilation it was probably incorrect.

Keeping this change would fix the LTS regression (since 3.3.1) #19710 but it would introduce new one

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.

2 participants