Skip to content

Commit c65d45d

Browse files
committed
Respect prefix when checking if selector selects
Use miniphase api instead of traversing. Share a megaphase with CheckShadowing. Perform more expensive checks last. Avoid intermediate collections. Tighten allowance for serialization methods. Don't ignore params of public methods. Show misplaced warn comment, unfulfilled expectations. Warn for unused patvars. Don't warn about canonical names (case class element names). Warn unassigned mutable patvars No transparent inline exclusion. Handle match types. No warn inline proxy. Detect summon inline. Unused import diagnostics have an origin. Original of literal. Typos in build. Handle aliased boolean settings. Resolve imports post inlining. Excuse only empty interfaces as unused bound. Use result of TypeTest.
1 parent 89c20f8 commit c65d45d

File tree

82 files changed

+2622
-1230
lines changed

Some content is hidden

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

82 files changed

+2622
-1230
lines changed

Diff for: compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
818818

819819
methSymbol = dd.symbol
820820
jMethodName = methSymbol.javaSimpleName
821-
returnType = asmMethodType(dd.symbol).returnType
821+
returnType = asmMethodType(methSymbol).returnType
822822
isMethSymStaticCtor = methSymbol.isStaticConstructor
823823

824824
resetMethodBookkeeping(dd)
@@ -915,7 +915,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
915915
for (p <- params) { emitLocalVarScope(p.symbol, veryFirstProgramPoint, onePastLastProgramPoint, force = true) }
916916
}
917917

918-
if (isMethSymStaticCtor) { appendToStaticCtor(dd) }
918+
if (isMethSymStaticCtor) { appendToStaticCtor() }
919919
} // end of emitNormalMethodBody()
920920

921921
lineNumber(rhs)
@@ -936,7 +936,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
936936
*
937937
* TODO document, explain interplay with `fabricateStaticInitAndroid()`
938938
*/
939-
private def appendToStaticCtor(dd: DefDef): Unit = {
939+
private def appendToStaticCtor(): Unit = {
940940

941941
def insertBefore(
942942
location: asm.tree.AbstractInsnNode,

Diff for: compiler/src/dotty/tools/dotc/Compiler.scala

+2-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import typer.{TyperPhase, RefChecks}
77
import parsing.Parser
88
import Phases.Phase
99
import transform.*
10-
import dotty.tools.backend
1110
import backend.jvm.{CollectSuperCalls, GenBCode}
1211
import localopt.StringInterpolatorOpt
1312

@@ -34,8 +33,7 @@ class Compiler {
3433
protected def frontendPhases: List[List[Phase]] =
3534
List(new Parser) :: // Compiler frontend: scanner, parser
3635
List(new TyperPhase) :: // Compiler frontend: namer, typer
37-
List(new CheckUnused.PostTyper) :: // Check for unused elements
38-
List(new CheckShadowing) :: // Check shadowing elements
36+
List(CheckUnused.PostTyper(), CheckShadowing()) :: // Check for unused, shadowed elements
3937
List(new YCheckPositions) :: // YCheck positions
4038
List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks
4139
List(new semanticdb.ExtractSemanticDB.ExtractSemanticInfo) :: // Extract info into .semanticdb files
@@ -51,10 +49,10 @@ class Compiler {
5149
List(new sbt.ExtractAPI) :: // Sends a representation of the API of classes to sbt via callbacks
5250
List(new Inlining) :: // Inline and execute macros
5351
List(new PostInlining) :: // Add mirror support for inlined code
54-
List(new CheckUnused.PostInlining) :: // Check for unused elements
5552
List(new Staging) :: // Check staging levels and heal staged types
5653
List(new Splicing) :: // Replace level 1 splices with holes
5754
List(new PickleQuotes) :: // Turn quoted trees into explicit run-time data structures
55+
List(new CheckUnused.PostInlining) :: // Check for unused elements
5856
Nil
5957

6058
/** Phases dealing with the transformation from pickled trees to backend trees */

Diff for: compiler/src/dotty/tools/dotc/ast/Desugar.scala

+12-2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ object desugar {
4747
*/
4848
val UntupledParam: Property.Key[Unit] = Property.StickyKey()
4949

50+
/** An attachment key to indicate that a ValDef originated from a pattern.
51+
*/
52+
val PatternVar: Property.Key[Unit] = Property.StickyKey()
53+
54+
/** An attachment key for Trees originating in for-comprehension, such as tupling of assignments.
55+
*/
56+
val ForArtifact: Property.Key[Unit] = Property.StickyKey()
57+
5058
/** An attachment key to indicate that a ValDef is an evidence parameter
5159
* for a context bound.
5260
*/
@@ -1507,7 +1515,7 @@ object desugar {
15071515
val matchExpr =
15081516
if (tupleOptimizable) rhs
15091517
else
1510-
val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids))
1518+
val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids).withAttachment(ForArtifact, ()))
15111519
Match(makeSelector(rhs, MatchCheck.IrrefutablePatDef), caseDef :: Nil)
15121520
vars match {
15131521
case Nil if !mods.is(Lazy) =>
@@ -1537,6 +1545,7 @@ object desugar {
15371545
ValDef(named.name.asTermName, tpt, selector(n))
15381546
.withMods(mods)
15391547
.withSpan(named.span)
1548+
.withAttachment(PatternVar, ())
15401549
)
15411550
flatTree(firstDef :: restDefs)
15421551
}
@@ -1922,6 +1931,7 @@ object desugar {
19221931
val vdef = ValDef(named.name.asTermName, tpt, rhs)
19231932
.withMods(mods)
19241933
.withSpan(original.span.withPoint(named.span.start))
1934+
.withAttachment(PatternVar, ())
19251935
val mayNeedSetter = valDef(vdef)
19261936
mayNeedSetter
19271937
}
@@ -2167,7 +2177,7 @@ object desugar {
21672177
case _ => Modifiers()
21682178
makePatDef(valeq, mods, defpat, rhs)
21692179
}
2170-
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, gen.expr, gen.checkMode) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
2180+
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, gen.expr, gen.checkMode) :: Nil, Block(pdefs, makeTuple(id0 :: ids).withAttachment(ForArtifact, ())))
21712181
val allpats = gen.pat :: pats
21722182
val vfrom1 = GenFrom(makeTuple(allpats), rhs1, GenCheckMode.Ignore)
21732183
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)

