@@ -377,8 +377,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
377377 /* Whether the extractor is irrefutable */
378378 def irrefutable (unapp : tpd.Tree ): Boolean = {
379379 // TODO: optionless patmat
380- unapp.tpe.widen.resultType.isRef(scalaSomeClass) ||
381- (unapp.symbol.is(Synthetic ) && unapp.symbol.owner.linkedClass.is(Case ))
380+ unapp.tpe.widen.finalResultType.isRef(scalaSomeClass) ||
381+ (unapp.symbol.is(Synthetic ) && unapp.symbol.owner.linkedClass.is(Case )) ||
382+ productArity(unapp.tpe.widen.finalResultType) > 0
382383 }
383384
384385 /** Return the space that represents the pattern `pat`
@@ -451,30 +452,48 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
451452 /** Parameter types of the case class type `tp`. Adapted from `unapplyPlan` in patternMatcher */
452453 def signature (unapp : Type , unappSym : Symbol , argLen : Int ): List [Type ] = {
453454 def caseClass = unappSym.owner.linkedClass
455+
454456 lazy val caseAccessors = caseClass.caseAccessors.filter(_.is(Method ))
455457
456458 def isSyntheticScala2Unapply (sym : Symbol ) =
457459 sym.is(SyntheticCase ) && sym.owner.is(Scala2x )
458460
459461 val mt @ MethodType (_) = unapp.widen
460462
461- if (isSyntheticScala2Unapply(unappSym) && caseAccessors.length == argLen)
462- caseAccessors.map(_.info.asSeenFrom(mt.paramInfos.head, caseClass).widen)
463- else if (mt.resultType.isRef(defn.BooleanClass ))
464- List ()
465- else {
466- val isUnapplySeq = unappSym.name == nme.unapplySeq
467- if (isProductMatch(mt.resultType, argLen) && ! isUnapplySeq) {
468- productSelectors(mt.resultType).take(argLen)
469- .map(_.info.asSeenFrom(mt.resultType, mt.resultType.classSymbol).widen)
470- }
463+ // Case unapply:
464+ // 1. return types of constructor fields if the extractor is synthesized for Scala2 case classes & length match
465+ // 2. return Nil if unapply returns Boolean (boolean pattern)
466+ // 3. return product selector types if unapply returns a product type (product pattern)
467+ // 4. return product selectors of `T` where `def get: T` is a member of the return type of unapply & length match (named-based pattern)
468+ // 5. otherwise, return `T` where `def get: T` is a member of the return type of unapply
469+ //
470+ // Case unapplySeq:
471+ // 1. return the type `List[T]` where `T` is the element type of the unapplySeq return type `Seq[T]`
472+
473+ val sig =
474+ if (isSyntheticScala2Unapply(unappSym) && caseAccessors.length == argLen)
475+ caseAccessors.map(_.info.asSeenFrom(mt.paramInfos.head, caseClass).widen)
476+ else if (mt.finalResultType.isRef(defn.BooleanClass ))
477+ List ()
471478 else {
472- val resTp = mt.resultType.select(nme.get).resultType.widen
473- if (isUnapplySeq) scalaListType.appliedTo(resTp.argTypes.head) :: Nil
474- else if (argLen == 0 ) Nil
475- else productSelectors(resTp).map(_.info.asSeenFrom(resTp, resTp.classSymbol).widen)
479+ val isUnapplySeq = unappSym.name == nme.unapplySeq
480+ if (isProductMatch(mt.finalResultType, argLen) && ! isUnapplySeq) {
481+ productSelectors(mt.finalResultType).take(argLen)
482+ .map(_.info.asSeenFrom(mt.finalResultType, mt.resultType.classSymbol).widen)
483+ }
484+ else {
485+ val resTp = mt.finalResultType.select(nme.get).finalResultType.widen
486+ if (isUnapplySeq) scalaListType.appliedTo(resTp.argTypes.head) :: Nil
487+ else if (argLen == 0 ) Nil
488+ else if (isProductMatch(resTp, argLen))
489+ productSelectors(resTp).map(_.info.asSeenFrom(resTp, resTp.classSymbol).widen)
490+ else resTp :: Nil
491+ }
476492 }
477- }
493+
494+ debug.println(s " signature of ${unappSym.showFullName} ----> ${sig.map(_.show).mkString(" , " )}" )
495+
496+ sig
478497 }
479498
480499 /** Decompose a type into subspaces -- assume the type can be decomposed */
@@ -705,14 +724,14 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
705724 showType(tp) + params(tp).map(_ => " _" ).mkString(" (" , " , " , " )" )
706725 else if (decomposed) " _: " + showType(tp)
707726 else " _"
708- case Prod (tp, fun, _ , params, _) =>
727+ case Prod (tp, fun, sym , params, _) =>
709728 if (ctx.definitions.isTupleType(tp))
710729 " (" + params.map(doShow(_)).mkString(" , " ) + " )"
711730 else if (tp.isRef(scalaConsType.symbol))
712731 if (mergeList) params.map(doShow(_, mergeList)).mkString(" , " )
713732 else params.map(doShow(_, true )).filter(_ != " Nil" ).mkString(" List(" , " , " , " )" )
714733 else
715- showType(tp ) + params.map(doShow(_)).mkString(" (" , " , " , " )" )
734+ showType(sym.owner.typeRef ) + params.map(doShow(_)).mkString(" (" , " , " , " )" )
716735 case Or (_) =>
717736 throw new Exception (" incorrect flatten result " + s)
718737 }
0 commit comments