diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9239020335e7..b22a44c7db7c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -782,14 +782,14 @@ jobs: uses: ./.github/workflows/build-chocolatey.yml needs: [ build-sdk-package ] with: - version: 3.3.5-local # unused - url : https://api.github.com/repos/scala/scala3/actions/artifacts/${{ needs.build-sdk-package.outputs.universal-id }}/zip - digest : ${{ needs.build-sdk-package.outputs.universal-digest }} + version: 3.3.7-SNAPSHOT # Fake version, used only for choco tests + url : https://api.github.com/repos/scala/scala3/actions/artifacts/${{ needs.build-sdk-package.outputs.win-x86_64-id }}/zip + digest : ${{ needs.build-sdk-package.outputs.win-x86_64-digest }} test-chocolatey-package: uses: ./.github/workflows/test-chocolatey.yml with: - version : 3.3.5-local # unused + version : 3.3.7-SNAPSHOT # Fake version, used only for choco tests java-version: 8 if: github.event_name == 'pull_request' && contains(github.event.pull_request.body, '[test_chocolatey]') needs: [ build-chocolatey-package ] diff --git a/.github/workflows/test-chocolatey.yml b/.github/workflows/test-chocolatey.yml index b6ca9bf74b12..e302968b9129 100644 --- a/.github/workflows/test-chocolatey.yml +++ b/.github/workflows/test-chocolatey.yml @@ -21,7 +21,10 @@ on: env: CHOCOLATEY-REPOSITORY: chocolatey-pkgs - DOTTY_CI_INSTALLATION: ${{ secrets.GITHUB_TOKEN }} + # Controls behaviour of chocolatey{Install,Uninstall}.ps1 scripts + # During snapshot releases it uses a different layout and requires access token to GH Actions artifacts + # During stable releases it uses publically available archives + DOTTY_CI_INSTALLATION: ${{ endsWith(inputs.version, '-SNAPSHOT') && secrets.GITHUB_TOKEN || '' }} jobs: test: diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 1572ed476c6c..13425d5effaa 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -2180,10 +2180,7 @@ class JSCodeGen()(using genCtx: Context) { val Apply(fun @ Select(sup @ Super(qual, _), _), args) = tree: @unchecked val sym = fun.symbol - if (sym == defn.Any_getClass) { - // The only primitive that is also callable as super call - js.GetClass(genThis()) - } else if (currentClassSym.isNonNativeJSClass) { + if (currentClassSym.isNonNativeJSClass) { genJSSuperCall(tree, isStat) } else { /* #3013 `qual` can be `this.$outer()` in some cases since Scala 2.12, diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index 092ab2eeea0d..1556b31e4ce8 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -254,7 +254,8 @@ object JavaParsers { t } - def optArrayBrackets(tpt: Tree): Tree = + def optArrayBrackets(tpt: Tree): Tree = { + annotations() if (in.token == LBRACKET) { val tpt1 = atSpan(tpt.span.start, in.offset) { arrayOf(tpt) } in.nextToken() @@ -262,6 +263,7 @@ object JavaParsers { optArrayBrackets(tpt1) } else tpt + } def basicType(): Tree = atSpan(in.offset) { @@ -335,7 +337,7 @@ object JavaParsers { } def annotations(): List[Tree] = { - var annots = new ListBuffer[Tree] + val annots = new ListBuffer[Tree] while (in.token == AT) { in.nextToken() annotation() match { diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index bf99def353b0..2757304f32e8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -274,11 +274,16 @@ object Checking { */ def checkInfo(tp: Type): Type = tp match { case tp @ TypeAlias(alias) => - tp.derivedAlias(checkPart(alias, "alias")) + val lo1 = atVariance(-1)(checkPart(alias, "alias")) + val hi1 = checkUpper(alias, "alias") + if lo1 eq hi1 then + tp.derivedAlias(lo1) + else + tp.derivedTypeBounds(lo1, hi1) case tp @ MatchAlias(alias) => - tp.derivedAlias(checkUpper(alias, "match")) + tp.derivedAlias(atVariance(0)(checkUpper(alias, "match"))) case tp @ TypeBounds(lo, hi) => - tp.derivedTypeBounds(checkPart(lo, "lower bound"), checkUpper(hi, "upper bound")) + tp.derivedTypeBounds(atVariance(-1)(checkPart(lo, "lower bound")), checkUpper(hi, "upper bound")) case _ => tp } @@ -299,12 +304,12 @@ object Checking { case tp: TermRef => this(tp.info) mapOver(tp) - case tp @ AppliedType(tycon, args) => - tp.derivedAppliedType(this(tycon), args.mapConserve(this(_, nestedCycleOK, nestedCycleOK))) case tp @ RefinedType(parent, name, rinfo) => tp.derivedRefinedType(this(parent), name, this(rinfo, nestedCycleOK, nestedCycleOK)) case tp: RecType => tp.rebind(this(tp.parent)) + case tp: LazyRef => + tp case tp @ TypeRef(pre, _) => try { // A prefix is interesting if it might contain (transitively) a reference @@ -337,14 +342,17 @@ object Checking { if isInteresting(pre) then CyclicReference.trace(i"explore ${tp.symbol} for cyclic references"): - val pre1 = this(pre, false, false) + val pre1 = atVariance(variance max 0)(this(pre, false, false)) if locked.contains(tp) || tp.symbol.infoOrCompleter.isInstanceOf[NoCompleter] + && tp.symbol == sym then throw CyclicReference(tp.symbol) locked += tp try - if tp.symbol.isOpaqueAlias then + if tp.symbol.infoOrCompleter.isInstanceOf[NoCompleter] then + ; // skip checking info (and avoid forcing the symbol with .isOpaqueAlias/etc) + else if tp.symbol.isOpaqueAlias then checkInfo(TypeAlias(tp.translucentSuperType)) else if !tp.symbol.isClass then checkInfo(tp.info) @@ -362,6 +370,16 @@ object Checking { } case _ => mapOver(tp) } + + override def mapArg(arg: Type, tparam: ParamInfo): Type = + val varianceDiff = variance != tparam.paramVarianceSign + atVariance(variance * tparam.paramVarianceSign): + // Using tests/pos/i22257.scala as an example, + // if we consider FP's lower-bound of Fixed[Node] + // than `Node` is a type argument in contravariant + // position, while the type parameter is covariant. + val nestedCycleOK1 = nestedCycleOK || variance != 0 && varianceDiff + this(arg, nestedCycleOK, nestedCycleOK1) } /** Under -Yrequire-targetName, if `sym` has an operator name, check that it has a diff --git a/sjs-compiler-tests/test/scala/dotty/tools/dotc/ScalaJSLink.scala b/sjs-compiler-tests/test/scala/dotty/tools/dotc/ScalaJSLink.scala index 54e92b1559d6..440116bdf2a2 100644 --- a/sjs-compiler-tests/test/scala/dotty/tools/dotc/ScalaJSLink.scala +++ b/sjs-compiler-tests/test/scala/dotty/tools/dotc/ScalaJSLink.scala @@ -17,6 +17,10 @@ object ScalaJSLink: Semantics.Defaults .withAsInstanceOfs(CheckedBehavior.Compliant) .withArrayIndexOutOfBounds(CheckedBehavior.Compliant) + .withArrayStores(CheckedBehavior.Compliant) + .withNegativeArraySizes(CheckedBehavior.Compliant) + .withNullPointers(CheckedBehavior.Compliant) + .withStringIndexOutOfBounds(CheckedBehavior.Compliant) .withModuleInit(CheckedBehavior.Compliant) end compliantSemantics diff --git a/tests/neg/i4368.scala b/tests/neg/i4368.scala index 95c342d5fe2a..6718aece4eba 100644 --- a/tests/neg/i4368.scala +++ b/tests/neg/i4368.scala @@ -98,7 +98,7 @@ object Test6 { object Test7 { class Fix[F[_]] { - class Foo { type R >: F[T] <: F[T] } // error: cyclic + class Foo { type R >: F[T] <: F[T] } // error type T = F[Foo#R] } @@ -149,9 +149,9 @@ object Test9 { object i4369 { trait X { self => type R <: Z - type Z >: X { type R = self.R; type Z = self.R } // error: cyclic // error: cyclic // error: cyclic + type Z >: X { type R = self.R; type Z = self.R } // error: cyclic } - class Foo extends X { type R = Foo; type Z = Foo } + class Foo extends X { type R = Foo; type Z = Foo } // error } object i4370 { class Foo { type R = A } diff --git a/tests/neg/i4369c.scala b/tests/neg/i4369c.scala index a2bfbcb598d6..06a77d51cdbe 100644 --- a/tests/neg/i4369c.scala +++ b/tests/neg/i4369c.scala @@ -1,5 +1,18 @@ trait X { self => type R <: Z - type Z >: X { type R = self.R; type Z = self.R } // error // error // error + type Z >: + X { // error + type R = // was-error + self.R + type Z = // was-error + self.R + } +} + +class Foo // error + extends X { + type R = + Foo + type Z = + Foo } -class Foo extends X { type R = Foo; type Z = Foo } diff --git a/tests/neg/toplevel-cyclic/defs_1.scala b/tests/neg/toplevel-cyclic/defs_1.scala index 34b0475066b0..f40fa5bdebdd 100644 --- a/tests/neg/toplevel-cyclic/defs_1.scala +++ b/tests/neg/toplevel-cyclic/defs_1.scala @@ -1 +1 @@ -type A = B +type A = B // error: recursion limit exceeded diff --git a/tests/neg/toplevel-cyclic/moredefs_1.scala b/tests/neg/toplevel-cyclic/moredefs_1.scala index 3c8c3de93aa7..91360d0c0f4d 100644 --- a/tests/neg/toplevel-cyclic/moredefs_1.scala +++ b/tests/neg/toplevel-cyclic/moredefs_1.scala @@ -1 +1 @@ -type B = A // error: recursion limit exceeded +type B = A diff --git a/tests/pos/i19642/Valid.java b/tests/pos/i19642/Valid.java new file mode 100644 index 000000000000..17e0e1173726 --- /dev/null +++ b/tests/pos/i19642/Valid.java @@ -0,0 +1,17 @@ +package lib; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE }) +@Retention(RUNTIME) +@Documented +public @interface Valid {} diff --git a/tests/pos/i19642/i19642.java b/tests/pos/i19642/i19642.java new file mode 100644 index 000000000000..c7d8ba9f0e72 --- /dev/null +++ b/tests/pos/i19642/i19642.java @@ -0,0 +1,9 @@ +package app; + +import java.util.Optional; +import lib.*; + +public class i19642 { + private String @lib.Valid [] flatArray; + private String @lib.Valid [] @lib.Valid [] nestedArray; +} diff --git a/tests/pos/i22257.fixed.scala b/tests/pos/i22257.fixed.scala new file mode 100644 index 000000000000..d0fa1a0e81cb --- /dev/null +++ b/tests/pos/i22257.fixed.scala @@ -0,0 +1,52 @@ + +object Scaffold { + + trait Arrow + object Arrow { + trait Outbound extends Arrow + } + + trait NodeKOrGraphK {} + + trait NodeK extends NodeKOrGraphK { + + type FBound <: Induction + + protected def getInduction: Seq[FBound] + } + + trait Induction { + def arrow: Arrow + def node: NodeK + } + + object Induction { + + trait FP[+N <: NodeK] extends Induction { // short for "fixed point" + def node: N + } + } + + trait GraphK extends NodeKOrGraphK { + + type Batch[+T] <: Iterable[T] + + type _Node <: NodeK + + def entries: Batch[_Node] + } + + trait Topology { + + type Node = NodeK { type FBound <: Topology.this.FBound } + trait Node_ extends NodeK { + type FBound = Topology.this.FBound + } + + type FP = Induction.FP[Node] + type FBound <: FP + + type Graph = GraphK { type _Node <: Node } + } + +} diff --git a/tests/pos/i22257.orig.scala b/tests/pos/i22257.orig.scala new file mode 100644 index 000000000000..0be8d02d5a85 --- /dev/null +++ b/tests/pos/i22257.orig.scala @@ -0,0 +1,52 @@ + +object Scaffold { + + trait Arrow + object Arrow { + trait Outbound extends Arrow + } + + trait NodeKOrGraphK {} + + trait NodeK extends NodeKOrGraphK { + + type FBound <: Induction + + protected def getInduction: Seq[FBound] + } + + trait Induction { + def arrow: Arrow + def node: NodeK + } + + object Induction { + + trait FP[+N <: NodeK] extends Induction { // short for "fixed point" + def node: N + } + } + + trait GraphK extends NodeKOrGraphK { + + type Batch[+T] <: Iterable[T] + + type _Node <: NodeK + + def entries: Batch[_Node] + } + + trait Topology { + + type FP = Induction.FP[Node] + type FBound <: FP + + type Node = NodeK { type FBound <: Topology.this.FBound } + trait Node_ extends NodeK { + type FBound = Topology.this.FBound + } + + type Graph = GraphK { type _Node <: Node } + } + +} diff --git a/tests/pos/i22257.scala b/tests/pos/i22257.scala new file mode 100644 index 000000000000..8cd797529097 --- /dev/null +++ b/tests/pos/i22257.scala @@ -0,0 +1,26 @@ +trait NodeK { type FBound } +trait Fixed[+N <: NodeK] + +type Bound1 <: FP1 +type FP1 = Fixed[Node1] +type Node1 = NodeK { type FBound <: Bound1 } // was-error + +type FP2 = Fixed[Node2] // was-error +type Bound2 <: FP2 +type Node2 = NodeK { type FBound <: Bound2 } + +type Node3 = NodeK { type FBound <: Bound3 } +type FP3 = Fixed[Node3] +type Bound3 <: FP3 + +type Bound4 <: FP4 +type Node4 = NodeK { type FBound <: Bound4 } // was-error +type FP4 = Fixed[Node4] + +type FP5 = Fixed[Node5] // was-error +type Node5 = NodeK { type FBound <: Bound5 } +type Bound5 <: FP5 + +type Node6 = NodeK { type FBound <: Bound6 } +type Bound6 <: FP6 +type FP6 = Fixed[Node6] diff --git a/tests/run/exceptions-2.scala b/tests/run/exceptions-2.scala index ddb4c9c51ee1..73ca70eb5add 100644 --- a/tests/run/exceptions-2.scala +++ b/tests/run/exceptions-2.scala @@ -1,4 +1,4 @@ -// scalajs: --skip +// scalajs: --compliant-semantics /* * Try exception handling and finally blocks. diff --git a/tests/run/exceptions-nest.scala b/tests/run/exceptions-nest.scala index 2e58459fb9f7..cfaf09929a42 100644 --- a/tests/run/exceptions-nest.scala +++ b/tests/run/exceptions-nest.scala @@ -1,4 +1,4 @@ -// scalajs: --skip +// scalajs: --compliant-semantics object Test extends App { @@ -12,9 +12,12 @@ object Test extends App { try { println(test8) } catch { case _: Throwable => println("OK") } println(test9) println(test10) - println(test11) + portablePrintln(test11) println(test12) + def portablePrintln(x: Any): Unit = + println(if (x == ()) "()" else x) + def test1 = { var x = 1 try {