Objects

dotty.tools.dotc.transform.init.Objects
class Objects(using x$1: Context)

Check initialization safety of static objects

The problem is illustrated by the example below:

class Foo(val opposite: Foo)
case object A extends Foo(B)     // A -> B
case object B extends Foo(A)     // B -> A

In the code above, the initialization of object A depends on B and vice versa. There is no correct way to initialize the code above. The current checker issues a warning for the code above.

At the high-level, the analysis has the following characteristics:

  1. The check enforces the principle of "initialization-time irrelevance", which means that the time when an object is initialized should not change program semantics. For that purpose, it enforces the following rule:

    The initialization of a static object should not directly or indirectly read or write
    mutable state of another static object.
    

    This principle not only put initialization of static objects on a solid foundation, but also avoids whole-program analysis.

  2. It is inter-procedural and flow-sensitive.

  3. The check is modular in the sense that each object is checked separately and there is no whole-program analysis. However, the check is not modular in terms of project boundaries.

Attributes

Graph
Supertypes
class Object
trait Matchable
class Any

Members list

Type members

Classlikes

case class ArgInfo(value: Objects.this.Value, trace: Trace, tree: Tree)

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
case class ArrayRef extends Ref

Represents arrays.

Represents arrays.

Note that the 2nd parameter block does not take part in the definition of equality.

Different arrays are distinguished by the context. Currently the default context is the static object whose initialization triggers the creation of the array.

In the future, it is possible that we introduce a mechanism for end-users to mark the context.

Value parameters

owner

The static object whose initialization creates the array.

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Objects.this.Ref
trait Objects.this.ValueElement
trait Objects.this.Value
class Objects.this.Scope
class Object
trait Matchable
class Any
Show all
object ArrayRef

Attributes

Companion
class
Supertypes
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.ArrayRef.type
object Cache

Cache used to terminate the check

Cache used to terminate the check

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.Cache.type
object Env

Environment for parameters

Environment for parameters

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.Env.type
object EnvMap

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.EnvMap.type
case class Fun(code: Tree, thisV: Objects.this.ThisValue, klass: ClassSymbol, scope: Objects.this.Scope) extends ValueElement

Represents a lambda expression

Represents a lambda expression

Value parameters

klass

The enclosing class of the anonymous function's creation site

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait Objects.this.ValueElement
trait Objects.this.Value
class Object
trait Matchable
class Any
Show all
object Heap

Abstract heap for mutable fields

Abstract heap for mutable fields

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.Heap.type
case class InstanceRef extends Ref

Represents values that are instances of the specified class.

Represents values that are instances of the specified class.

Note that the 2nd parameter block does not take part in the definition of equality.

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Objects.this.Ref
trait Objects.this.ValueElement
trait Objects.this.Value
class Objects.this.Scope
class Object
trait Matchable
class Any
Show all
object InstanceRef

Attributes

Companion
class
Supertypes
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.InstanceRef.type
trait Join[V]

Attributes

Supertypes
class Object
trait Matchable
class Any
Known subtypes
case class ObjectRef extends Ref

A reference to a static object

A reference to a static object

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Objects.this.Ref
trait Objects.this.ValueElement
trait Objects.this.Value
class Objects.this.Scope
class Object
trait Matchable
class Any
Show all
object ObjectRef

Attributes

Companion
class
Supertypes
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.ObjectRef.type
case class Package(packageModuleClass: ClassSymbol) extends Value

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
trait Objects.this.Value
class Object
trait Matchable
class Any
Show all
object Package

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.Package.type
sealed abstract class Ref(using x$1: Trace) extends Scope, ValueElement

Attributes

Supertypes
trait Objects.this.ValueElement
trait Objects.this.Value
class Objects.this.Scope
class Object
trait Matchable
class Any
Show all
Known subtypes
class Objects.this.ArrayRef
class Objects.this.InstanceRef
class Objects.this.ObjectRef
class RefSet(val refs: Set[Objects.this.Ref]) extends ValueSet

Represents a set of Refs. The equals method inherits from ValueSet, so no more fields should be added to RefSet

Represents a set of Refs. The equals method inherits from ValueSet, so no more fields should be added to RefSet

Attributes

Supertypes
class Objects.this.ValueSet
trait Serializable
trait Product
trait Equals
trait Objects.this.Value
class Object
trait Matchable
class Any
Show all
object Regions

Region context for mutable states

Region context for mutable states

By default, the region context is empty.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.Regions.type
object Returns

Handle return statements in methods and non-local returns in functions.

Handle return statements in methods and non-local returns in functions.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.Returns.type
case class SafeValue(typeSymbol: Symbol) extends ValueElement

Represents common base values like Int, String, etc. Assumption: all field initializers and methods calls on such values should not trigger initialization of global objects or read/write mutable fields

Represents common base values like Int, String, etc. Assumption: all field initializers and methods calls on such values should not trigger initialization of global objects or read/write mutable fields

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
trait Objects.this.ValueElement
trait Objects.this.Value
class Object
trait Matchable
class Any
Show all
object SafeValue

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.SafeValue.type
sealed abstract class Scope(using trace: Trace)

