Scala Compiler Plugin for Unique References

1.1 Build instructions

Check out the scala-unique branch:
      $ svn co https://lampsvn.epfl.ch/svn-repos/scala/scala/branches/scala-unique
    
Build the Scala compiler and library:
      $ ant
    
Build the uniqueness checker:
      $ ant pack.unique-library
    

This builds the plugin and the source annotations. You find the plugin packaged as a jar under build/pack/lib/unique-plugin.jar. Using the plugin also requires a few other Scala classes that are packaged as a jar under build/pack/lib/unique-library.jar.

Alternatively, the plugin can also be built using the compiler of a separate 2.8 Scala distribution (such as 2.8 Beta1). The compile-plugin.sh script picks up the compiler using the SCALA_HOME environment variable.

At this point, you may choose to run the test suite distributed with the plugin source, or use the plugin to check some example programs. Alternatively, Section 1.3 walks you through a simple example.

Cleaning the unique-plugin build:
      $ ant unique-plugin.clean
    

1.2 Running the test suite and checking example programs

Run tests for unique-plugin:
      $ ant test.unique-plugin
    
Compiling/checking partest with uniqueness annotations:
      $ ant -f build-partest-unique.xml
    
Clean build of partest-unique:
      $ ./compile-partest-unique.sh
    
Compiling/checking collections examples:
      $ ./check-double.sh
      $ ./check-hashmap.sh
      $ ./check-listbuffer.sh
    
Compiling/checking ray tracer example (requires compiling the ListBuffer example first):
      $ ./check-raytracer.sh
    

1.3 Example use

  1. Let's consider this very simple Scala class:
              /*-enable-unique*/
              import scala.annotation.unique
              class C {
                var f: C = _
                def consume(x: C @unique) {}
    
                def m() {
                  val c: C @unique = new C
                  consume(c)
                }
              }
            
    The method consume expects a unique object, indicated by the @unique annotation. For simplicity, we leave the body empty, but one could, for instance, transfer x to another actor. Next, we define the m method, which creates a unique instance c of class C. Then, it invokes consume, passing c. This is valid, since c is unique.
  2. Run the uniqueness checker on the class. Run scalac as usual, passing the -Xplugin flag:
              scalac -Xplugin:build/pack/lib/unique-plugin.jar -cp build/pack/lib/unique-library.jar GetStarted.scala
            
    The compilation should complete without any errors.
  3. Let's introduce an error now by invoking consume twice:
              val c: C @unique = new C
              consume(c)
              consume(c)
            
  4. Run the uniqueness checker again, just as before. This run should emit the following error:
              GetStarted.scala:10: error: not all required capabilities available
                  consume(c)
                         ^
              one error found