Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add compilation unit info to ClassSymbol #19010

Merged
7 changes: 7 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import config.Printers.typr
import dotty.tools.dotc.classpath.FileUtils.isScalaBinary

import scala.compiletime.uninitialized
import dotty.tools.tasty.TastyVersion

object Symbols {

Expand Down Expand Up @@ -281,6 +282,12 @@ object Symbols {
def compilationUnitInfo(using Context): CompilationUnitInfo | Null =
lastDenot.topLevelClass.compilationUnitInfo

/** The version of TASTy from which the symbol was loaded, None if not applicable. */
def tastyVersion(using Context): Option[TastyVersion] =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@EugeneFlesselle here is the new version of the TASTy version. I changed a bit your original design, now we only have a TASTy version if the symbol vas loaded from TASTy. For symbols created from source we can assume they have the current TASTy version.

val compUnitInfo = compilationUnitInfo
if compUnitInfo == null then None
else compUnitInfo.tastyVersion

/** The class file from which this class was generated, null if not applicable. */
final def binaryFile(using Context): AbstractFile | Null = {
val file = associatedFile
Expand Down
14 changes: 10 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1071,12 +1071,17 @@ trait Checking {
def checkValidInfix(tree: untpd.InfixOp, meth: Symbol)(using Context): Unit = {
tree.op match {
case id @ Ident(name: Name) =>
def methCompiledBeforeDeprecation =
meth.tastyVersion match
case Some(version) => version.minor < 4 // compiled before 3.4
case _ => false // compiled with the current compiler
name.toTermName match {
case name: SimpleName
if !untpd.isBackquoted(id) &&
!name.isOperatorName &&
!meth.isDeclaredInfix &&
!meth.maybeOwner.is(Scala2x) &&
!methCompiledBeforeDeprecation &&
!infixOKSinceFollowedBy(tree.right) =>
val (kind, alternative) =
if (ctx.mode.is(Mode.Type))
Expand All @@ -1085,13 +1090,14 @@ trait Checking {
("extractor", (n: Name) => s"prefix syntax $n(...)")
else
("method", (n: Name) => s"method syntax .$n(...)")
def rewriteMsg = Message.rewriteNotice("The latter", version = `future-migration`)
report.errorOrMigrationWarning(
def rewriteMsg = Message.rewriteNotice("The latter", version = `3.4-migration`)
report.gradualErrorOrMigrationWarning(
em"""Alphanumeric $kind $name is not declared ${hlAsKeyword("infix")}; it should not be used as infix operator.
|Instead, use ${alternative(name)} or backticked identifier `$name`.$rewriteMsg""",
tree.op.srcPos,
from = future)
if sourceVersion == `future-migration` then {
warnFrom = `3.4`,
errorFrom = future)
if sourceVersion.isMigrating && sourceVersion.isAtLeast(`3.4-migration`) then {
patch(Span(tree.op.span.start, tree.op.span.start), "`")
patch(Span(tree.op.span.end, tree.op.span.end), "`")
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/test-resources/repl/i1374
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
scala> implicit class Padder(val sb: StringBuilder) extends AnyVal { def pad2(width: Int) = { 1 to width - sb.length foreach { sb append '*' }; sb } }
scala> implicit class Padder(val sb: StringBuilder) extends AnyVal { infix def pad2(width: Int) = { 1 to width - sb.length foreach { sb append '*' }; sb } }
// defined class Padder
def Padder(sb: StringBuilder): Padder
scala> val greeting = new StringBuilder("Hello, kitteh!")
Expand Down
2 changes: 1 addition & 1 deletion compiler/test-resources/type-printer/infix
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def foo: (Int &: String) & Boolean
scala> def foo: Int &: (Boolean & String) = ???
def foo: Int &: (Boolean & String)
scala> import scala.annotation.showAsInfix
scala> @scala.annotation.showAsInfix class Mappy[T,U]
scala> @scala.annotation.showAsInfix infix class Mappy[T,U]
// defined class Mappy
scala> def foo: (Int Mappy Boolean) && String = ???
def foo: (Int Mappy Boolean) && String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import PositionContext.PosCtx
class CodeMarker(val name: String) extends Embedded {

/** A range of positions between this marker and `other`. */
def to(other: CodeMarker): CodeRange = CodeRange(this, other)
infix def to(other: CodeMarker): CodeRange = CodeRange(this, other)

/** The file containing this marker. */
def file: PosCtx[TestFile] = posCtx.positionOf(this)._1
Expand Down
4 changes: 2 additions & 2 deletions scaladoc-testcases/src/tests/infixTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ package infixTypes
import annotation.showAsInfix

@showAsInfix
trait SomeTrait[A, B]
infix trait SomeTrait[A, B]

trait SomeTrait2[A, B]
infix trait SomeTrait2[A, B]

def someTrait1[C, D]: C SomeTrait D
= ???
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,9 @@ object MemberLookup extends MemberLookup {
// Scaladoc overloading support allows terminal * (and they're meaningless)
val cleanStr = str.stripSuffix("*")

if cleanStr endsWith "$" then
if cleanStr.endsWith("$") then
Selector(cleanStr.init, SelectorKind.ForceTerm)
else if cleanStr endsWith "!" then
else if cleanStr.endsWith("!") then
Selector(cleanStr.init, SelectorKind.ForceType)
else
Selector(cleanStr, SelectorKind.NoForce)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ sealed class CharReader(buffer: String) { reader =>

var offset: Int = 0
def char: Char =
if (offset >= buffer.length) endOfText else buffer charAt offset
if (offset >= buffer.length) endOfText else buffer.charAt(offset)

final def nextChar() =
offset += 1
Expand Down Expand Up @@ -712,7 +712,7 @@ sealed class CharReader(buffer: String) { reader =>
jumpWhitespace()
val (ok0, chars0) =
if (chars.charAt(0) == ' ')
(offset > poff, chars substring 1)
(offset > poff, chars.substring(1))
else
(true, chars)
val ok = ok0 && jump(chars0)
Expand Down
2 changes: 1 addition & 1 deletion scaladoc/test/dotty/tools/scaladoc/testUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def tastyFiles(name: String, allowEmpty: Boolean = false, rootPck: String = "tes
}
def collectFiles(dir: File): List[File] = listFilesSafe(dir).toList.flatMap {
case f if f.isDirectory => collectFiles(f)
case f if f.getName endsWith ".tasty" => f :: Nil
case f if f.getName.endsWith(".tasty") => f :: Nil
case _ => Nil
}
val outputDir = BuildInfo.test_testcasesOutputDir
Expand Down
4 changes: 2 additions & 2 deletions tests/init-global/pos/i18628-lazy.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ trait Parsers {
}

def flatMap[U](f: T => Parser[U]): Parser[U]
= Parser{ in => this(in) flatMapWithNext(f)}
= Parser{ in => this(in).flatMapWithNext(f)}

def map[U](f: T => U): Parser[U] //= flatMap{x => success(f(x))}
= Parser{ in => this(in) map(f)}
= Parser{ in => this(in).map(f)}

def ^^ [U](f: T => U): Parser[U] = map(f)
}
Expand Down
4 changes: 2 additions & 2 deletions tests/init-global/pos/i18628.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ trait Parsers {
}

def flatMap[U](f: T => Parser[U]): Parser[U]
= Parser{ in => this(in) flatMapWithNext(f)}
= Parser{ in => this(in).flatMapWithNext(f)}

def map[U](f: T => U): Parser[U] //= flatMap{x => success(f(x))}
= Parser{ in => this(in) map(f)}
= Parser{ in => this(in).map(f)}

def ^^ [U](f: T => U): Parser[U] = map(f)
}
Expand Down
12 changes: 6 additions & 6 deletions tests/init/pos/Properties.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ private[scala] trait PropertiesTrait {
/** The loaded properties */
protected lazy val scalaProps: java.util.Properties = {
val props = new java.util.Properties
val stream = pickJarBasedOn getResourceAsStream propFilename
val stream = pickJarBasedOn.getResourceAsStream(propFilename)
if (stream ne null)
quietlyDispose(props load stream, stream.close)
quietlyDispose(props.load(stream), stream.close)

props
}
Expand All @@ -47,8 +47,8 @@ private[scala] trait PropertiesTrait {
final def setProp(name: String, value: String) = System.setProperty(name, value)
final def clearProp(name: String) = System.clearProperty(name)

final def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
final def envOrNone(name: String) = Option(System getenv name)
final def envOrElse(name: String, alt: String) = Option(System.getenv(name)) getOrElse alt
final def envOrNone(name: String) = Option(System.getenv(name))

final def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt

Expand All @@ -68,7 +68,7 @@ private[scala] trait PropertiesTrait {
val releaseVersion =
for {
v <- scalaPropOrNone("maven.version.number")
if !(v endsWith "-SNAPSHOT")
if !(v.endsWith("-SNAPSHOT"))
} yield v

/** The development Scala version, if this is not a final release.
Expand All @@ -82,7 +82,7 @@ private[scala] trait PropertiesTrait {
val developmentVersion =
for {
v <- scalaPropOrNone("maven.version.number")
if v endsWith "-SNAPSHOT"
if v.endsWith("-SNAPSHOT")
ov <- scalaPropOrNone("version.number")
} yield ov

Expand Down
2 changes: 1 addition & 1 deletion tests/init/pos/i15465.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class TestSuite:
protected val it = new ItWord

protected final class ItWord:
def should(string: String) = new ItVerbString("should", string)
infix def should(string: String) = new ItVerbString("should", string)

private def registerTestToRun(fun: => Any): Unit = ()

Expand Down
11 changes: 11 additions & 0 deletions tests/neg/alphanumeric-infix-operator-3.4.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//> using options -Werror

import language.`3.4`

class Foo:
def x(i: Int) = i
infix def y(i: Int) = i

def test(foo: Foo): Unit =
foo x 1 // error (because it was compiled with 3.4+)
foo y 2 // ok: is marked as infix
6 changes: 6 additions & 0 deletions tests/neg/alphanumeric-infix-operator.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Error: tests/neg/alphanumeric-infix-operator.scala:8:6 --------------------------------------------------------------
8 | foo x 1 // error (because it was compiled with 3.4+)
| ^
| Alphanumeric method x is not declared infix; it should not be used as infix operator.
| Instead, use method syntax .x(...) or backticked identifier `x`.
| The latter can be rewritten automatically under -rewrite -source 3.4-migration.
9 changes: 9 additions & 0 deletions tests/neg/alphanumeric-infix-operator.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//> using options -Werror

class Foo:
def x(i: Int) = i
infix def y(i: Int) = i

def test(foo: Foo): Unit =
foo x 1 // error (because it was compiled with 3.4+)
foo y 2 // ok: is marked as infix
8 changes: 4 additions & 4 deletions tests/neg/i10901.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ object BugExp4Point2D {

// N - N
@targetName("point2DConstant")
def º(y: T2): Point2D[T1,T2] = ???
infix def º(y: T2): Point2D[T1,T2] = ???


// N - C
@targetName("point2DConstantData")
def º(y: ColumnType[T2]): Point2D[T1,T2] = ???
infix def º(y: ColumnType[T2]): Point2D[T1,T2] = ???



extension [T1:Numeric, T2:Numeric](x: ColumnType[T1])
// C - C
@targetName("point2DData")
def º(y: ColumnType[T2]): Point2D[T1,T2] = ???
infix def º(y: ColumnType[T2]): Point2D[T1,T2] = ???

// C - N
@targetName("point2DDataConstant")
def º(y: T2): Point2D[T1,T2] = ???
infix def º(y: T2): Point2D[T1,T2] = ???


}
Expand Down
6 changes: 6 additions & 0 deletions tests/neg/i2033.check
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@
6 | val out = new ObjectOutputStream(println)
| ^^^^^^^
|method println is eta-expanded even though java.io.OutputStream does not have the @FunctionalInterface annotation.
-- Warning: tests/neg/i2033.scala:7:18 ---------------------------------------------------------------------------------
7 | val arr = bos toByteArray () // error
| ^^^^^^^^^^^
| Alphanumeric method toByteArray is not declared infix; it should not be used as infix operator.
| Instead, use method syntax .toByteArray(...) or backticked identifier `toByteArray`.
| The latter can be rewritten automatically under -rewrite -source 3.4-migration.
2 changes: 1 addition & 1 deletion tests/neg/rewrite-messages.check
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
| ^^^
| Alphanumeric method foo is not declared infix; it should not be used as infix operator.
| Instead, use method syntax .foo(...) or backticked identifier `foo`.
| The latter can be rewritten automatically under -rewrite -source future-migration.
| The latter can be rewritten automatically under -rewrite -source 3.4-migration.
6 changes: 6 additions & 0 deletions tests/neg/syntax-error-recovery.check
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,9 @@
| Discarded non-Unit value of type Null. You may want to use `()`.
|
| longer explanation available when compiling with `-explain`
-- Warning: tests/neg/syntax-error-recovery.scala:61:2 -----------------------------------------------------------------
61 | println(bam)
| ^^^^^^^
| Alphanumeric method println is not declared infix; it should not be used as infix operator.
| Instead, use method syntax .println(...) or backticked identifier `println`.
| The latter can be rewritten automatically under -rewrite -source 3.4-migration.
3 changes: 3 additions & 0 deletions tests/pos/alphanumeric-infix-operator-compat/A_1_c3.0.0.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class A:
def x(i: Int) = i
infix def y(i: Int) = i
3 changes: 3 additions & 0 deletions tests/pos/alphanumeric-infix-operator-compat/B_1_c3.1.0.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class B:
def x(i: Int) = i
infix def y(i: Int) = i
3 changes: 3 additions & 0 deletions tests/pos/alphanumeric-infix-operator-compat/C_1_c3.2.0.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class C:
def x(i: Int) = i
infix def y(i: Int) = i
3 changes: 3 additions & 0 deletions tests/pos/alphanumeric-infix-operator-compat/D_1_c3.3.0.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class D:
def x(i: Int) = i
infix def y(i: Int) = i
15 changes: 15 additions & 0 deletions tests/pos/alphanumeric-infix-operator-compat/Test3.4_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//> using options -Werror

import language.`3.4`

def test1(a: A, b: B, c: C, d: D): Unit =
a x 1 // ok: was compiled with 3.0
b x 1 // ok: was compiled with 3.1
c x 1 // ok: was compiled with 3.2
d x 1 // ok: was compiled with 3.3

// ok: is marked as infix
a y 2
b y 2
c y 2
d y 2
13 changes: 13 additions & 0 deletions tests/pos/alphanumeric-infix-operator-compat/TestFuture_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import language.future

def test2(a: A, b: B, c: C, d: D): Unit =
a x 1 // ok: was compiled with 3.0
b x 1 // ok: was compiled with 3.1
c x 1 // ok: was compiled with 3.2
d x 1 // ok: was compiled with 3.3

// ok: is marked as infix
a y 2
b y 2
c y 2
d y 2
2 changes: 1 addition & 1 deletion tests/pos/i7424c.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//> using options -Werror
object Main extends App:
enum Extends[A, B]:
infix enum Extends[A, B]:
case Ev[B, A <: B]() extends (A Extends B)

def cast(a: A): B = this match {
Expand Down
6 changes: 6 additions & 0 deletions tests/semanticdb/metac.expect
Original file line number Diff line number Diff line change
Expand Up @@ -3460,6 +3460,7 @@ Text => empty
Language => Scala
Symbols => 12 entries
Occurrences => 33 entries
Diagnostics => 1 entries
Synthetics => 4 entries

Symbols:
Expand Down Expand Up @@ -3511,6 +3512,11 @@ Occurrences:
[20:4..20:13): scalameta -> scala/reflect/Selectable#selectDynamic().
[21:4..21:19): StructuralTypes -> example/StructuralTypes.

Diagnostics:
[14:20..14:23): [warning] Alphanumeric method foo is not declared infix; it should not be used as infix operator.
Instead, use method syntax .foo(...) or backticked identifier `foo`.
The latter can be rewritten automatically under -rewrite -source 3.4-migration.

Synthetics:
[12:2..12:6):user => reflectiveSelectable(*)
[13:2..13:6):user => reflectiveSelectable(*)
Expand Down