Skip to content

Commit 221fc71

Browse files
authored
Merge pull request #14050 from dotty-staging/fix-13994-initial
fix #13994: initialise inline ctx in lateEnter
2 parents 6e58ccb + 0d7b645 commit 221fc71

File tree

10 files changed

+118
-25
lines changed

10 files changed

+118
-25
lines changed

compiler/src/dotty/tools/dotc/Run.scala

+8-16
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Types._
99
import Scopes._
1010
import Names.Name
1111
import Denotations.Denotation
12-
import typer.Typer
12+
import typer.{Typer, PrepareInlineable}
1313
import typer.ImportInfo._
1414
import Decorators._
1515
import io.{AbstractFile, PlainFile, VirtualFile}
@@ -23,8 +23,6 @@ import rewrites.Rewrites
2323

2424
import profile.Profiler
2525
import printing.XprintMode
26-
import parsing.Parsers.Parser
27-
import parsing.JavaParsers.JavaParser
2826
import typer.ImplicitRunInfo
2927
import config.Feature
3028
import StdNames.nme
@@ -302,19 +300,13 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
302300
.setCompilationUnit(unit)
303301
.withRootImports
304302

305-
def process()(using Context) = {
306-
unit.untpdTree =
307-
if (unit.isJava) new JavaParser(unit.source).parse()
308-
else new Parser(unit.source).parse()
309-
ctx.typer.lateEnter(unit.untpdTree)
310-
def processUnit() = {
311-
unit.tpdTree = ctx.typer.typedExpr(unit.untpdTree)
312-
val phase = new transform.SetRootTree()
313-
phase.run
314-
}
315-
if (typeCheck)
316-
if (compiling) finalizeActions += (() => processUnit()) else processUnit()
317-
}
303+
def process()(using Context) =
304+
ctx.typer.lateEnterUnit(doTypeCheck =>
305+
if typeCheck then
306+
if compiling then finalizeActions += doTypeCheck
307+
else doTypeCheck()
308+
)
309+
318310
process()(using unitCtx)
319311
}
320312

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

+39-8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import tpd.tpes
1818
import Variances.alwaysInvariant
1919
import config.{Config, Feature}
2020
import config.Printers.typr
21+
import parsing.JavaParsers.JavaParser
22+
import parsing.Parsers.Parser
2123
import Annotations._
2224
import Inferencing._
2325
import transform.ValueClasses._
@@ -708,15 +710,44 @@ class Namer { typer: Typer =>
708710
ctxWithStats
709711
}
710712

711-
/** Index symbols in `tree` while asserting the `lateCompile` flag.
712-
* This will cause any old top-level symbol with the same fully qualified
713-
* name as a newly created symbol to be replaced.
713+
/** Parse the source and index symbols in the compilation unit's untpdTree
714+
* while asserting the `lateCompile` flag. This will cause any old
715+
* top-level symbol with the same fully qualified name as a newly created
716+
* symbol to be replaced.
717+
*
718+
* Will call the callback with an implementation of type checking
719+
* That will set the tpdTree and root tree for the compilation unit.
714720
*/
715-
def lateEnter(tree: Tree)(using Context): Context = {
716-
val saved = lateCompile
717-
lateCompile = true
718-
try index(tree :: Nil) finally lateCompile = saved
719-
}
721+
def lateEnterUnit(typeCheckCB: (() => Unit) => Unit)(using Context) =
722+
val unit = ctx.compilationUnit
723+
724+
/** Index symbols in unit.untpdTree with lateCompile flag = true */
725+
def lateEnter()(using Context): Context =
726+
val saved = lateCompile
727+
lateCompile = true
728+
try index(unit.untpdTree :: Nil) finally lateCompile = saved
729+
730+
/** Set the tpdTree and root tree of the compilation unit */
731+
def lateTypeCheck()(using Context) =
732+
unit.tpdTree = typer.typedExpr(unit.untpdTree)
733+
val phase = new transform.SetRootTree()
734+
phase.run
735+
736+
unit.untpdTree =
737+
if (unit.isJava) new JavaParser(unit.source).parse()
738+
else new Parser(unit.source).parse()
739+
740+
atPhase(Phases.typerPhase) {
741+
inContext(PrepareInlineable.initContext(ctx)) {
742+
// inline body annotations are set in namer, capturing the current context
743+
// we need to prepare the context for inlining.
744+
lateEnter()
745+
typeCheckCB { () =>
746+
lateTypeCheck()
747+
}
748+
}
749+
}
750+
end lateEnterUnit
720751

