Dotty Documentation

0.11.0-bin-SNAPSHOT

class TypeComparer
extends Object with ConstraintHandling

Provides methods to compare types.

[-] Constructors

TypeComparer ( initctx: Context )

[-] Members

[+] var GADTused : Boolean

Indicates whether a previous subtype check used GADT bounds

[+] private var approx : ApproxState
[+] implicit val ctx : Context
[+] private val initctx : Context
[+] private var monitored : Boolean
[+] private var myAnyClass : ClassSymbol
[+] private var myAnyKindClass : ClassSymbol
[+] private var myAnyKindType : TypeRef
[+] private var myAnyType : TypeRef
[+] private var myNothingClass : ClassSymbol
[+] private var myNothingType : TypeRef
[+] private var myNullClass : ClassSymbol
[+] private var myObjectClass : ClassSymbol
[+] private var needsGc : Boolean
[+] private var pendingSubTypes : Set [ ( Type, Type ) ]
[+] private var recCount : Int
[+] val state : TyperState
[+] private var successCount : Int

For statistics: count how many isSubTypes are part of successful comparisons

[+] private var totalCount : Int
[+] def AnyClass : ClassSymbol
[+] def AnyKindClass : ClassSymbol
[+] def AnyKindType : TypeRef
[+] def AnyType : TypeRef
[+] private def GADTusage ( sym: Symbol ) : Boolean

Record that GADT bounds of sym were used in a subtype check. But exclude constructor type parameters, as these are aliased to the corresponding class parameters, which does not constitute a true usage of a GADT symbol.

[+] def GADTused_= ( x$1: Boolean ) : Unit

Indicates whether a previous subtype check used GADT bounds

[+] def NothingClass : ClassSymbol
[+] def NothingType : TypeRef
[+] def NullClass : ClassSymbol
[+] def ObjectClass : ClassSymbol
[+] final def andType ( tp1: Type , tp2: Type , isErased: Boolean ) : Type

Form a normalized conjunction of two types. Note: For certain types, & is distributed inside the type. This holds for all types which are not value types (e.g. TypeBounds, ClassInfo, ExprType, LambdaType). Also, when forming an &, instantiated TypeVars are dereferenced and annotations are stripped. Finally, refined types with the same refined name are opportunistically merged.

Sometimes, the conjunction of two types cannot be formed because the types are in conflict of each other. In particular:

  1. Two different class types are conflicting.
  2. A class type conflicts with a type bounds that does not include the class reference.
  3. Two method or poly types with different (type) parameters but the same signature are conflicting

In these cases, a MergeError is thrown.

[+] def andType$default$3 : Boolean

Form a normalized conjunction of two types. Note: For certain types, & is distributed inside the type. This holds for all types which are not value types (e.g. TypeBounds, ClassInfo, ExprType, LambdaType). Also, when forming an &, instantiated TypeVars are dereferenced and annotations are stripped. Finally, refined types with the same refined name are opportunistically merged.

Sometimes, the conjunction of two types cannot be formed because the types are in conflict of each other. In particular:

  1. Two different class types are conflicting.
  2. A class type conflicts with a type bounds that does not include the class reference.
  3. Two method or poly types with different (type) parameters but the same signature are conflicting

In these cases, a MergeError is thrown.

[+] protected def approxState : ApproxState
[+] def constValue ( tp: Type ) : Option [ Constant ]

Optionally, the constant c such that tp <:< ConstantType(c)

[+] def copyIn ( ctx: Context ) : TypeComparer

A new type comparer of the same type as this one, using the given context.

[+] private def distributeAnd ( tp1: Type , tp2: Type ) : Type
[+] private def distributeOr ( tp1: Type , tp2: Type ) : Type

Try to distribute | inside type, detect and handle conflicts Note that, unlike for &, a disjunction cannot be pushed into a refined or applied type. Example:

List[T] | List[U] is not the same as List[T | U].

The rhs is a proper supertype of the lhs.

[+] private def dropIfSuper ( tp: Type , sub: Type ) : Type

If some (&-operand of) this type is a supertype of sub replace it with NoType.

[+] private def either ( op1: => Boolean , op2: => Boolean ) : Boolean

Returns true iff the result of evaluating either op1 or op2 is true, trying at the same time to keep the constraint as wide as possible. E.g, if

tp11 <:< tp12 = true with post-constraint c1 tp12 <:< tp22 = true with post-constraint c2

and c1 subsumes c2, then c2 is kept as the post-constraint of the result, otherwise c1 is kept.

This method is used to approximate a solution in one of the following cases

T1 & T2 <:< T3 T1 <:< T2 | T3

