Details

      Description

      If I change the definition of encode in Names to "def encode: Name with ThisNameType" then this compiles, which should make it definitive that this is a bug given that ThisNameType <: Name.

      trait Namers {
        val global: scala.tools.nsc.Global
        import global.{ Name, Symbol }
      
        // Relevant definitions in Names
        //
        // def encode: ThisNameType
        // type ThisNameType >: Null <: Name
        //
        def f(x: Symbol): Name = x.name.encode
      
        /**
        b.scala:5: error: type mismatch;
         found   : Name.this.ThisNameType
         required: Namers.this.global.Name
          def f(x: Symbol): Name = x.name.encode
                                          ^
        one error found
        **/
      }
      

        Issue Links

          Activity

          Hide
          Paul Phillips added a comment -

          I think that example is "correct" because of SI-7278. "Same-named inner classes which are in no relationship with each other are explicitly allowed in both Java and Scala." The Element in A2 is not the Element in A1. But parameter types must match exactly. So the method declared in A1#Element has a different signature than the one declared in A2#Element.

          If it seems unsound, it's because it is.

          Show
          Paul Phillips added a comment - I think that example is "correct" because of SI-7278 . "Same-named inner classes which are in no relationship with each other are explicitly allowed in both Java and Scala." The Element in A2 is not the Element in A1. But parameter types must match exactly. So the method declared in A1#Element has a different signature than the one declared in A2#Element. If it seems unsound, it's because it is.
          Hide
          Paul Phillips added a comment -

          Note that if I define child in A2 like this:

          override def child(e: A2.super.Element):Unit = super.child(e)
          

          Then the signatures match and the override is fine, but we have a different and also true error:

          ./a.scala:18: error: class Element needs to be abstract, since method child in trait Elt of type (e: A2.this.Element)Unit is not defined
          (Note that A.this.Element does not match A2.this.Element)
            class Element extends super.Element {
                  ^
          one error found
          

          ...because the method signature in A2#Element no longer matches the abstract signature defined in A#Elt. Just for fun I will call super.child from THAT method so we can see all the types at play. This compiles.

          trait A {
            type Element<:Elt
            trait Elt {
              def doIt(x:Int):Int
              def child(e:Element):Unit
            }
          }
          class A1 extends A {
            class Element extends Elt {
              def doIt(x:Int):Int = x+3
              def child(e: A1.this.Element):Unit = ()
            }
          }
          class A2 extends A1 {
            class Element extends super.Element {
              override def doIt(x:Int):Int = super.doIt(x)+1
              override def child(e: A2.super.Element):Unit = super.child(e)
              def child(e: A2.this.Element):Unit = super.child(e: A2.super.Element)
            }
          }
          
          Show
          Paul Phillips added a comment - Note that if I define child in A2 like this: override def child(e: A2.super.Element):Unit = super.child(e) Then the signatures match and the override is fine, but we have a different and also true error: ./a.scala:18: error: class Element needs to be abstract, since method child in trait Elt of type (e: A2.this.Element)Unit is not defined (Note that A.this.Element does not match A2.this.Element) class Element extends super.Element { ^ one error found ...because the method signature in A2#Element no longer matches the abstract signature defined in A#Elt. Just for fun I will call super.child from THAT method so we can see all the types at play. This compiles. trait A { type Element<:Elt trait Elt { def doIt(x:Int):Int def child(e:Element):Unit } } class A1 extends A { class Element extends Elt { def doIt(x:Int):Int = x+3 def child(e: A1.this.Element):Unit = () } } class A2 extends A1 { class Element extends super.Element { override def doIt(x:Int):Int = super.doIt(x)+1 override def child(e: A2.super.Element):Unit = super.child(e) def child(e: A2.this.Element):Unit = super.child(e: A2.super.Element) } }
          Hide
          Grzegorz Kossakowski added a comment -

          Unassigning and rescheduling to M7 as previous deadline was missed.

          Show
          Grzegorz Kossakowski added a comment - Unassigning and rescheduling to M7 as previous deadline was missed.
          Hide
          Paul Phillips added a comment -

          I am not sure this can be fixed due to language unsoundness described in SI-7278.

          package p {
            trait N { type Name ; def make(): Name }
            trait N1 extends N { class Name ; def make(): Name = new Name }
            trait N2 extends N { class Name }
          
            object g extends App with N1 with N2 {
              val x = (this: N2).make()
              // java.lang.ClassCastException: p.N1$Name cannot be cast to p.N2$Name
            }
          }
          

          Until we're talking about a language where object g doesn't freely discard information about the types of its inherited members, or where the type x.Name doesn't fluctuate depending on the static type of x, there's no way to draw sound inferences based on the way an abstract type is refined in a trait.

          Show
          Paul Phillips added a comment - I am not sure this can be fixed due to language unsoundness described in SI-7278 . package p { trait N { type Name ; def make(): Name } trait N1 extends N { class Name ; def make(): Name = new Name } trait N2 extends N { class Name } object g extends App with N1 with N2 { val x = (this: N2).make() // java.lang.ClassCastException: p.N1$Name cannot be cast to p.N2$Name } } Until we're talking about a language where object g doesn't freely discard information about the types of its inherited members, or where the type x.Name doesn't fluctuate depending on the static type of x, there's no way to draw sound inferences based on the way an abstract type is refined in a trait.
          Hide
          Adriaan Moors added a comment -

          Wanted to keep it on my radar until the Sunday haze clears, but probably need to push to 2.12, yes.

          Show
          Adriaan Moors added a comment - Wanted to keep it on my radar until the Sunday haze clears, but probably need to push to 2.12, yes.

            People

            • Assignee:
              Adriaan Moors
              Reporter:
              Paul Phillips
            • Votes:
              0 Vote for this issue
              Watchers:
              7 Start watching this issue

              Dates

              • Created:
                Updated:

                Development