summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-07-18 11:29:44 +1000
committerJason Zaugg <jzaugg@gmail.com>2016-08-19 09:26:40 +1000
commita56afcd6192ae69633df23137576505015d34992 (patch)
tree7a1da49f51ae3ce4b723edfe1f29b06b8e2fd74f /src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
parentc141254b97a48e47ed7a6bfa08922671cc639081 (diff)
downloadscala-a56afcd6192ae69633df23137576505015d34992.tar.gz
scala-a56afcd6192ae69633df23137576505015d34992.tar.bz2
scala-a56afcd6192ae69633df23137576505015d34992.zip
Type#contains should peer into RefinementTypeRef-s
Usually, `contains` should not look into class symbol infos. For instance, we expect that: ``` scala> trait C { def foo: Int }; typeOf[C].contains(IntClass) defined trait C res1: Boolean = false ``` We do, however, look at the decls of a `RefinedType` in contains: ``` scala> typeOf[{ def foo: Int }].contains(IntClass) res2: Boolean = true ``` Things get a little vague, however, when we consider a type ref to the refinement class symbol of a refined type. ``` scala> TypeRef(NoPrefix, typeOf[{ def foo: Int }].typeSymbol, Nil) res3: $r.intp.global.Type = AnyRef{def foo: Int} scala> .contains(IntClass) res4: Boolean = false ``` These show up in the first element of the base type seq of a refined type, e.g: ``` scala> typeOf[{ def foo: Int }].typeSymbol.tpe_* res5: $r.intp.global.Type = AnyRef{def foo: Int} scala> typeOf[{ def foo: Int }].baseTypeSeq(0).getClass res7: Class[_ <: $r.intp.global.Type] = class scala.reflect.internal.Types$RefinementTypeRef scala> typeOf[{ def foo: Int }].typeSymbol.tpe_*.getClass res6: Class[_ <: $r.intp.global.Type] = class scala.reflect.internal.Types$RefinementTypeRef ``` This commit takes the opinion that a `RefinementTypeRef` should be transparent with respect to `contains`. This paves the way for fixing the base type sequences of existential types over refinement types. The implementation of `ContainsCollector` was already calling `normalize`, which goes from `RefinementTypeRef` to `RefinedType`. This commit maps over the result, which looks in the parents and decls.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala19
1 files changed, 13 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index 99ef4ed373..e0b64a7600 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -321,13 +321,20 @@ trait MethodSynthesis {
// starts compiling (instead of failing like it's supposed to) because the typer
// expects to be able to identify escaping locals in typedDefDef, and fails to
// spot that brand of them. In other words it's an artifact of the implementation.
+ //
+ // JZ: ... or we could go back to uniformly using explicit result types in all cases
+ // if we fix `dropExistential`. More details https://github.com/scala/scala-dev/issues/165
val getterTp = derivedSym.tpe_*.finalResultType
- val tpt = getterTp.widen match {
- // Range position errors ensue if we don't duplicate this in some
- // circumstances (at least: concrete vals with existential types.)
- case _: ExistentialType => TypeTree() setOriginal (tree.tpt.duplicate setPos tree.tpt.pos.focus)
- case _ if tree.mods.isDeferred => TypeTree() setOriginal tree.tpt // keep type tree of original abstract field
- case _ => TypeTree(getterTp)
+ // Range position errors ensue if we don't duplicate this in some
+ // circumstances (at least: concrete vals with existential types.)
+ def inferredTpt = TypeTree() setOriginal (tree.tpt.duplicate setPos tree.tpt.pos.focus)
+ val tpt = getterTp match {
+ case _: ExistentialType => inferredTpt
+ case _ => getterTp.widen match {
+ case _: ExistentialType => inferredTpt
+ case _ if tree.mods.isDeferred => TypeTree() setOriginal tree.tpt // keep type tree of original abstract field
+ case _ => TypeTree(getterTp)
+ }
}
tpt setPos tree.tpt.pos.focus
}