From 233fd90633975bfdab841a9e82af66c4f1730573 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Mon, 30 Sep 2024 12:48:38 +0200 Subject: [PATCH 1/5] SIP 61 - copy phase and annotation from com-lihaoyi/unroll also copy tests as sbt-scripted tests. Co-authored-by: Jamie Thompson Co-authored-by: Li Haoyi --- compiler/src/dotty/tools/dotc/Compiler.scala | 1 + .../dotty/tools/dotc/core/Definitions.scala | 1 + .../tools/dotc/transform/UnrollDefs.scala | 279 ++++++++++++++++++ library/src/scala/annotation/unroll.scala | 4 + sbt-test/unroll-annot/caseclass/build.sbt | 48 +++ .../project/DottyInjectedPlugin.scala | 12 + sbt-test/unroll-annot/caseclass/test | 14 + .../utils/src/main/scala/TestUtils.scala | 12 + .../v1/src/main/scala/Unrolled.scala | 5 + .../src/main/scala/UnrollTestMain.scala | 24 ++ .../main/scala/UnrollTestScalaSpecific.scala | 20 ++ .../v2/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 29 ++ .../main/scala/UnrollTestScalaSpecific.scala | 21 ++ .../v3/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 35 +++ .../scala/UnrollTestPlatformSpecific.scala | 33 +++ .../main/scala/UnrollTestScalaSpecific.scala | 20 ++ sbt-test/unroll-annot/classMethod/build.sbt | 48 +++ .../project/DottyInjectedPlugin.scala | 12 + sbt-test/unroll-annot/classMethod/test | 14 + .../utils/src/main/scala/TestUtils.scala | 12 + .../v1/src/main/scala/Unrolled.scala | 5 + .../src/main/scala/UnrollTestMain.scala | 9 + .../v2/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 11 + .../v3/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 14 + .../scala/UnrollTestPlatformSpecific.scala | 30 ++ sbt-test/unroll-annot/curriedMethod/build.sbt | 48 +++ .../project/DottyInjectedPlugin.scala | 12 + sbt-test/unroll-annot/curriedMethod/test | 14 + .../utils/src/main/scala/TestUtils.scala | 12 + .../v1/src/main/scala/Unrolled.scala | 5 + .../src/main/scala/UnrollTestMain.scala | 9 + .../v2/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 11 + .../v3/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 14 + .../scala/UnrollTestPlatformSpecific.scala | 29 ++ .../unroll-annot/methodWithImplicit/build.sbt | 48 +++ .../project/DottyInjectedPlugin.scala | 12 + sbt-test/unroll-annot/methodWithImplicit/test | 14 + .../utils/src/main/scala/TestUtils.scala | 12 + .../v1/src/main/scala/Unrolled.scala | 5 + .../src/main/scala/UnrollTestMain.scala | 10 + .../v2/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 12 + .../v3/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 15 + .../scala/UnrollTestPlatformSpecific.scala | 29 ++ sbt-test/unroll-annot/objectMethod/build.sbt | 48 +++ .../project/DottyInjectedPlugin.scala | 12 + sbt-test/unroll-annot/objectMethod/test | 14 + .../utils/src/main/scala/TestUtils.scala | 12 + .../v1/src/main/scala/Unrolled.scala | 6 + .../src/main/scala/UnrollTestMain.scala | 10 + .../v2/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 11 + .../v3/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 14 + .../scala/UnrollTestPlatformSpecific.scala | 48 +++ .../unroll-annot/primaryConstructor/build.sbt | 48 +++ .../project/DottyInjectedPlugin.scala | 12 + sbt-test/unroll-annot/primaryConstructor/test | 14 + .../utils/src/main/scala/TestUtils.scala | 12 + .../v1/src/main/scala/Unrolled.scala | 5 + .../src/main/scala/UnrollTestMain.scala | 10 + .../v2/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 11 + .../v3/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 14 + .../scala/UnrollTestPlatformSpecific.scala | 33 +++ .../secondParameterList/build.sbt | 48 +++ .../project/DottyInjectedPlugin.scala | 12 + .../unroll-annot/secondParameterList/test | 14 + .../utils/src/main/scala/TestUtils.scala | 12 + .../v1/src/main/scala/Unrolled.scala | 5 + .../src/main/scala/UnrollTestMain.scala | 9 + .../v2/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 11 + .../v3/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 14 + .../scala/UnrollTestPlatformSpecific.scala | 30 ++ .../secondaryConstructor/build.sbt | 48 +++ .../project/DottyInjectedPlugin.scala | 12 + .../unroll-annot/secondaryConstructor/test | 14 + .../utils/src/main/scala/TestUtils.scala | 12 + .../v1/src/main/scala/Unrolled.scala | 9 + .../src/main/scala/UnrollTestMain.scala | 10 + .../v2/src/main/scala/Unrolled.scala | 12 + .../src/main/scala/UnrollTestMain.scala | 11 + .../v3/src/main/scala/Unrolled.scala | 12 + .../src/main/scala/UnrollTestMain.scala | 14 + .../scala/UnrollTestPlatformSpecific.scala | 33 +++ sbt-test/unroll-annot/traitMethod/build.sbt | 48 +++ .../project/DottyInjectedPlugin.scala | 12 + sbt-test/unroll-annot/traitMethod/test | 14 + .../utils/src/main/scala/TestUtils.scala | 12 + .../v1/src/main/scala/Unrolled.scala | 7 + .../src/main/scala/UnrollTestMain.scala | 14 + .../v2/src/main/scala/Unrolled.scala | 9 + .../src/main/scala/UnrollTestMain.scala | 16 + .../v3/src/main/scala/Unrolled.scala | 9 + .../src/main/scala/UnrollTestMain.scala | 20 ++ .../scala/UnrollTestPlatformSpecific.scala | 28 ++ tests/run/unroll-caseclass.check | 37 +++ tests/run/unroll-caseclass/Test_4.scala | 11 + tests/run/unroll-caseclass/unrolledV1_1.scala | 61 ++++ tests/run/unroll-caseclass/unrolledV2_2.scala | 55 ++++ tests/run/unroll-caseclass/unrolledV3_3.scala | 95 ++++++ 111 files changed, 2246 insertions(+) create mode 100644 compiler/src/dotty/tools/dotc/transform/UnrollDefs.scala create mode 100644 library/src/scala/annotation/unroll.scala create mode 100644 sbt-test/unroll-annot/caseclass/build.sbt create mode 100644 sbt-test/unroll-annot/caseclass/project/DottyInjectedPlugin.scala create mode 100644 sbt-test/unroll-annot/caseclass/test create mode 100644 sbt-test/unroll-annot/caseclass/utils/src/main/scala/TestUtils.scala create mode 100644 sbt-test/unroll-annot/caseclass/v1/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestScalaSpecific.scala create mode 100644 sbt-test/unroll-annot/caseclass/v2/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestScalaSpecific.scala create mode 100644 sbt-test/unroll-annot/caseclass/v3/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala create mode 100644 sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestScalaSpecific.scala create mode 100644 sbt-test/unroll-annot/classMethod/build.sbt create mode 100644 sbt-test/unroll-annot/classMethod/project/DottyInjectedPlugin.scala create mode 100644 sbt-test/unroll-annot/classMethod/test create mode 100644 sbt-test/unroll-annot/classMethod/utils/src/main/scala/TestUtils.scala create mode 100644 sbt-test/unroll-annot/classMethod/v1/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/classMethod/v1_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/classMethod/v2/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/classMethod/v2_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/classMethod/v3/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala create mode 100644 sbt-test/unroll-annot/curriedMethod/build.sbt create mode 100644 sbt-test/unroll-annot/curriedMethod/project/DottyInjectedPlugin.scala create mode 100644 sbt-test/unroll-annot/curriedMethod/test create mode 100644 sbt-test/unroll-annot/curriedMethod/utils/src/main/scala/TestUtils.scala create mode 100644 sbt-test/unroll-annot/curriedMethod/v1/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/curriedMethod/v1_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/curriedMethod/v2/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/curriedMethod/v2_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/curriedMethod/v3/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala create mode 100644 sbt-test/unroll-annot/methodWithImplicit/build.sbt create mode 100644 sbt-test/unroll-annot/methodWithImplicit/project/DottyInjectedPlugin.scala create mode 100644 sbt-test/unroll-annot/methodWithImplicit/test create mode 100644 sbt-test/unroll-annot/methodWithImplicit/utils/src/main/scala/TestUtils.scala create mode 100644 sbt-test/unroll-annot/methodWithImplicit/v1/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/methodWithImplicit/v1_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/methodWithImplicit/v2/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/methodWithImplicit/v2_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/methodWithImplicit/v3/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala create mode 100644 sbt-test/unroll-annot/objectMethod/build.sbt create mode 100644 sbt-test/unroll-annot/objectMethod/project/DottyInjectedPlugin.scala create mode 100644 sbt-test/unroll-annot/objectMethod/test create mode 100644 sbt-test/unroll-annot/objectMethod/utils/src/main/scala/TestUtils.scala create mode 100644 sbt-test/unroll-annot/objectMethod/v1/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/objectMethod/v1_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/objectMethod/v2/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/objectMethod/v2_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/objectMethod/v3/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala create mode 100644 sbt-test/unroll-annot/primaryConstructor/build.sbt create mode 100644 sbt-test/unroll-annot/primaryConstructor/project/DottyInjectedPlugin.scala create mode 100644 sbt-test/unroll-annot/primaryConstructor/test create mode 100644 sbt-test/unroll-annot/primaryConstructor/utils/src/main/scala/TestUtils.scala create mode 100644 sbt-test/unroll-annot/primaryConstructor/v1/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/primaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/primaryConstructor/v2/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/primaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/primaryConstructor/v3/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala create mode 100644 sbt-test/unroll-annot/secondParameterList/build.sbt create mode 100644 sbt-test/unroll-annot/secondParameterList/project/DottyInjectedPlugin.scala create mode 100644 sbt-test/unroll-annot/secondParameterList/test create mode 100644 sbt-test/unroll-annot/secondParameterList/utils/src/main/scala/TestUtils.scala create mode 100644 sbt-test/unroll-annot/secondParameterList/v1/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/secondParameterList/v1_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/secondParameterList/v2/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/secondParameterList/v2_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/secondParameterList/v3/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala create mode 100644 sbt-test/unroll-annot/secondaryConstructor/build.sbt create mode 100644 sbt-test/unroll-annot/secondaryConstructor/project/DottyInjectedPlugin.scala create mode 100644 sbt-test/unroll-annot/secondaryConstructor/test create mode 100644 sbt-test/unroll-annot/secondaryConstructor/utils/src/main/scala/TestUtils.scala create mode 100644 sbt-test/unroll-annot/secondaryConstructor/v1/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/secondaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/secondaryConstructor/v2/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/secondaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/secondaryConstructor/v3/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala create mode 100644 sbt-test/unroll-annot/traitMethod/build.sbt create mode 100644 sbt-test/unroll-annot/traitMethod/project/DottyInjectedPlugin.scala create mode 100644 sbt-test/unroll-annot/traitMethod/test create mode 100644 sbt-test/unroll-annot/traitMethod/utils/src/main/scala/TestUtils.scala create mode 100644 sbt-test/unroll-annot/traitMethod/v1/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/traitMethod/v1_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/traitMethod/v2/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/traitMethod/v2_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/traitMethod/v3/src/main/scala/Unrolled.scala create mode 100644 sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestMain.scala create mode 100644 sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala create mode 100644 tests/run/unroll-caseclass.check create mode 100644 tests/run/unroll-caseclass/Test_4.scala create mode 100644 tests/run/unroll-caseclass/unrolledV1_1.scala create mode 100644 tests/run/unroll-caseclass/unrolledV2_2.scala create mode 100644 tests/run/unroll-caseclass/unrolledV3_3.scala diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index d8ba1ab5dc2e..24a492b4fe77 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -61,6 +61,7 @@ class Compiler { List(new InstrumentCoverage) :: // Perform instrumentation for code coverage (if -coverage-out is set) List(new CrossVersionChecks, // Check issues related to deprecated and experimental new FirstTransform, // Some transformations to put trees into a canonical form + new UnrollDefs, // Unroll annotated methods new CheckReentrant, // Internal use only: Check that compiled program has no data races involving global vars new ElimPackagePrefixes, // Eliminate references to package prefixes in Select nodes new CookComments, // Cook the comments: expand variables, doc, etc. diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 27ea5771c30b..f15595fbcdb6 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1036,6 +1036,7 @@ class Definitions { @tu lazy val MigrationAnnot: ClassSymbol = requiredClass("scala.annotation.migration") @tu lazy val NowarnAnnot: ClassSymbol = requiredClass("scala.annotation.nowarn") @tu lazy val UnusedAnnot: ClassSymbol = requiredClass("scala.annotation.unused") + @tu lazy val UnrollAnnot: ClassSymbol = requiredClass("scala.annotation.unroll") @tu lazy val TransparentTraitAnnot: ClassSymbol = requiredClass("scala.annotation.transparentTrait") @tu lazy val NativeAnnot: ClassSymbol = requiredClass("scala.native") @tu lazy val RepeatedAnnot: ClassSymbol = requiredClass("scala.annotation.internal.Repeated") diff --git a/compiler/src/dotty/tools/dotc/transform/UnrollDefs.scala b/compiler/src/dotty/tools/dotc/transform/UnrollDefs.scala new file mode 100644 index 000000000000..5fcf6f0ba9ab --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/UnrollDefs.scala @@ -0,0 +1,279 @@ +package dotty.tools.dotc.transform + +import dotty.tools.dotc.* +import core.* +import MegaPhase.MiniPhase +import Contexts.* +import Symbols.* +import Flags.* +import SymDenotations.* +import Decorators.* +import ast.Trees.* +import ast.tpd +import StdNames.nme +import Names.* +import Constants.Constant +import dotty.tools.dotc.core.NameKinds.DefaultGetterName +import dotty.tools.dotc.core.Types.{MethodType, NamedType, PolyType, Type} +import dotty.tools.dotc.core.Symbols + +import scala.language.implicitConversions + +class UnrollDefs extends MiniPhase { + import tpd._ + + val phaseName = "unroll" + + override val runsAfter = Set(FirstTransform.name) + + def copyParam(p: ValDef, parent: Symbol)(using Context) = { + implicitly[Context].typeAssigner.assignType( + cpy.ValDef(p)(p.name, p.tpt, p.rhs), + Symbols.newSymbol(parent, p.name, p.symbol.flags, p.symbol.info) + ) + } + + def copyParam2(p: TypeDef, parent: Symbol)(using Context) = { + implicitly[Context].typeAssigner.assignType( + cpy.TypeDef(p)(p.name, p.rhs), + Symbols.newSymbol(parent, p.name, p.symbol.flags, p.symbol.info) + ) + } + + def findUnrollAnnotations(params: List[Symbol])(using Context): List[Int] = { + params + .zipWithIndex + .collect { + case (v, i) if v.annotations.exists(_.symbol.fullName.toString == "scala.annotation.unroll") => + i + } + } + def isTypeClause(p: ParamClause) = p.headOption.exists(_.isInstanceOf[TypeDef]) + def generateSingleForwarder(defdef: DefDef, + prevMethodType: Type, + paramIndex: Int, + nextParamIndex: Int, + nextSymbol: Symbol, + annotatedParamListIndex: Int, + paramLists: List[ParamClause], + isCaseApply: Boolean) + (using Context) = { + + def truncateMethodType0(tpe: Type, n: Int): Type = { + tpe match{ + case pt: PolyType => PolyType(pt.paramNames, pt.paramInfos, truncateMethodType0(pt.resType, n + 1)) + case mt: MethodType => + if (n == annotatedParamListIndex) MethodType(mt.paramInfos.take(paramIndex), mt.resType) + else MethodType(mt.paramInfos, truncateMethodType0(mt.resType, n + 1)) + } + } + + val truncatedMethodType = truncateMethodType0(prevMethodType, 0) + val forwarderDefSymbol = Symbols.newSymbol( + defdef.symbol.owner, + defdef.name, + defdef.symbol.flags &~ + HasDefaultParams &~ + (if (nextParamIndex == -1) Flags.EmptyFlags else Deferred) | + Invisible, + truncatedMethodType + ) + + val newParamLists: List[ParamClause] = paramLists.zipWithIndex.map{ case (ps, i) => + if (i == annotatedParamListIndex) ps.take(paramIndex).map(p => copyParam(p.asInstanceOf[ValDef], forwarderDefSymbol)) + else { + if (isTypeClause(ps)) ps.map(p => copyParam2(p.asInstanceOf[TypeDef], forwarderDefSymbol)) + else ps.map(p => copyParam(p.asInstanceOf[ValDef], forwarderDefSymbol)) + } + } + forwarderDefSymbol.setParamssFromDefs(newParamLists) + + val defaultOffset = paramLists + .iterator + .take(annotatedParamListIndex) + .filter(!isTypeClause(_)) + .map(_.size) + .sum + + val defaultCalls = Range(paramIndex, nextParamIndex).map(n => + val inner = if (defdef.symbol.isConstructor) { + ref(defdef.symbol.owner.companionModule) + .select(DefaultGetterName(defdef.name, n + defaultOffset)) + } else if (isCaseApply) { + ref(defdef.symbol.owner.companionModule) + .select(DefaultGetterName(termName(""), n + defaultOffset)) + } else { + This(defdef.symbol.owner.asClass) + .select(DefaultGetterName(defdef.name, n + defaultOffset)) + } + + newParamLists + .take(annotatedParamListIndex) + .map(_.map(p => ref(p.symbol))) + .foldLeft[Tree](inner){ + case (lhs: Tree, newParams) => + if (newParams.headOption.exists(_.isInstanceOf[TypeTree])) TypeApply(lhs, newParams) + else Apply(lhs, newParams) + } + ) + + val forwarderInner: Tree = This(defdef.symbol.owner.asClass).select(nextSymbol) + + val forwarderCallArgs = + newParamLists.zipWithIndex.map{case (ps, i) => + if (i == annotatedParamListIndex) ps.map(p => ref(p.symbol)).take(nextParamIndex) ++ defaultCalls + else ps.map(p => ref(p.symbol)) + } + + lazy val forwarderCall0 = forwarderCallArgs.foldLeft[Tree](forwarderInner){ + case (lhs: Tree, newParams) => + if (newParams.headOption.exists(_.isInstanceOf[TypeTree])) TypeApply(lhs, newParams) + else Apply(lhs, newParams) + } + + lazy val forwarderCall = + if (!defdef.symbol.isConstructor) forwarderCall0 + else Block(List(forwarderCall0), Literal(Constant(()))) + + val forwarderDef = implicitly[Context].typeAssigner.assignType( + cpy.DefDef(defdef)( + name = forwarderDefSymbol.name, + paramss = newParamLists, + tpt = defdef.tpt, + rhs = if (nextParamIndex == -1) EmptyTree else forwarderCall + ), + forwarderDefSymbol + ) + + forwarderDef + } + + def generateFromProduct(startParamIndices: List[Int], paramCount: Int, defdef: DefDef)(using Context) = { + cpy.DefDef(defdef)( + name = defdef.name, + paramss = defdef.paramss, + tpt = defdef.tpt, + rhs = Match( + ref(defdef.paramss.head.head.asInstanceOf[ValDef].symbol).select(termName("productArity")), + startParamIndices.map { paramIndex => + val Apply(select, args) = defdef.rhs: @unchecked + CaseDef( + Literal(Constant(paramIndex)), + EmptyTree, + Apply( + select, + args.take(paramIndex) ++ + Range(paramIndex, paramCount).map(n => + ref(defdef.symbol.owner.companionModule) + .select(DefaultGetterName(defdef.symbol.owner.primaryConstructor.name.toTermName, n)) + ) + ) + ) + } ++ Seq( + CaseDef( + EmptyTree, + EmptyTree, + defdef.rhs + ) + ) + ) + ).setDefTree + } + + def generateSyntheticDefs(tree: Tree)(using Context): (Option[Symbol], Seq[Tree]) = tree match{ + case defdef: DefDef if defdef.paramss.nonEmpty => + import dotty.tools.dotc.core.NameOps.isConstructorName + + val isCaseCopy = + defdef.name.toString == "copy" && defdef.symbol.owner.is(CaseClass) + + val isCaseApply = + defdef.name.toString == "apply" && defdef.symbol.owner.companionClass.is(CaseClass) + + val isCaseFromProduct = defdef.name.toString == "fromProduct" && defdef.symbol.owner.companionClass.is(CaseClass) + + val annotated = + if (isCaseCopy) defdef.symbol.owner.primaryConstructor + else if (isCaseApply) defdef.symbol.owner.companionClass.primaryConstructor + else if (isCaseFromProduct) defdef.symbol.owner.companionClass.primaryConstructor + else defdef.symbol + + + annotated + .paramSymss + .zipWithIndex + .flatMap{case (paramClause, paramClauseIndex) => + val annotationIndices = findUnrollAnnotations(paramClause) + if (annotationIndices.isEmpty) None + else Some((paramClauseIndex, annotationIndices)) + } match{ + case Nil => (None, Nil) + case Seq((paramClauseIndex, annotationIndices)) => + val paramCount = annotated.paramSymss(paramClauseIndex).size + if (isCaseFromProduct) { + (Some(defdef.symbol), Seq(generateFromProduct(annotationIndices, paramCount, defdef))) + } else { + if (defdef.symbol.is(Deferred)){ + ( + Some(defdef.symbol), + (-1 +: annotationIndices :+ paramCount).sliding(2).toList.foldLeft((Seq.empty[DefDef], defdef.symbol))((m, v) => ((m, v): @unchecked) match { + case ((defdefs, nextSymbol), Seq(paramIndex, nextParamIndex)) => + val forwarder = generateSingleForwarder( + defdef, + defdef.symbol.info, + nextParamIndex, + paramIndex, + nextSymbol, + paramClauseIndex, + defdef.paramss, + isCaseApply + ) + (forwarder +: defdefs, forwarder.symbol) + })._1 + ) + + }else{ + + ( + None, + (annotationIndices :+ paramCount).sliding(2).toList.reverse.foldLeft((Seq.empty[DefDef], defdef.symbol))((m, v) => ((m, v): @unchecked) match { + case ((defdefs, nextSymbol), Seq(paramIndex, nextParamIndex)) => + val forwarder = generateSingleForwarder( + defdef, + defdef.symbol.info, + paramIndex, + nextParamIndex, + nextSymbol, + paramClauseIndex, + defdef.paramss, + isCaseApply + ) + (forwarder +: defdefs, forwarder.symbol) + })._1 + ) + } + } + + case multiple => sys.error("Cannot have multiple parameter lists containing `@unroll` annotation") + } + + case _ => (None, Nil) + } + + override def transformTemplate(tmpl: tpd.Template)(using Context): tpd.Tree = { + + val (removed0, generatedDefs) = tmpl.body.map(generateSyntheticDefs).unzip + val (_, generatedConstr) = generateSyntheticDefs(tmpl.constr) + val removed = removed0.flatten + + super.transformTemplate( + cpy.Template(tmpl)( + tmpl.constr, + tmpl.parents, + tmpl.derived, + tmpl.self, + tmpl.body.filter(t => !removed.contains(t.symbol)) ++ generatedDefs.flatten ++ generatedConstr + ) + ) + } +} diff --git a/library/src/scala/annotation/unroll.scala b/library/src/scala/annotation/unroll.scala new file mode 100644 index 000000000000..93327f7dcb86 --- /dev/null +++ b/library/src/scala/annotation/unroll.scala @@ -0,0 +1,4 @@ +package scala.annotation + +@experimental("under review as part of SIP-61") +final class unroll extends scala.annotation.StaticAnnotation diff --git a/sbt-test/unroll-annot/caseclass/build.sbt b/sbt-test/unroll-annot/caseclass/build.sbt new file mode 100644 index 000000000000..0568d222bf5a --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/build.sbt @@ -0,0 +1,48 @@ +lazy val utils = project.in(file("utils")) + +lazy val sharedSettings = Seq( + scalacOptions ++= Seq("-Ycheck:all", "-experimental") +) + +lazy val v1 = project.in(file("v1")) + .settings(sharedSettings) + +lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Compile / unmanagedClasspath := Seq( + Attributed.blank((v1 / Compile / classDirectory).value) + ), + ) + +lazy val v2 = project.in(file("v2")) + .settings(sharedSettings) + +lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value) + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v2 / Compile / classDirectory).value) + ), + ) + +lazy val v3 = project.in(file("v3")) + .settings(sharedSettings) + +lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value), + // add v2_app, compiled against v2, to the classpath + Attributed.blank((v2_app / Runtime / classDirectory).value), + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v3 / Compile / classDirectory).value) + ), + ) diff --git a/sbt-test/unroll-annot/caseclass/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/caseclass/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/unroll-annot/caseclass/test b/sbt-test/unroll-annot/caseclass/test new file mode 100644 index 000000000000..e8e500857b0e --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/test @@ -0,0 +1,14 @@ +# compile and run a basic version of Unrolled (v1), and an app that uses it +> v1/compile +> v1_app/runMain unroll.UnrollTestMainV1 +# add a field to the case class (v2), and update the app to use it, +# and ensure the old version (v1) still links +> v2/compile +> v2_app/runMain unroll.UnrollTestMainV1 +> v2_app/runMain unroll.UnrollTestMainV2 +# add a field to the case class (v3), and update the app to use it, +# and ensure the old versions (v1, v2) still link +> v3/compile +> v3_app/runMain unroll.UnrollTestMainV1 +> v3_app/runMain unroll.UnrollTestMainV2 +> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/caseclass/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/caseclass/utils/src/main/scala/TestUtils.scala new file mode 100644 index 000000000000..6ac413c9fe98 --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/utils/src/main/scala/TestUtils.scala @@ -0,0 +1,12 @@ +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/sbt-test/unroll-annot/caseclass/v1/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/caseclass/v1/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..997ae2f2dc00 --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/v1/src/main/scala/Unrolled.scala @@ -0,0 +1,5 @@ +package unroll + +case class Unrolled(s: String, n: Int = 1){ + def foo = s + n +} diff --git a/sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..e0b058ad0230 --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,24 @@ +package unroll +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV1{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled("cow").foo, "cow1") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2") + + logAssertStartsWith(Unrolled("cow").foo, "cow1") + logAssertStartsWith(Unrolled("cow", 2).foo, "cow2") + + val unrolled = Unrolled("cow") + + logAssertStartsWith(unrolled.copy(s = "cow").foo, "cow1") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2).foo, "cow2") + + val Unrolled(s, n) = unrolled + + assert(s == "cow") + assert(n == 1) + + UnrollTestScalaSpecificV1.test() + } +} diff --git a/sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestScalaSpecific.scala b/sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestScalaSpecific.scala new file mode 100644 index 000000000000..514905a741f4 --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestScalaSpecific.scala @@ -0,0 +1,20 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestScalaSpecificV1{ + def test() = { + val unrolled = Unrolled.fromProduct( + new Product{ + def canEqual(that: Any) = true + def productArity = 2 + def productElement(n: Int) = n match{ + case 0 => "hello" + case 1 => 31337 + } + } + ) + + logAssertStartsWith(unrolled.foo, "hello31337") + } +} diff --git a/sbt-test/unroll-annot/caseclass/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/caseclass/v2/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..916c44550a13 --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/v2/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true){ + def foo = s + n + b +} diff --git a/sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..c266a5f8c88e --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,29 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV2{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled("cow").foo, "cow1true") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2true") + logAssertStartsWith(new Unrolled("cow", 2, false).foo, "cow2false") + + logAssertStartsWith(Unrolled("cow").foo, "cow1true") + logAssertStartsWith(Unrolled("cow", 2).foo, "cow2true") + logAssertStartsWith(Unrolled("cow", 2, false).foo, "cow2false") + + val unrolled = Unrolled("cow") + + logAssertStartsWith(unrolled.copy(s = "cow").foo, "cow1true") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2).foo, "cow2true") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2, b = false).foo, "cow2false") + + val Unrolled(s, n, b) = unrolled + + assert(s == "cow") + assert(n == 1) + assert(b == true) + + UnrollTestScalaSpecificV2.test() + } +} diff --git a/sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestScalaSpecific.scala b/sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestScalaSpecific.scala new file mode 100644 index 000000000000..88ead065de6e --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestScalaSpecific.scala @@ -0,0 +1,21 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestScalaSpecificV2{ + def test() = { + val unrolled = Unrolled.fromProduct( + new Product { + def canEqual(that: Any) = true + def productArity = 3 + def productElement(n: Int) = n match { + case 0 => "hello" + case 1 => 31337 + case 2 => false + } + } + + ) + logAssertStartsWith(unrolled.foo, "hello31337false") + } +} \ No newline at end of file diff --git a/sbt-test/unroll-annot/caseclass/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/caseclass/v3/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..f1bf8c01ad2a --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/v3/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0){ + def foo = s + n + b + l +} diff --git a/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..a58303a6bdad --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,35 @@ +package unroll +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV3{ + def main(args: Array[String]): Unit = { + UnrollTestScalaSpecificV3() + UnrollTestPlatformSpecificV3() + + logAssertStartsWith(new Unrolled("cow").foo, "cow1true0") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2true0") + logAssertStartsWith(new Unrolled("cow", 2, false).foo, "cow2false0") + logAssertStartsWith(new Unrolled("cow", 2, false, 9L).foo, "cow2false9") + + logAssertStartsWith(Unrolled("cow").foo, "cow1true0") + logAssertStartsWith(Unrolled("cow", 2).foo, "cow2true0") + logAssertStartsWith(Unrolled("cow", 2, false).foo, "cow2false0") + logAssertStartsWith(Unrolled("cow", 2, false, 9L).foo, "cow2false9") + + val unrolled = Unrolled("cow") + + logAssertStartsWith(unrolled.copy(s = "cow").foo, "cow1true0") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2).foo, "cow2true0") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2, b = false).foo, "cow2false0") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2, b = false, l = 9L).foo, "cow2false9") + + val Unrolled(s, n, b, l) = unrolled + + assert(s == "cow") + assert(n == 1) + assert(b == true) + assert(l == 0L) + + + } +} diff --git a/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala new file mode 100644 index 000000000000..07dee69cd8a7 --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala @@ -0,0 +1,33 @@ +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + val cls = classOf[Unrolled] + + assert(scala.util.Try(cls.getConstructor(classOf[String])).isFailure) + println() + assert( + cls.getConstructor(classOf[String], classOf[Int]) + .newInstance("hello", 2: Integer) + .asInstanceOf[Unrolled] + .foo == + "hello2true0" + ) + assert( + cls.getConstructor(classOf[String], classOf[Int], classOf[Boolean]) + .newInstance("hello", 2: Integer, java.lang.Boolean.FALSE) + .asInstanceOf[Unrolled] + .foo == + "hello2false0" + ) + assert( + cls.getConstructor(classOf[String], classOf[Int], classOf[Boolean], classOf[Long]) + .newInstance("hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) + .asInstanceOf[Unrolled] + .foo == + "hello2false3" + ) + + cls.getConstructors.foreach(println) + } +} \ No newline at end of file diff --git a/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestScalaSpecific.scala b/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestScalaSpecific.scala new file mode 100644 index 000000000000..13d4fffe7f62 --- /dev/null +++ b/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestScalaSpecific.scala @@ -0,0 +1,20 @@ +package unroll +import unroll.TestUtils.logAssertStartsWith +object UnrollTestScalaSpecificV3{ + def apply() = { + val unrolled = Unrolled.fromProduct( + new Product { + def canEqual(that: Any) = true + def productArity = 4 + def productElement(n: Int) = n match { + case 0 => "hello" + case 1 => 31337 + case 2 => false + case 3 => 12345L + } + } + ) + + logAssertStartsWith(unrolled.foo, "hello31337false12345") + } +} \ No newline at end of file diff --git a/sbt-test/unroll-annot/classMethod/build.sbt b/sbt-test/unroll-annot/classMethod/build.sbt new file mode 100644 index 000000000000..0568d222bf5a --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/build.sbt @@ -0,0 +1,48 @@ +lazy val utils = project.in(file("utils")) + +lazy val sharedSettings = Seq( + scalacOptions ++= Seq("-Ycheck:all", "-experimental") +) + +lazy val v1 = project.in(file("v1")) + .settings(sharedSettings) + +lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Compile / unmanagedClasspath := Seq( + Attributed.blank((v1 / Compile / classDirectory).value) + ), + ) + +lazy val v2 = project.in(file("v2")) + .settings(sharedSettings) + +lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value) + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v2 / Compile / classDirectory).value) + ), + ) + +lazy val v3 = project.in(file("v3")) + .settings(sharedSettings) + +lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value), + // add v2_app, compiled against v2, to the classpath + Attributed.blank((v2_app / Runtime / classDirectory).value), + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v3 / Compile / classDirectory).value) + ), + ) diff --git a/sbt-test/unroll-annot/classMethod/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/classMethod/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/unroll-annot/classMethod/test b/sbt-test/unroll-annot/classMethod/test new file mode 100644 index 000000000000..e8e500857b0e --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/test @@ -0,0 +1,14 @@ +# compile and run a basic version of Unrolled (v1), and an app that uses it +> v1/compile +> v1_app/runMain unroll.UnrollTestMainV1 +# add a field to the case class (v2), and update the app to use it, +# and ensure the old version (v1) still links +> v2/compile +> v2_app/runMain unroll.UnrollTestMainV1 +> v2_app/runMain unroll.UnrollTestMainV2 +# add a field to the case class (v3), and update the app to use it, +# and ensure the old versions (v1, v2) still link +> v3/compile +> v3_app/runMain unroll.UnrollTestMainV1 +> v3_app/runMain unroll.UnrollTestMainV2 +> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/classMethod/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/classMethod/utils/src/main/scala/TestUtils.scala new file mode 100644 index 000000000000..6ac413c9fe98 --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/utils/src/main/scala/TestUtils.scala @@ -0,0 +1,12 @@ +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/sbt-test/unroll-annot/classMethod/v1/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/classMethod/v1/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..638bcfdeb96d --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/v1/src/main/scala/Unrolled.scala @@ -0,0 +1,5 @@ +package unroll + +class Unrolled{ + def foo(s: String) = s +} diff --git a/sbt-test/unroll-annot/classMethod/v1_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/classMethod/v1_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..f36e9dd07fed --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/v1_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,9 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV1{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled().foo("cow"), "cow") + } +} diff --git a/sbt-test/unroll-annot/classMethod/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/classMethod/v2/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..e46d36c230c0 --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/v2/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled{ + def foo(s: String, @unroll n: Int = 1, b: Boolean = true) = s + n + b +} diff --git a/sbt-test/unroll-annot/classMethod/v2_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/classMethod/v2_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..91b54aa9742c --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/v2_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,11 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV2{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled().foo("cow"), "cow1true") + logAssertStartsWith(new Unrolled().foo("cow", 2), "cow2true") + logAssertStartsWith(new Unrolled().foo("cow", 2, false), "cow2false") + } +} diff --git a/sbt-test/unroll-annot/classMethod/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/classMethod/v3/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..5f0b76a799d4 --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/v3/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled{ + def foo(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0) = s + n + b + l +} diff --git a/sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..9a6daa3a9210 --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,14 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV3{ + def main(args: Array[String]): Unit = { + UnrollTestPlatformSpecificV3() + + logAssertStartsWith(new Unrolled().foo("cow"), "cow1true0") + logAssertStartsWith(new Unrolled().foo("cow", 2), "cow2true0") + logAssertStartsWith(new Unrolled().foo("cow", 2, false), "cow2false0") + logAssertStartsWith(new Unrolled().foo("cow", 2, false, 3), "cow2false3") + } +} diff --git a/sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala new file mode 100644 index 000000000000..e8527808befd --- /dev/null +++ b/sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala @@ -0,0 +1,30 @@ +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + val instance = new Unrolled() + val cls = classOf[Unrolled] + + assert( + cls.getMethod("foo", classOf[String]).invoke(instance, "hello") == + "hello1true0" + ) + + // Only generate unrolled methods for annotated params + // (b: Boolean) is not annotated so this method should not exist + assert(scala.util.Try(cls.getMethod("foo", classOf[String], classOf[Int])).isFailure) + + assert( + cls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE) == + "hello2false0" + ) + assert( + cls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean], classOf[Long]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) == + "hello2false3" + ) + + cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + } +} \ No newline at end of file diff --git a/sbt-test/unroll-annot/curriedMethod/build.sbt b/sbt-test/unroll-annot/curriedMethod/build.sbt new file mode 100644 index 000000000000..0568d222bf5a --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/build.sbt @@ -0,0 +1,48 @@ +lazy val utils = project.in(file("utils")) + +lazy val sharedSettings = Seq( + scalacOptions ++= Seq("-Ycheck:all", "-experimental") +) + +lazy val v1 = project.in(file("v1")) + .settings(sharedSettings) + +lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Compile / unmanagedClasspath := Seq( + Attributed.blank((v1 / Compile / classDirectory).value) + ), + ) + +lazy val v2 = project.in(file("v2")) + .settings(sharedSettings) + +lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value) + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v2 / Compile / classDirectory).value) + ), + ) + +lazy val v3 = project.in(file("v3")) + .settings(sharedSettings) + +lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value), + // add v2_app, compiled against v2, to the classpath + Attributed.blank((v2_app / Runtime / classDirectory).value), + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v3 / Compile / classDirectory).value) + ), + ) diff --git a/sbt-test/unroll-annot/curriedMethod/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/curriedMethod/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/unroll-annot/curriedMethod/test b/sbt-test/unroll-annot/curriedMethod/test new file mode 100644 index 000000000000..e8e500857b0e --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/test @@ -0,0 +1,14 @@ +# compile and run a basic version of Unrolled (v1), and an app that uses it +> v1/compile +> v1_app/runMain unroll.UnrollTestMainV1 +# add a field to the case class (v2), and update the app to use it, +# and ensure the old version (v1) still links +> v2/compile +> v2_app/runMain unroll.UnrollTestMainV1 +> v2_app/runMain unroll.UnrollTestMainV2 +# add a field to the case class (v3), and update the app to use it, +# and ensure the old versions (v1, v2) still link +> v3/compile +> v3_app/runMain unroll.UnrollTestMainV1 +> v3_app/runMain unroll.UnrollTestMainV2 +> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/curriedMethod/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/curriedMethod/utils/src/main/scala/TestUtils.scala new file mode 100644 index 000000000000..6ac413c9fe98 --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/utils/src/main/scala/TestUtils.scala @@ -0,0 +1,12 @@ +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/sbt-test/unroll-annot/curriedMethod/v1/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/curriedMethod/v1/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..e508d4345313 --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/v1/src/main/scala/Unrolled.scala @@ -0,0 +1,5 @@ +package unroll + +class Unrolled{ + def foo(s: String)(f: String => String) = f(s) +} diff --git a/sbt-test/unroll-annot/curriedMethod/v1_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/curriedMethod/v1_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..8d1ca388477b --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/v1_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,9 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV1{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled().foo("cow")(identity), "cow") + } +} diff --git a/sbt-test/unroll-annot/curriedMethod/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/curriedMethod/v2/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..843dbaa73e16 --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/v2/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled{ + def foo(s: String, @unroll n: Int = 1, b: Boolean = true)(f: String => String) = f(s + n + b) +} diff --git a/sbt-test/unroll-annot/curriedMethod/v2_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/curriedMethod/v2_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..66ad8fdf8698 --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/v2_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,11 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV2{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled().foo("cow")(identity), "cow1true") + logAssertStartsWith(new Unrolled().foo("cow", 2)(identity), "cow2true") + logAssertStartsWith(new Unrolled().foo("cow", 2, false)(identity), "cow2false") + } +} diff --git a/sbt-test/unroll-annot/curriedMethod/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/curriedMethod/v3/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..01c34e9548cf --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/v3/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled{ + def foo(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0)(f: String => String) = f(s + n + b + l) +} diff --git a/sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..02b839fc07d2 --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,14 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV3{ + def main(args: Array[String]): Unit = { + UnrollTestPlatformSpecificV3() + + logAssertStartsWith(new Unrolled().foo("cow")(identity), "cow1true0") + logAssertStartsWith(new Unrolled().foo("cow", 2)(identity), "cow2true0") + logAssertStartsWith(new Unrolled().foo("cow", 2, false)(identity), "cow2false0") + logAssertStartsWith(new Unrolled().foo("cow", 2, false, 3)(identity), "cow2false3") + } +} diff --git a/sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala new file mode 100644 index 000000000000..61eeeb8756b8 --- /dev/null +++ b/sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala @@ -0,0 +1,29 @@ +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + val instance = new Unrolled() + val cls = classOf[Unrolled] + + assert( + cls.getMethod("foo", classOf[String], classOf[String => String]).invoke(instance, "hello", identity[String](_)) == + "hello1true0" + ) + + assert( + scala.util.Try(cls.getMethod("foo", classOf[String], classOf[Int], classOf[String => String])).isFailure + ) + assert( + cls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean], classOf[String => String]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE, identity[String](_)) == + "hello2false0" + ) + assert( + cls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean], classOf[Long], classOf[String => String]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer, identity[String](_)) == + "hello2false3" + ) + + cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + } +} \ No newline at end of file diff --git a/sbt-test/unroll-annot/methodWithImplicit/build.sbt b/sbt-test/unroll-annot/methodWithImplicit/build.sbt new file mode 100644 index 000000000000..0568d222bf5a --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/build.sbt @@ -0,0 +1,48 @@ +lazy val utils = project.in(file("utils")) + +lazy val sharedSettings = Seq( + scalacOptions ++= Seq("-Ycheck:all", "-experimental") +) + +lazy val v1 = project.in(file("v1")) + .settings(sharedSettings) + +lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Compile / unmanagedClasspath := Seq( + Attributed.blank((v1 / Compile / classDirectory).value) + ), + ) + +lazy val v2 = project.in(file("v2")) + .settings(sharedSettings) + +lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value) + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v2 / Compile / classDirectory).value) + ), + ) + +lazy val v3 = project.in(file("v3")) + .settings(sharedSettings) + +lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value), + // add v2_app, compiled against v2, to the classpath + Attributed.blank((v2_app / Runtime / classDirectory).value), + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v3 / Compile / classDirectory).value) + ), + ) diff --git a/sbt-test/unroll-annot/methodWithImplicit/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/methodWithImplicit/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/unroll-annot/methodWithImplicit/test b/sbt-test/unroll-annot/methodWithImplicit/test new file mode 100644 index 000000000000..e8e500857b0e --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/test @@ -0,0 +1,14 @@ +# compile and run a basic version of Unrolled (v1), and an app that uses it +> v1/compile +> v1_app/runMain unroll.UnrollTestMainV1 +# add a field to the case class (v2), and update the app to use it, +# and ensure the old version (v1) still links +> v2/compile +> v2_app/runMain unroll.UnrollTestMainV1 +> v2_app/runMain unroll.UnrollTestMainV2 +# add a field to the case class (v3), and update the app to use it, +# and ensure the old versions (v1, v2) still link +> v3/compile +> v3_app/runMain unroll.UnrollTestMainV1 +> v3_app/runMain unroll.UnrollTestMainV2 +> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/methodWithImplicit/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/methodWithImplicit/utils/src/main/scala/TestUtils.scala new file mode 100644 index 000000000000..6ac413c9fe98 --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/utils/src/main/scala/TestUtils.scala @@ -0,0 +1,12 @@ +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/sbt-test/unroll-annot/methodWithImplicit/v1/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/methodWithImplicit/v1/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..44137480e239 --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/v1/src/main/scala/Unrolled.scala @@ -0,0 +1,5 @@ +package unroll + +class Unrolled{ + def foo(s: String)(implicit f: String => String) = f(s) +} diff --git a/sbt-test/unroll-annot/methodWithImplicit/v1_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/methodWithImplicit/v1_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..928a74f57d5e --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/v1_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,10 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV1{ + def main(args: Array[String]): Unit = { + implicit def f(s: String): String = s + logAssertStartsWith(new Unrolled().foo("cow"), "cow") + } +} diff --git a/sbt-test/unroll-annot/methodWithImplicit/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/methodWithImplicit/v2/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..fa98747d28d8 --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/v2/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled{ + def foo(s: String, @unroll n: Int = 1, b: Boolean = true)(implicit f: String => String) = f(s + n + b) +} diff --git a/sbt-test/unroll-annot/methodWithImplicit/v2_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/methodWithImplicit/v2_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..de14613be3cc --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/v2_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,12 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV2{ + def main(args: Array[String]): Unit = { + implicit def f(s: String): String = s + logAssertStartsWith(new Unrolled().foo("cow"), "cow1true") + logAssertStartsWith(new Unrolled().foo("cow", 2), "cow2true") + logAssertStartsWith(new Unrolled().foo("cow", 2, false), "cow2false") + } +} diff --git a/sbt-test/unroll-annot/methodWithImplicit/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/methodWithImplicit/v3/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..58e88f581b4c --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/v3/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled{ + def foo(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0)(implicit f: String => String) = f(s + n + b + l) +} diff --git a/sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..1982d7dff344 --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,15 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV3{ + def main(args: Array[String]): Unit = { + UnrollTestPlatformSpecificV3() + + implicit def f(s: String): String = s + logAssertStartsWith(new Unrolled().foo("cow"), "cow1true0") + logAssertStartsWith(new Unrolled().foo("cow", 2), "cow2true0") + logAssertStartsWith(new Unrolled().foo("cow", 2, false), "cow2false0") + logAssertStartsWith(new Unrolled().foo("cow", 2, false, 3), "cow2false3") + } +} diff --git a/sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala new file mode 100644 index 000000000000..3537a6373e0d --- /dev/null +++ b/sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala @@ -0,0 +1,29 @@ +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + val instance = new Unrolled() + val cls = classOf[Unrolled] + + assert( + cls.getMethod("foo", classOf[String], classOf[String => String]).invoke(instance, "hello", identity[String](_)) == + "hello1true0" + ) + + assert(scala.util.Try(cls.getMethod("foo", classOf[String], classOf[Int], classOf[String => String])).isFailure) + + assert( + cls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean], classOf[String => String]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE, identity[String](_)) == + "hello2false0" + ) + assert( + cls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean], classOf[Long], classOf[String => String]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer, identity[String](_)) == + "hello2false3" + ) + + cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + + } +} \ No newline at end of file diff --git a/sbt-test/unroll-annot/objectMethod/build.sbt b/sbt-test/unroll-annot/objectMethod/build.sbt new file mode 100644 index 000000000000..0568d222bf5a --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/build.sbt @@ -0,0 +1,48 @@ +lazy val utils = project.in(file("utils")) + +lazy val sharedSettings = Seq( + scalacOptions ++= Seq("-Ycheck:all", "-experimental") +) + +lazy val v1 = project.in(file("v1")) + .settings(sharedSettings) + +lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Compile / unmanagedClasspath := Seq( + Attributed.blank((v1 / Compile / classDirectory).value) + ), + ) + +lazy val v2 = project.in(file("v2")) + .settings(sharedSettings) + +lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value) + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v2 / Compile / classDirectory).value) + ), + ) + +lazy val v3 = project.in(file("v3")) + .settings(sharedSettings) + +lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value), + // add v2_app, compiled against v2, to the classpath + Attributed.blank((v2_app / Runtime / classDirectory).value), + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v3 / Compile / classDirectory).value) + ), + ) diff --git a/sbt-test/unroll-annot/objectMethod/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/objectMethod/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/unroll-annot/objectMethod/test b/sbt-test/unroll-annot/objectMethod/test new file mode 100644 index 000000000000..e8e500857b0e --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/test @@ -0,0 +1,14 @@ +# compile and run a basic version of Unrolled (v1), and an app that uses it +> v1/compile +> v1_app/runMain unroll.UnrollTestMainV1 +# add a field to the case class (v2), and update the app to use it, +# and ensure the old version (v1) still links +> v2/compile +> v2_app/runMain unroll.UnrollTestMainV1 +> v2_app/runMain unroll.UnrollTestMainV2 +# add a field to the case class (v3), and update the app to use it, +# and ensure the old versions (v1, v2) still link +> v3/compile +> v3_app/runMain unroll.UnrollTestMainV1 +> v3_app/runMain unroll.UnrollTestMainV2 +> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/objectMethod/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/objectMethod/utils/src/main/scala/TestUtils.scala new file mode 100644 index 000000000000..6ac413c9fe98 --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/utils/src/main/scala/TestUtils.scala @@ -0,0 +1,12 @@ +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/sbt-test/unroll-annot/objectMethod/v1/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/objectMethod/v1/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..f4559bc2a820 --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/v1/src/main/scala/Unrolled.scala @@ -0,0 +1,6 @@ +package unroll + +object Unrolled{ + + def foo(s: String, n: Int = 1) = s + n +} diff --git a/sbt-test/unroll-annot/objectMethod/v1_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/objectMethod/v1_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..23f8e15b40cb --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/v1_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,10 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV1{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(Unrolled.foo("cow"), "cow1") + logAssertStartsWith(Unrolled.foo("cow", 2), "cow2") + } +} diff --git a/sbt-test/unroll-annot/objectMethod/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/objectMethod/v2/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..53d777884939 --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/v2/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +object Unrolled{ + def foo(s: String, n: Int = 1, @unroll b: Boolean = true) = s + n + b +} diff --git a/sbt-test/unroll-annot/objectMethod/v2_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/objectMethod/v2_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..ee5337bd4689 --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/v2_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,11 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV2{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(Unrolled.foo("cow"), "cow1true") + logAssertStartsWith(Unrolled.foo("cow", 2), "cow2true") + logAssertStartsWith(Unrolled.foo("cow", 2, false), "cow2false") + } +} diff --git a/sbt-test/unroll-annot/objectMethod/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/objectMethod/v3/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..5e3464c184a4 --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/v3/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +object Unrolled{ + def foo(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = s + n + b + l +} diff --git a/sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..b1996bd6d5d7 --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,14 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV3{ + def main(args: Array[String]): Unit = { + UnrollTestPlatformSpecificV3() + + logAssertStartsWith(Unrolled.foo("cow"), "cow1true0") + logAssertStartsWith(Unrolled.foo("cow", 2), "cow2true0") + logAssertStartsWith(Unrolled.foo("cow", 2, false), "cow2false0") + logAssertStartsWith(Unrolled.foo("cow", 2, false, 3), "cow2false3") + } +} diff --git a/sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala new file mode 100644 index 000000000000..2b5578dd482d --- /dev/null +++ b/sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala @@ -0,0 +1,48 @@ +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + val instance = Unrolled + val instanceCls = Class.forName("unroll.Unrolled$") + + instanceCls.getMethods.filter(_.getName.contains("foo")).foreach(println) + + // Make sure singleton instance forwarder methods are generated + assert(scala.util.Try(instanceCls.getMethod("foo", classOf[String])).isFailure) + assert( + instanceCls.getMethod("foo", classOf[String], classOf[Int]).invoke(instance, "hello", 2: Integer) == + "hello2true0" + ) + assert( + instanceCls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE) == + "hello2false0" + ) + assert( + instanceCls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean], classOf[Long]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) == + "hello2false3" + ) + + // Make sure static forwarder methods are generated + val staticCls = Class.forName("unroll.Unrolled") + staticCls.getMethods.filter(_.getName.contains("foo")).foreach(println) + + assert(scala.util.Try(staticCls.getMethod("foo", classOf[String])).isFailure) + assert( + staticCls.getMethod("foo", classOf[String], classOf[Int]).invoke(null, "hello", 2: Integer) == + "hello2true0" + ) + assert( + staticCls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean]) + .invoke(null, "hello", 2: Integer, java.lang.Boolean.FALSE) == + "hello2false0" + ) + assert( + staticCls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean], classOf[Long]) + .invoke(null, "hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) == + "hello2false3" + ) + + } +} \ No newline at end of file diff --git a/sbt-test/unroll-annot/primaryConstructor/build.sbt b/sbt-test/unroll-annot/primaryConstructor/build.sbt new file mode 100644 index 000000000000..0568d222bf5a --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/build.sbt @@ -0,0 +1,48 @@ +lazy val utils = project.in(file("utils")) + +lazy val sharedSettings = Seq( + scalacOptions ++= Seq("-Ycheck:all", "-experimental") +) + +lazy val v1 = project.in(file("v1")) + .settings(sharedSettings) + +lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Compile / unmanagedClasspath := Seq( + Attributed.blank((v1 / Compile / classDirectory).value) + ), + ) + +lazy val v2 = project.in(file("v2")) + .settings(sharedSettings) + +lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value) + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v2 / Compile / classDirectory).value) + ), + ) + +lazy val v3 = project.in(file("v3")) + .settings(sharedSettings) + +lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value), + // add v2_app, compiled against v2, to the classpath + Attributed.blank((v2_app / Runtime / classDirectory).value), + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v3 / Compile / classDirectory).value) + ), + ) diff --git a/sbt-test/unroll-annot/primaryConstructor/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/primaryConstructor/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/unroll-annot/primaryConstructor/test b/sbt-test/unroll-annot/primaryConstructor/test new file mode 100644 index 000000000000..e8e500857b0e --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/test @@ -0,0 +1,14 @@ +# compile and run a basic version of Unrolled (v1), and an app that uses it +> v1/compile +> v1_app/runMain unroll.UnrollTestMainV1 +# add a field to the case class (v2), and update the app to use it, +# and ensure the old version (v1) still links +> v2/compile +> v2_app/runMain unroll.UnrollTestMainV1 +> v2_app/runMain unroll.UnrollTestMainV2 +# add a field to the case class (v3), and update the app to use it, +# and ensure the old versions (v1, v2) still link +> v3/compile +> v3_app/runMain unroll.UnrollTestMainV1 +> v3_app/runMain unroll.UnrollTestMainV2 +> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/primaryConstructor/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/primaryConstructor/utils/src/main/scala/TestUtils.scala new file mode 100644 index 000000000000..6ac413c9fe98 --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/utils/src/main/scala/TestUtils.scala @@ -0,0 +1,12 @@ +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/sbt-test/unroll-annot/primaryConstructor/v1/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/primaryConstructor/v1/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..c7574f4346e0 --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/v1/src/main/scala/Unrolled.scala @@ -0,0 +1,5 @@ +package unroll + +class Unrolled(s: String, n: Int = 1){ + def foo = s + n +} diff --git a/sbt-test/unroll-annot/primaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/primaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..9bed955a9bc8 --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,10 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV1{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled("cow").foo, "cow1") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2") + } +} diff --git a/sbt-test/unroll-annot/primaryConstructor/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/primaryConstructor/v2/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..dfe3c2f0e46d --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/v2/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true){ + def foo = s + n + b +} diff --git a/sbt-test/unroll-annot/primaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/primaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..7a88d263a213 --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,11 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV2{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled("cow").foo, "cow1true") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2true") + logAssertStartsWith(new Unrolled("cow", 2, false).foo, "cow2false") + } +} diff --git a/sbt-test/unroll-annot/primaryConstructor/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/primaryConstructor/v3/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..b570bcaadbb3 --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/v3/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0){ + def foo = s + n + b + l +} diff --git a/sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..f05ca8808c3d --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,14 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV3{ + def main(args: Array[String]): Unit = { + UnrollTestPlatformSpecificV3() + + logAssertStartsWith(new Unrolled("cow").foo, "cow1true0") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2true0") + logAssertStartsWith(new Unrolled("cow", 2, false).foo, "cow2false0") + logAssertStartsWith(new Unrolled("cow", 2, false, 3).foo, "cow2false3") + } +} diff --git a/sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala new file mode 100644 index 000000000000..07dee69cd8a7 --- /dev/null +++ b/sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala @@ -0,0 +1,33 @@ +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + val cls = classOf[Unrolled] + + assert(scala.util.Try(cls.getConstructor(classOf[String])).isFailure) + println() + assert( + cls.getConstructor(classOf[String], classOf[Int]) + .newInstance("hello", 2: Integer) + .asInstanceOf[Unrolled] + .foo == + "hello2true0" + ) + assert( + cls.getConstructor(classOf[String], classOf[Int], classOf[Boolean]) + .newInstance("hello", 2: Integer, java.lang.Boolean.FALSE) + .asInstanceOf[Unrolled] + .foo == + "hello2false0" + ) + assert( + cls.getConstructor(classOf[String], classOf[Int], classOf[Boolean], classOf[Long]) + .newInstance("hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) + .asInstanceOf[Unrolled] + .foo == + "hello2false3" + ) + + cls.getConstructors.foreach(println) + } +} \ No newline at end of file diff --git a/sbt-test/unroll-annot/secondParameterList/build.sbt b/sbt-test/unroll-annot/secondParameterList/build.sbt new file mode 100644 index 000000000000..0568d222bf5a --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/build.sbt @@ -0,0 +1,48 @@ +lazy val utils = project.in(file("utils")) + +lazy val sharedSettings = Seq( + scalacOptions ++= Seq("-Ycheck:all", "-experimental") +) + +lazy val v1 = project.in(file("v1")) + .settings(sharedSettings) + +lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Compile / unmanagedClasspath := Seq( + Attributed.blank((v1 / Compile / classDirectory).value) + ), + ) + +lazy val v2 = project.in(file("v2")) + .settings(sharedSettings) + +lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value) + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v2 / Compile / classDirectory).value) + ), + ) + +lazy val v3 = project.in(file("v3")) + .settings(sharedSettings) + +lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value), + // add v2_app, compiled against v2, to the classpath + Attributed.blank((v2_app / Runtime / classDirectory).value), + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v3 / Compile / classDirectory).value) + ), + ) diff --git a/sbt-test/unroll-annot/secondParameterList/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/secondParameterList/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/unroll-annot/secondParameterList/test b/sbt-test/unroll-annot/secondParameterList/test new file mode 100644 index 000000000000..e8e500857b0e --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/test @@ -0,0 +1,14 @@ +# compile and run a basic version of Unrolled (v1), and an app that uses it +> v1/compile +> v1_app/runMain unroll.UnrollTestMainV1 +# add a field to the case class (v2), and update the app to use it, +# and ensure the old version (v1) still links +> v2/compile +> v2_app/runMain unroll.UnrollTestMainV1 +> v2_app/runMain unroll.UnrollTestMainV2 +# add a field to the case class (v3), and update the app to use it, +# and ensure the old versions (v1, v2) still link +> v3/compile +> v3_app/runMain unroll.UnrollTestMainV1 +> v3_app/runMain unroll.UnrollTestMainV2 +> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/secondParameterList/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/secondParameterList/utils/src/main/scala/TestUtils.scala new file mode 100644 index 000000000000..6ac413c9fe98 --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/utils/src/main/scala/TestUtils.scala @@ -0,0 +1,12 @@ +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/sbt-test/unroll-annot/secondParameterList/v1/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/secondParameterList/v1/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..f9ddac201c59 --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/v1/src/main/scala/Unrolled.scala @@ -0,0 +1,5 @@ +package unroll + +class Unrolled{ + def foo(f: String => String)(s: String) = f(s) +} diff --git a/sbt-test/unroll-annot/secondParameterList/v1_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/secondParameterList/v1_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..ef6fd3b68102 --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/v1_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,9 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV1{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled().foo(identity)("cow"), "cow") + } +} diff --git a/sbt-test/unroll-annot/secondParameterList/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/secondParameterList/v2/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..81d481deff38 --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/v2/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled{ + def foo(f: String => String)(s: String, @unroll n: Int = 1, b: Boolean = true) = f(s + n + b) +} diff --git a/sbt-test/unroll-annot/secondParameterList/v2_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/secondParameterList/v2_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..09c06869f617 --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/v2_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,11 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV2{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled().foo(identity)("cow"), "cow1true") + logAssertStartsWith(new Unrolled().foo(identity)("cow", 2), "cow2true") + logAssertStartsWith(new Unrolled().foo(identity)("cow", 2, false), "cow2false") + } +} diff --git a/sbt-test/unroll-annot/secondParameterList/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/secondParameterList/v3/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..35803d5220a8 --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/v3/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled{ + def foo(f: String => String)(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0) = f(s + n + b + l) +} diff --git a/sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..468f24956d94 --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,14 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV3{ + def main(args: Array[String]): Unit = { + UnrollTestPlatformSpecificV3() + + logAssertStartsWith(new Unrolled().foo(identity)("cow"), "cow1true0") + logAssertStartsWith(new Unrolled().foo(identity)("cow", 2), "cow2true0") + logAssertStartsWith(new Unrolled().foo(identity)("cow", 2, false), "cow2false0") + logAssertStartsWith(new Unrolled().foo(identity)("cow", 2, false, 3), "cow2false3") + } +} diff --git a/sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala new file mode 100644 index 000000000000..4663b2220cd7 --- /dev/null +++ b/sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala @@ -0,0 +1,30 @@ +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + val instance = new Unrolled() + val cls = classOf[Unrolled] + + assert( + cls.getMethod("foo", classOf[String => String], classOf[String]) + .invoke(instance, identity[String](_), "hello") == + "hello1true0" + ) + + assert( + scala.util.Try(cls.getMethod("foo", classOf[String => String], classOf[String], classOf[Int])).isFailure + ) + assert( + cls.getMethod("foo", classOf[String => String], classOf[String], classOf[Int], classOf[Boolean]) + .invoke(instance, identity[String](_), "hello", 2: Integer, java.lang.Boolean.FALSE) == + "hello2false0" + ) + assert( + cls.getMethod("foo", classOf[String => String], classOf[String], classOf[Int], classOf[Boolean], classOf[Long]) + .invoke(instance, identity[String](_), "hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) == + "hello2false3" + ) + + cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + } +} \ No newline at end of file diff --git a/sbt-test/unroll-annot/secondaryConstructor/build.sbt b/sbt-test/unroll-annot/secondaryConstructor/build.sbt new file mode 100644 index 000000000000..0568d222bf5a --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/build.sbt @@ -0,0 +1,48 @@ +lazy val utils = project.in(file("utils")) + +lazy val sharedSettings = Seq( + scalacOptions ++= Seq("-Ycheck:all", "-experimental") +) + +lazy val v1 = project.in(file("v1")) + .settings(sharedSettings) + +lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Compile / unmanagedClasspath := Seq( + Attributed.blank((v1 / Compile / classDirectory).value) + ), + ) + +lazy val v2 = project.in(file("v2")) + .settings(sharedSettings) + +lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value) + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v2 / Compile / classDirectory).value) + ), + ) + +lazy val v3 = project.in(file("v3")) + .settings(sharedSettings) + +lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value), + // add v2_app, compiled against v2, to the classpath + Attributed.blank((v2_app / Runtime / classDirectory).value), + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v3 / Compile / classDirectory).value) + ), + ) diff --git a/sbt-test/unroll-annot/secondaryConstructor/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/secondaryConstructor/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/unroll-annot/secondaryConstructor/test b/sbt-test/unroll-annot/secondaryConstructor/test new file mode 100644 index 000000000000..e8e500857b0e --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/test @@ -0,0 +1,14 @@ +# compile and run a basic version of Unrolled (v1), and an app that uses it +> v1/compile +> v1_app/runMain unroll.UnrollTestMainV1 +# add a field to the case class (v2), and update the app to use it, +# and ensure the old version (v1) still links +> v2/compile +> v2_app/runMain unroll.UnrollTestMainV1 +> v2_app/runMain unroll.UnrollTestMainV2 +# add a field to the case class (v3), and update the app to use it, +# and ensure the old versions (v1, v2) still link +> v3/compile +> v3_app/runMain unroll.UnrollTestMainV1 +> v3_app/runMain unroll.UnrollTestMainV2 +> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/secondaryConstructor/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/secondaryConstructor/utils/src/main/scala/TestUtils.scala new file mode 100644 index 000000000000..6ac413c9fe98 --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/utils/src/main/scala/TestUtils.scala @@ -0,0 +1,12 @@ +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/sbt-test/unroll-annot/secondaryConstructor/v1/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/secondaryConstructor/v1/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..529a3fc66de3 --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/v1/src/main/scala/Unrolled.scala @@ -0,0 +1,9 @@ +package unroll + +class Unrolled(){ + var foo = "" + def this(s: String, n: Int = 1) = { + this() + foo = s + n + } +} diff --git a/sbt-test/unroll-annot/secondaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/secondaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..9bed955a9bc8 --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,10 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV1{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled("cow").foo, "cow1") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2") + } +} diff --git a/sbt-test/unroll-annot/secondaryConstructor/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/secondaryConstructor/v2/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..382066698f31 --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/v2/src/main/scala/Unrolled.scala @@ -0,0 +1,12 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled() { + var foo = "" + + def this(s: String, n: Int = 1, @unroll b: Boolean = true) = { + this() + foo = s + n + b + } +} diff --git a/sbt-test/unroll-annot/secondaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/secondaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..7a88d263a213 --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,11 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV2{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled("cow").foo, "cow1true") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2true") + logAssertStartsWith(new Unrolled("cow", 2, false).foo, "cow2false") + } +} diff --git a/sbt-test/unroll-annot/secondaryConstructor/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/secondaryConstructor/v3/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..89411d6576ca --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/v3/src/main/scala/Unrolled.scala @@ -0,0 +1,12 @@ +package unroll + +import scala.annotation.unroll + +class Unrolled() { + var foo = "" + + def this(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = { + this() + foo = s + n + b + l + } +} diff --git a/sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..f05ca8808c3d --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,14 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV3{ + def main(args: Array[String]): Unit = { + UnrollTestPlatformSpecificV3() + + logAssertStartsWith(new Unrolled("cow").foo, "cow1true0") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2true0") + logAssertStartsWith(new Unrolled("cow", 2, false).foo, "cow2false0") + logAssertStartsWith(new Unrolled("cow", 2, false, 3).foo, "cow2false3") + } +} diff --git a/sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala new file mode 100644 index 000000000000..07dee69cd8a7 --- /dev/null +++ b/sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala @@ -0,0 +1,33 @@ +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + val cls = classOf[Unrolled] + + assert(scala.util.Try(cls.getConstructor(classOf[String])).isFailure) + println() + assert( + cls.getConstructor(classOf[String], classOf[Int]) + .newInstance("hello", 2: Integer) + .asInstanceOf[Unrolled] + .foo == + "hello2true0" + ) + assert( + cls.getConstructor(classOf[String], classOf[Int], classOf[Boolean]) + .newInstance("hello", 2: Integer, java.lang.Boolean.FALSE) + .asInstanceOf[Unrolled] + .foo == + "hello2false0" + ) + assert( + cls.getConstructor(classOf[String], classOf[Int], classOf[Boolean], classOf[Long]) + .newInstance("hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) + .asInstanceOf[Unrolled] + .foo == + "hello2false3" + ) + + cls.getConstructors.foreach(println) + } +} \ No newline at end of file diff --git a/sbt-test/unroll-annot/traitMethod/build.sbt b/sbt-test/unroll-annot/traitMethod/build.sbt new file mode 100644 index 000000000000..0568d222bf5a --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/build.sbt @@ -0,0 +1,48 @@ +lazy val utils = project.in(file("utils")) + +lazy val sharedSettings = Seq( + scalacOptions ++= Seq("-Ycheck:all", "-experimental") +) + +lazy val v1 = project.in(file("v1")) + .settings(sharedSettings) + +lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Compile / unmanagedClasspath := Seq( + Attributed.blank((v1 / Compile / classDirectory).value) + ), + ) + +lazy val v2 = project.in(file("v2")) + .settings(sharedSettings) + +lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value) + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v2 / Compile / classDirectory).value) + ), + ) + +lazy val v3 = project.in(file("v3")) + .settings(sharedSettings) + +lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) + .settings(sharedSettings) + .settings( + Runtime / unmanagedClasspath := Seq( + // add v1_app, compiled against v1, to the classpath + Attributed.blank((v1_app / Runtime / classDirectory).value), + // add v2_app, compiled against v2, to the classpath + Attributed.blank((v2_app / Runtime / classDirectory).value), + ), + Compile / unmanagedClasspath := Seq( + Attributed.blank((v3 / Compile / classDirectory).value) + ), + ) diff --git a/sbt-test/unroll-annot/traitMethod/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/traitMethod/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/unroll-annot/traitMethod/test b/sbt-test/unroll-annot/traitMethod/test new file mode 100644 index 000000000000..e8e500857b0e --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/test @@ -0,0 +1,14 @@ +# compile and run a basic version of Unrolled (v1), and an app that uses it +> v1/compile +> v1_app/runMain unroll.UnrollTestMainV1 +# add a field to the case class (v2), and update the app to use it, +# and ensure the old version (v1) still links +> v2/compile +> v2_app/runMain unroll.UnrollTestMainV1 +> v2_app/runMain unroll.UnrollTestMainV2 +# add a field to the case class (v3), and update the app to use it, +# and ensure the old versions (v1, v2) still link +> v3/compile +> v3_app/runMain unroll.UnrollTestMainV1 +> v3_app/runMain unroll.UnrollTestMainV2 +> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/traitMethod/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/traitMethod/utils/src/main/scala/TestUtils.scala new file mode 100644 index 000000000000..6ac413c9fe98 --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/utils/src/main/scala/TestUtils.scala @@ -0,0 +1,12 @@ +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/sbt-test/unroll-annot/traitMethod/v1/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/traitMethod/v1/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..eaadde758ac7 --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/v1/src/main/scala/Unrolled.scala @@ -0,0 +1,7 @@ +package unroll + +trait Unrolled{ + def foo(s: String, n: Int = 1) = s + n +} + +object Unrolled extends Unrolled \ No newline at end of file diff --git a/sbt-test/unroll-annot/traitMethod/v1_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/traitMethod/v1_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..f1c7c8bb88a4 --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/v1_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,14 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV1{ + def main(args: Array[String]): Unit = { + val unrolled = new Unrolled{} + logAssertStartsWith(unrolled.foo("cow"), "cow1") + logAssertStartsWith(unrolled.foo("cow", 2), "cow2") + + logAssertStartsWith(Unrolled.foo("cow"), "cow1") + logAssertStartsWith(Unrolled.foo("cow", 2), "cow2") + } +} diff --git a/sbt-test/unroll-annot/traitMethod/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/traitMethod/v2/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..7d40ff17b846 --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/v2/src/main/scala/Unrolled.scala @@ -0,0 +1,9 @@ +package unroll + +import scala.annotation.unroll + +trait Unrolled{ + def foo(s: String, n: Int = 1, @unroll b: Boolean = true) = s + n + b +} + +object Unrolled extends Unrolled \ No newline at end of file diff --git a/sbt-test/unroll-annot/traitMethod/v2_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/traitMethod/v2_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..30eb52263e50 --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/v2_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,16 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV2{ + def main(args: Array[String]): Unit = { + val unrolled = new Unrolled{} + logAssertStartsWith(unrolled.foo("cow"), "cow1true") + logAssertStartsWith(unrolled.foo("cow", 2), "cow2true") + logAssertStartsWith(unrolled.foo("cow", 2, false), "cow2false") + + logAssertStartsWith(Unrolled.foo("cow"), "cow1true") + logAssertStartsWith(Unrolled.foo("cow", 2), "cow2true") + logAssertStartsWith(Unrolled.foo("cow", 2, false), "cow2false") + } +} diff --git a/sbt-test/unroll-annot/traitMethod/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/traitMethod/v3/src/main/scala/Unrolled.scala new file mode 100644 index 000000000000..085ecea52adf --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/v3/src/main/scala/Unrolled.scala @@ -0,0 +1,9 @@ +package unroll + +import scala.annotation.unroll + +trait Unrolled{ + def foo(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = s + n + b + l +} + +object Unrolled extends Unrolled \ No newline at end of file diff --git a/sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestMain.scala b/sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestMain.scala new file mode 100644 index 000000000000..89154b958161 --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestMain.scala @@ -0,0 +1,20 @@ +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV3{ + def main(args: Array[String]): Unit = { + UnrollTestPlatformSpecificV3() + + val unrolled = new Unrolled{} + logAssertStartsWith(unrolled.foo("cow"), "cow1true0") + logAssertStartsWith(unrolled.foo("cow", 2), "cow2true0") + logAssertStartsWith(unrolled.foo("cow", 2, false), "cow2false0") + logAssertStartsWith(unrolled.foo("cow", 2, false, 3), "cow2false3") + + logAssertStartsWith(Unrolled.foo("cow"), "cow1true0") + logAssertStartsWith(Unrolled.foo("cow", 2), "cow2true0") + logAssertStartsWith(Unrolled.foo("cow", 2, false), "cow2false0") + logAssertStartsWith(Unrolled.foo("cow", 2, false, 3), "cow2false3") + } +} diff --git a/sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala new file mode 100644 index 000000000000..e8367679233f --- /dev/null +++ b/sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala @@ -0,0 +1,28 @@ +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + val instance = new Unrolled {} + val cls = classOf[Unrolled] + + assert(scala.util.Try(cls.getMethod("foo", classOf[String])).isFailure) + println() + assert( + cls.getMethod("foo", classOf[String], classOf[Int]).invoke(instance, "hello", 2: Integer) == + "hello2true0" + ) + assert( + cls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE) == + "hello2false0" + ) + assert( + cls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean], classOf[Long]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) == + "hello2false3" + ) + + cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + + } +} \ No newline at end of file diff --git a/tests/run/unroll-caseclass.check b/tests/run/unroll-caseclass.check new file mode 100644 index 000000000000..3d0ebd182b9f --- /dev/null +++ b/tests/run/unroll-caseclass.check @@ -0,0 +1,37 @@ +=== Unrolled Test V1 === +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "hello31337" + "true0" +=== Unrolled Test V2 === +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "hello31337false" + "0" +=== Unrolled Test V3 === +Assertion passed: found "hello31337false12345" +as expected, no constructor for Unrolled(s: String) +public example.Unrolled(java.lang.String,int,boolean,long) +public example.Unrolled(java.lang.String,int) +public example.Unrolled(java.lang.String,int,boolean) +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false9" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false9" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false9" diff --git a/tests/run/unroll-caseclass/Test_4.scala b/tests/run/unroll-caseclass/Test_4.scala new file mode 100644 index 000000000000..3040e9133652 --- /dev/null +++ b/tests/run/unroll-caseclass/Test_4.scala @@ -0,0 +1,11 @@ +//> using options -experimental +import example.* +// !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check +@main def Test(): Unit = { + println("=== Unrolled Test V1 ===") + UnrollTestMainV1.main(Array.empty) + println("=== Unrolled Test V2 ===") + UnrollTestMainV2.main(Array.empty) + println("=== Unrolled Test V3 ===") + UnrollTestMainV3.main(Array.empty) +} diff --git a/tests/run/unroll-caseclass/unrolledV1_1.scala b/tests/run/unroll-caseclass/unrolledV1_1.scala new file mode 100644 index 000000000000..a07e8499442e --- /dev/null +++ b/tests/run/unroll-caseclass/unrolledV1_1.scala @@ -0,0 +1,61 @@ +//> using options -experimental +package example +// !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check + +// import scala.annotation.unroll <- v1 did not need to unroll yet + +// v1 of Unrolled +case class Unrolled(s: String, n: Int = 1) { + def foo = s + n +} + +// v1: original code that compiled against v1 of Unrolled +object UnrollTestMainV1 extends TestUtil { + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled("cow").foo, "cow1") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2") + + logAssertStartsWith(Unrolled("cow").foo, "cow1") + logAssertStartsWith(Unrolled("cow", 2).foo, "cow2") + + val unrolled = Unrolled("cow") + + logAssertStartsWith(unrolled.copy(s = "cow").foo, "cow1") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2).foo, "cow2") + + val Unrolled(s, n) = unrolled + + assert(s == "cow") + assert(n == 1) + + UnrollTestScalaSpecificV1.test() + } +} + +object UnrollTestScalaSpecificV1 extends TestUtil { + def test() = { + val unrolled = summon[scala.deriving.Mirror.Of[Unrolled]].fromProduct( + new Product{ + def canEqual(that: Any) = true + def productArity = 2 + def productElement(n: Int) = n match{ + case 0 => "hello" + case 1 => 31337 + } + } + ) + + logAssertStartsWith(unrolled.foo, "hello31337") + } +} + +trait TestUtil { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/tests/run/unroll-caseclass/unrolledV2_2.scala b/tests/run/unroll-caseclass/unrolledV2_2.scala new file mode 100644 index 000000000000..e1affa387652 --- /dev/null +++ b/tests/run/unroll-caseclass/unrolledV2_2.scala @@ -0,0 +1,55 @@ +//> using options -experimental +package example +// !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check + +import scala.annotation.unroll + +// v2 of Unrolled +case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true){ + def foo = s + n + b +} + +// v2: ammendments to code that exercise a new parameter +object UnrollTestMainV2 extends TestUtil { + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled("cow").foo, "cow1true") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2true") + logAssertStartsWith(new Unrolled("cow", 2, false).foo, "cow2false") + + logAssertStartsWith(Unrolled("cow").foo, "cow1true") + logAssertStartsWith(Unrolled("cow", 2).foo, "cow2true") + logAssertStartsWith(Unrolled("cow", 2, false).foo, "cow2false") + + val unrolled = Unrolled("cow") + + logAssertStartsWith(unrolled.copy(s = "cow").foo, "cow1true") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2).foo, "cow2true") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2, b = false).foo, "cow2false") + + val Unrolled(s, n, b) = unrolled + + assert(s == "cow") + assert(n == 1) + assert(b == true) + + UnrollTestScalaSpecificV2.test() + } +} + +object UnrollTestScalaSpecificV2 extends TestUtil { + def test() = { + val unrolled = summon[scala.deriving.Mirror.Of[Unrolled]].fromProduct( + new Product { + def canEqual(that: Any) = true + def productArity = 3 + def productElement(n: Int) = n match { + case 0 => "hello" + case 1 => 31337 + case 2 => false + } + } + + ) + logAssertStartsWith(unrolled.foo, "hello31337false") + } +} diff --git a/tests/run/unroll-caseclass/unrolledV3_3.scala b/tests/run/unroll-caseclass/unrolledV3_3.scala new file mode 100644 index 000000000000..9bb2d66a0039 --- /dev/null +++ b/tests/run/unroll-caseclass/unrolledV3_3.scala @@ -0,0 +1,95 @@ +//> using options -experimental +package example +// !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check + +import scala.annotation.unroll + +// v3 of Unrolled +case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0){ + def foo = s + n + b + l +} + +// v3: ammendments to code that exercise a new parameter +object UnrollTestMainV3 extends TestUtil { + def main(args: Array[String]): Unit = { + UnrollTestScalaSpecificV3() + UnrollTestPlatformSpecificV3() + + logAssertStartsWith(new Unrolled("cow").foo, "cow1true0") + logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2true0") + logAssertStartsWith(new Unrolled("cow", 2, false).foo, "cow2false0") + logAssertStartsWith(new Unrolled("cow", 2, false, 9L).foo, "cow2false9") + + logAssertStartsWith(Unrolled("cow").foo, "cow1true0") + logAssertStartsWith(Unrolled("cow", 2).foo, "cow2true0") + logAssertStartsWith(Unrolled("cow", 2, false).foo, "cow2false0") + logAssertStartsWith(Unrolled("cow", 2, false, 9L).foo, "cow2false9") + + val unrolled = Unrolled("cow") + + logAssertStartsWith(unrolled.copy(s = "cow").foo, "cow1true0") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2).foo, "cow2true0") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2, b = false).foo, "cow2false0") + logAssertStartsWith(unrolled.copy(s = "cow", n = 2, b = false, l = 9L).foo, "cow2false9") + + val Unrolled(s, n, b, l) = unrolled + + assert(s == "cow") + assert(n == 1) + assert(b == true) + assert(l == 0L) + + + } +} + +object UnrollTestScalaSpecificV3 extends TestUtil { + def apply() = { + val unrolled = summon[scala.deriving.Mirror.Of[Unrolled]].fromProduct( + new Product { + def canEqual(that: Any) = true + def productArity = 4 + def productElement(n: Int) = n match { + case 0 => "hello" + case 1 => 31337 + case 2 => false + case 3 => 12345L + } + } + ) + + logAssertStartsWith(unrolled.foo, "hello31337false12345") + } +} + +object UnrollTestPlatformSpecificV3 extends TestUtil { + def apply() = { + val cls = classOf[Unrolled] + + assert(scala.util.Try(cls.getConstructor(classOf[String])).isFailure) + println("as expected, no constructor for Unrolled(s: String)") + assert( + cls.getConstructor(classOf[String], classOf[Int]) + .newInstance("hello", 2: Integer) + .asInstanceOf[Unrolled] + .foo == + "hello2true0" + ) + assert( + cls.getConstructor(classOf[String], classOf[Int], classOf[Boolean]) + .newInstance("hello", 2: Integer, java.lang.Boolean.FALSE) + .asInstanceOf[Unrolled] + .foo == + "hello2false0" + ) + assert( + cls.getConstructor(classOf[String], classOf[Int], classOf[Boolean], classOf[Long]) + .newInstance("hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) + .asInstanceOf[Unrolled] + .foo == + "hello2false3" + ) + + cls.getConstructors.foreach(println) + } +} From 3f2925f599b43d7212562a2bd086a7d71994fca9 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Tue, 1 Oct 2024 12:20:41 +0200 Subject: [PATCH 2/5] SIP 61 - Improve checks and type substitution for forwarders - add documentation page - move before pickling, fix errors due to unpickling select of Invisible definitions and incorrect spans - forwarders now only call the original method. - detect in posttyper which compilation units have unrolled definitions - detect clashes with forwarders and existing definitions - check for illegal uses of @unroll - implementation restriction: no unroll for trait parameters - unlink replaced definitions - check for default parameter - fix invalid pattern in generateFromProduct - sbt-test/scripted: fork when running with unmanaged classpaths - update stdlibExperimentalDefinitions.scala - skip reflection test on scala.js - require final methods, remove special treatment of abstract methods - fix order of printing in test - better error when multiple parameter lists with unroll - Move sbt-scripted tests to vulpix suites --- .../dotty/tools/dotc/CompilationUnit.scala | 3 + compiler/src/dotty/tools/dotc/Compiler.scala | 2 +- .../tools/dotc/core/tasty/TreePickler.scala | 12 +- .../tools/dotc/reporting/ErrorMessageID.scala | 1 + .../dotty/tools/dotc/reporting/messages.scala | 31 +- .../tools/dotc/transform/PostTyper.scala | 43 +++ .../dotc/transform/UnrollDefinitions.scala | 358 ++++++++++++++++++ .../tools/dotc/transform/UnrollDefs.scala | 279 -------------- .../tools/dotc/typer/CrossVersionChecks.scala | 27 +- .../reference/experimental/unrolled-defs.md | 156 ++++++++ docs/sidebar.yml | 1 + library/src/scala/annotation/unroll.scala | 8 + sbt-test/unroll-annot/caseclass/build.sbt | 48 --- .../project/DottyInjectedPlugin.scala | 12 - sbt-test/unroll-annot/caseclass/test | 14 - sbt-test/unroll-annot/classMethod/build.sbt | 48 --- .../project/DottyInjectedPlugin.scala | 12 - sbt-test/unroll-annot/classMethod/test | 14 - .../v2/src/main/scala/Unrolled.scala | 7 - .../v3/src/main/scala/Unrolled.scala | 7 - sbt-test/unroll-annot/curriedMethod/build.sbt | 48 --- .../project/DottyInjectedPlugin.scala | 12 - sbt-test/unroll-annot/curriedMethod/test | 14 - .../v2/src/main/scala/Unrolled.scala | 7 - .../v3/src/main/scala/Unrolled.scala | 7 - .../unroll-annot/methodWithImplicit/build.sbt | 48 --- .../project/DottyInjectedPlugin.scala | 12 - sbt-test/unroll-annot/methodWithImplicit/test | 14 - .../v2/src/main/scala/Unrolled.scala | 7 - .../v3/src/main/scala/Unrolled.scala | 7 - sbt-test/unroll-annot/objectMethod/build.sbt | 48 --- .../project/DottyInjectedPlugin.scala | 12 - sbt-test/unroll-annot/objectMethod/test | 14 - .../utils/src/main/scala/TestUtils.scala | 12 - .../v2/src/main/scala/Unrolled.scala | 7 - .../v3/src/main/scala/Unrolled.scala | 7 - .../unroll-annot/primaryConstructor/build.sbt | 48 --- .../project/DottyInjectedPlugin.scala | 12 - sbt-test/unroll-annot/primaryConstructor/test | 14 - .../utils/src/main/scala/TestUtils.scala | 12 - .../secondParameterList/build.sbt | 48 --- .../project/DottyInjectedPlugin.scala | 12 - .../unroll-annot/secondParameterList/test | 14 - .../utils/src/main/scala/TestUtils.scala | 12 - .../v2/src/main/scala/Unrolled.scala | 7 - .../v3/src/main/scala/Unrolled.scala | 7 - .../secondaryConstructor/build.sbt | 48 --- .../project/DottyInjectedPlugin.scala | 12 - .../unroll-annot/secondaryConstructor/test | 14 - .../utils/src/main/scala/TestUtils.scala | 12 - sbt-test/unroll-annot/traitMethod/build.sbt | 48 --- .../project/DottyInjectedPlugin.scala | 12 - sbt-test/unroll-annot/traitMethod/test | 14 - .../utils/src/main/scala/TestUtils.scala | 12 - .../v2/src/main/scala/Unrolled.scala | 9 - .../v3/src/main/scala/Unrolled.scala | 9 - tests/neg/unroll-abstractMethod.check | 8 + tests/neg/unroll-abstractMethod.scala | 11 + tests/neg/unroll-clash.check | 12 + tests/neg/unroll-clash.scala | 18 + tests/neg/unroll-duped.check | 12 + tests/neg/unroll-duped.scala | 27 ++ tests/neg/unroll-illegal.check | 36 ++ tests/neg/unroll-illegal.scala | 29 ++ tests/neg/unroll-illegal2.check | 4 + tests/neg/unroll-illegal2.scala | 9 + tests/neg/unroll-illegal3.check | 12 + tests/neg/unroll-illegal3.scala | 17 + tests/neg/unroll-multipleParams.check | 4 + tests/neg/unroll-multipleParams.scala | 7 + tests/neg/unroll-no-default.check | 4 + tests/neg/unroll-no-default.scala | 7 + tests/neg/unroll-traitConstructor.check | 4 + tests/neg/unroll-traitConstructor.scala | 8 + .../stdlibExperimentalDefinitions.scala | 5 +- .../TestUtils_1.scala | 1 + .../unroll-caseclass-integration/Test_4.scala | 8 + .../UnrollTestMain_1.scala | 1 + .../UnrollTestMain_2.scala | 1 + .../UnrollTestMain_3.scala | 1 + .../UnrollTestPlatformSpecific_3.scala | 4 +- .../UnrollTestScalaSpecific_1.scala | 3 +- .../UnrollTestScalaSpecific_2.scala | 3 +- .../UnrollTestScalaSpecific_3.scala | 3 +- .../Unrolled_1.scala | 1 + .../Unrolled_2.scala | 1 + .../Unrolled_3.scala | 1 + tests/run/unroll-caseclass.check | 2 +- tests/run/unroll-caseclass/Test_4.scala | 2 + tests/run/unroll-caseclass/unrolledV1_1.scala | 1 + tests/run/unroll-caseclass/unrolledV2_2.scala | 1 + tests/run/unroll-caseclass/unrolledV3_3.scala | 3 +- .../TestUtils_1.scala | 1 + .../Test_4.scala | 8 + .../UnrollTestMain_1.scala | 1 + .../UnrollTestMain_2.scala | 1 + .../UnrollTestMain_3.scala | 1 + .../UnrollTestPlatformSpecific_3.scala | 4 +- .../Unrolled_1.scala | 1 + .../Unrolled_2.scala | 8 + .../Unrolled_3.scala | 8 + .../TestUtils_1.scala | 1 + .../Test_4.scala | 8 + .../UnrollTestMain_1.scala | 1 + .../UnrollTestMain_2.scala | 1 + .../UnrollTestMain_3.scala | 1 + .../UnrollTestPlatformSpecific_3.scala | 4 +- .../Unrolled_1.scala | 1 + .../Unrolled_2.scala | 8 + .../Unrolled_3.scala | 8 + .../TestUtils_1.scala | 1 + .../Test_4.scala | 8 + .../UnrollTestMain_1.scala | 10 + .../UnrollTestMain_2.scala | 12 + .../UnrollTestMain_3.scala | 15 + .../UnrollTestPlatformSpecific_3.scala | 29 ++ .../Unrolled_1.scala | 6 + .../Unrolled_2.scala | 8 + .../Unrolled_3.scala | 8 + tests/run/unroll-inferredFinal.scala | 17 + .../TestUtils_1.scala | 13 + .../Test_4.scala | 8 + .../UnrollTestMain_1.scala | 1 + .../UnrollTestMain_2.scala | 1 + .../UnrollTestMain_3.scala | 1 + .../UnrollTestPlatformSpecific_3.scala | 6 +- .../Unrolled_1.scala | 1 + .../Unrolled_2.scala | 8 + .../Unrolled_3.scala | 8 + tests/run/unroll-multiple.scala | 72 ++++ .../TestUtils_1.scala | 13 + .../Test_4.scala | 8 + .../UnrollTestMain_1.scala | 1 + .../UnrollTestMain_2.scala | 1 + .../UnrollTestMain_3.scala | 1 + .../UnrollTestPlatformSpecific_3.scala | 4 +- .../Unrolled_1.scala | 1 + .../Unrolled_2.scala | 8 + .../Unrolled_3.scala | 8 + .../TestUtils_1.scala | 13 + .../Test_4.scala | 8 + .../UnrollTestMain_1.scala | 1 + .../UnrollTestMain_2.scala | 1 + .../UnrollTestMain_3.scala | 1 + .../UnrollTestPlatformSpecific_3.scala | 4 +- .../Unrolled_1.scala | 1 + .../Unrolled_2.scala | 3 +- .../Unrolled_3.scala | 1 + .../TestUtils_1.scala | 13 + .../Test_4.scala | 8 + .../UnrollTestMain_1.scala | 1 + .../UnrollTestMain_2.scala | 1 + .../UnrollTestMain_3.scala | 1 + .../UnrollTestPlatformSpecific_3.scala | 4 +- .../Unrolled_1.scala | 1 + .../Unrolled_2.scala | 8 + .../Unrolled_3.scala | 8 + .../TestUtils_1.scala | 13 + .../Test_4.scala | 8 + .../UnrollTestMain_1.scala | 1 + .../UnrollTestMain_2.scala | 1 + .../UnrollTestMain_3.scala | 1 + .../UnrollTestPlatformSpecific_3.scala | 4 +- .../Unrolled_1.scala | 1 + .../Unrolled_2.scala | 1 + .../Unrolled_3.scala | 1 + .../TestUtils_1.scala | 13 + .../Test_4.scala | 8 + .../UnrollTestMain_1.scala | 1 + .../UnrollTestMain_2.scala | 1 + .../UnrollTestMain_3.scala | 1 + .../UnrollTestPlatformSpecific_3.scala | 4 +- .../Unrolled_1.scala | 1 + .../Unrolled_2.scala | 10 + .../Unrolled_3.scala | 10 + tests/run/unroll-traitMethod/Test_2.scala | 6 + tests/run/unroll-traitMethod/Unrolled_1.scala | 10 + 177 files changed, 1403 insertions(+), 1121 deletions(-) create mode 100644 compiler/src/dotty/tools/dotc/transform/UnrollDefinitions.scala delete mode 100644 compiler/src/dotty/tools/dotc/transform/UnrollDefs.scala create mode 100644 docs/_docs/reference/experimental/unrolled-defs.md delete mode 100644 sbt-test/unroll-annot/caseclass/build.sbt delete mode 100644 sbt-test/unroll-annot/caseclass/project/DottyInjectedPlugin.scala delete mode 100644 sbt-test/unroll-annot/caseclass/test delete mode 100644 sbt-test/unroll-annot/classMethod/build.sbt delete mode 100644 sbt-test/unroll-annot/classMethod/project/DottyInjectedPlugin.scala delete mode 100644 sbt-test/unroll-annot/classMethod/test delete mode 100644 sbt-test/unroll-annot/classMethod/v2/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/classMethod/v3/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/curriedMethod/build.sbt delete mode 100644 sbt-test/unroll-annot/curriedMethod/project/DottyInjectedPlugin.scala delete mode 100644 sbt-test/unroll-annot/curriedMethod/test delete mode 100644 sbt-test/unroll-annot/curriedMethod/v2/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/curriedMethod/v3/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/methodWithImplicit/build.sbt delete mode 100644 sbt-test/unroll-annot/methodWithImplicit/project/DottyInjectedPlugin.scala delete mode 100644 sbt-test/unroll-annot/methodWithImplicit/test delete mode 100644 sbt-test/unroll-annot/methodWithImplicit/v2/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/methodWithImplicit/v3/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/objectMethod/build.sbt delete mode 100644 sbt-test/unroll-annot/objectMethod/project/DottyInjectedPlugin.scala delete mode 100644 sbt-test/unroll-annot/objectMethod/test delete mode 100644 sbt-test/unroll-annot/objectMethod/utils/src/main/scala/TestUtils.scala delete mode 100644 sbt-test/unroll-annot/objectMethod/v2/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/objectMethod/v3/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/primaryConstructor/build.sbt delete mode 100644 sbt-test/unroll-annot/primaryConstructor/project/DottyInjectedPlugin.scala delete mode 100644 sbt-test/unroll-annot/primaryConstructor/test delete mode 100644 sbt-test/unroll-annot/primaryConstructor/utils/src/main/scala/TestUtils.scala delete mode 100644 sbt-test/unroll-annot/secondParameterList/build.sbt delete mode 100644 sbt-test/unroll-annot/secondParameterList/project/DottyInjectedPlugin.scala delete mode 100644 sbt-test/unroll-annot/secondParameterList/test delete mode 100644 sbt-test/unroll-annot/secondParameterList/utils/src/main/scala/TestUtils.scala delete mode 100644 sbt-test/unroll-annot/secondParameterList/v2/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/secondParameterList/v3/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/secondaryConstructor/build.sbt delete mode 100644 sbt-test/unroll-annot/secondaryConstructor/project/DottyInjectedPlugin.scala delete mode 100644 sbt-test/unroll-annot/secondaryConstructor/test delete mode 100644 sbt-test/unroll-annot/secondaryConstructor/utils/src/main/scala/TestUtils.scala delete mode 100644 sbt-test/unroll-annot/traitMethod/build.sbt delete mode 100644 sbt-test/unroll-annot/traitMethod/project/DottyInjectedPlugin.scala delete mode 100644 sbt-test/unroll-annot/traitMethod/test delete mode 100644 sbt-test/unroll-annot/traitMethod/utils/src/main/scala/TestUtils.scala delete mode 100644 sbt-test/unroll-annot/traitMethod/v2/src/main/scala/Unrolled.scala delete mode 100644 sbt-test/unroll-annot/traitMethod/v3/src/main/scala/Unrolled.scala create mode 100644 tests/neg/unroll-abstractMethod.check create mode 100644 tests/neg/unroll-abstractMethod.scala create mode 100644 tests/neg/unroll-clash.check create mode 100644 tests/neg/unroll-clash.scala create mode 100644 tests/neg/unroll-duped.check create mode 100644 tests/neg/unroll-duped.scala create mode 100644 tests/neg/unroll-illegal.check create mode 100644 tests/neg/unroll-illegal.scala create mode 100644 tests/neg/unroll-illegal2.check create mode 100644 tests/neg/unroll-illegal2.scala create mode 100644 tests/neg/unroll-illegal3.check create mode 100644 tests/neg/unroll-illegal3.scala create mode 100644 tests/neg/unroll-multipleParams.check create mode 100644 tests/neg/unroll-multipleParams.scala create mode 100644 tests/neg/unroll-no-default.check create mode 100644 tests/neg/unroll-no-default.scala create mode 100644 tests/neg/unroll-traitConstructor.check create mode 100644 tests/neg/unroll-traitConstructor.scala rename sbt-test/unroll-annot/caseclass/utils/src/main/scala/TestUtils.scala => tests/run/unroll-caseclass-integration/TestUtils_1.scala (91%) create mode 100644 tests/run/unroll-caseclass-integration/Test_4.scala rename sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-caseclass-integration/UnrollTestMain_1.scala (95%) rename sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-caseclass-integration/UnrollTestMain_2.scala (96%) rename sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-caseclass-integration/UnrollTestMain_3.scala (97%) rename sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala => tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala (94%) rename sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestScalaSpecific.scala => tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_1.scala (78%) rename sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestScalaSpecific.scala => tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_2.scala (79%) rename sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestScalaSpecific.scala => tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_3.scala (80%) rename sbt-test/unroll-annot/caseclass/v1/src/main/scala/Unrolled.scala => tests/run/unroll-caseclass-integration/Unrolled_1.scala (71%) rename sbt-test/unroll-annot/caseclass/v2/src/main/scala/Unrolled.scala => tests/run/unroll-caseclass-integration/Unrolled_2.scala (81%) rename sbt-test/unroll-annot/caseclass/v3/src/main/scala/Unrolled.scala => tests/run/unroll-caseclass-integration/Unrolled_3.scala (84%) rename sbt-test/unroll-annot/classMethod/utils/src/main/scala/TestUtils.scala => tests/run/unroll-classMethod-integration/TestUtils_1.scala (91%) create mode 100644 tests/run/unroll-classMethod-integration/Test_4.scala rename sbt-test/unroll-annot/classMethod/v1_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-classMethod-integration/UnrollTestMain_1.scala (85%) rename sbt-test/unroll-annot/classMethod/v2_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-classMethod-integration/UnrollTestMain_2.scala (91%) rename sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-classMethod-integration/UnrollTestMain_3.scala (93%) rename sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala => tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala (94%) rename sbt-test/unroll-annot/classMethod/v1/src/main/scala/Unrolled.scala => tests/run/unroll-classMethod-integration/Unrolled_1.scala (64%) create mode 100644 tests/run/unroll-classMethod-integration/Unrolled_2.scala create mode 100644 tests/run/unroll-classMethod-integration/Unrolled_3.scala rename sbt-test/unroll-annot/curriedMethod/utils/src/main/scala/TestUtils.scala => tests/run/unroll-curriedMethod-integration/TestUtils_1.scala (91%) create mode 100644 tests/run/unroll-curriedMethod-integration/Test_4.scala rename sbt-test/unroll-annot/curriedMethod/v1_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-curriedMethod-integration/UnrollTestMain_1.scala (86%) rename sbt-test/unroll-annot/curriedMethod/v2_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-curriedMethod-integration/UnrollTestMain_2.scala (91%) rename sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-curriedMethod-integration/UnrollTestMain_3.scala (93%) rename sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala => tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala (95%) rename sbt-test/unroll-annot/curriedMethod/v1/src/main/scala/Unrolled.scala => tests/run/unroll-curriedMethod-integration/Unrolled_1.scala (72%) create mode 100644 tests/run/unroll-curriedMethod-integration/Unrolled_2.scala create mode 100644 tests/run/unroll-curriedMethod-integration/Unrolled_3.scala rename sbt-test/unroll-annot/methodWithImplicit/utils/src/main/scala/TestUtils.scala => tests/run/unroll-genericMethod-integration/TestUtils_1.scala (91%) create mode 100644 tests/run/unroll-genericMethod-integration/Test_4.scala create mode 100644 tests/run/unroll-genericMethod-integration/UnrollTestMain_1.scala create mode 100644 tests/run/unroll-genericMethod-integration/UnrollTestMain_2.scala create mode 100644 tests/run/unroll-genericMethod-integration/UnrollTestMain_3.scala create mode 100644 tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala create mode 100644 tests/run/unroll-genericMethod-integration/Unrolled_1.scala create mode 100644 tests/run/unroll-genericMethod-integration/Unrolled_2.scala create mode 100644 tests/run/unroll-genericMethod-integration/Unrolled_3.scala create mode 100644 tests/run/unroll-inferredFinal.scala create mode 100644 tests/run/unroll-methodWithImplicit-integration/TestUtils_1.scala create mode 100644 tests/run/unroll-methodWithImplicit-integration/Test_4.scala rename sbt-test/unroll-annot/methodWithImplicit/v1_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_1.scala (87%) rename sbt-test/unroll-annot/methodWithImplicit/v2_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_2.scala (92%) rename sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_3.scala (93%) rename sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala => tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala (94%) rename sbt-test/unroll-annot/methodWithImplicit/v1/src/main/scala/Unrolled.scala => tests/run/unroll-methodWithImplicit-integration/Unrolled_1.scala (74%) create mode 100644 tests/run/unroll-methodWithImplicit-integration/Unrolled_2.scala create mode 100644 tests/run/unroll-methodWithImplicit-integration/Unrolled_3.scala create mode 100644 tests/run/unroll-multiple.scala create mode 100644 tests/run/unroll-objectMethod-integration/TestUtils_1.scala create mode 100644 tests/run/unroll-objectMethod-integration/Test_4.scala rename sbt-test/unroll-annot/objectMethod/v1_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-objectMethod-integration/UnrollTestMain_1.scala (88%) rename sbt-test/unroll-annot/objectMethod/v2_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-objectMethod-integration/UnrollTestMain_2.scala (90%) rename sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-objectMethod-integration/UnrollTestMain_3.scala (93%) rename sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala => tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala (97%) rename sbt-test/unroll-annot/objectMethod/v1/src/main/scala/Unrolled.scala => tests/run/unroll-objectMethod-integration/Unrolled_1.scala (70%) create mode 100644 tests/run/unroll-objectMethod-integration/Unrolled_2.scala create mode 100644 tests/run/unroll-objectMethod-integration/Unrolled_3.scala create mode 100644 tests/run/unroll-primaryConstructor-integration/TestUtils_1.scala create mode 100644 tests/run/unroll-primaryConstructor-integration/Test_4.scala rename sbt-test/unroll-annot/primaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-primaryConstructor-integration/UnrollTestMain_1.scala (88%) rename sbt-test/unroll-annot/primaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-primaryConstructor-integration/UnrollTestMain_2.scala (91%) rename sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-primaryConstructor-integration/UnrollTestMain_3.scala (93%) rename sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala => tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala (94%) rename sbt-test/unroll-annot/primaryConstructor/v1/src/main/scala/Unrolled.scala => tests/run/unroll-primaryConstructor-integration/Unrolled_1.scala (70%) rename sbt-test/unroll-annot/primaryConstructor/v2/src/main/scala/Unrolled.scala => tests/run/unroll-primaryConstructor-integration/Unrolled_2.scala (65%) rename sbt-test/unroll-annot/primaryConstructor/v3/src/main/scala/Unrolled.scala => tests/run/unroll-primaryConstructor-integration/Unrolled_3.scala (83%) create mode 100644 tests/run/unroll-secondParameterList-integration/TestUtils_1.scala create mode 100644 tests/run/unroll-secondParameterList-integration/Test_4.scala rename sbt-test/unroll-annot/secondParameterList/v1_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-secondParameterList-integration/UnrollTestMain_1.scala (86%) rename sbt-test/unroll-annot/secondParameterList/v2_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-secondParameterList-integration/UnrollTestMain_2.scala (91%) rename sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-secondParameterList-integration/UnrollTestMain_3.scala (93%) rename sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala => tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala (95%) rename sbt-test/unroll-annot/secondParameterList/v1/src/main/scala/Unrolled.scala => tests/run/unroll-secondParameterList-integration/Unrolled_1.scala (72%) create mode 100644 tests/run/unroll-secondParameterList-integration/Unrolled_2.scala create mode 100644 tests/run/unroll-secondParameterList-integration/Unrolled_3.scala create mode 100644 tests/run/unroll-secondaryConstructor-integration/TestUtils_1.scala create mode 100644 tests/run/unroll-secondaryConstructor-integration/Test_4.scala rename sbt-test/unroll-annot/secondaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_1.scala (88%) rename sbt-test/unroll-annot/secondaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_2.scala (91%) rename sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_3.scala (93%) rename sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala => tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala (94%) rename sbt-test/unroll-annot/secondaryConstructor/v1/src/main/scala/Unrolled.scala => tests/run/unroll-secondaryConstructor-integration/Unrolled_1.scala (78%) rename sbt-test/unroll-annot/secondaryConstructor/v2/src/main/scala/Unrolled.scala => tests/run/unroll-secondaryConstructor-integration/Unrolled_2.scala (85%) rename sbt-test/unroll-annot/secondaryConstructor/v3/src/main/scala/Unrolled.scala => tests/run/unroll-secondaryConstructor-integration/Unrolled_3.scala (86%) create mode 100644 tests/run/unroll-traitMethod-integration/TestUtils_1.scala create mode 100644 tests/run/unroll-traitMethod-integration/Test_4.scala rename sbt-test/unroll-annot/traitMethod/v1_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-traitMethod-integration/UnrollTestMain_1.scala (92%) rename sbt-test/unroll-annot/traitMethod/v2_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-traitMethod-integration/UnrollTestMain_2.scala (94%) rename sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestMain.scala => tests/run/unroll-traitMethod-integration/UnrollTestMain_3.scala (95%) rename sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala => tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala (94%) rename sbt-test/unroll-annot/traitMethod/v1/src/main/scala/Unrolled.scala => tests/run/unroll-traitMethod-integration/Unrolled_1.scala (77%) create mode 100644 tests/run/unroll-traitMethod-integration/Unrolled_2.scala create mode 100644 tests/run/unroll-traitMethod-integration/Unrolled_3.scala create mode 100644 tests/run/unroll-traitMethod/Test_2.scala create mode 100644 tests/run/unroll-traitMethod/Unrolled_1.scala diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 0d755797d026..0368374b6596 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -59,6 +59,9 @@ class CompilationUnit protected (val source: SourceFile, val info: CompilationUn var hasMacroAnnotations: Boolean = false + def hasUnrollDefs: Boolean = unrolledClasses != null + var unrolledClasses: Set[Symbol] | Null = null + /** Set to `true` if inliner added anonymous mirrors that need to be completed */ var needsMirrorSupport: Boolean = false diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 24a492b4fe77..6e1e65d03976 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -40,6 +40,7 @@ class Compiler { List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks List(new semanticdb.ExtractSemanticDB.ExtractSemanticInfo) :: // Extract info into .semanticdb files List(new PostTyper) :: // Additional checks and cleanups after type checking + List(new UnrollDefinitions) :: // Unroll annotated methods if detected in PostTyper List(new sjs.PrepJSInterop) :: // Additional checks and transformations for Scala.js (Scala.js only) List(new SetRootTree) :: // Set the `rootTreeOrProvider` on class symbols Nil @@ -61,7 +62,6 @@ class Compiler { List(new InstrumentCoverage) :: // Perform instrumentation for code coverage (if -coverage-out is set) List(new CrossVersionChecks, // Check issues related to deprecated and experimental new FirstTransform, // Some transformations to put trees into a canonical form - new UnrollDefs, // Unroll annotated methods new CheckReentrant, // Internal use only: Check that compiled program has no data races involving global vars new ElimPackagePrefixes, // Eliminate references to package prefixes in Select nodes new CookComments, // Cook the comments: expand variables, doc, etc. diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 7b80c7c80a21..6822fcc8e548 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -20,6 +20,7 @@ import collection.mutable import reporting.{Profile, NoProfile} import dotty.tools.tasty.TastyFormat.ASTsSection import quoted.QuotePatterns +import dotty.tools.dotc.config.Feature object TreePickler: class StackSizeExceeded(val mdef: tpd.MemberDef) extends Exception @@ -474,15 +475,16 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { case _ => if passesConditionForErroringBestEffortCode(tree.hasType) then // #19951 The signature of a constructor of a Java annotation is irrelevant + val sym = tree.symbol val sig = - if name == nme.CONSTRUCTOR && tree.symbol.exists && tree.symbol.owner.is(JavaAnnotation) then Signature.NotAMethod + if name == nme.CONSTRUCTOR && sym.exists && sym.owner.is(JavaAnnotation) then Signature.NotAMethod else tree.tpe.signature - var ename = tree.symbol.targetName + var ename = sym.targetName val selectFromQualifier = name.isTypeName || qual.isInstanceOf[Hole] // holes have no symbol || sig == Signature.NotAMethod // no overload resolution necessary - || !tree.denot.symbol.exists // polymorphic function type + || !sym.exists // polymorphic function type || tree.denot.asSingleDenotation.isRefinedMethod // refined methods have no defining class symbol if selectFromQualifier then writeByte(if name.isTypeName then SELECTtpt else SELECT) @@ -491,9 +493,9 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { else // select from owner writeByte(SELECTin) withLength { - pickleNameAndSig(name, tree.symbol.signature, ename) + pickleNameAndSig(name, sym.signature, ename) pickleTree(qual) - pickleType(tree.symbol.owner.typeRef) + pickleType(sym.owner.typeRef) } else writeByte(if name.isTypeName then SELECTtpt else SELECT) diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index cc78203e873f..25f2f879077e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -220,6 +220,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe case DeprecatedInfixNamedArgumentSyntaxID // errorNumber: 204 case GivenSearchPriorityID // errorNumber: 205 case EnumMayNotBeValueClassesID // errorNumber: 206 + case IllegalUnrollPlacementID // errorNumber: 207 def errorNumber = ordinal - 1 diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index ab4f40677371..0bc418301d4e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -3334,14 +3334,14 @@ final class QuotedTypeMissing(tpe: Type)(using Context) extends StagingMessage(Q private def witness = defn.QuotedTypeClass.typeRef.appliedTo(tpe) - override protected def msg(using Context): String = + override protected def msg(using Context): String = i"Reference to $tpe within quotes requires a given ${witness} in scope" override protected def explain(using Context): String = - i"""Referencing `$tpe` inside a quoted expression requires a `${witness}` to be in scope. + i"""Referencing `$tpe` inside a quoted expression requires a `${witness}` to be in scope. |Since Scala is subject to erasure at runtime, the type information will be missing during the execution of the code. - |`${witness}` is therefore needed to carry `$tpe`'s type information into the quoted code. - |Without an implicit `${witness}`, the type `$tpe` cannot be properly referenced within the expression. + |`${witness}` is therefore needed to carry `$tpe`'s type information into the quoted code. + |Without an implicit `${witness}`, the type `$tpe` cannot be properly referenced within the expression. |To resolve this, ensure that a `${witness}` is available, either through a context-bound or explicitly. |""" @@ -3408,3 +3408,26 @@ final class EnumMayNotBeValueClasses(sym: Symbol)(using Context) extends SyntaxM def explain(using Context) = "" end EnumMayNotBeValueClasses + +class IllegalUnrollPlacement(origin: Option[Symbol])(using Context) +extends DeclarationMsg(IllegalUnrollPlacementID): + def msg(using Context) = origin match + case None => "@unroll is only allowed on a method parameter" + case Some(method) => + val isCtor = method.isConstructor + def what = if isCtor then i"a ${if method.owner.is(Trait) then "trait" else "class"} constructor" else i"method ${method.name}" + val prefix = s"Can not unroll parameters of $what" + if method.is(Deferred) then + i"$prefix: it must not be abstract" + else if isCtor && method.owner.is(Trait) then + i"implementation restriction: $prefix" + else if !(isCtor || method.is(Final) || method.owner.is(ModuleClass)) then + i"$prefix: it is not final" + else if method.owner.companionClass.is(CaseClass) then + i"$prefix of a case class companion object: please annotate the class constructor instead" + else + assert(method.owner.is(CaseClass)) + i"$prefix of a case class: please annotate the class constructor instead" + + def explain(using Context) = "" +end IllegalUnrollPlacement diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 898517806e50..cc7595442ddb 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -21,6 +21,7 @@ import reporting.* import NameKinds.WildcardParamName import cc.* import dotty.tools.dotc.transform.MacroAnnotations.hasMacroAnnotation +import dotty.tools.dotc.core.NameKinds.DefaultGetterName object PostTyper { val name: String = "posttyper" @@ -119,8 +120,39 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => private var inJavaAnnot: Boolean = false + private var seenUnrolledMethods: util.EqHashMap[Symbol, Boolean] | Null = null + private var noCheckNews: Set[New] = Set() + def isValidUnrolledMethod(method: Symbol, origin: SrcPos)(using Context): Boolean = + val seenMethods = + val local = seenUnrolledMethods + if local == null then + val map = new util.EqHashMap[Symbol, Boolean] + seenUnrolledMethods = map + map + else + local + seenMethods.getOrElseUpdate(method, { + val isCtor = method.isConstructor + if + method.name.is(DefaultGetterName) + then + false // not an error, but not an expandable unrolled method + else if + method.is(Deferred) + || isCtor && method.owner.is(Trait) + || !(isCtor || method.is(Final) || method.owner.is(ModuleClass)) + || method.owner.companionClass.is(CaseClass) + && (method.name == nme.apply || method.name == nme.fromProduct) + || method.owner.is(CaseClass) && method.name == nme.copy + then + report.error(IllegalUnrollPlacement(Some(method)), origin) + false + else + true + }) + def withNoCheckNews[T](ts: List[New])(op: => T): T = { val saved = noCheckNews noCheckNews ++= ts @@ -199,6 +231,16 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => tree } + private def registerIfUnrolledParam(sym: Symbol)(using Context): Unit = + if sym.hasAnnotation(defn.UnrollAnnot) && isValidUnrolledMethod(sym.owner, sym.sourcePos) then + val cls = sym.enclosingClass + val classes = ctx.compilationUnit.unrolledClasses + val additions = Array(cls, cls.linkedClass).filter(_ != NoSymbol) + if classes == null then + ctx.compilationUnit.unrolledClasses = Set.from(additions) + else + ctx.compilationUnit.unrolledClasses = classes ++ additions + private def processValOrDefDef(tree: Tree)(using Context): tree.type = val sym = tree.symbol tree match @@ -215,6 +257,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => ++ sym.annotations) else if sym.is(Param) then + registerIfUnrolledParam(sym) sym.keepAnnotationsCarrying(thisPhase, Set(defn.ParamMetaAnnot), orNoneOf = defn.NonBeanMetaAnnots) else if sym.is(ParamAccessor) then // @publicInBinary is not a meta-annotation and therefore not kept by `keepAnnotationsCarrying` diff --git a/compiler/src/dotty/tools/dotc/transform/UnrollDefinitions.scala b/compiler/src/dotty/tools/dotc/transform/UnrollDefinitions.scala new file mode 100644 index 000000000000..9cbaf7738533 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/UnrollDefinitions.scala @@ -0,0 +1,358 @@ +package dotty.tools.dotc +package transform + +import ast.tpd +import ast.Trees.* +import core.* +import Flags.* +import Decorators.* +import Contexts.* +import Symbols.* +import Constants.Constant +import Decorators.* +import DenotTransformers.IdentityDenotTransformer +import Names.* +import dotty.tools.dotc.core.NameKinds.DefaultGetterName + +import dotty.tools.dotc.core.Types.{MethodType, NamedType, PolyType, Type, NoPrefix, NoType} + +import dotty.tools.dotc.printing.Formatting.hl + +import scala.collection.mutable +import scala.util.boundary, boundary.break +import dotty.tools.dotc.core.StdNames.nme +import dotty.tools.unreachable + +/**Implementation of SIP-61. + * Runs when `@unroll` annotations are found in a compilation unit, installing new definitions + * + * Note that it only generates `Invisible` methods, so no interactions with Zinc/SemanticDB + */ +class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { + self => + + import tpd.* + + private var _unrolledDefs: util.EqHashMap[Symbol, ComputedIndicies] | Null = null + private def initializeUnrolledDefs(): util.EqHashMap[Symbol, ComputedIndicies] = + val local = _unrolledDefs + if local == null then + val map = new util.EqHashMap[Symbol, ComputedIndicies] + _unrolledDefs = map + map + else + local.clear() + local + + override def phaseName: String = UnrollDefinitions.name + + override def description: String = UnrollDefinitions.description + + override def changesMembers: Boolean = true + + override def run(using Context): Unit = + if ctx.compilationUnit.hasUnrollDefs then + super.run // create and run the transformer on the current compilation unit + + def newTransformer(using Context): Transformer = + UnrollingTransformer(ctx.compilationUnit.unrolledClasses.nn) + + type ComputedIndicies = List[(Int, List[Int])] + type ComputeIndicies = Context ?=> Symbol => ComputedIndicies + + private class UnrollingTransformer(classes: Set[Symbol]) extends Transformer { + private val unrolledDefs = initializeUnrolledDefs() + + def computeIndices(annotated: Symbol)(using Context): ComputedIndicies = + unrolledDefs.getOrElseUpdate(annotated, { + if annotated.name.is(DefaultGetterName) then + Nil // happens in curried methods where more than one parameter list has @unroll + else + val indices = annotated + .paramSymss + .zipWithIndex + .flatMap: (paramClause, paramClauseIndex) => + val annotationIndices = findUnrollAnnotations(paramClause) + if (annotationIndices.isEmpty) None + else Some((paramClauseIndex, annotationIndices)) + if indices.nonEmpty then + // pre-validation should have occurred in posttyper + assert(annotated.is(Final, butNot = Deferred) || annotated.isConstructor || annotated.owner.is(ModuleClass) || annotated.name.is(DefaultGetterName), + i"$annotated is not final&concrete, or a constructor") + indices + }) + end computeIndices + + override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match + case tree @ TypeDef(_, impl: Template) if classes(tree.symbol) => + super.transform(cpy.TypeDef(tree)(rhs = unrollTemplate(impl, computeIndices))) + case tree => + super.transform(tree) + } + + def copyParamSym(sym: Symbol, parent: Symbol)(using Context): (Symbol, Symbol) = + val copied = sym.copy(owner = parent, flags = (sym.flags &~ HasDefault), coord = sym.coord) + sym -> copied + + def symLocation(sym: Symbol)(using Context) = { + val lineDesc = + if (sym.span.exists && sym.span != sym.owner.span) + s" at line ${sym.srcPos.line + 1}" + else "" + i"in ${sym.owner}${lineDesc}" + } + + def findUnrollAnnotations(params: List[Symbol])(using Context): List[Int] = { + params + .zipWithIndex + .collect { + case (v, i) if v.hasAnnotation(defn.UnrollAnnot) => + i + } + } + + def isTypeClause(p: ParamClause) = p.headOption.exists(_.isInstanceOf[TypeDef]) + + def generateSingleForwarder(defdef: DefDef, + prevMethodType: Type, + paramIndex: Int, + paramCount: Int, + nextParamIndex: Int, + nextSymbol: Symbol, + annotatedParamListIndex: Int, + isCaseApply: Boolean)(using Context) = { + + def initNewForwarder()(using Context): (TermSymbol, List[List[Symbol]]) = { + val forwarderDefSymbol0 = Symbols.newSymbol( + defdef.symbol.owner, + defdef.name, + defdef.symbol.flags &~ HasDefaultParams | + Invisible | Synthetic, + NoType, // fill in later + coord = nextSymbol.span.shift(1) // shift by 1 to avoid "secondary constructor must call preceding" error + ).entered + + val newParamSymMappings = extractParamSymss(copyParamSym(_, forwarderDefSymbol0)) + val (oldParams, newParams) = newParamSymMappings.flatten.unzip + + val newParamSymLists0 = + newParamSymMappings.map: pairss => + pairss.map: (oldSym, newSym) => + newSym.info = oldSym.info.substSym(oldParams, newParams) + newSym + + val newResType = defdef.tpt.tpe.substSym(oldParams, newParams) + forwarderDefSymbol0.info = NamerOps.methodType(newParamSymLists0, newResType) + forwarderDefSymbol0.setParamss(newParamSymLists0) + forwarderDefSymbol0 -> newParamSymLists0 + } + + def extractParamSymss[T](onSymbol: Symbol => T): List[List[T]] = + defdef.paramss.zipWithIndex.map{ case (ps, i) => + if (i == annotatedParamListIndex) ps.take(paramIndex).map(p => onSymbol(p.symbol)) + else ps.map(p => onSymbol(p.symbol)) + } + + val paramCount = defdef.symbol.paramSymss(annotatedParamListIndex).size + + val (forwarderDefSymbol, newParamSymLists) = initNewForwarder() + + def forwarderRhs(): tpd.Tree = { + val defaultOffset = defdef.paramss + .iterator + .take(annotatedParamListIndex) + .filter(!isTypeClause(_)) + .map(_.size) + .sum + + val defaultCalls = Range(paramIndex, paramCount).map(n => + + def makeSelect(refTree: Tree, name: TermName): Tree = + val sym = refTree.symbol + if !sym.findMember(name, NoPrefix, EmptyFlags, EmptyFlags).exists then + val param = defdef.paramss(annotatedParamListIndex)(n) + val methodStr = s"method ${defdef.name} ${symLocation(defdef.symbol)}" + val paramStr = s"parameter ${param.name}" + val errorMessage = + i"Cannot unroll $methodStr because $paramStr needs a default value" + report.error(errorMessage, param.srcPos) + ref(newErrorSymbol(sym, nme.ERROR, errorMessage.toMessage)) + else + refTree.select(name) + + val inner = if (defdef.symbol.isConstructor) { + makeSelect(ref(defdef.symbol.owner.companionModule), + DefaultGetterName(defdef.name, n + defaultOffset)) + } else if (isCaseApply) { + makeSelect(ref(defdef.symbol.owner.companionModule), + DefaultGetterName(termName(""), n + defaultOffset)) + } else { + makeSelect(This(defdef.symbol.owner.asClass), + DefaultGetterName(defdef.name, n + defaultOffset)) + } + + newParamSymLists + .take(annotatedParamListIndex) + .map(_.map(ref)) + .foldLeft(inner): (lhs, newParams) => + if (newParams.headOption.exists(_.isInstanceOf[TypeTree])) TypeApply(lhs, newParams) + else Apply(lhs, newParams) + ) + + val forwarderInner: Tree = + This(defdef.symbol.owner.asClass).select(defdef.symbol) + + val forwarderCallArgs = + newParamSymLists.zipWithIndex.map{case (ps, i) => + if (i == annotatedParamListIndex) ps.map(ref).take(nextParamIndex) ++ defaultCalls + else ps.map(ref) + } + + val forwarderCall0 = forwarderCallArgs.foldLeft[Tree](forwarderInner){ + case (lhs: Tree, newParams) => + if (newParams.headOption.exists(_.isInstanceOf[TypeTree])) TypeApply(lhs, newParams) + else Apply(lhs, newParams) + } + + val forwarderCall = + if (!defdef.symbol.isConstructor) forwarderCall0 + else Block(List(forwarderCall0), Literal(Constant(()))) + + forwarderCall + } + + val forwarderDef = + tpd.DefDef(forwarderDefSymbol, rhs = forwarderRhs()) + + forwarderDef.withSpan(nextSymbol.span.shift(1)) + } + + def generateFromProduct(startParamIndices: List[Int], paramCount: Int, defdef: DefDef)(using Context) = { + cpy.DefDef(defdef)( + name = defdef.name, + paramss = defdef.paramss, + tpt = defdef.tpt, + rhs = Match( + ref(defdef.paramss.head.head.asInstanceOf[ValDef].symbol).select(termName("productArity")), + startParamIndices.map { paramIndex => + val Apply(select, args) = defdef.rhs: @unchecked + CaseDef( + Literal(Constant(paramIndex)), + EmptyTree, + Apply( + select, + args.take(paramIndex) ++ + Range(paramIndex, paramCount).map(n => + ref(defdef.symbol.owner.companionModule) + .select(DefaultGetterName(defdef.symbol.owner.primaryConstructor.name.toTermName, n)) + ) + ) + ) + } ++ Seq( + CaseDef( + Underscore(defn.IntType), + EmptyTree, + defdef.rhs + ) + ) + ) + ).setDefTree + } + + def generateSyntheticDefs(tree: Tree, compute: ComputeIndicies)(using Context): Option[(Symbol, Option[Symbol], Seq[DefDef])] = tree match { + case defdef: DefDef if defdef.paramss.nonEmpty => + import dotty.tools.dotc.core.NameOps.isConstructorName + + val isCaseCopy = + defdef.name.toString == "copy" && defdef.symbol.owner.is(CaseClass) + + val isCaseApply = + defdef.name.toString == "apply" && defdef.symbol.owner.companionClass.is(CaseClass) + + val isCaseFromProduct = defdef.name.toString == "fromProduct" && defdef.symbol.owner.companionClass.is(CaseClass) + + val annotated = + if (isCaseCopy) defdef.symbol.owner.primaryConstructor + else if (isCaseApply) defdef.symbol.owner.companionClass.primaryConstructor + else if (isCaseFromProduct) defdef.symbol.owner.companionClass.primaryConstructor + else defdef.symbol + + compute(annotated) match { + case Nil => None + case Seq((paramClauseIndex, annotationIndices)) => + val paramCount = annotated.paramSymss(paramClauseIndex).size + if isCaseFromProduct then + Some((defdef.symbol, Some(defdef.symbol), Seq(generateFromProduct(annotationIndices, paramCount, defdef)))) + else + val (generatedDefs, _) = + val indices = (annotationIndices :+ paramCount).sliding(2).toList.reverse + indices.foldLeft((Seq.empty[DefDef], defdef.symbol)): + case ((defdefs, nextSymbol), Seq(paramIndex, nextParamIndex)) => + val forwarder = generateSingleForwarder( + defdef, + defdef.symbol.info, + paramIndex, + paramCount, + nextParamIndex, + nextSymbol, + paramClauseIndex, + isCaseApply + ) + (forwarder +: defdefs, forwarder.symbol) + case _ => unreachable("sliding with at least 2 elements") + Some((defdef.symbol, None, generatedDefs)) + + case multiple => + report.error("Cannot have multiple parameter lists containing `@unroll` annotation", defdef.srcPos) + None + } + + case _ => None + } + + def unrollTemplate(tmpl: tpd.Template, compute: ComputeIndicies)(using Context): tpd.Tree = { + + val generatedBody = tmpl.body.flatMap(generateSyntheticDefs(_, compute)) + val generatedConstr0 = generateSyntheticDefs(tmpl.constr, compute) + val allGenerated = generatedBody ++ generatedConstr0 + val bodySubs = generatedBody.flatMap((_, maybeSub, _) => maybeSub).toSet + val otherDecls = tmpl.body.filterNot(d => d.symbol.exists && bodySubs(d.symbol)) + + /** inlined from compiler/src/dotty/tools/dotc/typer/Checking.scala */ + def checkClash(decl: Symbol, other: Symbol) = + def staticNonStaticPair = decl.isScalaStatic != other.isScalaStatic + decl.matches(other) && !staticNonStaticPair + + if allGenerated.nonEmpty then + val byName = (tmpl.constr :: otherDecls).groupMap(_.symbol.name.toString)(_.symbol) + for + (src, _, dcls) <- allGenerated + dcl <- dcls + do + val replaced = dcl.symbol + byName.get(dcl.name.toString).foreach { syms => + val clashes = syms.filter(checkClash(replaced, _)) + for existing <- clashes do + report.error(i"""Unrolled $replaced clashes with existing declaration. + |Please remove the clashing definition, or the @unroll annotation. + |Unrolled from ${hl(src.showDcl)} ${symLocation(src)}""".stripMargin, existing.srcPos) + } + end if + + val generatedDefs = generatedBody.flatMap((_, _, gens) => gens) + val generatedConstr = generatedConstr0.toList.flatMap((_, _, gens) => gens) + + cpy.Template(tmpl)( + tmpl.constr, + tmpl.parents, + tmpl.derived, + tmpl.self, + otherDecls ++ generatedDefs ++ generatedConstr + ) + } + +} + +object UnrollDefinitions: + val name: String = "unrollDefs" + val description: String = "generates forwarders for methods annotated with @unroll" diff --git a/compiler/src/dotty/tools/dotc/transform/UnrollDefs.scala b/compiler/src/dotty/tools/dotc/transform/UnrollDefs.scala deleted file mode 100644 index 5fcf6f0ba9ab..000000000000 --- a/compiler/src/dotty/tools/dotc/transform/UnrollDefs.scala +++ /dev/null @@ -1,279 +0,0 @@ -package dotty.tools.dotc.transform - -import dotty.tools.dotc.* -import core.* -import MegaPhase.MiniPhase -import Contexts.* -import Symbols.* -import Flags.* -import SymDenotations.* -import Decorators.* -import ast.Trees.* -import ast.tpd -import StdNames.nme -import Names.* -import Constants.Constant -import dotty.tools.dotc.core.NameKinds.DefaultGetterName -import dotty.tools.dotc.core.Types.{MethodType, NamedType, PolyType, Type} -import dotty.tools.dotc.core.Symbols - -import scala.language.implicitConversions - -class UnrollDefs extends MiniPhase { - import tpd._ - - val phaseName = "unroll" - - override val runsAfter = Set(FirstTransform.name) - - def copyParam(p: ValDef, parent: Symbol)(using Context) = { - implicitly[Context].typeAssigner.assignType( - cpy.ValDef(p)(p.name, p.tpt, p.rhs), - Symbols.newSymbol(parent, p.name, p.symbol.flags, p.symbol.info) - ) - } - - def copyParam2(p: TypeDef, parent: Symbol)(using Context) = { - implicitly[Context].typeAssigner.assignType( - cpy.TypeDef(p)(p.name, p.rhs), - Symbols.newSymbol(parent, p.name, p.symbol.flags, p.symbol.info) - ) - } - - def findUnrollAnnotations(params: List[Symbol])(using Context): List[Int] = { - params - .zipWithIndex - .collect { - case (v, i) if v.annotations.exists(_.symbol.fullName.toString == "scala.annotation.unroll") => - i - } - } - def isTypeClause(p: ParamClause) = p.headOption.exists(_.isInstanceOf[TypeDef]) - def generateSingleForwarder(defdef: DefDef, - prevMethodType: Type, - paramIndex: Int, - nextParamIndex: Int, - nextSymbol: Symbol, - annotatedParamListIndex: Int, - paramLists: List[ParamClause], - isCaseApply: Boolean) - (using Context) = { - - def truncateMethodType0(tpe: Type, n: Int): Type = { - tpe match{ - case pt: PolyType => PolyType(pt.paramNames, pt.paramInfos, truncateMethodType0(pt.resType, n + 1)) - case mt: MethodType => - if (n == annotatedParamListIndex) MethodType(mt.paramInfos.take(paramIndex), mt.resType) - else MethodType(mt.paramInfos, truncateMethodType0(mt.resType, n + 1)) - } - } - - val truncatedMethodType = truncateMethodType0(prevMethodType, 0) - val forwarderDefSymbol = Symbols.newSymbol( - defdef.symbol.owner, - defdef.name, - defdef.symbol.flags &~ - HasDefaultParams &~ - (if (nextParamIndex == -1) Flags.EmptyFlags else Deferred) | - Invisible, - truncatedMethodType - ) - - val newParamLists: List[ParamClause] = paramLists.zipWithIndex.map{ case (ps, i) => - if (i == annotatedParamListIndex) ps.take(paramIndex).map(p => copyParam(p.asInstanceOf[ValDef], forwarderDefSymbol)) - else { - if (isTypeClause(ps)) ps.map(p => copyParam2(p.asInstanceOf[TypeDef], forwarderDefSymbol)) - else ps.map(p => copyParam(p.asInstanceOf[ValDef], forwarderDefSymbol)) - } - } - forwarderDefSymbol.setParamssFromDefs(newParamLists) - - val defaultOffset = paramLists - .iterator - .take(annotatedParamListIndex) - .filter(!isTypeClause(_)) - .map(_.size) - .sum - - val defaultCalls = Range(paramIndex, nextParamIndex).map(n => - val inner = if (defdef.symbol.isConstructor) { - ref(defdef.symbol.owner.companionModule) - .select(DefaultGetterName(defdef.name, n + defaultOffset)) - } else if (isCaseApply) { - ref(defdef.symbol.owner.companionModule) - .select(DefaultGetterName(termName(""), n + defaultOffset)) - } else { - This(defdef.symbol.owner.asClass) - .select(DefaultGetterName(defdef.name, n + defaultOffset)) - } - - newParamLists - .take(annotatedParamListIndex) - .map(_.map(p => ref(p.symbol))) - .foldLeft[Tree](inner){ - case (lhs: Tree, newParams) => - if (newParams.headOption.exists(_.isInstanceOf[TypeTree])) TypeApply(lhs, newParams) - else Apply(lhs, newParams) - } - ) - - val forwarderInner: Tree = This(defdef.symbol.owner.asClass).select(nextSymbol) - - val forwarderCallArgs = - newParamLists.zipWithIndex.map{case (ps, i) => - if (i == annotatedParamListIndex) ps.map(p => ref(p.symbol)).take(nextParamIndex) ++ defaultCalls - else ps.map(p => ref(p.symbol)) - } - - lazy val forwarderCall0 = forwarderCallArgs.foldLeft[Tree](forwarderInner){ - case (lhs: Tree, newParams) => - if (newParams.headOption.exists(_.isInstanceOf[TypeTree])) TypeApply(lhs, newParams) - else Apply(lhs, newParams) - } - - lazy val forwarderCall = - if (!defdef.symbol.isConstructor) forwarderCall0 - else Block(List(forwarderCall0), Literal(Constant(()))) - - val forwarderDef = implicitly[Context].typeAssigner.assignType( - cpy.DefDef(defdef)( - name = forwarderDefSymbol.name, - paramss = newParamLists, - tpt = defdef.tpt, - rhs = if (nextParamIndex == -1) EmptyTree else forwarderCall - ), - forwarderDefSymbol - ) - - forwarderDef - } - - def generateFromProduct(startParamIndices: List[Int], paramCount: Int, defdef: DefDef)(using Context) = { - cpy.DefDef(defdef)( - name = defdef.name, - paramss = defdef.paramss, - tpt = defdef.tpt, - rhs = Match( - ref(defdef.paramss.head.head.asInstanceOf[ValDef].symbol).select(termName("productArity")), - startParamIndices.map { paramIndex => - val Apply(select, args) = defdef.rhs: @unchecked - CaseDef( - Literal(Constant(paramIndex)), - EmptyTree, - Apply( - select, - args.take(paramIndex) ++ - Range(paramIndex, paramCount).map(n => - ref(defdef.symbol.owner.companionModule) - .select(DefaultGetterName(defdef.symbol.owner.primaryConstructor.name.toTermName, n)) - ) - ) - ) - } ++ Seq( - CaseDef( - EmptyTree, - EmptyTree, - defdef.rhs - ) - ) - ) - ).setDefTree - } - - def generateSyntheticDefs(tree: Tree)(using Context): (Option[Symbol], Seq[Tree]) = tree match{ - case defdef: DefDef if defdef.paramss.nonEmpty => - import dotty.tools.dotc.core.NameOps.isConstructorName - - val isCaseCopy = - defdef.name.toString == "copy" && defdef.symbol.owner.is(CaseClass) - - val isCaseApply = - defdef.name.toString == "apply" && defdef.symbol.owner.companionClass.is(CaseClass) - - val isCaseFromProduct = defdef.name.toString == "fromProduct" && defdef.symbol.owner.companionClass.is(CaseClass) - - val annotated = - if (isCaseCopy) defdef.symbol.owner.primaryConstructor - else if (isCaseApply) defdef.symbol.owner.companionClass.primaryConstructor - else if (isCaseFromProduct) defdef.symbol.owner.companionClass.primaryConstructor - else defdef.symbol - - - annotated - .paramSymss - .zipWithIndex - .flatMap{case (paramClause, paramClauseIndex) => - val annotationIndices = findUnrollAnnotations(paramClause) - if (annotationIndices.isEmpty) None - else Some((paramClauseIndex, annotationIndices)) - } match{ - case Nil => (None, Nil) - case Seq((paramClauseIndex, annotationIndices)) => - val paramCount = annotated.paramSymss(paramClauseIndex).size - if (isCaseFromProduct) { - (Some(defdef.symbol), Seq(generateFromProduct(annotationIndices, paramCount, defdef))) - } else { - if (defdef.symbol.is(Deferred)){ - ( - Some(defdef.symbol), - (-1 +: annotationIndices :+ paramCount).sliding(2).toList.foldLeft((Seq.empty[DefDef], defdef.symbol))((m, v) => ((m, v): @unchecked) match { - case ((defdefs, nextSymbol), Seq(paramIndex, nextParamIndex)) => - val forwarder = generateSingleForwarder( - defdef, - defdef.symbol.info, - nextParamIndex, - paramIndex, - nextSymbol, - paramClauseIndex, - defdef.paramss, - isCaseApply - ) - (forwarder +: defdefs, forwarder.symbol) - })._1 - ) - - }else{ - - ( - None, - (annotationIndices :+ paramCount).sliding(2).toList.reverse.foldLeft((Seq.empty[DefDef], defdef.symbol))((m, v) => ((m, v): @unchecked) match { - case ((defdefs, nextSymbol), Seq(paramIndex, nextParamIndex)) => - val forwarder = generateSingleForwarder( - defdef, - defdef.symbol.info, - paramIndex, - nextParamIndex, - nextSymbol, - paramClauseIndex, - defdef.paramss, - isCaseApply - ) - (forwarder +: defdefs, forwarder.symbol) - })._1 - ) - } - } - - case multiple => sys.error("Cannot have multiple parameter lists containing `@unroll` annotation") - } - - case _ => (None, Nil) - } - - override def transformTemplate(tmpl: tpd.Template)(using Context): tpd.Tree = { - - val (removed0, generatedDefs) = tmpl.body.map(generateSyntheticDefs).unzip - val (_, generatedConstr) = generateSyntheticDefs(tmpl.constr) - val removed = removed0.flatten - - super.transformTemplate( - cpy.Template(tmpl)( - tmpl.constr, - tmpl.parents, - tmpl.derived, - tmpl.self, - tmpl.body.filter(t => !removed.contains(t.symbol)) ++ generatedDefs.flatten ++ generatedConstr - ) - ) - } -} diff --git a/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala b/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala index 6020431672b9..8f8a68aa5735 100644 --- a/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala @@ -81,18 +81,37 @@ class CrossVersionChecks extends MiniPhase: report.deprecationWarning(em"inheritance from $psym is deprecated$since$msg", parent.srcPos, origin=psym.showFullName) } + private def unrollError(pos: SrcPos)(using Context): Unit = + report.error(IllegalUnrollPlacement(None), pos) + + private def checkUnrollAnnot(annotSym: Symbol, pos: SrcPos)(using Context): Unit = + if annotSym == defn.UnrollAnnot then + unrollError(pos) + + private def checkUnrollMemberDef(memberDef: MemberDef)(using Context): Unit = + val sym = memberDef.symbol + if + sym.hasAnnotation(defn.UnrollAnnot) + && !(sym.isTerm && sym.is(Param)) + then + val normSym = if sym.is(ModuleVal) then sym.moduleClass else sym + unrollError(normSym.srcPos) + override def transformValDef(tree: ValDef)(using Context): ValDef = + checkUnrollMemberDef(tree) checkDeprecatedOvers(tree) checkExperimentalAnnots(tree.symbol) tree override def transformDefDef(tree: DefDef)(using Context): DefDef = + checkUnrollMemberDef(tree) checkDeprecatedOvers(tree) checkExperimentalAnnots(tree.symbol) tree override def transformTypeDef(tree: TypeDef)(using Context): TypeDef = // TODO do we need to check checkDeprecatedOvers(tree)? + checkUnrollMemberDef(tree) checkExperimentalAnnots(tree.symbol) tree @@ -126,6 +145,8 @@ class CrossVersionChecks extends MiniPhase: if tree.span.isSourceDerived then checkDeprecatedRef(sym, tree.srcPos) checkExperimentalRef(sym, tree.srcPos) + case AnnotatedType(_, annot) => + checkUnrollAnnot(annot.symbol, tree.srcPos) case _ => } tree @@ -140,7 +161,11 @@ class CrossVersionChecks extends MiniPhase: case tree: TypeTree => transformTypeTree(tree) case _ => } - tree + tree match + case Annotated(_, annot) => + checkUnrollAnnot(annot.tpe.typeSymbol, tree.srcPos) + tree + case tree => tree end CrossVersionChecks diff --git a/docs/_docs/reference/experimental/unrolled-defs.md b/docs/_docs/reference/experimental/unrolled-defs.md new file mode 100644 index 000000000000..f2e09e82bc18 --- /dev/null +++ b/docs/_docs/reference/experimental/unrolled-defs.md @@ -0,0 +1,156 @@ +--- +layout: doc-page +title: "Automatic Parameter Unrolling" +nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/unrolled-defs.html +--- + +Parameter unrolling enables new parameters to be added to methods and classes, +while still preserving backwards binary compatibility. An `@unroll` annotation, on a parameter with default value, will generate backwards compatible forwarders to a method or constructor. + +## Example +```scala +// V1 +final def foo( + s: String, + i: Int +): String = s + i +``` + +In the example above, assume version `V1` of a library defines the method `foo` with two parameters: `s` and `i`. +Assume a client library or application `C1` compiles against `V1` of `foo`. + +```scala +// V2 +final def foo( + s: String, + i: Int, + @unroll b: Boolean = true, + l: Long = 0L +): String = s + i + b + l + +// Generated automatically +`` final def foo( + s: String, + i: Int +) = foo(s, i, true, 0L) +``` + +In version `V2`, the library adds the `b` and `l` parameters to `foo`, along with default values. +To preserve compatibility with `V1`, `b` is annotated with `@unroll`, generating a forwarder with only the parameters that come before, i.e. it has the same signature as `foo` in `V1`. + +A client `C2` compiling against `V2` will only see `foo` with four parameters in the public API. +The generated forwarder is hidden from those clients. +However, `C1` remains compatible with `V2` of the library, and does not need to be recompiled. +At runtime, it will continue to link against the signature of the old `foo` method, and call the generated forwarder which is accessible in the binary API. + +## Specification + +### `@unroll` annotation + +The `scala.annotation.unroll` annotation can be applied to any term parameter of an effectively-final method: +- `def` in an `object` (i.e. `final` may be omitted) +- `final def` in a `class` or `trait` +- `class` parameters (i.e. primary constructors) +- `def this` in a `class` (i.e. secondary constructors) + +### Restrictions + +It is illegal for `@unroll` to be applied to any other definition (including `trait` parameters and local methods), or to annotate a type. + +`@unroll` may be applied to more than one parameter per method, but all occurrences must appear in the same parameter clause. + +The annotated parameter, and any parameters to the right in the same parameter clause, must have a default value. + +It is a compile-time error if any generated forwarder matches the signature of another declaration in the same class. + +## Code generation + +Expansion of `@unroll` parameters is performed before TASTy generation, so generated code will appear in TASTy. + +Below specifies the transformations that occur: + +For each method `m` of a template, there is a target method `t` which is checked for `@unroll`: +- for `fromProduct`, `copy`, and `apply` of the companion of case class `C`, then `t` is the primary constructor of `C`. +- otherwise `m` is `t`. + +if `t` has a single parameter list with `@unroll` annotations, then `m` is subject to code generation. There are two +possible transformations: +1. Forwarder generation +2. Reimplementation: for `fromProduct` of a case class companion + +### (1) Forwarder generation + +In a method `foo` with unrolled parameters in parameter list `i`: +each parameter `p` with an `@unroll` annotation causes the generation of exactly one forwarder method `f_p`. + +for a given method with generic signature + +```scala +final def foo[T](ps0...)(psX..., @unroll p, psY...)(psN...): T = + ... +``` +then `f_p` will take the form + +```scala +`` final def foo[T](ps0...)(psX...)(psN...): T = + foo(ps0...)(psX..., p_D, psY_D...)(psN...) +``` + +i.e. result type is preserved, parameter lists before and after `i` are unchanged, and within `i`: +- the parameters `psX...` to the left of `p` are preserved, +- the parameters `p` and `psY...` are dropped. + +In the body of `f_p`, parameters are passed positionally to the original `foo`, except for the dropped parameters, which are replaced by default arguments for those parameters (`p_D` for `p`, and `psY_D...` for `psY...`). + +Forwarders are generated after type checking, before pickling, and with the `Invisible` flag. +This means that while present in TASTy, they can not be resolved from other top-level classes. + +Forwarder method parameters do not have default values, and are never annotated with `@unroll`. + +### (2) Method reimplementation + +To preserve semantic compatibility of `fromProduct`, its body is replaced with a pattern match over the `productArity` of the parameter. +For each forwarder generated for the case class primary constructor, an equivalent case is generated in the pattern match. + +e.g. for a forwarder +```scala +`` def this(ps...) = this(ps..., ds...) +``` +then the following case is generated: +```scala +case n => new C(...p.productElement(n - 1), ds...) +``` +where `n` is an integer matching the number of parameters in `ps`. + +The pattern match will have a default wildcard case, which has the same body as the original `fromProduct` method. + +In all the complete transformation: + +```scala +case class C(ps0...) // ps0 has z parameters + +object C: + def fromProduct(p: Product): C = + p.productArity match + case ... => ... + case n => new C(...p.productElement(n - 1), ds...) + case _ => new C(...p.productElement(z - 1)) +``` + + +## Background Motivation + +The Scala language library ecosystem is based upon compatability of API's represented via both the TASTy format (TASTy compatibility), and the Java class file format (binary compatibility). + +Adding a parameter to a method or constructor is a binary backwards incompatible change: +clients compiled against the previous version will expect the old signature to exist, and cause a `LinkageError` to be thrown at runtime. +The correct solution to this problem, to preserve compatibility, is to duplicate the method before adding the new parameter. + +In practice, Scala users developed various techniques and disciplines for mitigating this problem when evolving APIs. +Either by forbidding certain features, such as case classes, or various code generation frameworks. Here are some well-known examples: + +1. [data-class](https://index.scala-lang.org/alexarchambault/data-class) +2. [SBT Contraband](https://www.scala-sbt.org/contraband/) +3. [Structural Data Structures](https://github.com/scala/docs.scala-lang/pull/2662) + +The `@unroll` annotation was proposed as an alternative to these disciplines that not not require learning a new meta-language on top of Scala. The standard data modelling techniques of `def`, `case class`, `enum`, `class` and `trait` are preserved, and the mistake-prone boilerplate is automated. diff --git a/docs/sidebar.yml b/docs/sidebar.yml index a306d8bdf274..8cae4e95725a 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -163,6 +163,7 @@ subsection: - page: reference/experimental/typeclasses.md - page: reference/experimental/runtimeChecked.md - page: reference/experimental/better-fors.md + - page: reference/experimental/unrolled-defs.md - page: reference/syntax.md - title: Language Versions index: reference/language-versions/language-versions.md diff --git a/library/src/scala/annotation/unroll.scala b/library/src/scala/annotation/unroll.scala index 93327f7dcb86..c37b7903d605 100644 --- a/library/src/scala/annotation/unroll.scala +++ b/library/src/scala/annotation/unroll.scala @@ -1,4 +1,12 @@ package scala.annotation @experimental("under review as part of SIP-61") +/**The `@unroll` annotation is reserved for parameters of classes and methods. + * + * It enables to add new parameters while preserving backwards binary compatibility, + * through code generation of hidden forwarder methods (but visible in the binary API). + * + * Read more about parameter unrolling, and the usage of `@unroll` in the reference documentation: + * https://dotty.epfl.ch/docs/reference/experimental/unrolled-defs.html + */ final class unroll extends scala.annotation.StaticAnnotation diff --git a/sbt-test/unroll-annot/caseclass/build.sbt b/sbt-test/unroll-annot/caseclass/build.sbt deleted file mode 100644 index 0568d222bf5a..000000000000 --- a/sbt-test/unroll-annot/caseclass/build.sbt +++ /dev/null @@ -1,48 +0,0 @@ -lazy val utils = project.in(file("utils")) - -lazy val sharedSettings = Seq( - scalacOptions ++= Seq("-Ycheck:all", "-experimental") -) - -lazy val v1 = project.in(file("v1")) - .settings(sharedSettings) - -lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Compile / unmanagedClasspath := Seq( - Attributed.blank((v1 / Compile / classDirectory).value) - ), - ) - -lazy val v2 = project.in(file("v2")) - .settings(sharedSettings) - -lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value) - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v2 / Compile / classDirectory).value) - ), - ) - -lazy val v3 = project.in(file("v3")) - .settings(sharedSettings) - -lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value), - // add v2_app, compiled against v2, to the classpath - Attributed.blank((v2_app / Runtime / classDirectory).value), - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v3 / Compile / classDirectory).value) - ), - ) diff --git a/sbt-test/unroll-annot/caseclass/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/caseclass/project/DottyInjectedPlugin.scala deleted file mode 100644 index 69f15d168bfc..000000000000 --- a/sbt-test/unroll-annot/caseclass/project/DottyInjectedPlugin.scala +++ /dev/null @@ -1,12 +0,0 @@ -import sbt._ -import Keys._ - -object DottyInjectedPlugin extends AutoPlugin { - override def requires = plugins.JvmPlugin - override def trigger = allRequirements - - override val projectSettings = Seq( - scalaVersion := sys.props("plugin.scalaVersion"), - scalacOptions += "-source:3.0-migration" - ) -} diff --git a/sbt-test/unroll-annot/caseclass/test b/sbt-test/unroll-annot/caseclass/test deleted file mode 100644 index e8e500857b0e..000000000000 --- a/sbt-test/unroll-annot/caseclass/test +++ /dev/null @@ -1,14 +0,0 @@ -# compile and run a basic version of Unrolled (v1), and an app that uses it -> v1/compile -> v1_app/runMain unroll.UnrollTestMainV1 -# add a field to the case class (v2), and update the app to use it, -# and ensure the old version (v1) still links -> v2/compile -> v2_app/runMain unroll.UnrollTestMainV1 -> v2_app/runMain unroll.UnrollTestMainV2 -# add a field to the case class (v3), and update the app to use it, -# and ensure the old versions (v1, v2) still link -> v3/compile -> v3_app/runMain unroll.UnrollTestMainV1 -> v3_app/runMain unroll.UnrollTestMainV2 -> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/classMethod/build.sbt b/sbt-test/unroll-annot/classMethod/build.sbt deleted file mode 100644 index 0568d222bf5a..000000000000 --- a/sbt-test/unroll-annot/classMethod/build.sbt +++ /dev/null @@ -1,48 +0,0 @@ -lazy val utils = project.in(file("utils")) - -lazy val sharedSettings = Seq( - scalacOptions ++= Seq("-Ycheck:all", "-experimental") -) - -lazy val v1 = project.in(file("v1")) - .settings(sharedSettings) - -lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Compile / unmanagedClasspath := Seq( - Attributed.blank((v1 / Compile / classDirectory).value) - ), - ) - -lazy val v2 = project.in(file("v2")) - .settings(sharedSettings) - -lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value) - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v2 / Compile / classDirectory).value) - ), - ) - -lazy val v3 = project.in(file("v3")) - .settings(sharedSettings) - -lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value), - // add v2_app, compiled against v2, to the classpath - Attributed.blank((v2_app / Runtime / classDirectory).value), - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v3 / Compile / classDirectory).value) - ), - ) diff --git a/sbt-test/unroll-annot/classMethod/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/classMethod/project/DottyInjectedPlugin.scala deleted file mode 100644 index 69f15d168bfc..000000000000 --- a/sbt-test/unroll-annot/classMethod/project/DottyInjectedPlugin.scala +++ /dev/null @@ -1,12 +0,0 @@ -import sbt._ -import Keys._ - -object DottyInjectedPlugin extends AutoPlugin { - override def requires = plugins.JvmPlugin - override def trigger = allRequirements - - override val projectSettings = Seq( - scalaVersion := sys.props("plugin.scalaVersion"), - scalacOptions += "-source:3.0-migration" - ) -} diff --git a/sbt-test/unroll-annot/classMethod/test b/sbt-test/unroll-annot/classMethod/test deleted file mode 100644 index e8e500857b0e..000000000000 --- a/sbt-test/unroll-annot/classMethod/test +++ /dev/null @@ -1,14 +0,0 @@ -# compile and run a basic version of Unrolled (v1), and an app that uses it -> v1/compile -> v1_app/runMain unroll.UnrollTestMainV1 -# add a field to the case class (v2), and update the app to use it, -# and ensure the old version (v1) still links -> v2/compile -> v2_app/runMain unroll.UnrollTestMainV1 -> v2_app/runMain unroll.UnrollTestMainV2 -# add a field to the case class (v3), and update the app to use it, -# and ensure the old versions (v1, v2) still link -> v3/compile -> v3_app/runMain unroll.UnrollTestMainV1 -> v3_app/runMain unroll.UnrollTestMainV2 -> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/classMethod/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/classMethod/v2/src/main/scala/Unrolled.scala deleted file mode 100644 index e46d36c230c0..000000000000 --- a/sbt-test/unroll-annot/classMethod/v2/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,7 +0,0 @@ -package unroll - -import scala.annotation.unroll - -class Unrolled{ - def foo(s: String, @unroll n: Int = 1, b: Boolean = true) = s + n + b -} diff --git a/sbt-test/unroll-annot/classMethod/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/classMethod/v3/src/main/scala/Unrolled.scala deleted file mode 100644 index 5f0b76a799d4..000000000000 --- a/sbt-test/unroll-annot/classMethod/v3/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,7 +0,0 @@ -package unroll - -import scala.annotation.unroll - -class Unrolled{ - def foo(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0) = s + n + b + l -} diff --git a/sbt-test/unroll-annot/curriedMethod/build.sbt b/sbt-test/unroll-annot/curriedMethod/build.sbt deleted file mode 100644 index 0568d222bf5a..000000000000 --- a/sbt-test/unroll-annot/curriedMethod/build.sbt +++ /dev/null @@ -1,48 +0,0 @@ -lazy val utils = project.in(file("utils")) - -lazy val sharedSettings = Seq( - scalacOptions ++= Seq("-Ycheck:all", "-experimental") -) - -lazy val v1 = project.in(file("v1")) - .settings(sharedSettings) - -lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Compile / unmanagedClasspath := Seq( - Attributed.blank((v1 / Compile / classDirectory).value) - ), - ) - -lazy val v2 = project.in(file("v2")) - .settings(sharedSettings) - -lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value) - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v2 / Compile / classDirectory).value) - ), - ) - -lazy val v3 = project.in(file("v3")) - .settings(sharedSettings) - -lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value), - // add v2_app, compiled against v2, to the classpath - Attributed.blank((v2_app / Runtime / classDirectory).value), - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v3 / Compile / classDirectory).value) - ), - ) diff --git a/sbt-test/unroll-annot/curriedMethod/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/curriedMethod/project/DottyInjectedPlugin.scala deleted file mode 100644 index 69f15d168bfc..000000000000 --- a/sbt-test/unroll-annot/curriedMethod/project/DottyInjectedPlugin.scala +++ /dev/null @@ -1,12 +0,0 @@ -import sbt._ -import Keys._ - -object DottyInjectedPlugin extends AutoPlugin { - override def requires = plugins.JvmPlugin - override def trigger = allRequirements - - override val projectSettings = Seq( - scalaVersion := sys.props("plugin.scalaVersion"), - scalacOptions += "-source:3.0-migration" - ) -} diff --git a/sbt-test/unroll-annot/curriedMethod/test b/sbt-test/unroll-annot/curriedMethod/test deleted file mode 100644 index e8e500857b0e..000000000000 --- a/sbt-test/unroll-annot/curriedMethod/test +++ /dev/null @@ -1,14 +0,0 @@ -# compile and run a basic version of Unrolled (v1), and an app that uses it -> v1/compile -> v1_app/runMain unroll.UnrollTestMainV1 -# add a field to the case class (v2), and update the app to use it, -# and ensure the old version (v1) still links -> v2/compile -> v2_app/runMain unroll.UnrollTestMainV1 -> v2_app/runMain unroll.UnrollTestMainV2 -# add a field to the case class (v3), and update the app to use it, -# and ensure the old versions (v1, v2) still link -> v3/compile -> v3_app/runMain unroll.UnrollTestMainV1 -> v3_app/runMain unroll.UnrollTestMainV2 -> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/curriedMethod/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/curriedMethod/v2/src/main/scala/Unrolled.scala deleted file mode 100644 index 843dbaa73e16..000000000000 --- a/sbt-test/unroll-annot/curriedMethod/v2/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,7 +0,0 @@ -package unroll - -import scala.annotation.unroll - -class Unrolled{ - def foo(s: String, @unroll n: Int = 1, b: Boolean = true)(f: String => String) = f(s + n + b) -} diff --git a/sbt-test/unroll-annot/curriedMethod/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/curriedMethod/v3/src/main/scala/Unrolled.scala deleted file mode 100644 index 01c34e9548cf..000000000000 --- a/sbt-test/unroll-annot/curriedMethod/v3/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,7 +0,0 @@ -package unroll - -import scala.annotation.unroll - -class Unrolled{ - def foo(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0)(f: String => String) = f(s + n + b + l) -} diff --git a/sbt-test/unroll-annot/methodWithImplicit/build.sbt b/sbt-test/unroll-annot/methodWithImplicit/build.sbt deleted file mode 100644 index 0568d222bf5a..000000000000 --- a/sbt-test/unroll-annot/methodWithImplicit/build.sbt +++ /dev/null @@ -1,48 +0,0 @@ -lazy val utils = project.in(file("utils")) - -lazy val sharedSettings = Seq( - scalacOptions ++= Seq("-Ycheck:all", "-experimental") -) - -lazy val v1 = project.in(file("v1")) - .settings(sharedSettings) - -lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Compile / unmanagedClasspath := Seq( - Attributed.blank((v1 / Compile / classDirectory).value) - ), - ) - -lazy val v2 = project.in(file("v2")) - .settings(sharedSettings) - -lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value) - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v2 / Compile / classDirectory).value) - ), - ) - -lazy val v3 = project.in(file("v3")) - .settings(sharedSettings) - -lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value), - // add v2_app, compiled against v2, to the classpath - Attributed.blank((v2_app / Runtime / classDirectory).value), - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v3 / Compile / classDirectory).value) - ), - ) diff --git a/sbt-test/unroll-annot/methodWithImplicit/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/methodWithImplicit/project/DottyInjectedPlugin.scala deleted file mode 100644 index 69f15d168bfc..000000000000 --- a/sbt-test/unroll-annot/methodWithImplicit/project/DottyInjectedPlugin.scala +++ /dev/null @@ -1,12 +0,0 @@ -import sbt._ -import Keys._ - -object DottyInjectedPlugin extends AutoPlugin { - override def requires = plugins.JvmPlugin - override def trigger = allRequirements - - override val projectSettings = Seq( - scalaVersion := sys.props("plugin.scalaVersion"), - scalacOptions += "-source:3.0-migration" - ) -} diff --git a/sbt-test/unroll-annot/methodWithImplicit/test b/sbt-test/unroll-annot/methodWithImplicit/test deleted file mode 100644 index e8e500857b0e..000000000000 --- a/sbt-test/unroll-annot/methodWithImplicit/test +++ /dev/null @@ -1,14 +0,0 @@ -# compile and run a basic version of Unrolled (v1), and an app that uses it -> v1/compile -> v1_app/runMain unroll.UnrollTestMainV1 -# add a field to the case class (v2), and update the app to use it, -# and ensure the old version (v1) still links -> v2/compile -> v2_app/runMain unroll.UnrollTestMainV1 -> v2_app/runMain unroll.UnrollTestMainV2 -# add a field to the case class (v3), and update the app to use it, -# and ensure the old versions (v1, v2) still link -> v3/compile -> v3_app/runMain unroll.UnrollTestMainV1 -> v3_app/runMain unroll.UnrollTestMainV2 -> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/methodWithImplicit/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/methodWithImplicit/v2/src/main/scala/Unrolled.scala deleted file mode 100644 index fa98747d28d8..000000000000 --- a/sbt-test/unroll-annot/methodWithImplicit/v2/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,7 +0,0 @@ -package unroll - -import scala.annotation.unroll - -class Unrolled{ - def foo(s: String, @unroll n: Int = 1, b: Boolean = true)(implicit f: String => String) = f(s + n + b) -} diff --git a/sbt-test/unroll-annot/methodWithImplicit/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/methodWithImplicit/v3/src/main/scala/Unrolled.scala deleted file mode 100644 index 58e88f581b4c..000000000000 --- a/sbt-test/unroll-annot/methodWithImplicit/v3/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,7 +0,0 @@ -package unroll - -import scala.annotation.unroll - -class Unrolled{ - def foo(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0)(implicit f: String => String) = f(s + n + b + l) -} diff --git a/sbt-test/unroll-annot/objectMethod/build.sbt b/sbt-test/unroll-annot/objectMethod/build.sbt deleted file mode 100644 index 0568d222bf5a..000000000000 --- a/sbt-test/unroll-annot/objectMethod/build.sbt +++ /dev/null @@ -1,48 +0,0 @@ -lazy val utils = project.in(file("utils")) - -lazy val sharedSettings = Seq( - scalacOptions ++= Seq("-Ycheck:all", "-experimental") -) - -lazy val v1 = project.in(file("v1")) - .settings(sharedSettings) - -lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Compile / unmanagedClasspath := Seq( - Attributed.blank((v1 / Compile / classDirectory).value) - ), - ) - -lazy val v2 = project.in(file("v2")) - .settings(sharedSettings) - -lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value) - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v2 / Compile / classDirectory).value) - ), - ) - -lazy val v3 = project.in(file("v3")) - .settings(sharedSettings) - -lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value), - // add v2_app, compiled against v2, to the classpath - Attributed.blank((v2_app / Runtime / classDirectory).value), - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v3 / Compile / classDirectory).value) - ), - ) diff --git a/sbt-test/unroll-annot/objectMethod/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/objectMethod/project/DottyInjectedPlugin.scala deleted file mode 100644 index 69f15d168bfc..000000000000 --- a/sbt-test/unroll-annot/objectMethod/project/DottyInjectedPlugin.scala +++ /dev/null @@ -1,12 +0,0 @@ -import sbt._ -import Keys._ - -object DottyInjectedPlugin extends AutoPlugin { - override def requires = plugins.JvmPlugin - override def trigger = allRequirements - - override val projectSettings = Seq( - scalaVersion := sys.props("plugin.scalaVersion"), - scalacOptions += "-source:3.0-migration" - ) -} diff --git a/sbt-test/unroll-annot/objectMethod/test b/sbt-test/unroll-annot/objectMethod/test deleted file mode 100644 index e8e500857b0e..000000000000 --- a/sbt-test/unroll-annot/objectMethod/test +++ /dev/null @@ -1,14 +0,0 @@ -# compile and run a basic version of Unrolled (v1), and an app that uses it -> v1/compile -> v1_app/runMain unroll.UnrollTestMainV1 -# add a field to the case class (v2), and update the app to use it, -# and ensure the old version (v1) still links -> v2/compile -> v2_app/runMain unroll.UnrollTestMainV1 -> v2_app/runMain unroll.UnrollTestMainV2 -# add a field to the case class (v3), and update the app to use it, -# and ensure the old versions (v1, v2) still link -> v3/compile -> v3_app/runMain unroll.UnrollTestMainV1 -> v3_app/runMain unroll.UnrollTestMainV2 -> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/objectMethod/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/objectMethod/utils/src/main/scala/TestUtils.scala deleted file mode 100644 index 6ac413c9fe98..000000000000 --- a/sbt-test/unroll-annot/objectMethod/utils/src/main/scala/TestUtils.scala +++ /dev/null @@ -1,12 +0,0 @@ -package unroll - -object TestUtils { - def logAssertStartsWith(actual: String, expected: String): Unit = { - assert(actual.startsWith(expected)) - val suffix = { - val suffix0 = actual.stripPrefix(expected) - if (suffix0.isEmpty) "" else s""" + "$suffix0"""" - } - println(s"""Assertion passed: found "$expected"$suffix""") - } -} diff --git a/sbt-test/unroll-annot/objectMethod/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/objectMethod/v2/src/main/scala/Unrolled.scala deleted file mode 100644 index 53d777884939..000000000000 --- a/sbt-test/unroll-annot/objectMethod/v2/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,7 +0,0 @@ -package unroll - -import scala.annotation.unroll - -object Unrolled{ - def foo(s: String, n: Int = 1, @unroll b: Boolean = true) = s + n + b -} diff --git a/sbt-test/unroll-annot/objectMethod/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/objectMethod/v3/src/main/scala/Unrolled.scala deleted file mode 100644 index 5e3464c184a4..000000000000 --- a/sbt-test/unroll-annot/objectMethod/v3/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,7 +0,0 @@ -package unroll - -import scala.annotation.unroll - -object Unrolled{ - def foo(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = s + n + b + l -} diff --git a/sbt-test/unroll-annot/primaryConstructor/build.sbt b/sbt-test/unroll-annot/primaryConstructor/build.sbt deleted file mode 100644 index 0568d222bf5a..000000000000 --- a/sbt-test/unroll-annot/primaryConstructor/build.sbt +++ /dev/null @@ -1,48 +0,0 @@ -lazy val utils = project.in(file("utils")) - -lazy val sharedSettings = Seq( - scalacOptions ++= Seq("-Ycheck:all", "-experimental") -) - -lazy val v1 = project.in(file("v1")) - .settings(sharedSettings) - -lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Compile / unmanagedClasspath := Seq( - Attributed.blank((v1 / Compile / classDirectory).value) - ), - ) - -lazy val v2 = project.in(file("v2")) - .settings(sharedSettings) - -lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value) - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v2 / Compile / classDirectory).value) - ), - ) - -lazy val v3 = project.in(file("v3")) - .settings(sharedSettings) - -lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value), - // add v2_app, compiled against v2, to the classpath - Attributed.blank((v2_app / Runtime / classDirectory).value), - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v3 / Compile / classDirectory).value) - ), - ) diff --git a/sbt-test/unroll-annot/primaryConstructor/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/primaryConstructor/project/DottyInjectedPlugin.scala deleted file mode 100644 index 69f15d168bfc..000000000000 --- a/sbt-test/unroll-annot/primaryConstructor/project/DottyInjectedPlugin.scala +++ /dev/null @@ -1,12 +0,0 @@ -import sbt._ -import Keys._ - -object DottyInjectedPlugin extends AutoPlugin { - override def requires = plugins.JvmPlugin - override def trigger = allRequirements - - override val projectSettings = Seq( - scalaVersion := sys.props("plugin.scalaVersion"), - scalacOptions += "-source:3.0-migration" - ) -} diff --git a/sbt-test/unroll-annot/primaryConstructor/test b/sbt-test/unroll-annot/primaryConstructor/test deleted file mode 100644 index e8e500857b0e..000000000000 --- a/sbt-test/unroll-annot/primaryConstructor/test +++ /dev/null @@ -1,14 +0,0 @@ -# compile and run a basic version of Unrolled (v1), and an app that uses it -> v1/compile -> v1_app/runMain unroll.UnrollTestMainV1 -# add a field to the case class (v2), and update the app to use it, -# and ensure the old version (v1) still links -> v2/compile -> v2_app/runMain unroll.UnrollTestMainV1 -> v2_app/runMain unroll.UnrollTestMainV2 -# add a field to the case class (v3), and update the app to use it, -# and ensure the old versions (v1, v2) still link -> v3/compile -> v3_app/runMain unroll.UnrollTestMainV1 -> v3_app/runMain unroll.UnrollTestMainV2 -> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/primaryConstructor/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/primaryConstructor/utils/src/main/scala/TestUtils.scala deleted file mode 100644 index 6ac413c9fe98..000000000000 --- a/sbt-test/unroll-annot/primaryConstructor/utils/src/main/scala/TestUtils.scala +++ /dev/null @@ -1,12 +0,0 @@ -package unroll - -object TestUtils { - def logAssertStartsWith(actual: String, expected: String): Unit = { - assert(actual.startsWith(expected)) - val suffix = { - val suffix0 = actual.stripPrefix(expected) - if (suffix0.isEmpty) "" else s""" + "$suffix0"""" - } - println(s"""Assertion passed: found "$expected"$suffix""") - } -} diff --git a/sbt-test/unroll-annot/secondParameterList/build.sbt b/sbt-test/unroll-annot/secondParameterList/build.sbt deleted file mode 100644 index 0568d222bf5a..000000000000 --- a/sbt-test/unroll-annot/secondParameterList/build.sbt +++ /dev/null @@ -1,48 +0,0 @@ -lazy val utils = project.in(file("utils")) - -lazy val sharedSettings = Seq( - scalacOptions ++= Seq("-Ycheck:all", "-experimental") -) - -lazy val v1 = project.in(file("v1")) - .settings(sharedSettings) - -lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Compile / unmanagedClasspath := Seq( - Attributed.blank((v1 / Compile / classDirectory).value) - ), - ) - -lazy val v2 = project.in(file("v2")) - .settings(sharedSettings) - -lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value) - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v2 / Compile / classDirectory).value) - ), - ) - -lazy val v3 = project.in(file("v3")) - .settings(sharedSettings) - -lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value), - // add v2_app, compiled against v2, to the classpath - Attributed.blank((v2_app / Runtime / classDirectory).value), - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v3 / Compile / classDirectory).value) - ), - ) diff --git a/sbt-test/unroll-annot/secondParameterList/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/secondParameterList/project/DottyInjectedPlugin.scala deleted file mode 100644 index 69f15d168bfc..000000000000 --- a/sbt-test/unroll-annot/secondParameterList/project/DottyInjectedPlugin.scala +++ /dev/null @@ -1,12 +0,0 @@ -import sbt._ -import Keys._ - -object DottyInjectedPlugin extends AutoPlugin { - override def requires = plugins.JvmPlugin - override def trigger = allRequirements - - override val projectSettings = Seq( - scalaVersion := sys.props("plugin.scalaVersion"), - scalacOptions += "-source:3.0-migration" - ) -} diff --git a/sbt-test/unroll-annot/secondParameterList/test b/sbt-test/unroll-annot/secondParameterList/test deleted file mode 100644 index e8e500857b0e..000000000000 --- a/sbt-test/unroll-annot/secondParameterList/test +++ /dev/null @@ -1,14 +0,0 @@ -# compile and run a basic version of Unrolled (v1), and an app that uses it -> v1/compile -> v1_app/runMain unroll.UnrollTestMainV1 -# add a field to the case class (v2), and update the app to use it, -# and ensure the old version (v1) still links -> v2/compile -> v2_app/runMain unroll.UnrollTestMainV1 -> v2_app/runMain unroll.UnrollTestMainV2 -# add a field to the case class (v3), and update the app to use it, -# and ensure the old versions (v1, v2) still link -> v3/compile -> v3_app/runMain unroll.UnrollTestMainV1 -> v3_app/runMain unroll.UnrollTestMainV2 -> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/secondParameterList/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/secondParameterList/utils/src/main/scala/TestUtils.scala deleted file mode 100644 index 6ac413c9fe98..000000000000 --- a/sbt-test/unroll-annot/secondParameterList/utils/src/main/scala/TestUtils.scala +++ /dev/null @@ -1,12 +0,0 @@ -package unroll - -object TestUtils { - def logAssertStartsWith(actual: String, expected: String): Unit = { - assert(actual.startsWith(expected)) - val suffix = { - val suffix0 = actual.stripPrefix(expected) - if (suffix0.isEmpty) "" else s""" + "$suffix0"""" - } - println(s"""Assertion passed: found "$expected"$suffix""") - } -} diff --git a/sbt-test/unroll-annot/secondParameterList/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/secondParameterList/v2/src/main/scala/Unrolled.scala deleted file mode 100644 index 81d481deff38..000000000000 --- a/sbt-test/unroll-annot/secondParameterList/v2/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,7 +0,0 @@ -package unroll - -import scala.annotation.unroll - -class Unrolled{ - def foo(f: String => String)(s: String, @unroll n: Int = 1, b: Boolean = true) = f(s + n + b) -} diff --git a/sbt-test/unroll-annot/secondParameterList/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/secondParameterList/v3/src/main/scala/Unrolled.scala deleted file mode 100644 index 35803d5220a8..000000000000 --- a/sbt-test/unroll-annot/secondParameterList/v3/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,7 +0,0 @@ -package unroll - -import scala.annotation.unroll - -class Unrolled{ - def foo(f: String => String)(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0) = f(s + n + b + l) -} diff --git a/sbt-test/unroll-annot/secondaryConstructor/build.sbt b/sbt-test/unroll-annot/secondaryConstructor/build.sbt deleted file mode 100644 index 0568d222bf5a..000000000000 --- a/sbt-test/unroll-annot/secondaryConstructor/build.sbt +++ /dev/null @@ -1,48 +0,0 @@ -lazy val utils = project.in(file("utils")) - -lazy val sharedSettings = Seq( - scalacOptions ++= Seq("-Ycheck:all", "-experimental") -) - -lazy val v1 = project.in(file("v1")) - .settings(sharedSettings) - -lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Compile / unmanagedClasspath := Seq( - Attributed.blank((v1 / Compile / classDirectory).value) - ), - ) - -lazy val v2 = project.in(file("v2")) - .settings(sharedSettings) - -lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value) - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v2 / Compile / classDirectory).value) - ), - ) - -lazy val v3 = project.in(file("v3")) - .settings(sharedSettings) - -lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value), - // add v2_app, compiled against v2, to the classpath - Attributed.blank((v2_app / Runtime / classDirectory).value), - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v3 / Compile / classDirectory).value) - ), - ) diff --git a/sbt-test/unroll-annot/secondaryConstructor/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/secondaryConstructor/project/DottyInjectedPlugin.scala deleted file mode 100644 index 69f15d168bfc..000000000000 --- a/sbt-test/unroll-annot/secondaryConstructor/project/DottyInjectedPlugin.scala +++ /dev/null @@ -1,12 +0,0 @@ -import sbt._ -import Keys._ - -object DottyInjectedPlugin extends AutoPlugin { - override def requires = plugins.JvmPlugin - override def trigger = allRequirements - - override val projectSettings = Seq( - scalaVersion := sys.props("plugin.scalaVersion"), - scalacOptions += "-source:3.0-migration" - ) -} diff --git a/sbt-test/unroll-annot/secondaryConstructor/test b/sbt-test/unroll-annot/secondaryConstructor/test deleted file mode 100644 index e8e500857b0e..000000000000 --- a/sbt-test/unroll-annot/secondaryConstructor/test +++ /dev/null @@ -1,14 +0,0 @@ -# compile and run a basic version of Unrolled (v1), and an app that uses it -> v1/compile -> v1_app/runMain unroll.UnrollTestMainV1 -# add a field to the case class (v2), and update the app to use it, -# and ensure the old version (v1) still links -> v2/compile -> v2_app/runMain unroll.UnrollTestMainV1 -> v2_app/runMain unroll.UnrollTestMainV2 -# add a field to the case class (v3), and update the app to use it, -# and ensure the old versions (v1, v2) still link -> v3/compile -> v3_app/runMain unroll.UnrollTestMainV1 -> v3_app/runMain unroll.UnrollTestMainV2 -> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/secondaryConstructor/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/secondaryConstructor/utils/src/main/scala/TestUtils.scala deleted file mode 100644 index 6ac413c9fe98..000000000000 --- a/sbt-test/unroll-annot/secondaryConstructor/utils/src/main/scala/TestUtils.scala +++ /dev/null @@ -1,12 +0,0 @@ -package unroll - -object TestUtils { - def logAssertStartsWith(actual: String, expected: String): Unit = { - assert(actual.startsWith(expected)) - val suffix = { - val suffix0 = actual.stripPrefix(expected) - if (suffix0.isEmpty) "" else s""" + "$suffix0"""" - } - println(s"""Assertion passed: found "$expected"$suffix""") - } -} diff --git a/sbt-test/unroll-annot/traitMethod/build.sbt b/sbt-test/unroll-annot/traitMethod/build.sbt deleted file mode 100644 index 0568d222bf5a..000000000000 --- a/sbt-test/unroll-annot/traitMethod/build.sbt +++ /dev/null @@ -1,48 +0,0 @@ -lazy val utils = project.in(file("utils")) - -lazy val sharedSettings = Seq( - scalacOptions ++= Seq("-Ycheck:all", "-experimental") -) - -lazy val v1 = project.in(file("v1")) - .settings(sharedSettings) - -lazy val v1_app = project.in(file("v1_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Compile / unmanagedClasspath := Seq( - Attributed.blank((v1 / Compile / classDirectory).value) - ), - ) - -lazy val v2 = project.in(file("v2")) - .settings(sharedSettings) - -lazy val v2_app = project.in(file("v2_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value) - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v2 / Compile / classDirectory).value) - ), - ) - -lazy val v3 = project.in(file("v3")) - .settings(sharedSettings) - -lazy val v3_app = project.in(file("v3_app")).dependsOn(utils) - .settings(sharedSettings) - .settings( - Runtime / unmanagedClasspath := Seq( - // add v1_app, compiled against v1, to the classpath - Attributed.blank((v1_app / Runtime / classDirectory).value), - // add v2_app, compiled against v2, to the classpath - Attributed.blank((v2_app / Runtime / classDirectory).value), - ), - Compile / unmanagedClasspath := Seq( - Attributed.blank((v3 / Compile / classDirectory).value) - ), - ) diff --git a/sbt-test/unroll-annot/traitMethod/project/DottyInjectedPlugin.scala b/sbt-test/unroll-annot/traitMethod/project/DottyInjectedPlugin.scala deleted file mode 100644 index 69f15d168bfc..000000000000 --- a/sbt-test/unroll-annot/traitMethod/project/DottyInjectedPlugin.scala +++ /dev/null @@ -1,12 +0,0 @@ -import sbt._ -import Keys._ - -object DottyInjectedPlugin extends AutoPlugin { - override def requires = plugins.JvmPlugin - override def trigger = allRequirements - - override val projectSettings = Seq( - scalaVersion := sys.props("plugin.scalaVersion"), - scalacOptions += "-source:3.0-migration" - ) -} diff --git a/sbt-test/unroll-annot/traitMethod/test b/sbt-test/unroll-annot/traitMethod/test deleted file mode 100644 index e8e500857b0e..000000000000 --- a/sbt-test/unroll-annot/traitMethod/test +++ /dev/null @@ -1,14 +0,0 @@ -# compile and run a basic version of Unrolled (v1), and an app that uses it -> v1/compile -> v1_app/runMain unroll.UnrollTestMainV1 -# add a field to the case class (v2), and update the app to use it, -# and ensure the old version (v1) still links -> v2/compile -> v2_app/runMain unroll.UnrollTestMainV1 -> v2_app/runMain unroll.UnrollTestMainV2 -# add a field to the case class (v3), and update the app to use it, -# and ensure the old versions (v1, v2) still link -> v3/compile -> v3_app/runMain unroll.UnrollTestMainV1 -> v3_app/runMain unroll.UnrollTestMainV2 -> v3_app/runMain unroll.UnrollTestMainV3 diff --git a/sbt-test/unroll-annot/traitMethod/utils/src/main/scala/TestUtils.scala b/sbt-test/unroll-annot/traitMethod/utils/src/main/scala/TestUtils.scala deleted file mode 100644 index 6ac413c9fe98..000000000000 --- a/sbt-test/unroll-annot/traitMethod/utils/src/main/scala/TestUtils.scala +++ /dev/null @@ -1,12 +0,0 @@ -package unroll - -object TestUtils { - def logAssertStartsWith(actual: String, expected: String): Unit = { - assert(actual.startsWith(expected)) - val suffix = { - val suffix0 = actual.stripPrefix(expected) - if (suffix0.isEmpty) "" else s""" + "$suffix0"""" - } - println(s"""Assertion passed: found "$expected"$suffix""") - } -} diff --git a/sbt-test/unroll-annot/traitMethod/v2/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/traitMethod/v2/src/main/scala/Unrolled.scala deleted file mode 100644 index 7d40ff17b846..000000000000 --- a/sbt-test/unroll-annot/traitMethod/v2/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,9 +0,0 @@ -package unroll - -import scala.annotation.unroll - -trait Unrolled{ - def foo(s: String, n: Int = 1, @unroll b: Boolean = true) = s + n + b -} - -object Unrolled extends Unrolled \ No newline at end of file diff --git a/sbt-test/unroll-annot/traitMethod/v3/src/main/scala/Unrolled.scala b/sbt-test/unroll-annot/traitMethod/v3/src/main/scala/Unrolled.scala deleted file mode 100644 index 085ecea52adf..000000000000 --- a/sbt-test/unroll-annot/traitMethod/v3/src/main/scala/Unrolled.scala +++ /dev/null @@ -1,9 +0,0 @@ -package unroll - -import scala.annotation.unroll - -trait Unrolled{ - def foo(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = s + n + b + l -} - -object Unrolled extends Unrolled \ No newline at end of file diff --git a/tests/neg/unroll-abstractMethod.check b/tests/neg/unroll-abstractMethod.check new file mode 100644 index 000000000000..948c7d1a7862 --- /dev/null +++ b/tests/neg/unroll-abstractMethod.check @@ -0,0 +1,8 @@ +-- [E207] Declaration Error: tests/neg/unroll-abstractMethod.scala:6:41 ------------------------------------------------ +6 | def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String // error + | ^ + | Can not unroll parameters of method foo: it must not be abstract +-- [E207] Declaration Error: tests/neg/unroll-abstractMethod.scala:10:41 ----------------------------------------------- +10 | def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String // error + | ^ + | Can not unroll parameters of method foo: it must not be abstract diff --git a/tests/neg/unroll-abstractMethod.scala b/tests/neg/unroll-abstractMethod.scala new file mode 100644 index 000000000000..8f30fb63b20f --- /dev/null +++ b/tests/neg/unroll-abstractMethod.scala @@ -0,0 +1,11 @@ +//> using options -experimental + +import scala.annotation.unroll + +trait Unrolled { + def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String // error +} + +abstract class UnrolledBase { + def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String // error +} diff --git a/tests/neg/unroll-clash.check b/tests/neg/unroll-clash.check new file mode 100644 index 000000000000..a398c550c461 --- /dev/null +++ b/tests/neg/unroll-clash.check @@ -0,0 +1,12 @@ +-- Error: tests/neg/unroll-clash.scala:7:6 ----------------------------------------------------------------------------- +7 | def foo(x: Int) = { // error + | ^ + | Unrolled method foo clashes with existing declaration. + | Please remove the clashing definition, or the @unroll annotation. + | Unrolled from final def foo(x: Int, y: Int): Int in class Foo at line 6 +-- Error: tests/neg/unroll-clash.scala:13:20 --------------------------------------------------------------------------- +13 |class UnrolledClass2(s: String) { // error + | ^ + | Unrolled constructor UnrolledClass2 clashes with existing declaration. + | Please remove the clashing definition, or the @unroll annotation. + | Unrolled from def (s: String, y: Boolean): UnrolledClass2 in class UnrolledClass2 at line 15 diff --git a/tests/neg/unroll-clash.scala b/tests/neg/unroll-clash.scala new file mode 100644 index 000000000000..79a75c2ba785 --- /dev/null +++ b/tests/neg/unroll-clash.scala @@ -0,0 +1,18 @@ +//> using options -experimental + +import scala.annotation.unroll + +class Foo { + final def foo(x: Int, @unroll y: Int = 0) = x + y + def foo(x: Int) = { // error + println("Not binary compatible!") + -1 + } +} + +class UnrolledClass2(s: String) { // error + + def this(s: String, @unroll y: Boolean = true) = this(s + y) + + override def toString = s"UnrolledClass2($s)" +} diff --git a/tests/neg/unroll-duped.check b/tests/neg/unroll-duped.check new file mode 100644 index 000000000000..2c1cc80cfee7 --- /dev/null +++ b/tests/neg/unroll-duped.check @@ -0,0 +1,12 @@ +-- [E207] Declaration Error: tests/neg/unroll-duped.scala:11:45 -------------------------------------------------------- +11 | final def copy(s: String = this.s, @unroll y: Boolean = this.y): UnrolledCase = // error + | ^ + | Can not unroll parameters of method copy of a case class: please annotate the class constructor instead +-- [E207] Declaration Error: tests/neg/unroll-duped.scala:18:12 -------------------------------------------------------- +18 | @unroll y: Boolean = true // error + | ^ + |Can not unroll parameters of method apply of a case class companion object: please annotate the class constructor instead +-- [E207] Declaration Error: tests/neg/unroll-duped.scala:22:26 -------------------------------------------------------- +22 | def fromProduct(@unroll p: Product = EmptyTuple): UnrolledCase = { // error + | ^ + |Can not unroll parameters of method fromProduct of a case class companion object: please annotate the class constructor instead diff --git a/tests/neg/unroll-duped.scala b/tests/neg/unroll-duped.scala new file mode 100644 index 000000000000..a578fc837628 --- /dev/null +++ b/tests/neg/unroll-duped.scala @@ -0,0 +1,27 @@ +//> using options -experimental + +import scala.annotation.unroll + +case class UnrolledCase( + s: String, + y: Boolean = true, +) { + def foo: String = s + y + + final def copy(s: String = this.s, @unroll y: Boolean = this.y): UnrolledCase = // error + new UnrolledCase(s, y) +} + +object UnrolledCase { + def apply( + s: String, + @unroll y: Boolean = true // error + ): UnrolledCase = + new UnrolledCase(s, y) + + def fromProduct(@unroll p: Product = EmptyTuple): UnrolledCase = { // error + val s = p.productElement(0).asInstanceOf[String] + val y = p.productElement(1).asInstanceOf[Boolean] + UnrolledCase(s, y) + } +} diff --git a/tests/neg/unroll-illegal.check b/tests/neg/unroll-illegal.check new file mode 100644 index 000000000000..96d7528ac338 --- /dev/null +++ b/tests/neg/unroll-illegal.check @@ -0,0 +1,36 @@ +-- [E207] Declaration Error: tests/neg/unroll-illegal.scala:6:6 -------------------------------------------------------- +6 |class UnrollClass // error + | ^ + | @unroll is only allowed on a method parameter +-- [E207] Declaration Error: tests/neg/unroll-illegal.scala:9:6 -------------------------------------------------------- +9 |trait UnrollTrait // error + | ^ + | @unroll is only allowed on a method parameter +-- [E207] Declaration Error: tests/neg/unroll-illegal.scala:12:7 ------------------------------------------------------- +12 |object UnrollObject // error + | ^ + | @unroll is only allowed on a method parameter +-- [E207] Declaration Error: tests/neg/unroll-illegal.scala:18:5 ------------------------------------------------------- +18 |enum UnrollEnum { case X } // error + | ^ + | @unroll is only allowed on a method parameter +-- [E207] Declaration Error: tests/neg/unroll-illegal.scala:21:25 ------------------------------------------------------ +21 | val annotExpr: Int = 23: @unroll // error + | ^ + | @unroll is only allowed on a method parameter +-- [E207] Declaration Error: tests/neg/unroll-illegal.scala:22:19 ------------------------------------------------------ +22 | type annotType = Int @unroll // error + | ^^^^^^^^^^^ + | @unroll is only allowed on a method parameter +-- [E207] Declaration Error: tests/neg/unroll-illegal.scala:25:6 ------------------------------------------------------- +25 | val unrollVal: Int = 23 // error + | ^ + | @unroll is only allowed on a method parameter +-- [E207] Declaration Error: tests/neg/unroll-illegal.scala:28:6 ------------------------------------------------------- +28 | def unrollDef: Int = 23 // error + | ^ + | @unroll is only allowed on a method parameter +-- [E207] Declaration Error: tests/neg/unroll-illegal.scala:15:5 ------------------------------------------------------- +15 |type UnrollType = Int // error + | ^ + | @unroll is only allowed on a method parameter diff --git a/tests/neg/unroll-illegal.scala b/tests/neg/unroll-illegal.scala new file mode 100644 index 000000000000..0b40a1c33c03 --- /dev/null +++ b/tests/neg/unroll-illegal.scala @@ -0,0 +1,29 @@ +//> using options -experimental + +import scala.annotation.unroll + +@unroll +class UnrollClass // error + +@unroll +trait UnrollTrait // error + +@unroll +object UnrollObject // error + +@unroll +type UnrollType = Int // error + +@unroll +enum UnrollEnum { case X } // error + +object wrap { + val annotExpr: Int = 23: @unroll // error + type annotType = Int @unroll // error + + @unroll + val unrollVal: Int = 23 // error + + @unroll + def unrollDef: Int = 23 // error +} diff --git a/tests/neg/unroll-illegal2.check b/tests/neg/unroll-illegal2.check new file mode 100644 index 000000000000..e2ead2ee3fe7 --- /dev/null +++ b/tests/neg/unroll-illegal2.check @@ -0,0 +1,4 @@ +-- [E200] Syntax Error: tests/neg/unroll-illegal2.scala:7:10 ----------------------------------------------------------- +7 | final def foo(s: String, @unroll y: Boolean) = s + y // error + | ^^^ + | The final modifier is not allowed on local definitions diff --git a/tests/neg/unroll-illegal2.scala b/tests/neg/unroll-illegal2.scala new file mode 100644 index 000000000000..ad7284506bbf --- /dev/null +++ b/tests/neg/unroll-illegal2.scala @@ -0,0 +1,9 @@ +//> using options -experimental + +import scala.annotation.unroll + +class wrap { + locally { + final def foo(s: String, @unroll y: Boolean) = s + y // error + } +} diff --git a/tests/neg/unroll-illegal3.check b/tests/neg/unroll-illegal3.check new file mode 100644 index 000000000000..8502b76b50e2 --- /dev/null +++ b/tests/neg/unroll-illegal3.check @@ -0,0 +1,12 @@ +-- [E207] Declaration Error: tests/neg/unroll-illegal3.scala:7:31 ------------------------------------------------------ +7 | def foo(s: String, @unroll y: Boolean) = s + y // error + | ^ + | Can not unroll parameters of method foo: it is not final +-- [E207] Declaration Error: tests/neg/unroll-illegal3.scala:12:29 ----------------------------------------------------- +12 | def foo(s: String, @unroll y: Boolean) = s + y // error + | ^ + | Can not unroll parameters of method foo: it is not final +-- [E207] Declaration Error: tests/neg/unroll-illegal3.scala:16:29 ----------------------------------------------------- +16 | def foo(s: String, @unroll y: Boolean): String // error + | ^ + | Can not unroll parameters of method foo: it must not be abstract diff --git a/tests/neg/unroll-illegal3.scala b/tests/neg/unroll-illegal3.scala new file mode 100644 index 000000000000..22a53bd04de6 --- /dev/null +++ b/tests/neg/unroll-illegal3.scala @@ -0,0 +1,17 @@ +//> using options -experimental + +import scala.annotation.unroll + +object wrap { + locally { + def foo(s: String, @unroll y: Boolean) = s + y // error + } +} + +class UnrolledCls { + def foo(s: String, @unroll y: Boolean) = s + y // error +} + +trait UnrolledTrait { + def foo(s: String, @unroll y: Boolean): String // error +} diff --git a/tests/neg/unroll-multipleParams.check b/tests/neg/unroll-multipleParams.check new file mode 100644 index 000000000000..f8f1bc22510c --- /dev/null +++ b/tests/neg/unroll-multipleParams.check @@ -0,0 +1,4 @@ +-- Error: tests/neg/unroll-multipleParams.scala:6:12 ------------------------------------------------------------------- +6 | final def foo(x: Int, @unroll y: Int = 0)(@unroll z: Int = 0) = x + y + z // error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | Cannot have multiple parameter lists containing `@unroll` annotation diff --git a/tests/neg/unroll-multipleParams.scala b/tests/neg/unroll-multipleParams.scala new file mode 100644 index 000000000000..80371fec74c4 --- /dev/null +++ b/tests/neg/unroll-multipleParams.scala @@ -0,0 +1,7 @@ +//> using options -experimental + +import scala.annotation.unroll + +class Foo { + final def foo(x: Int, @unroll y: Int = 0)(@unroll z: Int = 0) = x + y + z // error +} diff --git a/tests/neg/unroll-no-default.check b/tests/neg/unroll-no-default.check new file mode 100644 index 000000000000..d16a94ce0527 --- /dev/null +++ b/tests/neg/unroll-no-default.check @@ -0,0 +1,4 @@ +-- Error: tests/neg/unroll-no-default.scala:6:32 ----------------------------------------------------------------------- +6 | final def foo(x: Int, @unroll y: Int) = x + y // error + | ^^^^^^^^^^^^^^ + | Cannot unroll method foo in class Foo at line 6 because parameter y needs a default value diff --git a/tests/neg/unroll-no-default.scala b/tests/neg/unroll-no-default.scala new file mode 100644 index 000000000000..1058f34087e3 --- /dev/null +++ b/tests/neg/unroll-no-default.scala @@ -0,0 +1,7 @@ +//> using options -experimental -Xprint:unrollDefs + +import scala.annotation.unroll + +class Foo { + final def foo(x: Int, @unroll y: Int) = x + y // error +} diff --git a/tests/neg/unroll-traitConstructor.check b/tests/neg/unroll-traitConstructor.check new file mode 100644 index 000000000000..0a5570667196 --- /dev/null +++ b/tests/neg/unroll-traitConstructor.check @@ -0,0 +1,4 @@ +-- [E207] Declaration Error: tests/neg/unroll-traitConstructor.scala:5:32 ---------------------------------------------- +5 |trait Unroll(a: String, @unroll b: Boolean = true): // error + | ^ + | implementation restriction: Can not unroll parameters of a trait constructor diff --git a/tests/neg/unroll-traitConstructor.scala b/tests/neg/unroll-traitConstructor.scala new file mode 100644 index 000000000000..3c48852d8303 --- /dev/null +++ b/tests/neg/unroll-traitConstructor.scala @@ -0,0 +1,8 @@ +//> using options -experimental + +import scala.annotation.unroll + +trait Unroll(a: String, @unroll b: Boolean = true): // error + def show: String = a + b + +class Bar(arg: String, bool: Boolean) extends Unroll(arg, bool) diff --git a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala index 65e3a730ee7e..2c4ee5401f92 100644 --- a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala @@ -93,7 +93,10 @@ val experimentalDefinitionInLibrary = Set( "scala.quoted.runtime.Patterns$.higherOrderHoleWithTypes", // New feature: SIP 57 - runtimeChecked replacement of @unchecked - "scala.Predef$.runtimeChecked", "scala.annotation.internal.RuntimeChecked" + "scala.Predef$.runtimeChecked", "scala.annotation.internal.RuntimeChecked", + + // New feature: SIP 61 - @unroll annotation + "scala.annotation.unroll" ) diff --git a/sbt-test/unroll-annot/caseclass/utils/src/main/scala/TestUtils.scala b/tests/run/unroll-caseclass-integration/TestUtils_1.scala similarity index 91% rename from sbt-test/unroll-annot/caseclass/utils/src/main/scala/TestUtils.scala rename to tests/run/unroll-caseclass-integration/TestUtils_1.scala index 6ac413c9fe98..e639a54d924b 100644 --- a/sbt-test/unroll-annot/caseclass/utils/src/main/scala/TestUtils.scala +++ b/tests/run/unroll-caseclass-integration/TestUtils_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll object TestUtils { diff --git a/tests/run/unroll-caseclass-integration/Test_4.scala b/tests/run/unroll-caseclass-integration/Test_4.scala new file mode 100644 index 000000000000..cae956f8b1bf --- /dev/null +++ b/tests/run/unroll-caseclass-integration/Test_4.scala @@ -0,0 +1,8 @@ +//> using options -experimental +// scalajs: --skip +import unroll.* + +@main def Test: Unit = + UnrollTestMainV1.main(Array.empty[String]) + UnrollTestMainV2.main(Array.empty[String]) + UnrollTestMainV3.main(Array.empty[String]) diff --git a/sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-caseclass-integration/UnrollTestMain_1.scala similarity index 95% rename from sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-caseclass-integration/UnrollTestMain_1.scala index e0b058ad0230..45ce6a768f2a 100644 --- a/sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-caseclass-integration/UnrollTestMain_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-caseclass-integration/UnrollTestMain_2.scala similarity index 96% rename from sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-caseclass-integration/UnrollTestMain_2.scala index c266a5f8c88e..f6cfbfc54a2c 100644 --- a/sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-caseclass-integration/UnrollTestMain_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-caseclass-integration/UnrollTestMain_3.scala similarity index 97% rename from sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-caseclass-integration/UnrollTestMain_3.scala index a58303a6bdad..b0e4d7a5d25a 100644 --- a/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-caseclass-integration/UnrollTestMain_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala similarity index 94% rename from sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala rename to tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala index 07dee69cd8a7..e06a38502c62 100644 --- a/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala +++ b/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala @@ -1,3 +1,5 @@ +//> using options -experimental +// scalajs: --skip package unroll object UnrollTestPlatformSpecificV3{ @@ -30,4 +32,4 @@ object UnrollTestPlatformSpecificV3{ cls.getConstructors.foreach(println) } -} \ No newline at end of file +} diff --git a/sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestScalaSpecific.scala b/tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_1.scala similarity index 78% rename from sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestScalaSpecific.scala rename to tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_1.scala index 514905a741f4..28eb2815e979 100644 --- a/sbt-test/unroll-annot/caseclass/v1_app/src/main/scala/UnrollTestScalaSpecific.scala +++ b/tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_1.scala @@ -1,10 +1,11 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith object UnrollTestScalaSpecificV1{ def test() = { - val unrolled = Unrolled.fromProduct( + val unrolled = summon[scala.deriving.Mirror.Of[Unrolled]].fromProduct( new Product{ def canEqual(that: Any) = true def productArity = 2 diff --git a/sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestScalaSpecific.scala b/tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_2.scala similarity index 79% rename from sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestScalaSpecific.scala rename to tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_2.scala index 88ead065de6e..5d4079a093ce 100644 --- a/sbt-test/unroll-annot/caseclass/v2_app/src/main/scala/UnrollTestScalaSpecific.scala +++ b/tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_2.scala @@ -1,10 +1,11 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith object UnrollTestScalaSpecificV2{ def test() = { - val unrolled = Unrolled.fromProduct( + val unrolled = summon[scala.deriving.Mirror.Of[Unrolled]].fromProduct( new Product { def canEqual(that: Any) = true def productArity = 3 diff --git a/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestScalaSpecific.scala b/tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_3.scala similarity index 80% rename from sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestScalaSpecific.scala rename to tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_3.scala index 13d4fffe7f62..46f84998baa0 100644 --- a/sbt-test/unroll-annot/caseclass/v3_app/src/main/scala/UnrollTestScalaSpecific.scala +++ b/tests/run/unroll-caseclass-integration/UnrollTestScalaSpecific_3.scala @@ -1,8 +1,9 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith object UnrollTestScalaSpecificV3{ def apply() = { - val unrolled = Unrolled.fromProduct( + val unrolled = summon[scala.deriving.Mirror.Of[Unrolled]].fromProduct( new Product { def canEqual(that: Any) = true def productArity = 4 diff --git a/sbt-test/unroll-annot/caseclass/v1/src/main/scala/Unrolled.scala b/tests/run/unroll-caseclass-integration/Unrolled_1.scala similarity index 71% rename from sbt-test/unroll-annot/caseclass/v1/src/main/scala/Unrolled.scala rename to tests/run/unroll-caseclass-integration/Unrolled_1.scala index 997ae2f2dc00..e3f57bddd325 100644 --- a/sbt-test/unroll-annot/caseclass/v1/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-caseclass-integration/Unrolled_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll case class Unrolled(s: String, n: Int = 1){ diff --git a/sbt-test/unroll-annot/caseclass/v2/src/main/scala/Unrolled.scala b/tests/run/unroll-caseclass-integration/Unrolled_2.scala similarity index 81% rename from sbt-test/unroll-annot/caseclass/v2/src/main/scala/Unrolled.scala rename to tests/run/unroll-caseclass-integration/Unrolled_2.scala index 916c44550a13..cb2232a57726 100644 --- a/sbt-test/unroll-annot/caseclass/v2/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-caseclass-integration/Unrolled_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import scala.annotation.unroll diff --git a/sbt-test/unroll-annot/caseclass/v3/src/main/scala/Unrolled.scala b/tests/run/unroll-caseclass-integration/Unrolled_3.scala similarity index 84% rename from sbt-test/unroll-annot/caseclass/v3/src/main/scala/Unrolled.scala rename to tests/run/unroll-caseclass-integration/Unrolled_3.scala index f1bf8c01ad2a..66b4981660df 100644 --- a/sbt-test/unroll-annot/caseclass/v3/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-caseclass-integration/Unrolled_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import scala.annotation.unroll diff --git a/tests/run/unroll-caseclass.check b/tests/run/unroll-caseclass.check index 3d0ebd182b9f..ad59ed9b4dde 100644 --- a/tests/run/unroll-caseclass.check +++ b/tests/run/unroll-caseclass.check @@ -20,9 +20,9 @@ Assertion passed: found "hello31337false" + "0" === Unrolled Test V3 === Assertion passed: found "hello31337false12345" as expected, no constructor for Unrolled(s: String) -public example.Unrolled(java.lang.String,int,boolean,long) public example.Unrolled(java.lang.String,int) public example.Unrolled(java.lang.String,int,boolean) +public example.Unrolled(java.lang.String,int,boolean,long) Assertion passed: found "cow1true0" Assertion passed: found "cow2true0" Assertion passed: found "cow2false0" diff --git a/tests/run/unroll-caseclass/Test_4.scala b/tests/run/unroll-caseclass/Test_4.scala index 3040e9133652..8b6b72f79cf7 100644 --- a/tests/run/unroll-caseclass/Test_4.scala +++ b/tests/run/unroll-caseclass/Test_4.scala @@ -1,4 +1,6 @@ //> using options -experimental +// scalajs: --skip + import example.* // !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check @main def Test(): Unit = { diff --git a/tests/run/unroll-caseclass/unrolledV1_1.scala b/tests/run/unroll-caseclass/unrolledV1_1.scala index a07e8499442e..639a994e7e36 100644 --- a/tests/run/unroll-caseclass/unrolledV1_1.scala +++ b/tests/run/unroll-caseclass/unrolledV1_1.scala @@ -1,4 +1,5 @@ //> using options -experimental +// scalajs: --skip package example // !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check diff --git a/tests/run/unroll-caseclass/unrolledV2_2.scala b/tests/run/unroll-caseclass/unrolledV2_2.scala index e1affa387652..7833c0eb6892 100644 --- a/tests/run/unroll-caseclass/unrolledV2_2.scala +++ b/tests/run/unroll-caseclass/unrolledV2_2.scala @@ -1,4 +1,5 @@ //> using options -experimental +// scalajs: --skip package example // !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check diff --git a/tests/run/unroll-caseclass/unrolledV3_3.scala b/tests/run/unroll-caseclass/unrolledV3_3.scala index 9bb2d66a0039..24f8b59ac78e 100644 --- a/tests/run/unroll-caseclass/unrolledV3_3.scala +++ b/tests/run/unroll-caseclass/unrolledV3_3.scala @@ -1,4 +1,5 @@ //> using options -experimental +// scalajs: --skip package example // !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check @@ -90,6 +91,6 @@ object UnrollTestPlatformSpecificV3 extends TestUtil { "hello2false3" ) - cls.getConstructors.foreach(println) + cls.getConstructors.sortBy(_.getParameterCount()).foreach(println) } } diff --git a/sbt-test/unroll-annot/classMethod/utils/src/main/scala/TestUtils.scala b/tests/run/unroll-classMethod-integration/TestUtils_1.scala similarity index 91% rename from sbt-test/unroll-annot/classMethod/utils/src/main/scala/TestUtils.scala rename to tests/run/unroll-classMethod-integration/TestUtils_1.scala index 6ac413c9fe98..e639a54d924b 100644 --- a/sbt-test/unroll-annot/classMethod/utils/src/main/scala/TestUtils.scala +++ b/tests/run/unroll-classMethod-integration/TestUtils_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll object TestUtils { diff --git a/tests/run/unroll-classMethod-integration/Test_4.scala b/tests/run/unroll-classMethod-integration/Test_4.scala new file mode 100644 index 000000000000..cae956f8b1bf --- /dev/null +++ b/tests/run/unroll-classMethod-integration/Test_4.scala @@ -0,0 +1,8 @@ +//> using options -experimental +// scalajs: --skip +import unroll.* + +@main def Test: Unit = + UnrollTestMainV1.main(Array.empty[String]) + UnrollTestMainV2.main(Array.empty[String]) + UnrollTestMainV3.main(Array.empty[String]) diff --git a/sbt-test/unroll-annot/classMethod/v1_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-classMethod-integration/UnrollTestMain_1.scala similarity index 85% rename from sbt-test/unroll-annot/classMethod/v1_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-classMethod-integration/UnrollTestMain_1.scala index f36e9dd07fed..62d61c81d21d 100644 --- a/sbt-test/unroll-annot/classMethod/v1_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-classMethod-integration/UnrollTestMain_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/classMethod/v2_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-classMethod-integration/UnrollTestMain_2.scala similarity index 91% rename from sbt-test/unroll-annot/classMethod/v2_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-classMethod-integration/UnrollTestMain_2.scala index 91b54aa9742c..921ee48ff0db 100644 --- a/sbt-test/unroll-annot/classMethod/v2_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-classMethod-integration/UnrollTestMain_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-classMethod-integration/UnrollTestMain_3.scala similarity index 93% rename from sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-classMethod-integration/UnrollTestMain_3.scala index 9a6daa3a9210..bc985b58c359 100644 --- a/sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-classMethod-integration/UnrollTestMain_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala similarity index 94% rename from sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala rename to tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala index e8527808befd..3b5dc603fd3a 100644 --- a/sbt-test/unroll-annot/classMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala +++ b/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -1,3 +1,5 @@ +//> using options -experimental +// scalajs: --skip package unroll object UnrollTestPlatformSpecificV3{ @@ -27,4 +29,4 @@ object UnrollTestPlatformSpecificV3{ cls.getMethods.filter(_.getName.contains("foo")).foreach(println) } -} \ No newline at end of file +} diff --git a/sbt-test/unroll-annot/classMethod/v1/src/main/scala/Unrolled.scala b/tests/run/unroll-classMethod-integration/Unrolled_1.scala similarity index 64% rename from sbt-test/unroll-annot/classMethod/v1/src/main/scala/Unrolled.scala rename to tests/run/unroll-classMethod-integration/Unrolled_1.scala index 638bcfdeb96d..aa6ca65fe6a3 100644 --- a/sbt-test/unroll-annot/classMethod/v1/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-classMethod-integration/Unrolled_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll class Unrolled{ diff --git a/tests/run/unroll-classMethod-integration/Unrolled_2.scala b/tests/run/unroll-classMethod-integration/Unrolled_2.scala new file mode 100644 index 000000000000..2091bb4c5a9e --- /dev/null +++ b/tests/run/unroll-classMethod-integration/Unrolled_2.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +class Unrolled{ + final def foo(s: String, @unroll n: Int = 1, b: Boolean = true) = s + n + b +} diff --git a/tests/run/unroll-classMethod-integration/Unrolled_3.scala b/tests/run/unroll-classMethod-integration/Unrolled_3.scala new file mode 100644 index 000000000000..8991bda3aeb7 --- /dev/null +++ b/tests/run/unroll-classMethod-integration/Unrolled_3.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +class Unrolled{ + final def foo(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0) = s + n + b + l +} diff --git a/sbt-test/unroll-annot/curriedMethod/utils/src/main/scala/TestUtils.scala b/tests/run/unroll-curriedMethod-integration/TestUtils_1.scala similarity index 91% rename from sbt-test/unroll-annot/curriedMethod/utils/src/main/scala/TestUtils.scala rename to tests/run/unroll-curriedMethod-integration/TestUtils_1.scala index 6ac413c9fe98..e639a54d924b 100644 --- a/sbt-test/unroll-annot/curriedMethod/utils/src/main/scala/TestUtils.scala +++ b/tests/run/unroll-curriedMethod-integration/TestUtils_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll object TestUtils { diff --git a/tests/run/unroll-curriedMethod-integration/Test_4.scala b/tests/run/unroll-curriedMethod-integration/Test_4.scala new file mode 100644 index 000000000000..cae956f8b1bf --- /dev/null +++ b/tests/run/unroll-curriedMethod-integration/Test_4.scala @@ -0,0 +1,8 @@ +//> using options -experimental +// scalajs: --skip +import unroll.* + +@main def Test: Unit = + UnrollTestMainV1.main(Array.empty[String]) + UnrollTestMainV2.main(Array.empty[String]) + UnrollTestMainV3.main(Array.empty[String]) diff --git a/sbt-test/unroll-annot/curriedMethod/v1_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-curriedMethod-integration/UnrollTestMain_1.scala similarity index 86% rename from sbt-test/unroll-annot/curriedMethod/v1_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-curriedMethod-integration/UnrollTestMain_1.scala index 8d1ca388477b..411aae125e20 100644 --- a/sbt-test/unroll-annot/curriedMethod/v1_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-curriedMethod-integration/UnrollTestMain_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/curriedMethod/v2_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-curriedMethod-integration/UnrollTestMain_2.scala similarity index 91% rename from sbt-test/unroll-annot/curriedMethod/v2_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-curriedMethod-integration/UnrollTestMain_2.scala index 66ad8fdf8698..9be52201ed8b 100644 --- a/sbt-test/unroll-annot/curriedMethod/v2_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-curriedMethod-integration/UnrollTestMain_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-curriedMethod-integration/UnrollTestMain_3.scala similarity index 93% rename from sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-curriedMethod-integration/UnrollTestMain_3.scala index 02b839fc07d2..1f281db4f497 100644 --- a/sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-curriedMethod-integration/UnrollTestMain_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala similarity index 95% rename from sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala rename to tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala index 61eeeb8756b8..69bbaf06d6ae 100644 --- a/sbt-test/unroll-annot/curriedMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala +++ b/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -1,3 +1,5 @@ +//> using options -experimental +// scalajs: --skip package unroll object UnrollTestPlatformSpecificV3{ @@ -26,4 +28,4 @@ object UnrollTestPlatformSpecificV3{ cls.getMethods.filter(_.getName.contains("foo")).foreach(println) } -} \ No newline at end of file +} diff --git a/sbt-test/unroll-annot/curriedMethod/v1/src/main/scala/Unrolled.scala b/tests/run/unroll-curriedMethod-integration/Unrolled_1.scala similarity index 72% rename from sbt-test/unroll-annot/curriedMethod/v1/src/main/scala/Unrolled.scala rename to tests/run/unroll-curriedMethod-integration/Unrolled_1.scala index e508d4345313..d6b8b06da582 100644 --- a/sbt-test/unroll-annot/curriedMethod/v1/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-curriedMethod-integration/Unrolled_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll class Unrolled{ diff --git a/tests/run/unroll-curriedMethod-integration/Unrolled_2.scala b/tests/run/unroll-curriedMethod-integration/Unrolled_2.scala new file mode 100644 index 000000000000..5a526bf6eeb2 --- /dev/null +++ b/tests/run/unroll-curriedMethod-integration/Unrolled_2.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +class Unrolled{ + final def foo(s: String, @unroll n: Int = 1, b: Boolean = true)(f: String => String) = f(s + n + b) +} diff --git a/tests/run/unroll-curriedMethod-integration/Unrolled_3.scala b/tests/run/unroll-curriedMethod-integration/Unrolled_3.scala new file mode 100644 index 000000000000..008576a9a5c3 --- /dev/null +++ b/tests/run/unroll-curriedMethod-integration/Unrolled_3.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +class Unrolled{ + final def foo(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0)(f: String => String) = f(s + n + b + l) +} diff --git a/sbt-test/unroll-annot/methodWithImplicit/utils/src/main/scala/TestUtils.scala b/tests/run/unroll-genericMethod-integration/TestUtils_1.scala similarity index 91% rename from sbt-test/unroll-annot/methodWithImplicit/utils/src/main/scala/TestUtils.scala rename to tests/run/unroll-genericMethod-integration/TestUtils_1.scala index 6ac413c9fe98..e639a54d924b 100644 --- a/sbt-test/unroll-annot/methodWithImplicit/utils/src/main/scala/TestUtils.scala +++ b/tests/run/unroll-genericMethod-integration/TestUtils_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll object TestUtils { diff --git a/tests/run/unroll-genericMethod-integration/Test_4.scala b/tests/run/unroll-genericMethod-integration/Test_4.scala new file mode 100644 index 000000000000..cae956f8b1bf --- /dev/null +++ b/tests/run/unroll-genericMethod-integration/Test_4.scala @@ -0,0 +1,8 @@ +//> using options -experimental +// scalajs: --skip +import unroll.* + +@main def Test: Unit = + UnrollTestMainV1.main(Array.empty[String]) + UnrollTestMainV2.main(Array.empty[String]) + UnrollTestMainV3.main(Array.empty[String]) diff --git a/tests/run/unroll-genericMethod-integration/UnrollTestMain_1.scala b/tests/run/unroll-genericMethod-integration/UnrollTestMain_1.scala new file mode 100644 index 000000000000..62d61c81d21d --- /dev/null +++ b/tests/run/unroll-genericMethod-integration/UnrollTestMain_1.scala @@ -0,0 +1,10 @@ +//> using options -experimental +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV1{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled().foo("cow"), "cow") + } +} diff --git a/tests/run/unroll-genericMethod-integration/UnrollTestMain_2.scala b/tests/run/unroll-genericMethod-integration/UnrollTestMain_2.scala new file mode 100644 index 000000000000..921ee48ff0db --- /dev/null +++ b/tests/run/unroll-genericMethod-integration/UnrollTestMain_2.scala @@ -0,0 +1,12 @@ +//> using options -experimental +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV2{ + def main(args: Array[String]): Unit = { + logAssertStartsWith(new Unrolled().foo("cow"), "cow1true") + logAssertStartsWith(new Unrolled().foo("cow", 2), "cow2true") + logAssertStartsWith(new Unrolled().foo("cow", 2, false), "cow2false") + } +} diff --git a/tests/run/unroll-genericMethod-integration/UnrollTestMain_3.scala b/tests/run/unroll-genericMethod-integration/UnrollTestMain_3.scala new file mode 100644 index 000000000000..bc985b58c359 --- /dev/null +++ b/tests/run/unroll-genericMethod-integration/UnrollTestMain_3.scala @@ -0,0 +1,15 @@ +//> using options -experimental +package unroll + +import unroll.TestUtils.logAssertStartsWith + +object UnrollTestMainV3{ + def main(args: Array[String]): Unit = { + UnrollTestPlatformSpecificV3() + + logAssertStartsWith(new Unrolled().foo("cow"), "cow1true0") + logAssertStartsWith(new Unrolled().foo("cow", 2), "cow2true0") + logAssertStartsWith(new Unrolled().foo("cow", 2, false), "cow2false0") + logAssertStartsWith(new Unrolled().foo("cow", 2, false, 3), "cow2false3") + } +} diff --git a/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala new file mode 100644 index 000000000000..d5310b3e302b --- /dev/null +++ b/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -0,0 +1,29 @@ +//> using options -experimental +// scalajs: --skip +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + val instance = new Unrolled() + val cls = classOf[Unrolled] + + assert( + cls.getMethod("foo", classOf[Object]).invoke(instance, "hello") == + "hello1true0" + ) + + assert(scala.util.Try(cls.getMethod("foo", classOf[Object], classOf[Int])).isFailure) + assert( + cls.getMethod("foo", classOf[Object], classOf[Int], classOf[Boolean]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE) == + "hello2false0" + ) + assert( + cls.getMethod("foo", classOf[Object], classOf[Int], classOf[Boolean], classOf[Long]) + .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) == + "hello2false3" + ) + cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + + } +} diff --git a/tests/run/unroll-genericMethod-integration/Unrolled_1.scala b/tests/run/unroll-genericMethod-integration/Unrolled_1.scala new file mode 100644 index 000000000000..a1d69945bc7e --- /dev/null +++ b/tests/run/unroll-genericMethod-integration/Unrolled_1.scala @@ -0,0 +1,6 @@ +//> using options -experimental +package unroll + +class Unrolled{ + def foo[T](s: T) = s.toString +} diff --git a/tests/run/unroll-genericMethod-integration/Unrolled_2.scala b/tests/run/unroll-genericMethod-integration/Unrolled_2.scala new file mode 100644 index 000000000000..e5970388fff8 --- /dev/null +++ b/tests/run/unroll-genericMethod-integration/Unrolled_2.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +class Unrolled{ + final def foo[T](s: T, @unroll n: Int = 1, b: Boolean = true) = s.toString + n + b +} diff --git a/tests/run/unroll-genericMethod-integration/Unrolled_3.scala b/tests/run/unroll-genericMethod-integration/Unrolled_3.scala new file mode 100644 index 000000000000..2ababa300ed1 --- /dev/null +++ b/tests/run/unroll-genericMethod-integration/Unrolled_3.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +class Unrolled{ + final def foo[T](s: T, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0) = s.toString + n + b + l +} diff --git a/tests/run/unroll-inferredFinal.scala b/tests/run/unroll-inferredFinal.scala new file mode 100644 index 000000000000..b4e1ccd9f011 --- /dev/null +++ b/tests/run/unroll-inferredFinal.scala @@ -0,0 +1,17 @@ +//> using options -experimental + +import scala.annotation.unroll + +object UnrolledObj { + // final is not needed because objects can't be extended + def foo(s: String, @unroll y: Boolean = true): String = s + y +} + +// final inferred for constructor +class UnrolledClass(s: String, @unroll y: Boolean = true): + override def toString = s"UnrolledClass($s,$y)" + + +@main def Test: Unit = + assert(UnrolledObj.foo("foo") == "footrue") + assert(new UnrolledClass("foo").toString == "UnrolledClass(foo,true)") diff --git a/tests/run/unroll-methodWithImplicit-integration/TestUtils_1.scala b/tests/run/unroll-methodWithImplicit-integration/TestUtils_1.scala new file mode 100644 index 000000000000..e639a54d924b --- /dev/null +++ b/tests/run/unroll-methodWithImplicit-integration/TestUtils_1.scala @@ -0,0 +1,13 @@ +//> using options -experimental +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/tests/run/unroll-methodWithImplicit-integration/Test_4.scala b/tests/run/unroll-methodWithImplicit-integration/Test_4.scala new file mode 100644 index 000000000000..cae956f8b1bf --- /dev/null +++ b/tests/run/unroll-methodWithImplicit-integration/Test_4.scala @@ -0,0 +1,8 @@ +//> using options -experimental +// scalajs: --skip +import unroll.* + +@main def Test: Unit = + UnrollTestMainV1.main(Array.empty[String]) + UnrollTestMainV2.main(Array.empty[String]) + UnrollTestMainV3.main(Array.empty[String]) diff --git a/sbt-test/unroll-annot/methodWithImplicit/v1_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_1.scala similarity index 87% rename from sbt-test/unroll-annot/methodWithImplicit/v1_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_1.scala index 928a74f57d5e..e4e91e6709f3 100644 --- a/sbt-test/unroll-annot/methodWithImplicit/v1_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/methodWithImplicit/v2_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_2.scala similarity index 92% rename from sbt-test/unroll-annot/methodWithImplicit/v2_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_2.scala index de14613be3cc..69a5a0b39ab6 100644 --- a/sbt-test/unroll-annot/methodWithImplicit/v2_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_3.scala similarity index 93% rename from sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_3.scala index 1982d7dff344..ffd528e15f5e 100644 --- a/sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-methodWithImplicit-integration/UnrollTestMain_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala similarity index 94% rename from sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala rename to tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala index 3537a6373e0d..431c1e7c2d4c 100644 --- a/sbt-test/unroll-annot/methodWithImplicit/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala +++ b/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala @@ -1,3 +1,5 @@ +//> using options -experimental +// scalajs: --skip package unroll object UnrollTestPlatformSpecificV3{ @@ -11,7 +13,7 @@ object UnrollTestPlatformSpecificV3{ ) assert(scala.util.Try(cls.getMethod("foo", classOf[String], classOf[Int], classOf[String => String])).isFailure) - + assert( cls.getMethod("foo", classOf[String], classOf[Int], classOf[Boolean], classOf[String => String]) .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE, identity[String](_)) == @@ -26,4 +28,4 @@ object UnrollTestPlatformSpecificV3{ cls.getMethods.filter(_.getName.contains("foo")).foreach(println) } -} \ No newline at end of file +} diff --git a/sbt-test/unroll-annot/methodWithImplicit/v1/src/main/scala/Unrolled.scala b/tests/run/unroll-methodWithImplicit-integration/Unrolled_1.scala similarity index 74% rename from sbt-test/unroll-annot/methodWithImplicit/v1/src/main/scala/Unrolled.scala rename to tests/run/unroll-methodWithImplicit-integration/Unrolled_1.scala index 44137480e239..1de415b26952 100644 --- a/sbt-test/unroll-annot/methodWithImplicit/v1/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-methodWithImplicit-integration/Unrolled_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll class Unrolled{ diff --git a/tests/run/unroll-methodWithImplicit-integration/Unrolled_2.scala b/tests/run/unroll-methodWithImplicit-integration/Unrolled_2.scala new file mode 100644 index 000000000000..01a5d2fb037a --- /dev/null +++ b/tests/run/unroll-methodWithImplicit-integration/Unrolled_2.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +class Unrolled{ + final def foo(s: String, @unroll n: Int = 1, b: Boolean = true)(implicit f: String => String) = f(s + n + b) +} diff --git a/tests/run/unroll-methodWithImplicit-integration/Unrolled_3.scala b/tests/run/unroll-methodWithImplicit-integration/Unrolled_3.scala new file mode 100644 index 000000000000..07627f604d76 --- /dev/null +++ b/tests/run/unroll-methodWithImplicit-integration/Unrolled_3.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +class Unrolled{ + final def foo(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0)(implicit f: String => String) = f(s + n + b + l) +} diff --git a/tests/run/unroll-multiple.scala b/tests/run/unroll-multiple.scala new file mode 100644 index 000000000000..e1790be26395 --- /dev/null +++ b/tests/run/unroll-multiple.scala @@ -0,0 +1,72 @@ +//> using options -experimental + +import scala.annotation.unroll +import scala.deriving.Mirror + +class Unrolled { + final def foo( + s: String, + @unroll y: Boolean = true, + @unroll i: Int = 0, + @unroll c: Char = '?'): String = s + y + i + c +} + +class Outer { + class Unrolled { + final def bar( + s: String, + @unroll y: Boolean = true, + @unroll i: Int = 0, + @unroll c: Char = '?'): String = s + y + i + c + } + + case class UnrolledCase( + s: String, + @unroll y: Boolean = true, + @unroll i: Int = 0, + @unroll c: Char = '?') { + def baz: String = s + y + i + c + } + + class UnrolledSecondary { + private var msg = "" + + def qux: String = msg + + def this( + s: String, + @unroll y: Boolean = true, + @unroll i: Int = 0, + @unroll c: Char = '?') = { + this() + msg = s + y + i + c + } + } +} + +@main def Test: Unit = + assert(Unrolled().foo("foo") == "footrue0?") + assert(Unrolled().foo("foo", false) == "foofalse0?") + assert(Unrolled().foo("foo", false, 1) == "foofalse1?") + assert(Unrolled().foo("foo", false, 1, '@') == "foofalse1@") + val outer = new Outer() + assert(new outer.Unrolled().bar("bar") == "bartrue0?") + assert(new outer.Unrolled().bar("bar", false) == "barfalse0?") + assert(new outer.Unrolled().bar("bar", false, 1) == "barfalse1?") + assert(new outer.Unrolled().bar("bar", false, 1, '@') == "barfalse1@") + assert(outer.UnrolledCase.apply("baz").baz == "baztrue0?") + assert(outer.UnrolledCase.apply("baz", false).baz == "bazfalse0?") + assert(outer.UnrolledCase.apply("baz", false, 1).baz == "bazfalse1?") + assert(outer.UnrolledCase.apply("baz", false, 1, '@').baz == "bazfalse1@") + assert((new outer.UnrolledCase("baz")).baz == "baztrue0?") + assert((new outer.UnrolledCase("baz", false)).baz == "bazfalse0?") + assert((new outer.UnrolledCase("baz", false, 1)).baz == "bazfalse1?") + assert((new outer.UnrolledCase("baz", false, 1, '@')).baz == "bazfalse1@") + assert(summon[Mirror.Of[outer.UnrolledCase]].fromProduct(Tuple("baz")).baz == "baztrue0?") + assert(summon[Mirror.Of[outer.UnrolledCase]].fromProduct(("baz", false)).baz == "bazfalse0?") + assert(summon[Mirror.Of[outer.UnrolledCase]].fromProduct(("baz", false, 1)).baz == "bazfalse1?") + assert(summon[Mirror.Of[outer.UnrolledCase]].fromProduct(("baz", false, 1, '@')).baz == "bazfalse1@") + assert(new outer.UnrolledSecondary("qux").qux == "quxtrue0?") + assert(new outer.UnrolledSecondary("qux", false).qux == "quxfalse0?") + assert(new outer.UnrolledSecondary("qux", false, 1).qux == "quxfalse1?") + assert(new outer.UnrolledSecondary("qux", false, 1, '@').qux == "quxfalse1@") diff --git a/tests/run/unroll-objectMethod-integration/TestUtils_1.scala b/tests/run/unroll-objectMethod-integration/TestUtils_1.scala new file mode 100644 index 000000000000..e639a54d924b --- /dev/null +++ b/tests/run/unroll-objectMethod-integration/TestUtils_1.scala @@ -0,0 +1,13 @@ +//> using options -experimental +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/tests/run/unroll-objectMethod-integration/Test_4.scala b/tests/run/unroll-objectMethod-integration/Test_4.scala new file mode 100644 index 000000000000..cae956f8b1bf --- /dev/null +++ b/tests/run/unroll-objectMethod-integration/Test_4.scala @@ -0,0 +1,8 @@ +//> using options -experimental +// scalajs: --skip +import unroll.* + +@main def Test: Unit = + UnrollTestMainV1.main(Array.empty[String]) + UnrollTestMainV2.main(Array.empty[String]) + UnrollTestMainV3.main(Array.empty[String]) diff --git a/sbt-test/unroll-annot/objectMethod/v1_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-objectMethod-integration/UnrollTestMain_1.scala similarity index 88% rename from sbt-test/unroll-annot/objectMethod/v1_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-objectMethod-integration/UnrollTestMain_1.scala index 23f8e15b40cb..9cba53c444ce 100644 --- a/sbt-test/unroll-annot/objectMethod/v1_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-objectMethod-integration/UnrollTestMain_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/objectMethod/v2_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-objectMethod-integration/UnrollTestMain_2.scala similarity index 90% rename from sbt-test/unroll-annot/objectMethod/v2_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-objectMethod-integration/UnrollTestMain_2.scala index ee5337bd4689..2fe609543d51 100644 --- a/sbt-test/unroll-annot/objectMethod/v2_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-objectMethod-integration/UnrollTestMain_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-objectMethod-integration/UnrollTestMain_3.scala similarity index 93% rename from sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-objectMethod-integration/UnrollTestMain_3.scala index b1996bd6d5d7..e6d442d3bf7c 100644 --- a/sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-objectMethod-integration/UnrollTestMain_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala similarity index 97% rename from sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala rename to tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala index 2b5578dd482d..6f399649b4b8 100644 --- a/sbt-test/unroll-annot/objectMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala +++ b/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -1,3 +1,5 @@ +//> using options -experimental +// scalajs: --skip package unroll object UnrollTestPlatformSpecificV3{ @@ -45,4 +47,4 @@ object UnrollTestPlatformSpecificV3{ ) } -} \ No newline at end of file +} diff --git a/sbt-test/unroll-annot/objectMethod/v1/src/main/scala/Unrolled.scala b/tests/run/unroll-objectMethod-integration/Unrolled_1.scala similarity index 70% rename from sbt-test/unroll-annot/objectMethod/v1/src/main/scala/Unrolled.scala rename to tests/run/unroll-objectMethod-integration/Unrolled_1.scala index f4559bc2a820..042ab3180cdc 100644 --- a/sbt-test/unroll-annot/objectMethod/v1/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-objectMethod-integration/Unrolled_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll object Unrolled{ diff --git a/tests/run/unroll-objectMethod-integration/Unrolled_2.scala b/tests/run/unroll-objectMethod-integration/Unrolled_2.scala new file mode 100644 index 000000000000..bfef86beb6b2 --- /dev/null +++ b/tests/run/unroll-objectMethod-integration/Unrolled_2.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +object Unrolled{ + final def foo(s: String, n: Int = 1, @unroll b: Boolean = true) = s + n + b +} diff --git a/tests/run/unroll-objectMethod-integration/Unrolled_3.scala b/tests/run/unroll-objectMethod-integration/Unrolled_3.scala new file mode 100644 index 000000000000..c76521e731d8 --- /dev/null +++ b/tests/run/unroll-objectMethod-integration/Unrolled_3.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +object Unrolled{ + final def foo(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = s + n + b + l +} diff --git a/tests/run/unroll-primaryConstructor-integration/TestUtils_1.scala b/tests/run/unroll-primaryConstructor-integration/TestUtils_1.scala new file mode 100644 index 000000000000..e639a54d924b --- /dev/null +++ b/tests/run/unroll-primaryConstructor-integration/TestUtils_1.scala @@ -0,0 +1,13 @@ +//> using options -experimental +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/tests/run/unroll-primaryConstructor-integration/Test_4.scala b/tests/run/unroll-primaryConstructor-integration/Test_4.scala new file mode 100644 index 000000000000..cae956f8b1bf --- /dev/null +++ b/tests/run/unroll-primaryConstructor-integration/Test_4.scala @@ -0,0 +1,8 @@ +//> using options -experimental +// scalajs: --skip +import unroll.* + +@main def Test: Unit = + UnrollTestMainV1.main(Array.empty[String]) + UnrollTestMainV2.main(Array.empty[String]) + UnrollTestMainV3.main(Array.empty[String]) diff --git a/sbt-test/unroll-annot/primaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-primaryConstructor-integration/UnrollTestMain_1.scala similarity index 88% rename from sbt-test/unroll-annot/primaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-primaryConstructor-integration/UnrollTestMain_1.scala index 9bed955a9bc8..ac80b2a5734b 100644 --- a/sbt-test/unroll-annot/primaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-primaryConstructor-integration/UnrollTestMain_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/primaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-primaryConstructor-integration/UnrollTestMain_2.scala similarity index 91% rename from sbt-test/unroll-annot/primaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-primaryConstructor-integration/UnrollTestMain_2.scala index 7a88d263a213..5140d999ee9b 100644 --- a/sbt-test/unroll-annot/primaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-primaryConstructor-integration/UnrollTestMain_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-primaryConstructor-integration/UnrollTestMain_3.scala similarity index 93% rename from sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-primaryConstructor-integration/UnrollTestMain_3.scala index f05ca8808c3d..c80c33672d3e 100644 --- a/sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-primaryConstructor-integration/UnrollTestMain_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala similarity index 94% rename from sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala rename to tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala index 07dee69cd8a7..e06a38502c62 100644 --- a/sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala +++ b/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala @@ -1,3 +1,5 @@ +//> using options -experimental +// scalajs: --skip package unroll object UnrollTestPlatformSpecificV3{ @@ -30,4 +32,4 @@ object UnrollTestPlatformSpecificV3{ cls.getConstructors.foreach(println) } -} \ No newline at end of file +} diff --git a/sbt-test/unroll-annot/primaryConstructor/v1/src/main/scala/Unrolled.scala b/tests/run/unroll-primaryConstructor-integration/Unrolled_1.scala similarity index 70% rename from sbt-test/unroll-annot/primaryConstructor/v1/src/main/scala/Unrolled.scala rename to tests/run/unroll-primaryConstructor-integration/Unrolled_1.scala index c7574f4346e0..0ddd25a70127 100644 --- a/sbt-test/unroll-annot/primaryConstructor/v1/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-primaryConstructor-integration/Unrolled_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll class Unrolled(s: String, n: Int = 1){ diff --git a/sbt-test/unroll-annot/primaryConstructor/v2/src/main/scala/Unrolled.scala b/tests/run/unroll-primaryConstructor-integration/Unrolled_2.scala similarity index 65% rename from sbt-test/unroll-annot/primaryConstructor/v2/src/main/scala/Unrolled.scala rename to tests/run/unroll-primaryConstructor-integration/Unrolled_2.scala index dfe3c2f0e46d..c8558df1af55 100644 --- a/sbt-test/unroll-annot/primaryConstructor/v2/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-primaryConstructor-integration/Unrolled_2.scala @@ -1,7 +1,8 @@ +//> using options -experimental package unroll import scala.annotation.unroll class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true){ - def foo = s + n + b + final def foo = s + n + b } diff --git a/sbt-test/unroll-annot/primaryConstructor/v3/src/main/scala/Unrolled.scala b/tests/run/unroll-primaryConstructor-integration/Unrolled_3.scala similarity index 83% rename from sbt-test/unroll-annot/primaryConstructor/v3/src/main/scala/Unrolled.scala rename to tests/run/unroll-primaryConstructor-integration/Unrolled_3.scala index b570bcaadbb3..c6be439e1dec 100644 --- a/sbt-test/unroll-annot/primaryConstructor/v3/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-primaryConstructor-integration/Unrolled_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import scala.annotation.unroll diff --git a/tests/run/unroll-secondParameterList-integration/TestUtils_1.scala b/tests/run/unroll-secondParameterList-integration/TestUtils_1.scala new file mode 100644 index 000000000000..e639a54d924b --- /dev/null +++ b/tests/run/unroll-secondParameterList-integration/TestUtils_1.scala @@ -0,0 +1,13 @@ +//> using options -experimental +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/tests/run/unroll-secondParameterList-integration/Test_4.scala b/tests/run/unroll-secondParameterList-integration/Test_4.scala new file mode 100644 index 000000000000..cae956f8b1bf --- /dev/null +++ b/tests/run/unroll-secondParameterList-integration/Test_4.scala @@ -0,0 +1,8 @@ +//> using options -experimental +// scalajs: --skip +import unroll.* + +@main def Test: Unit = + UnrollTestMainV1.main(Array.empty[String]) + UnrollTestMainV2.main(Array.empty[String]) + UnrollTestMainV3.main(Array.empty[String]) diff --git a/sbt-test/unroll-annot/secondParameterList/v1_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-secondParameterList-integration/UnrollTestMain_1.scala similarity index 86% rename from sbt-test/unroll-annot/secondParameterList/v1_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-secondParameterList-integration/UnrollTestMain_1.scala index ef6fd3b68102..163225fb93bf 100644 --- a/sbt-test/unroll-annot/secondParameterList/v1_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-secondParameterList-integration/UnrollTestMain_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/secondParameterList/v2_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-secondParameterList-integration/UnrollTestMain_2.scala similarity index 91% rename from sbt-test/unroll-annot/secondParameterList/v2_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-secondParameterList-integration/UnrollTestMain_2.scala index 09c06869f617..de0776c569db 100644 --- a/sbt-test/unroll-annot/secondParameterList/v2_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-secondParameterList-integration/UnrollTestMain_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-secondParameterList-integration/UnrollTestMain_3.scala similarity index 93% rename from sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-secondParameterList-integration/UnrollTestMain_3.scala index 468f24956d94..b18a7f18b4d0 100644 --- a/sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-secondParameterList-integration/UnrollTestMain_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala similarity index 95% rename from sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala rename to tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala index 4663b2220cd7..49dff864f49b 100644 --- a/sbt-test/unroll-annot/secondParameterList/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala +++ b/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala @@ -1,3 +1,5 @@ +//> using options -experimental +// scalajs: --skip package unroll object UnrollTestPlatformSpecificV3{ @@ -27,4 +29,4 @@ object UnrollTestPlatformSpecificV3{ cls.getMethods.filter(_.getName.contains("foo")).foreach(println) } -} \ No newline at end of file +} diff --git a/sbt-test/unroll-annot/secondParameterList/v1/src/main/scala/Unrolled.scala b/tests/run/unroll-secondParameterList-integration/Unrolled_1.scala similarity index 72% rename from sbt-test/unroll-annot/secondParameterList/v1/src/main/scala/Unrolled.scala rename to tests/run/unroll-secondParameterList-integration/Unrolled_1.scala index f9ddac201c59..fbe0a58dca24 100644 --- a/sbt-test/unroll-annot/secondParameterList/v1/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-secondParameterList-integration/Unrolled_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll class Unrolled{ diff --git a/tests/run/unroll-secondParameterList-integration/Unrolled_2.scala b/tests/run/unroll-secondParameterList-integration/Unrolled_2.scala new file mode 100644 index 000000000000..68c4170f6f6e --- /dev/null +++ b/tests/run/unroll-secondParameterList-integration/Unrolled_2.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +class Unrolled{ + final def foo(f: String => String)(s: String, @unroll n: Int = 1, b: Boolean = true) = f(s + n + b) +} diff --git a/tests/run/unroll-secondParameterList-integration/Unrolled_3.scala b/tests/run/unroll-secondParameterList-integration/Unrolled_3.scala new file mode 100644 index 000000000000..ddbe8c4cfaf4 --- /dev/null +++ b/tests/run/unroll-secondParameterList-integration/Unrolled_3.scala @@ -0,0 +1,8 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +class Unrolled{ + final def foo(f: String => String)(s: String, @unroll n: Int = 1, b: Boolean = true, @unroll l: Long = 0) = f(s + n + b + l) +} diff --git a/tests/run/unroll-secondaryConstructor-integration/TestUtils_1.scala b/tests/run/unroll-secondaryConstructor-integration/TestUtils_1.scala new file mode 100644 index 000000000000..e639a54d924b --- /dev/null +++ b/tests/run/unroll-secondaryConstructor-integration/TestUtils_1.scala @@ -0,0 +1,13 @@ +//> using options -experimental +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/tests/run/unroll-secondaryConstructor-integration/Test_4.scala b/tests/run/unroll-secondaryConstructor-integration/Test_4.scala new file mode 100644 index 000000000000..cae956f8b1bf --- /dev/null +++ b/tests/run/unroll-secondaryConstructor-integration/Test_4.scala @@ -0,0 +1,8 @@ +//> using options -experimental +// scalajs: --skip +import unroll.* + +@main def Test: Unit = + UnrollTestMainV1.main(Array.empty[String]) + UnrollTestMainV2.main(Array.empty[String]) + UnrollTestMainV3.main(Array.empty[String]) diff --git a/sbt-test/unroll-annot/secondaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_1.scala similarity index 88% rename from sbt-test/unroll-annot/secondaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_1.scala index 9bed955a9bc8..ac80b2a5734b 100644 --- a/sbt-test/unroll-annot/secondaryConstructor/v1_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/secondaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_2.scala similarity index 91% rename from sbt-test/unroll-annot/secondaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_2.scala index 7a88d263a213..5140d999ee9b 100644 --- a/sbt-test/unroll-annot/secondaryConstructor/v2_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_3.scala similarity index 93% rename from sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_3.scala index f05ca8808c3d..c80c33672d3e 100644 --- a/sbt-test/unroll-annot/primaryConstructor/v3_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-secondaryConstructor-integration/UnrollTestMain_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala similarity index 94% rename from sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala rename to tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala index 07dee69cd8a7..e06a38502c62 100644 --- a/sbt-test/unroll-annot/secondaryConstructor/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala +++ b/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala @@ -1,3 +1,5 @@ +//> using options -experimental +// scalajs: --skip package unroll object UnrollTestPlatformSpecificV3{ @@ -30,4 +32,4 @@ object UnrollTestPlatformSpecificV3{ cls.getConstructors.foreach(println) } -} \ No newline at end of file +} diff --git a/sbt-test/unroll-annot/secondaryConstructor/v1/src/main/scala/Unrolled.scala b/tests/run/unroll-secondaryConstructor-integration/Unrolled_1.scala similarity index 78% rename from sbt-test/unroll-annot/secondaryConstructor/v1/src/main/scala/Unrolled.scala rename to tests/run/unroll-secondaryConstructor-integration/Unrolled_1.scala index 529a3fc66de3..855b20efa8f6 100644 --- a/sbt-test/unroll-annot/secondaryConstructor/v1/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-secondaryConstructor-integration/Unrolled_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll class Unrolled(){ diff --git a/sbt-test/unroll-annot/secondaryConstructor/v2/src/main/scala/Unrolled.scala b/tests/run/unroll-secondaryConstructor-integration/Unrolled_2.scala similarity index 85% rename from sbt-test/unroll-annot/secondaryConstructor/v2/src/main/scala/Unrolled.scala rename to tests/run/unroll-secondaryConstructor-integration/Unrolled_2.scala index 382066698f31..b8f1f4f28328 100644 --- a/sbt-test/unroll-annot/secondaryConstructor/v2/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-secondaryConstructor-integration/Unrolled_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import scala.annotation.unroll diff --git a/sbt-test/unroll-annot/secondaryConstructor/v3/src/main/scala/Unrolled.scala b/tests/run/unroll-secondaryConstructor-integration/Unrolled_3.scala similarity index 86% rename from sbt-test/unroll-annot/secondaryConstructor/v3/src/main/scala/Unrolled.scala rename to tests/run/unroll-secondaryConstructor-integration/Unrolled_3.scala index 89411d6576ca..1da3e0d69ec6 100644 --- a/sbt-test/unroll-annot/secondaryConstructor/v3/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-secondaryConstructor-integration/Unrolled_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import scala.annotation.unroll diff --git a/tests/run/unroll-traitMethod-integration/TestUtils_1.scala b/tests/run/unroll-traitMethod-integration/TestUtils_1.scala new file mode 100644 index 000000000000..e639a54d924b --- /dev/null +++ b/tests/run/unroll-traitMethod-integration/TestUtils_1.scala @@ -0,0 +1,13 @@ +//> using options -experimental +package unroll + +object TestUtils { + def logAssertStartsWith(actual: String, expected: String): Unit = { + assert(actual.startsWith(expected)) + val suffix = { + val suffix0 = actual.stripPrefix(expected) + if (suffix0.isEmpty) "" else s""" + "$suffix0"""" + } + println(s"""Assertion passed: found "$expected"$suffix""") + } +} diff --git a/tests/run/unroll-traitMethod-integration/Test_4.scala b/tests/run/unroll-traitMethod-integration/Test_4.scala new file mode 100644 index 000000000000..cae956f8b1bf --- /dev/null +++ b/tests/run/unroll-traitMethod-integration/Test_4.scala @@ -0,0 +1,8 @@ +//> using options -experimental +// scalajs: --skip +import unroll.* + +@main def Test: Unit = + UnrollTestMainV1.main(Array.empty[String]) + UnrollTestMainV2.main(Array.empty[String]) + UnrollTestMainV3.main(Array.empty[String]) diff --git a/sbt-test/unroll-annot/traitMethod/v1_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-traitMethod-integration/UnrollTestMain_1.scala similarity index 92% rename from sbt-test/unroll-annot/traitMethod/v1_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-traitMethod-integration/UnrollTestMain_1.scala index f1c7c8bb88a4..b290c95e1f9c 100644 --- a/sbt-test/unroll-annot/traitMethod/v1_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-traitMethod-integration/UnrollTestMain_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/traitMethod/v2_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-traitMethod-integration/UnrollTestMain_2.scala similarity index 94% rename from sbt-test/unroll-annot/traitMethod/v2_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-traitMethod-integration/UnrollTestMain_2.scala index 30eb52263e50..6721b302e3f1 100644 --- a/sbt-test/unroll-annot/traitMethod/v2_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-traitMethod-integration/UnrollTestMain_2.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestMain.scala b/tests/run/unroll-traitMethod-integration/UnrollTestMain_3.scala similarity index 95% rename from sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestMain.scala rename to tests/run/unroll-traitMethod-integration/UnrollTestMain_3.scala index 89154b958161..d4091763a86f 100644 --- a/sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestMain.scala +++ b/tests/run/unroll-traitMethod-integration/UnrollTestMain_3.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll import unroll.TestUtils.logAssertStartsWith diff --git a/sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala b/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala similarity index 94% rename from sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala rename to tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala index e8367679233f..88b0e2255741 100644 --- a/sbt-test/unroll-annot/traitMethod/v3_app/src/main/scala/UnrollTestPlatformSpecific.scala +++ b/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -1,3 +1,5 @@ +//> using options -experimental +// scalajs: --skip package unroll object UnrollTestPlatformSpecificV3{ @@ -25,4 +27,4 @@ object UnrollTestPlatformSpecificV3{ cls.getMethods.filter(_.getName.contains("foo")).foreach(println) } -} \ No newline at end of file +} diff --git a/sbt-test/unroll-annot/traitMethod/v1/src/main/scala/Unrolled.scala b/tests/run/unroll-traitMethod-integration/Unrolled_1.scala similarity index 77% rename from sbt-test/unroll-annot/traitMethod/v1/src/main/scala/Unrolled.scala rename to tests/run/unroll-traitMethod-integration/Unrolled_1.scala index eaadde758ac7..aa9375698103 100644 --- a/sbt-test/unroll-annot/traitMethod/v1/src/main/scala/Unrolled.scala +++ b/tests/run/unroll-traitMethod-integration/Unrolled_1.scala @@ -1,3 +1,4 @@ +//> using options -experimental package unroll trait Unrolled{ diff --git a/tests/run/unroll-traitMethod-integration/Unrolled_2.scala b/tests/run/unroll-traitMethod-integration/Unrolled_2.scala new file mode 100644 index 000000000000..242054d41be4 --- /dev/null +++ b/tests/run/unroll-traitMethod-integration/Unrolled_2.scala @@ -0,0 +1,10 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +trait Unrolled{ + final def foo(s: String, n: Int = 1, @unroll b: Boolean = true) = s + n + b +} + +object Unrolled extends Unrolled diff --git a/tests/run/unroll-traitMethod-integration/Unrolled_3.scala b/tests/run/unroll-traitMethod-integration/Unrolled_3.scala new file mode 100644 index 000000000000..398ddbb4da22 --- /dev/null +++ b/tests/run/unroll-traitMethod-integration/Unrolled_3.scala @@ -0,0 +1,10 @@ +//> using options -experimental +package unroll + +import scala.annotation.unroll + +trait Unrolled{ + final def foo(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = s + n + b + l +} + +object Unrolled extends Unrolled diff --git a/tests/run/unroll-traitMethod/Test_2.scala b/tests/run/unroll-traitMethod/Test_2.scala new file mode 100644 index 000000000000..48d2acef560e --- /dev/null +++ b/tests/run/unroll-traitMethod/Test_2.scala @@ -0,0 +1,6 @@ +//> using options -experimental + +@main def Test = + + // ensure that impl.foo isn't `Invisible`, so can be resolved from TASTy + assert(UnrolledImpl.impl.foo("foo") == "foo1true") diff --git a/tests/run/unroll-traitMethod/Unrolled_1.scala b/tests/run/unroll-traitMethod/Unrolled_1.scala new file mode 100644 index 000000000000..fa4c78708f4b --- /dev/null +++ b/tests/run/unroll-traitMethod/Unrolled_1.scala @@ -0,0 +1,10 @@ +//> using options -experimental +import scala.annotation.unroll + +trait Unrolled { + final def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String = s + n + b +} + +object UnrolledImpl { + val impl: Unrolled = new Unrolled {} +} From c1c1e957c5a28a4be2d2662417e3e420cafdeb2b Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Mon, 7 Oct 2024 17:51:32 +0200 Subject: [PATCH 3/5] new Invisble flag semantics - now invisible members are visible in typer when resolving SELECTin from TASTy. - add sbt-test/tasty-compat test to demonstrate when inline method calls forwarder --- .../dotty/tools/dotc/core/Denotations.scala | 2 +- compiler/src/dotty/tools/dotc/core/Mode.scala | 5 ++- .../tools/dotc/core/SymDenotations.scala | 2 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 8 +++-- .../add-param-unroll/a-changes/A.scala | 9 +++++ .../tasty-compat/add-param-unroll/a/A.scala | 9 +++++ .../tasty-compat/add-param-unroll/b/B.scala | 7 ++++ .../tasty-compat/add-param-unroll/build.sbt | 36 +++++++++++++++++++ .../tasty-compat/add-param-unroll/c/C.scala | 5 +++ .../project/DottyInjectedPlugin.scala | 11 ++++++ sbt-test/tasty-compat/add-param-unroll/test | 8 +++++ tasty/src/dotty/tools/tasty/TastyFormat.scala | 2 +- 12 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 sbt-test/tasty-compat/add-param-unroll/a-changes/A.scala create mode 100644 sbt-test/tasty-compat/add-param-unroll/a/A.scala create mode 100644 sbt-test/tasty-compat/add-param-unroll/b/B.scala create mode 100644 sbt-test/tasty-compat/add-param-unroll/build.sbt create mode 100644 sbt-test/tasty-compat/add-param-unroll/c/C.scala create mode 100644 sbt-test/tasty-compat/add-param-unroll/project/DottyInjectedPlugin.scala create mode 100644 sbt-test/tasty-compat/add-param-unroll/test diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 85ff51bc19de..e2ef3f7eafb8 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -1072,7 +1072,7 @@ object Denotations { def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation = if (denots.exists && denots.matches(this)) NoDenotation else this def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation = - val realExcluded = if ctx.isAfterTyper then excluded else excluded | Invisible + val realExcluded = if ctx.isAfterTyper then excluded else excluded | (if ctx.mode.is(Mode.ResolveFromTASTy) then EmptyFlags else Invisible) def symd: SymDenotation = this match case symd: SymDenotation => symd case _ => symbol.denot diff --git a/compiler/src/dotty/tools/dotc/core/Mode.scala b/compiler/src/dotty/tools/dotc/core/Mode.scala index 14d7827974c0..965c3823d610 100644 --- a/compiler/src/dotty/tools/dotc/core/Mode.scala +++ b/compiler/src/dotty/tools/dotc/core/Mode.scala @@ -105,7 +105,7 @@ object Mode { /** Use previous Scheme for implicit resolution. Currently significant * in 3.0-migration where we use Scala-2's scheme instead and in 3.5 and 3.6-migration - * where we use the previous scheme up to 3.4 for comparison with the new scheme. + * where we use the previous scheme up to 3.4 for comparison with the new scheme. */ val OldImplicitResolution: Mode = newMode(15, "OldImplicitResolution") @@ -125,6 +125,9 @@ object Mode { /** Read original positions when unpickling from TASTY */ val ReadPositions: Mode = newMode(17, "ReadPositions") + /** We are resolving a SELECT name from TASTy */ + val ResolveFromTASTy: Mode = newMode(18, "ResolveFromTASTy") + /** We are elaborating the fully qualified name of a package clause. * In this case, identifiers should never be imported. */ diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 53df2d4aa39a..670663ff2161 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -617,7 +617,7 @@ object SymDenotations { case _ => // Otherwise, no completion is necessary, see the preconditions of `markAbsent()`. (myInfo `eq` NoType) - || is(Invisible) && ctx.isTyper + || (is(Invisible) && !ctx.mode.is(Mode.ResolveFromTASTy)) && ctx.isTyper || is(ModuleVal, butNot = Package) && moduleClass.isAbsent(canForce) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index c07121a52191..d6f2812dad0d 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1563,7 +1563,7 @@ class TreeUnpickler(reader: TastyReader, * - sbt-test/tasty-compat/remove-override * - sbt-test/tasty-compat/move-method */ - def lookupInSuper = + def lookupInSuper(using Context) = val cls = ownerTpe.classSymbol if cls.exists then cls.asClass.classDenot @@ -1572,7 +1572,8 @@ class TreeUnpickler(reader: TastyReader, else NoDenotation - val denot = + + def searchDenot(using Context): Denotation = if owner.is(JavaAnnotation) && name == nme.CONSTRUCTOR then // #19951 Fix up to read TASTy produced before 3.5.0 -- ignore the signature ownerTpe.nonPrivateDecl(name).asSeenFrom(prefix) @@ -1580,6 +1581,9 @@ class TreeUnpickler(reader: TastyReader, val d = ownerTpe.decl(name).atSignature(sig, target) (if !d.exists then lookupInSuper else d).asSeenFrom(prefix) + val denot = inContext(ctx.addMode(Mode.ResolveFromTASTy)): + searchDenot // able to resolve Invisible members + makeSelect(qual, name, denot) case REPEATED => val elemtpt = readTpt() diff --git a/sbt-test/tasty-compat/add-param-unroll/a-changes/A.scala b/sbt-test/tasty-compat/add-param-unroll/a-changes/A.scala new file mode 100644 index 000000000000..9cbb82b5dc30 --- /dev/null +++ b/sbt-test/tasty-compat/add-param-unroll/a-changes/A.scala @@ -0,0 +1,9 @@ +package a + +import scala.annotation.unroll + +object A { + + def foo(s: String, x: Int, @unroll b: Boolean = true): String = s + x + b + +} diff --git a/sbt-test/tasty-compat/add-param-unroll/a/A.scala b/sbt-test/tasty-compat/add-param-unroll/a/A.scala new file mode 100644 index 000000000000..b2b74e32a922 --- /dev/null +++ b/sbt-test/tasty-compat/add-param-unroll/a/A.scala @@ -0,0 +1,9 @@ +package a + +import scala.annotation.unroll + +object A { + + def foo(s: String, x: Int): String = s + x + +} diff --git a/sbt-test/tasty-compat/add-param-unroll/b/B.scala b/sbt-test/tasty-compat/add-param-unroll/b/B.scala new file mode 100644 index 000000000000..6afa8e347c54 --- /dev/null +++ b/sbt-test/tasty-compat/add-param-unroll/b/B.scala @@ -0,0 +1,7 @@ +package b + +import a.* + +object B { + transparent inline def caller = A.foo("abc", 2) +} diff --git a/sbt-test/tasty-compat/add-param-unroll/build.sbt b/sbt-test/tasty-compat/add-param-unroll/build.sbt new file mode 100644 index 000000000000..7ea07075632f --- /dev/null +++ b/sbt-test/tasty-compat/add-param-unroll/build.sbt @@ -0,0 +1,36 @@ +lazy val commonSettings = Seq( + scalacOptions += "-experimental", +) + +lazy val printSettings = Seq( + scalacOptions += "-Yprint-tasty", +) + +lazy val a = project.in(file("a")) + .settings(commonSettings) + .settings( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "b-input" + ) + +lazy val b = project.in(file("b")) + .settings(commonSettings) + .settings( + Compile / unmanagedClasspath += (ThisBuild / baseDirectory).value / "b-input", + Compile / classDirectory := (ThisBuild / baseDirectory).value / "c-input" + ) + +lazy val `a-changes` = project.in(file("a-changes")) + .settings(commonSettings) + .settings( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "c-input" + ) + +lazy val c = project.in(file("c")) + .settings(commonSettings) + .settings(printSettings) + .settings( + // scalacOptions ++= Seq("-from-tasty", "-Ycheck:readTasty", "-Xfatal-warnings", "-Xprint:readTasty", "-Xprint-types"), + // Compile / sources := Seq(new java.io.File("c-input/B.tasty")), + Compile / unmanagedClasspath += (ThisBuild / baseDirectory).value / "c-input", + Compile / classDirectory := (ThisBuild / baseDirectory).value / "c-output" + ) diff --git a/sbt-test/tasty-compat/add-param-unroll/c/C.scala b/sbt-test/tasty-compat/add-param-unroll/c/C.scala new file mode 100644 index 000000000000..6ce872a8730c --- /dev/null +++ b/sbt-test/tasty-compat/add-param-unroll/c/C.scala @@ -0,0 +1,5 @@ +import b.* + +object C { + val res = B.caller +} diff --git a/sbt-test/tasty-compat/add-param-unroll/project/DottyInjectedPlugin.scala b/sbt-test/tasty-compat/add-param-unroll/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..fb946c4b8c61 --- /dev/null +++ b/sbt-test/tasty-compat/add-param-unroll/project/DottyInjectedPlugin.scala @@ -0,0 +1,11 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion") + ) +} diff --git a/sbt-test/tasty-compat/add-param-unroll/test b/sbt-test/tasty-compat/add-param-unroll/test new file mode 100644 index 000000000000..3fa9e731fe40 --- /dev/null +++ b/sbt-test/tasty-compat/add-param-unroll/test @@ -0,0 +1,8 @@ +# compile library A +> a/compile +# compile library B, from source, against A +> b/compile +# add a new parameter in method to library A', using @unroll to generate a forwarder +> a-changes/compile +# compile B, from tasty, against A', it should still compile: the generated forwarder is resolved. +> c/compile diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index 8ff590fefec5..de3700c667a4 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -227,7 +227,7 @@ Standard-Section: "ASTs" TopLevelStat* PARAMalias -- Parameter is alias of a superclass parameter EXPORTED -- An export forwarder OPEN -- an open class - INVISIBLE -- invisible during typechecking + INVISIBLE -- invisible during typechecking, except when resolving from TASTy TRACKED -- a tracked class parameter / a dependent class Annotation From f8a81b1814bb1b274be7440baaaa660ce3c6ca86 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 13 Nov 2024 08:21:25 +0100 Subject: [PATCH 4/5] address review comments - add check files for run/unroll tests - refactorings - test clause interleaving and value class --- .../dotty/tools/dotc/CompilationUnit.scala | 4 +- .../dotty/tools/dotc/core/Denotations.scala | 4 +- .../tools/dotc/core/tasty/TreePickler.scala | 12 +- .../dotty/tools/dotc/reporting/messages.scala | 2 +- .../tools/dotc/transform/PostTyper.scala | 18 +- .../dotc/transform/UnrollDefinitions.scala | 155 +++++++++--------- .../src/dotty/tools/dotc/typer/Checking.scala | 7 +- .../src/dotty/tools/dotc/typer/Typer.scala | 4 +- tests/neg/unroll-abstractMethod.check | 4 +- tests/neg/unroll-clause-interleaving.check | 7 + tests/neg/unroll-clause-interleaving.scala | 10 ++ tests/neg/unroll-duped.check | 6 +- tests/neg/unroll-illegal3.check | 6 +- tests/neg/unroll-traitConstructor.check | 2 +- tests/run/unroll-caseclass-integration.check | 34 ++++ .../UnrollTestPlatformSpecific_3.scala | 2 +- .../run/unroll-classMethod-integration.check | 14 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- tests/run/unroll-clause-interleaving.check | 0 .../unroll-clause-interleaving/Test_4.scala | 7 + .../Unrolled_1.scala | 14 ++ .../Unrolled_2.scala | 16 ++ .../Unrolled_3.scala | 18 ++ .../unroll-curriedMethod-integration.check | 14 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- .../unroll-genericMethod-integration.check | 14 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- tests/run/unroll-inferredFinal.check | 0 ...nroll-methodWithImplicit-integration.check | 14 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- tests/run/unroll-multiple.check | 0 .../run/unroll-objectMethod-integration.check | 21 +++ .../UnrollTestPlatformSpecific_3.scala | 4 +- ...nroll-primaryConstructor-integration.check | 13 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- ...roll-secondParameterList-integration.check | 14 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- ...oll-secondaryConstructor-integration.check | 14 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- .../run/unroll-traitMethod-integration.check | 31 ++++ .../UnrollTestPlatformSpecific_3.scala | 2 +- tests/run/unroll-traitMethod/Test_2.scala | 6 - tests/run/unroll-traitMethod/Unrolled_1.scala | 10 -- tests/run/unroll-value-class.check | 0 tests/run/unroll-value-class/Test_4.scala | 7 + tests/run/unroll-value-class/Unrolled_1.scala | 13 ++ tests/run/unroll-value-class/Unrolled_2.scala | 15 ++ tests/run/unroll-value-class/Unrolled_3.scala | 17 ++ 48 files changed, 427 insertions(+), 142 deletions(-) create mode 100644 tests/neg/unroll-clause-interleaving.check create mode 100644 tests/neg/unroll-clause-interleaving.scala create mode 100644 tests/run/unroll-caseclass-integration.check create mode 100644 tests/run/unroll-classMethod-integration.check create mode 100644 tests/run/unroll-clause-interleaving.check create mode 100644 tests/run/unroll-clause-interleaving/Test_4.scala create mode 100644 tests/run/unroll-clause-interleaving/Unrolled_1.scala create mode 100644 tests/run/unroll-clause-interleaving/Unrolled_2.scala create mode 100644 tests/run/unroll-clause-interleaving/Unrolled_3.scala create mode 100644 tests/run/unroll-curriedMethod-integration.check create mode 100644 tests/run/unroll-genericMethod-integration.check create mode 100644 tests/run/unroll-inferredFinal.check create mode 100644 tests/run/unroll-methodWithImplicit-integration.check create mode 100644 tests/run/unroll-multiple.check create mode 100644 tests/run/unroll-objectMethod-integration.check create mode 100644 tests/run/unroll-primaryConstructor-integration.check create mode 100644 tests/run/unroll-secondParameterList-integration.check create mode 100644 tests/run/unroll-secondaryConstructor-integration.check create mode 100644 tests/run/unroll-traitMethod-integration.check delete mode 100644 tests/run/unroll-traitMethod/Test_2.scala delete mode 100644 tests/run/unroll-traitMethod/Unrolled_1.scala create mode 100644 tests/run/unroll-value-class.check create mode 100644 tests/run/unroll-value-class/Test_4.scala create mode 100644 tests/run/unroll-value-class/Unrolled_1.scala create mode 100644 tests/run/unroll-value-class/Unrolled_2.scala create mode 100644 tests/run/unroll-value-class/Unrolled_3.scala diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 0368374b6596..9c985ecd84b3 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -59,8 +59,8 @@ class CompilationUnit protected (val source: SourceFile, val info: CompilationUn var hasMacroAnnotations: Boolean = false - def hasUnrollDefs: Boolean = unrolledClasses != null - var unrolledClasses: Set[Symbol] | Null = null + def hasUnrollDefs: Boolean = unrolledClasses.nonEmpty + var unrolledClasses: Set[Symbol] = Set.empty /** Set to `true` if inliner added anonymous mirrors that need to be completed */ var needsMirrorSupport: Boolean = false diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index e2ef3f7eafb8..4d7ff138a2e8 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -1072,7 +1072,9 @@ object Denotations { def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation = if (denots.exists && denots.matches(this)) NoDenotation else this def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation = - val realExcluded = if ctx.isAfterTyper then excluded else excluded | (if ctx.mode.is(Mode.ResolveFromTASTy) then EmptyFlags else Invisible) + val realExcluded = + if ctx.isAfterTyper || ctx.mode.is(Mode.ResolveFromTASTy) then excluded + else excluded | Invisible def symd: SymDenotation = this match case symd: SymDenotation => symd case _ => symbol.denot diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 6822fcc8e548..7b80c7c80a21 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -20,7 +20,6 @@ import collection.mutable import reporting.{Profile, NoProfile} import dotty.tools.tasty.TastyFormat.ASTsSection import quoted.QuotePatterns -import dotty.tools.dotc.config.Feature object TreePickler: class StackSizeExceeded(val mdef: tpd.MemberDef) extends Exception @@ -475,16 +474,15 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { case _ => if passesConditionForErroringBestEffortCode(tree.hasType) then // #19951 The signature of a constructor of a Java annotation is irrelevant - val sym = tree.symbol val sig = - if name == nme.CONSTRUCTOR && sym.exists && sym.owner.is(JavaAnnotation) then Signature.NotAMethod + if name == nme.CONSTRUCTOR && tree.symbol.exists && tree.symbol.owner.is(JavaAnnotation) then Signature.NotAMethod else tree.tpe.signature - var ename = sym.targetName + var ename = tree.symbol.targetName val selectFromQualifier = name.isTypeName || qual.isInstanceOf[Hole] // holes have no symbol || sig == Signature.NotAMethod // no overload resolution necessary - || !sym.exists // polymorphic function type + || !tree.denot.symbol.exists // polymorphic function type || tree.denot.asSingleDenotation.isRefinedMethod // refined methods have no defining class symbol if selectFromQualifier then writeByte(if name.isTypeName then SELECTtpt else SELECT) @@ -493,9 +491,9 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { else // select from owner writeByte(SELECTin) withLength { - pickleNameAndSig(name, sym.signature, ename) + pickleNameAndSig(name, tree.symbol.signature, ename) pickleTree(qual) - pickleType(sym.owner.typeRef) + pickleType(tree.symbol.owner.typeRef) } else writeByte(if name.isTypeName then SELECTtpt else SELECT) diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 0bc418301d4e..20347f706502 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -3416,7 +3416,7 @@ extends DeclarationMsg(IllegalUnrollPlacementID): case Some(method) => val isCtor = method.isConstructor def what = if isCtor then i"a ${if method.owner.is(Trait) then "trait" else "class"} constructor" else i"method ${method.name}" - val prefix = s"Can not unroll parameters of $what" + val prefix = s"Cannot unroll parameters of $what" if method.is(Deferred) then i"$prefix: it must not be abstract" else if isCtor && method.owner.is(Trait) then diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index cc7595442ddb..02f5434aa549 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -120,20 +120,12 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => private var inJavaAnnot: Boolean = false - private var seenUnrolledMethods: util.EqHashMap[Symbol, Boolean] | Null = null + private val seenUnrolledMethods: util.EqHashMap[Symbol, Boolean] = new util.EqHashMap[Symbol, Boolean] private var noCheckNews: Set[New] = Set() def isValidUnrolledMethod(method: Symbol, origin: SrcPos)(using Context): Boolean = - val seenMethods = - val local = seenUnrolledMethods - if local == null then - val map = new util.EqHashMap[Symbol, Boolean] - seenUnrolledMethods = map - map - else - local - seenMethods.getOrElseUpdate(method, { + seenUnrolledMethods.getOrElseUpdate(method, { val isCtor = method.isConstructor if method.name.is(DefaultGetterName) @@ -234,12 +226,8 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => private def registerIfUnrolledParam(sym: Symbol)(using Context): Unit = if sym.hasAnnotation(defn.UnrollAnnot) && isValidUnrolledMethod(sym.owner, sym.sourcePos) then val cls = sym.enclosingClass - val classes = ctx.compilationUnit.unrolledClasses val additions = Array(cls, cls.linkedClass).filter(_ != NoSymbol) - if classes == null then - ctx.compilationUnit.unrolledClasses = Set.from(additions) - else - ctx.compilationUnit.unrolledClasses = classes ++ additions + ctx.compilationUnit.unrolledClasses ++= additions private def processValOrDefDef(tree: Tree)(using Context): tree.type = val sym = tree.symbol diff --git a/compiler/src/dotty/tools/dotc/transform/UnrollDefinitions.scala b/compiler/src/dotty/tools/dotc/transform/UnrollDefinitions.scala index 9cbaf7738533..b431a81afeac 100644 --- a/compiler/src/dotty/tools/dotc/transform/UnrollDefinitions.scala +++ b/compiler/src/dotty/tools/dotc/transform/UnrollDefinitions.scala @@ -22,6 +22,7 @@ import scala.collection.mutable import scala.util.boundary, boundary.break import dotty.tools.dotc.core.StdNames.nme import dotty.tools.unreachable +import dotty.tools.dotc.util.Spans.Span /**Implementation of SIP-61. * Runs when `@unroll` annotations are found in a compilation unit, installing new definitions @@ -33,16 +34,10 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { import tpd.* - private var _unrolledDefs: util.EqHashMap[Symbol, ComputedIndicies] | Null = null - private def initializeUnrolledDefs(): util.EqHashMap[Symbol, ComputedIndicies] = - val local = _unrolledDefs - if local == null then - val map = new util.EqHashMap[Symbol, ComputedIndicies] - _unrolledDefs = map - map - else - local.clear() - local + private val _unrolledDefs: util.EqHashMap[Symbol, ComputedIndices] = new util.EqHashMap[Symbol, ComputedIndices] + private def initializeUnrolledDefs(): util.EqHashMap[Symbol, ComputedIndices] = + _unrolledDefs.clear() + _unrolledDefs override def phaseName: String = UnrollDefinitions.name @@ -55,18 +50,25 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { super.run // create and run the transformer on the current compilation unit def newTransformer(using Context): Transformer = - UnrollingTransformer(ctx.compilationUnit.unrolledClasses.nn) + UnrollingTransformer(ctx.compilationUnit.unrolledClasses) - type ComputedIndicies = List[(Int, List[Int])] - type ComputeIndicies = Context ?=> Symbol => ComputedIndicies + type ComputedIndices = List[(Int, List[Int])] + type ComputeIndices = Context ?=> Symbol => ComputedIndices - private class UnrollingTransformer(classes: Set[Symbol]) extends Transformer { + private class UnrollingTransformer(unrolledClasses: Set[Symbol]) extends Transformer { private val unrolledDefs = initializeUnrolledDefs() - def computeIndices(annotated: Symbol)(using Context): ComputedIndicies = + def computeIndices(annotated: Symbol)(using Context): ComputedIndices = unrolledDefs.getOrElseUpdate(annotated, { if annotated.name.is(DefaultGetterName) then - Nil // happens in curried methods where more than one parameter list has @unroll + // happens in curried methods, where default argument occurs in parameter list + // after the unrolled parameter list. + // example: + // `final def foo(@unroll y: String = "")(x: Int = 23) = x` + // yields: + // `def foo$default$2(@unroll y: String): Int @uncheckedVariance = 23` + // Perhaps annotations should be preprocessed before they are copied? + Nil else val indices = annotated .paramSymss @@ -84,17 +86,17 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { end computeIndices override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match - case tree @ TypeDef(_, impl: Template) if classes(tree.symbol) => + case tree @ TypeDef(_, impl: Template) if unrolledClasses(tree.symbol) => super.transform(cpy.TypeDef(tree)(rhs = unrollTemplate(impl, computeIndices))) case tree => super.transform(tree) } - def copyParamSym(sym: Symbol, parent: Symbol)(using Context): (Symbol, Symbol) = + private def copyParamSym(sym: Symbol, parent: Symbol)(using Context): (Symbol, Symbol) = val copied = sym.copy(owner = parent, flags = (sym.flags &~ HasDefault), coord = sym.coord) sym -> copied - def symLocation(sym: Symbol)(using Context) = { + private def symLocation(sym: Symbol)(using Context) = { val lineDesc = if (sym.span.exists && sym.span != sym.owner.span) s" at line ${sym.srcPos.line + 1}" @@ -102,7 +104,7 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { i"in ${sym.owner}${lineDesc}" } - def findUnrollAnnotations(params: List[Symbol])(using Context): List[Int] = { + private def findUnrollAnnotations(params: List[Symbol])(using Context): List[Int] = { params .zipWithIndex .collect { @@ -111,16 +113,23 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { } } - def isTypeClause(p: ParamClause) = p.headOption.exists(_.isInstanceOf[TypeDef]) - - def generateSingleForwarder(defdef: DefDef, - prevMethodType: Type, + private def isTypeClause(p: ParamClause) = p.headOption.exists(_.isInstanceOf[TypeDef]) + + /** Generate a forwarder that calls the next one in a "chain" of forwarders + * + * @param defdef the original unrolled def that the forwarder is derived from + * @param paramIndex index of the unrolled parameter (in the parameter list) that we stop at + * @param paramCount number of parameters in the annotated parameter list + * @param nextParamIndex index of next unrolled parameter - to fetch default argument + * @param annotatedParamListIndex index of the parameter list that contains unrolled parameters + * @param isCaseApply if `defdef` is a case class apply/constructor - used for selection of default arguments + */ + private def generateSingleForwarder(defdef: DefDef, paramIndex: Int, paramCount: Int, nextParamIndex: Int, - nextSymbol: Symbol, annotatedParamListIndex: Int, - isCaseApply: Boolean)(using Context) = { + isCaseApply: Boolean)(using Context): DefDef = { def initNewForwarder()(using Context): (TermSymbol, List[List[Symbol]]) = { val forwarderDefSymbol0 = Symbols.newSymbol( @@ -129,15 +138,15 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { defdef.symbol.flags &~ HasDefaultParams | Invisible | Synthetic, NoType, // fill in later - coord = nextSymbol.span.shift(1) // shift by 1 to avoid "secondary constructor must call preceding" error + coord = defdef.span ).entered val newParamSymMappings = extractParamSymss(copyParamSym(_, forwarderDefSymbol0)) val (oldParams, newParams) = newParamSymMappings.flatten.unzip val newParamSymLists0 = - newParamSymMappings.map: pairss => - pairss.map: (oldSym, newSym) => + newParamSymMappings.map: pairs => + pairs.map: (oldSym, newSym) => newSym.info = oldSym.info.substSym(oldParams, newParams) newSym @@ -153,8 +162,6 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { else ps.map(p => onSymbol(p.symbol)) } - val paramCount = defdef.symbol.paramSymss(annotatedParamListIndex).size - val (forwarderDefSymbol, newParamSymLists) = initNewForwarder() def forwarderRhs(): tpd.Tree = { @@ -194,9 +201,7 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { newParamSymLists .take(annotatedParamListIndex) .map(_.map(ref)) - .foldLeft(inner): (lhs, newParams) => - if (newParams.headOption.exists(_.isInstanceOf[TypeTree])) TypeApply(lhs, newParams) - else Apply(lhs, newParams) + .foldLeft(inner)(_.appliedToArgs(_)) ) val forwarderInner: Tree = @@ -208,11 +213,7 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { else ps.map(ref) } - val forwarderCall0 = forwarderCallArgs.foldLeft[Tree](forwarderInner){ - case (lhs: Tree, newParams) => - if (newParams.headOption.exists(_.isInstanceOf[TypeTree])) TypeApply(lhs, newParams) - else Apply(lhs, newParams) - } + val forwarderCall0 = forwarderCallArgs.foldLeft(forwarderInner)(_.appliedToArgs(_)) val forwarderCall = if (!defdef.symbol.isConstructor) forwarderCall0 @@ -222,12 +223,12 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { } val forwarderDef = - tpd.DefDef(forwarderDefSymbol, rhs = forwarderRhs()) + tpd.DefDef(forwarderDefSymbol, rhs = forwarderRhs()).withSpan(defdef.span) - forwarderDef.withSpan(nextSymbol.span.shift(1)) + forwarderDef } - def generateFromProduct(startParamIndices: List[Int], paramCount: Int, defdef: DefDef)(using Context) = { + private def generateFromProduct(startParamIndices: List[Int], paramCount: Int, defdef: DefDef)(using Context) = { cpy.DefDef(defdef)( name = defdef.name, paramss = defdef.paramss, @@ -248,28 +249,35 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { ) ) ) - } ++ Seq( - CaseDef( - Underscore(defn.IntType), - EmptyTree, - defdef.rhs - ) + } :+ CaseDef( + Underscore(defn.IntType), + EmptyTree, + defdef.rhs ) ) ).setDefTree } - def generateSyntheticDefs(tree: Tree, compute: ComputeIndicies)(using Context): Option[(Symbol, Option[Symbol], Seq[DefDef])] = tree match { + private enum Gen: + case Substitute(origin: Symbol, newDef: DefDef) + case Forwarders(origin: Symbol, forwarders: List[DefDef]) + + def origin: Symbol + def extras: List[DefDef] = this match + case Substitute(_, d) => d :: Nil + case Forwarders(_, ds) => ds + + private def generateSyntheticDefs(tree: Tree, compute: ComputeIndices)(using Context): Option[Gen] = tree match { case defdef: DefDef if defdef.paramss.nonEmpty => import dotty.tools.dotc.core.NameOps.isConstructorName val isCaseCopy = - defdef.name.toString == "copy" && defdef.symbol.owner.is(CaseClass) + defdef.name == nme.copy && defdef.symbol.owner.is(CaseClass) val isCaseApply = - defdef.name.toString == "apply" && defdef.symbol.owner.companionClass.is(CaseClass) + defdef.name == nme.apply && defdef.symbol.owner.companionClass.is(CaseClass) - val isCaseFromProduct = defdef.name.toString == "fromProduct" && defdef.symbol.owner.companionClass.is(CaseClass) + val isCaseFromProduct = defdef.name == nme.fromProduct && defdef.symbol.owner.companionClass.is(CaseClass) val annotated = if (isCaseCopy) defdef.symbol.owner.primaryConstructor @@ -279,28 +287,28 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { compute(annotated) match { case Nil => None - case Seq((paramClauseIndex, annotationIndices)) => + case (paramClauseIndex, annotationIndices) :: Nil => val paramCount = annotated.paramSymss(paramClauseIndex).size if isCaseFromProduct then - Some((defdef.symbol, Some(defdef.symbol), Seq(generateFromProduct(annotationIndices, paramCount, defdef)))) + Some(Gen.Substitute( + origin = defdef.symbol, + newDef = generateFromProduct(annotationIndices, paramCount, defdef) + )) else - val (generatedDefs, _) = + val generatedDefs = val indices = (annotationIndices :+ paramCount).sliding(2).toList.reverse - indices.foldLeft((Seq.empty[DefDef], defdef.symbol)): - case ((defdefs, nextSymbol), Seq(paramIndex, nextParamIndex)) => - val forwarder = generateSingleForwarder( + indices.foldLeft(List.empty[DefDef]): + case (defdefs, paramIndex :: nextParamIndex :: Nil) => + generateSingleForwarder( defdef, - defdef.symbol.info, paramIndex, paramCount, nextParamIndex, - nextSymbol, paramClauseIndex, isCaseApply - ) - (forwarder +: defdefs, forwarder.symbol) + ) :: defdefs case _ => unreachable("sliding with at least 2 elements") - Some((defdef.symbol, None, generatedDefs)) + Some(Gen.Forwarders(origin = defdef.symbol, forwarders = generatedDefs)) case multiple => report.error("Cannot have multiple parameter lists containing `@unroll` annotation", defdef.srcPos) @@ -310,44 +318,37 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer { case _ => None } - def unrollTemplate(tmpl: tpd.Template, compute: ComputeIndicies)(using Context): tpd.Tree = { + private def unrollTemplate(tmpl: tpd.Template, compute: ComputeIndices)(using Context): tpd.Tree = { val generatedBody = tmpl.body.flatMap(generateSyntheticDefs(_, compute)) val generatedConstr0 = generateSyntheticDefs(tmpl.constr, compute) val allGenerated = generatedBody ++ generatedConstr0 - val bodySubs = generatedBody.flatMap((_, maybeSub, _) => maybeSub).toSet + val bodySubs = generatedBody.collect({ case s: Gen.Substitute => s.origin }).toSet val otherDecls = tmpl.body.filterNot(d => d.symbol.exists && bodySubs(d.symbol)) - /** inlined from compiler/src/dotty/tools/dotc/typer/Checking.scala */ - def checkClash(decl: Symbol, other: Symbol) = - def staticNonStaticPair = decl.isScalaStatic != other.isScalaStatic - decl.matches(other) && !staticNonStaticPair - if allGenerated.nonEmpty then val byName = (tmpl.constr :: otherDecls).groupMap(_.symbol.name.toString)(_.symbol) for - (src, _, dcls) <- allGenerated - dcl <- dcls + syntheticDefs <- allGenerated + dcl <- syntheticDefs.extras do val replaced = dcl.symbol byName.get(dcl.name.toString).foreach { syms => - val clashes = syms.filter(checkClash(replaced, _)) + val clashes = syms.filter(ctx.typer.matchesSameStatic(replaced, _)) for existing <- clashes do + val src = syntheticDefs.origin report.error(i"""Unrolled $replaced clashes with existing declaration. |Please remove the clashing definition, or the @unroll annotation. |Unrolled from ${hl(src.showDcl)} ${symLocation(src)}""".stripMargin, existing.srcPos) } end if - val generatedDefs = generatedBody.flatMap((_, _, gens) => gens) - val generatedConstr = generatedConstr0.toList.flatMap((_, _, gens) => gens) - cpy.Template(tmpl)( tmpl.constr, tmpl.parents, tmpl.derived, tmpl.self, - otherDecls ++ generatedDefs ++ generatedConstr + otherDecls ++ allGenerated.flatMap(_.extras) ) } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 3a2f16438c88..2a40cb78f442 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -1226,6 +1226,10 @@ trait Checking { /** A hook to exclude selected symbols from double declaration check */ def excludeFromDoubleDeclCheck(sym: Symbol)(using Context): Boolean = false + def matchesSameStatic(decl: Symbol, other: Symbol)(using Context): Boolean = + def staticNonStaticPair = decl.isScalaStatic != other.isScalaStatic + decl.matches(other) && !staticNonStaticPair + /** Check that class does not declare same symbol twice */ def checkNoDoubleDeclaration(cls: Symbol)(using Context): Unit = { val seen = new mutable.HashMap[Name, List[Symbol]].withDefaultValue(Nil) @@ -1237,8 +1241,7 @@ trait Checking { def javaFieldMethodPair = decl.is(JavaDefined) && other.is(JavaDefined) && decl.is(Method) != other.is(Method) - def staticNonStaticPair = decl.isScalaStatic != other.isScalaStatic - if (decl.matches(other) && !javaFieldMethodPair && !staticNonStaticPair) { + if (matchesSameStatic(decl, other) && !javaFieldMethodPair) { def doubleDefError(decl: Symbol, other: Symbol): Unit = if (!decl.info.isErroneous && !other.info.isErroneous) report.error(DoubleDefinition(decl, other, cls), decl.srcPos) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 9b7e4fe36668..ee22f093c08c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2950,7 +2950,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer def checkThisConstrCall(tree: Tree): Unit = tree match case app: Apply if untpd.isSelfConstrCall(app) => - if (sym.span.exists && app.symbol.span.exists && sym.span.start <= app.symbol.span.start) + if !sym.is(Synthetic) + && sym.span.exists && app.symbol.span.exists && sym.span.start <= app.symbol.span.start + then report.error("secondary constructor must call a preceding constructor", app.srcPos) case Block(call :: _, _) => checkThisConstrCall(call) case _ => diff --git a/tests/neg/unroll-abstractMethod.check b/tests/neg/unroll-abstractMethod.check index 948c7d1a7862..d0874c8a44d8 100644 --- a/tests/neg/unroll-abstractMethod.check +++ b/tests/neg/unroll-abstractMethod.check @@ -1,8 +1,8 @@ -- [E207] Declaration Error: tests/neg/unroll-abstractMethod.scala:6:41 ------------------------------------------------ 6 | def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String // error | ^ - | Can not unroll parameters of method foo: it must not be abstract + | Cannot unroll parameters of method foo: it must not be abstract -- [E207] Declaration Error: tests/neg/unroll-abstractMethod.scala:10:41 ----------------------------------------------- 10 | def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String // error | ^ - | Can not unroll parameters of method foo: it must not be abstract + | Cannot unroll parameters of method foo: it must not be abstract diff --git a/tests/neg/unroll-clause-interleaving.check b/tests/neg/unroll-clause-interleaving.check new file mode 100644 index 000000000000..eea8a7383e09 --- /dev/null +++ b/tests/neg/unroll-clause-interleaving.check @@ -0,0 +1,7 @@ +-- Error: tests/neg/unroll-clause-interleaving.scala:6:12 -------------------------------------------------------------- +6 | final def foo(@unroll x: Int = 0)[T](// error + | ^ + | Cannot have multiple parameter lists containing `@unroll` annotation +7 | s: T, +8 | @unroll y: Boolean = true, +9 | ): String = "" + x + s + y diff --git a/tests/neg/unroll-clause-interleaving.scala b/tests/neg/unroll-clause-interleaving.scala new file mode 100644 index 000000000000..c40941320db1 --- /dev/null +++ b/tests/neg/unroll-clause-interleaving.scala @@ -0,0 +1,10 @@ +//> using options -experimental + +import scala.annotation.unroll + +class Unrolled { + final def foo(@unroll x: Int = 0)[T](// error + s: T, + @unroll y: Boolean = true, + ): String = "" + x + s + y +} diff --git a/tests/neg/unroll-duped.check b/tests/neg/unroll-duped.check index 2c1cc80cfee7..9ec09672566b 100644 --- a/tests/neg/unroll-duped.check +++ b/tests/neg/unroll-duped.check @@ -1,12 +1,12 @@ -- [E207] Declaration Error: tests/neg/unroll-duped.scala:11:45 -------------------------------------------------------- 11 | final def copy(s: String = this.s, @unroll y: Boolean = this.y): UnrolledCase = // error | ^ - | Can not unroll parameters of method copy of a case class: please annotate the class constructor instead + | Cannot unroll parameters of method copy of a case class: please annotate the class constructor instead -- [E207] Declaration Error: tests/neg/unroll-duped.scala:18:12 -------------------------------------------------------- 18 | @unroll y: Boolean = true // error | ^ - |Can not unroll parameters of method apply of a case class companion object: please annotate the class constructor instead + |Cannot unroll parameters of method apply of a case class companion object: please annotate the class constructor instead -- [E207] Declaration Error: tests/neg/unroll-duped.scala:22:26 -------------------------------------------------------- 22 | def fromProduct(@unroll p: Product = EmptyTuple): UnrolledCase = { // error | ^ - |Can not unroll parameters of method fromProduct of a case class companion object: please annotate the class constructor instead + |Cannot unroll parameters of method fromProduct of a case class companion object: please annotate the class constructor instead diff --git a/tests/neg/unroll-illegal3.check b/tests/neg/unroll-illegal3.check index 8502b76b50e2..6201a7d815cd 100644 --- a/tests/neg/unroll-illegal3.check +++ b/tests/neg/unroll-illegal3.check @@ -1,12 +1,12 @@ -- [E207] Declaration Error: tests/neg/unroll-illegal3.scala:7:31 ------------------------------------------------------ 7 | def foo(s: String, @unroll y: Boolean) = s + y // error | ^ - | Can not unroll parameters of method foo: it is not final + | Cannot unroll parameters of method foo: it is not final -- [E207] Declaration Error: tests/neg/unroll-illegal3.scala:12:29 ----------------------------------------------------- 12 | def foo(s: String, @unroll y: Boolean) = s + y // error | ^ - | Can not unroll parameters of method foo: it is not final + | Cannot unroll parameters of method foo: it is not final -- [E207] Declaration Error: tests/neg/unroll-illegal3.scala:16:29 ----------------------------------------------------- 16 | def foo(s: String, @unroll y: Boolean): String // error | ^ - | Can not unroll parameters of method foo: it must not be abstract + | Cannot unroll parameters of method foo: it must not be abstract diff --git a/tests/neg/unroll-traitConstructor.check b/tests/neg/unroll-traitConstructor.check index 0a5570667196..9bb74d2559bf 100644 --- a/tests/neg/unroll-traitConstructor.check +++ b/tests/neg/unroll-traitConstructor.check @@ -1,4 +1,4 @@ -- [E207] Declaration Error: tests/neg/unroll-traitConstructor.scala:5:32 ---------------------------------------------- 5 |trait Unroll(a: String, @unroll b: Boolean = true): // error | ^ - | implementation restriction: Can not unroll parameters of a trait constructor + | implementation restriction: Cannot unroll parameters of a trait constructor diff --git a/tests/run/unroll-caseclass-integration.check b/tests/run/unroll-caseclass-integration.check new file mode 100644 index 000000000000..0418867c80c6 --- /dev/null +++ b/tests/run/unroll-caseclass-integration.check @@ -0,0 +1,34 @@ +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "hello31337" + "true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "hello31337false" + "0" +Assertion passed: found "hello31337false12345" + +public unroll.Unrolled(java.lang.String,int) +public unroll.Unrolled(java.lang.String,int,boolean) +public unroll.Unrolled(java.lang.String,int,boolean,long) +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false9" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false9" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false9" diff --git a/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala index e06a38502c62..7a8021b304da 100644 --- a/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala @@ -30,6 +30,6 @@ object UnrollTestPlatformSpecificV3{ "hello2false3" ) - cls.getConstructors.foreach(println) + cls.getConstructors.map(_.toString).sorted.foreach(println) } } diff --git a/tests/run/unroll-classMethod-integration.check b/tests/run/unroll-classMethod-integration.check new file mode 100644 index 000000000000..db6f0ee5732d --- /dev/null +++ b/tests/run/unroll-classMethod-integration.check @@ -0,0 +1,14 @@ +Assertion passed: found "cow" + "1true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +public boolean unroll.Unrolled.foo$default$3() +public final java.lang.String unroll.Unrolled.foo(java.lang.String) +public final java.lang.String unroll.Unrolled.foo(java.lang.String,int,boolean) +public final java.lang.String unroll.Unrolled.foo(java.lang.String,int,boolean,long) +public int unroll.Unrolled.foo$default$2() +public long unroll.Unrolled.foo$default$4() +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala index 3b5dc603fd3a..f68cc60c3139 100644 --- a/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -27,6 +27,6 @@ object UnrollTestPlatformSpecificV3{ "hello2false3" ) - cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + cls.getMethods.filter(_.getName.contains("foo")).map(_.toString).sorted.foreach(println) } } diff --git a/tests/run/unroll-clause-interleaving.check b/tests/run/unroll-clause-interleaving.check new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/run/unroll-clause-interleaving/Test_4.scala b/tests/run/unroll-clause-interleaving/Test_4.scala new file mode 100644 index 000000000000..4090469bb716 --- /dev/null +++ b/tests/run/unroll-clause-interleaving/Test_4.scala @@ -0,0 +1,7 @@ +//> using options -experimental + +@main def Test: Unit = + val u = Unrolled() + TestV1().test(u) + TestV2().test(u) + TestV3().test(u) diff --git a/tests/run/unroll-clause-interleaving/Unrolled_1.scala b/tests/run/unroll-clause-interleaving/Unrolled_1.scala new file mode 100644 index 000000000000..7954acc15680 --- /dev/null +++ b/tests/run/unroll-clause-interleaving/Unrolled_1.scala @@ -0,0 +1,14 @@ +//> using options -experimental + +import scala.annotation.unroll + +class Unrolled { + final def foo(x: Int)[T]( + s: T, + ): String = "" + x + s +} + +class TestV1 { + def test(u: Unrolled): Unit = + assert(u.foo(0)("foo").startsWith("0foo")) +} diff --git a/tests/run/unroll-clause-interleaving/Unrolled_2.scala b/tests/run/unroll-clause-interleaving/Unrolled_2.scala new file mode 100644 index 000000000000..5adc2bc924ec --- /dev/null +++ b/tests/run/unroll-clause-interleaving/Unrolled_2.scala @@ -0,0 +1,16 @@ +//> using options -experimental + +import scala.annotation.unroll + +class Unrolled { + final def foo(x: Int)[T]( + s: T, + @unroll y: Boolean = true, + ): String = "" + x + s + y +} + +class TestV2 { + def test(u: Unrolled): Unit = + assert(u.foo(0)("foo").startsWith("0footrue")) + assert(u.foo(0)("foo", false).startsWith("0foofalse")) +} diff --git a/tests/run/unroll-clause-interleaving/Unrolled_3.scala b/tests/run/unroll-clause-interleaving/Unrolled_3.scala new file mode 100644 index 000000000000..e23b9d12843a --- /dev/null +++ b/tests/run/unroll-clause-interleaving/Unrolled_3.scala @@ -0,0 +1,18 @@ +//> using options -experimental + +import scala.annotation.unroll + +class Unrolled { + final def foo(x: Int)[T]( + s: T, + @unroll y: Boolean = true, + @unroll i: Int = 0, + ): String = "" + x + s + y + i +} + +class TestV3 { + def test(u: Unrolled): Unit = + assert(u.foo(0)("foo").startsWith("0footrue0")) + assert(u.foo(0)("foo", false).startsWith("0foofalse0")) + assert(u.foo(0)("foo", false, 1).startsWith("0foofalse1")) +} diff --git a/tests/run/unroll-curriedMethod-integration.check b/tests/run/unroll-curriedMethod-integration.check new file mode 100644 index 000000000000..bd696cc21ed5 --- /dev/null +++ b/tests/run/unroll-curriedMethod-integration.check @@ -0,0 +1,14 @@ +Assertion passed: found "cow" + "1true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +public boolean unroll.Unrolled.foo$default$3() +public final java.lang.String unroll.Unrolled.foo(java.lang.String,int,boolean,long,scala.Function1) +public final java.lang.String unroll.Unrolled.foo(java.lang.String,int,boolean,scala.Function1) +public final java.lang.String unroll.Unrolled.foo(java.lang.String,scala.Function1) +public int unroll.Unrolled.foo$default$2() +public long unroll.Unrolled.foo$default$4() +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala index 69bbaf06d6ae..ac4ad5f22d1e 100644 --- a/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -26,6 +26,6 @@ object UnrollTestPlatformSpecificV3{ "hello2false3" ) - cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + cls.getMethods.filter(_.getName.contains("foo")).map(_.toString).sorted.foreach(println) } } diff --git a/tests/run/unroll-genericMethod-integration.check b/tests/run/unroll-genericMethod-integration.check new file mode 100644 index 000000000000..e1880e773f8e --- /dev/null +++ b/tests/run/unroll-genericMethod-integration.check @@ -0,0 +1,14 @@ +Assertion passed: found "cow" + "1true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +public boolean unroll.Unrolled.foo$default$3() +public final java.lang.String unroll.Unrolled.foo(java.lang.Object) +public final java.lang.String unroll.Unrolled.foo(java.lang.Object,int,boolean) +public final java.lang.String unroll.Unrolled.foo(java.lang.Object,int,boolean,long) +public int unroll.Unrolled.foo$default$2() +public long unroll.Unrolled.foo$default$4() +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala index d5310b3e302b..f39864bee0fd 100644 --- a/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -23,7 +23,7 @@ object UnrollTestPlatformSpecificV3{ .invoke(instance, "hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) == "hello2false3" ) - cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + cls.getMethods.filter(_.getName.contains("foo")).map(_.toString).sorted.foreach(println) } } diff --git a/tests/run/unroll-inferredFinal.check b/tests/run/unroll-inferredFinal.check new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/run/unroll-methodWithImplicit-integration.check b/tests/run/unroll-methodWithImplicit-integration.check new file mode 100644 index 000000000000..bd696cc21ed5 --- /dev/null +++ b/tests/run/unroll-methodWithImplicit-integration.check @@ -0,0 +1,14 @@ +Assertion passed: found "cow" + "1true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +public boolean unroll.Unrolled.foo$default$3() +public final java.lang.String unroll.Unrolled.foo(java.lang.String,int,boolean,long,scala.Function1) +public final java.lang.String unroll.Unrolled.foo(java.lang.String,int,boolean,scala.Function1) +public final java.lang.String unroll.Unrolled.foo(java.lang.String,scala.Function1) +public int unroll.Unrolled.foo$default$2() +public long unroll.Unrolled.foo$default$4() +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala index 431c1e7c2d4c..399b18583c23 100644 --- a/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala @@ -25,7 +25,7 @@ object UnrollTestPlatformSpecificV3{ "hello2false3" ) - cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + cls.getMethods.filter(_.getName.contains("foo")).map(_.toString).sorted.foreach(println) } } diff --git a/tests/run/unroll-multiple.check b/tests/run/unroll-multiple.check new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/run/unroll-objectMethod-integration.check b/tests/run/unroll-objectMethod-integration.check new file mode 100644 index 000000000000..b29f42ca6d8e --- /dev/null +++ b/tests/run/unroll-objectMethod-integration.check @@ -0,0 +1,21 @@ +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +public boolean unroll.Unrolled$.foo$default$3() +public final java.lang.String unroll.Unrolled$.foo(java.lang.String,int) +public final java.lang.String unroll.Unrolled$.foo(java.lang.String,int,boolean) +public final java.lang.String unroll.Unrolled$.foo(java.lang.String,int,boolean,long) +public int unroll.Unrolled$.foo$default$2() +public long unroll.Unrolled$.foo$default$4() +public static boolean unroll.Unrolled.foo$default$3() +public static int unroll.Unrolled.foo$default$2() +public static java.lang.String unroll.Unrolled.foo(java.lang.String,int) +public static java.lang.String unroll.Unrolled.foo(java.lang.String,int,boolean) +public static java.lang.String unroll.Unrolled.foo(java.lang.String,int,boolean,long) +public static long unroll.Unrolled.foo$default$4() +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala index 6f399649b4b8..31cd0db29aca 100644 --- a/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -7,7 +7,7 @@ object UnrollTestPlatformSpecificV3{ val instance = Unrolled val instanceCls = Class.forName("unroll.Unrolled$") - instanceCls.getMethods.filter(_.getName.contains("foo")).foreach(println) + instanceCls.getMethods.filter(_.getName.contains("foo")).map(_.toString).sorted.foreach(println) // Make sure singleton instance forwarder methods are generated assert(scala.util.Try(instanceCls.getMethod("foo", classOf[String])).isFailure) @@ -28,7 +28,7 @@ object UnrollTestPlatformSpecificV3{ // Make sure static forwarder methods are generated val staticCls = Class.forName("unroll.Unrolled") - staticCls.getMethods.filter(_.getName.contains("foo")).foreach(println) + staticCls.getMethods.filter(_.getName.contains("foo")).map(_.toString).sorted.foreach(println) assert(scala.util.Try(staticCls.getMethod("foo", classOf[String])).isFailure) assert( diff --git a/tests/run/unroll-primaryConstructor-integration.check b/tests/run/unroll-primaryConstructor-integration.check new file mode 100644 index 000000000000..f5f6e28d5635 --- /dev/null +++ b/tests/run/unroll-primaryConstructor-integration.check @@ -0,0 +1,13 @@ +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" + +public unroll.Unrolled(java.lang.String,int) +public unroll.Unrolled(java.lang.String,int,boolean) +public unroll.Unrolled(java.lang.String,int,boolean,long) +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala index e06a38502c62..7a8021b304da 100644 --- a/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala @@ -30,6 +30,6 @@ object UnrollTestPlatformSpecificV3{ "hello2false3" ) - cls.getConstructors.foreach(println) + cls.getConstructors.map(_.toString).sorted.foreach(println) } } diff --git a/tests/run/unroll-secondParameterList-integration.check b/tests/run/unroll-secondParameterList-integration.check new file mode 100644 index 000000000000..d9ba05c5fc84 --- /dev/null +++ b/tests/run/unroll-secondParameterList-integration.check @@ -0,0 +1,14 @@ +Assertion passed: found "cow" + "1true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +public boolean unroll.Unrolled.foo$default$4(scala.Function1) +public final java.lang.String unroll.Unrolled.foo(scala.Function1,java.lang.String) +public final java.lang.String unroll.Unrolled.foo(scala.Function1,java.lang.String,int,boolean) +public final java.lang.String unroll.Unrolled.foo(scala.Function1,java.lang.String,int,boolean,long) +public int unroll.Unrolled.foo$default$3(scala.Function1) +public long unroll.Unrolled.foo$default$5(scala.Function1) +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala index 49dff864f49b..fad69270bbd1 100644 --- a/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala @@ -27,6 +27,6 @@ object UnrollTestPlatformSpecificV3{ "hello2false3" ) - cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + cls.getMethods.filter(_.getName.contains("foo")).map(_.toString).sorted.foreach(println) } } diff --git a/tests/run/unroll-secondaryConstructor-integration.check b/tests/run/unroll-secondaryConstructor-integration.check new file mode 100644 index 000000000000..016acefc31a1 --- /dev/null +++ b/tests/run/unroll-secondaryConstructor-integration.check @@ -0,0 +1,14 @@ +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" + +public unroll.Unrolled() +public unroll.Unrolled(java.lang.String,int) +public unroll.Unrolled(java.lang.String,int,boolean) +public unroll.Unrolled(java.lang.String,int,boolean,long) +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala index e06a38502c62..7a8021b304da 100644 --- a/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala @@ -30,6 +30,6 @@ object UnrollTestPlatformSpecificV3{ "hello2false3" ) - cls.getConstructors.foreach(println) + cls.getConstructors.map(_.toString).sorted.foreach(println) } } diff --git a/tests/run/unroll-traitMethod-integration.check b/tests/run/unroll-traitMethod-integration.check new file mode 100644 index 000000000000..1f83c55f588f --- /dev/null +++ b/tests/run/unroll-traitMethod-integration.check @@ -0,0 +1,31 @@ +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" + +public default boolean unroll.Unrolled.foo$default$3() +public default int unroll.Unrolled.foo$default$2() +public default java.lang.String unroll.Unrolled.foo(java.lang.String,int) +public default java.lang.String unroll.Unrolled.foo(java.lang.String,int,boolean) +public default java.lang.String unroll.Unrolled.foo(java.lang.String,int,boolean,long) +public default long unroll.Unrolled.foo$default$4() +public static boolean unroll.Unrolled.foo$default$3$(unroll.Unrolled) +public static int unroll.Unrolled.foo$default$2$(unroll.Unrolled) +public static java.lang.String unroll.Unrolled.foo$(unroll.Unrolled,java.lang.String,int) +public static java.lang.String unroll.Unrolled.foo$(unroll.Unrolled,java.lang.String,int,boolean) +public static java.lang.String unroll.Unrolled.foo$(unroll.Unrolled,java.lang.String,int,boolean,long) +public static long unroll.Unrolled.foo$default$4$(unroll.Unrolled) +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala index 88b0e2255741..ca6ed3e78262 100644 --- a/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -24,7 +24,7 @@ object UnrollTestPlatformSpecificV3{ "hello2false3" ) - cls.getMethods.filter(_.getName.contains("foo")).foreach(println) + cls.getMethods.filter(_.getName.contains("foo")).map(_.toString).sorted.foreach(println) } } diff --git a/tests/run/unroll-traitMethod/Test_2.scala b/tests/run/unroll-traitMethod/Test_2.scala deleted file mode 100644 index 48d2acef560e..000000000000 --- a/tests/run/unroll-traitMethod/Test_2.scala +++ /dev/null @@ -1,6 +0,0 @@ -//> using options -experimental - -@main def Test = - - // ensure that impl.foo isn't `Invisible`, so can be resolved from TASTy - assert(UnrolledImpl.impl.foo("foo") == "foo1true") diff --git a/tests/run/unroll-traitMethod/Unrolled_1.scala b/tests/run/unroll-traitMethod/Unrolled_1.scala deleted file mode 100644 index fa4c78708f4b..000000000000 --- a/tests/run/unroll-traitMethod/Unrolled_1.scala +++ /dev/null @@ -1,10 +0,0 @@ -//> using options -experimental -import scala.annotation.unroll - -trait Unrolled { - final def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String = s + n + b -} - -object UnrolledImpl { - val impl: Unrolled = new Unrolled {} -} diff --git a/tests/run/unroll-value-class.check b/tests/run/unroll-value-class.check new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/run/unroll-value-class/Test_4.scala b/tests/run/unroll-value-class/Test_4.scala new file mode 100644 index 000000000000..98d7ff7e3f64 --- /dev/null +++ b/tests/run/unroll-value-class/Test_4.scala @@ -0,0 +1,7 @@ +//> using options -experimental + +@main def Test: Unit = + val u = Unrolled(0) + TestV1().test(u) + TestV2().test(u) + TestV3().test(u) diff --git a/tests/run/unroll-value-class/Unrolled_1.scala b/tests/run/unroll-value-class/Unrolled_1.scala new file mode 100644 index 000000000000..86d12831b78f --- /dev/null +++ b/tests/run/unroll-value-class/Unrolled_1.scala @@ -0,0 +1,13 @@ +//> using options -experimental + +import scala.annotation.unroll + +class Unrolled(val x: Int) extends AnyVal { + final def foo( + s: String, + ): String = "" + x + s +} + +class TestV1: + def test(u: Unrolled): Unit = + assert(u.foo("foo").startsWith("0foo")) diff --git a/tests/run/unroll-value-class/Unrolled_2.scala b/tests/run/unroll-value-class/Unrolled_2.scala new file mode 100644 index 000000000000..1be3f4ee38b6 --- /dev/null +++ b/tests/run/unroll-value-class/Unrolled_2.scala @@ -0,0 +1,15 @@ +//> using options -experimental + +import scala.annotation.unroll + +class Unrolled(val x: Int) extends AnyVal { + final def foo( + s: String, + @unroll y: Boolean = true, + ): String = "" + x + s + y +} + +class TestV2: + def test(u: Unrolled): Unit = + assert(u.foo("foo").startsWith("0footrue")) + assert(u.foo("foo", false).startsWith("0foofalse")) diff --git a/tests/run/unroll-value-class/Unrolled_3.scala b/tests/run/unroll-value-class/Unrolled_3.scala new file mode 100644 index 000000000000..05e5399bbe53 --- /dev/null +++ b/tests/run/unroll-value-class/Unrolled_3.scala @@ -0,0 +1,17 @@ +//> using options -experimental + +import scala.annotation.unroll + +class Unrolled(val x: Int) extends AnyVal { + final def foo( + s: String, + @unroll y: Boolean = true, + @unroll i: Int = 0 + ): String = "" + x + s + y + i +} + +class TestV3: + def test(u: Unrolled): Unit = + assert(u.foo("foo").startsWith("0footrue0")) + assert(u.foo("foo", false).startsWith("0foofalse0")) + assert(u.foo("foo", false, 1).startsWith("0foofalse1")) From 2a04670da7a36a6343b921fe6b5a773bd2f41890 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Fri, 17 Jan 2025 01:39:23 +0100 Subject: [PATCH 5/5] Only skip reflection code on JS - add basic support for `//> using target.platform jvm|scala-js` in Vulpix. - if the directive is present, filter out files in compilation that dont match the test platform, also add a suffix to the expected check-file name. - duplicate UnrollTestPlatformSpecific files for jvm and scala-js platforms, deleting the reflection code in scala-js version. - remove directives from compilation tests not listened to by vulpix. --- compiler/test/dotty/tools/utils.scala | 41 +++++++- .../dotty/tools/vulpix/ParallelTesting.scala | 23 ++++- .../tools/dotc/ScalaJSCompilationTests.scala | 2 + tests/neg/16463.scala | 2 +- tests/neg/i19320.scala | 8 +- tests/neg/i21696.check | 6 +- tests/pos-custom-args/captures/i21347.scala | 4 +- ...=> unroll-caseclass-integration.jvm.check} | 0 ...roll-caseclass-integration.scala-js.check} | 7 -- .../unroll-caseclass-integration/Test_4.scala | 1 - .../UnrollTestPlatformSpecificJS_3.scala | 9 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- tests/run/unroll-caseclass/Test_4.scala | 13 --- tests/run/unroll-caseclass/unrolledV1_1.scala | 62 ------------ tests/run/unroll-caseclass/unrolledV2_2.scala | 56 ----------- tests/run/unroll-caseclass/unrolledV3_3.scala | 96 ------------------- ... unroll-classMethod-integration.jvm.check} | 0 ...oll-classMethod-integration.scala-js.check | 8 ++ .../Test_4.scala | 1 - .../UnrollTestPlatformSpecificJS_3.scala | 9 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- tests/run/unroll-clause-interleaving.check | 0 ...nroll-curriedMethod-integration.jvm.check} | 0 ...l-curriedMethod-integration.scala-js.check | 8 ++ .../Test_4.scala | 1 - .../UnrollTestPlatformSpecificJS_3.scala | 9 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- ...nroll-genericMethod-integration.jvm.check} | 0 ...l-genericMethod-integration.scala-js.check | 8 ++ .../Test_4.scala | 1 - .../UnrollTestPlatformSpecificJS_3.scala | 9 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- tests/run/unroll-inferredFinal.check | 0 ...-methodWithImplicit-integration.jvm.check} | 0 ...hodWithImplicit-integration.scala-js.check | 8 ++ .../Test_4.scala | 1 - .../UnrollTestPlatformSpecificJS_3.scala | 9 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- tests/run/unroll-multiple.check | 0 ...unroll-objectMethod-integration.jvm.check} | 0 ...ll-objectMethod-integration.scala-js.check | 9 ++ .../Test_4.scala | 1 - .../UnrollTestPlatformSpecificJS_3.scala | 9 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- ...-primaryConstructor-integration.jvm.check} | 0 ...maryConstructor-integration.scala-js.check | 9 ++ .../Test_4.scala | 1 - .../UnrollTestPlatformSpecificJS_3.scala | 9 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- ...secondParameterList-integration.jvm.check} | 0 ...ndParameterList-integration.scala-js.check | 8 ++ .../Test_4.scala | 1 - .../UnrollTestPlatformSpecificJS_3.scala | 9 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- ...econdaryConstructor-integration.jvm.check} | 0 ...daryConstructor-integration.scala-js.check | 9 ++ .../Test_4.scala | 1 - .../UnrollTestPlatformSpecificJS_3.scala | 9 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- ... unroll-traitMethod-integration.jvm.check} | 0 ...oll-traitMethod-integration.scala-js.check | 18 ++++ .../Test_4.scala | 1 - .../UnrollTestPlatformSpecificJS_3.scala | 9 ++ .../UnrollTestPlatformSpecific_3.scala | 2 +- tests/run/unroll-value-class.check | 0 65 files changed, 254 insertions(+), 271 deletions(-) rename tests/run/{unroll-caseclass-integration.check => unroll-caseclass-integration.jvm.check} (100%) rename tests/run/{unroll-caseclass.check => unroll-caseclass-integration.scala-js.check} (80%) create mode 100644 tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecificJS_3.scala delete mode 100644 tests/run/unroll-caseclass/Test_4.scala delete mode 100644 tests/run/unroll-caseclass/unrolledV1_1.scala delete mode 100644 tests/run/unroll-caseclass/unrolledV2_2.scala delete mode 100644 tests/run/unroll-caseclass/unrolledV3_3.scala rename tests/run/{unroll-classMethod-integration.check => unroll-classMethod-integration.jvm.check} (100%) create mode 100644 tests/run/unroll-classMethod-integration.scala-js.check create mode 100644 tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecificJS_3.scala delete mode 100644 tests/run/unroll-clause-interleaving.check rename tests/run/{unroll-curriedMethod-integration.check => unroll-curriedMethod-integration.jvm.check} (100%) create mode 100644 tests/run/unroll-curriedMethod-integration.scala-js.check create mode 100644 tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecificJS_3.scala rename tests/run/{unroll-genericMethod-integration.check => unroll-genericMethod-integration.jvm.check} (100%) create mode 100644 tests/run/unroll-genericMethod-integration.scala-js.check create mode 100644 tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecificJS_3.scala delete mode 100644 tests/run/unroll-inferredFinal.check rename tests/run/{unroll-methodWithImplicit-integration.check => unroll-methodWithImplicit-integration.jvm.check} (100%) create mode 100644 tests/run/unroll-methodWithImplicit-integration.scala-js.check create mode 100644 tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecificJS_3.scala delete mode 100644 tests/run/unroll-multiple.check rename tests/run/{unroll-objectMethod-integration.check => unroll-objectMethod-integration.jvm.check} (100%) create mode 100644 tests/run/unroll-objectMethod-integration.scala-js.check create mode 100644 tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecificJS_3.scala rename tests/run/{unroll-primaryConstructor-integration.check => unroll-primaryConstructor-integration.jvm.check} (100%) create mode 100644 tests/run/unroll-primaryConstructor-integration.scala-js.check create mode 100644 tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecificJS_3.scala rename tests/run/{unroll-secondParameterList-integration.check => unroll-secondParameterList-integration.jvm.check} (100%) create mode 100644 tests/run/unroll-secondParameterList-integration.scala-js.check create mode 100644 tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecificJS_3.scala rename tests/run/{unroll-secondaryConstructor-integration.check => unroll-secondaryConstructor-integration.jvm.check} (100%) create mode 100644 tests/run/unroll-secondaryConstructor-integration.scala-js.check create mode 100644 tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecificJS_3.scala rename tests/run/{unroll-traitMethod-integration.check => unroll-traitMethod-integration.jvm.check} (100%) create mode 100644 tests/run/unroll-traitMethod-integration.scala-js.check create mode 100644 tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecificJS_3.scala delete mode 100644 tests/run/unroll-value-class.check diff --git a/compiler/test/dotty/tools/utils.scala b/compiler/test/dotty/tools/utils.scala index d17edbaa855e..a5ebf0d59ec0 100644 --- a/compiler/test/dotty/tools/utils.scala +++ b/compiler/test/dotty/tools/utils.scala @@ -57,25 +57,54 @@ def assertThrows[T <: Throwable: ClassTag](p: T => Boolean)(body: => Any): Unit case NonFatal(other) => throw AssertionError(s"Wrong exception: expected ${implicitly[ClassTag[T]]} but was ${other.getClass.getName}").tap(_.addSuppressed(other)) end assertThrows +enum TestPlatform: + case JVM, ScalaJS + override def toString: String = this match + case JVM => "jvm" + case ScalaJS => "scala-js" + +object TestPlatform: + def named(s: String): TestPlatform = s match + case "jvm" => TestPlatform.JVM + case "scala-js" => TestPlatform.ScalaJS + case _ => throw IllegalArgumentException(s) + /** Famous tool names in the ecosystem. Used for tool args in test files. */ enum ToolName: - case Scala, Scalac, Java, Javac, ScalaJS, Test + case Scala, Scalac, Java, Javac, ScalaJS, Test, Target object ToolName: def named(s: String): ToolName = values.find(_.toString.equalsIgnoreCase(s)).getOrElse(throw IllegalArgumentException(s)) type ToolArgs = Map[ToolName, List[String]] +type PlatformFiles = Map[TestPlatform, List[String]] /** Take a prefix of each file, extract tool args, parse, and combine. * Arg parsing respects quotation marks. Result is a map from ToolName to the combined tokens. */ def toolArgsFor(files: List[JPath], charset: Charset = UTF_8): ToolArgs = - files.foldLeft(Map.empty[ToolName, List[String]]) { (res, path) => + val (_, toolArgs) = platformAndToolArgsFor(files, charset) + toolArgs + +/** Take a prefix of each file, extract tool args, parse, and combine. + * Arg parsing respects quotation marks. Result is a map from ToolName to the combined tokens. + * If the ToolName is Target, then also accumulate the file name associated with the given platform. + */ +def platformAndToolArgsFor(files: List[JPath], charset: Charset = UTF_8): (PlatformFiles, ToolArgs) = + files.foldLeft(Map.empty[TestPlatform, List[String]] -> Map.empty[ToolName, List[String]]) { (res, path) => val toolargs = toolArgsParse(resource(Files.lines(path, charset))(_.limit(10).toScala(List)), Some(path.toString)) toolargs.foldLeft(res) { - case (acc, (tool, args)) => + case ((plat, acc), (tool, args)) => val name = ToolName.named(tool) val tokens = CommandLineParser.tokenize(args) - acc.updatedWith(name)(v0 => v0.map(_ ++ tokens).orElse(Some(tokens))) + + val plat1 = if name eq ToolName.Target then + val testPlatform = TestPlatform.named(tokens.head) + val fileName = path.toString + plat.updatedWith(testPlatform)(_.map(fileName :: _).orElse(Some(fileName :: Nil))) + else + plat + + plat1 -> acc.updatedWith(name)(v0 => v0.map(_ ++ tokens).orElse(Some(tokens))) } } @@ -94,6 +123,8 @@ private val toolArg = raw"(?://|/\*| \*) ?(?i:(${ToolName.values.mkString("|")}) /** Directive to specify to vulpix the options to pass to Dotty */ private val directiveOptionsArg = raw"//> using options (.*)".r.unanchored private val directiveJavacOptions = raw"//> using javacOpt (.*)".r.unanchored +private val directiveTargetOptions = raw"//> using target.platform (jvm|scala-js)".r.unanchored +private val directiveUnknown = raw"//> using (.*)".r.unanchored // Inspect the lines for compiler options of the form // `//> using options args`, `// scalajs: args`, `/* scalajs: args`, ` * scalajs: args` etc. @@ -109,6 +140,8 @@ def toolArgsParse(lines: List[String], filename: Option[String]): List[(String,S lines.flatMap { case directiveOptionsArg(args) => List(("scalac", args)) case directiveJavacOptions(args) => List(("javac", args)) + case directiveTargetOptions(platform) => List(("target", platform)) + case directiveUnknown(rest) => sys.error(s"Unknown directive: `//> using ${CommandLineParser.tokenize(rest).headOption.getOrElse("''")}`${filename.fold("")(f => s" in file $f")}") case _ => Nil } diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 7827b94e165a..9a02cd17f5bd 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -60,6 +60,8 @@ trait ParallelTesting extends RunnerOrchestration { self => /** Contains a list of failed tests to run, if list is empty no tests will run */ def failedTests: Option[List[String]] + protected def testPlatform: TestPlatform = TestPlatform.JVM + /** A test source whose files or directory of files is to be compiled * in a specific way defined by the `Test` */ @@ -343,7 +345,11 @@ trait ParallelTesting extends RunnerOrchestration { self => new JFile(f.getPath.replaceFirst("\\.(scala|java)$", ".check")) } case ts: SeparateCompilationSource => - Option(new JFile(ts.dir.getPath + ".check")) + val platform = + if testSource.allToolArgs.getOrElse(ToolName.Target, Nil).nonEmpty then + s".$testPlatform" + else "" + Option(new JFile(ts.dir.getPath + platform + ".check")) } } @@ -499,7 +505,8 @@ trait ParallelTesting extends RunnerOrchestration { self => val files: Array[JFile] = files0.flatMap(flattenFiles) - val toolArgs = toolArgsFor(files.toList.map(_.toPath), getCharsetFromEncodingOpt(flags0)) + val (platformFiles, toolArgs) = + platformAndToolArgsFor(files.toList.map(_.toPath), getCharsetFromEncodingOpt(flags0)) val spec = raw"(\d+)(\+)?".r val testIsFiltered = toolArgs.get(ToolName.Test) match @@ -557,7 +564,17 @@ trait ParallelTesting extends RunnerOrchestration { self => // If a test contains a Java file that cannot be parsed by Dotty's Java source parser, its // name must contain the string "JAVA_ONLY". val dottyFiles = files.filterNot(_.getName.contains("JAVA_ONLY")).map(_.getPath) - driver.process(allArgs ++ dottyFiles, reporter = reporter) + + val dottyFiles0 = + if platformFiles.isEmpty then dottyFiles + else + val excludedFiles = platformFiles + .collect { case (plat, files) if plat != testPlatform => files } + .flatten + .toSet + dottyFiles.filterNot(excludedFiles) + + driver.process(allArgs ++ dottyFiles0, reporter = reporter) // todo a better mechanism than ONLY. test: -scala-only? val javaFiles = files.filter(_.getName.endsWith(".java")).filterNot(_.getName.contains("SCALA_ONLY")).map(_.getPath) diff --git a/sjs-compiler-tests/test/scala/dotty/tools/dotc/ScalaJSCompilationTests.scala b/sjs-compiler-tests/test/scala/dotty/tools/dotc/ScalaJSCompilationTests.scala index 0f4eb633b770..0e5bd20d5c06 100644 --- a/sjs-compiler-tests/test/scala/dotty/tools/dotc/ScalaJSCompilationTests.scala +++ b/sjs-compiler-tests/test/scala/dotty/tools/dotc/ScalaJSCompilationTests.scala @@ -40,6 +40,8 @@ class ScalaJSCompilationTests extends ParallelTesting { override protected def shouldSkipTestSource(testSource: TestSource): Boolean = testSource.allToolArgs.get(ToolName.ScalaJS).exists(_.contains("--skip")) + override protected def testPlatform: TestPlatform = TestPlatform.ScalaJS + override def runMain(classPath: String, toolArgs: ToolArgs)(implicit summaryReport: SummaryReporting): Status = import scala.concurrent.ExecutionContext.Implicits.global diff --git a/tests/neg/16463.scala b/tests/neg/16463.scala index 80a84cf02bc8..6011678552b7 100644 --- a/tests/neg/16463.scala +++ b/tests/neg/16463.scala @@ -1,4 +1,4 @@ -//> using scala "3.2.1" +//!> using scala "3.2.1" import scala.compiletime.ops.int._ diff --git a/tests/neg/i19320.scala b/tests/neg/i19320.scala index e802215a1f10..3597f02cf431 100644 --- a/tests/neg/i19320.scala +++ b/tests/neg/i19320.scala @@ -1,7 +1,7 @@ -//> using scala "3.3.1" -//> using dep org.http4s::http4s-ember-client:1.0.0-M40 -//> using dep org.http4s::http4s-ember-server:1.0.0-M40 -//> using dep org.http4s::http4s-dsl:1.0.0-M40 +//!> using scala "3.3.1" +//!> using dep org.http4s::http4s-ember-client:1.0.0-M40 +//!> using dep org.http4s::http4s-ember-server:1.0.0-M40 +//!> using dep org.http4s::http4s-dsl:1.0.0-M40 //import cats.effect.* //import cats.implicits.* diff --git a/tests/neg/i21696.check b/tests/neg/i21696.check index 9195263040b3..ce4844782107 100644 --- a/tests/neg/i21696.check +++ b/tests/neg/i21696.check @@ -5,9 +5,9 @@ |--------------------------------------------------------------------------------------------------------------------- | Explanation (enabled by `-explain`) |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | Referencing `T` inside a quoted expression requires a `scala.quoted.Type[T]` to be in scope. + | Referencing `T` inside a quoted expression requires a `scala.quoted.Type[T]` to be in scope. | Since Scala is subject to erasure at runtime, the type information will be missing during the execution of the code. - | `scala.quoted.Type[T]` is therefore needed to carry `T`'s type information into the quoted code. - | Without an implicit `scala.quoted.Type[T]`, the type `T` cannot be properly referenced within the expression. + | `scala.quoted.Type[T]` is therefore needed to carry `T`'s type information into the quoted code. + | Without an implicit `scala.quoted.Type[T]`, the type `T` cannot be properly referenced within the expression. | To resolve this, ensure that a `scala.quoted.Type[T]` is available, either through a context-bound or explicitly. --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/pos-custom-args/captures/i21347.scala b/tests/pos-custom-args/captures/i21347.scala index e74c15bff8c1..a965b7e4f26b 100644 --- a/tests/pos-custom-args/captures/i21347.scala +++ b/tests/pos-custom-args/captures/i21347.scala @@ -1,4 +1,4 @@ -//> using scala 3.6.0-RC1-bin-SNAPSHOT +//!> using scala 3.6.0-RC1-bin-SNAPSHOT import language.experimental.captureChecking @@ -8,4 +8,4 @@ def run[Cap^](f: Box[Cap]^{Cap^} => Unit): Box[Cap]^{Cap^} = ??? def main() = val b = run(_ => ()) - // val b = run[caps.CapSet](_ => ()) // this compiles \ No newline at end of file + // val b = run[caps.CapSet](_ => ()) // this compiles diff --git a/tests/run/unroll-caseclass-integration.check b/tests/run/unroll-caseclass-integration.jvm.check similarity index 100% rename from tests/run/unroll-caseclass-integration.check rename to tests/run/unroll-caseclass-integration.jvm.check diff --git a/tests/run/unroll-caseclass.check b/tests/run/unroll-caseclass-integration.scala-js.check similarity index 80% rename from tests/run/unroll-caseclass.check rename to tests/run/unroll-caseclass-integration.scala-js.check index ad59ed9b4dde..dbd2d93b08dd 100644 --- a/tests/run/unroll-caseclass.check +++ b/tests/run/unroll-caseclass-integration.scala-js.check @@ -1,4 +1,3 @@ -=== Unrolled Test V1 === Assertion passed: found "cow1" + "true0" Assertion passed: found "cow2" + "true0" Assertion passed: found "cow1" + "true0" @@ -6,7 +5,6 @@ Assertion passed: found "cow2" + "true0" Assertion passed: found "cow1" + "true0" Assertion passed: found "cow2" + "true0" Assertion passed: found "hello31337" + "true0" -=== Unrolled Test V2 === Assertion passed: found "cow1true" + "0" Assertion passed: found "cow2true" + "0" Assertion passed: found "cow2false" + "0" @@ -17,12 +15,7 @@ Assertion passed: found "cow1true" + "0" Assertion passed: found "cow2true" + "0" Assertion passed: found "cow2false" + "0" Assertion passed: found "hello31337false" + "0" -=== Unrolled Test V3 === Assertion passed: found "hello31337false12345" -as expected, no constructor for Unrolled(s: String) -public example.Unrolled(java.lang.String,int) -public example.Unrolled(java.lang.String,int,boolean) -public example.Unrolled(java.lang.String,int,boolean,long) Assertion passed: found "cow1true0" Assertion passed: found "cow2true0" Assertion passed: found "cow2false0" diff --git a/tests/run/unroll-caseclass-integration/Test_4.scala b/tests/run/unroll-caseclass-integration/Test_4.scala index cae956f8b1bf..dc60b5bf2059 100644 --- a/tests/run/unroll-caseclass-integration/Test_4.scala +++ b/tests/run/unroll-caseclass-integration/Test_4.scala @@ -1,5 +1,4 @@ //> using options -experimental -// scalajs: --skip import unroll.* @main def Test: Unit = diff --git a/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecificJS_3.scala b/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecificJS_3.scala new file mode 100644 index 000000000000..190890788014 --- /dev/null +++ b/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecificJS_3.scala @@ -0,0 +1,9 @@ +//> using options -experimental +//> using target.platform scala-js +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + // do nothing for scala-js + } +} diff --git a/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala index 7a8021b304da..0ec252f740f4 100644 --- a/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-caseclass-integration/UnrollTestPlatformSpecific_3.scala @@ -1,5 +1,5 @@ //> using options -experimental -// scalajs: --skip +//> using target.platform jvm package unroll object UnrollTestPlatformSpecificV3{ diff --git a/tests/run/unroll-caseclass/Test_4.scala b/tests/run/unroll-caseclass/Test_4.scala deleted file mode 100644 index 8b6b72f79cf7..000000000000 --- a/tests/run/unroll-caseclass/Test_4.scala +++ /dev/null @@ -1,13 +0,0 @@ -//> using options -experimental -// scalajs: --skip - -import example.* -// !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check -@main def Test(): Unit = { - println("=== Unrolled Test V1 ===") - UnrollTestMainV1.main(Array.empty) - println("=== Unrolled Test V2 ===") - UnrollTestMainV2.main(Array.empty) - println("=== Unrolled Test V3 ===") - UnrollTestMainV3.main(Array.empty) -} diff --git a/tests/run/unroll-caseclass/unrolledV1_1.scala b/tests/run/unroll-caseclass/unrolledV1_1.scala deleted file mode 100644 index 639a994e7e36..000000000000 --- a/tests/run/unroll-caseclass/unrolledV1_1.scala +++ /dev/null @@ -1,62 +0,0 @@ -//> using options -experimental -// scalajs: --skip -package example -// !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check - -// import scala.annotation.unroll <- v1 did not need to unroll yet - -// v1 of Unrolled -case class Unrolled(s: String, n: Int = 1) { - def foo = s + n -} - -// v1: original code that compiled against v1 of Unrolled -object UnrollTestMainV1 extends TestUtil { - def main(args: Array[String]): Unit = { - logAssertStartsWith(new Unrolled("cow").foo, "cow1") - logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2") - - logAssertStartsWith(Unrolled("cow").foo, "cow1") - logAssertStartsWith(Unrolled("cow", 2).foo, "cow2") - - val unrolled = Unrolled("cow") - - logAssertStartsWith(unrolled.copy(s = "cow").foo, "cow1") - logAssertStartsWith(unrolled.copy(s = "cow", n = 2).foo, "cow2") - - val Unrolled(s, n) = unrolled - - assert(s == "cow") - assert(n == 1) - - UnrollTestScalaSpecificV1.test() - } -} - -object UnrollTestScalaSpecificV1 extends TestUtil { - def test() = { - val unrolled = summon[scala.deriving.Mirror.Of[Unrolled]].fromProduct( - new Product{ - def canEqual(that: Any) = true - def productArity = 2 - def productElement(n: Int) = n match{ - case 0 => "hello" - case 1 => 31337 - } - } - ) - - logAssertStartsWith(unrolled.foo, "hello31337") - } -} - -trait TestUtil { - def logAssertStartsWith(actual: String, expected: String): Unit = { - assert(actual.startsWith(expected)) - val suffix = { - val suffix0 = actual.stripPrefix(expected) - if (suffix0.isEmpty) "" else s""" + "$suffix0"""" - } - println(s"""Assertion passed: found "$expected"$suffix""") - } -} diff --git a/tests/run/unroll-caseclass/unrolledV2_2.scala b/tests/run/unroll-caseclass/unrolledV2_2.scala deleted file mode 100644 index 7833c0eb6892..000000000000 --- a/tests/run/unroll-caseclass/unrolledV2_2.scala +++ /dev/null @@ -1,56 +0,0 @@ -//> using options -experimental -// scalajs: --skip -package example -// !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check - -import scala.annotation.unroll - -// v2 of Unrolled -case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true){ - def foo = s + n + b -} - -// v2: ammendments to code that exercise a new parameter -object UnrollTestMainV2 extends TestUtil { - def main(args: Array[String]): Unit = { - logAssertStartsWith(new Unrolled("cow").foo, "cow1true") - logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2true") - logAssertStartsWith(new Unrolled("cow", 2, false).foo, "cow2false") - - logAssertStartsWith(Unrolled("cow").foo, "cow1true") - logAssertStartsWith(Unrolled("cow", 2).foo, "cow2true") - logAssertStartsWith(Unrolled("cow", 2, false).foo, "cow2false") - - val unrolled = Unrolled("cow") - - logAssertStartsWith(unrolled.copy(s = "cow").foo, "cow1true") - logAssertStartsWith(unrolled.copy(s = "cow", n = 2).foo, "cow2true") - logAssertStartsWith(unrolled.copy(s = "cow", n = 2, b = false).foo, "cow2false") - - val Unrolled(s, n, b) = unrolled - - assert(s == "cow") - assert(n == 1) - assert(b == true) - - UnrollTestScalaSpecificV2.test() - } -} - -object UnrollTestScalaSpecificV2 extends TestUtil { - def test() = { - val unrolled = summon[scala.deriving.Mirror.Of[Unrolled]].fromProduct( - new Product { - def canEqual(that: Any) = true - def productArity = 3 - def productElement(n: Int) = n match { - case 0 => "hello" - case 1 => 31337 - case 2 => false - } - } - - ) - logAssertStartsWith(unrolled.foo, "hello31337false") - } -} diff --git a/tests/run/unroll-caseclass/unrolledV3_3.scala b/tests/run/unroll-caseclass/unrolledV3_3.scala deleted file mode 100644 index 24f8b59ac78e..000000000000 --- a/tests/run/unroll-caseclass/unrolledV3_3.scala +++ /dev/null @@ -1,96 +0,0 @@ -//> using options -experimental -// scalajs: --skip -package example -// !! IMPORTANT: If you remove this test, also remove unroll-caseclass.check - -import scala.annotation.unroll - -// v3 of Unrolled -case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0){ - def foo = s + n + b + l -} - -// v3: ammendments to code that exercise a new parameter -object UnrollTestMainV3 extends TestUtil { - def main(args: Array[String]): Unit = { - UnrollTestScalaSpecificV3() - UnrollTestPlatformSpecificV3() - - logAssertStartsWith(new Unrolled("cow").foo, "cow1true0") - logAssertStartsWith(new Unrolled("cow", 2).foo, "cow2true0") - logAssertStartsWith(new Unrolled("cow", 2, false).foo, "cow2false0") - logAssertStartsWith(new Unrolled("cow", 2, false, 9L).foo, "cow2false9") - - logAssertStartsWith(Unrolled("cow").foo, "cow1true0") - logAssertStartsWith(Unrolled("cow", 2).foo, "cow2true0") - logAssertStartsWith(Unrolled("cow", 2, false).foo, "cow2false0") - logAssertStartsWith(Unrolled("cow", 2, false, 9L).foo, "cow2false9") - - val unrolled = Unrolled("cow") - - logAssertStartsWith(unrolled.copy(s = "cow").foo, "cow1true0") - logAssertStartsWith(unrolled.copy(s = "cow", n = 2).foo, "cow2true0") - logAssertStartsWith(unrolled.copy(s = "cow", n = 2, b = false).foo, "cow2false0") - logAssertStartsWith(unrolled.copy(s = "cow", n = 2, b = false, l = 9L).foo, "cow2false9") - - val Unrolled(s, n, b, l) = unrolled - - assert(s == "cow") - assert(n == 1) - assert(b == true) - assert(l == 0L) - - - } -} - -object UnrollTestScalaSpecificV3 extends TestUtil { - def apply() = { - val unrolled = summon[scala.deriving.Mirror.Of[Unrolled]].fromProduct( - new Product { - def canEqual(that: Any) = true - def productArity = 4 - def productElement(n: Int) = n match { - case 0 => "hello" - case 1 => 31337 - case 2 => false - case 3 => 12345L - } - } - ) - - logAssertStartsWith(unrolled.foo, "hello31337false12345") - } -} - -object UnrollTestPlatformSpecificV3 extends TestUtil { - def apply() = { - val cls = classOf[Unrolled] - - assert(scala.util.Try(cls.getConstructor(classOf[String])).isFailure) - println("as expected, no constructor for Unrolled(s: String)") - assert( - cls.getConstructor(classOf[String], classOf[Int]) - .newInstance("hello", 2: Integer) - .asInstanceOf[Unrolled] - .foo == - "hello2true0" - ) - assert( - cls.getConstructor(classOf[String], classOf[Int], classOf[Boolean]) - .newInstance("hello", 2: Integer, java.lang.Boolean.FALSE) - .asInstanceOf[Unrolled] - .foo == - "hello2false0" - ) - assert( - cls.getConstructor(classOf[String], classOf[Int], classOf[Boolean], classOf[Long]) - .newInstance("hello", 2: Integer, java.lang.Boolean.FALSE, 3: Integer) - .asInstanceOf[Unrolled] - .foo == - "hello2false3" - ) - - cls.getConstructors.sortBy(_.getParameterCount()).foreach(println) - } -} diff --git a/tests/run/unroll-classMethod-integration.check b/tests/run/unroll-classMethod-integration.jvm.check similarity index 100% rename from tests/run/unroll-classMethod-integration.check rename to tests/run/unroll-classMethod-integration.jvm.check diff --git a/tests/run/unroll-classMethod-integration.scala-js.check b/tests/run/unroll-classMethod-integration.scala-js.check new file mode 100644 index 000000000000..001534a32889 --- /dev/null +++ b/tests/run/unroll-classMethod-integration.scala-js.check @@ -0,0 +1,8 @@ +Assertion passed: found "cow" + "1true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-classMethod-integration/Test_4.scala b/tests/run/unroll-classMethod-integration/Test_4.scala index cae956f8b1bf..dc60b5bf2059 100644 --- a/tests/run/unroll-classMethod-integration/Test_4.scala +++ b/tests/run/unroll-classMethod-integration/Test_4.scala @@ -1,5 +1,4 @@ //> using options -experimental -// scalajs: --skip import unroll.* @main def Test: Unit = diff --git a/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecificJS_3.scala b/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecificJS_3.scala new file mode 100644 index 000000000000..190890788014 --- /dev/null +++ b/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecificJS_3.scala @@ -0,0 +1,9 @@ +//> using options -experimental +//> using target.platform scala-js +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + // do nothing for scala-js + } +} diff --git a/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala index f68cc60c3139..decffbaf3c74 100644 --- a/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-classMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -1,5 +1,5 @@ //> using options -experimental -// scalajs: --skip +//> using target.platform jvm package unroll object UnrollTestPlatformSpecificV3{ diff --git a/tests/run/unroll-clause-interleaving.check b/tests/run/unroll-clause-interleaving.check deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/run/unroll-curriedMethod-integration.check b/tests/run/unroll-curriedMethod-integration.jvm.check similarity index 100% rename from tests/run/unroll-curriedMethod-integration.check rename to tests/run/unroll-curriedMethod-integration.jvm.check diff --git a/tests/run/unroll-curriedMethod-integration.scala-js.check b/tests/run/unroll-curriedMethod-integration.scala-js.check new file mode 100644 index 000000000000..001534a32889 --- /dev/null +++ b/tests/run/unroll-curriedMethod-integration.scala-js.check @@ -0,0 +1,8 @@ +Assertion passed: found "cow" + "1true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-curriedMethod-integration/Test_4.scala b/tests/run/unroll-curriedMethod-integration/Test_4.scala index cae956f8b1bf..dc60b5bf2059 100644 --- a/tests/run/unroll-curriedMethod-integration/Test_4.scala +++ b/tests/run/unroll-curriedMethod-integration/Test_4.scala @@ -1,5 +1,4 @@ //> using options -experimental -// scalajs: --skip import unroll.* @main def Test: Unit = diff --git a/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecificJS_3.scala b/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecificJS_3.scala new file mode 100644 index 000000000000..190890788014 --- /dev/null +++ b/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecificJS_3.scala @@ -0,0 +1,9 @@ +//> using options -experimental +//> using target.platform scala-js +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + // do nothing for scala-js + } +} diff --git a/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala index ac4ad5f22d1e..24ca27b644a1 100644 --- a/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-curriedMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -1,5 +1,5 @@ //> using options -experimental -// scalajs: --skip +//> using target.platform jvm package unroll object UnrollTestPlatformSpecificV3{ diff --git a/tests/run/unroll-genericMethod-integration.check b/tests/run/unroll-genericMethod-integration.jvm.check similarity index 100% rename from tests/run/unroll-genericMethod-integration.check rename to tests/run/unroll-genericMethod-integration.jvm.check diff --git a/tests/run/unroll-genericMethod-integration.scala-js.check b/tests/run/unroll-genericMethod-integration.scala-js.check new file mode 100644 index 000000000000..001534a32889 --- /dev/null +++ b/tests/run/unroll-genericMethod-integration.scala-js.check @@ -0,0 +1,8 @@ +Assertion passed: found "cow" + "1true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-genericMethod-integration/Test_4.scala b/tests/run/unroll-genericMethod-integration/Test_4.scala index cae956f8b1bf..dc60b5bf2059 100644 --- a/tests/run/unroll-genericMethod-integration/Test_4.scala +++ b/tests/run/unroll-genericMethod-integration/Test_4.scala @@ -1,5 +1,4 @@ //> using options -experimental -// scalajs: --skip import unroll.* @main def Test: Unit = diff --git a/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecificJS_3.scala b/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecificJS_3.scala new file mode 100644 index 000000000000..190890788014 --- /dev/null +++ b/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecificJS_3.scala @@ -0,0 +1,9 @@ +//> using options -experimental +//> using target.platform scala-js +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + // do nothing for scala-js + } +} diff --git a/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala index f39864bee0fd..2ef19e0f378e 100644 --- a/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-genericMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -1,5 +1,5 @@ //> using options -experimental -// scalajs: --skip +//> using target.platform jvm package unroll object UnrollTestPlatformSpecificV3{ diff --git a/tests/run/unroll-inferredFinal.check b/tests/run/unroll-inferredFinal.check deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/run/unroll-methodWithImplicit-integration.check b/tests/run/unroll-methodWithImplicit-integration.jvm.check similarity index 100% rename from tests/run/unroll-methodWithImplicit-integration.check rename to tests/run/unroll-methodWithImplicit-integration.jvm.check diff --git a/tests/run/unroll-methodWithImplicit-integration.scala-js.check b/tests/run/unroll-methodWithImplicit-integration.scala-js.check new file mode 100644 index 000000000000..001534a32889 --- /dev/null +++ b/tests/run/unroll-methodWithImplicit-integration.scala-js.check @@ -0,0 +1,8 @@ +Assertion passed: found "cow" + "1true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-methodWithImplicit-integration/Test_4.scala b/tests/run/unroll-methodWithImplicit-integration/Test_4.scala index cae956f8b1bf..dc60b5bf2059 100644 --- a/tests/run/unroll-methodWithImplicit-integration/Test_4.scala +++ b/tests/run/unroll-methodWithImplicit-integration/Test_4.scala @@ -1,5 +1,4 @@ //> using options -experimental -// scalajs: --skip import unroll.* @main def Test: Unit = diff --git a/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecificJS_3.scala b/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecificJS_3.scala new file mode 100644 index 000000000000..190890788014 --- /dev/null +++ b/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecificJS_3.scala @@ -0,0 +1,9 @@ +//> using options -experimental +//> using target.platform scala-js +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + // do nothing for scala-js + } +} diff --git a/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala index 399b18583c23..86cd5514cfd5 100644 --- a/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-methodWithImplicit-integration/UnrollTestPlatformSpecific_3.scala @@ -1,5 +1,5 @@ //> using options -experimental -// scalajs: --skip +//> using target.platform jvm package unroll object UnrollTestPlatformSpecificV3{ diff --git a/tests/run/unroll-multiple.check b/tests/run/unroll-multiple.check deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/run/unroll-objectMethod-integration.check b/tests/run/unroll-objectMethod-integration.jvm.check similarity index 100% rename from tests/run/unroll-objectMethod-integration.check rename to tests/run/unroll-objectMethod-integration.jvm.check diff --git a/tests/run/unroll-objectMethod-integration.scala-js.check b/tests/run/unroll-objectMethod-integration.scala-js.check new file mode 100644 index 000000000000..248ef79ed88a --- /dev/null +++ b/tests/run/unroll-objectMethod-integration.scala-js.check @@ -0,0 +1,9 @@ +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-objectMethod-integration/Test_4.scala b/tests/run/unroll-objectMethod-integration/Test_4.scala index cae956f8b1bf..dc60b5bf2059 100644 --- a/tests/run/unroll-objectMethod-integration/Test_4.scala +++ b/tests/run/unroll-objectMethod-integration/Test_4.scala @@ -1,5 +1,4 @@ //> using options -experimental -// scalajs: --skip import unroll.* @main def Test: Unit = diff --git a/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecificJS_3.scala b/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecificJS_3.scala new file mode 100644 index 000000000000..190890788014 --- /dev/null +++ b/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecificJS_3.scala @@ -0,0 +1,9 @@ +//> using options -experimental +//> using target.platform scala-js +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + // do nothing for scala-js + } +} diff --git a/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala index 31cd0db29aca..61450765623a 100644 --- a/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-objectMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -1,5 +1,5 @@ //> using options -experimental -// scalajs: --skip +//> using target.platform jvm package unroll object UnrollTestPlatformSpecificV3{ diff --git a/tests/run/unroll-primaryConstructor-integration.check b/tests/run/unroll-primaryConstructor-integration.jvm.check similarity index 100% rename from tests/run/unroll-primaryConstructor-integration.check rename to tests/run/unroll-primaryConstructor-integration.jvm.check diff --git a/tests/run/unroll-primaryConstructor-integration.scala-js.check b/tests/run/unroll-primaryConstructor-integration.scala-js.check new file mode 100644 index 000000000000..248ef79ed88a --- /dev/null +++ b/tests/run/unroll-primaryConstructor-integration.scala-js.check @@ -0,0 +1,9 @@ +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-primaryConstructor-integration/Test_4.scala b/tests/run/unroll-primaryConstructor-integration/Test_4.scala index cae956f8b1bf..dc60b5bf2059 100644 --- a/tests/run/unroll-primaryConstructor-integration/Test_4.scala +++ b/tests/run/unroll-primaryConstructor-integration/Test_4.scala @@ -1,5 +1,4 @@ //> using options -experimental -// scalajs: --skip import unroll.* @main def Test: Unit = diff --git a/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecificJS_3.scala b/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecificJS_3.scala new file mode 100644 index 000000000000..190890788014 --- /dev/null +++ b/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecificJS_3.scala @@ -0,0 +1,9 @@ +//> using options -experimental +//> using target.platform scala-js +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + // do nothing for scala-js + } +} diff --git a/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala index 7a8021b304da..0ec252f740f4 100644 --- a/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-primaryConstructor-integration/UnrollTestPlatformSpecific_3.scala @@ -1,5 +1,5 @@ //> using options -experimental -// scalajs: --skip +//> using target.platform jvm package unroll object UnrollTestPlatformSpecificV3{ diff --git a/tests/run/unroll-secondParameterList-integration.check b/tests/run/unroll-secondParameterList-integration.jvm.check similarity index 100% rename from tests/run/unroll-secondParameterList-integration.check rename to tests/run/unroll-secondParameterList-integration.jvm.check diff --git a/tests/run/unroll-secondParameterList-integration.scala-js.check b/tests/run/unroll-secondParameterList-integration.scala-js.check new file mode 100644 index 000000000000..001534a32889 --- /dev/null +++ b/tests/run/unroll-secondParameterList-integration.scala-js.check @@ -0,0 +1,8 @@ +Assertion passed: found "cow" + "1true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-secondParameterList-integration/Test_4.scala b/tests/run/unroll-secondParameterList-integration/Test_4.scala index cae956f8b1bf..dc60b5bf2059 100644 --- a/tests/run/unroll-secondParameterList-integration/Test_4.scala +++ b/tests/run/unroll-secondParameterList-integration/Test_4.scala @@ -1,5 +1,4 @@ //> using options -experimental -// scalajs: --skip import unroll.* @main def Test: Unit = diff --git a/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecificJS_3.scala b/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecificJS_3.scala new file mode 100644 index 000000000000..190890788014 --- /dev/null +++ b/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecificJS_3.scala @@ -0,0 +1,9 @@ +//> using options -experimental +//> using target.platform scala-js +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + // do nothing for scala-js + } +} diff --git a/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala index fad69270bbd1..a3cb5b7a8f0c 100644 --- a/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-secondParameterList-integration/UnrollTestPlatformSpecific_3.scala @@ -1,5 +1,5 @@ //> using options -experimental -// scalajs: --skip +//> using target.platform jvm package unroll object UnrollTestPlatformSpecificV3{ diff --git a/tests/run/unroll-secondaryConstructor-integration.check b/tests/run/unroll-secondaryConstructor-integration.jvm.check similarity index 100% rename from tests/run/unroll-secondaryConstructor-integration.check rename to tests/run/unroll-secondaryConstructor-integration.jvm.check diff --git a/tests/run/unroll-secondaryConstructor-integration.scala-js.check b/tests/run/unroll-secondaryConstructor-integration.scala-js.check new file mode 100644 index 000000000000..248ef79ed88a --- /dev/null +++ b/tests/run/unroll-secondaryConstructor-integration.scala-js.check @@ -0,0 +1,9 @@ +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-secondaryConstructor-integration/Test_4.scala b/tests/run/unroll-secondaryConstructor-integration/Test_4.scala index cae956f8b1bf..dc60b5bf2059 100644 --- a/tests/run/unroll-secondaryConstructor-integration/Test_4.scala +++ b/tests/run/unroll-secondaryConstructor-integration/Test_4.scala @@ -1,5 +1,4 @@ //> using options -experimental -// scalajs: --skip import unroll.* @main def Test: Unit = diff --git a/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecificJS_3.scala b/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecificJS_3.scala new file mode 100644 index 000000000000..190890788014 --- /dev/null +++ b/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecificJS_3.scala @@ -0,0 +1,9 @@ +//> using options -experimental +//> using target.platform scala-js +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + // do nothing for scala-js + } +} diff --git a/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala index 7a8021b304da..0ec252f740f4 100644 --- a/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-secondaryConstructor-integration/UnrollTestPlatformSpecific_3.scala @@ -1,5 +1,5 @@ //> using options -experimental -// scalajs: --skip +//> using target.platform jvm package unroll object UnrollTestPlatformSpecificV3{ diff --git a/tests/run/unroll-traitMethod-integration.check b/tests/run/unroll-traitMethod-integration.jvm.check similarity index 100% rename from tests/run/unroll-traitMethod-integration.check rename to tests/run/unroll-traitMethod-integration.jvm.check diff --git a/tests/run/unroll-traitMethod-integration.scala-js.check b/tests/run/unroll-traitMethod-integration.scala-js.check new file mode 100644 index 000000000000..1ac3ffa822f0 --- /dev/null +++ b/tests/run/unroll-traitMethod-integration.scala-js.check @@ -0,0 +1,18 @@ +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1" + "true0" +Assertion passed: found "cow2" + "true0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true" + "0" +Assertion passed: found "cow2true" + "0" +Assertion passed: found "cow2false" + "0" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" +Assertion passed: found "cow1true0" +Assertion passed: found "cow2true0" +Assertion passed: found "cow2false0" +Assertion passed: found "cow2false3" diff --git a/tests/run/unroll-traitMethod-integration/Test_4.scala b/tests/run/unroll-traitMethod-integration/Test_4.scala index cae956f8b1bf..dc60b5bf2059 100644 --- a/tests/run/unroll-traitMethod-integration/Test_4.scala +++ b/tests/run/unroll-traitMethod-integration/Test_4.scala @@ -1,5 +1,4 @@ //> using options -experimental -// scalajs: --skip import unroll.* @main def Test: Unit = diff --git a/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecificJS_3.scala b/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecificJS_3.scala new file mode 100644 index 000000000000..190890788014 --- /dev/null +++ b/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecificJS_3.scala @@ -0,0 +1,9 @@ +//> using options -experimental +//> using target.platform scala-js +package unroll + +object UnrollTestPlatformSpecificV3{ + def apply() = { + // do nothing for scala-js + } +} diff --git a/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala b/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala index ca6ed3e78262..bf004b8f656d 100644 --- a/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala +++ b/tests/run/unroll-traitMethod-integration/UnrollTestPlatformSpecific_3.scala @@ -1,5 +1,5 @@ //> using options -experimental -// scalajs: --skip +//> using target.platform jvm package unroll object UnrollTestPlatformSpecificV3{ diff --git a/tests/run/unroll-value-class.check b/tests/run/unroll-value-class.check deleted file mode 100644 index e69de29bb2d1..000000000000