Skip to content

Commit e412524

Browse files
committed
ProductN, and method synthesis toolbox.
- Finished giving case classes a ProductN parent, and flipped it on. The "finish" part involved not breaking existing code where case classes manually extend the appropriate ProductN. (Like, Tuple 1-22.) - Generalized most of SyntheticMethods to ease method creation and class manipulation in general. - Fixed bugs related to the above, like the fact that this used to be a compile error: scala> case class Foo() extends Serializable <console>:28: error: trait Serializable is inherited twice case class Foo() extends Serializable ^ It feels like there's a better way to eliminate the duplicate parents, but after spending a lot of time chasing my tail in that peril-fraught zone between namer and typer, I don't see an easy path to improve on it. Closes SI-1799. For that modification to Typers, review by odersky.
1 parent 660d80f commit e412524

File tree

12 files changed

+422
-320
lines changed

12 files changed

+422
-320
lines changed

src/compiler/scala/reflect/internal/Definitions.scala

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
420420
lazy val ProductClass = mkArityArray("Product", MaxProductArity)
421421
lazy val FunctionClass = mkArityArray("Function", MaxFunctionArity, 0)
422422
lazy val AbstractFunctionClass = mkArityArray("runtime.AbstractFunction", MaxFunctionArity, 0)
423+
lazy val isProductNClass = ProductClass.toSet
423424

424425
def tupleField(n: Int, j: Int) = getMember(TupleClass(n), "_" + j)
425426
def isTupleType(tp: Type): Boolean = isTupleType(tp, false)
@@ -454,11 +455,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
454455
def productProj(n: Int, j: Int): Symbol = productProj(ProductClass(n), j)
455456

456457
/** returns true if this type is exactly ProductN[T1,...,Tn], not some subclass */
457-
def isExactProductType(tp: Type): Boolean = cond(tp.normalize) {
458-
case TypeRef(_, sym, elems) =>
459-
val len = elems.length
460-
len <= MaxProductArity && sym == ProductClass(len)
461-
}
458+
def isExactProductType(tp: Type): Boolean = isProductNClass(tp.typeSymbol)
462459

463460
def productType(elems: List[Type]) = {
464461
if (elems.isEmpty) UnitClass.tpe
@@ -472,15 +469,16 @@ trait Definitions extends reflect.api.StandardDefinitions {
472469
}
473470
}
474471

475-
/** if tpe <: ProductN[T1,...,TN], returns Some((T1,...,TN)) else None */
476-
def getProductArgs(tpe: Type): Option[List[Type]] =
477-
tpe.baseClasses collectFirst { case x if isExactProductType(x.tpe) => tpe.baseType(x).typeArgs }
472+
/** if tpe <: ProductN[T1,...,TN], returns List(T1,...,TN) else Nil */
473+
def getProductArgs(tpe: Type): List[Type] = tpe.baseClasses find isProductNClass match {
474+
case Some(x) => tpe.baseType(x).typeArgs
475+
case _ => Nil
476+
}
478477

479-
def unapplyUnwrap(tpe:Type) = (tpe match {
480-
case PolyType(_,MethodType(_, res)) => res
481-
case MethodType(_, res) => res
482-
case tpe => tpe
483-
}).normalize
478+
def unapplyUnwrap(tpe:Type) = tpe.finalResultType.normalize match {
479+
case RefinedType(p :: _, _) => p.normalize
480+
case tp => tp
481+
}
484482

