Semantic

dotty.tools.dotc.transform.init.Semantic
object Semantic

Checks safe initialization of objects

This algorithm cannot handle safe access of global object names. That part is handled by the check in Objects (@see Objects).

Attributes

Graph
Supertypes
class Object
trait Matchable
class Any
Self type
Semantic.type

Members list

Type members

Classlikes

object Cache

Cache used in fixed point computation

Cache used in fixed point computation

The analysis computes the least fixed point for the cache (see doc for ExprValueCache).

For the fixed point computation to terminate, we need to make sure that the domain of the cache, i.e. the key pair (Ref, Tree) is finite. As the code is finite, we only need to carefully design the abstract domain to be finitary.

We also need to make sure that the computing function (i.e. the abstract interpreter) is monotone. Error handling breaks monotonicity of the abstract interpreter, because when an error happens, we always return the bottom value Hot for an expression. It is not a threat for termination because when an error happens, we stop the fixed point computation at the end of the iteration where the error happens. Care must be paid to tests of errors, monotonicity will be broken if we simply ignore the test errors (See TryReporter).

Note: It's tempting to use location of trees as key. That should be avoided as a template may have the same location as its single statement body. Macros may also create incorrect locations.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Cache.type
case object Cold extends Value

An object with unknown initialization status

An object with unknown initialization status

Attributes

Supertypes
trait Singleton
trait Product
trait Mirror
trait Serializable
trait Product
trait Equals
class Value
class Object
trait Matchable
class Any
Show all
Self type
Cold.type
case class Fun(expr: Tree, thisV: Ref, klass: ClassSymbol) extends Value

A function value

A function value

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Value
class Object
trait Matchable
class Any
Show all
case object Hot extends Value

A transitively initialized object

A transitively initialized object

Attributes

Supertypes
trait Singleton
trait Product
trait Mirror
trait Serializable
trait Product
trait Equals
class Value
class Object
trait Matchable
class Any
Show all
Self type
Hot.type
case class Objekt(klass: ClassSymbol, fields: Map[Symbol, Value], outers: Map[ClassSymbol, Value])

The abstract object which stores value about its fields and immediate outers.

The abstract object which stores value about its fields and immediate outers.

Semantically it suffices to store the outer for klass. We cache other outers for performance reasons.

Note: Object is NOT a value.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
opaque object Promoted

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Promoted.type
sealed abstract class Ref extends Value

Attributes

Supertypes
class Value
class Object
trait Matchable
class Any
Known subtypes
class ThisRef
class Warm
case class RefSet(refs: List[Fun | Ref]) extends Value

A value which represents a set of addresses

A value which represents a set of addresses

It comes from if expressions.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Value
class Object
trait Matchable
class Any
Show all
object Reporter

Attributes

Companion
trait
Supertypes
class Object
trait Matchable
class Any
Self type
Reporter.type
trait Reporter

Error reporting

Error reporting

Attributes

Companion
object
Supertypes
class Object
trait Matchable
class Any
Known subtypes
case class ThisRef(klass: ClassSymbol) extends Ref

A reference to the object under initialization pointed by this

A reference to the object under initialization pointed by this

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Ref
class Value
class Object
trait Matchable
class Any
Show all
trait TryReporter extends Reporter

A TryReporter cannot be simply thrown away

A TryReporter cannot be simply thrown away

Either abort should be called or the errors be reported.

If errors are ignored and abort is not called, the monotonicity of the computation function is not guaranteed, thus termination of fixed-point computation becomes a problem.

Attributes

Supertypes
trait Reporter
class Object
trait Matchable
class Any
Known subtypes
sealed abstract class Value

Abstract values

Abstract values

Value = Hot | Cold | Warm | ThisRef | Fun | RefSet

           Cold
  ┌──────►  ▲  ◄────┐  ◄────┐
  │         │       │       │
  │         │       │       │
  |         │       │       │
  |         │       │       │

ThisRef Warm Fun RefSet │ ▲ ▲ ▲ │ │ │ │ | │ │ │ ▲ │ │ │ │ │ │ │ └─────────┴───────┴───────┘ Hot

The diagram above does not reflect relationship between RefSet and other values. RefSet represents a set of values which could be ThisRef, Warm or Fun. The following ordering applies for RefSet:

   R_a ⊑ R_b if R_a ⊆ R_b

   V ⊑ R if V ∈ R

Attributes

Supertypes
class Object
trait Matchable
class Any
Known subtypes
object Cold.type
class Fun
object Hot.type
class Ref
class ThisRef
class Warm
class RefSet
Show all
case class Warm(klass: ClassSymbol, outer: Value, ctor: Symbol, args: List[Value]) extends Ref

An object with all fields initialized but reaches objects under initialization

An object with all fields initialized but reaches objects under initialization

We need to restrict nesting levels of outer to finitize the domain.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Ref
class Value
class Object
trait Matchable
class Any
Show all

Types

type Contextual[T] = (Context, Trace, Promoted, Data, Reporter) ?=> T

The state that threads through the interpreter

The state that threads through the interpreter

Attributes

Value members

Concrete methods

inline def cache(using c: Data): Data
def cases(expr: Tree, thisV: Ref, klass: ClassSymbol): () ?=> Value

Handles the evaluation of different expressions

Handles the evaluation of different expressions

Note: Recursive call should go to eval instead of cases.

Value parameters

expr

The expression to be evaluated.

klass

The enclosing class where the expression expr is located.

thisV

The value for C.this where C is represented by the parameter klass.

Attributes

def cases(tp: Type, thisV: Ref, klass: ClassSymbol): () ?=> Value

Handle semantics of leaf nodes

Handle semantics of leaf nodes

