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

Compiler bug for updateDynamic invocations within expressions

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: Scala 2.10.0-M3
    • Fix Version/s: Scala 2.10.0
    • Component/s: Misc Compiler
    • Labels:
    • Environment:

      Scala code runner version 2.10.0-20120502-114738-cc8671c165

      Description

      Problem with updateDynamic:
      If a dynamic field assignment is invoked within an expression (the type of the assignment invocation depends on the result type of method updateDynamic), then the compiler reports the error reassignment to val.

      scala> val foo = new A // A implements selectDynamic and updateDynamic
      foo: A = A@71933d6c
      
      scala> foo.xxx = 3
      foo.xxx: Any = 3
      
      scala> foo.xxx
      res0: Any = 3
      
      scala> println(foo.xxx = 3)
      <console>:12: error: reassignment to val
                    println(foo.xxx = 3)
                                    ^
      
      scala> val x = (foo.xxx = 3) == ()
      <console>:11: error: reassignment to val
             val x = (foo.xxx = 3) == ()
                              ^
      

        Activity

        Hide
        Dominik Gruntz added a comment -

        Actually, the latter assignments are not translated by the compiler to invocations of updateDynamic. If we look at the tree after typers, it looks as follows:

            private[this] val foo: A = new A();
            Test.this.foo.updateDynamic("xxx")(3);
            scala.this.Predef.println(foo.xxx = 3);
            private[this] val x: <error> = foo.xxx = 3.==()
        
        Show
        Dominik Gruntz added a comment - Actually, the latter assignments are not translated by the compiler to invocations of updateDynamic . If we look at the tree after typers, it looks as follows: private[this] val foo: A = new A(); Test.this.foo.updateDynamic("xxx")(3); scala.this.Predef.println(foo.xxx = 3); private[this] val x: <error> = foo.xxx = 3.==()
        Hide
        Mark Harrah added a comment -

        Can you provide an implementation of A that demonstrates this issue?

        Show
        Mark Harrah added a comment - Can you provide an implementation of A that demonstrates this issue?
        Hide
        Alexis Agahi added a comment - - edited

        Can't figure out why updateDynamic works in App and wont compile the test class...

        src/AB.scala
        import language.dynamics
        
        object A extends Dynamic {
          var a = "a"
        
          def selectDynamic(method:String): String = a
        
          def updateDynamic(method:String)(v:String) { a = v }
        }
        
        class B extends Dynamic {
          var b = "b"
        
          def selectDynamic(method:String): String = b
        
          def updateDynamic(method:String)(v:String) { b = v }
        }
        
        object TestApp extends App {
          assert( A.foo == "a" )
          assert( A.bar == "a" )
          A.aaa = "aaa"
          assert( A.bar == "aaa" )
        
        
          val b = new B
          assert( b.foo == "b" )
          assert( b.bar == "b" )
          b.bbb = "bbb"
          assert( b.bar == "bbb" )
        
          println("Done")
        }
        
        test/ABTest.scala
        import org.junit.Test
        import language.dynamics
        
        class ABTest {
        
          @Test
          def test() {
            assert( A.foo == "a" )
            assert( A.bar == "a" )
            A.aaa = "aaa"
            assert( A.bar == "aaa" )
        
        
            val b = new B
            assert( b.foo == "b" )
            assert( b.bar == "b" )
            b.bbb = "bbb"
            assert( b.bar == "bbb" )
        
          }
        
        }
        
        build.sbt
        scalaVersion := "2.10.0-RC1"
        
        scalaSource in Compile <<= baseDirectory(_ / "src")
        
        scalaSource in Test <<= baseDirectory(_ / "test")
        
        libraryDependencies += "com.novocode" % "junit-interface" % "0.10-M1" % "test"
        
        libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.10.0-RC1"
        
        libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-RC1"
        
        > scala-version
        [info] 2.10.0-RC1
        > sbt-version
        [info] 0.12.1
        > test
        [info] Compiling 1 Scala source to /2.10/target/scala-2.10/test-classes...
        [error] /2.10/test/ABTest.scala:24: reassignment to val
        [error]     A.aaa = "aaa"
        [error]           ^
        [error] /2.10/test/DynamicTest.scala:31: reassignment to val
        [error]     b.bbb = "bbb"
        [error]           ^
        [error] two errors found
        [error] (test:compile) Compilation failed
        
        > clean
        [success] Total time: 0 s, completed 14 oct. 2012 00:18:51
        > run
        [info] Updating {file:/2.10/}default-5d6b7a...
        [info] Resolving org.scala-tools.testing#test-interface;0.5 ...
        [info] Done updating.
        [info] Compiling 1 Scala sources to /2.10/target/scala-2.10/classes...
        [info] Running TestApp 
        Done
        [success] Total time: 17 s, completed 14 oct. 2012 00:19:09
        
        Show
        Alexis Agahi added a comment - - edited Can't figure out why updateDynamic works in App and wont compile the test class... src/AB.scala import language.dynamics object A extends Dynamic { var a = "a" def selectDynamic(method:String): String = a def updateDynamic(method:String)(v:String) { a = v } } class B extends Dynamic { var b = "b" def selectDynamic(method:String): String = b def updateDynamic(method:String)(v:String) { b = v } } object TestApp extends App { assert( A.foo == "a" ) assert( A.bar == "a" ) A.aaa = "aaa" assert( A.bar == "aaa" ) val b = new B assert( b.foo == "b" ) assert( b.bar == "b" ) b.bbb = "bbb" assert( b.bar == "bbb" ) println("Done") } test/ABTest.scala import org.junit.Test import language.dynamics class ABTest { @Test def test() { assert( A.foo == "a" ) assert( A.bar == "a" ) A.aaa = "aaa" assert( A.bar == "aaa" ) val b = new B assert( b.foo == "b" ) assert( b.bar == "b" ) b.bbb = "bbb" assert( b.bar == "bbb" ) } } build.sbt scalaVersion := "2.10.0-RC1" scalaSource in Compile <<= baseDirectory(_ / "src") scalaSource in Test <<= baseDirectory(_ / "test") libraryDependencies += "com.novocode" % "junit-interface" % "0.10-M1" % "test" libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.10.0-RC1" libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.0-RC1" > scala-version [info] 2.10.0-RC1 > sbt-version [info] 0.12.1 > test [info] Compiling 1 Scala source to /2.10/target/scala-2.10/test-classes... [error] /2.10/test/ABTest.scala:24: reassignment to val [error] A.aaa = "aaa" [error] ^ [error] /2.10/test/DynamicTest.scala:31: reassignment to val [error] b.bbb = "bbb" [error] ^ [error] two errors found [error] (test:compile) Compilation failed > clean [success] Total time: 0 s, completed 14 oct. 2012 00:18:51 > run [info] Updating {file:/2.10/}default-5d6b7a... [info] Resolving org.scala-tools.testing#test-interface;0.5 ... [info] Done updating. [info] Compiling 1 Scala sources to /2.10/target/scala-2.10/classes... [info] Running TestApp Done [success] Total time: 17 s, completed 14 oct. 2012 00:19:09
        Show
        Paul Phillips added a comment - https://github.com/scala/scala/pull/1681
        Show
        Jason Zaugg added a comment - https://github.com/scala/scala/commit/edbcc64483ac0009eeeb58fe31e57a411da9e4c6

          People

          • Assignee:
            Paul Phillips
            Reporter:
            Dominik Gruntz
          • Votes:
            1 Vote for this issue
            Watchers:
            7 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development