485483
def functionApply(n: Int) = getMember(FunctionClass(n), nme.apply)
486484
def functionType(formals: List[Type], restpe: Type) = {
@@ -753,6 +751,9 @@ trait Definitions extends reflect.api.StandardDefinitions {
753751
/** Is symbol a phantom class for which no runtime representation exists? */
754752
lazy val isPhantomClass = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)
755753

754+
/** Is the symbol that of a parent which is added during parsing? */
755+
lazy val isPossibleSyntheticParent = ProductClass.toSet[Symbol] + ProductRootClass + SerializableClass
756+
756757
private lazy val scalaValueClassesSet = ScalaValueClasses.toSet
757758
private lazy val boxedValueClassesSet = boxedClass.values.toSet + BoxedUnitClass
758759

src/compiler/scala/tools/nsc/ast/parser/Parsers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2675,7 +2675,7 @@ self =>
26752675
def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Int): Template = {
26762676
/** A synthetic ProductN parent for case classes. */
26772677
def extraCaseParents = (
2678-
if (settings.Xexperimental.value && mods.isCase) {
2678+
if (mods.isCase) {
26792679
val arity = if (vparamss.isEmpty || vparamss.head.isEmpty) 0 else vparamss.head.size
26802680
if (arity == 0) Nil
26812681
else List(

src/compiler/scala/tools/nsc/matching/ParallelMatching.scala

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ trait ParallelMatching extends ast.TreeDSL
2424
self: ExplicitOuter =>
2525

2626
import global.{ typer => _, _ }
27-
import definitions.{ AnyRefClass, NothingClass, IntClass, BooleanClass, SomeClass, getProductArgs, productProj }
27+
import definitions.{ AnyRefClass, NothingClass, IntClass, BooleanClass, SomeClass, OptionClass, getProductArgs, productProj }
2828
import CODE._
2929
import Types._
3030
import Debug._
@@ -355,24 +355,26 @@ trait ParallelMatching extends ast.TreeDSL
355355
lazy val unapplyResult: PatternVar =
356356
scrut.createVar(unMethod.tpe, Apply(unTarget, scrut.id :: trailing) setType _.tpe)
357357

358-
lazy val cond: Tree =
359-
if (unapplyResult.tpe.isBoolean) unapplyResult.ident
360-
else if (unapplyResult.tpe.typeSymbol == SomeClass) TRUE
361-
else NOT(unapplyResult.ident DOT nme.isEmpty)
358+
lazy val cond: Tree = unapplyResult.tpe.normalize match {
359+
case TypeRef(_, BooleanClass, _) => unapplyResult.ident
360+
case TypeRef(_, SomeClass, _) => TRUE
361+
case _ => NOT(unapplyResult.ident DOT nme.isEmpty)
362+
}
362363

363364
lazy val failure =
364365
mkFail(zipped.tail filterNot (x => SameUnapplyPattern(x._1)) map { case (pat, r) => r insert pat })
365366

366367
private def doSuccess: (List[PatternVar], List[PatternVar], List[Row]) = {
367368
// pattern variable for the unapply result of Some(x).get
368-
lazy val pv = scrut.createVar(
369-
unMethod.tpe typeArgs 0,
370-
_ => fn(ID(unapplyResult.lhs), nme.get)
371-
)
369+
def unMethodTypeArg = unMethod.tpe.baseType(OptionClass).typeArgs match {
370+
case Nil => log("No type argument for unapply result! " + unMethod.tpe) ; NoType
371+
case arg :: _ => arg
372+
}
373+
lazy val pv = scrut.createVar(unMethodTypeArg, _ => fn(ID(unapplyResult.lhs), nme.get))
372374
def tuple = pv.lhs
373375

374376
// at this point it's Some[T1,T2...]
375-
lazy val tpes = getProductArgs(tuple.tpe).get
377+
lazy val tpes = getProductArgs(tuple.tpe)
376378

377379
// one pattern variable per tuple element
378380
lazy val tuplePVs =

src/compiler/scala/tools/nsc/typechecker/RefChecks.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
287287
infoStringWithLocation(other),
288288
infoStringWithLocation(member)
289289
)
290+
else if (settings.debug.value)
291+
analyzer.foundReqMsg(member.tpe, other.tpe)
290292
else ""
291293

292294
"overriding %s;\n %s %s%s".format(

0 commit comments

Comments
 (0)