In the first case (the second one is analogous), we have a choice whether we want to establish the subtyping judgement using

T1 <:< T3 or T2 <:< T3

as a precondition. Either precondition might constrain type variables. The purpose of this method is to pick the precondition that constrains less. The method is not complete, because sometimes there is no best solution. Example:

A? & B? <: T

Here, each precondition leads to a different constraint, and neither of the two post-constraints subsumes the other.

[+] final def ensureStableSingleton ( tp: Type ) : SingletonType
[+] private def fixRecs ( anchor: SingletonType , tp: Type ) : Type

Replace any top-level recursive type { z => T } in tp with [z := anchor]T.

[+] protected def gadtBounds ( sym: Symbol ) ( implicit ctx: Context ) : TypeBounds
[+] protected def gadtSetBounds ( sym: Symbol , b: TypeBounds ) : Unit
[+] def glb ( tp1: Type , tp2: Type ) : Type

The greatest lower bound of two types

[+] final def glb ( tps: List [ Type ] ) : Type

The greatest lower bound of a list types

[+] def glbArgs ( args1: List [ Type ] , args2: List [ Type ] , tparams: List [ TypeParamInfo ] ) : List [ Type ]

Try to produce joint arguments for a glb A[T_1, ..., T_n] & A[T_1', ..., T_n'] using the following strategies:

  • if arguments are the same, that argument.
  • if corresponding parameter variance is co/contra-variant, the glb/lub.
  • if at least one of the arguments if a TypeBounds, the union of the bounds.
  • if homogenizeArgs is set, and arguments can be unified by instantiating type parameters, the unified argument.
  • otherwise NoType

The unification rule is contentious because it cuts the constraint set. Therefore it is subject to Config option alignArgsInAnd.

[+] protected def hasMatchingMember ( name: Name , tp1: Type , tp2: RefinedType ) : Boolean

Does type tp1 have a member with name name whose normalized type is a subtype of the normalized type of the refinement tp2? Normalization is as follows: If tp2 contains a skolem to its refinement type, rebase both itself and the member info of tp on a freshly created skolem type.

[+] private def isAsGood ( tp1: Type , tp2: Type ) : Boolean

A comparison function to pick a winner in case of a merge conflict

[+] private def isCovered ( tp: Type ) : Boolean

A type has been covered previously in subtype checking if it is some combination of TypeRefs that point to classes, where the combiners are AppliedTypes, RefinedTypes, RecTypes, And/Or-Types or AnnotatedTypes.

[+] def isMatchedByProto ( proto: ProtoType , tp: Type ) : Boolean

Defer constraining type variables when compared against prototypes

[+] def isSameRef ( tp1: Type , tp2: Type ) : Boolean

Same as isSameType but also can be applied to overloaded TermRefs, where two overloaded refs are the same if they have pairwise equal alternatives

[+] def isSameType ( tp1: Type , tp2: Type ) : Boolean

Two types are the same if are mutual subtypes of each other

[+] def isSubArgs ( args1: List [ Type ] , args2: List [ Type ] , tp1: Type , tparams: List [ ParamInfo ] ) : Boolean

Subtype test for corresponding arguments in args1, args2 according to variances in type parameters tparams.

[+] private def isSubRefinements ( tp1: RefinedType , tp2: RefinedType , limit: Type ) : Boolean

Are refinements in tp1 pairwise subtypes of the refinements of tp2 up to parent type limit?

[+] protected def isSubType ( tp1: Type , tp2: Type , a: ApproxState ) : Boolean
[+] protected def isSubType ( tp1: Type , tp2: Type ) : Boolean
[+] private def liftIfHK ( tp1: Type , tp2: Type , op: (Type, Type) => Type , original: (Type, Type) => Type ) : Type

op(tp1, tp2) unless tp1 and tp2 are type-constructors. In the latter case, combine tp1 and tp2 under a type lambda like this:

[X1, ..., Xn] -> op(tp1[X1, ..., Xn], tp2[X1, ..., Xn])

[+] def lub ( tp1: Type , tp2: Type , canConstrain: Boolean ) : Type
[+] final def lub ( tps: List [ Type ] ) : Type

The least upper bound of a list of types

[+] def lub$default$3 : Boolean
[+] def lubArgs ( args1: List [ Type ] , args2: List [ Type ] , tparams: List [ TypeParamInfo ] , canConstrain: Boolean ) : List [ Type ]
[+] def lubArgs$default$4 : Boolean
[+] final def matchesType ( tp1: Type , tp2: Type , relaxed: Boolean ) : Boolean

A function implementing tp1 matches tp2.

[+] def matchingMethodParams ( tp1: MethodType , tp2: MethodType ) : Boolean

