Skip to content

Commit 290120a

Browse files
Backport "Add warnings for inferred flexible types in public methods and fields" to 3.7.4 (#23993)
Backports #23880 to the 3.7.4. PR submitted by the release tooling. [skip ci]
2 parents 9fac8b5 + 404ac77 commit 290120a

29 files changed

+216
-81
lines changed

compiler/src/dotty/tools/MainGenericCompiler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ case class CompileSettings(
8585

8686
object MainGenericCompiler {
8787

88-
val classpathSeparator = File.pathSeparator
88+
val classpathSeparator: String = File.pathSeparator
8989

9090
@sharable val javaOption = raw"""-J(.*)""".r
9191
@sharable val javaPropOption = raw"""-D(.+?)=(.?)""".r

compiler/src/dotty/tools/MainGenericRunner.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ case class Settings(
9696

9797
object MainGenericRunner {
9898

99-
val classpathSeparator = File.pathSeparator
99+
val classpathSeparator: String = File.pathSeparator
100100

101101
def processClasspath(cp: String, tail: List[String]): (List[String], List[String]) =
102102
val cpEntries = cp.split(classpathSeparator).toList

compiler/src/dotty/tools/backend/jvm/CodeGen.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)(
152152
new interfaces.AbstractFile {
153153
override def name = absfile.name
154154
override def path = absfile.path
155-
override def jfile = Optional.ofNullable(absfile.file)
155+
override def jfile: Optional[java.io.File] = Optional.ofNullable(absfile.file)
156156
}
157157

158158
private def genClass(cd: TypeDef, unit: CompilationUnit): ClassNode = {

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2961,7 +2961,7 @@ object SymDenotations {
29612961
dependent = null
29622962
}
29632963

2964-
protected def addDependent(dep: InheritedCache) = {
2964+
protected def addDependent(dep: InheritedCache): Unit = {
29652965
if (dependent == null) dependent = new WeakHashMap
29662966
dependent.nn.put(dep, ())
29672967
}

compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ class InteractiveDriver(val settings: List[String]) extends Driver {
234234
private def classesFromDir(dir: Path, buffer: mutable.ListBuffer[TypeName]): Unit =
235235
try
236236
Files.walkFileTree(dir, new SimpleFileVisitor[Path] {
237-
override def visitFile(path: Path, attrs: BasicFileAttributes) = {
237+
override def visitFile(path: Path, attrs: BasicFileAttributes): FileVisitResult = {
238238
if (!attrs.isDirectory) {
239239
val name = path.getFileName.toString
240240
if name.endsWith(tastySuffix) then

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ import xsbti.api.SafeLazy.strict
1717
*/
1818
object APIUtils {
1919
private object Constants {
20-
val PublicAccess = api.Public.create()
21-
val EmptyModifiers = new api.Modifiers(false, false, false, false, false, false, false, false)
22-
val EmptyStructure = api.Structure.of(strict(Array.empty), strict(Array.empty), strict(Array.empty))
23-
val EmptyType = api.EmptyType.of()
20+
val PublicAccess: api.Public = api.Public.create()
21+
val EmptyModifiers: api.Modifiers = new api.Modifiers(false, false, false, false, false, false, false, false)
22+
val EmptyStructure: api.Structure = api.Structure.of(strict(Array.empty), strict(Array.empty), strict(Array.empty))
23+
val EmptyType: api.EmptyType = api.EmptyType.of()
2424
}
2525

2626
import Constants.*

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,13 @@ private class ExtractAPICollector(nonLocalClassSymbols: mutable.HashSet[Symbol])
232232

233233
private object Constants {
234234
val emptyStringArray = Array[String]()
235-
val local = api.ThisQualifier.create()
236-
val public = api.Public.create()
237-
val privateLocal = api.Private.create(local)
238-
val protectedLocal = api.Protected.create(local)
239-
val unqualified = api.Unqualified.create()
240-
val thisPath = api.This.create()
241-
val emptyType = api.EmptyType.create()
235+
val local: api.ThisQualifier = api.ThisQualifier.create()
236+
val public: api.Public = api.Public.create()
237+
val privateLocal: api.Private = api.Private.create(local)
238+
val protectedLocal: api.Protected = api.Protected.create(local)
239+
val unqualified: api.Unqualified = api.Unqualified.create()
240+
val thisPath: api.This = api.This.create()
241+
val emptyType: api.EmptyType = api.EmptyType.create()
242242
val emptyModifiers =
243243
new api.Modifiers(false, false, false, false, false,false, false, false)
244244
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,18 @@ object RefChecks {
11851185
report.warning(ExtensionNullifiedByMember(sym, target), sym.srcPos)
11861186
end checkExtensionMethods
11871187

1188+
/** Check that public (and protected) methods/fields do not expose flexible types. */
1189+
def checkPublicFlexibleTypes(sym: Symbol)(using Context): Unit =
1190+
if ctx.explicitNulls && !ctx.isJava
1191+
&& sym.exists && !sym.is(Private) && sym.owner.isClass
1192+
&& !sym.isOneOf(Synthetic | InlineProxy | Param | Exported) then
1193+
val resTp = sym.info.finalResultType
1194+
if resTp.existsPart(_.isInstanceOf[FlexibleType], StopAt.Static) then
1195+
report.warning(
1196+
em"${sym.show} exposes a flexible type in its inferred result type ${resTp}. Consider annotating the type explicitly",
1197+
sym.srcPos
1198+
)
1199+
11881200
/** Verify that references in the user-defined `@implicitNotFound` message are valid.
11891201
* (i.e. they refer to a type variable that really occurs in the signature of the annotated symbol.)
11901202
*/
@@ -1321,6 +1333,7 @@ class RefChecks extends MiniPhase { thisPhase =>
13211333
val sym = tree.symbol
13221334
checkNoPrivateOverrides(sym)
13231335
checkVolatile(sym)
1336+
checkPublicFlexibleTypes(sym)
13241337
if (sym.exists && sym.owner.isTerm) {
13251338
tree.rhs match {
13261339
case Ident(nme.WILDCARD) => report.error(UnboundPlaceholderParameter(), sym.srcPos)
@@ -1336,6 +1349,7 @@ class RefChecks extends MiniPhase { thisPhase =>
13361349
checkImplicitNotFoundAnnotation.defDef(sym.denot)
13371350
checkUnaryMethods(sym)
13381351
checkExtensionMethods(sym)
1352+
checkPublicFlexibleTypes(sym)
13391353
tree
13401354
}
13411355

compiler/src/dotty/tools/io/Path.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,12 @@ class Path private[io] (val jpath: JPath) {
245245
if (!exists) false
246246
else {
247247
Files.walkFileTree(jpath, new SimpleFileVisitor[JPath]() {
248-
override def visitFile(file: JPath, attrs: BasicFileAttributes) = {
248+
override def visitFile(file: JPath, attrs: BasicFileAttributes): FileVisitResult = {
249249
Files.delete(file)
250250
FileVisitResult.CONTINUE
251251
}
252252

253-
override def postVisitDirectory(dir: JPath, exc: IOException) = {
253+
override def postVisitDirectory(dir: JPath, exc: IOException): FileVisitResult = {
254254
Files.delete(dir)
255255
FileVisitResult.CONTINUE
256256
}

compiler/src/dotty/tools/repl/AbstractFileClassLoader.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader) exten
2626
// on JDK 20 the URL constructor we're using is deprecated,
2727
// but the recommended replacement, URL.of, doesn't exist on JDK 8
2828
@annotation.nowarn("cat=deprecation")
29-
override protected def findResource(name: String) =
29+
override protected def findResource(name: String): URL | Null =
3030
findAbstractFile(name) match
3131
case null => null
3232
case file => new URL(null, s"memory:${file.path}", new URLStreamHandler {
@@ -35,13 +35,13 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader) exten
3535
override def getInputStream = file.input
3636
}
3737
})
38-
override protected def findResources(name: String) =
38+
override protected def findResources(name: String): java.util.Enumeration[URL] =
3939
findResource(name) match
4040
case null => Collections.enumeration(Collections.emptyList[URL]) //Collections.emptyEnumeration[URL]
4141
case url => Collections.enumeration(Collections.singleton(url))
4242

4343
override def findClass(name: String): Class[?] = {
44-
var file: AbstractFile = root
44+
var file: AbstractFile | Null = root
4545
val pathParts = name.split("[./]").toList
4646
for (dirPart <- pathParts.init) {
4747
file = file.lookupName(dirPart, true)

0 commit comments

Comments
 (0)