Skip to content

Commit c94b333

Browse files
authored
Merge pull request #12931 from dotty-staging/fix-11861
Fix #11861 - hash nested calls to inline definitions
2 parents 0193dda + 683c458 commit c94b333

File tree

88 files changed

+919
-63
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+919
-63
lines changed

compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala

+188-59
Large diffs are not rendered by default.

compiler/src/dotty/tools/dotc/sbt/package.scala

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import dotty.tools.dotc.core.Symbols.Symbol
55
import dotty.tools.dotc.core.NameOps.stripModuleClassSuffix
66
import dotty.tools.dotc.core.Names.Name
77

8+
inline val TermNameHash = 1987 // 300th prime
9+
inline val TypeNameHash = 1993 // 301st prime
10+
inline val InlineParamHash = 1997 // 302nd prime
11+
812
extension (sym: Symbol)
913

1014
def constructorName(using Context) =

compiler/src/dotty/tools/dotc/typer/Implicits.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,7 @@ trait Implicits:
980980
trace(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) {
981981
record("inferImplicit")
982982
assert(ctx.phase.allowsImplicitSearch,
983-
if (argument.isEmpty) i"missing implicit parameter of type $pt after typer"
983+
if (argument.isEmpty) i"missing implicit parameter of type $pt after typer at phase ${ctx.phase.phaseName}"
984984
else i"type error: ${argument.tpe} does not conform to $pt${err.whyNoMatchStr(argument.tpe, pt)}")
985985

986986
if pt.unusableForInference

library/src/scala/compiletime/package.scala

-1
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,3 @@ def byName[T](x: => T): T = x
188188
*/
189189
extension [T](x: T)
190190
transparent inline def asMatchable: x.type & Matchable = x.asInstanceOf[x.type & Matchable]
191-

project/scripts/bootstrapCmdTests

+16-2
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ IFS=':=' read -ra versionProps < "$cwd/dist/target/pack/VERSION" # temporarily s
9696
[ -n ${versionProps[2]} ] || die "Expected non-empty 'version' property in $cwd/dist/target/pack/VERSION"
9797
scala_version=${versionProps[2]}
9898

99-
echo "testing -sourcepath with inlining"
100-
# Here we will test that an inline method symbol loaded from the sourcepath (-sourcepath compiler option)
99+
echo "testing -sourcepath with incremental compile: inlining changed inline def into a def"
100+
# Here we will test that a changed inline method symbol loaded from the sourcepath (-sourcepath compiler option)
101101
# will have its `defTree` correctly set when its method body is required for inlining.
102102
# So far I have not found a way to replicate issue https://github.com/lampepfl/dotty/issues/13994
103103
# with sbt scripted tests, if a way is found, move this test there.
@@ -107,3 +107,17 @@ sbt_test_command="++${scala_version}!;clean;prepareSources;compile;copyChanges;c
107107
rm -rf "$cwd/tests/cmdTest-sbt-tests/sourcepath-with-inline/target"
108108
rm -rf "$cwd/tests/cmdTest-sbt-tests/sourcepath-with-inline/project/target"
109109
rm -f "$cwd/tests/cmdTest-sbt-tests/sourcepath-with-inline/src/main/scala/a/zz.scala"
110+
111+
echo "testing -sourcepath with incremental compile: hashing reference to changed inline def from an inline def"
112+
# Here we will test that a changed inline method symbol loaded from the sourcepath (-sourcepath compiler option)
113+
# will have its `defTree` correctly set when its method body is hashed by extractAPI, when referenced from another
114+
# inline method.
115+
# So far I have not found a way to replicate https://github.com/lampepfl/dotty/pull/12931#discussion_r753212124
116+
# with sbt scripted tests, if a way is found, move this test there.
117+
cwd=$(pwd)
118+
sbt_test_dir="$cwd/tests/cmdTest-sbt-tests/sourcepath-with-inline-api-hash"
119+
sbt_test_command="++${scala_version}!;clean;prepareSources;compile;copyChanges;compile"
120+
(cd "$sbt_test_dir" && "$SBT" "$sbt_test_command")
121+
rm -rf "$sbt_test_dir/target"
122+
rm -rf "$sbt_test_dir/project/target"
123+
rm -f "$sbt_test_dir/src/main/scala/a/zz.scala"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object A {
2+
3+
class Box[T](val value: T)
4+
5+
extension (box: Box[Int]) def map[I <: Int](f: Int => I): Box[I] = new Box(f(box.value))
6+
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import A.Box
2+
import A.map
3+
4+
class B {
5+
val n = Box(5).map(x => x * 3)
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import sbt.internal.inc.Analysis
2+
import complete.DefaultParsers._
3+
4+
// Reset compiler iterations, necessary because tests run in batch mode
5+
val recordPreviousIterations = taskKey[Unit]("Record previous iterations.")
6+
recordPreviousIterations := {
7+
val log = streams.value.log
8+
CompileState.previousIterations = {
9+
val previousAnalysis = (previousCompile in Compile).value.analysis.asScala
10+
previousAnalysis match {
11+
case None =>
12+
log.info("No previous analysis detected")
13+
0
14+
case Some(a: Analysis) => a.compilations.allCompilations.size
15+
}
16+
}
17+
}
18+
19+
val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterations of incremental compilation.")
20+
21+
checkIterations := {
22+
val expected: Int = (Space ~> NatBasic).parsed
23+
val actual: Int = ((compile in Compile).value match { case a: Analysis => a.compilations.allCompilations.size }) - CompileState.previousIterations
24+
assert(expected == actual, s"Expected $expected compilations, got $actual")
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object A {
2+
3+
class Box[T](val value: T)
4+
5+
extension (box: Box[Int]) def map[I](f: Int => I): Box[I] = new Box(f(box.value))
6+
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// This is necessary because tests are run in batch mode
2+
object CompileState {
3+
@volatile var previousIterations: Int = -1
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import sbt._
2+
import Keys._
3+
4+
object DottyInjectedPlugin extends AutoPlugin {
5+
override def requires = plugins.JvmPlugin
6+
override def trigger = allRequirements
7+
8+
override val projectSettings = Seq(
9+
scalaVersion := sys.props("plugin.scalaVersion")
10+
)
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
> compile
2+
> recordPreviousIterations
3+
# Force recompilation of B because A.map, called by B.n, has changed
4+
$ copy-file changes/A1.scala A.scala
5+
> compile
6+
# 1 to recompile A, then 1 more to recompile B due to A.map change
7+
> checkIterations 2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object A {
2+
3+
inline def callInline: Any = B.inlinedAny("yyy")
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object B {
2+
3+
inline def inlinedAny(x: String): x.type = x
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class C {
2+
val n = A.callInline
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import sbt.internal.inc.Analysis
2+
import complete.DefaultParsers._
3+
4+
// Reset compiler iterations, necessary because tests run in batch mode
5+
val recordPreviousIterations = taskKey[Unit]("Record previous iterations.")
6+
recordPreviousIterations := {
7+
val log = streams.value.log
8+
CompileState.previousIterations = {
9+
val previousAnalysis = (previousCompile in Compile).value.analysis.asScala
10+
previousAnalysis match {
11+
case None =>
12+
log.info("No previous analysis detected")
13+
0
14+
case Some(a: Analysis) => a.compilations.allCompilations.size
15+
}
16+
}
17+
}
18+
19+
val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterations of incremental compilation.")
20+
21+
checkIterations := {
22+
val expected: Int = (Space ~> NatBasic).parsed
23+
val actual: Int = ((compile in Compile).value match { case a: Analysis => a.compilations.allCompilations.size }) - CompileState.previousIterations
24+
assert(expected == actual, s"Expected $expected compilations, got $actual")
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object B {
2+
3+
inline def inlinedAny(inline x: String): x.type = x
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// This is necessary because tests are run in batch mode
2+
object CompileState {
3+
@volatile var previousIterations: Int = -1
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import sbt._
2+
import Keys._
3+
4+
object DottyInjectedPlugin extends AutoPlugin {
5+
override def requires = plugins.JvmPlugin
6+
override def trigger = allRequirements
7+
8+
override val projectSettings = Seq(
9+
scalaVersion := sys.props("plugin.scalaVersion")
10+
)
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
> compile
2+
> recordPreviousIterations
3+
# Force recompilation of A because B.inlinedAny, called by A.callInline, has added
4+
# the inline flag to one of its parameters.
5+
$ copy-file changes/B1.scala B.scala
6+
> compile
7+
# 1 to recompile B, then 1 more to recompile A due to B.inlinedAny change,
8+
# then 1 final compilation to recompile C due to A.callInline change
9+
> checkIterations 3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object A {
2+
3+
inline def callInline: Any = B.inlinedAny("yyy")
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object B {
2+
3+
inline def inlinedAny(x: String): x.type = x
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class C {
2+
val n = A.callInline
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import sbt.internal.inc.Analysis
2+
import complete.DefaultParsers._
3+
4+
// Reset compiler iterations, necessary because tests run in batch mode
5+
val recordPreviousIterations = taskKey[Unit]("Record previous iterations.")
6+
recordPreviousIterations := {
7+
val log = streams.value.log
8+
CompileState.previousIterations = {
9+
val previousAnalysis = (previousCompile in Compile).value.analysis.asScala
10+
previousAnalysis match {
11+
case None =>
12+
log.info("No previous analysis detected")
13+
0
14+
case Some(a: Analysis) => a.compilations.allCompilations.size
15+
}
16+
}
17+
}
18+
19+
val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterations of incremental compilation.")
20+
21+
checkIterations := {
22+
val expected: Int = (Space ~> NatBasic).parsed
23+
val actual: Int = ((compile in Compile).value match { case a: Analysis => a.compilations.allCompilations.size }) - CompileState.previousIterations
24+
assert(expected == actual, s"Expected $expected compilations, got $actual")
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object B {
2+
3+
inline def inlinedAny(x: Any): x.type = x
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// This is necessary because tests are run in batch mode
2+
object CompileState {
3+
@volatile var previousIterations: Int = -1
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import sbt._
2+
import Keys._
3+
4+
object DottyInjectedPlugin extends AutoPlugin {
5+
override def requires = plugins.JvmPlugin
6+
override def trigger = allRequirements
7+
8+
override val projectSettings = Seq(
9+
scalaVersion := sys.props("plugin.scalaVersion")
10+
)
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
> compile
2+
> recordPreviousIterations
3+
# Force recompilation of A because B.inlinedAny, called by A.callInline, has changed
4+
# the type of its parameters.
5+
$ copy-file changes/B1.scala B.scala
6+
> compile
7+
# 1 to recompile B, then 1 more to recompile A due to B.inlinedAny change,
8+
# then 1 final compilation to recompile C due to A.callInline change
9+
> checkIterations 3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object A {
2+
3+
inline def callInline: Any = B.inlinedAny("yyy")
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object B {
2+
3+
transparent inline def inlinedAny(x: String): x.type = x
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class C {
2+
val n = A.callInline
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import sbt.internal.inc.Analysis
2+
import complete.DefaultParsers._
3+
4+
// Reset compiler iterations, necessary because tests run in batch mode
5+
val recordPreviousIterations = taskKey[Unit]("Record previous iterations.")
6+
recordPreviousIterations := {
7+
val log = streams.value.log
8+
CompileState.previousIterations = {
9+
val previousAnalysis = (previousCompile in Compile).value.analysis.asScala
10+
previousAnalysis match {
11+
case None =>
12+
log.info("No previous analysis detected")
13+
0
14+
case Some(a: Analysis) => a.compilations.allCompilations.size
15+
}
16+
}
17+
}
18+
19+
val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterations of incremental compilation.")
20+
21+
checkIterations := {
22+
val expected: Int = (Space ~> NatBasic).parsed
23+
val actual: Int = ((compile in Compile).value match { case a: Analysis => a.compilations.allCompilations.size }) - CompileState.previousIterations
24+
assert(expected == actual, s"Expected $expected compilations, got $actual")
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object B {
2+
3+
transparent inline def inlinedAny(x: String): String = x
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// This is necessary because tests are run in batch mode
2+
object CompileState {
3+
@volatile var previousIterations: Int = -1
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import sbt._
2+
import Keys._
3+
4+
object DottyInjectedPlugin extends AutoPlugin {
5+
override def requires = plugins.JvmPlugin
6+
override def trigger = allRequirements
7+
8+
override val projectSettings = Seq(
9+
scalaVersion := sys.props("plugin.scalaVersion")
10+
)
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
> compile
2+
> recordPreviousIterations
3+
# Force recompilation of A because B.inlinedAny, called by A.callInline, has changed
4+
# the type of its result, while being an inline method.
5+
$ copy-file changes/B1.scala B.scala
6+
> compile
7+
# 1 to recompile B, then 1 more to recompile A due to B.inlinedAny change,
8+
# then 1 final compilation to recompile C due to A.callInline change
9+
> checkIterations 3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object A {
2+
3+
inline def callInline: Any = B.inlinedAny("yyy")
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object B {
2+
3+
inline def inlinedAny(x: String): x.type = x
4+
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class C {
2+
val n = A.callInline
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import sbt.internal.inc.Analysis
2+
import complete.DefaultParsers._
3+
4+
// Reset compiler iterations, necessary because tests run in batch mode
5+
val recordPreviousIterations = taskKey[Unit]("Record previous iterations.")
6+
recordPreviousIterations := {
7+
val log = streams.value.log
8+
CompileState.previousIterations = {
9+
val previousAnalysis = (previousCompile in Compile).value.analysis.asScala
10+
previousAnalysis match {
11+
case None =>
12+
log.info("No previous analysis detected")
13+
0
14+
case Some(a: Analysis) => a.compilations.allCompilations.size
15+
}
16+
}
17+
}
18+
19+
val checkIterations = inputKey[Unit]("Verifies the accumulated number of iterations of incremental compilation.")
20+
21+
checkIterations := {
22+
val expected: Int = (Space ~> NatBasic).parsed
23+
val actual: Int = ((compile in Compile).value match { case a: Analysis => a.compilations.allCompilations.size }) - CompileState.previousIterations
24+
assert(expected == actual, s"Expected $expected compilations, got $actual")
25+
}

0 commit comments

Comments
 (0)