Skip to content

Commit 76e7558

Browse files
som-snytttgodzik
authored andcommitted
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 f8a1729 commit 76e7558

File tree

81 files changed

+2764
-1340
lines changed

Some content is hidden

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

81 files changed

+2764
-1340
lines changed

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,

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

+2-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import cc.CheckCaptures
88
import parsing.Parser
99
import Phases.Phase
1010
import transform.*
11-
import dotty.tools.backend
1211
import backend.jvm.{CollectSuperCalls, GenBCode}
1312
import localopt.StringInterpolatorOpt
1413

@@ -35,8 +34,7 @@ class Compiler {
3534
protected def frontendPhases: List[List[Phase]] =
3635
List(new Parser) :: // Compiler frontend: scanner, parser
3736
List(new TyperPhase) :: // Compiler frontend: namer, typer
38-
List(new CheckUnused.PostTyper) :: // Check for unused elements
39-
List(new CheckShadowing) :: // Check shadowing elements
37+
List(CheckUnused.PostTyper(), CheckShadowing()) :: // Check for unused, shadowed elements
4038
List(new YCheckPositions) :: // YCheck positions
4139
List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks
4240
List(new semanticdb.ExtractSemanticDB.ExtractSemanticInfo) :: // Extract info into .semanticdb files
@@ -51,10 +49,10 @@ class Compiler {
5149
List(new Pickler) :: // Generate TASTY info
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 */

compiler/src/dotty/tools/dotc/ast/Desugar.scala

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

48+
/** An attachment key to indicate that a ValDef originated from a pattern.
49+
*/
50+
val PatternVar: Property.Key[Unit] = Property.StickyKey()
51+
52+
/** An attachment key for Trees originating in for-comprehension, such as tupling of assignments.
53+
*/
54+
val ForArtifact: Property.Key[Unit] = Property.StickyKey()
55+
4856
/** What static check should be applied to a Match? */
4957
enum MatchCheck {
5058
case None, Exhaustive, IrrefutablePatDef, IrrefutableGenFrom
@@ -1221,7 +1229,7 @@ object desugar {
12211229
val matchExpr =
12221230
if (tupleOptimizable) rhs
12231231
else
1224-
val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids))
1232+
val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids).withAttachment(ForArtifact, ()))
12251233
Match(makeSelector(rhs, MatchCheck.IrrefutablePatDef), caseDef :: Nil)
12261234
vars match {
12271235
case Nil if !mods.is(Lazy) =>
@@ -1251,6 +1259,7 @@ object desugar {
12511259
ValDef(named.name.asTermName, tpt, selector(n))
12521260
.withMods(mods)
12531261
.withSpan(named.span)
1262+
.withAttachment(PatternVar, ())
12541263
)
12551264
flatTree(firstDef :: restDefs)
12561265
}
@@ -1542,6 +1551,7 @@ object desugar {
15421551
val vdef = ValDef(named.name.asTermName, tpt, rhs)
15431552
.withMods(mods)
15441553
.withSpan(original.span.withPoint(named.span.start))
1554+
.withAttachment(PatternVar, ())
15451555
val mayNeedSetter = valDef(vdef)
15461556
mayNeedSetter
15471557
}
@@ -1733,7 +1743,7 @@ object desugar {
17331743
case _ => Modifiers()
17341744
makePatDef(valeq, mods, defpat, rhs)
17351745
}
1736-
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, gen.expr, gen.checkMode) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
1746+
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, gen.expr, gen.checkMode) :: Nil, Block(pdefs, makeTuple(id0 :: ids).withAttachment(ForArtifact, ())))
17371747
val allpats = gen.pat :: pats
17381748
val vfrom1 = GenFrom(makeTuple(allpats), rhs1, GenCheckMode.Ignore)
17391749
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

