Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -Xlint:pattern-shadow to lint pattern varids which are backquotable #8806

Merged
merged 11 commits into from
Jan 17, 2024
2 changes: 1 addition & 1 deletion src/compiler/scala/reflect/reify/codegen/GenTrees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ trait GenTrees {
abort("free var local to the reifee, should have already been inlined by Metalevels: " + inlinedSymtab.symDef(sym))
state.symtab ++= inlinedSymtab
rtree
case tree =>
case _ =>
val migrated = Apply(Select(splicee, nme.in), List(Ident(nme.MIRROR_SHORT)))
Select(migrated, nme.tree)
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/reflect/reify/phases/Reshape.scala
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ trait Reshape {
def toScalaAnnotation(jann: ClassfileAnnotArg): Tree = (jann: @unchecked) match {
case LiteralAnnotArg(const) => Literal(const)
case ArrayAnnotArg(arr) => Apply(Ident(definitions.ArrayModule), arr.toList map toScalaAnnotation)
case NestedAnnotArg(ann) => toPreTyperAnnotation(ann)
case NestedAnnotArg(naa) => toPreTyperAnnotation(naa)
}

ann.assocs map { case (nme, arg) => NamedArg(Ident(nme), toScalaAnnotation(arg)) }
Expand Down
26 changes: 11 additions & 15 deletions src/compiler/scala/tools/nsc/ast/DocComments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,11 @@ trait DocComments { self: Global =>

def sectionString(param: String, paramMap: Map[String, (Int, Int)]): String =
paramMap.get(param) match {
case Some(section) =>
// Cleanup the section tag and parameter
val sectionTextBounds = extractSectionText(parent, section)
cleanupSectionText(parent.substring(sectionTextBounds._1, sectionTextBounds._2))
case Some(paramSection) =>
val (start, end) = extractSectionText(parent, paramSection)
cleanupSectionText(parent.substring(start, end)) // Cleanup the section tag and parameter
case None =>
reporter.echo(sym.pos, "The \"" + getSectionHeader + "\" annotation of the " + sym +
" comment contains @inheritdoc, but the corresponding section in the parent is not defined.")
reporter.echo(sym.pos, s"""The "$getSectionHeader" annotation of the $sym comment contains @inheritdoc, but the corresponding section in the parent is not defined.""")
"<invalid inheritdoc annotation>"
}

Expand Down Expand Up @@ -457,8 +455,8 @@ trait DocComments { self: Global =>

def getSite(name: Name): Type = {
def findIn(sites: List[Symbol]): Type = sites match {
case List() => NoType
case site :: sites1 => select(site.thisType, name, findIn(sites1))
case site1 :: sites1 => select(site1.thisType, name, findIn(sites1))
case _ => NoType
}
// Previously, searching was taking place *only* in the current package and in the root package
// now we're looking for it everywhere in the hierarchy, so we'll be able to link variable expansions like
Expand Down Expand Up @@ -543,16 +541,14 @@ trait DocComments { self: Global =>

val substAliases = new TypeMap {
def apply(tp: Type) = mapOver(tp) match {
case tp1 @ TypeRef(pre, sym, args) if (sym.name.length > 1 && sym.name.startChar == '$') =>
case tp1 @ TypeRef(_, sym, args) if sym.name.length > 1 && sym.name.startChar == '$' =>
subst(sym, aliases, aliasExpansions) match {
case (TypeRef(pre1, sym1, _), canNormalize) =>
val tpe = typeRef(pre1, sym1, args)
case (TypeRef(pre, sym, _), canNormalize) =>
val tpe = typeRef(pre, sym, args)
if (canNormalize) tpe.normalize else tpe
case _ =>
tp1
case _ => tp1
}
case tp1 =>
tp1
case tp1 => tp1
}
}

Expand Down
15 changes: 8 additions & 7 deletions src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,10 @@ self =>
def smartParse(): Tree = withSmartParsing {
val firstTry = parse()
if (syntaxErrors.isEmpty) firstTry
else in.healBraces() match {
case Nil => showSyntaxErrors() ; firstTry
case patches => withPatches(patches).parse()
else {
val patches = in.healBraces()
if (!patches.isEmpty) withPatches(patches).parse()
else { showSyntaxErrors(); firstTry }
}
}
}
Expand Down Expand Up @@ -2225,7 +2226,7 @@ self =>
else atPos(p.pos.start, p.pos.start, body.pos.end) {
val t = Bind(name, body)
body match {
case Ident(nme.WILDCARD) if settings.warnUnusedPatVars => t updateAttachment NoWarnAttachment
case Ident(nme.WILDCARD) if settings.warnUnusedPatVars || settings.warnPatternShadow => t.updateAttachment(NoWarnAttachment)
case _ => t
}
}
Expand Down Expand Up @@ -3412,9 +3413,9 @@ self =>
* }}}
* @param isPre specifies whether in early initializer (true) or not (false)
*/
def templateBody(isPre: Boolean) = inBraces(templateStatSeq(isPre = isPre)) match {
case (self, Nil) => (self, EmptyTree.asList)
case result => result
def templateBody(isPre: Boolean) = inBraces(templateStatSeq(isPre)) match {
case (selfTypeVal, Nil) => (selfTypeVal, EmptyTree.asList)
case result => result
}
def templateBodyOpt(parenMeansSyntaxError: Boolean): (ValDef, List[Tree]) = {
newLineOptWhenFollowedBy(LBRACE)
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ abstract class TreeBuilder {
/** Create tree for a pattern alternative */
def makeAlternative(ts: List[Tree]): Tree = {
def alternatives(t: Tree): List[Tree] = t match {
case Alternative(ts) => ts
case _ => List(t)
case Alternative(alts) => alts
som-snytt marked this conversation as resolved.
Show resolved Hide resolved
case _ => List(t)
}
Alternative(ts flatMap alternatives)
Alternative(ts.flatMap(alternatives))
}

/** Create tree for case definition <case pat if guard => rhs> */
Expand Down
22 changes: 11 additions & 11 deletions src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,19 @@ abstract class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
MethodBType(paramBTypes, resultType)
}

def bootstrapMethodArg(t: Constant, pos: Position): AnyRef = t match {
case Constant(mt: Type) =>
def bootstrapMethodArg(t: Constant, pos: Position): AnyRef = t.value match {
case mt: Type =>
transformedType(mt) match {
case mt1: MethodType =>
methodBTypeFromMethodType(mt1, isConstructor = false).toASMType
case t =>
typeToBType(t).toASMType
case transformed =>
typeToBType(transformed).toASMType
}
case c @ Constant(sym: Symbol) if sym.owner.isJavaDefined && sym.isStaticMember => staticHandleFromSymbol(sym)
case c @ Constant(sym: Symbol) => handleFromMethodSymbol(sym)
case c @ Constant(value: String) => value
case c @ Constant(value) if c.isNonUnitAnyVal => c.value.asInstanceOf[AnyRef]
case _ => reporter.error(pos, "Unable to convert static argument of ApplyDynamic into a classfile constant: " + t); null
case sym: Symbol if sym.owner.isJavaDefined && sym.isStaticMember => staticHandleFromSymbol(sym)
case sym: Symbol => handleFromMethodSymbol(sym)
case value: String => value
case value if t.isNonUnitAnyVal => value.asInstanceOf[AnyRef]
case _ => reporter.error(pos, s"Unable to convert static argument of ApplyDynamic into a classfile constant: $t"); null
}

def staticHandleFromSymbol(sym: Symbol): asm.Handle = {
Expand Down Expand Up @@ -233,8 +233,8 @@ abstract class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
case SingleType(_, sym) => primitiveOrClassToBType(sym)
case ConstantType(_) => typeToBType(t.underlying)
case RefinedType(parents, _) => parents.map(typeToBType(_).asClassBType).reduceLeft((a, b) => a.jvmWiseLUB(b).get)
case AnnotatedType(_, t) => typeToBType(t)
case ExistentialType(_, t) => typeToBType(t)
case AnnotatedType(_, at) => typeToBType(at)
case ExistentialType(_, et) => typeToBType(et)
case x => throw new MatchError(x)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,11 @@ final class FileBasedCache[K, T] {
private case class Entry(k: K, stamps: Seq[Stamp], t: T) {
val referenceCount: AtomicInteger = new AtomicInteger(1)
var timerTask: TimerTask = null
def cancelTimer(): Unit = {
def cancelTimer(): Unit =
timerTask match {
case null =>
case t => t.cancel()
case task => task.cancel()
}
}
}
private val cache = collection.mutable.Map.empty[(K, Seq[Path]), Entry]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
def loop(seen: List[String], args: List[String]): (List[String], List[String]) = args match {
case Optionlike() :: _ if halting => (seen, args)
case "help" :: rest if helpText.isDefined => sawHelp = true ; loop(seen, rest)
case arg :: rest => loop(arg :: seen, rest)
case head :: rest => loop(head :: seen, rest)
case Nil => (seen, Nil)
}
val (seen, rest) = loop(Nil, args)
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/scala/tools/nsc/settings/Warnings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ trait Warnings {
val ArgDiscard = LintWarning("arg-discard", "-Wvalue-discard for adapted arguments.")
val IntDivToFloat = LintWarning("int-div-to-float", "Warn when an integer division is converted (widened) to floating point: `(someInt / 2): Double`.")
val NamedBooleans = LintWarning("named-booleans", "Boolean literals should be named args unless param is @deprecatedName.")
val PatternShadow = LintWarning("pattern-shadow", "Pattern variable id is also a term in scope.")

def allLintWarnings = values.toSeq.asInstanceOf[Seq[LintWarning]]
}
Expand Down Expand Up @@ -254,6 +255,7 @@ trait Warnings {
def lintArgDiscard = lint.contains(ArgDiscard)
def lintIntDivToFloat = lint.contains(IntDivToFloat)
def lintNamedBooleans = lint.contains(NamedBooleans)
def warnPatternShadow = lint.contains(PatternShadow)

// The Xlint warning group.
val lint = MultiChoiceSetting(
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ abstract class BrowsingLoaders extends GlobalSymbolLoaders {
}

override def traverse(tree: Tree): Unit = tree match {
case PackageDef(pkg, body) =>
inPackagePrefix(pkg) { body foreach traverse }
case PackageDef(pid, stats) =>
inPackagePrefix(pid) { stats.foreach(traverse) }

case ClassDef(_, name, _, _) =>
if (packagePrefix == root.fullName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -648,10 +648,8 @@ abstract class ClassfileParser(reader: ReusableInstance[ReusableDataReader]) {
case BOOL_TAG => BooleanTpe
case 'L' =>
def processInner(tp: Type): Type = tp match {
case TypeRef(pre, sym, args) if (!sym.isStatic) =>
typeRef(processInner(pre.widen), sym, args)
case _ =>
tp
case TypeRef(pre, sym, args) if !sym.isStatic => typeRef(processInner(pre.widen), sym, args)
case _ => tp
}
def processClassType(tp: Type): Type = tp match {
case TypeRef(pre, classSym, args) =>
Expand Down Expand Up @@ -699,9 +697,11 @@ abstract class ClassfileParser(reader: ReusableInstance[ReusableDataReader]) {
tp
}

val classSym = classNameToSymbol(subName(c => c == ';' || c == '<'))
assert(!classSym.isOverloaded, classSym.alternatives)
val classTpe = if (classSym eq ObjectClass) ObjectTpeJava else classSym.tpe_*
val classTpe = {
val classSym = classNameToSymbol(subName(c => c == ';' || c == '<'))
assert(!classSym.isOverloaded, classSym.alternatives)
if (classSym eq ObjectClass) ObjectTpeJava else classSym.tpe_*
}
var tpe = processClassType(processInner(classTpe))
while (sig.charAt(index) == '.') {
accept('.')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ abstract class Pickler extends SubComponent {
case StringTag => writeRef(newTermName(c.stringValue))
case ClazzTag => writeRef(c.typeValue)
case EnumTag => writeRef(c.symbolValue)
case tag => if (ByteTag <= tag && tag <= LongTag) writeLong(c.longValue)
case ctag => if (ByteTag <= ctag && ctag <= LongTag) writeLong(c.longValue)
}

def writeModifiers(mods: Modifiers): Unit = {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/transform/PostErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ trait PostErasure extends InfoTransform with TypingTransformers with scala.refle
case AsInstanceOf(v, tpe) if v.tpe <:< tpe => finish(v) // x.asInstanceOf[X] ==> x
case ValueClass.BoxAndUnbox(v) => finish(v) // (new B(v)).unbox ==> v
case ValueClass.BoxAndCompare(v1, op, v2) => binop(v1, op, v2) // new B(v1) == new B(v2) ==> v1 == v2
case tree => tree
case transformed => transformed
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,11 @@ private[async] trait AnfTransform extends TransformUtils {
case ld: LabelDef if ld.tpe.typeSymbol == definitions.BoxedUnitClass =>
currentStats += ld
literalBoxedUnit
case ld: LabelDef if ld.tpe.typeSymbol == definitions.UnitClass =>
case ld: LabelDef if ld.tpe.typeSymbol == definitions.UnitClass =>
currentStats += ld
literalUnit
case expr => expr
case expr1 =>
expr1
}

case ValDef(mods, name, tpt, rhs) => atOwner(tree.symbol) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ abstract class AsyncPhase extends Transform with TypingTransformers with AnfTran
currentTransformState = saved
}
}
case tree =>
tree
case transformed => transformed
}

private def asyncTransform(asyncBody: Tree): (Tree, List[Tree]) = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ trait ExprBuilder extends TransformUtils with AsyncAnalysis {
Block(StateTransitionStyle.UpdateAndContinue.trees(state, new StateSet), typedCurrentPos(literalUnit)).setType(definitions.UnitTpe)
case None => ap
}
case tree => tree
case transformed => transformed
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ trait MatchTranslation {
def pt = unbound match {
case Star(tpt) => seqType(tpt.tpe)
case TypeBound(tpe) => tpe
case tree => tree.tpe
case unbound => unbound.tpe
}

object SymbolAndTypeBound {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
// `case 1 | 2` is considered as two cases.
def exceedsTwoCasesOrAlts = {
// avoids traversing the entire list if there are more than 3 elements
def lengthMax3(l: List[List[TreeMaker]]): Int = l match {
def lengthMax3(cases: List[List[TreeMaker]]): Int = cases match {
case a :: b :: c :: _ => 3
case cases => cases.map {
case AlternativesTreeMaker(_, alts, _) :: _ => lengthMax3(alts)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,16 @@ trait PatternMatching extends Transform
// but for the rest of us pass in top as the expected type to avoid waste.
val pt = if (origTp <:< definitions.AnyTpe) definitions.AnyTpe else WildcardType
localTyper.typed(translated, pt) match {
case b @ Block(stats, m: Match) =>
case b @ Block(_, m: Match) =>
b.setType(origTp)
m.setType(origTp)
b
case tree => tree setType origTp
case t => t.setType(origTp)
}
} catch {
case x: (Types#TypeError) =>
case x: Types#TypeError =>
// TODO: this should never happen; error should've been reported during type checking
reporter.error(tree.pos, "error during expansion of this match (this is a scalac bug).\nThe underlying error was: "+ x.msg)
reporter.error(tree.pos, s"error during expansion of this match (this is a scalac bug).\nThe underlying error was: ${x.msg}")
translated
}
case Try(block, catches, finalizer) =>
Expand Down
23 changes: 9 additions & 14 deletions src/compiler/scala/tools/nsc/transform/patmat/Solving.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@

package scala.tools.nsc.transform.patmat

import scala.annotation.tailrec
import scala.collection.mutable.ArrayBuffer
import scala.collection.{immutable, mutable}
import scala.annotation.{tailrec, unused}
import scala.collection.{immutable, mutable}, mutable.ArrayBuffer

/** Solve pattern matcher exhaustivity problem via DPLL. */
trait Solving extends Logic {
Expand Down Expand Up @@ -340,27 +339,23 @@ trait Solving extends Logic {
val cnfExtractor = new AlreadyInCNF(symbolMapping)
val cnfTransformer = new TransformToCnf(symbolMapping)

def cnfFor(prop: Prop): Solvable = {
def cnfFor(prop: Prop): Solvable =
prop match {
case cnfExtractor.ToCnf(solvable) =>
// this is needed because t6942 would generate too many clauses with Tseitin
// already in CNF, just add clauses
solvable
case p =>
cnfTransformer.apply(p)
// this is needed because t6942 would generate too many clauses with Tseitin
// already in CNF, just add clauses
case cnfExtractor.ToCnf(solvable) => solvable
case prop => cnfTransformer.apply(prop)
}
}

simplified match {
case And(props) =>
// scala/bug#6942:
// CNF(P1 /\ ... /\ PN) == CNF(P1) ++ CNF(...) ++ CNF(PN)
val cnfs = new Array[Solvable](props.size)
@annotation.unused val copied = props.iterator.map(x => cnfFor(x)).copyToArray(cnfs)
@unused val copied = props.iterator.map(x => cnfFor(x)).copyToArray(cnfs)
//assert(copied == cnfs.length, "")
new Solvable(cnfs.flatten[Clause](_.cnf, reflect.classTag[Clause]), cnfs.head.symbolMapping)
case p =>
cnfFor(p)
case simplified => cnfFor(simplified)
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/compiler/scala/tools/nsc/typechecker/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,18 @@ trait Contexts { self: Analyzer =>
var unused = List.empty[Culled]
@tailrec def loop(infos: List[(ImportInfo, Symbol)]): Unit =
infos match {
case (info, owner) :: rest =>
case (info, owner) :: infos =>
val used = allUsedSelectors.remove(info).getOrElse(Set.empty)
def checkSelectors(selectors: List[ImportSelector]): Unit =
selectors match {
case selector :: rest =>
checkSelectors(rest)
case selector :: selectors =>
checkSelectors(selectors)
if (!selector.isMask && !used(selector))
unused ::= ((selector, info, owner))
case _ =>
}
checkSelectors(info.tree.selectors)
loop(rest)
loop(infos)
case _ =>
}
loop(infos0)
Expand Down