Do the parameter types of tp1 and tp2 match in a way that allows tp1 to override tp2 ? This is the case if they're pairwise =:=, as a special case, we allow Any in Java methods to match Object.

[+] def matchingPolyParams ( tp1: PolyType , tp2: PolyType ) : Boolean

Do the parameter types of tp1 and tp2 match in a way that allows tp1 to override tp2 ? This is the case if they're pairwise >:>.

[+] private def mergeIfSub ( tp1: Type , tp2: Type ) : Type

Merge t1 into tp2 if t1 is a subtype of some &-summand of tp2.

[+] private def mergeIfSuper ( tp1: Type , tp2: Type , canConstrain: Boolean ) : Type

Merge tp1 into tp2 if tp1 is a supertype of some |-summand of tp2.

[+] private def narrowGADTBounds ( tr: NamedType , bound: Type , approx: ApproxState , isUpper: Boolean ) : Boolean

Narrow gadt.bounds for the type parameter referenced by tr to include bound as an upper or lower bound (which depends on isUpper). Test that the resulting bounds are still satisfiable.

[+] def natValue ( tp: Type ) : Option [ Int ]

Optionally, the n such that tp <:< ConstantType(Constant(n: Int))

[+] final def orType ( tp1: Type , tp2: Type , isErased: Boolean ) : Type

Form a normalized conjunction of two types. Note: For certain types, | is distributed inside the type. This holds for all types which are not value types (e.g. TypeBounds, ClassInfo, ExprType, LambdaType). Also, when forming an |, instantiated TypeVars are dereferenced and annotations are stripped.

Sometimes, the disjunction of two types cannot be formed because the types are in conflict of each other. (@see andType for an enumeration of these cases). In cases of conflict a MergeError is raised.

[+] def orType$default$3 : Boolean

Form a normalized conjunction of two types. Note: For certain types, | is distributed inside the type. This holds for all types which are not value types (e.g. TypeBounds, ClassInfo, ExprType, LambdaType). Also, when forming an |, instantiated TypeVars are dereferenced and annotations are stripped.

Sometimes, the disjunction of two types cannot be formed because the types are in conflict of each other. (@see andType for an enumeration of these cases). In cases of conflict a MergeError is raised.

[+] private def recombineAnd ( tp: AndType , tp1: Type , tp2: Type ) : Type
[+] def recordStatistics ( result: Boolean , prevSuccessCount: Int ) : Unit

Record statistics about the total number of subtype checks and the number of "successful" subtype checks, i.e. checks that form part of a subtype derivation tree that's ultimately successful.

[+] protected def recur ( tp1: Type , tp2: Type ) : Boolean
[+] def showGoal ( tp1: Type , tp2: Type ) ( implicit ctx: Context ) : Unit

Show subtype goal that led to an assertion failure

[+] private def showType ( tp: Type ) ( implicit ctx: Context ) : String

Show type, handling type types better than the default

[+] def singletonInterval ( tp1: Type , tp2: Type ) : Type

If the range tp1..tp2 consist of a single type, that type, otherwise NoType. This is the case iftp1 =:= tp2, but also iftp1 <:< tp2,tp1is a singleton type, andtp2derives fromscala.Singleton` (or vice-versa). Examples of the latter case:

"name".type .. Singleton "name".type .. String & Singleton Singleton .. "name".type String & Singleton .. "name".type

All consist of the single type "name".type.

[+] private def skipMatching ( tp1: Type , tp2: RefinedType ) : Type

Skip refinements in tp2 which match corresponding refinements in tp1. "Match" means: - they appear in the same order, - they refine the same names, - the refinement in tp1 is an alias type, and - neither refinement refers back to the refined type via a refined this.

[+] def subtypeCheckInProgress : Boolean

Is a subtype check in progress? In that case we may not permanently instantiate type variables, because the corresponding constraint might still be retracted and the instantiation should then be reversed.

[+] private def testLifted ( tp1: Type , tp2: Type , tparams: List [ TypeParamInfo ] , p: Type => Boolean ) : Boolean

Test whether tp1 has a base type of the form B[T1, ..., Tn] where - B derives from one of the class symbols of tp2, - the type parameters of B match one-by-one the variances of tparams, - B satisfies predicate p.

[+] def topLevelSubType ( tp1: Type , tp2: Type ) : Boolean
[+] def traceIndented ( str: String ) ( op: => T ) : T

A hook for showing subtype traces. Overridden in ExplainingTypeComparer

[+] private def traceInfo ( tp1: Type , tp2: Type ) : String
[+] protected def typeVarInstance ( tvar: TypeVar ) ( implicit ctx: Context ) : Type