Skip to content

Commit

Permalink
Merge pull request #8806 from som-snytt/issue/11850
Browse files Browse the repository at this point in the history
Lint pattern varids which are backquotable [ci: last-only]
  • Loading branch information
lrytz committed Jan 17, 2024
2 parents 906d814 + e534c44 commit 578fe92
Show file tree
Hide file tree
Showing 67 changed files with 618 additions and 307 deletions.
2 changes: 1 addition & 1 deletion src/compiler/scala/reflect/reify/codegen/GenTrees.scala
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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

0 comments on commit 578fe92

Please sign in to comment.