For leaf nodes, their semantics is determined by their types.

Value parameters

klass

The enclosing class where the type tp is located.

thisV

The value for C.this where C is represented by the parameter klass.

tp

The type to be evaluated.

Attributes

def checkClasses(classes: List[ClassSymbol])(using Context): Unit

Check the specified concrete classes

Check the specified concrete classes

Attributes

def checkTermUsage(tpt: Tree, thisV: Ref, klass: ClassSymbol): () ?=> Unit

Check that path in path-dependent types are initialized

Check that path in path-dependent types are initialized

This is intended to avoid type soundness issues in Dotty.

Attributes

def eval(expr: Tree, thisV: Ref, klass: ClassSymbol, cacheResult: Boolean): () ?=> Value

Evaluate an expression with the given value for this in a given class klass

Evaluate an expression with the given value for this in a given class klass

Note that klass might be a super class of the object referred by thisV. The parameter klass is needed for this resolution. Consider the following code:

class A { A.this class B extends A { A.this } }

As can be seen above, the meaning of the expression A.this depends on where it is located.

This method only handles cache logic and delegates the work to cases.

Value parameters

cacheResult

It is used to reduce the size of the cache.

expr

The expression to be evaluated.

klass

The enclosing class where the expression is located.

thisV

The value for C.this where C is represented by the parameter klass.

Attributes

def eval(exprs: List[Tree], thisV: Ref, klass: ClassSymbol): () ?=> List[Value]

Evaluate a list of expressions

Evaluate a list of expressions

Attributes

def evalArgs(args: List[Arg], thisV: Ref, klass: ClassSymbol): () ?=> List[ArgInfo]

Evaluate arguments of methods

Evaluate arguments of methods

Attributes

def init(tpl: Template, thisV: Ref, klass: ClassSymbol): () ?=> Value

Initialize part of an abstract object in klass of the inheritance chain

Initialize part of an abstract object in klass of the inheritance chain

Value parameters

klass

The class to which the template belongs.

thisV

The value of the current object to be initialized.

tpl

The class body to be evaluated.

Attributes

def outerValue(tref: TypeRef, thisV: Ref, klass: ClassSymbol): () ?=> Value

Compute the outer value that correspond to tref.prefix

Compute the outer value that correspond to tref.prefix

Value parameters

klass

The enclosing class where the type tref is located.

thisV

The value for C.this where C is represented by the parameter klass.

tref

The type whose prefix is to be evaluated.

Attributes

inline def reporter(using r: Reporter): Reporter
def resolveThis(target: ClassSymbol, thisV: Value, klass: ClassSymbol): () ?=> Value

Resolve C.this that appear in klass

Resolve C.this that appear in klass

Value parameters

klass

The enclosing class where the type C.this is located.

target

The class symbol for C for which C.this is to be resolved.

thisV

The value for D.this where D is represented by the parameter klass.

Attributes

Extensions

Extensions

extension (a: Value)
def join(b: Value): Value
def widenArg: () ?=> Value

Conservatively approximate the value with Cold or Hot

Conservatively approximate the value with Cold or Hot

Attributes

extension (arg: ArgInfo)
def promote: () ?=> Unit
extension (ref: Ref)
def ensureFresh()(using Data): Ref
def ensureObjectExists()(using Data): Ref
def objekt: () ?=> Objekt
def updateField(field: Symbol, value: Value): () ?=> Unit

Update field value of the abstract object

Update field value of the abstract object

Invariant: fields are immutable and only set once

Attributes

def updateOuter(klass: ClassSymbol, value: Value): () ?=> Unit

Update the immediate outer of the given klass of the abstract object

Update the immediate outer of the given klass of the abstract object

Invariant: outers are immutable and only set once

Attributes

extension (ref: Ref)
def accessLocal(tmref: TermRef, klass: ClassSymbol): () ?=> Value
extension (ref: Ref)
def isFullyFilled: () ?=> Boolean

Whether the object is fully assigned

Whether the object is fully assigned

It means all fields and outers are set. For performance, we don't check outers here, because Scala semantics ensure that they are always set before any user code in the constructor.

Note that isFullyFilled = true does not mean we can use the object freely, as its fields or outers may still reach uninitialized objects.

Attributes

def nonInitFields(): () ?=> List[Symbol]
extension (thisRef: ThisRef)
extension (value: Value)
def call(meth: Symbol, args: List[ArgInfo], receiver: Type, superType: Type, needResolve: Boolean): () ?=> Value
def callConstructor(ctor: Symbol, args: List[ArgInfo]): () ?=> Value
def ensureHot(msg: String): () ?=> Value
def instantiate(klass: ClassSymbol, ctor: Symbol, args: List[ArgInfo]): () ?=> Value

Handle a new expression new p.C where p is abstracted by value

Handle a new expression new p.C where p is abstracted by value

Attributes

def select(field: Symbol, receiver: Type, needResolve: Boolean): () ?=> Value
extension (value: Value)
def promote(msg: String): () ?=> Unit

Promotion of values to hot

Promotion of values to hot

Attributes

extension (value: Ref)

Can the method call on value be ignored?

Can the method call on value be ignored?

Note: assume overriding resolution has been performed.

Attributes

extension (values: Seq[Value])
def join: Value
def widenArgs: () ?=> List[Value]
extension (warm: Warm)
def tryPromote(msg: String): () ?=> List[Error]

Try early promotion of warm objects

Try early promotion of warm objects

Promotion is expensive and should only be performed for small classes.

  1. for each concrete method m of the warm object: call the method and promote the result

  2. for each concrete field f of the warm object: promote the field value

If the object contains nested classes as members, the checker simply reports a warning to avoid expensive checks.

Attributes