Diff for: compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

+5-15
Original file line numberDiff line numberDiff line change
@@ -173,28 +173,20 @@ private sealed trait WarningSettings:
173173
choices = List(
174174
ChoiceWithHelp("nowarn", ""),
175175
ChoiceWithHelp("all", ""),
176-
ChoiceWithHelp(
177-
name = "imports",
178-
description = "Warn if an import selector is not referenced.\n" +
179-
"NOTE : overrided by -Wunused:strict-no-implicit-warn"),
176+
ChoiceWithHelp("imports", "Warn if an import selector is not referenced."),
180177
ChoiceWithHelp("privates", "Warn if a private member is unused"),
181178
ChoiceWithHelp("locals", "Warn if a local definition is unused"),
182179
ChoiceWithHelp("explicits", "Warn if an explicit parameter is unused"),
183180
ChoiceWithHelp("implicits", "Warn if an implicit parameter is unused"),
184181
ChoiceWithHelp("params", "Enable -Wunused:explicits,implicits"),
182+
ChoiceWithHelp("patvars","Warn if a variable bound in a pattern is unused"),
183+
//ChoiceWithHelp("inlined", "Apply -Wunused to inlined expansions"), // TODO
185184
ChoiceWithHelp("linted", "Enable -Wunused:imports,privates,locals,implicits"),
186185
ChoiceWithHelp(
187186
name = "strict-no-implicit-warn",
188187
description = "Same as -Wunused:import, only for imports of explicit named members.\n" +
189188
"NOTE : This overrides -Wunused:imports and NOT set by -Wunused:all"
190189
),
191-
// ChoiceWithHelp("patvars","Warn if a variable bound in a pattern is unused"),
192-
ChoiceWithHelp(
193-
name = "unsafe-warn-patvars",
194-
description = "(UNSAFE) Warn if a variable bound in a pattern is unused.\n" +
195-
"This warning can generate false positive, as warning cannot be\n" +
196-
"suppressed yet."
197-
)
198190
),
199191
default = Nil
200192
)
@@ -206,7 +198,6 @@ private sealed trait WarningSettings:
206198
// Is any choice set for -Wunused?
207199
def any(using Context): Boolean = Wall.value || Wunused.value.nonEmpty
208200

