Scala Programming Language
  1. Scala Programming Language
  2. SI-4712

Raw type used in argument position is not existentially quantified

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: Scala 2.8.1, Scala 2.9.0
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None

      Description

      IBaseInterface.java
      public interface IBaseInterface<T> { 
          void f(T t); 
      }
      
      IDerivedInterface.java
      public interface IDerivedInterface extends IBaseInterface<Class> { 
          void g(Class c); 
      }
      
      Problem.scala
      object Problem { 
        def a(i:IDerivedInterface) = i.f(classOf[String]) // error!
        def b(i:IDerivedInterface) = i.g(classOf[String]) 
      }
      
      problem.scala:2: error: type mismatch;
       found   : Class[_$1] where type _$1
       required: java.lang.Class
        def a(i:IDerivedInterface) = i.f(classOf[String].asInstanceOf[Class[_]]) 
      

      Notice the required type 'java.lang.Class', which should be transformed to an existential type when seen from IDerivedInterface. The compiler does the correct thing for the method g, which is not inherited.

        Activity

        Hide
        Adriaan Moors added a comment - - edited

        I had a quick look, and I think the problem is that cooking of a symbol's info happens irrespective of the actual type arguments that are provided for the type parameters in scope at the symbol.

        Concretely, cooking is a no-op for the info of `method f` since `T` is not considered a raw type. Of course it is instantiated to the mother of all raw types, Class, here, but that happens after cooking.

        Debug info for illustration:

        typing i.f(classOf[String]): pt = ?
        typing i.f: pt = ?
        [...]
        cooking: method f: (x$1: T)Unit to (x$1: T)Unit
        typed i.f: (x$1: java.lang.Class)Unit
        adapted i.f: (x$1: java.lang.Class)Unit to ?,

        Show
        Adriaan Moors added a comment - - edited I had a quick look, and I think the problem is that cooking of a symbol's info happens irrespective of the actual type arguments that are provided for the type parameters in scope at the symbol. Concretely, cooking is a no-op for the info of `method f` since `T` is not considered a raw type. Of course it is instantiated to the mother of all raw types, Class, here, but that happens after cooking. Debug info for illustration: typing i.f(classOf [String] ): pt = ? typing i.f: pt = ? [...] cooking: method f: (x$1: T)Unit to (x$1: T)Unit typed i.f: (x$1: java.lang.Class)Unit adapted i.f: (x$1: java.lang.Class)Unit to ?,
        Hide
        Adriaan Moors added a comment - - edited

        proposed fix:

                 } else if (!context.undetparams.isEmpty && !inPolyMode(mode)) { // (9)
                  assert(!inHKMode(mode)) //@M
                  instantiate(tree, mode, pt)
        +        } else if (tree.hasSymbol && tree.symbol.isJavaDefined && (tree.tpe.isInstanceOf[MethodType] || tree.tpe.isInstanceOf[OverloadedType])) {
        +          // may need to re-cook now that type parameters have been instantiated to possibly raw type arguments
        +          tree setType rawToExistential(tree.tpe)
                } else if (tree.tpe <:< pt) {
                  tree
        
        Show
        Adriaan Moors added a comment - - edited proposed fix: } else if (!context.undetparams.isEmpty && !inPolyMode(mode)) { // (9) assert(!inHKMode(mode)) //@M instantiate(tree, mode, pt) + } else if (tree.hasSymbol && tree.symbol.isJavaDefined && (tree.tpe.isInstanceOf[MethodType] || tree.tpe.isInstanceOf[OverloadedType])) { + // may need to re-cook now that type parameters have been instantiated to possibly raw type arguments + tree setType rawToExistential(tree.tpe) } else if (tree.tpe <:< pt) { tree
        Hide
        Martin Odersky added a comment -

        We could do that, but it comes a bit late for my taste. The problem is when we compute the base type of Derived. I'd rather eliminate the raw type there.

        Show
        Martin Odersky added a comment - We could do that, but it comes a bit late for my taste. The problem is when we compute the base type of Derived. I'd rather eliminate the raw type there.
        Hide
        Simon Ochsenreither added a comment -

        This seems to be related to SI-3634.

        Show
        Simon Ochsenreither added a comment - This seems to be related to SI-3634 .
        Hide
        Adriaan Moors added a comment -

        right, I see what you meant now in my office – I've found it a bit trickier to find a nice hook so that TypeRef's baseType and baseTypeSeq uniformly do the right thing...

        Show
        Adriaan Moors added a comment - right, I see what you meant now in my office – I've found it a bit trickier to find a nice hook so that TypeRef's baseType and baseTypeSeq uniformly do the right thing...
        Hide
        Commit Message Bot added a comment -

        (odersky in r25126) Fixes #4712. Review by moors.

        Show
        Commit Message Bot added a comment - (odersky in r25126 ) Fixes #4712. Review by moors.
        Hide
        Martin Odersky added a comment - - edited

        My earlier attempts did not work because other things fail by going from raw to existential too early. The new (admittedly kludgey) fix is to do rawToExistential very late, once we already got an error.

        Show
        Martin Odersky added a comment - - edited My earlier attempts did not work because other things fail by going from raw to existential too early. The new (admittedly kludgey) fix is to do rawToExistential very late, once we already got an error.

          People

          • Assignee:
            Martin Odersky
            Reporter:
            Iulian Dragos
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development