E195: Phantom Symbol Not Value

This error occurs when you try to use a compiler-generated phantom symbol as a standalone value. Phantom symbols are synthetic entries created by the compiler for various features but cannot be used as actual values.

This error is triggered for:

  • Constructor proxies: Symbols representing factory methods for non-case classes (since 3.3.1)
  • Context bound companions: Symbols representing witnesses for context bounds (since 3.5.0)
  • Dummy capture parameters: Symbols representing references to capture parameters in experimental capture checking (since 3.7.2)

Note: This error code is used by multiple message classes and the exact message varies depending on the context.


Example

The following example demonstrates a dummy capture parameter being incorrectly used as a value. This occurs when using the experimental capture checking feature:

import language.experimental.captureChecking

class A:
  type C^

def example(a: A): a.C = a.C

Here, C^ declares a capture parameter type, and the compiler creates a synthetic term C to allow referring to it in capture sets. However, this term cannot be used as an actual value.

Error

-- [E195] Type Error: example.scala:6:27 ---------------------------------------
6 |def example(a: A): a.C = a.C
  |                         ^^^
  |            dummy term capture parameter value C cannot be used as a value
  |-----------------------------------------------------------------------------
  | Explanation (enabled by `-explain`)
  |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  | A term capture parameter is a symbol made up by the compiler to represent a reference
  | to a real capture parameter in capture sets. For instance, in
  |
  |    class A:
  |      type C^
  |
  | there is just a type `A` declared but not a value `A`. Nevertheless, one can write
  | the selection `(a: A).C` and use a a value, which works because the compiler created a
  | term capture parameter for `C`. However, these term capture parameters are not real values,
  | they can only be referred in capture sets.
   -----------------------------------------------------------------------------

Solution

Use a real declared member instead of the phantom symbol:

import language.experimental.captureChecking

class A:
  type C^
  val getC: C = ???

def example(a: A): a.C = a.getC