+5-15
Original file line numberDiff line numberDiff line change
@@ -179,28 +179,20 @@ private sealed trait WarningSettings:
179179
choices = List(
180180
ChoiceWithHelp("nowarn", ""),
181181
ChoiceWithHelp("all", ""),
182-
ChoiceWithHelp(
183-
name = "imports",
184-
description = "Warn if an import selector is not referenced.\n" +
185-
"NOTE : overrided by -Wunused:strict-no-implicit-warn"),
182+
ChoiceWithHelp("imports", "Warn if an import selector is not referenced."),
186183
ChoiceWithHelp("privates", "Warn if a private member is unused"),
187184
ChoiceWithHelp("locals", "Warn if a local definition is unused"),
188185
ChoiceWithHelp("explicits", "Warn if an explicit parameter is unused"),
189186
ChoiceWithHelp("implicits", "Warn if an implicit parameter is unused"),
190187
ChoiceWithHelp("params", "Enable -Wunused:explicits,implicits"),
188+
ChoiceWithHelp("patvars","Warn if a variable bound in a pattern is unused"),
189+
//ChoiceWithHelp("inlined", "Apply -Wunused to inlined expansions"), // TODO
191190
ChoiceWithHelp("linted", "Enable -Wunused:imports,privates,locals,implicits"),
192191
ChoiceWithHelp(
193192
name = "strict-no-implicit-warn",
194193
description = "Same as -Wunused:import, only for imports of explicit named members.\n" +
195194
"NOTE : This overrides -Wunused:imports and NOT set by -Wunused:all"
196195
),
197-
// ChoiceWithHelp("patvars","Warn if a variable bound in a pattern is unused"),
198-
ChoiceWithHelp(
199-
name = "unsafe-warn-patvars",
200-
description = "(UNSAFE) Warn if a variable bound in a pattern is unused.\n" +
201-
"This warning can generate false positive, as warning cannot be\n" +
202-
"suppressed yet."
203-
)
204196
),
205197
default = Nil
206198
)
@@ -212,7 +204,6 @@ private sealed trait WarningSettings:
212204
// Is any choice set for -Wunused?
213205
def any(using Context): Boolean = Wall.value || Wunused.value.nonEmpty
214206

215-
// overrided by strict-no-implicit-warn
216207
def imports(using Context) =
217208
(allOr("imports") || allOr("linted")) && !(strictNoImplicitWarn)
218209
def locals(using Context) =
@@ -226,9 +217,8 @@ private sealed trait WarningSettings:
226217
def params(using Context) = allOr("params")
227218
def privates(using Context) =
228219
allOr("privates") || allOr("linted")
229-
def patvars(using Context) =
230-
isChoiceSet("unsafe-warn-patvars") // not with "all"
231-
// allOr("patvars") // todo : rename once fixed
220+
def patvars(using Context) = allOr("patvars")
221+
def inlined(using Context) = isChoiceSet("inlined")
232222
def linted(using Context) =
233223
allOr("linted")
234224
def strictNoImplicitWarn(using Context) =

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

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

485+
@tu lazy val SameTypeClass: ClassSymbol = requiredClass("scala.=:=")
486+
@tu lazy val SameType_refl: Symbol = SameTypeClass.companionModule.requiredMethod(nme.refl)
485487
@tu lazy val SubTypeClass: ClassSymbol = requiredClass("scala.<:<")
486488
@tu lazy val SubType_refl: Symbol = SubTypeClass.companionModule.requiredMethod(nme.refl)
487489

