Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/MainGenericCompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ case class CompileSettings(

object MainGenericCompiler {

val classpathSeparator = File.pathSeparator
val classpathSeparator: String = File.pathSeparator

@sharable val javaOption = raw"""-J(.*)""".r
@sharable val javaPropOption = raw"""-D(.+?)=(.?)""".r
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/MainGenericRunner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ case class Settings(

object MainGenericRunner {

val classpathSeparator = File.pathSeparator
val classpathSeparator: String = File.pathSeparator

def processClasspath(cp: String, tail: List[String]): (List[String], List[String]) =
val cpEntries = cp.split(classpathSeparator).toList
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/backend/jvm/CodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)(
new interfaces.AbstractFile {
override def name = absfile.name
override def path = absfile.path
override def jfile = Optional.ofNullable(absfile.file)
override def jfile: Optional[java.io.File] = Optional.ofNullable(absfile.file)
}

private def genClass(cd: TypeDef, unit: CompilationUnit): ClassNode = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class InteractiveDriver(val settings: List[String]) extends Driver {
private def classesFromDir(dir: Path, buffer: mutable.ListBuffer[TypeName]): Unit =
try
Files.walkFileTree(dir, new SimpleFileVisitor[Path] {
override def visitFile(path: Path, attrs: BasicFileAttributes) = {
override def visitFile(path: Path, attrs: BasicFileAttributes): FileVisitResult = {
if (!attrs.isDirectory) {
val name = path.getFileName.toString
if name.endsWith(tastySuffix) then
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/sbt/APIUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import xsbti.api.SafeLazy.strict
*/
object APIUtils {
private object Constants {
val PublicAccess = api.Public.create()
val EmptyModifiers = new api.Modifiers(false, false, false, false, false, false, false, false)
val EmptyStructure = api.Structure.of(strict(Array.empty), strict(Array.empty), strict(Array.empty))
val EmptyType = api.EmptyType.of()
val PublicAccess: api.Public = api.Public.create()
val EmptyModifiers: api.Modifiers = new api.Modifiers(false, false, false, false, false, false, false, false)
val EmptyStructure: api.Structure = api.Structure.of(strict(Array.empty), strict(Array.empty), strict(Array.empty))
val EmptyType: api.EmptyType = api.EmptyType.of()
}

import Constants.*
Expand Down
14 changes: 7 additions & 7 deletions compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,13 @@ private class ExtractAPICollector(nonLocalClassSymbols: mutable.HashSet[Symbol])

private object Constants {
val emptyStringArray = Array[String]()
val local = api.ThisQualifier.create()
val public = api.Public.create()
val privateLocal = api.Private.create(local)
val protectedLocal = api.Protected.create(local)
val unqualified = api.Unqualified.create()
val thisPath = api.This.create()
val emptyType = api.EmptyType.create()
val local: api.ThisQualifier = api.ThisQualifier.create()
val public: api.Public = api.Public.create()
val privateLocal: api.Private = api.Private.create(local)
val protectedLocal: api.Protected = api.Protected.create(local)
val unqualified: api.Unqualified = api.Unqualified.create()
val thisPath: api.This = api.This.create()
val emptyType: api.EmptyType = api.EmptyType.create()
val emptyModifiers =
new api.Modifiers(false, false, false, false, false,false, false, false)
}
Expand Down
25 changes: 22 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3089,13 +3089,32 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
//todo: make sure dependent method types do not depend on implicits or by-name params
}

/** (1) Check that the signature of the class member does not return a repeated parameter type
* (2) Make sure the definition's symbol is `sym`.
* (3) Set the `defTree` of `sym` to be `mdef`.
/** (1) Check that the signature of the class member does not return a repeated parameter type.
* (2) Check that the signature of the public class member does not expose a flexible type.
* (3) Make sure the definition's symbol is `sym`.
* (4) Set the `defTree` of `sym` to be `mdef`.
*/
private def postProcessInfo(mdef: MemberDef, sym: Symbol)(using Context): MemberDef =
if (!sym.isOneOf(Synthetic | InlineProxy | Param) && sym.info.finalResultType.isRepeatedParam)
report.error(em"Cannot return repeated parameter type ${sym.info.finalResultType}", sym.srcPos)

// Warn if a public method/field exposes FlexibleType in its result type under explicit nulls
// and encourage explicit annotation.
if ctx.phase.isTyper && ctx.explicitNulls && !ctx.isJava
&& sym.exists && sym.isPublic && sym.owner.isClass
&& !sym.isOneOf(Synthetic | InlineProxy | Param) then
Copy link
Preview

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

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

[nitpick] The complex conditional logic spans multiple lines without clear grouping. Consider extracting this logic into a helper method like shouldWarnForFlexibleType(sym: Symbol, ctx: Context) to improve readability and testability.

Copilot uses AI. Check for mistakes.

val resTp = sym.info.finalResultType
if resTp.existsPart(_.isInstanceOf[FlexibleType], StopAt.Static) then
val suggestion = resTp match
case ft: FlexibleType =>
val hi = ft.hi
i"Consider annotating the type as ${hi} or ${hi} | Null explicitly"
case _ => "Consider annotating the type explicitly"
report.warning(
em"Public ${sym.show} exposes a flexible type ${resTp} in its inferred signature. $suggestion",
sym.srcPos
)

mdef.ensureHasSym(sym)
mdef.setDefTree

Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/io/Path.scala
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,12 @@ class Path private[io] (val jpath: JPath) {
if (!exists) false
else {
Files.walkFileTree(jpath, new SimpleFileVisitor[JPath]() {
override def visitFile(file: JPath, attrs: BasicFileAttributes) = {
override def visitFile(file: JPath, attrs: BasicFileAttributes): FileVisitResult = {
Files.delete(file)
FileVisitResult.CONTINUE
}

override def postVisitDirectory(dir: JPath, exc: IOException) = {
override def postVisitDirectory(dir: JPath, exc: IOException): FileVisitResult = {
Files.delete(dir)
FileVisitResult.CONTINUE
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/repl/JLineTerminal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class JLineTerminal extends java.io.Closeable {
) extends reader.ParsedLine {
// Using dummy values, not sure what they are used for
def wordIndex = -1
def words = java.util.Collections.emptyList[String]
def words: java.util.List[String] = java.util.Collections.emptyList[String]
}

def parse(input: String, cursor: Int, context: ParseContext): reader.ParsedLine = {
Expand Down
13 changes: 7 additions & 6 deletions compiler/src/dotty/tools/repl/ScriptEngine.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,21 @@ class ScriptEngine extends AbstractScriptEngine {

object ScriptEngine {
import java.util.Arrays
import java.util.List
Copy link
Preview

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

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

The import for java.util.List is added but the existing java.util.Arrays import already covers the usage. This creates redundant imports that could be consolidated.

Suggested change
import java.util.List

Copilot uses AI. Check for mistakes.

import scala.util.Properties

class Factory extends ScriptEngineFactory {
def getEngineName = "Scala REPL"
def getEngineVersion = "3.0"
def getExtensions = Arrays.asList("scala")
def getExtensions: List[String] = Arrays.asList("scala")
def getLanguageName = "Scala"
def getLanguageVersion = Properties.versionString
def getMimeTypes = Arrays.asList("application/x-scala")
def getNames = Arrays.asList("scala")
def getMimeTypes: List[String] = Arrays.asList("application/x-scala")
def getNames: List[String] = Arrays.asList("scala")

def getMethodCallSyntax(obj: String, m: String, args: String*) = s"$obj.$m(${args.mkString(", ")})"
def getMethodCallSyntax(obj: String, m: String, args: String*): String = s"$obj.$m(${args.mkString(", ")})"

def getOutputStatement(toDisplay: String) = s"""print("$toDisplay")"""
def getOutputStatement(toDisplay: String): String = s"""print("$toDisplay")"""

def getParameter(key: String): Object = key match {
case JScriptEngine.ENGINE => getEngineName
Expand All @@ -88,7 +89,7 @@ object ScriptEngine {
case _ => null
}

def getProgram(statements: String*) = statements.mkString("; ")
def getProgram(statements: String*): String = statements.mkString("; ")

def getScriptEngine: JScriptEngine = new ScriptEngine
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ object BestEffortTastyFormat {
// added AST tag - Best Effort TASTy only
final val ERRORtype = 50

def astTagToString(tag: Int) = tag match {
def astTagToString(tag: Int): String = tag match {
case ERRORtype => "ERRORtype"
case _ => TastyFormat.astTagToString(tag)
}
Expand Down
22 changes: 13 additions & 9 deletions compiler/test/dotty/tools/dotc/TupleShowTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,24 +54,28 @@ class TupleShowTests extends DottyTest:

@Test def tup3_show10 = chkEq("(Int,\n Long,\n Short)".normEOL, tup3.toText(ctx.printer).mkString(10, false))

val res21 = """|(Int, Int, Int, Int, Int, Long, Long, Long, Long, Long, Int, Int, Int, Int,
| Int, Long, Long, Long, Long, Long, Int)""".stripMargin.normEOL
val res21: String =
"""|(Int, Int, Int, Int, Int, Long, Long, Long, Long, Long, Int, Int, Int, Int,
| Int, Long, Long, Long, Long, Long, Int)""".stripMargin.normEOL

val res22 = """|(Int, Int, Int, Int, Int, Long, Long, Long, Long, Long, Int, Int, Int, Int,
| Int, Long, Long, Long, Long, Long, Int, Long)""".stripMargin.normEOL
val res22: String =
"""|(Int, Int, Int, Int, Int, Long, Long, Long, Long, Long, Int, Int, Int, Int,
| Int, Long, Long, Long, Long, Long, Int, Long)""".stripMargin.normEOL

val res23 = """|(Int, Int, Int, Int, Int, Long, Long, Long, Long, Long, Int, Int, Int, Int,
| Int, Long, Long, Long, Long, Long, Int, Long, Short)""".stripMargin.normEOL
val res23: String =
"""|(Int, Int, Int, Int, Int, Long, Long, Long, Long, Long, Int, Int, Int, Int,
| Int, Long, Long, Long, Long, Long, Int, Long, Short)""".stripMargin.normEOL

val res24 = """|(Int, Int, Int, Int, Int, Long, Long, Long, Long, Long, Int, Int, Int, Int,
| Int, Long, Long, Long, Long, Long, Int, Long, Short, Short)""".stripMargin.normEOL
val res24: String =
"""|(Int, Int, Int, Int, Int, Long, Long, Long, Long, Long, Int, Int, Int, Int,
| Int, Long, Long, Long, Long, Long, Int, Long, Short, Short)""".stripMargin.normEOL

def chkEq[A](expected: A, obtained: A) = assert(expected == obtained, diff(s"$expected", s"$obtained"))

/** On Windows the string literal in this test source file will be read with `\n` (b/c of "-encoding UTF8")
* but the compiler will correctly emit \r\n as the line separator.
* So we align the expected result to faithfully compare test results. */
extension (str: String) def normEOL = if EOL == "\n" then str else str.replace("\n", EOL)
extension (str: String) def normEOL: String = if EOL == "\n" then str else str.replace("\n", EOL)

def diff(exp: String, obt: String) =
val min = math.min(exp.length, obt.length)
Expand Down
16 changes: 8 additions & 8 deletions compiler/test/dotty/tools/dotc/semanticdb/SemanticdbTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import dotty.tools.dotc.util.SourceFile
* only 1 semanticdb file should be present
* @param source the single source file producing the semanticdb
*/
@main def metac(root: String, source: String) =
@main def metac(root: String, source: String): Unit =
val rootSrc = Paths.get(root)
val sourceSrc = Paths.get(source)
val semanticFile = FileSystems.getDefault.getPathMatcher("glob:**.semanticdb")
Expand All @@ -53,13 +53,13 @@ import dotty.tools.dotc.util.SourceFile

@Category(Array(classOf[BootstrappedOnlyTests]))
class SemanticdbTests:
val javaFile = FileSystems.getDefault.getPathMatcher("glob:**.java")
val scalaFile = FileSystems.getDefault.getPathMatcher("glob:**.scala")
val expectFile = FileSystems.getDefault.getPathMatcher("glob:**.expect.scala")
val rootSrc = Paths.get(System.getProperty("dotty.tools.dotc.semanticdb.test"))
val expectSrc = rootSrc.resolve("expect")
val javaRoot = rootSrc.resolve("javacp")
val metacExpectFile = rootSrc.resolve("metac.expect")
val javaFile: PathMatcher = FileSystems.getDefault.getPathMatcher("glob:**.java")
val scalaFile: PathMatcher = FileSystems.getDefault.getPathMatcher("glob:**.scala")
val expectFile: PathMatcher = FileSystems.getDefault.getPathMatcher("glob:**.expect.scala")
val rootSrc: Path = Paths.get(System.getProperty("dotty.tools.dotc.semanticdb.test"))
val expectSrc: Path = rootSrc.resolve("expect")
val javaRoot: Path = rootSrc.resolve("javacp")
val metacExpectFile: Path = rootSrc.resolve("metac.expect")

@Category(Array(classOf[dotty.SlowTests]))
@Test def expectTests: Unit = if (!scala.util.Properties.isWin) runExpectTest(updateExpectFiles = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AbstractFileClassLoaderTest:
// cf ScalaClassLoader#classBytes
extension (loader: ClassLoader)
// An InputStream representing the given class name, or null if not found.
def classAsStream(className: String) = loader.getResourceAsStream {
def classAsStream(className: String): InputStream = loader.getResourceAsStream {
if className.endsWith(".class") then className
else s"${className.replace('.', '/')}.class" // classNameToPath
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/test/dotty/tools/scripting/ScriptTestEnv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ object ScriptTestEnv {
}

extension(f: File) {
def name = f.getName
def name: String = f.getName
def norm: String = f.toPath.normalize.norm
def absPath: String = f.getAbsolutePath.norm
def relpath: Path = f.toPath.relpath
Expand All @@ -305,7 +305,7 @@ object ScriptTestEnv {
// dist[*]/target/universal/stage, if present
// else, SCALA_HOME if defined
// else, not defined
lazy val envScalaHome =
lazy val envScalaHome: String =
printf("scalacPath: %s\n", scalacPath.norm)
if scalacPath.isFile then scalacPath.replaceAll("/bin/scalac", "")
else envOrElse("SCALA_HOME", "not-found").norm
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/dotty/tools/utils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def scriptsDir(path: String): File = {
dir
}

extension (f: File) def absPath =
extension (f: File) def absPath: String =
f.getAbsolutePath.replace('\\', '/')

extension (str: String) def dropExtension =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class InferExpectedType(
driver: InteractiveDriver,
params: OffsetParams
)(implicit rc: ReportContext):
val uri = params.uri().nn
val code = params.text().nn
val uri: java.net.URI = params.uri()
val code: String = params.text()

val sourceFile = SourceFile.virtual(uri, code)
driver.run(uri, sourceFile)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ class PcInlayHintsProvider(
symbolSearch: SymbolSearch,
)(using ReportContext):

val uri = params.uri().nn
val filePath = Paths.get(uri).nn
val sourceText = params.text().nn
val text = sourceText.toCharArray().nn
val source =
val uri: java.net.URI = params.uri()
val filePath: java.nio.file.Path = Paths.get(uri)
val sourceText: String = params.text()
val text: Array[Char] = sourceText.toCharArray()
val source: SourceFile =
SourceFile.virtual(filePath.toString, sourceText)
driver.run(uri, source)
given InlayHintsParams = params
Expand Down Expand Up @@ -119,7 +119,7 @@ class PcInlayHintsProvider(
InlayHintKind.Type,
)
.addDefinition(adjustedPos.start)
case Parameters(isInfixFun, args) =>
case Parameters(isInfixFun, args) =>
def isNamedParam(pos: SourcePosition): Boolean =
val start = text.indexWhere(!_.isWhitespace, pos.start)
val end = text.lastIndexWhere(!_.isWhitespace, pos.end - 1)
Expand All @@ -142,9 +142,9 @@ class PcInlayHintsProvider(
case (ih, (name, pos0, isByName)) =>
val pos = adjustPos(pos0)
val isBlock = isBlockParam(pos)
val namedLabel =
val namedLabel =
if params.namedParameters() && !isInfixFun && !isBlock && !isNamedParam(pos) then s"${name} = " else ""
val byNameLabel =
val byNameLabel =
if params.byNameParameters() && isByName && (!isInfixFun || isBlock) then "=> " else ""

val labelStr = s"${namedLabel}${byNameLabel}"
Expand Down Expand Up @@ -432,19 +432,19 @@ object InferredType:
end InferredType

object Parameters:
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context): Option[(Boolean, List[(Name, SourcePosition, Boolean)])] =
def shouldSkipFun(fun: Tree)(using Context): Boolean =
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context): Option[(Boolean, List[(Name, SourcePosition, Boolean)])] =
def shouldSkipFun(fun: Tree)(using Context): Boolean =
fun match
case sel: Select => isForComprehensionMethod(sel) || sel.symbol.name == nme.unapply || sel.symbol.is(Flags.JavaDefined)
case _ => false

def isInfixFun(fun: Tree, args: List[Tree])(using Context): Boolean =
def isInfixFun(fun: Tree, args: List[Tree])(using Context): Boolean =
val isInfixSelect = fun match
case Select(sel, _) => sel.isInfix
case _ => false
val source = fun.source
if args.isEmpty then isInfixSelect
else
else
(!(fun.span.end until args.head.span.start)
.map(source.apply)
.contains('.') && fun.symbol.is(Flags.ExtensionMethod)) || isInfixSelect
Expand All @@ -467,23 +467,23 @@ object Parameters:

if (params.namedParameters() || params.byNameParameters()) then
tree match
case Apply(fun, args) if isRealApply(fun) =>
case Apply(fun, args) if isRealApply(fun) =>
val underlyingFun = getUnderlyingFun(fun)
if shouldSkipFun(underlyingFun) then
None
else
val funTp = fun.typeOpt.widenTermRefExpr
val paramNames = funTp.paramNamess.flatten
val paramInfos = funTp.paramInfoss.flatten

Some(
isInfixFun(fun, args) || underlyingFun.isInfix,
(
args
.zip(paramNames)
.zip(paramInfos)
.collect {
case ((arg, paramName), paramInfo) if !arg.span.isZeroExtent && !isDefaultArg(arg) =>
case ((arg, paramName), paramInfo) if !arg.span.isZeroExtent && !isDefaultArg(arg) =>
(paramName.fieldName, arg.sourcePos, paramInfo.isByName)
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ case class ScalaPresentationCompiler(
): PresentationCompiler =
copy(completionItemPriority = priority)

override def withBuildTargetName(buildTargetName: String) =
override def withBuildTargetName(buildTargetName: String): PresentationCompiler =
copy(buildTargetName = Some(buildTargetName))

override def withReportsLoggerLevel(level: String): PresentationCompiler =
Expand Down
Loading
Loading