From 4ebccb09d37a9bd69684758186f1a8e579047b28 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Fri, 14 Nov 2025 13:11:24 +0100 Subject: [PATCH 1/3] Setup `doc / scalaInstance` instance to be used when building docs. Enable `packageDoc / publishArtifact` for bootstrapped projects - javadoc is required by Sonatype validation --- project/Build.scala | 59 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 33e74fea44fc..4e1f49913f24 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -198,12 +198,12 @@ object Build { "-encoding", "UTF8", "-language:implicitConversions", s"--java-output-version:${Versions.minimumJVMVersion}", - "-Yexplicit-nulls", + "-Yexplicit-nulls", "-Wsafe-init" ), (Compile / compile / javacOptions) ++= Seq( - "-Xlint:unchecked", + "-Xlint:unchecked", "-Xlint:deprecation", "--release", Versions.minimumJVMVersion ), @@ -448,6 +448,34 @@ object Build { ) ++ extMap } + // Setups up doc / scalaInstance to use in the bootstrapped projects instead of the default one + lazy val scaladocDerivedInstanceSettings = Def.settings( + // We cannot include scaladoc in the regular `scalaInstance` task because + // it's a bootstrapped-only project, so we would run into a loop since we + // need the output of that task to compile scaladoc. But we can include it + // in the `scalaInstance` of the `doc` task which allows us to run + // `scala3-library-bootstrapped/doc` for example. + doc / scalaInstance := { + val externalDeps = (LocalProject("scaladoc-new") / Compile / externalDependencyClasspath).value.map(_.data) + val scalaDoc = (LocalProject("scaladoc-new") / Compile / packageBin).value + val docJars = Array(scalaDoc) ++ externalDeps + + val base = scalaInstance.value + val docScalaInstance = Defaults.makeScalaInstance( + version = base.version, + libraryJars = base.libraryJars, + allCompilerJars = base.compilerJars, + allDocJars = docJars, + state.value, + scalaInstanceTopLoader.value + ) + // assert that sbt reuses the same compiler class loader + assert(docScalaInstance.loaderCompilerOnly == base.loaderCompilerOnly) + docScalaInstance + }, + Compile / doc / scalacOptions ++= scalacOptionsDocSettings(), + ) + // Settings used when compiling dotty with a non-bootstrapped dotty lazy val commonBootstrappedSettings = commonDottySettings ++ Seq( // To enable support of scaladoc and language-server projects you need to change this to true @@ -931,7 +959,7 @@ object Build { ), // Packaging configuration of `scala3-sbt-bridge` Compile / packageBin / publishArtifact := true, - Compile / packageDoc / publishArtifact := false, + Compile / packageDoc / publishArtifact := true, Compile / packageSrc / publishArtifact := true, // Only publish compilation artifacts, no test artifacts Test / publishArtifact := false, @@ -963,6 +991,7 @@ object Build { scalaInstanceTopLoader.value ) }, + scaladocDerivedInstanceSettings, scalaCompilerBridgeBinaryJar := { Some((`scala3-sbt-bridge-nonbootstrapped` / Compile / packageBin).value) }, @@ -989,7 +1018,7 @@ object Build { Test / unmanagedSourceDirectories := Seq(baseDirectory.value / "test"), // Packaging configuration of `scala3-staging` Compile / packageBin / publishArtifact := true, - Compile / packageDoc / publishArtifact := false, + Compile / packageDoc / publishArtifact := true, Compile / packageSrc / publishArtifact := true, // Only publish compilation artifacts, no test artifacts Test / publishArtifact := false, @@ -1018,6 +1047,7 @@ object Build { scalaInstanceTopLoader.value ) }, + scaladocDerivedInstanceSettings, scalaCompilerBridgeBinaryJar := { Some((`scala3-sbt-bridge-nonbootstrapped` / Compile / packageBin).value) }, @@ -1045,7 +1075,7 @@ object Build { // Make sure that the produced artifacts have the minimum JVM version in the bytecode // Packaging configuration of `scala3-staging` Compile / packageBin / publishArtifact := true, - Compile / packageDoc / publishArtifact := false, + Compile / packageDoc / publishArtifact := true, Compile / packageSrc / publishArtifact := true, // Only publish compilation artifacts, no test artifacts Test / publishArtifact := false, @@ -1074,6 +1104,7 @@ object Build { scalaInstanceTopLoader.value ) }, + scaladocDerivedInstanceSettings, scalaCompilerBridgeBinaryJar := { Some((`scala3-sbt-bridge-nonbootstrapped` / Compile / packageBin).value) }, @@ -1098,7 +1129,7 @@ object Build { Test / unmanagedResourceDirectories := Seq(baseDirectory.value / "test-resources"), // Packaging configuration of `scala3-staging` Compile / packageBin / publishArtifact := true, - Compile / packageDoc / publishArtifact := false, + Compile / packageDoc / publishArtifact := true, Compile / packageSrc / publishArtifact := true, // Only publish compilation artifacts, no test artifacts Test / publishArtifact := false, @@ -1138,6 +1169,7 @@ object Build { scalaInstanceTopLoader.value ) }, + scaladocDerivedInstanceSettings, scalaCompilerBridgeBinaryJar := { Some((`scala3-sbt-bridge-nonbootstrapped` / Compile / packageBin).value) }, @@ -1299,7 +1331,7 @@ object Build { ), // Packaging configuration of the stdlib Compile / packageBin / publishArtifact := true, - Compile / packageDoc / publishArtifact := false, + Compile / packageDoc / publishArtifact := true, Compile / packageSrc / publishArtifact := true, // Only publish compilation artifacts, no test artifacts Test / publishArtifact := false, @@ -1332,6 +1364,7 @@ object Build { scalaInstanceTopLoader.value ) }, + scaladocDerivedInstanceSettings, scalaCompilerBridgeBinaryJar := { Some((`scala3-sbt-bridge-nonbootstrapped` / Compile / packageBin).value) }, @@ -1436,7 +1469,7 @@ object Build { }, // Packaging configuration of the stdlib Compile / packageBin / publishArtifact := true, - Compile / packageDoc / publishArtifact := false, + Compile / packageDoc / publishArtifact := true, Compile / packageSrc / publishArtifact := true, // Only publish compilation artifacts, no test artifacts Test / publishArtifact := false, @@ -1497,6 +1530,7 @@ object Build { scalaInstanceTopLoader.value ) }, + scaladocDerivedInstanceSettings, scalaCompilerBridgeBinaryJar := { Some((`scala3-sbt-bridge-nonbootstrapped` / Compile / packageBin).value) }, @@ -1647,7 +1681,7 @@ object Build { ), // Packaging configuration of the stdlib Compile / packageBin / publishArtifact := true, - Compile / packageDoc / publishArtifact := false, + Compile / packageDoc / publishArtifact := true, Compile / packageSrc / publishArtifact := true, // Only publish compilation artifacts, no test artifacts Test / publishArtifact := false, @@ -1679,6 +1713,7 @@ object Build { scalaInstanceTopLoader.value ) }, + scaladocDerivedInstanceSettings, scalaCompilerBridgeBinaryJar := { Some((`scala3-sbt-bridge-nonbootstrapped` / Compile / packageBin).value) }, @@ -1871,7 +1906,7 @@ object Build { packageOptions += ManifestAttributes(("Git-Hash", VersionUtil.gitHash)), // Used by the REPL // Packaging configuration of the stdlib Compile / packageBin / publishArtifact := true, - Compile / packageDoc / publishArtifact := false, + Compile / packageDoc / publishArtifact := true, Compile / packageSrc / publishArtifact := true, // Only publish compilation artifacts, no test artifacts Test / publishArtifact := false, @@ -1905,6 +1940,7 @@ object Build { scalaInstanceTopLoader.value ) }, + scaladocDerivedInstanceSettings, scalaCompilerBridgeBinaryJar := { Some((`scala3-sbt-bridge-nonbootstrapped` / Compile / packageBin).value) }, @@ -2019,7 +2055,7 @@ object Build { Compile / scalacOptions += "-experimental", // Packaging configuration of the stdlib Compile / packageBin / publishArtifact := true, - Compile / packageDoc / publishArtifact := false, + Compile / packageDoc / publishArtifact := true, Compile / packageSrc / publishArtifact := true, // Only publish compilation artifacts, no test artifacts Test / publishArtifact := false, @@ -2033,6 +2069,7 @@ object Build { BuildInfoPlugin.buildInfoDefaultSettings, // Configure to use the non-bootstrapped compiler managedScalaInstance := false, + scaladocDerivedInstanceSettings, scalaInstance := { val externalCompilerDeps = (`scala3-compiler-nonbootstrapped` / Compile / externalDependencyClasspath).value.map(_.data).toSet From 26440da27c1b46b6b0b1b446515e867015e64ab0 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sun, 23 Nov 2025 15:40:44 +0100 Subject: [PATCH 2/3] Enable scala-library-bootstrapped docs generation again --- project/Build.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/project/Build.scala b/project/Build.scala index 4e1f49913f24..f3139bd5b399 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1305,7 +1305,6 @@ object Build { lazy val `scala-library-bootstrapped` = project.in(file("library")) .enablePlugins(ScalaLibraryPlugin) .settings(publishSettings) - .settings(disableDocSetting) // TODO now produces empty JAR to satisfy Sonatype, see https://github.com/scala/scala3/issues/24434 .settings( name := "scala-library-bootstrapped", moduleName := "scala-library", From ae78649adaf330261952ea1e526d57cd4c2e87d8 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sun, 23 Nov 2025 15:46:17 +0100 Subject: [PATCH 3/3] Adjust assertions and errors to be more relaxed under --from-tasty compilation (Mode.ReadPositions) --- compiler/src/dotty/tools/dotc/ast/TreeInfo.scala | 4 ++-- compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala | 2 +- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Checking.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Implicits.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 8c6303d07b9a..64cab1b76b95 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -1012,12 +1012,12 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => else cpy.PackageDef(tree)(pid, slicedStats) :: Nil case tdef: TypeDef => val sym = tdef.symbol - assert(sym.isClass || ctx.tolerateErrorsForBestEffort) + assert(sym.isClass || ctx.tolerateErrorsForBestEffort || ctx.mode.is(Mode.ReadPositions)) if (cls == sym || cls == sym.linkedClass) tdef :: Nil else Nil case vdef: ValDef => val sym = vdef.symbol - assert(sym.is(Module) || ctx.tolerateErrorsForBestEffort) + assert(sym.is(Module) || ctx.tolerateErrorsForBestEffort || ctx.mode.is(Mode.ReadPositions)) if (cls == sym.companionClass || cls == sym.moduleClass) vdef :: Nil else Nil case tree => diff --git a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala index 9ddcb7cce332..0f6377c4869e 100644 --- a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala +++ b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala @@ -113,7 +113,7 @@ object CheckCaptures: if refSym.isType && !refSym.info.derivesFrom(defn.Caps_CapSet) then report.error(em"$elem is not a legal element of a capture set", ann.srcPos) case ref: CoreCapability => - if !ref.isTrackableRef && !ref.isCapRef then + if !ref.isTrackableRef && !ref.isCapRef && !ctx.mode.is(Mode.ReadPositions) then report.error(em"$elem cannot be tracked since it is not a parameter or local value", ann.srcPos) case ReachCapability(ref) => check(ref) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 3b198ea4dbaa..3ef50b8fa423 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -2053,7 +2053,7 @@ object SymDenotations { case p :: parents1 => p.classSymbol match { case pcls: ClassSymbol => builder.addAll(pcls.baseClasses) - case _ => assert(isRefinementClass || p.isError || ctx.mode.is(Mode.Interactive) || ctx.tolerateErrorsForBestEffort, s"$this has non-class parent: $p") + case _ => assert(isRefinementClass || p.isError || ctx.mode.is(Mode.Interactive) || ctx.tolerateErrorsForBestEffort || ctx.mode.is(Mode.ReadPositions), s"$this has non-class parent: $p") } traverse(parents1) case nil => diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 7f52c871f9de..328cc001766c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -1687,7 +1687,7 @@ trait Checking { val tname = sym.targetName if tname != sym.name then val preExisting = ctx.effectiveScope.lookup(tname) - if preExisting.exists || seen.contains(tname) then + if (preExisting.exists || seen.contains(tname)) && !ctx.mode.is(Mode.ReadPositions) then report.error(em"@targetName annotation ${'"'}$tname${'"'} clashes with other definition in same scope", stat.srcPos) if stat.isDef then seen += tname diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 8b4e00a11d35..43e1068e3876 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1098,7 +1098,7 @@ trait Implicits: def inferImplicit(pt: Type, argument: Tree, span: Span, ignored: Set[Symbol] = Set.empty)(using Context): SearchResult = ctx.profiler.onImplicitSearch(pt): trace(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) { record("inferImplicit") - assert(ctx.phase.allowsImplicitSearch, + assert(ctx.phase.allowsImplicitSearch || ctx.mode.is(Mode.ReadPositions), if (argument.isEmpty) i"missing implicit parameter of type $pt after typer at phase ${ctx.phase}" else i"type error: ${argument.tpe} does not conform to $pt${err.whyNoMatchStr(argument.tpe, pt)}") diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f2e7e4a2c07c..484eb9fac27f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3287,7 +3287,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer selfType.member(decl.name).symbol.filter(other => other.isClass && other.owner != cls) decls.iterator.filter(_.isType).foldLeft(false) { (foundRedef, decl) => val other = memberInSelfButNotThis(decl) - if (other.exists) { + if (other.exists && !ctx.mode.is(Mode.ReadPositions)) { val msg = CannotHaveSameNameAs(decl, other, CannotHaveSameNameAs.DefinedInSelf(self)) report.error(msg, decl.srcPos) }