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

Nesting of @static field and separate compilation definition-site and call-site causes compiler crash in icode phase with message "no-symbol does not have an owner"

    Details

      Description

      scala> object Foo {
           | @annotation.static val foo = 353/0 }
      defined module Foo
      scala> println(Foo.foo)
      ReplGlobal.abort: no-symbol does not have an owner
      error: no-symbol does not have an owner
      error:
           while compiling: <console>
              during phase: icode
           library version: version 2.10.0-M6
          compiler version: version 2.10.0-M6
        reconstructed args:
      
      ...
      
      
      That entry seems to have slain the compiler.  Shall I replay
      your session? I can re-run each line except the last one.
      [y/n]
      

      see

      https://groups.google.com/forum/?fromgroups#!topic/scala-internals/RA8xNVri60s%5B1-25%5D

        Activity

        Hide
        Paul Phillips added a comment -

        It's unrelated to the repl. Just nest like the repl does.

        // a.scala
        package p {
          object x {
            object x {
              @scala.annotation.static val foo: Int = 353
            }
          }
        }
        // b.scala - separately compiled
        object Test {
          def main(args: Array[String]): Unit = {
            println(p.x.x.foo)
          }
        }
        
        Show
        Paul Phillips added a comment - It's unrelated to the repl. Just nest like the repl does. // a.scala package p { object x { object x { @scala.annotation.static val foo: Int = 353 } } } // b.scala - separately compiled object Test { def main(args: Array[String]): Unit = { println(p.x.x.foo) } }
        Hide
        DaveScala added a comment -

        Thanks Paul, changed the title

        Show
        DaveScala added a comment - Thanks Paul, changed the title
        Hide
        Aleksandar Prokopec added a comment -

        Apparently, the first compilation creates a classfile for p.x.x which has a static field foo:

        Compiled from "file_1.scala"
        public class p.x$x extends java.lang.Object
          SourceFile: "file_1.scala"
          Scala: length = 0x
           
        ...
        
        const #20 = Asciz	SourceFile;
        const #21 = Asciz	Scala;
        
        {
        public static int foo;
        
        ...
        
        }
        
        

        During the second compilation, during icode, members of p.x.x are missing foo:

        Scope{
          def <init>(): p.y$x;
          final def $asInstanceOf[T0 >: ? <: ?](): T0;
          final def $isInstanceOf[T0 >: ? <: ?](): Boolean;
          final def synchronized(x$1: Object): Object;
          final def ##(): Int;
          final def !=(x$1: Object): Boolean;
          final def ==(x$1: Object): Boolean;
          final def ne(x$1: Object): Boolean;
          final def eq(x$1: Object): Boolean;
          protected[package lang] def finalize(): Unit;
          final def wait(): Unit;
          final def wait(x$1: Long,x$2: Int): Unit;
          final def wait(x$1: Long): Unit;
          final def notifyAll(): Unit;
          final def notify(): Unit;
          def toString(): String;
          protected[package lang] def clone(): Object;
          def equals(x$1: Object): Boolean;
          def hashCode(): Int;
          final def getClass(): Class;
          def <init>(): Object
        }
        
        Show
        Aleksandar Prokopec added a comment - Apparently, the first compilation creates a classfile for p.x.x which has a static field foo : Compiled from "file_1.scala" public class p.x$x extends java.lang.Object SourceFile: "file_1.scala" Scala: length = 0x ... const #20 = Asciz SourceFile; const #21 = Asciz Scala; { public static int foo; ... } During the second compilation, during icode, members of p.x.x are missing foo : Scope{ def <init>(): p.y$x; final def $asInstanceOf[T0 >: ? <: ?](): T0; final def $isInstanceOf[T0 >: ? <: ?](): Boolean; final def synchronized(x$1: Object): Object; final def ##(): Int; final def !=(x$1: Object): Boolean; final def ==(x$1: Object): Boolean; final def ne(x$1: Object): Boolean; final def eq(x$1: Object): Boolean; protected[package lang] def finalize(): Unit; final def wait(): Unit; final def wait(x$1: Long,x$2: Int): Unit; final def wait(x$1: Long): Unit; final def notifyAll(): Unit; final def notify(): Unit; def toString(): String; protected[package lang] def clone(): Object; def equals(x$1: Object): Boolean; def hashCode(): Int; final def getClass(): Class; def <init>(): Object }
        Hide
        Paul Phillips added a comment -

        When reading from bytecode, and when reading from java source, statics are mapped into the (possibly synthetic) companion object of the class being read. So although there is bytecode for p$x$x with a static field in it, the scala class p.x.x does not have it; the object p.x.x does.

        If I change this:

        val hostClass = qual.tpe.typeSymbol.orElse(sym.owner).companionClass

        Not to call companionClass, then it finds the field foo and stops crashing. Of course then it fails at runtime with "java.lang.NoSuchFieldError: foo" because the confusion surrounding this is not so nicely localized.

        Show
        Paul Phillips added a comment - When reading from bytecode, and when reading from java source, statics are mapped into the (possibly synthetic) companion object of the class being read. So although there is bytecode for p$x$x with a static field in it, the scala class p.x.x does not have it; the object p.x.x does. If I change this: val hostClass = qual.tpe.typeSymbol.orElse(sym.owner).companionClass Not to call companionClass, then it finds the field foo and stops crashing. Of course then it fails at runtime with "java.lang.NoSuchFieldError: foo" because the confusion surrounding this is not so nicely localized.
        Hide
        Paul Phillips added a comment -

        Ah, I see you made exactly that change in https://github.com/scala/scala/pull/1138 .

        Show
        Paul Phillips added a comment - Ah, I see you made exactly that change in https://github.com/scala/scala/pull/1138 .
        Hide
        Aleksandar Prokopec added a comment -

        Ah, of course - a static field won't be in the list of members of the class. Thanks for pointing this out.

        I still call the companionClass in 1138, I just moved it to the next line.

        Show
        Aleksandar Prokopec added a comment - Ah, of course - a static field won't be in the list of members of the class. Thanks for pointing this out. I still call the companionClass in 1138, I just moved it to the next line.
        Hide
        Aleksandar Prokopec added a comment - - edited

        The symbol for foo in the companion object still has the static annotation during the second compilation. If the current run does not compile the companion object and the field is @static-annotated, then I can probably recreate the static field in the companion class.

        Show
        Aleksandar Prokopec added a comment - - edited The symbol for foo in the companion object still has the static annotation during the second compilation. If the current run does not compile the companion object and the field is @static -annotated, then I can probably recreate the static field in the companion class.
        Show
        Aleksandar Prokopec added a comment - https://github.com/scala/scala/pull/1138

          People

          • Assignee:
            Aleksandar Prokopec
            Reporter:
            DaveScala
          • Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development