Skip to content

Commit

Permalink
Merge pull request #437 from sjrd/scala-3.4.0
Browse files Browse the repository at this point in the history
Upgrade to Scala 3.4.0 and support its TASTy format.
  • Loading branch information
bishabosha authored Feb 20, 2024
2 parents ce0fdb4 + cc6115e commit a85f200
Show file tree
Hide file tree
Showing 16 changed files with 84 additions and 77 deletions.
7 changes: 4 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import sbt.internal.util.ManagedLogger

import org.scalajs.jsenv.nodejs.NodeJSEnv

val usedScalaCompiler = "3.3.1"
val usedScalaCompiler = "3.4.0"
val usedTastyRelease = usedScalaCompiler
val scala2Version = "2.13.12"

Expand Down Expand Up @@ -37,7 +37,7 @@ inThisBuild(Def.settings(
Developer("sjrd", "Sébastien Doeraene", "[email protected]", url("https://github.com/sjrd/")),
Developer("bishabosha", "Jamie Thompson", "[email protected]", url("https://github.com/bishabosha")),
),
versionPolicyIntention := Compatibility.BinaryAndSourceCompatible,
versionPolicyIntention := Compatibility.BinaryCompatible,
// Ignore dependencies to internal modules whose version is like `1.2.3+4...` (see https://github.com/scalacenter/sbt-version-policy#how-to-integrate-with-sbt-dynver)
versionPolicyIgnoredInternalDependencyVersions := Some("^\\d+\\.\\d+\\.\\d+\\+\\d+".r)
))
Expand Down Expand Up @@ -139,7 +139,8 @@ lazy val tastyQuery =
)
},