209-
// overrided by strict-no-implicit-warn
210201
def imports(using Context) =
211202
(allOr("imports") || allOr("linted")) && !(strictNoImplicitWarn)
212203
def locals(using Context) =
@@ -220,9 +211,8 @@ private sealed trait WarningSettings:
220211
def params(using Context) = allOr("params")
221212
def privates(using Context) =
222213
allOr("privates") || allOr("linted")
223-
def patvars(using Context) =
224-
isChoiceSet("unsafe-warn-patvars") // not with "all"
225-
// allOr("patvars") // todo : rename once fixed
214+
def patvars(using Context) = allOr("patvars")
215+
def inlined(using Context) = isChoiceSet("inlined")
226216
def linted(using Context) =
227217
allOr("linted")
228218
def strictNoImplicitWarn(using Context) =

Diff for: compiler/src/dotty/tools/dotc/core/Definitions.scala

+5
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,8 @@ class Definitions {
494494
@tu lazy val Predef_undefined: Symbol = ScalaPredefModule.requiredMethod(nme.???)
495495
@tu lazy val ScalaPredefModuleClass: ClassSymbol = ScalaPredefModule.moduleClass.asClass
496496

497+
@tu lazy val SameTypeClass: ClassSymbol = requiredClass("scala.=:=")
498+
@tu lazy val SameType_refl: Symbol = SameTypeClass.companionModule.requiredMethod(nme.refl)
497499
@tu lazy val SubTypeClass: ClassSymbol = requiredClass("scala.<:<")
498500
@tu lazy val SubType_refl: Symbol = SubTypeClass.companionModule.requiredMethod(nme.refl)
499501

@@ -834,6 +836,7 @@ class Definitions {
834836
@tu lazy val QuotedExprClass: ClassSymbol = requiredClass("scala.quoted.Expr")
835837

836838
@tu lazy val QuotesClass: ClassSymbol = requiredClass("scala.quoted.Quotes")
839+
@tu lazy val Quotes_reflectModule: Symbol = QuotesClass.requiredClass("reflectModule")
837840
@tu lazy val Quotes_reflect: Symbol = QuotesClass.requiredValue("reflect")
838841
@tu lazy val Quotes_reflect_asTerm: Symbol = Quotes_reflect.requiredMethod("asTerm")
839842
@tu lazy val Quotes_reflect_Apply: Symbol = Quotes_reflect.requiredValue("Apply")
@@ -955,6 +958,7 @@ class Definitions {
955958
def NonEmptyTupleClass(using Context): ClassSymbol = NonEmptyTupleTypeRef.symbol.asClass
956959
lazy val NonEmptyTuple_tail: Symbol = NonEmptyTupleClass.requiredMethod("tail")
957960
@tu lazy val PairClass: ClassSymbol = requiredClass("scala.*:")
961+
@tu lazy val PairClass_unapply: Symbol = PairClass.companionModule.requiredMethod("unapply")
958962

959963
@tu lazy val TupleXXLClass: ClassSymbol = requiredClass("scala.runtime.TupleXXL")
960964
def TupleXXLModule(using Context): Symbol = TupleXXLClass.companionModule
@@ -1062,6 +1066,7 @@ class Definitions {
10621066
@tu lazy val UntrackedCapturesAnnot: ClassSymbol = requiredClass("scala.caps.untrackedCaptures")
10631067
@tu lazy val UseAnnot: ClassSymbol = requiredClass("scala.caps.use")
10641068
@tu lazy val VolatileAnnot: ClassSymbol = requiredClass("scala.volatile")
1069+
@tu lazy val LanguageFeatureMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.languageFeature")
10651070
@tu lazy val BeanGetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanGetter")
10661071
@tu lazy val BeanSetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanSetter")
10671072
@tu lazy val FieldMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.field")

Diff for: compiler/src/dotty/tools/dotc/report.scala

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
package dotty.tools.dotc
22

3-
import reporting.*
4-
import Diagnostic.*
5-
import util.{SourcePosition, NoSourcePosition, SrcPos}
6-
import core.*
7-
import Contexts.*, Flags.*, Symbols.*, Decorators.*
8-
import config.SourceVersion
93
import ast.*
10-
import config.Feature.sourceVersion
4+
import core.*, Contexts.*, Flags.*, Symbols.*, Decorators.*
5+
import config.Feature.sourceVersion, config.{MigrationVersion, SourceVersion}
6+
import reporting.*, Diagnostic.*
7+
import util.{SourcePosition, NoSourcePosition, SrcPos}
8+
119
import java.lang.System.currentTimeMillis
12-
import dotty.tools.dotc.config.MigrationVersion
1310

1411
object report:
1512

@@ -55,6 +52,9 @@ object report:
5552
else issueWarning(new FeatureWarning(msg, pos.sourcePos))
5653
end featureWarning
5754

55+
def warning(msg: Message, pos: SrcPos, origin: String)(using Context): Unit =
56+
issueWarning(LintWarning(msg, addInlineds(pos), origin))
57+
5858
def warning(msg: Message, pos: SrcPos)(using Context): Unit =
5959
issueWarning(new Warning(msg, addInlineds(pos)))
6060

Diff for: compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala

+15-7
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ object Diagnostic:
3636
pos: SourcePosition
3737
) extends Error(msg, pos)
3838

39+
/** A Warning with an origin. The semantics of `origin` depend on the warning.
40+
* For example, an unused import warning has an origin that specifies the unused selector.
41+
* The origin of a deprecation is the deprecated element.
42+
*/
43+
trait OriginWarning(val origin: String):
44+
self: Warning =>
45+
46+
/** Lints are likely to be filtered. Provide extra axes for filtering by `-Wconf`.
47+
*/
48+
class LintWarning(msg: Message, pos: SourcePosition, origin: String)
49+
extends Warning(msg, pos), OriginWarning(origin)
50+
3951
class Warning(
4052
msg: Message,
4153
pos: SourcePosition
@@ -73,13 +85,9 @@ object Diagnostic:
7385
def enablingOption(using Context): Setting[Boolean] = ctx.settings.unchecked
7486
}
7587

76-
class DeprecationWarning(
77-
msg: Message,
78-
pos: SourcePosition,
79-
val origin: String
80-
) extends ConditionalWarning(msg, pos) {
88+
class DeprecationWarning(msg: Message, pos: SourcePosition, origin: String)
89+
extends ConditionalWarning(msg, pos), OriginWarning(origin):
8190
def enablingOption(using Context): Setting[Boolean] = ctx.settings.deprecation
82-
}
8391

8492
class MigrationWarning(
8593
msg: Message,
@@ -104,5 +112,5 @@ class Diagnostic(
104112
override def diagnosticRelatedInformation: JList[interfaces.DiagnosticRelatedInformation] =
105113
Collections.emptyList()
106114

107-
override def toString: String = s"$getClass at $pos: $message"
115+
override def toString: String = s"$getClass at $pos L${pos.line+1}: $message"
108116
end Diagnostic

Diff for: compiler/src/dotty/tools/dotc/reporting/WConf.scala

+13-11
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ import scala.annotation.internal.sharable
1414
import scala.util.matching.Regex
1515

1616
enum MessageFilter:
17-
def matches(message: Diagnostic): Boolean = this match
17+
def matches(message: Diagnostic): Boolean =
18+
import Diagnostic.*
19+
this match
1820
case Any => true
19-
case Deprecated => message.isInstanceOf[Diagnostic.DeprecationWarning]
20-
case Feature => message.isInstanceOf[Diagnostic.FeatureWarning]
21-
case Unchecked => message.isInstanceOf[Diagnostic.UncheckedWarning]
21+
case Deprecated => message.isInstanceOf[DeprecationWarning]
22+
case Feature => message.isInstanceOf[FeatureWarning]
23+
case Unchecked => message.isInstanceOf[UncheckedWarning]
2224
case MessageID(errorId) => message.msg.errorId == errorId
2325
case MessagePattern(pattern) =>
2426
val noHighlight = message.msg.message.replaceAll("\\e\\[[\\d;]*[^\\d;]","")
@@ -31,7 +33,7 @@ enum MessageFilter:
3133
pattern.findFirstIn(path).nonEmpty
3234
case Origin(pattern) =>
3335
message match
34-
case message: Diagnostic.DeprecationWarning => pattern.findFirstIn(message.origin).nonEmpty
36+
case message: OriginWarning => pattern.findFirstIn(message.origin).nonEmpty
3537
case _ => false
3638
case None => false
3739

@@ -56,12 +58,12 @@ object WConf:
5658
private type Conf = (List[MessageFilter], Action)
5759

5860
def parseAction(s: String): Either[List[String], Action] = s match
59-
case "error" | "e" => Right(Error)
60-
case "warning" | "w" => Right(Warning)
61-
case "verbose" | "v" => Right(Verbose)
62-
case "info" | "i" => Right(Info)
63-
case "silent" | "s" => Right(Silent)
64-
case _ => Left(List(s"unknown action: `$s`"))
61+
case "error" | "e" => Right(Error)
62+
case "warning" | "w" => Right(Warning)
63+
case "verbose" | "v" => Right(Verbose)
64+
case "info" | "i" => Right(Info)
65+
case "silent" | "s" => Right(Silent)
66+
case _ => Left(List(s"unknown action: `$s`"))
6567

6668
private def regex(s: String) =
6769
try Right(s.r)

Diff for: compiler/src/dotty/tools/dotc/reporting/messages.scala

+13-11
Original file line numberDiff line numberDiff line change
@@ -3290,22 +3290,24 @@ extends TypeMsg(ConstructorProxyNotValueID):
32903290
|companion value with the (term-)name `A`. However, these context bound companions
32913291
|are not values themselves, they can only be referred to in selections."""
32923292

3293-
class UnusedSymbol(errorText: String)(using Context)
3293+
class UnusedSymbol(errorText: String, val actions: List[CodeAction] = Nil)(using Context)
32943294
extends Message(UnusedSymbolID) {
32953295
def kind = MessageKind.UnusedSymbol
32963296

32973297
override def msg(using Context) = errorText
32983298
override def explain(using Context) = ""
3299-
}
3300-
3301-
object UnusedSymbol {
3302-
def imports(using Context): UnusedSymbol = new UnusedSymbol(i"unused import")
3303-
def localDefs(using Context): UnusedSymbol = new UnusedSymbol(i"unused local definition")
3304-
def explicitParams(using Context): UnusedSymbol = new UnusedSymbol(i"unused explicit parameter")
3305-
def implicitParams(using Context): UnusedSymbol = new UnusedSymbol(i"unused implicit parameter")
3306-
def privateMembers(using Context): UnusedSymbol = new UnusedSymbol(i"unused private member")
3307-
def patVars(using Context): UnusedSymbol = new UnusedSymbol(i"unused pattern variable")
3308-
}
3299+
override def actions(using Context) = this.actions
3300+
}
3301+
3302+
object UnusedSymbol:
3303+
def imports(actions: List[CodeAction])(using Context): UnusedSymbol = UnusedSymbol(i"unused import", actions)
3304+
def localDefs(using Context): UnusedSymbol = UnusedSymbol(i"unused local definition")
3305+
def explicitParams(using Context): UnusedSymbol = UnusedSymbol(i"unused explicit parameter")
3306+
def implicitParams(using Context): UnusedSymbol = UnusedSymbol(i"unused implicit parameter")
3307+
def privateMembers(using Context): UnusedSymbol = UnusedSymbol(i"unused private member")
3308+
def patVars(using Context): UnusedSymbol = UnusedSymbol(i"unused pattern variable")
3309+
def unsetLocals(using Context): UnusedSymbol = UnusedSymbol(i"unset local variable, consider using an immutable val instead")
3310+
def unsetPrivates(using Context): UnusedSymbol = UnusedSymbol(i"unset private variable, consider using an immutable val instead")
33093311

33103312
class NonNamedArgumentInJavaAnnotation(using Context) extends SyntaxMsg(NonNamedArgumentInJavaAnnotationID):
33113313

0 commit comments

Comments
 (0)