diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-01-09 10:17:51 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-01-09 22:25:22 +0100 |
commit | 3e9e2c65a6a0144edbf86949295e776c8cdf2e67 (patch) | |
tree | e94e570a09d70149be84e186880ce78e6d8700fe /src | |
parent | 969a269033ee3477cb21a539cf2b5b6fa308d105 (diff) | |
download | scala-3e9e2c65a6a0144edbf86949295e776c8cdf2e67.tar.gz scala-3e9e2c65a6a0144edbf86949295e776c8cdf2e67.tar.bz2 scala-3e9e2c65a6a0144edbf86949295e776c8cdf2e67.zip |
SI-8128 Fix regression in extractors returning existentials
The advent of the named based pattern matcher brought with it
a change in the way we determine the type of the value in the
"match monad". We used to take the base type to `Option` or `Seq`
(guided by the method name in `unapply` vs `unapplySeq`), and
simply use the type argument.
Name-based patmat, instead, uses the result type of methods in the
type. For example, the element type of an Option-like extractor
result is given by the result type of the no-args `get` method.
This approach, however, swiftly runs aground when navigating the
existential atolls. Here's why:
scala> class F[_]
defined class F
scala> val tp = typeOf[Some[F[X]] forSome { type X }]
warning: there were 1 feature warning(s); re-run with -feature for details
tp: $r.intp.global.Type = scala.this.Some[F[X]] forSome { type X }
scala> tp.baseType(typeOf[Option[_]].typeSymbol).typeArgs.head
res10: $r.intp.global.Type = F[X] forSome { type X }
scala> tp.memberType(tp.member(nme.get)).finalResultType
res11: $r.intp.global.Type = F[X]
`res10` corresponds to 2.10.x approach in `matchMonadResult`.
`res11` corresponds to the new approach in `resultOfMatchingMethod`.
The last result is not wrapped by the existential type. This results
in errors like (shown under -Ydebug to turn un accurate printing of
skolems):
error: error during expansion of this match (this is a scalac bug).
The underlying error was: type mismatch;
found : _$1&0 where type _$1&0
required: _$1
(0: Any) match {
^
one error found
This commit addresses the regression in 2.10.x compatible extractors
by using the 2.10 approach for them.
The residual problem is shown in the enclosed pending test.
Diffstat (limited to 'src')
-rw-r--r-- | src/reflect/scala/reflect/internal/Definitions.scala | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index b7e67bc377..3ccf321227 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -819,11 +819,18 @@ trait Definitions extends api.StandardDefinitions { // FYI the long clunky name is because it's really hard to put "get" into the // name of a method without it sounding like the method "get"s something, whereas // this method is about a type member which just happens to be named get. - def typeOfMemberNamedGet(tp: Type) = resultOfMatchingMethod(tp, nme.get)() - def typeOfMemberNamedHead(tp: Type) = resultOfMatchingMethod(tp, nme.head)() - def typeOfMemberNamedApply(tp: Type) = resultOfMatchingMethod(tp, nme.apply)(IntTpe) - def typeOfMemberNamedDrop(tp: Type) = resultOfMatchingMethod(tp, nme.drop)(IntTpe) + def typeOfMemberNamedGet(tp: Type) = typeArgOfBaseTypeOr(tp, OptionClass)(resultOfMatchingMethod(tp, nme.get)()) + def typeOfMemberNamedHead(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.head)()) + def typeOfMemberNamedApply(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.apply)(IntTpe)) + def typeOfMemberNamedDrop(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.drop)(IntTpe)) def typesOfSelectors(tp: Type) = getterMemberTypes(tp, productSelectors(tp)) + // SI-8128 Still using the type argument of the base type at Seq/Option if this is an old-style (2.10 compatible) + // extractor to limit exposure to regressions like the reported problem with existentials. + // TODO fix the existential problem in the general case, see test/pending/pos/t8128.scala + private def typeArgOfBaseTypeOr(tp: Type, baseClass: Symbol)(or: => Type): Type = (tp baseType baseClass).typeArgs match { + case x :: Nil => x + case _ => or + } // Can't only check for _1 thanks to pos/t796. def hasSelectors(tp: Type) = ( |