summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Infer.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-02-09 19:30:30 -0800
committerPaul Phillips <paulp@improving.org>2013-02-09 19:41:08 -0800
commit747f6a8d24c628d05ab3acea0b95a82d04a71df3 (patch)
tree435f44dd8856c91e1ac4ba1da86d74178e0a3586 /src/compiler/scala/tools/nsc/typechecker/Infer.scala
parentce32c1af462de7d7c6b90efd56217e202a18d1e6 (diff)
parent81d8f9d3da656cfb05f125ba7cf70ca51a477240 (diff)
downloadscala-747f6a8d24c628d05ab3acea0b95a82d04a71df3.tar.gz
scala-747f6a8d24c628d05ab3acea0b95a82d04a71df3.tar.bz2
scala-747f6a8d24c628d05ab3acea0b95a82d04a71df3.zip
Merge commit '81d8f9d3da' into merge-210
* excluded from merge: [nomerge] SI-6667 Demote a new ambiguity error to a lint warning. Revert "SI-6422: add missing Fractional and Integral alias in scala package" [backport] SI-6482, lost bounds in extension methods. * commit '81d8f9d3da': (31 commits) reflecting @throws defined in Scala code pullrequest feedback SI-5833 Fixes tail-of-Nil problem in RefinedType#normalizeImpl SI-6017 Scaladoc: Show all letters without dangling links SI-6017 Generate Scaladoc's index links in Scala side SI-5313 Minor code cleanup for store clobbering SI-5313 Test clobbers on the back edge of a loop SI-7033 Be symful when creating factory methods. SI-7022 Additional test case for value class w. bounds SI-7039 unapplySeq result type independent of subpattern count evicts javac-artifacts.jar SI-7008 @throws annotations are now populated in reflect Fix SI-6578. Deprecated `askType` because of possible race conditions in type checker. SI-7029 - Make test more robust SI-7029 - Makes sure that uncaught exceptions are propagated to the UEH for the global ExecutionContext SI-6941 tests SI-6686 drop valdef unused in flatMapCond's block ... Conflicts: src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala src/reflect/scala/reflect/internal/Definitions.scala
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Infer.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala70
1 files changed, 42 insertions, 28 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 27f157e3a6..0207c841d2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -75,20 +75,31 @@ trait Infer extends Checkable {
* @throws TypeError when the unapply[Seq] definition is ill-typed
* @returns (null, null) when the expected number of sub-patterns cannot be satisfied by the given extractor
*
- * From the spec:
+ * This is the spec currently implemented -- TODO: update it.
+ *
* 8.1.8 ExtractorPatterns
*
* An extractor pattern x(p1, ..., pn) where n ≥ 0 is of the same syntactic form as a constructor pattern.
* However, instead of a case class, the stable identifier x denotes an object which has a member method named unapply or unapplySeq that matches the pattern.
- * An unapply method in an object x matches the pattern x(p1, ..., pn) if it takes exactly one argument and one of the following applies:
*
- * n = 0 and unapply’s result type is Boolean.
+ * An `unapply` method with result type `R` in an object `x` matches the
+ * pattern `x(p_1, ..., p_n)` if it takes exactly one argument and, either:
+ * - `n = 0` and `R =:= Boolean`, or
+ * - `n = 1` and `R <:< Option[T]`, for some type `T`.
+ * The argument pattern `p1` is typed in turn with expected type `T`.
+ * - Or, `n > 1` and `R <:< Option[Product_n[T_1, ..., T_n]]`, for some
+ * types `T_1, ..., T_n`. The argument patterns `p_1, ..., p_n` are
+ * typed with expected types `T_1, ..., T_n`.
+ *
+ * An `unapplySeq` method in an object `x` matches the pattern `x(p_1, ..., p_n)`
+ * if it takes exactly one argument and its result type is of the form `Option[S]`,
+ * where either:
+ * - `S` is a subtype of `Seq[U]` for some element type `U`, (set `m = 0`)
+ * - or `S` is a `ProductX[T_1, ..., T_m]` and `T_m <: Seq[U]` (`m <= n`).
*
- * n = 1 and unapply’s result type is Option[T], for some type T.
- * the (only) argument pattern p1 is typed in turn with expected type T
+ * The argument patterns `p_1, ..., p_n` are typed with expected types
+ * `T_1, ..., T_m, U, ..., U`. Here, `U` is repeated `n-m` times.
*
- * n > 1 and unapply’s result type is Option[(T1, ..., Tn)], for some types T1, ..., Tn.
- * the argument patterns p1, ..., pn are typed in turn with expected types T1, ..., Tn
*/
def extractorFormalTypes(pos: Position, resTp: Type, nbSubPats: Int, unappSym: Symbol): (List[Type], List[Type]) = {
val isUnapplySeq = unappSym.name == nme.unapplySeq
@@ -100,31 +111,34 @@ trait Infer extends Checkable {
else toRepeated
}
+ // empty list --> error, otherwise length == 1
+ lazy val optionArgs = resTp.baseType(OptionClass).typeArgs
+ // empty list --> not a ProductN, otherwise product element types
+ def productArgs = getProductArgs(optionArgs.head)
+
val formals =
- if (nbSubPats == 0 && booleanExtractor && !isUnapplySeq) Nil
- else resTp.baseType(OptionClass).typeArgs match {
- case optionTArg :: Nil =>
- def productArgs = getProductArgs(optionTArg)
+ // convert Seq[T] to the special repeated argument type
+ // so below we can use formalTypes to expand formals to correspond to the number of actuals
+ if (isUnapplySeq) {
+ if (optionArgs.nonEmpty)
+ productArgs match {
+ case Nil => List(seqToRepeatedChecked(optionArgs.head))
+ case normalTps :+ seqTp => normalTps :+ seqToRepeatedChecked(seqTp)
+ }
+ else throw new TypeError(s"result type $resTp of unapplySeq defined in ${unappSym.fullLocationString} does not conform to Option[_]")
+ } else {
+ if (booleanExtractor && nbSubPats == 0) Nil
+ else if (optionArgs.nonEmpty)
if (nbSubPats == 1) {
- if (isUnapplySeq) List(seqToRepeatedChecked(optionTArg))
- else {
- val productArity = productArgs.size
- if (productArity > 1 && settings.lint.value)
- global.currentUnit.warning(pos, s"extractor pattern binds a single value to a Product${productArity} of type ${optionTArg}")
- List(optionTArg)
- }
+ val productArity = productArgs.size
+ if (productArity > 1 && settings.lint.value)
+ global.currentUnit.warning(pos, s"extractor pattern binds a single value to a Product${productArity} of type ${optionArgs.head}")
+ optionArgs
}
// TODO: update spec to reflect we allow any ProductN, not just TupleN
- else productArgs match {
- case Nil if isUnapplySeq => List(seqToRepeatedChecked(optionTArg))
- case tps if isUnapplySeq => tps.init :+ seqToRepeatedChecked(tps.last)
- case tps => tps
- }
- case _ =>
- if (isUnapplySeq)
- throw new TypeError(s"result type $resTp of unapplySeq defined in ${unappSym.owner+unappSym.owner.locationString} not in {Option[_], Some[_]}")
- else
- throw new TypeError(s"result type $resTp of unapply defined in ${unappSym.owner+unappSym.owner.locationString} not in {Boolean, Option[_], Some[_]}")
+ else productArgs
+ else
+ throw new TypeError(s"result type $resTp of unapply defined in ${unappSym.fullLocationString} does not conform to Option[_] or Boolean")
}
// for unapplySeq, replace last vararg by as many instances as required by nbSubPats