Represents the possible values of the current enclosing scope when evaluating an expression

Represents the possible values of the current enclosing scope when evaluating an expression

Attributes

Supertypes
class Object
trait Matchable
class Any
Known subtypes
class EnvRef
class Objects.this.Ref
class Objects.this.ArrayRef
class Objects.this.InstanceRef
class Objects.this.ObjectRef
object State

Checking state

Checking state

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Objects.this.Objects.this.State.type
case object UnknownValue extends ValueElement

Represents values unknown to the checker, such as values loaded without source

Represents values unknown to the checker, such as values loaded without source

Attributes

Supertypes
trait Singleton
trait Product
trait Mirror
trait Serializable
trait Product
trait Equals
trait Objects.this.ValueElement
trait Objects.this.Value
class Object
trait Matchable
class Any
Show all
Self type
Objects.this.Objects.this.UnknownValue.type
sealed trait Value

Syntax for the data structure abstraction used in abstract domain:

Syntax for the data structure abstraction used in abstract domain:

ve ::= ObjectRef(class) // global object | InstanceRef(class, ownerObject, ctor, regions) // instance of a class | ArrayRef(ownerObject, regions) // represents values of native array class in Array.scala | Fun(code, thisV, scope) // value elements that can be contained in ValueSet | SafeValue // values on which method calls and field accesses won't cause warnings. Int, String, etc. | UnknownValue // values whose source are unknown at compile time vs ::= ValueSet(Set(ve)) // set of abstract values Value ::= ve | vs | Package Ref ::= ObjectRef | InstanceRef | ArrayRef // values that represent a reference to some (global or instance) object RefSet ::= Set(ref) // set of refs Bottom ::= RefSet(Empty) // unreachable code ThisValue ::= Ref | RefSet // possible values for 'this' EnvRef(meth, ownerObject) // represents environments for methods or functions EnvSet ::= Set(EnvRef) InstanceBody ::= (valsMap: Map[Symbol, Value], outersMap: Map[ClassSymbol, Value], outerEnv: EnvSet) // represents combined information of all instances represented by a ref Heap ::= Ref -> InstanceBody // heap is mutable EnvBody ::= (valsMap: Map[Symbol, Value], thisV: Value, outerEnv: EnvSet) // represents combined information of all instances represented by an env EnvMap ::= EnvRef -> EnvBody Scope ::= Ref | EnvRef Config ::= (thisV: Value, scope: Scope, Heap, EnvMap) Cache ::= Config -> (Heap, EnvMap)

regions ::= List(sourcePosition)

Attributes

Supertypes
class Object
trait Matchable
class Any
Known subtypes
class Objects.this.Package
trait Objects.this.ValueElement
class Objects.this.Fun
class Objects.this.Ref
class Objects.this.ArrayRef
class Objects.this.InstanceRef
class Objects.this.ObjectRef
class Objects.this.SafeValue
object Objects.this.UnknownValue
class Objects.this.ValueSet
class Objects.this.RefSet
Show all
sealed trait ValueElement extends Value

ValueElement are elements that can be contained in a ValueSet

ValueElement are elements that can be contained in a ValueSet

Attributes

Supertypes
trait Objects.this.Value
class Object
trait Matchable
class Any
Known subtypes
class Objects.this.Fun
class Objects.this.Ref
class Objects.this.ArrayRef
class Objects.this.InstanceRef
class Objects.this.ObjectRef
class Objects.this.SafeValue
object Objects.this.UnknownValue
Show all
case class ValueSet(values: Set[Objects.this.ValueElement]) extends Value

Represents a set of values

Represents a set of values

It comes from if expressions.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait Objects.this.Value
class Object
trait Matchable
class Any
Show all
Known subtypes
class Objects.this.RefSet
object given_Join_EnvSet extends Join[EnvSet]

Attributes

Supertypes
trait Objects.this.Join[EnvSet]
class Object
trait Matchable
class Any
Self type
object given_Join_Value extends Join[Value]

Attributes

Supertypes
trait Objects.this.Join[Objects.this.Value]
class Object
trait Matchable
class Any
Self type

Types

type ThisValue = Ref | RefSet

Possible types for 'this'

Possible types for 'this'

Attributes

Value members

Concrete methods

def assign(lhs: Value, field: Symbol, rhs: Value, rhsTyp: Type): () => Value

Handle assignment lhs.f = rhs.

Handle assignment lhs.f = rhs.

Value parameters

field

The symbol of the target field.

lhs

The value of the object to be mutated.

rhs

The value to be assigned.

rhsTyp

The type of the right-hand side.

Attributes

inline def cache(using c: Data): Data
def call(value: Value, meth: Symbol, args: List[ArgInfo], receiver: Type, superType: Type, needResolve: Boolean = ...): () => Value

Handle method calls e.m(args).

Handle method calls e.m(args).

Value parameters

args

Arguments of the method call (all parameter blocks flatten to a list).

meth

The symbol of the target method (could be virtual or abstract method).

needResolve

Whether the target of the call needs resolution?

receiver

The type of the receiver.

superType

The type of the super in a super call. NoType for non-super calls.