721752
/** The type bound on wildcard imports of an import list, with special values
722753
* Nothing if no wildcard imports of this kind exist

project/scripts/bootstrapCmdTests

+20
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,23 @@ clear_out "$OUT"
8787
./bin/scalac -d "$OUT/out.jar" tests/pos/i12973.scala
8888
echo "Bug12973().check" | TERM=dumb ./bin/scala -cp "$OUT/out.jar" > "$tmp" 2>&1
8989
grep -qe "Bug12973 is fixed" "$tmp"
90+
91+
echo "capturing scala version from dist/target/pack/VERSION"
92+
cwd=$(pwd)
93+
IFS=':=' read -ra versionProps < "$cwd/dist/target/pack/VERSION" # temporarily set IFS to ':=' to split versionProps
94+
[ ${#versionProps[@]} -eq 3 ] && \
95+
[ ${versionProps[0]} = "version" ] && \
96+
[ -n ${versionProps[2]} ] || die "Expected non-empty 'version' property in $cwd/dist/target/pack/VERSION"
97+
scala_version=${versionProps[2]}
98+
99+
echo "testing -sourcepath with inlining"
100+
# Here we will test that an inline method symbol loaded from the sourcepath (-sourcepath compiler option)
101+
# will have its `defTree` correctly set when its method body is required for inlining.
102+
# So far I have not found a way to replicate issue https://github.com/lampepfl/dotty/issues/13994
103+
# with sbt scripted tests, if a way is found, move this test there.
104+
cwd=$(pwd)
105+
sbt_test_command="++${scala_version}!;clean;prepareSources;compile;copyChanges;compile"
106+
(cd "$cwd/tests/cmdTest-sbt-tests/sourcepath-with-inline" && "$SBT" "$sbt_test_command")
107+
rm -rf "$cwd/tests/cmdTest-sbt-tests/sourcepath-with-inline/target"
108+
rm -rf "$cwd/tests/cmdTest-sbt-tests/sourcepath-with-inline/project/target"
109+
rm -f "$cwd/tests/cmdTest-sbt-tests/sourcepath-with-inline/src/main/scala/a/zz.scala"

project/scripts/cmdTestsCommon.inc.sh

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
set -eux
22

3-
SBT="./project/scripts/sbt" # if run on CI
3+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" >& /dev/null && pwd)/../.."
4+
5+
SBT="$ROOT/project/scripts/sbt" # if run on CI
46
# SBT="sbt" # if run locally
57

68
SOURCE="tests/pos/HelloWorld.scala"
@@ -12,6 +14,11 @@ OUT=$(mktemp -d)
1214
OUT1=$(mktemp -d)
1315
tmp=$(mktemp)
1416

17+
die () {
18+
echo >&2 "$@"
19+
exit 1
20+
}
21+
1522
clear_out()
1623
{
1724
local out="$1"

tests/cmdTest-sbt-tests/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Readme
2+
3+
Do not use this directory for testing sbt projects in general, add a test case to `dotty/sbt-test`
4+
5+
This directory is for sbt tests that can not be reproduced with sbt scripted tests.
6+
7+
Adding a test here will reduce the performance of running all tests.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import java.util.Properties
2+
3+
val prepareSources = taskKey[Unit]("Copy changes to the src directory")
4+
val copyChanges = taskKey[Unit]("Copy changes to the src directory")
5+
6+
val srcDir = settingKey[File]("The directory to copy changes to")
7+
val changesDir = settingKey[File]("The directory to copy changes from")
8+
9+
srcDir := (ThisBuild / baseDirectory).value / "src" / "main" / "scala"
10+
changesDir := (ThisBuild / baseDirectory).value / "changes"
11+
12+
prepareSources := IO.copyFile(changesDir.value / "zz.original.scala", srcDir.value / "a" / "zz.scala")
13+
copyChanges := IO.copyFile(changesDir.value / "zz.new.scala", srcDir.value / "a" / "zz.scala")
14+
15+
(Compile / scalacOptions) ++= Seq(
16+
"-sourcepath", (Compile / sourceDirectories).value.map(_.getAbsolutePath).distinct.mkString(java.io.File.pathSeparator),
17+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package a
2+
3+
object Foo: // note that `Foo` is defined in `zz.scala`
4+
class Local
5+
inline def foo(using Local): Nothing =
6+
???
7+
???
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package a
2+
3+
object Foo: // note that `Foo` is defined in `zz.scala`
4+
class Local
5+
inline def foo(using Local): Nothing =
6+
???
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sbt.version=1.5.5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package a
2+
3+
object Bar:
4+
given Foo.Local()
5+
def Bar = Foo.foo

0 commit comments

Comments
 (0)