diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-02-09 17:24:01 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-02-09 17:24:01 -0800 |
commit | 9038fe66959446787f92dc4e5dfaf9127bdab8c5 (patch) | |
tree | c52d7e5e68581c2610684b39f858b2ca78968b20 /src | |
parent | 01d53a0aea8a62b93f9b6dc04d0565d1a59419ce (diff) | |
parent | 38162b564b8e0b9b500fdc0443cb9e1a423a3ba3 (diff) | |
download | scala-9038fe66959446787f92dc4e5dfaf9127bdab8c5.tar.gz scala-9038fe66959446787f92dc4e5dfaf9127bdab8c5.tar.bz2 scala-9038fe66959446787f92dc4e5dfaf9127bdab8c5.zip |
Merge pull request #3471 from adriaanm/t6169
SI-6169 Refine java wildcard bounds using corresponding tparam
Diffstat (limited to 'src')
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 2d4e0b3b34..4fbac235f4 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -899,7 +899,7 @@ trait Types -1 } - /** If this is a poly- or methodtype, a copy with cloned type / value parameters + /** If this is a ExistentialType, PolyType or MethodType, a copy with cloned type / value parameters * owned by `owner`. Identity for all other types. */ def cloneInfo(owner: Symbol) = this @@ -2683,8 +2683,55 @@ trait Types override def baseTypeSeq = underlying.baseTypeSeq map maybeRewrap override def isHigherKinded = false - override def skolemizeExistential(owner: Symbol, origin: AnyRef) = + /** [SI-6169, SI-8197 -- companion to SI-1786] + * + * Approximation to improve the bounds of a Java-defined existential type, + * based on the bounds of the type parameters of the quantified type + * In Scala syntax, given a java-defined class C[T <: String], the existential type C[_] + * is improved to C[_ <: String] before skolemization, which captures (get it?) what Java does: + * enter the type paramers' bounds into the context when checking subtyping/type equality of existential types + * + * (Also tried doing this once during class file parsing or when creating the existential type, + * but that causes cyclic errors because it happens too early.) + */ + private def sharpenQuantifierBounds(): Unit = { + /* Check that we're looking at rawToExistential's handiwork + * (`existentialAbstraction(eparams, typeRef(apply(pre), sym, eparams map (_.tpe)))`). + * We can't do this sharpening there because we'll run into cycles. + */ + def rawToExistentialCreatedMe = (quantified corresponds underlying.typeArgs){ (q, a) => q.tpe =:= a } + + if (underlying.typeSymbol.isJavaDefined && rawToExistentialCreatedMe) { + val tpars = underlying.typeSymbol.initialize.typeParams // TODO: is initialize needed? + debuglog(s"sharpen bounds: $this | ${underlying.typeArgs.map(_.typeSymbol)} <-- ${tpars.map(_.info)}") + + foreach2(quantified, tpars) { (quant, tparam) => + // TODO: check `tparam.info.substSym(tpars, quantified) <:< quant.info` instead (for some weird reason not working for test/t6169/ExistF) + // for now, crude approximation for the common case + if (quant.info.bounds.isEmptyBounds && !tparam.info.bounds.isEmptyBounds) { + // avoid creating cycles [pos/t2940] that consist of an existential quantifier's + // bounded by an existential type that unhygienically has that quantifier as its own quantifier + // (TODO: clone latter existential with fresh quantifiers -- not covering this case for now) + if ((existentialsInType(tparam.info) intersect quantified).isEmpty) + quant setInfo tparam.info.substSym(tpars, quantified) + } + } + } + + _sharpenQuantifierBounds = false + } + private[this] var _sharpenQuantifierBounds = true + + override def skolemizeExistential(owner: Symbol, origin: AnyRef) = { + // do this here because it's quite close to what Java does: + // when checking subtyping/type equality, enter constraints + // derived from the existentially quantified type into the typing environment + // (aka \Gamma, which tracks types for variables and constraints/kinds for types) + // as a nice bonus, delaying this until we need it avoids cyclic errors + if (_sharpenQuantifierBounds) sharpenQuantifierBounds + deriveType(quantified, tparam => (owner orElse tparam.owner).newExistentialSkolem(tparam, origin))(underlying) + } private def wildcardArgsString(qset: Set[Symbol], args: List[Type]): List[String] = args map { case TypeRef(_, sym, _) if (qset contains sym) => |