SIP-19 Implicit Source Locations

Philipp Haller

30 March 2012

Motivation

The Scala compiler's error messages would be nearly useless if they wouldn't provide the corresponding source location, that is, file name, line number, and (some representation of the) character offset, of each error. However, source locations are also very useful outside of the compiler. Libraries and frameworks routinely deal with application- or system-level errors (usually in the form of exceptions), logging, debugging support through tracing, etc. All of these aspects greatly benefit from source location information.

Moreover, embedded domain-specific languages often depend upon source location information for providing useful error messages. Domain-specific languages that employ staging for code generation can use source locations for debug information in the generated code.

This proposal discusses a minimal extension of Scala's implicit parameters to provide access to the source location of method invocations. The design is analogous to the way manifests are generated by the compiler, and should therefore be natural to anyone familiar with manifests in Scala.

Example

To obtain the source location for each invocation of a method debug, say, one adds an implicit parameter of type SourceLocation:

def debug(message: String)(implicit loc: SourceLocation): Unit = {
  println("@" + loc.fileName + ":" + loc.line + ": " + message)
}

This means that inside the body of the debug method, we can access the source location of its current invocation through the loc parameter. For example, suppose we are invoking debug on line 34 in a file "MyApp.scala":

34:    if (debugEnabled) debug("debug message")

Assuming debugEnabled evaluates to true, the above expression would lead to the following output:

@MyApp.scala:34: debug message

The SourceLocation Trait

The SourceLocation trait is a new type member of the scala.reflect package. It has the following members:

trait SourceLocation {
  /** The name of the source file */
  def fileName: String

  /** The line number */
  def line: Int

  /** The character offset */
  def charOffset: Int
}

Specification

Implicit source locations are supported through the following small addition to Scala's implicit rules.

If an implicit parameter of a method or constructor is of type SourceLocation, a source location object is determined according to the following rules.

First, if there is already an implicit argument of type SourceLocation, this argument is selected. Otherwise, an instance of SourceLocation is generated by invoking the apply method of the object scala.reflect.SourceLocation, passing the components of the source location as arguments.

Implementation

An implementation of this proposal can be found at: https://github.com/phaller/scala/tree/topic/source-location

An extension of this proposal is also part of Scala-Virtualized. The extension adds a subtrait SourceContext which in addition provides access to information, such as variable names in the context of a method invocation. More information can be found at: https://github.com/TiarkRompf/scala-virtualized/wiki/SourceLocation-and-SourceContext

blog comments powered by Disqus

Contents

SIP Committee Decision

Not Accepted

This is in Not Accepted status. We expect this to be easily implemented using macros without going through a full SIP.