diff options
author | Adriaan Moors <adriaan@lightbend.com> | 2016-08-29 11:55:33 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-08-29 11:55:33 +0200 |
commit | 66430e076dbe79553c930878aa47f183767c68af (patch) | |
tree | 747e29678c67330b02bc422bd330c978c3d16ced /src/reflect | |
parent | 3304bc33987f5821912bb0c7371b5e9a115c893d (diff) | |
parent | 8ef3e6e47098786f9522ebcaffaa261d8f240308 (diff) | |
download | scala-66430e076dbe79553c930878aa47f183767c68af.tar.gz scala-66430e076dbe79553c930878aa47f183767c68af.tar.bz2 scala-66430e076dbe79553c930878aa47f183767c68af.zip |
Merge pull request #5280 from retronym/ticket/8079
SI-8079 Only expand local aliases during variance checks
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/scala/reflect/internal/Variances.scala | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index bc8a5de119..98b4e881af 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -50,11 +50,9 @@ trait Variances { sym.isParameter && !(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem && tvar.owner == sym.owner) ) - // return Bivariant if `sym` is local to a term - // or is private[this] or protected[this] - def isLocalOnly(sym: Symbol) = !sym.owner.isClass || ( - sym.isTerm // ?? shouldn't this be sym.owner.isTerm according to the comments above? - && (sym.isLocalToThis || sym.isSuperAccessor) // super accessors are implicitly local #4345 + // Is `sym` is local to a term or is private[this] or protected[this]? + def isExemptFromVariance(sym: Symbol): Boolean = !sym.owner.isClass || ( + (sym.isLocalToThis || sym.isSuperAccessor) // super accessors are implicitly local #4345 && !escapedLocals(sym) ) @@ -66,7 +64,7 @@ trait Variances { * Initially the state is covariant, but it might change along the search. * * A local alias type is treated as Bivariant; - * this is OK because we always expand aliases for variance checking. + * this is OK because such aliases are expanded for variance checking. * However, for an alias which might be externally visible, we must assume Invariant, * because there may be references to the type parameter that are not checked, * leading to unsoundness (see SI-6566). @@ -74,7 +72,7 @@ trait Variances { def relativeVariance(tvar: Symbol): Variance = { def nextVariance(sym: Symbol, v: Variance): Variance = ( if (shouldFlip(sym, tvar)) v.flip - else if (isLocalOnly(sym)) Bivariant + else if (isExemptFromVariance(sym)) Bivariant else if (sym.isAliasType) ( // Unsound pre-2.11 behavior preserved under -Xsource:2.10 if (settings.isScala211 || sym.isOverridingSymbol) Invariant @@ -126,7 +124,7 @@ trait Variances { tp match { case _ if isUncheckedVariance(tp) => case _ if resultTypeOnly(tp) => this(tp.resultType) - case TypeRef(_, sym, _) if sym.isAliasType => this(tp.normalize) + case TypeRef(_, sym, _) if shouldDealias(sym) => this(tp.normalize) case TypeRef(_, sym, _) if !sym.variance.isInvariant => checkVarianceOfSymbol(sym) ; mapOver(tp) case RefinedType(_, _) => withinRefinement(mapOver(tp)) case ClassInfoType(parents, _, _) => parents foreach this @@ -138,6 +136,12 @@ trait Variances { // than the result of the pattern match above, which normalizes types. tp } + private def shouldDealias(sym: Symbol): Boolean = { + // The RHS of (private|protected)[this] type aliases are excluded from variance checks. This is + // implemented in relativeVariance. + // As such, we need to expand references to them to retain soundness. Example: neg/t8079a.scala + sym.isAliasType && isExemptFromVariance(sym) + } def validateDefinition(base: Symbol) { val saved = this.base this.base = base |