tastyMiMaPreviousArtifacts := mimaPreviousArtifacts.value,
// Temporarily disabled until we have a published version of tasty-query that can handle 3.4.x.
//tastyMiMaPreviousArtifacts := mimaPreviousArtifacts.value,
tastyMiMaConfig ~= { prev =>
import tastymima.intf._
prev
Expand Down
37 changes: 24 additions & 13 deletions tasty-query/shared/src/main/scala/tastyquery/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -527,21 +527,32 @@ object Trees {
tpt.toType

case None =>
val methodType = meth.tpe.widenTermRef match
case mt: MethodType if !mt.resultType.isInstanceOf[MethodicType] =>
mt
case mt =>
throw InvalidProgramStructureException(s"Unexpected type for the `meth` part of a Lambda: $mt")

val paramCount = methodType.paramNames.size
val functionNTypeRef = defn.FunctionNClass(paramCount).staticRef

if methodType.isResultDependent then
val parent = functionNTypeRef.appliedTo(List.fill(paramCount + 1)(defn.AnyType))
TermRefinement(parent, isStable = false, nme.m_apply, methodType)
else functionNTypeRef.appliedTo(methodType.paramTypes :+ methodType.resultType.asInstanceOf[Type])
convertMethodTypeToFunctionType(meth.tpe.widenTermRef)
end calculateType

private def convertMethodTypeToFunctionType(tpe: TermType)(using Context): Type =
tpe match
case tpe: MethodType if tpe.resultType.isInstanceOf[Type] =>
val paramCount = tpe.paramNames.size
val functionNTypeRef = defn.FunctionNClass(paramCount).staticRef

if tpe.isResultDependent then
val parent = functionNTypeRef.appliedTo(List.fill(paramCount + 1)(defn.AnyType))
TermRefinement(parent, isStable = false, nme.m_apply, tpe)
else functionNTypeRef.appliedTo(tpe.paramTypes :+ tpe.resultType.asInstanceOf[Type])

case tpe: PolyType if tpe.resultType.isInstanceOf[MethodType] =>
val polyFunctionClass = defn.PolyFunctionClass.getOrElse {
throw InvalidProgramStructureException(
s"Found a polymorphic Lambda but PolyFunction is not on the classpath"
)
}
TermRefinement(polyFunctionClass.staticRef, isStable = false, nme.m_apply, tpe)

case _ =>
throw InvalidProgramStructureException(s"Unexpected type for the `meth` part of a Lambda: ${tpe.showBasic}")
end convertMethodTypeToFunctionType

/** The class symbol of the SAM type of this lambda.
*
* A `Lambda` can be considered as an anonymous class of the form `new tpt { ... }`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ private[tasties] object TastyFormat:
* compatibility, but remains backwards compatible, with all
* preceeding `MinorVersion`.
*/
final val MinorVersion: Int = 3
final val MinorVersion: Int = 4

/** Natural Number. The `ExperimentalVersion` allows for
* experimentation with changes to TASTy without committing
Expand Down
10 changes: 5 additions & 5 deletions tasty-query/shared/src/test/scala/tastyquery/PositionSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ class PositionSuite extends RestrictedUnpicklingSuite {
| case _ => -x
| }""".stripMargin,
"""xs match
| case List(elems: _*) => 0
| case _ => 1""".stripMargin
| case List(elems*) => 0
| case _ => 1""".stripMargin
)
)

Expand All @@ -132,8 +132,8 @@ class PositionSuite extends RestrictedUnpicklingSuite {
"case 3 | 4 | 5 if x < 5 => 0",
"case _ if (x % 2 == 0) => x / 2",
"case _ => -x",
"case List(elems: _*) => 0",
"case _ => 1"
"case List(elems*) => 0",
"case _ => 1"
)
)
}
Expand All @@ -151,7 +151,7 @@ class PositionSuite extends RestrictedUnpicklingSuite {
"(x: Int) => x + 1",
"() => ()",
"T] => T => T", // TODO Improve this
"T] => (x: T) => x", // TODO Improve this
"[T] => (x: T) => x",
"(x: Any) => x.type",
"x => x"
)
Expand Down
58 changes: 18 additions & 40 deletions tasty-query/shared/src/test/scala/tastyquery/ReadTreeSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -631,22 +631,25 @@ class ReadTreeSuite extends RestrictedUnpicklingSuite {
val test1Def = findTree(tree) { case test1Def @ DefDef(SimpleName("test1"), _, _, _, _) =>
test1Def
}
val matchTree = findTree(test1Def) { case mt: Match =>
mt
}

val forExpressionMatch1: StructureCheck = {
case CaseDef(
Unapply(
TypeApply(Select(Ident(SimpleName("Tuple2")), SignedName(SimpleName("unapply"), _, _)), _),
Nil,
List(
Bind(i, WildcardPattern(TypeRefInternal(_, SimpleTypeName("Int"))), _),
Bind(SimpleName("i"), WildcardPattern(TypeRefInternal(_, SimpleTypeName("Int"))), _),
WildcardPattern(TypeRefInternal(_, SimpleTypeName("String")))
)
),
None,
Literal(Constant(true))
_
) =>
}
assert(containsSubtree(forExpressionMatch1)(clue(test1Def)))
assert(containsSubtree(forExpressionMatch1)(clue(matchTree)))
}

testUnpickle("singletonType", "simple_trees.SingletonType") { tree =>
Expand Down Expand Up @@ -959,50 +962,25 @@ class ReadTreeSuite extends RestrictedUnpicklingSuite {
Some(
Block(
List(
ClassDef(
_,
Template(
_,
List(
Apply(Select(New(TypeWrapper(_)), _), List()),
TypeWrapper(TypeRefInternal(_, SimpleTypeName("PolyFunction")))
),
None,
List(
DefDef(
SimpleName("apply"),
List(
Right(List(TypeParam(SimpleTypeName("T"), _, _))),
Left(List(ValDef(SimpleName("x"), TypeIdent(SimpleTypeName("T")), None, _)))
),
TypeIdent(SimpleTypeName("T")),
Some(Ident(SimpleName("x"))),
_
)
)
DefDef(
SimpleName("$anonfun"),
List(
Right(List(TypeParam(SimpleTypeName("T"), _, _))),
Left(List(ValDef(SimpleName("x"), _, _, _)))
),
_
_,
_,
defSym
)
),
Typed(
Apply(Select(New(TypeIdent(_)), _), List()),
TypeWrapper(
ty.TermRefinement(
TypeRefInternal(_, SimpleTypeName("PolyFunction")),
SimpleName("apply"),
polyType @ ty.PolyType(
List(SimpleTypeName("T") -> _),
ty.MethodType(List(SimpleName("x") -> (tref1: TypeParamRef)), tref2: TypeParamRef)
)
)
)
)
Lambda(defRef @ Ident(SimpleName("$anonfun")), None)
)
),
_
) if Seq(tref1, tref2).forall(tref => (tref.binder eq polyType) && tref.paramNum == 0) =>
) if defRef.symbol == defSym =>
}
assert(containsSubtree(polyIDMatch)(clue(tree)))
val polyIDVal = findValDefTree(tree, termName("polyID"))
assert(containsSubtree(polyIDMatch)(clue(polyIDVal)))

val dependentIDMatch: StructureCheck = {
case ValDef(
Expand Down
6 changes: 6 additions & 0 deletions tasty-query/shared/src/test/scala/tastyquery/TestUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ object TestUtils:
}
end findLocalValDef

def findValDefTree(body: Tree, name: TermName): ValDef =
findTree(body) {
case vd: ValDef if vd.name == name => vd
}
end findValDefTree

def findTree[A](body: Tree)(test: PartialFunction[Tree, A]): A =
object finder extends TreeTraverser:
var result: Option[A] = None
Expand Down
3 changes: 2 additions & 1 deletion tasty-query/shared/src/test/scala/tastyquery/TypeSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2728,7 +2728,8 @@ class TypeSuite extends UnrestrictedUnpicklingSuite {
testTypeApply("testAsInstanceOfInt", nme.m_asInstanceOf, _.isRef(defn.IntClass))
testTypeApply("testAsInstanceOfProduct", nme.m_asInstanceOf, _.isRef(ProductClass))

testTypeApply("testTypeCast", termName("$asInstanceOf$"), _.isRef(defn.IntClass))
// FIXME #436: the type test should be _.widenTermRef.isRef(defn.IntClass)
testTypeApply("testTypeCast", termName("$asInstanceOf$"), _.isInstanceOf[TermRef])

testApplyTypeApply(
"testGetClassAny",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package simple_trees

import scala.annotation.nowarn

@nowarn("msg=The \\[this\\] qualifier will be deprecated")
class AccessModifiers(
localParam: Int,
private[this] val privateThisParam: Int,
Expand Down
4 changes: 2 additions & 2 deletions test-sources/src/main/scala/simple_trees/AnyMethods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ class AnyMethods:

class Bag extends scala.reflect.Selectable

def testTypeCast(bag: Bag { val m: Int }): Any = bag.m // bag.selectDynamic("m").$asInstanceOf$[Int]
def testTypeCast(bag: Bag { val m: Int }): Any = bag.m // bag.selectDynamic("m").$asInstanceOf$[bag.m.type]

def testGetClassAny(x: Any): Any = x.getClass()
def testGetClassProduct(x: Product): Class[_ <: Product] = x.getClass()
def testGetClassProduct(x: Product): Class[? <: Product] = x.getClass()
def testGetClassInt(x: Int): Class[Int] = x.getClass() // nonsensical, but what can we do?
end AnyMethods
4 changes: 2 additions & 2 deletions test-sources/src/main/scala/simple_trees/Match.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ class Match {
}

def g(xs: Seq[Int]): Int = xs match
case List(elems: _*) => 0
case _ => 1
case List(elems*) => 0
case _ => 1
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ type RecursiveMatchType[A <: Tuple] <: Tuple = A match
object RecursiveMatchType:
inline def rec[A <: Tuple](a: A): RecursiveMatchType[A] =
inline a match
case b: (hd *: tl) => b.head *: rec(b.tail)
case b: (hd *: tl) => headOf(b) *: rec(tailOf(b))
case _: EmptyTuple => EmptyTuple

def headOf[H, T <: Tuple](t: H *: T): H = t.head
def tailOf[H, T <: Tuple](t: H *: T): T = t.tail
end RecursiveMatchType

// must be in a separate TASTy file to trigger issue #401
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ class RefinedTypeTree {

def polyTypeRefinement(c: C { type Poly[X] = List[(X, X)] }) = c

// With an additional 'with'
// With an additional '&'

trait AndTypeA
trait AndTypeB extends AndTypeA

def andType(): AndTypeA with AndTypeB { def foo: String } =
def andType(): (AndTypeA & AndTypeB) { def foo: String } =
new AndTypeA with AndTypeB { def foo: String = toString }
}
10 changes: 5 additions & 5 deletions test-sources/src/main/scala/simple_trees/TypeRefIn.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ package simple_trees
class TypeRefIn {
def withArray[U](arr: Array[U]): Unit = ()

def withArrayOfSubtype[T](arr: Array[_ <: T]): Unit = withArray(arr)
def withArrayOfSubtype[T](arr: Array[? <: T]): Unit = withArray(arr)

def withArrayAnyRef[U <: AnyRef](arr: Array[U]): Unit = ()

def withArrayOfSubtypeAnyRef[T <: AnyRef](arr: Array[_ <: T]): Unit = withArrayAnyRef(arr)
def withArrayOfSubtypeAnyRef[T <: AnyRef](arr: Array[? <: T]): Unit = withArrayAnyRef(arr)

def withArrayAnyVal[U <: AnyVal](arr: Array[U]): Unit = ()

def withArrayOfSubtypeAnyVal[T <: AnyVal](arr: Array[_ <: T]): Unit = withArrayAnyVal(arr)
def withArrayOfSubtypeAnyVal[T <: AnyVal](arr: Array[? <: T]): Unit = withArrayAnyVal(arr)

def withArrayList[U <: List[?]](arr: Array[U]): Unit = ()

def withArrayOfSubtypeList[T <: List[?]](arr: Array[_ <: T]): Unit = withArrayList(arr)
def withArrayOfSubtypeList[T <: List[?]](arr: Array[? <: T]): Unit = withArrayList(arr)

def withArrayExactAny(array: Array[Any]): Unit = ()

Expand All @@ -25,5 +25,5 @@ class TypeRefIn {

def withListOfSubtypeOfInt[T <: Int](x: List[T]): Unit = ()

def withListOfSubtypeOfSubtypeOfInt[T <: Int](x: List[_ <: T]): Unit = withListOfSubtypeOfInt(x)
def withListOfSubtypeOfSubtypeOfInt[T <: Int](x: List[? <: T]): Unit = withListOfSubtypeOfInt(x)
}
4 changes: 4 additions & 0 deletions test-sources/src/main/scala/simple_trees/Uninitialized.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package simple_trees

import scala.annotation.nowarn

import scala.compiletime.uninitialized as renamedUninitialized

abstract class Uninitialized:
var uninitializedRHS: Product = scala.compiletime.uninitialized
var renamedUninitializedRHS: String = renamedUninitialized

@nowarn("msg=uninitialized")
var wildcardRHS: Int = _

var abstractVar: Int // confidence check: an abstract var is marked Deferred
Expand Down
2 changes: 1 addition & 1 deletion test-sources/src/main/scala/simple_trees/ValueClass.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package simple_trees

final class ValueClass(val it: List[_]) extends AnyVal {
final class ValueClass(val it: List[?]) extends AnyVal {
def myLength: Int = it.size
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package simple_trees

class GenericWithTypeBound[T <: AnyKind]

class WildcardTypeApplication(anyList: List[_]) extends GenericWithTypeBound[_]
class WildcardTypeApplication(anyList: List[?]) extends GenericWithTypeBound[?]

0 comments on commit a85f200

Please sign in to comment.