diff --git a/build.sbt b/build.sbt index c863baf2..36156f0e 100644 --- a/build.sbt +++ b/build.sbt @@ -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" @@ -37,7 +37,7 @@ inThisBuild(Def.settings( Developer("sjrd", "Sébastien Doeraene", "sjrdoeraene@gmail.com", url("https://github.com/sjrd/")), Developer("bishabosha", "Jamie Thompson", "bishbashboshjt@gmail.com", 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) )) @@ -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 diff --git a/tasty-query/shared/src/main/scala/tastyquery/Trees.scala b/tasty-query/shared/src/main/scala/tastyquery/Trees.scala index 28b3d1cf..8158f020 100644 --- a/tasty-query/shared/src/main/scala/tastyquery/Trees.scala +++ b/tasty-query/shared/src/main/scala/tastyquery/Trees.scala @@ -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 { ... }`. diff --git a/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TastyFormat.scala b/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TastyFormat.scala index fa230afb..05b82938 100644 --- a/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TastyFormat.scala +++ b/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TastyFormat.scala @@ -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 diff --git a/tasty-query/shared/src/test/scala/tastyquery/PositionSuite.scala b/tasty-query/shared/src/test/scala/tastyquery/PositionSuite.scala index 651edf05..c9540772 100644 --- a/tasty-query/shared/src/test/scala/tastyquery/PositionSuite.scala +++ b/tasty-query/shared/src/test/scala/tastyquery/PositionSuite.scala @@ -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 ) ) @@ -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" ) ) } @@ -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" ) diff --git a/tasty-query/shared/src/test/scala/tastyquery/ReadTreeSuite.scala b/tasty-query/shared/src/test/scala/tastyquery/ReadTreeSuite.scala index 43802be4..bbe4c29f 100644 --- a/tasty-query/shared/src/test/scala/tastyquery/ReadTreeSuite.scala +++ b/tasty-query/shared/src/test/scala/tastyquery/ReadTreeSuite.scala @@ -631,6 +631,9 @@ 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( @@ -638,15 +641,15 @@ class ReadTreeSuite extends RestrictedUnpicklingSuite { 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 => @@ -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( diff --git a/tasty-query/shared/src/test/scala/tastyquery/TestUtils.scala b/tasty-query/shared/src/test/scala/tastyquery/TestUtils.scala index afe96d7a..7c6cfa11 100644 --- a/tasty-query/shared/src/test/scala/tastyquery/TestUtils.scala +++ b/tasty-query/shared/src/test/scala/tastyquery/TestUtils.scala @@ -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 diff --git a/tasty-query/shared/src/test/scala/tastyquery/TypeSuite.scala b/tasty-query/shared/src/test/scala/tastyquery/TypeSuite.scala index 6a4c47f3..d93cc273 100644 --- a/tasty-query/shared/src/test/scala/tastyquery/TypeSuite.scala +++ b/tasty-query/shared/src/test/scala/tastyquery/TypeSuite.scala @@ -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", diff --git a/test-sources/src/main/scala/simple_trees/AccessModifiers.scala b/test-sources/src/main/scala/simple_trees/AccessModifiers.scala index cc3be1f3..5ef7824b 100644 --- a/test-sources/src/main/scala/simple_trees/AccessModifiers.scala +++ b/test-sources/src/main/scala/simple_trees/AccessModifiers.scala @@ -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, diff --git a/test-sources/src/main/scala/simple_trees/AnyMethods.scala b/test-sources/src/main/scala/simple_trees/AnyMethods.scala index 6d66375f..78b539df 100644 --- a/test-sources/src/main/scala/simple_trees/AnyMethods.scala +++ b/test-sources/src/main/scala/simple_trees/AnyMethods.scala @@ -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 diff --git a/test-sources/src/main/scala/simple_trees/Match.scala b/test-sources/src/main/scala/simple_trees/Match.scala index 9826069a..44823785 100644 --- a/test-sources/src/main/scala/simple_trees/Match.scala +++ b/test-sources/src/main/scala/simple_trees/Match.scala @@ -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 } diff --git a/test-sources/src/main/scala/simple_trees/RecursiveMatchType.scala b/test-sources/src/main/scala/simple_trees/RecursiveMatchType.scala index 78c02b67..cb5a86b3 100644 --- a/test-sources/src/main/scala/simple_trees/RecursiveMatchType.scala +++ b/test-sources/src/main/scala/simple_trees/RecursiveMatchType.scala @@ -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 diff --git a/test-sources/src/main/scala/simple_trees/RefinedTypeTree.scala b/test-sources/src/main/scala/simple_trees/RefinedTypeTree.scala index dedb6da0..c650f201 100644 --- a/test-sources/src/main/scala/simple_trees/RefinedTypeTree.scala +++ b/test-sources/src/main/scala/simple_trees/RefinedTypeTree.scala @@ -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 } } diff --git a/test-sources/src/main/scala/simple_trees/TypeRefIn.scala b/test-sources/src/main/scala/simple_trees/TypeRefIn.scala index 08acf188..6273e92a 100644 --- a/test-sources/src/main/scala/simple_trees/TypeRefIn.scala +++ b/test-sources/src/main/scala/simple_trees/TypeRefIn.scala @@ -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 = () @@ -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) } diff --git a/test-sources/src/main/scala/simple_trees/Uninitialized.scala b/test-sources/src/main/scala/simple_trees/Uninitialized.scala index 094aaead..68744271 100644 --- a/test-sources/src/main/scala/simple_trees/Uninitialized.scala +++ b/test-sources/src/main/scala/simple_trees/Uninitialized.scala @@ -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 diff --git a/test-sources/src/main/scala/simple_trees/ValueClass.scala b/test-sources/src/main/scala/simple_trees/ValueClass.scala index 1ac1947e..444a0978 100644 --- a/test-sources/src/main/scala/simple_trees/ValueClass.scala +++ b/test-sources/src/main/scala/simple_trees/ValueClass.scala @@ -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 } diff --git a/test-sources/src/main/scala/simple_trees/WildcardTypeApplication.scala b/test-sources/src/main/scala/simple_trees/WildcardTypeApplication.scala index 38c6f933..d679fbe3 100644 --- a/test-sources/src/main/scala/simple_trees/WildcardTypeApplication.scala +++ b/test-sources/src/main/scala/simple_trees/WildcardTypeApplication.scala @@ -2,4 +2,4 @@ package simple_trees class GenericWithTypeBound[T <: AnyKind] -class WildcardTypeApplication(anyList: List[_]) extends GenericWithTypeBound[_] +class WildcardTypeApplication(anyList: List[?]) extends GenericWithTypeBound[?]