summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-09-28 04:46:02 -0700
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-09-28 04:46:02 -0700
commit57db28c55c3610f508b07940f7077cb73932418f (patch)
tree70b62aa01670cfc4b0877327a96e9d434f152418 /src
parent0614d2f512ad7b1b3885f81d9e6e779f447a6511 (diff)
parent211c9620ba83de143ea4776f55a3e0c4de11d002 (diff)
downloadscala-57db28c55c3610f508b07940f7077cb73932418f.tar.gz
scala-57db28c55c3610f508b07940f7077cb73932418f.tar.bz2
scala-57db28c55c3610f508b07940f7077cb73932418f.zip
Merge pull request #1399 from paulp/210-unchecked
Much better unchecked warnings.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/matching/Patterns.scala12
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Checkable.scala284
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala97
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala19
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala10
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala10
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala7
-rw-r--r--src/reflect/scala/reflect/internal/util/Collections.scala14
10 files changed, 337 insertions, 123 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index eaee39d7e6..a7da857429 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1750,7 +1750,7 @@ self =>
in.nextToken()
if (in.token == SUBTYPE || in.token == SUPERTYPE) wildcardType(start)
else atPos(start) { Bind(tpnme.WILDCARD, EmptyTree) }
- case IDENTIFIER if treeInfo.isVariableName(in.name) =>
+ case IDENTIFIER if nme.isVariableName(in.name) =>
atPos(start) { Bind(identForType(), EmptyTree) }
case _ =>
typ()
diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala
index af77d3fe3f..40e520076a 100644
--- a/src/compiler/scala/tools/nsc/matching/Patterns.scala
+++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala
@@ -21,7 +21,7 @@ trait Patterns extends ast.TreeDSL {
import definitions._
import CODE._
import Debug._
- import treeInfo.{ unbind, isStar, isVarPattern, isVariableName }
+ import treeInfo.{ unbind, isStar, isVarPattern }
type PatternMatch = MatchMatrix#PatternMatch
private type PatternVar = MatrixContext#PatternVar
@@ -366,7 +366,7 @@ trait Patterns extends ast.TreeDSL {
lazy val Select(qualifier, name) = select
def pathSegments = getPathSegments(tree)
def backticked: Option[String] = qualifier match {
- case _: This if isVariableName(name) => Some("`%s`".format(name))
+ case _: This if nme.isVariableName(name) => Some("`%s`".format(name))
case _ => None
}
override def covers(sym: Symbol) = newMatchesPattern(sym, tree.tpe)
@@ -388,11 +388,11 @@ trait Patterns extends ast.TreeDSL {
lazy val UnApply(unfn, args) = tree
lazy val Apply(fn, _) = unfn
lazy val MethodType(List(arg, _*), _) = fn.tpe
-
+
// Covers if the symbol matches the unapply method's argument type,
// and the return type of the unapply is Some.
override def covers(sym: Symbol) = newMatchesPattern(sym, arg.tpe)
-
+
// TODO: for alwaysCovers:
// fn.tpe.finalResultType.typeSymbol == SomeClass
@@ -451,7 +451,7 @@ trait Patterns extends ast.TreeDSL {
(sym.tpe.baseTypeSeq exists (_ matchesPattern pattp))
}
}
-
+
def sym = tree.symbol
def tpe = tree.tpe
def isEmpty = tree.isEmpty
@@ -496,4 +496,4 @@ trait Patterns extends ast.TreeDSL {
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 5a3db26e30..d3a5cebea0 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -185,7 +185,7 @@ abstract class UnCurry extends InfoTransform
* try {
* body
* } catch {
- * case ex: NonLocalReturnControl[_] =>
+ * case ex: NonLocalReturnControl[T @unchecked] =>
* if (ex.key().eq(key)) ex.value()
* else throw ex
* }
@@ -195,7 +195,8 @@ abstract class UnCurry extends InfoTransform
localTyper typed {
val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType)
val ex = meth.newValue(nme.ex, body.pos) setInfo extpe
- val pat = gen.mkBindForCase(ex, NonLocalReturnControlClass, List(meth.tpe.finalResultType))
+ val argType = meth.tpe.finalResultType withAnnotation (AnnotationInfo marker UncheckedClass.tpe)
+ val pat = gen.mkBindForCase(ex, NonLocalReturnControlClass, List(argType))
val rhs = (
IF ((ex DOT nme.key)() OBJ_EQ Ident(key))
THEN ((ex DOT nme.value)())
diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
new file mode 100644
index 0000000000..7e15cf91a7
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
@@ -0,0 +1,284 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2012 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package typechecker
+
+import scala.collection.{ mutable, immutable }
+import scala.collection.mutable.ListBuffer
+import scala.util.control.ControlThrowable
+import symtab.Flags._
+import scala.annotation.tailrec
+import Checkability._
+
+/** On pattern matcher checkability:
+ *
+ * Consider a pattern match of this form: (x: X) match { case _: P => }
+ *
+ * There are four possibilities to consider:
+ * [P1] X will always conform to P
+ * [P2] x will never conform to P
+ * [P3] X <: P if some runtime test is true
+ * [P4] X cannot be checked against P
+ *
+ * The first two cases correspond to those when there is enough
+ * static information to say X <: P or that (x ∈ X) ⇒ (x ∉ P).
+ * The fourth case includes unknown abstract types or structural
+ * refinements appearing within a pattern.
+ *
+ * The third case is the interesting one. We designate another type, XR,
+ * which is essentially the intersection of X and |P|, where |P| is
+ * the erasure of P. If XR <: P, then no warning is emitted.
+ *
+ * Examples of how this info is put to use:
+ * sealed trait A[T] ; class B[T] extends A[T]
+ * def f(x: B[Int]) = x match { case _: A[Int] if true => }
+ * def g(x: A[Int]) = x match { case _: B[Int] => }
+ *
+ * `f` requires no warning because X=B[Int], P=A[Int], and B[Int] <:< A[Int].
+ * `g` requires no warning because X=A[Int], P=B[Int], XR=B[Int], and B[Int] <:< B[Int].
+ * XR=B[Int] because a value of type A[Int] which is tested to be a B can
+ * only be a B[Int], due to the definition of B (B[T] extends A[T].)
+ *
+ * This is something like asSeenFrom, only rather than asking what a type looks
+ * like from the point of view of one of its base classes, we ask what it looks
+ * like from the point of view of one of its subclasses.
+ */
+trait Checkable {
+ self: Analyzer =>
+
+ import global._
+ import definitions._
+ import CheckabilityChecker.{ isNeverSubType, isNeverSubClass }
+
+ /** The applied type of class 'to' after inferring anything
+ * possible from the knowledge that 'to' must also be of the
+ * type given in 'from'.
+ */
+ def propagateKnownTypes(from: Type, to: Symbol): Type = {
+ def tparams = to.typeParams
+ val tvars = tparams map (p => TypeVar(p))
+ val tvarType = appliedType(to, tvars: _*)
+ val bases = from.baseClasses filter (to.baseClasses contains _)
+
+ bases foreach { bc =>
+ val tps1 = (from baseType bc).typeArgs
+ val tps2 = (tvarType baseType bc).typeArgs
+ (tps1, tps2).zipped foreach (_ =:= _)
+ // Alternate, variance respecting formulation causes
+ // neg/unchecked3.scala to fail (abstract types). TODO -
+ // figure it out. It seems there is more work to do if I
+ // allow for variance, because the constraints accumulate
+ // as bounds and "tvar.instValid" is false.
+ //
+ // foreach3(tps1, tps2, bc.typeParams)((tp1, tp2, tparam) =>
+ // if (tparam.initialize.isCovariant) tp1 <:< tp2
+ // else if (tparam.isContravariant) tp2 <:< tp1
+ // else tp1 =:= tp2
+ // )
+ }
+
+ val resArgs = tparams zip tvars map {
+ case (_, tvar) if tvar.instValid => tvar.constr.inst
+ case (tparam, _) => tparam.tpe
+ }
+ appliedType(to, resArgs: _*)
+ }
+
+ private def isUnwarnableTypeArgSymbol(sym: Symbol) = (
+ sym.isTypeParameter // dummy
+ || (sym.name.toTermName == nme.WILDCARD) // _
+ || nme.isVariableName(sym.name) // type variable
+ )
+ private def isUnwarnableTypeArg(arg: Type) = (
+ uncheckedOk(arg) // @unchecked T
+ || isUnwarnableTypeArgSymbol(arg.typeSymbolDirect) // has to be direct: see pos/t1439
+ )
+ private def uncheckedOk(tp: Type) = tp hasAnnotation UncheckedClass
+
+ private def typeArgsInTopLevelType(tp: Type): List[Type] = {
+ val tps = tp match {
+ case RefinedType(parents, _) => parents flatMap typeArgsInTopLevelType
+ case TypeRef(_, ArrayClass, arg :: Nil) => typeArgsInTopLevelType(arg)
+ case TypeRef(pre, sym, args) => typeArgsInTopLevelType(pre) ++ args
+ case ExistentialType(tparams, underlying) => tparams.map(_.tpe) ++ typeArgsInTopLevelType(underlying)
+ case _ => Nil
+ }
+ tps filterNot isUnwarnableTypeArg
+ }
+
+ private class CheckabilityChecker(val X: Type, val P: Type) {
+ def Xsym = X.typeSymbol
+ def Psym = P.typeSymbol
+ def XR = propagateKnownTypes(X, Psym)
+ // sadly the spec says (new java.lang.Boolean(true)).isInstanceOf[scala.Boolean]
+ def P1 = X matchesPattern P
+ def P2 = !Psym.isPrimitiveValueClass && isNeverSubType(X, P)
+ def P3 = isNonRefinementClassType(P) && (XR matchesPattern P)
+ def P4 = !(P1 || P2 || P3)
+
+ def summaryString = f"""
+ |Checking checkability of (x: $X) against pattern $P
+ |[P1] $P1%-6s X <: P // $X <: $P
+ |[P2] $P2%-6s x ∉ P // (x ∈ $X) ⇒ (x ∉ $P)
+ |[P3] $P3%-6s XR <: P // $XR <: $P
+ |[P4] $P4%-6s None of the above // !(P1 || P2 || P3)
+ """.stripMargin.trim
+
+ val result = (
+ if (X.isErroneous || P.isErroneous) CheckabilityError
+ else if (P1) StaticallyTrue
+ else if (P2) StaticallyFalse
+ else if (P3) RuntimeCheckable
+ else if (uncheckableType == NoType) {
+ // Avoid warning (except ourselves) if we can't pinpoint the uncheckable type
+ debugwarn("Checkability checker says 'Uncheckable', but uncheckable type cannot be found:\n" + summaryString)
+ CheckabilityError
+ }
+ else Uncheckable
+ )
+ lazy val uncheckableType = if (Psym.isAbstractType) P else {
+ val possibles = typeArgsInTopLevelType(P).toSet
+ val opt = possibles find { targ =>
+ // Create a derived type with every possibly uncheckable type replaced
+ // with a WildcardType, except for 'targ'. If !(XR <: derived) then
+ // 'targ' is uncheckable.
+ val derived = P map (tp => if (possibles(tp) && !(tp =:= targ)) WildcardType else tp)
+ !(XR <:< derived)
+ }
+ opt getOrElse NoType
+ }
+
+ def neverSubClass = isNeverSubClass(Xsym, Psym)
+ def neverMatches = result == StaticallyFalse
+ def isUncheckable = result == Uncheckable
+ def uncheckableMessage = uncheckableType match {
+ case NoType => "something"
+ case tp @ RefinedType(_, _) => "refinement " + tp
+ case TypeRef(_, sym, _) if sym.isAbstractType => "abstract type " + sym.name
+ case tp => "non-variable type argument " + tp
+ }
+ }
+
+ /** X, P, [P1], etc. are all explained at the top of the file.
+ */
+ private object CheckabilityChecker {
+ /** A knowable class is one which is either effectively final
+ * itself, or sealed with only knowable children.
+ */
+ def isKnowable(sym: Symbol): Boolean = /*logResult(s"isKnowable($sym)")*/(
+ sym.initialize.isEffectivelyFinal // pesky .initialize requirement, or we receive lies about isSealed
+ || sym.isSealed && (sym.children forall isKnowable)
+ )
+ def knownSubclasses(sym: Symbol): List[Symbol] = /*logResult(s"knownSubclasses($sym)")*/(sym :: {
+ if (sym.isSealed) sym.children.toList flatMap knownSubclasses
+ else Nil
+ })
+ def excludable(s1: Symbol, s2: Symbol) = /*logResult(s"excludable($s1, $s2)")*/(
+ isKnowable(s1)
+ && !(s2 isSubClass s1)
+ && knownSubclasses(s1).forall(child => !(child isSubClass s2))
+ )
+
+ /** Given classes A and B, can it be shown that nothing which is
+ * an A will ever be a subclass of something which is a B? This
+ * entails not only showing that !(A isSubClass B) but that the
+ * same is true of all their subclasses. Restated for symmetry:
+ * the same value cannot be a member of both A and B.
+ *
+ * 1) A must not be a subclass of B, nor B of A (the trivial check)
+ * 2) One of A or B must be completely knowable (see isKnowable)
+ * 3) Assuming A is knowable, the proposition is true if
+ * !(A' isSubClass B) for all A', where A' is a subclass of A.
+ *
+ * Due to symmetry, the last condition applies as well in reverse.
+ */
+ def isNeverSubClass(sym1: Symbol, sym2: Symbol) = /*logResult(s"isNeverSubClass($sym1, $sym2)")*/(
+ sym1.isClass
+ && sym2.isClass
+ && (excludable(sym1, sym2) || excludable(sym2, sym1))
+ )
+ private def isNeverSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol]): Boolean = /*logResult(s"isNeverSubArgs($tps1, $tps2, $tparams)")*/ {
+ def isNeverSubArg(t1: Type, t2: Type, variance: Int) = {
+ if (variance > 0) isNeverSubType(t2, t1)
+ else if (variance < 0) isNeverSubType(t1, t2)
+ else isNeverSameType(t1, t2)
+ }
+ exists3(tps1, tps2, tparams map (_.variance))(isNeverSubArg)
+ }
+ private def isNeverSameType(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match {
+ case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) =>
+ ( isNeverSubClass(sym1, sym2)
+ || isNeverSubClass(sym2, sym1)
+ || ((sym1 == sym2) && isNeverSubArgs(args1, args2, sym1.typeParams))
+ )
+ case _ =>
+ false
+ }
+ // Important to dealias at any entry point (this is the only one at this writing.)
+ def isNeverSubType(tp1: Type, tp2: Type): Boolean = /*logResult(s"isNeverSubType($tp1, $tp2)")*/((tp1.dealias, tp2.dealias) match {
+ case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) =>
+ isNeverSubClass(sym1, sym2) || {
+ (sym1 isSubClass sym2) && {
+ val tp1seen = tp1 baseType sym2
+ isNeverSubArgs(tp1seen.typeArgs, args2, sym2.typeParams)
+ }
+ }
+ case _ => false
+ })
+ }
+
+ trait InferCheckable {
+ self: Inferencer =>
+
+ /** TODO: much better error positions.
+ * Kind of stuck right now because they just pass us the one tree.
+ * TODO: Eliminate inPattern, canRemedy, which have no place here.
+ */
+ def checkCheckable(tree: Tree, P0: Type, X0: Type, inPattern: Boolean, canRemedy: Boolean = false) {
+ if (uncheckedOk(P0)) return
+ def where = if (inPattern) "pattern " else ""
+
+ // singleton types not considered here
+ val P = P0.widen
+ val X = X0.widen
+
+ P match {
+ // Prohibit top-level type tests for these, but they are ok nested (e.g. case Foldable[Nothing] => ... )
+ case TypeRef(_, NothingClass | NullClass | AnyValClass, _) =>
+ InferErrorGen.TypePatternOrIsInstanceTestError(tree, P)
+ // If top-level abstract types can be checked using a classtag extractor, don't warn about them
+ case TypeRef(_, sym, _) if sym.isAbstractType && canRemedy =>
+ ;
+ // Matching on types like case _: AnyRef { def bippy: Int } => doesn't work -- yet.
+ case RefinedType(_, decls) if !decls.isEmpty =>
+ getContext.unit.warning(tree.pos, s"a pattern match on a refinement type is unchecked")
+ case _ =>
+ val checker = new CheckabilityChecker(X, P)
+ log(checker.summaryString)
+ if (checker.neverMatches) {
+ val addendum = if (checker.neverSubClass) "" else " (but still might match its erasure)"
+ getContext.unit.warning(tree.pos, s"fruitless type test: a value of type $X cannot also be a $P$addendum")
+ }
+ else if (checker.isUncheckable) {
+ val msg = (
+ if (checker.uncheckableType =:= P) s"abstract type $where$P"
+ else s"${checker.uncheckableMessage} in type $where$P"
+ )
+ getContext.unit.warning(tree.pos, s"$msg is unchecked since it is eliminated by erasure")
+ }
+ }
+ }
+ }
+}
+
+private[typechecker] final class Checkability(val value: Int) extends AnyVal { }
+private[typechecker] object Checkability {
+ val StaticallyTrue = new Checkability(0)
+ val StaticallyFalse = new Checkability(1)
+ val RuntimeCheckable = new Checkability(2)
+ val Uncheckable = new Checkability(3)
+ val CheckabilityError = new Checkability(4)
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 22077303a4..0c3dcb9342 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -17,7 +17,7 @@ import scala.annotation.tailrec
* @author Martin Odersky
* @version 1.0
*/
-trait Infer {
+trait Infer extends Checkable {
self: Analyzer =>
import global._
@@ -254,7 +254,7 @@ trait Infer {
private val stdErrorValue = stdErrorClass.newErrorValue(nme.ERROR)
/** The context-dependent inferencer part */
- class Inferencer(context: Context) extends InferencerContextErrors {
+ class Inferencer(context: Context) extends InferencerContextErrors with InferCheckable {
import InferErrorGen._
/* -- Error Messages --------------------------------------------------- */
@@ -1341,99 +1341,6 @@ trait Infer {
check(tp, Nil)
}
- // if top-level abstract types can be checked using a classtag extractor, don't warn about them
- def checkCheckable(tree: Tree, typeToTest: Type, typeEnsured: Type, inPattern: Boolean, canRemedy: Boolean = false) = {
- log(s"checkCheckable($tree, $typeToTest, $typeEnsured, inPattern = $inPattern, canRemedy = $canRemedy")
-
- sealed abstract class TypeConformance(check: (Type, Type) => Boolean) {
- def apply(t1: Type, t2: Type): Boolean = check(t1, t2) && {
- log(s"Skipping unchecked for statically verifiable condition $t1 ${this} $t2")
- true
- }
- }
- // I tried to use varianceInType to track the variance implications
- // but I could not make it work.
- case object =:= extends TypeConformance(_ =:= _)
- case object <:< extends TypeConformance(_ <:< _)
- case object >:> extends TypeConformance((t1, t2) => t2 <:< t1)
- case object =!= extends TypeConformance((t1, t2) => false)
-
- var bound: List[Symbol] = Nil
- var warningMessages: List[String] = Nil
-
- def isLocalBinding(sym: Symbol) = (
- sym.isAbstractType && (
- (bound contains sym)
- || (sym.name == tpnme.WILDCARD)
- || {
- val e = context.scope.lookupEntry(sym.name)
- (e ne null) && e.sym == sym && !e.sym.isTypeParameterOrSkolem && e.owner == context.scope
- }
- )
- )
- def check(tp0: Type, pt: Type, conformance: TypeConformance): Boolean = {
- val tp = tp0.normalize
- // Set the warning message to be issued when the top-level call fails.
- def warn(what: String): Boolean = {
- warningMessages ::= what
- false
- }
- def checkArg(param: Symbol, arg: Type) = {
- def conforms = (
- if (param.isCovariant) <:<
- else if (param.isContravariant) >:>
- else =:=
- )
- (arg hasAnnotation UncheckedClass) || {
- arg.withoutAnnotations match {
- case TypeRef(_, sym, args) =>
- ( isLocalBinding(sym)
- || arg.typeSymbol.isTypeParameterOrSkolem
- || (sym.name == tpnme.WILDCARD) // avoid spurious warnings on HK types
- || check(arg, param.tpeHK, conforms)
- || warn("non-variable type argument " + arg)
- )
- case _ =>
- warn("non-variable type argument " + arg)
- }
- }
- }
-
- // Checking if pt (the expected type of the pattern, and the type
- // we are guaranteed) conforms to tp (the type expressed in the pattern's
- // type test.) If it does, then even if the type being checked for appears
- // to be uncheckable, it is not a warning situation, because it is indeed
- // checked: not at runtime, but statically.
- conformance.apply(pt, tp) || (tp match {
- case SingleType(pre, _) => check(pre, pt, =:=)
- case ExistentialType(quantified, tp1) => bound :::= quantified ; check(tp1, pt, <:<)
- case ThisType(_) | NoPrefix => true
- case RefinedType(parents, decls) if decls.isEmpty => parents forall (p => check(p, pt, <:<))
- case RefinedType(_, _) => warn("refinement " + tp)
- case TypeRef(_, ArrayClass, arg :: Nil) => check(arg, NoType, =!=)
- case TypeRef(_, NonLocalReturnControlClass, _) => true // no way to suppress unchecked warnings on try/catch
- // we only use the extractor for top-level type tests, type arguments remain unchecked
- case TypeRef(_, sym, _) if sym.isAbstractType => isLocalBinding(sym) || canRemedy || warn("abstract type " + tp)
- case TypeRef(_, _, Nil) => false // leaf node
- case TypeRef(pre, sym, args) => forall2(sym.typeParams, args)(checkArg) && check(pre, pt.prefix, =:=)
- case _ => warn("type " + tp)
- })
- }
- typeToTest match {
- // Prohibit top-level type tests for these, but they are
- // acceptable nested (e.g. case Foldable[Nothing] => ... )
- case TypeRef(_, NothingClass | NullClass | AnyValClass, _) =>
- TypePatternOrIsInstanceTestError(tree, typeToTest)
- case _ =>
- def where = ( if (inPattern) "pattern " else "" ) + typeToTest
- if (check(typeToTest, typeEnsured, =:=)) ()
- // Note that this is a regular warning, not an uncheckedWarning,
- // which is now the province of such notifications as "pattern matcher
- // exceeded its analysis budget."
- else warningMessages foreach (m =>
- context.unit.warning(tree.pos, s"$m in type $where is unchecked since it is eliminated by erasure"))
- }
- }
/** Type intersection of simple type tp1 with general type tp2.
* The result eliminates some redundancies.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index fa7e756e36..c25b6c3726 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -253,12 +253,6 @@ trait Typers extends Modes with Adaptations with Tags {
result
}
}
- def isNonRefinementClassType(tpe: Type) = tpe match {
- case SingleType(_, sym) => sym.isModuleClass
- case TypeRef(_, sym, _) => sym.isClass && !sym.isRefinementClass
- case ErrorType => true
- case _ => false
- }
private def errorNotClass(tpt: Tree, found: Type) = { ClassTypeRequiredError(tpt, found); false }
private def errorNotStable(tpt: Tree, found: Type) = { TypeNotAStablePrefixError(tpt, found); false }
@@ -3768,9 +3762,13 @@ trait Typers extends Modes with Adaptations with Tags {
if (fun.symbol == Predef_classOf)
typedClassOf(tree, args.head, true)
else {
- if (!isPastTyper && fun.symbol == Any_isInstanceOf && !targs.isEmpty)
- checkCheckable(tree, targs.head, AnyClass.tpe, inPattern = false)
-
+ if (!isPastTyper && fun.symbol == Any_isInstanceOf && targs.nonEmpty) {
+ val scrutineeType = fun match {
+ case Select(qual, _) => qual.tpe
+ case _ => AnyClass.tpe
+ }
+ checkCheckable(tree, targs.head, scrutineeType, inPattern = false)
+ }
val resultpe = restpe.instantiateTypeParams(tparams, targs)
//@M substitution in instantiateParams needs to be careful!
//@M example: class Foo[a] { def foo[m[x]]: m[a] = error("") } (new Foo[Int]).foo[List] : List[Int]
@@ -3780,7 +3778,8 @@ trait Typers extends Modes with Adaptations with Tags {
//println("instantiating type params "+restpe+" "+tparams+" "+targs+" = "+resultpe)
treeCopy.TypeApply(tree, fun, args) setType resultpe
}
- } else {
+ }
+ else {
TypedApplyWrongNumberOfTpeParametersError(tree, fun)
}
case ErrorType =>
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 2cdfb05e77..eacbf6a0cc 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -346,6 +346,16 @@ trait StdNames {
def isSingletonName(name: Name) = name endsWith SINGLETON_SUFFIX
def isModuleName(name: Name) = name endsWith MODULE_SUFFIX_NAME
+ /** Is name a variable name? */
+ def isVariableName(name: Name): Boolean = {
+ val first = name.startChar
+ ( ((first.isLower && first.isLetter) || first == '_')
+ && (name != nme.false_)
+ && (name != nme.true_)
+ && (name != nme.null_)
+ )
+ }
+
def isDeprecatedIdentifierName(name: Name) = name.toTermName match {
case nme.`then` | nme.`macro` => true
case _ => false
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index 6ef4c3f660..68decc27f5 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -247,7 +247,7 @@ abstract class TreeInfo {
/** Is tree a variable pattern? */
def isVarPattern(pat: Tree): Boolean = pat match {
- case x: Ident => !x.isBackquoted && isVariableName(x.name)
+ case x: Ident => !x.isBackquoted && nme.isVariableName(x.name)
case _ => false
}
def isDeprecatedIdentifier(tree: Tree): Boolean = tree match {
@@ -312,14 +312,6 @@ abstract class TreeInfo {
/** Is name a left-associative operator? */
def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.endChar != ':')
- private val reserved = Set[Name](nme.false_, nme.true_, nme.null_)
-
- /** Is name a variable name? */
- def isVariableName(name: Name): Boolean = {
- val first = name.startChar
- ((first.isLower && first.isLetter) || first == '_') && !reserved(name)
- }
-
/** Is tree a `this` node which belongs to `enclClass`? */
def isSelf(tree: Tree, enclClass: Symbol): Boolean = tree match {
case This(_) => tree.symbol == enclClass
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index fd5694b599..6b274467fc 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -5732,6 +5732,13 @@ trait Types extends api.Types { self: SymbolTable =>
case _ => false
}
+ def isNonRefinementClassType(tpe: Type) = tpe match {
+ case SingleType(_, sym) => sym.isModuleClass
+ case TypeRef(_, sym, _) => sym.isClass && !sym.isRefinementClass
+ case ErrorType => true
+ case _ => false
+ }
+
// @assume tp1.isHigherKinded || tp2.isHigherKinded
def isHKSubType0(tp1: Type, tp2: Type, depth: Int): Boolean = (
tp1.typeSymbol == NothingClass
diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala
index 14b5d3003d..201b4dfe0a 100644
--- a/src/reflect/scala/reflect/internal/util/Collections.scala
+++ b/src/reflect/scala/reflect/internal/util/Collections.scala
@@ -175,6 +175,20 @@ trait Collections {
}
false
}
+ final def exists3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Boolean): Boolean = {
+ var ys1 = xs1
+ var ys2 = xs2
+ var ys3 = xs3
+ while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) {
+ if (f(ys1.head, ys2.head, ys3.head))
+ return true
+
+ ys1 = ys1.tail
+ ys2 = ys2.tail
+ ys3 = ys3.tail
+ }
+ false
+ }
final def forall2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = {
var ys1 = xs1
var ys2 = xs2