@@ -816,6 +818,7 @@ class Definitions {
816818
@tu lazy val QuotedExprClass: ClassSymbol = requiredClass("scala.quoted.Expr")
817819

818820
@tu lazy val QuotesClass: ClassSymbol = requiredClass("scala.quoted.Quotes")
821+
@tu lazy val Quotes_reflectModule: Symbol = QuotesClass.requiredClass("reflectModule")
819822
@tu lazy val Quotes_reflect: Symbol = QuotesClass.requiredValue("reflect")
820823
@tu lazy val Quotes_reflect_asTerm: Symbol = Quotes_reflect.requiredMethod("asTerm")
821824
@tu lazy val Quotes_reflect_Apply: Symbol = Quotes_reflect.requiredValue("Apply")
@@ -941,6 +944,7 @@ class Definitions {
941944
def NonEmptyTupleClass(using Context): ClassSymbol = NonEmptyTupleTypeRef.symbol.asClass
942945
lazy val NonEmptyTuple_tail: Symbol = NonEmptyTupleClass.requiredMethod("tail")
943946
@tu lazy val PairClass: ClassSymbol = requiredClass("scala.*:")
947+
@tu lazy val PairClass_unapply: Symbol = PairClass.companionModule.requiredMethod("unapply")
944948

945949
@tu lazy val TupleXXLClass: ClassSymbol = requiredClass("scala.runtime.TupleXXL")
946950
def TupleXXLModule(using Context): Symbol = TupleXXLClass.companionModule
@@ -1031,6 +1035,7 @@ class Definitions {
10311035
@tu lazy val UncheckedCapturesAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedCaptures")
10321036
@tu lazy val VolatileAnnot: ClassSymbol = requiredClass("scala.volatile")
10331037
@tu lazy val WithPureFunsAnnot: ClassSymbol = requiredClass("scala.annotation.internal.WithPureFuns")
1038+
@tu lazy val LanguageFeatureMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.languageFeature")
10341039
@tu lazy val BeanGetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanGetter")
10351040
@tu lazy val BeanSetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanSetter")
10361041
@tu lazy val FieldMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.field")

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

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
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.SourceVersion
6+
import reporting.*, Diagnostic.*
7+
import util.{SourcePosition, NoSourcePosition, SrcPos}
8+
119
import java.lang.System.currentTimeMillis
1210

1311
object report:
@@ -54,6 +52,9 @@ object report:
5452
else issueWarning(new FeatureWarning(msg, pos.sourcePos))
5553
end featureWarning
5654

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

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

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)

compiler/src/dotty/tools/dotc/reporting/messages.scala

+14-11
Original file line numberDiff line numberDiff line change
@@ -3155,22 +3155,25 @@ extends SyntaxMsg(VolatileOnValID):
31553155
protected def msg(using Context): String = "values cannot be volatile"
31563156
protected def explain(using Context): String = ""
31573157

3158-
class UnusedSymbol(errorText: String)(using Context)
3158+
3159+
class UnusedSymbol(errorText: String, val actions: List[CodeAction] = Nil)(using Context)
31593160
extends Message(UnusedSymbolID) {
31603161
def kind = MessageKind.UnusedSymbol
31613162

31623163
override def msg(using Context) = errorText
31633164
override def explain(using Context) = ""
3164-
}
3165-
3166-
object UnusedSymbol {
3167-
def imports(using Context): UnusedSymbol = new UnusedSymbol(i"unused import")
3168-
def localDefs(using Context): UnusedSymbol = new UnusedSymbol(i"unused local definition")
3169-
def explicitParams(using Context): UnusedSymbol = new UnusedSymbol(i"unused explicit parameter")
3170-
def implicitParams(using Context): UnusedSymbol = new UnusedSymbol(i"unused implicit parameter")
3171-
def privateMembers(using Context): UnusedSymbol = new UnusedSymbol(i"unused private member")
3172-
def patVars(using Context): UnusedSymbol = new UnusedSymbol(i"unused pattern variable")
3173-
}
3165+
override def actions(using Context) = this.actions
3166+
}
3167+
3168+
object UnusedSymbol:
3169+
def imports(actions: List[CodeAction])(using Context): UnusedSymbol = UnusedSymbol(i"unused import", actions)
3170+
def localDefs(using Context): UnusedSymbol = UnusedSymbol(i"unused local definition")
3171+
def explicitParams(using Context): UnusedSymbol = UnusedSymbol(i"unused explicit parameter")
3172+
def implicitParams(using Context): UnusedSymbol = UnusedSymbol(i"unused implicit parameter")
3173+
def privateMembers(using Context): UnusedSymbol = UnusedSymbol(i"unused private member")
3174+
def patVars(using Context): UnusedSymbol = UnusedSymbol(i"unused pattern variable")
3175+
def unsetLocals(using Context): UnusedSymbol = UnusedSymbol(i"unset local variable, consider using an immutable val instead")
3176+
def unsetPrivates(using Context): UnusedSymbol = UnusedSymbol(i"unset private variable, consider using an immutable val instead")
31743177

31753178
final class QuotedTypeMissing(tpe: Type)(using Context) extends StagingMessage(QuotedTypeMissingID):
31763179

0 commit comments

Comments
 (0)