value

The value for the receiver.

Attributes

def callConstructor(value: Value, ctor: Symbol, args: List[ArgInfo]): () => Value

Handle constructor calls <init>(args).

Handle constructor calls <init>(args).

Value parameters

args

Arguments of the constructor call (all parameter blocks flatten to a list).

ctor

The symbol of the target method.

value

The value for the receiver.

Attributes

def cases(expr: Tree, thisV: ThisValue, 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 checkClasses(classes: List[ClassSymbol])(using Context): Unit
def errorMutateOtherStaticObject(currentObj: ClassSymbol, scope: Scope)(using Trace, Context): Unit
def errorReadOtherStaticObject(currentObj: ClassSymbol, scope: Scope)(using Trace, Context): Unit
def eval(expr: Tree, thisV: ThisValue, 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 evalArgs(args: List[Arg], thisV: ThisValue, klass: ClassSymbol): () => List[ArgInfo]

Evaluate arguments of methods and constructors

Evaluate arguments of methods and constructors

Attributes

def evalExprs(exprs: List[Tree], thisV: ThisValue, klass: ClassSymbol): () => List[Value]

Evaluate a list of expressions

Evaluate a list of expressions

Attributes

def evalType(tp: Type, thisV: ThisValue, klass: ClassSymbol, elideObjectAccess: Boolean = ...): () => Value

Handle semantics of leaf nodes

Handle semantics of leaf nodes

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

Value parameters

elideObjectAccess

Whether object access should be omitted. Object access elission happens when the object access is used as a prefix in new o.C and C does not need an outer.

klass

The enclosing class where the type tp is located.

thisV

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

tp

The type to be evaluated.

Attributes

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

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 initLocal(sym: Symbol, value: Value): () => Unit

Handle local variable definition, val x = e or var x = e.

Handle local variable definition, val x = e or var x = e.

Value parameters

sym

The symbol of the variable.

value

The value of the initializer.

Attributes

def instantiate(outer: Value, klass: ClassSymbol, ctor: Symbol, args: List[ArgInfo]): () => Value

Handle new expression new p.C(args). The actual instance might be cached without running the constructor. See tests/init-global/pos/cache-constructor.scala

Handle new expression new p.C(args). The actual instance might be cached without running the constructor. See tests/init-global/pos/cache-constructor.scala

Value parameters

args

The arguments passsed to the constructor.

ctor

The symbol of the target constructor.

klass

The symbol of the class C.

outer

The value for p.

Attributes

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

Compute the outer value that corresponds to tref.prefix

Compute the outer value that corresponds 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

def patternMatch(scrutinee: Value, cases: List[CaseDef], thisV: ThisValue, klass: ClassSymbol): () => Value

Evaluate the cases against the scrutinee value.

Evaluate the cases against the scrutinee value.

It returns the scrutinee in most cases. The main effect of the function is for its side effects of adding bindings to the environment.

See https://docs.scala-lang.org/scala3/reference/changed-features/pattern-matching.html

Value parameters

cases

The cases to match.

klass

The enclosing class where the type tp is located.

scrutinee

The abstract value of the scrutinee.

thisV

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

Attributes

def readLocal(thisV: ThisValue, sym: Symbol): () => Value

Read local variable x.

Read local variable x.

Value parameters

sym

The symbol of the variable.

thisV

The value for this where the variable is used.

Attributes

def resolveThis(target: ClassSymbol, thisV: ThisValue, klass: ClassSymbol, elideObjectAccess: Boolean = ...): () => ThisValue

Resolve C.this that appear in D.this

Resolve C.this that appear in D.this

Value parameters

elideObjectAccess

Whether object access should be omitted. Object access elision happens when the object access is used as a prefix in new o.C and C does not need an outer.

klass

The enclosing class D where C.this appears

target

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

thisV

The value for D.this.

Attributes

def select(value: Value, field: Symbol, receiver: Type, needResolve: Boolean = ...): () => Value

Handle selection e.f.

Handle selection e.f.

Value parameters

field

The symbol of the target field (could be virtual or abstract).

needResolve

Whether the target of the selection needs resolution?

receiver

The type of the receiver.

value

The value for the receiver.

Attributes

def writeLocal(thisV: ThisValue, sym: Symbol, value: Value): () => Value

Handle local variable assignmenbt, x = e.

Handle local variable assignmenbt, x = e.

Value parameters

sym

The symbol of the variable.

thisV

The value for this where the assignment locates.

value

The value of the rhs of the assignment.

Attributes

Concrete fields

val Bottom: RefSet

Check if the checker option reports warnings about unknown code

Check if the checker option reports warnings about unknown code

Attributes

Extensions

Extensions

extension (a: Value)
def filterClass(sym: Symbol)(using Context): Value
def filterType(tpe: Type)(using Context): Value
def remove(b: Value): Value
extension [V : Join](map: Map[Symbol, V])
def join(sym: Symbol, value: V): Map[Symbol, V]
extension (scopes: Iterable[EnvSet])
def join: EnvSet
extension (thisV: ThisValue)
extension (values: Iterable[Value])
def join: Value