diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 4be99a1fbd45..f3c547697dec 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -477,7 +477,7 @@ object Denotations { val jointInfo = infoMeet(info1, info2, safeIntersection) if jointInfo.exists then val sym = if symScore >= 0 then sym1 else sym2 - JointRefDenotation(sym, jointInfo, denot1.validFor & denot2.validFor, pre) + JointRefDenotation(sym, jointInfo, denot1.validFor & denot2.validFor, pre, denot1.isRefinedMethod || denot2.isRefinedMethod) else if symScore == 2 then denot1 else if symScore == -2 then denot2 else @@ -569,7 +569,7 @@ object Denotations { /** A non-overloaded denotation */ abstract class SingleDenotation(symbol: Symbol, initInfo: Type) extends Denotation(symbol, initInfo) { - protected def newLikeThis(symbol: Symbol, info: Type, pre: Type): SingleDenotation + protected def newLikeThis(symbol: Symbol, info: Type, pre: Type, isRefinedMethod: Boolean): SingleDenotation final def name(using Context): Name = symbol.name @@ -582,6 +582,9 @@ object Denotations { */ def prefix: Type = NoPrefix + /** True if the info of this denotation comes from a refinement. */ + def isRefinedMethod: Boolean = false + /** For SymDenotations, the language-specific signature of the info, depending on * where the symbol is defined. For non-SymDenotations, the Scala 3 * signature. @@ -615,9 +618,9 @@ object Denotations { case _ => Signature.NotAMethod } - def derivedSingleDenotation(symbol: Symbol, info: Type, pre: Type = this.prefix)(using Context): SingleDenotation = - if ((symbol eq this.symbol) && (info eq this.info) && (pre eq this.prefix)) this - else newLikeThis(symbol, info, pre) + def derivedSingleDenotation(symbol: Symbol, info: Type, pre: Type = this.prefix, isRefinedMethod: Boolean = this.isRefinedMethod)(using Context): SingleDenotation = + if ((symbol eq this.symbol) && (info eq this.info) && (pre eq this.prefix) && (isRefinedMethod == this.isRefinedMethod)) this + else newLikeThis(symbol, info, pre, isRefinedMethod) def mapInfo(f: Type => Type)(using Context): SingleDenotation = derivedSingleDenotation(symbol, f(info)) @@ -1107,7 +1110,11 @@ object Denotations { case sd: SymDenotation => true case _ => info eq symbol.info - if !owner.membersNeedAsSeenFrom(pre) && ((pre ne owner.thisType) || hasOriginalInfo) + def ownerIsPrefix = pre match + case pre: ThisType => pre.sameThis(owner.thisType) + case _ => false + + if !owner.membersNeedAsSeenFrom(pre) && (!ownerIsPrefix || hasOriginalInfo) || symbol.is(NonMember) then this else derived(symbol.info) @@ -1126,26 +1133,30 @@ object Denotations { prefix: Type) extends NonSymSingleDenotation(symbol, initInfo, prefix) { validFor = initValidFor override def hasUniqueSym: Boolean = true - protected def newLikeThis(s: Symbol, i: Type, pre: Type): SingleDenotation = - new UniqueRefDenotation(s, i, validFor, pre) + protected def newLikeThis(s: Symbol, i: Type, pre: Type, isRefinedMethod: Boolean): SingleDenotation = + if isRefinedMethod then + new JointRefDenotation(s, i, validFor, pre, isRefinedMethod) + else + new UniqueRefDenotation(s, i, validFor, pre) } class JointRefDenotation( symbol: Symbol, initInfo: Type, initValidFor: Period, - prefix: Type) extends NonSymSingleDenotation(symbol, initInfo, prefix) { + prefix: Type, + override val isRefinedMethod: Boolean) extends NonSymSingleDenotation(symbol, initInfo, prefix) { validFor = initValidFor override def hasUniqueSym: Boolean = false - protected def newLikeThis(s: Symbol, i: Type, pre: Type): SingleDenotation = - new JointRefDenotation(s, i, validFor, pre) + protected def newLikeThis(s: Symbol, i: Type, pre: Type, isRefinedMethod: Boolean): SingleDenotation = + new JointRefDenotation(s, i, validFor, pre, isRefinedMethod) } class ErrorDenotation(using Context) extends NonSymSingleDenotation(NoSymbol, NoType, NoType) { override def exists: Boolean = false override def hasUniqueSym: Boolean = false validFor = Period.allInRun(ctx.runId) - protected def newLikeThis(s: Symbol, i: Type, pre: Type): SingleDenotation = + protected def newLikeThis(s: Symbol, i: Type, pre: Type, isRefinedMethod: Boolean): SingleDenotation = this } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 7f25655d0334..a7dec8281d89 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -896,11 +896,14 @@ object SymDenotations { * accessed via prefix `pre`? */ def membersNeedAsSeenFrom(pre: Type)(using Context): Boolean = + def preIsThis = pre match + case pre: ThisType => pre.sameThis(thisType) + case _ => false !( this.isTerm || this.isStaticOwner && !this.seesOpaques || ctx.erasedTypes || (pre eq NoPrefix) - || (pre eq thisType) + || preIsThis ) /** Is this symbol concrete, or that symbol deferred? */ @@ -1504,8 +1507,11 @@ object SymDenotations { // ----- copies and transforms ---------------------------------------- - protected def newLikeThis(s: Symbol, i: Type, pre: Type): SingleDenotation = - new UniqueRefDenotation(s, i, validFor, pre) + protected def newLikeThis(s: Symbol, i: Type, pre: Type, isRefinedMethod: Boolean): SingleDenotation = + if isRefinedMethod then + new JointRefDenotation(s, i, validFor, pre, isRefinedMethod) + else + new UniqueRefDenotation(s, i, validFor, pre) /** Copy this denotation, overriding selective fields */ final def copySymDenotation( diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c9930e036559..a90b485e46e3 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -772,15 +772,16 @@ object Types { pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo) } else + val isRefinedMethod = rinfo.isInstanceOf[MethodOrPoly] val joint = pdenot.meet( - new JointRefDenotation(NoSymbol, rinfo, Period.allInRun(ctx.runId), pre), + new JointRefDenotation(NoSymbol, rinfo, Period.allInRun(ctx.runId), pre, isRefinedMethod), pre, safeIntersection = ctx.base.pendingMemberSearches.contains(name)) joint match case joint: SingleDenotation - if rinfo.isInstanceOf[MethodOrPoly] && rinfo <:< joint.info => + if isRefinedMethod && rinfo <:< joint.info => // use `rinfo` to keep the right parameter names for named args. See i8516.scala. - joint.derivedSingleDenotation(joint.symbol, rinfo) + joint.derivedSingleDenotation(joint.symbol, rinfo, pre, isRefinedMethod) case _ => joint } @@ -2662,8 +2663,11 @@ object Types { * the future. See also NamedType#withDenot. Test case is neg/opaque-self-encoding.scala. */ private def designatorFor(prefix: Type, name: Name, denot: Denotation)(using Context): Designator = { + def ownerIsPrefix(owner: Symbol) = prefix match + case prefix: ThisType => prefix.sameThis(owner.thisType) + case _ => false val sym = denot.symbol - if (sym.exists && (prefix.eq(NoPrefix) || prefix.ne(sym.owner.thisType))) + if (sym.exists && (prefix.eq(NoPrefix) || !ownerIsPrefix(sym.owner))) sym else name @@ -2735,6 +2739,12 @@ object Types { case that: ThisType => tref.eq(that.tref) case _ => false } + + /** Check that the rhs is a ThisType that refers to the same class. + */ + def sameThis(that: Type)(using Context): Boolean = (that eq this) || that.match + case that: ThisType => this.cls eq that.cls + case _ => false } final class CachedThisType(tref: TypeRef) extends ThisType(tref) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 0ee7fe15f32d..2ccb1163e25a 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -409,22 +409,23 @@ class TreePickler(pickler: TastyPickler) { case _ => val sig = tree.tpe.signature var ename = tree.symbol.targetName - val isAmbiguous = - sig != Signature.NotAMethod - && qual.tpe.nonPrivateMember(name).match - case d: MultiDenotation => d.atSignature(sig, ename).isInstanceOf[MultiDenotation] - case _ => false - if isAmbiguous then + val selectFromQualifier = + name.isTypeName + || qual.isInstanceOf[TreePickler.Hole] // holes have no symbol + || sig == Signature.NotAMethod // no overload resolution necessary + || !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) + pickleNameAndSig(name, sig, ename) + pickleTree(qual) + else // select from owner writeByte(SELECTin) withLength { pickleNameAndSig(name, tree.symbol.signature, ename) pickleTree(qual) pickleType(tree.symbol.owner.typeRef) } - else - writeByte(if (name.isTypeName) SELECTtpt else SELECT) - pickleNameAndSig(name, sig, ename) - pickleTree(qual) } case Apply(fun, args) => if (fun.symbol eq defn.throwMethod) { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index f210f9934df2..961dce08c514 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1186,15 +1186,34 @@ class TreeUnpickler(reader: TastyReader, case SELECTin => var sname = readName() val qual = readTerm() - val owner = readType() - def select(name: Name, denot: Denotation) = - val prefix = ctx.typeAssigner.maybeSkolemizePrefix(qual.tpe.widenIfUnstable, name) - makeSelect(qual, name, denot.asSeenFrom(prefix)) - sname match - case SignedName(name, sig, target) => - select(name, owner.decl(name).atSignature(sig, target)) - case name => - select(name, owner.decl(name)) + val ownerTpe = readType() + val owner = ownerTpe.typeSymbol + val SignedName(name, sig, target) = sname: @unchecked // only methods with params use SELECTin + val qualType = qual.tpe.widenIfUnstable + val prefix = ctx.typeAssigner.maybeSkolemizePrefix(qualType, name) + + /** Tasty should still be able to resolve a method from another root class, + * even if it has been moved to a super type, + * or an override has been removed. + * + * This is tested in + * - sbt-dotty/sbt-test/tasty-compat/remove-override + * - sbt-dotty/sbt-test/tasty-compat/move-method + */ + def lookupInSuper = + val cls = ownerTpe.classSymbol + if cls.exists then + cls.asClass.classDenot + .findMember(name, cls.thisType, EmptyFlags, excluded=Private) + .atSignature(sig, target) + else + NoDenotation + + val denot = + val d = ownerTpe.decl(name).atSignature(sig, target) + (if !d.exists then lookupInSuper else d).asSeenFrom(prefix) + + makeSelect(qual, name, denot) case REPEATED => val elemtpt = readTpt() SeqLiteral(until(end)(readTerm()), elemtpt) @@ -1494,4 +1513,4 @@ object TreeUnpickler { final val AllDefs = 2 // add everything class TreeWithoutOwner extends Exception -} \ No newline at end of file +} diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index f580a79ceb0d..57b409109961 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -149,10 +149,13 @@ trait MessageRendering { if (posString.nonEmpty) sb.append(posString).append(EOL) if (pos.exists) { val pos1 = pos.nonInlined - val (srcBefore, srcAfter, offset) = sourceLines(pos1, diagnosticLevel) - val marker = columnMarker(pos1, offset, diagnosticLevel) - val err = errorMsg(pos1, msg.message, offset) - sb.append((srcBefore ::: marker :: err :: outer(pos, " " * (offset - 1)) ::: srcAfter).mkString(EOL)) + if (pos1.exists && pos1.source.file.exists) { + val (srcBefore, srcAfter, offset) = sourceLines(pos1, diagnosticLevel) + val marker = columnMarker(pos1, offset, diagnosticLevel) + val err = errorMsg(pos1, msg.message, offset) + sb.append((srcBefore ::: marker :: err :: outer(pos, " " * (offset - 1)) ::: srcAfter).mkString(EOL)) + } + else sb.append(msg.message) } else sb.append(msg.message) sb.toString diff --git a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala index be9006592a4e..211c1576254f 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala @@ -114,8 +114,10 @@ object Scala3: /** Is symbol global? Non-global symbols get localN names */ def isGlobal(using Context): Boolean = - sym.is(Package) - || !sym.isSelfSym && (sym.is(Param) || sym.owner.isClass) && sym.owner.isGlobal + sym.exists && ( + sym.is(Package) + || !sym.isSelfSym && (sym.is(Param) || sym.owner.isClass) && sym.owner.isGlobal + ) def isLocalWithinSameName(using Context): Boolean = sym.exists && !sym.isGlobal && sym.name == sym.owner.name diff --git a/compiler/src/dotty/tools/dotc/util/SourceFile.scala b/compiler/src/dotty/tools/dotc/util/SourceFile.scala index 9f555638a40e..73fd53289a9b 100644 --- a/compiler/src/dotty/tools/dotc/util/SourceFile.scala +++ b/compiler/src/dotty/tools/dotc/util/SourceFile.scala @@ -196,7 +196,7 @@ class SourceFile(val file: AbstractFile, computeContent: => Array[Char]) extends var idx = startOfLine(offset) var col = 0 while (idx != offset) { - col += (if (idx < length && content()(idx) == '\t') (tabInc - col) % tabInc else 1) + col += (if (idx < content().length && content()(idx) == '\t') (tabInc - col) % tabInc else 1) idx += 1 } col @@ -285,4 +285,3 @@ object SourceFile { override def exists: Boolean = false override def atSpan(span: Span): SourcePosition = NoSourcePosition } - diff --git a/sbt-dotty/sbt-test/tasty-compat/add-overload/a-changes/A.scala b/sbt-dotty/sbt-test/tasty-compat/add-overload/a-changes/A.scala new file mode 100644 index 000000000000..4a4e1920975f --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-overload/a-changes/A.scala @@ -0,0 +1,10 @@ +package a + +object A { + + class Buf[A] { + def append(a: A): this.type = this + def append(a: A*): this.type = this + } + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/add-overload/a/A.scala b/sbt-dotty/sbt-test/tasty-compat/add-overload/a/A.scala new file mode 100644 index 000000000000..1cedbc4e9dc9 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-overload/a/A.scala @@ -0,0 +1,9 @@ +package a + +object A { + + class Buf[A] { + def append(a: A): this.type = this + } + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/add-overload/b/B.scala b/sbt-dotty/sbt-test/tasty-compat/add-overload/b/B.scala new file mode 100644 index 000000000000..7db9a992cf26 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-overload/b/B.scala @@ -0,0 +1,7 @@ +import a.* + +object B { + val foo = new A.Buf[Seq[Double]] + val bar = Seq.empty[Double] + foo.append(bar) +} diff --git a/sbt-dotty/sbt-test/tasty-compat/add-overload/build.sbt b/sbt-dotty/sbt-test/tasty-compat/add-overload/build.sbt new file mode 100644 index 000000000000..82dc596134c8 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-overload/build.sbt @@ -0,0 +1,23 @@ +lazy val a = project.in(file("a")) + .settings( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "b-input" + ) + +lazy val b = project.in(file("b")) + .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( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "c-input" + ) + +lazy val c = project.in(file(".")) + .settings( + scalacOptions ++= Seq("-from-tasty", "-Ycheck:readTasty"), + 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-dotty/sbt-test/tasty-compat/add-overload/project/DottyInjectedPlugin.scala b/sbt-dotty/sbt-test/tasty-compat/add-overload/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..fb946c4b8c61 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-overload/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-dotty/sbt-test/tasty-compat/add-overload/project/plugins.sbt b/sbt-dotty/sbt-test/tasty-compat/add-overload/project/plugins.sbt new file mode 100644 index 000000000000..c17caab2d98c --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-overload/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % sys.props("plugin.version")) diff --git a/sbt-dotty/sbt-test/tasty-compat/add-overload/test b/sbt-dotty/sbt-test/tasty-compat/add-overload/test new file mode 100644 index 000000000000..a89cab750f2b --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-overload/test @@ -0,0 +1,8 @@ +# compile library A +> a/compile +# compile library B, from source, against A +> b/compile +# add a new overload to library A' +> a-changes/compile +# compile B, from tasty, against A', it should still compile: the overload does not conflict +> c/compile diff --git a/sbt-dotty/sbt-test/tasty-compat/add-override/a-changes/A.scala b/sbt-dotty/sbt-test/tasty-compat/add-override/a-changes/A.scala new file mode 100644 index 000000000000..0cf1abded01d --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-override/a-changes/A.scala @@ -0,0 +1,15 @@ +package a + +object A { + + trait Box0[A] { + def append(a: A): this.type = this + } + + trait BoxInt extends Box0[Int] { + override def append(a: Int): this.type = this + } + + val box: BoxInt = new BoxInt {} + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/add-override/a/A.scala b/sbt-dotty/sbt-test/tasty-compat/add-override/a/A.scala new file mode 100644 index 000000000000..7f1bf717ac6d --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-override/a/A.scala @@ -0,0 +1,13 @@ +package a + +object A { + + trait Box0[A] { + def append(a: A): this.type = this + } + + trait BoxInt extends Box0[Int] + + val box: BoxInt = new BoxInt {} + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/add-override/b/B.scala b/sbt-dotty/sbt-test/tasty-compat/add-override/b/B.scala new file mode 100644 index 000000000000..6ae8d364efff --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-override/b/B.scala @@ -0,0 +1,5 @@ +import a.* + +object B extends App { + A.box.append(0) +} diff --git a/sbt-dotty/sbt-test/tasty-compat/add-override/build.sbt b/sbt-dotty/sbt-test/tasty-compat/add-override/build.sbt new file mode 100644 index 000000000000..82dc596134c8 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-override/build.sbt @@ -0,0 +1,23 @@ +lazy val a = project.in(file("a")) + .settings( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "b-input" + ) + +lazy val b = project.in(file("b")) + .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( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "c-input" + ) + +lazy val c = project.in(file(".")) + .settings( + scalacOptions ++= Seq("-from-tasty", "-Ycheck:readTasty"), + 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-dotty/sbt-test/tasty-compat/add-override/project/DottyInjectedPlugin.scala b/sbt-dotty/sbt-test/tasty-compat/add-override/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..fb946c4b8c61 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-override/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-dotty/sbt-test/tasty-compat/add-override/project/plugins.sbt b/sbt-dotty/sbt-test/tasty-compat/add-override/project/plugins.sbt new file mode 100644 index 000000000000..c17caab2d98c --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-override/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % sys.props("plugin.version")) diff --git a/sbt-dotty/sbt-test/tasty-compat/add-override/test b/sbt-dotty/sbt-test/tasty-compat/add-override/test new file mode 100644 index 000000000000..f2963fd8a3fa --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-override/test @@ -0,0 +1,8 @@ +# compile library A +> a/compile +# compile library B, from source, against A +> b/compile +# add a new override to library A' +> a-changes/compile +# compile B, from tasty, against A', it should still compile: the override is forward compatible +> c/compile diff --git a/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/a-changes/A.scala b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/a-changes/A.scala new file mode 100644 index 000000000000..ecd129e9ec9a --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/a-changes/A.scala @@ -0,0 +1,11 @@ +package a + +object A { + + trait Fn[-T1, +R] { def apply(v1: T1): R } + + val fn0: Fn[Int, Int] { def apply(arg: Int): Int } = x => x + + val fn = fn0 + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/a/A.scala b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/a/A.scala new file mode 100644 index 000000000000..162203e90322 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/a/A.scala @@ -0,0 +1,11 @@ +package a + +object A { + + trait Fn[-T1, +R] { def apply(v1: T1): R } + + val fn0: Fn[Int, Int] = x => x + + val fn = fn0 + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/b/B.scala b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/b/B.scala new file mode 100644 index 000000000000..a10f88cd9d2c --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/b/B.scala @@ -0,0 +1,5 @@ +import a.* + +object B extends App { + A.fn(v1 = 0) +} diff --git a/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/build.sbt b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/build.sbt new file mode 100644 index 000000000000..3dc1c793f50d --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/build.sbt @@ -0,0 +1,23 @@ +lazy val a = project.in(file("a")) + .settings( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "b-input" + ) + +lazy val b = project.in(file("b")) + .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( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "c-input" + ) + +lazy val c = project.in(file(".")) + .settings( + scalacOptions ++= Seq("-from-tasty", "-Ycheck:all"), + 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-dotty/sbt-test/tasty-compat/add-refinement-change-names/project/DottyInjectedPlugin.scala b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..fb946c4b8c61 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/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-dotty/sbt-test/tasty-compat/add-refinement-change-names/project/plugins.sbt b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/project/plugins.sbt new file mode 100644 index 000000000000..c17caab2d98c --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % sys.props("plugin.version")) diff --git a/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/test b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/test new file mode 100644 index 000000000000..3259ac5a90f7 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/add-refinement-change-names/test @@ -0,0 +1,8 @@ +# compile library A +> a/compile +# compile library B, from source, against A +> b/compile +# add a refinement in library A', it changes the parameter names +> a-changes/compile +# compile B, from tasty, against A', it should continue compile: named arguments still ok. +> c/compile diff --git a/sbt-dotty/sbt-test/tasty-compat/change-refinement/a-changes/A.scala b/sbt-dotty/sbt-test/tasty-compat/change-refinement/a-changes/A.scala new file mode 100644 index 000000000000..ecd129e9ec9a --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/change-refinement/a-changes/A.scala @@ -0,0 +1,11 @@ +package a + +object A { + + trait Fn[-T1, +R] { def apply(v1: T1): R } + + val fn0: Fn[Int, Int] { def apply(arg: Int): Int } = x => x + + val fn = fn0 + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/change-refinement/a/A.scala b/sbt-dotty/sbt-test/tasty-compat/change-refinement/a/A.scala new file mode 100644 index 000000000000..7560c6747856 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/change-refinement/a/A.scala @@ -0,0 +1,11 @@ +package a + +object A { + + trait Fn[-T1, +R] { def apply(v1: T1): R } + + val fn0: Fn[Int, Int] { def apply(int: Int): Int } = x => x + + val fn = fn0 + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/change-refinement/b/B.scala b/sbt-dotty/sbt-test/tasty-compat/change-refinement/b/B.scala new file mode 100644 index 000000000000..71a881aee105 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/change-refinement/b/B.scala @@ -0,0 +1,5 @@ +import a.* + +object B extends App { + A.fn(int = 0) +} diff --git a/sbt-dotty/sbt-test/tasty-compat/change-refinement/build.sbt b/sbt-dotty/sbt-test/tasty-compat/change-refinement/build.sbt new file mode 100644 index 000000000000..82dc596134c8 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/change-refinement/build.sbt @@ -0,0 +1,23 @@ +lazy val a = project.in(file("a")) + .settings( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "b-input" + ) + +lazy val b = project.in(file("b")) + .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( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "c-input" + ) + +lazy val c = project.in(file(".")) + .settings( + scalacOptions ++= Seq("-from-tasty", "-Ycheck:readTasty"), + 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-dotty/sbt-test/tasty-compat/change-refinement/project/DottyInjectedPlugin.scala b/sbt-dotty/sbt-test/tasty-compat/change-refinement/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..fb946c4b8c61 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/change-refinement/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-dotty/sbt-test/tasty-compat/change-refinement/project/plugins.sbt b/sbt-dotty/sbt-test/tasty-compat/change-refinement/project/plugins.sbt new file mode 100644 index 000000000000..c17caab2d98c --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/change-refinement/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % sys.props("plugin.version")) diff --git a/sbt-dotty/sbt-test/tasty-compat/change-refinement/test b/sbt-dotty/sbt-test/tasty-compat/change-refinement/test new file mode 100644 index 000000000000..221937a3b919 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/change-refinement/test @@ -0,0 +1,9 @@ +# compile library A +> a/compile +# compile library B, from source, against A +> b/compile +# change the method parameter names in a refinement in library A' +> a-changes/compile +# compile B, from tasty, against A', it should fail to compile: the refinement of `Fn.apply` has changed its +# named arguments. +-> c/compile diff --git a/sbt-dotty/sbt-test/tasty-compat/move-method/a-changes/A.scala b/sbt-dotty/sbt-test/tasty-compat/move-method/a-changes/A.scala new file mode 100644 index 000000000000..c776e3a5fd9f --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/move-method/a-changes/A.scala @@ -0,0 +1,13 @@ +package a + +object A { + + trait Box0[A] { + def append(a: A): Unit = () + } + + trait BoxInt extends Box0[Int] + + val box: BoxInt = new BoxInt {} + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/move-method/a/A.scala b/sbt-dotty/sbt-test/tasty-compat/move-method/a/A.scala new file mode 100644 index 000000000000..e63ac38f5b4d --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/move-method/a/A.scala @@ -0,0 +1,13 @@ +package a + +object A { + + trait Box0[A] + + trait BoxInt extends Box0[Int] { + def append(a: Int): Unit = () + } + + val box: BoxInt = new BoxInt {} + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/move-method/b/B.scala b/sbt-dotty/sbt-test/tasty-compat/move-method/b/B.scala new file mode 100644 index 000000000000..6ae8d364efff --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/move-method/b/B.scala @@ -0,0 +1,5 @@ +import a.* + +object B extends App { + A.box.append(0) +} diff --git a/sbt-dotty/sbt-test/tasty-compat/move-method/build.sbt b/sbt-dotty/sbt-test/tasty-compat/move-method/build.sbt new file mode 100644 index 000000000000..82dc596134c8 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/move-method/build.sbt @@ -0,0 +1,23 @@ +lazy val a = project.in(file("a")) + .settings( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "b-input" + ) + +lazy val b = project.in(file("b")) + .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( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "c-input" + ) + +lazy val c = project.in(file(".")) + .settings( + scalacOptions ++= Seq("-from-tasty", "-Ycheck:readTasty"), + 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-dotty/sbt-test/tasty-compat/move-method/project/DottyInjectedPlugin.scala b/sbt-dotty/sbt-test/tasty-compat/move-method/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..fb946c4b8c61 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/move-method/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-dotty/sbt-test/tasty-compat/move-method/project/plugins.sbt b/sbt-dotty/sbt-test/tasty-compat/move-method/project/plugins.sbt new file mode 100644 index 000000000000..c17caab2d98c --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/move-method/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % sys.props("plugin.version")) diff --git a/sbt-dotty/sbt-test/tasty-compat/move-method/test b/sbt-dotty/sbt-test/tasty-compat/move-method/test new file mode 100644 index 000000000000..152b560a834f --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/move-method/test @@ -0,0 +1,8 @@ +# compile library A +> a/compile +# compile library B, from source, against A +> b/compile +# move a method to its super type in library A' +> a-changes/compile +# compile B, from tasty, against A', it should compile: we can find the method in a supertype. +> c/compile diff --git a/sbt-dotty/sbt-test/tasty-compat/remove-override/a-changes/A.scala b/sbt-dotty/sbt-test/tasty-compat/remove-override/a-changes/A.scala new file mode 100644 index 000000000000..c776e3a5fd9f --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-override/a-changes/A.scala @@ -0,0 +1,13 @@ +package a + +object A { + + trait Box0[A] { + def append(a: A): Unit = () + } + + trait BoxInt extends Box0[Int] + + val box: BoxInt = new BoxInt {} + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/remove-override/a/A.scala b/sbt-dotty/sbt-test/tasty-compat/remove-override/a/A.scala new file mode 100644 index 000000000000..da2a07836fb9 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-override/a/A.scala @@ -0,0 +1,15 @@ +package a + +object A { + + trait Box0[A] { + def append(a: A): Unit = () + } + + trait BoxInt extends Box0[Int] { + override def append(a: Int): Unit = () + } + + val box: BoxInt = new BoxInt {} + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/remove-override/b/B.scala b/sbt-dotty/sbt-test/tasty-compat/remove-override/b/B.scala new file mode 100644 index 000000000000..6ae8d364efff --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-override/b/B.scala @@ -0,0 +1,5 @@ +import a.* + +object B extends App { + A.box.append(0) +} diff --git a/sbt-dotty/sbt-test/tasty-compat/remove-override/build.sbt b/sbt-dotty/sbt-test/tasty-compat/remove-override/build.sbt new file mode 100644 index 000000000000..82dc596134c8 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-override/build.sbt @@ -0,0 +1,23 @@ +lazy val a = project.in(file("a")) + .settings( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "b-input" + ) + +lazy val b = project.in(file("b")) + .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( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "c-input" + ) + +lazy val c = project.in(file(".")) + .settings( + scalacOptions ++= Seq("-from-tasty", "-Ycheck:readTasty"), + 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-dotty/sbt-test/tasty-compat/remove-override/project/DottyInjectedPlugin.scala b/sbt-dotty/sbt-test/tasty-compat/remove-override/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..fb946c4b8c61 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-override/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-dotty/sbt-test/tasty-compat/remove-override/project/plugins.sbt b/sbt-dotty/sbt-test/tasty-compat/remove-override/project/plugins.sbt new file mode 100644 index 000000000000..c17caab2d98c --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-override/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % sys.props("plugin.version")) diff --git a/sbt-dotty/sbt-test/tasty-compat/remove-override/test b/sbt-dotty/sbt-test/tasty-compat/remove-override/test new file mode 100644 index 000000000000..1f861298259c --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-override/test @@ -0,0 +1,8 @@ +# compile library A +> a/compile +# compile library B, from source, against A +> b/compile +# remove an override in library A' +> a-changes/compile +# compile B, from tasty, against A', it should compile: we can find the method in a supertype. +> c/compile diff --git a/sbt-dotty/sbt-test/tasty-compat/remove-refinement/a-changes/A.scala b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/a-changes/A.scala new file mode 100644 index 000000000000..162203e90322 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/a-changes/A.scala @@ -0,0 +1,11 @@ +package a + +object A { + + trait Fn[-T1, +R] { def apply(v1: T1): R } + + val fn0: Fn[Int, Int] = x => x + + val fn = fn0 + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/remove-refinement/a/A.scala b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/a/A.scala new file mode 100644 index 000000000000..04480fa763a7 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/a/A.scala @@ -0,0 +1,11 @@ +package a + +object A { + + trait Fn[-T1, +R] { def apply(v1: T1): R } + + val fn0: Fn[Int, Int] { def apply(arg: Int): Int } = ??? + + val fn = fn0 + +} diff --git a/sbt-dotty/sbt-test/tasty-compat/remove-refinement/b/B.scala b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/b/B.scala new file mode 100644 index 000000000000..99a52e3832df --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/b/B.scala @@ -0,0 +1,5 @@ +import a.* + +object B extends App { + A.fn(0) +} diff --git a/sbt-dotty/sbt-test/tasty-compat/remove-refinement/build.sbt b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/build.sbt new file mode 100644 index 000000000000..3dc1c793f50d --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/build.sbt @@ -0,0 +1,23 @@ +lazy val a = project.in(file("a")) + .settings( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "b-input" + ) + +lazy val b = project.in(file("b")) + .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( + Compile / classDirectory := (ThisBuild / baseDirectory).value / "c-input" + ) + +lazy val c = project.in(file(".")) + .settings( + scalacOptions ++= Seq("-from-tasty", "-Ycheck:all"), + 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-dotty/sbt-test/tasty-compat/remove-refinement/project/DottyInjectedPlugin.scala b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..fb946c4b8c61 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/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-dotty/sbt-test/tasty-compat/remove-refinement/project/plugins.sbt b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/project/plugins.sbt new file mode 100644 index 000000000000..c17caab2d98c --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % sys.props("plugin.version")) diff --git a/sbt-dotty/sbt-test/tasty-compat/remove-refinement/test b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/test new file mode 100644 index 000000000000..3259ac5a90f7 --- /dev/null +++ b/sbt-dotty/sbt-test/tasty-compat/remove-refinement/test @@ -0,0 +1,8 @@ +# compile library A +> a/compile +# compile library B, from source, against A +> b/compile +# add a refinement in library A', it changes the parameter names +> a-changes/compile +# compile B, from tasty, against A', it should continue compile: named arguments still ok. +> c/compile diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index f964a460c377..f8c077c0aa0b 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -301,7 +301,7 @@ object TastyFormat { * is able to read final TASTy documents if the file's * `MinorVersion` is strictly less than the current value. */ - final val ExperimentalVersion: Int = 2 + final val ExperimentalVersion: Int = 3 /**This method implements a binary relation (`<:<`) between two TASTy versions. * We label the lhs `file` and rhs `compiler`. diff --git a/tests/pos/i11819.scala b/tests/pos/i11819.scala new file mode 100644 index 000000000000..b6883dd517a5 --- /dev/null +++ b/tests/pos/i11819.scala @@ -0,0 +1,12 @@ +package opaquetypes + +object `package`: // must be a package object + + opaque type Foo = Double // `Foo` must be an opaque type, reference must be primitive + + object Bar: // must have a wrapper object + + class Baz(val i: Foo): // must be an unqualified reference to `Foo` + def foo(that: Any): Boolean = that match + case that1 @ (_: Baz) => Baz.this.i == that1.i // error: symbol for `==` changed + case _ => true diff --git a/tests/pos/i8516.scala b/tests/pos/i8516.scala index 9e95e3e4eb02..3f76c307bf9c 100644 --- a/tests/pos/i8516.scala +++ b/tests/pos/i8516.scala @@ -1,3 +1,3 @@ val x: Function1[Int, Int] { def apply(arg: Int): Int } = x => x val x1 = x -val y = x.apply(arg = 1) \ No newline at end of file +val y = x.apply(arg = 1) diff --git a/tests/pos/i9050.scala b/tests/pos/i9050.scala index e538ec5d1cd3..4e9b9340eeab 100644 --- a/tests/pos/i9050.scala +++ b/tests/pos/i9050.scala @@ -3,4 +3,5 @@ object Foo { val foo = scala.collection.mutable.ArrayBuffer.empty[Seq[Double]] val bar = Seq.empty[Double] foo.append(bar) -} \ No newline at end of file + foo.append(Seq(bar):_*) +} diff --git a/tests/pos/p11210-multiowner.scala b/tests/pos/p11210-multiowner.scala new file mode 100644 index 000000000000..95e4d71e0a93 --- /dev/null +++ b/tests/pos/p11210-multiowner.scala @@ -0,0 +1,12 @@ +trait Foo[A] { + def append(elem: A): Unit = {} +} +trait Bar[A] { + def append(elems: A*): Unit = {} +} + +@main def Test = { + val foobar: Foo[Seq[Double]] & Bar[Seq[Double]] = ??? + val seq = Seq.empty[Double] + foobar.append(seq) +} diff --git a/tests/pos/p11210-refinement.scala b/tests/pos/p11210-refinement.scala new file mode 100644 index 000000000000..3a95fefa5a3f --- /dev/null +++ b/tests/pos/p11210-refinement.scala @@ -0,0 +1,13 @@ +trait Poly { + def f[T]: String +} + +val p: Poly { def f[T]: "hello" } = ??? +val q: "hello" = p.f[Int] + +trait Box { + val x: String +} + +val b: Box { val x: "goodbye" } = ??? +val c: "goodbye" = b.x diff --git a/tests/pos/p11210-values.scala b/tests/pos/p11210-values.scala new file mode 100644 index 000000000000..48d299118930 --- /dev/null +++ b/tests/pos/p11210-values.scala @@ -0,0 +1,11 @@ +trait Foo[+A] { + def toSeq: Seq[A] = ??? +} +trait Bar[+A] { + def toSeq: Seq[Seq[A]] = ??? +} + +@main def Test = { + val foobar: Foo[Seq[Double]] & Bar[Double] = ??? + val m: Seq[Seq[Double]] = foobar.toSeq +} diff --git a/tests/pos/selectinalways.scala b/tests/pos/selectinalways.scala new file mode 100644 index 000000000000..378fb2c4f7d2 --- /dev/null +++ b/tests/pos/selectinalways.scala @@ -0,0 +1,10 @@ +class Buf[A] { + def append(a: A): this.type = this + def append(a: A*): this.type = this +} + +@main def Test = { + val foo = new Buf[Seq[Double]] + val bar = Seq.empty[Double] + foo.append(bar) +} diff --git a/tests/pos/tasty-named-arguments.scala b/tests/pos/tasty-named-arguments.scala new file mode 100644 index 000000000000..b73069e4a261 --- /dev/null +++ b/tests/pos/tasty-named-arguments.scala @@ -0,0 +1,15 @@ +trait Fn[-T, R] { def apply(t: T): R } + +val f: Fn[Int, Int] { def apply(arg: Int): Int } = x => x +val g = f.apply(arg = 1) + +val m: [T] => (arg: T) => T = [T] => (arg: T) => arg +val n = m.apply(arg = 23) + +trait KeyValuePair { type Value; def value: Value } + +val d: (kvp: KeyValuePair) => kvp.Value = _.value +val e = d.apply(kvp = new { type Value = Int; val value = 23 } ) + +val c: (i: Int) ?=> i.type = x ?=> x +val i = c.apply(using 0)