Skip to content

Commit

Permalink
Class symbols can't be contravariant.
Browse files Browse the repository at this point in the history
During development of the fix for SI-6666, I encountered:

    % test/files/pos/t4842.scala
    test/files/pos/t4842.scala:10: error: contravariant class Bar occurs in covariant position in type ()this.Bar of constructor Bar
         this(new { class Bar { println(Bar.this); new { println(Bar.this) } }; new Bar } ) // okay

I had incorrectly set the INCONSTRUCTOR flag on the class symbol
`Bar`. (It isn't directly in the self constructor call, as it
is nested an intervening anonymous class.)

But, this flag shares a slot with CONTRAVARIANT, and the variance
validation intepreted it as such.

ClassSymbol already has this code to resolve the ambiguous
flags for display purposes:

    override def resolveOverloadedFlag(flag: Long) = flag match {
      case INCONSTRUCTOR => "<inconstructor>" // INCONSTRUCTOR / CONTRAVARIANT / LABEL
      case EXISTENTIAL   => "<existential>"   // EXISTENTIAL / MIXEDIN
      case IMPLCLASS     => "<implclass>"     // IMPLCLASS / PRESUPER
      case _             => super.resolveOverloadedFlag(flag)
    }

This commit overrides `isContravariant` to reflect the same logic.
  • Loading branch information
retronym committed Feb 4, 2013
1 parent 275b341 commit 81fa831
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/compiler/scala/tools/nsc/interpreter/IMain.scala
Expand Up @@ -262,7 +262,9 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
protected def newCompiler(settings: Settings, reporter: Reporter): ReplGlobal = {
settings.outputDirs setSingleOutput virtualDirectory
settings.exposeEmptyPackage.value = true
new Global(settings, reporter) with ReplGlobal
new Global(settings, reporter) with ReplGlobal {
override def toString: String = "<global>"
}
}

/** Parent classloader. Overridable. */
Expand Down
1 change: 1 addition & 0 deletions src/reflect/scala/reflect/internal/Symbols.scala
Expand Up @@ -2867,6 +2867,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final override def isNonClassType = false
final override def isAbstractType = false
final override def isAliasType = false
final override def isContravariant = false

override def isAbstractClass = this hasFlag ABSTRACT
override def isCaseClass = this hasFlag CASE
Expand Down
36 changes: 36 additions & 0 deletions test/files/run/class-symbol-contravariant.check
@@ -0,0 +1,36 @@
Type in expressions to have them evaluated.
Type :help for more information.

scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'. **
** scala.tools.nsc._ has been imported **
** global._, definitions._ also imported **
** Try :help, :vals, power.<tab> **

scala> val u = rootMirror.universe
u: $r.intp.global.type = <global>

scala> import u._, scala.reflect.internal.Flags
import u._
import scala.reflect.internal.Flags

scala> class C
defined class C

scala> val sym = u.typeOf[C].typeSymbol
sym: u.Symbol = class C

scala> sym.isContravariant
res0: Boolean = false

scala> sym setFlag Flags.INCONSTRUCTOR
res1: sym.type = class C

scala> sym.isClassLocalToConstructor
res2: Boolean = true

scala> sym.isContravariant // was true
res3: Boolean = false

scala>
15 changes: 15 additions & 0 deletions test/files/run/class-symbol-contravariant.scala
@@ -0,0 +1,15 @@
import scala.tools.partest.ReplTest

object Test extends ReplTest {
override def code = """
|:power
|val u = rootMirror.universe
|import u._, scala.reflect.internal.Flags
|class C
|val sym = u.typeOf[C].typeSymbol
|sym.isContravariant
|sym setFlag Flags.INCONSTRUCTOR
|sym.isClassLocalToConstructor
|sym.isContravariant // was true
|""".stripMargin.trim
}

0 comments on commit 81fa831

Please sign in to comment.