Dotty Documentation

0.3.0-bin-SNAPSHOT

class TypeComparer
extends DotClass with ConstraintHandling

Provides methods to compare types.

[-] Constructors

TypeComparer ( initctx: Context )

[-] Members

[+] var GADTused : Boolean

Indicates whether a previous subtype check used GADT bounds

[+] implicit val ctx : Context
[+] private val initctx : Context
[+] private var myAnyClass : ClassSymbol
[+] private var myAnyType : TypeRef
[+] private var myNothingClass : ClassSymbol
[+] private var myNothingType : TypeRef
[+] private var myNullClass : ClassSymbol
[+] private var myObjectClass : ClassSymbol
[+] private var myPhantomNothingClass : 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 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
[+] def PhantomNothingClass : ClassSymbol
[+] final def andType ( tp1: Type , tp2: Type , erased: 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 compareHkApply1 ( tp1: HKApply , tycon1: Type , args1: List [ Type ] , tp2: Type ) : Boolean

Subtype test for the hk application tp1 = tycon1[args1].

[+] def compareHkApply2 ( tp1: Type , tp2: HKApply , tycon2: Type , args2: List [ Type ] ) : Boolean

Subtype test for the hk application tp2 = tycon2[args2].

[+] 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
[+] 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 firstTry ( tp1: Type , tp2: Type ) : Boolean
[+] private def fixRecs ( anchor: SingletonType , tp: Type ) : Type

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

[+] private def fourthTry ( tp1: Type , tp2: Type ) : Boolean
[+] 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

[+] 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 isCappable ( tp: Type ) : Boolean

Can type tp be constrained from above by adding a constraint to a typevar that it refers to? In that case we have to be careful not to approximate with the lower bound of a type in thirdTry. Instead, we should first unroll tp1 until we hit the type variable and bind the type variable with (the corresponding type in) tp2 instead.

[+] 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 RefinedTypes, RecTypes, And/Or-Types or AnnotatedTypes.

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

Defer constraining type variables when compared against prototypes

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

Like tp1 <:< tp2, but returns false immediately if we know that the case was covered previously during subtyping.

[+] 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 ] , 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 ) : Boolean
[+] private def liftIfHK ( tp1: Type , tp2: Type , op: (Type, Type) => Type , original: (Type, Type) => Type ) : R

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

[+] final def matchesType ( tp1: Type , tp2: Type , relaxed: Boolean ) : Boolean

A function implementing tp1 matches tp2.

[+] def matchingParams ( lam1: MethodOrPoly , lam2: MethodOrPoly ) : Boolean

Do lambda types lam1 and lam2 have parameters that have the same types and the same implicit status? (after renaming one set to the other)

[+] 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 monitoredIsSubType ( tp1: Type , tp2: Type ) : Boolean
[+] private def myAnyClass_= ( x$1: ClassSymbol ) : Unit
[+] private def myAnyType_= ( x$1: TypeRef ) : Unit
[+] private def myNothingClass_= ( x$1: ClassSymbol ) : Unit
[+] private def myNothingType_= ( x$1: TypeRef ) : Unit
[+] private def myNullClass_= ( x$1: ClassSymbol ) : Unit
[+] private def myObjectClass_= ( x$1: ClassSymbol ) : Unit
[+] private def myPhantomNothingClass_= ( x$1: ClassSymbol ) : Unit
[+] private def narrowGADTBounds ( tr: NamedType , bound: Type , 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.

[+] private def needsGc_= ( x$1: Boolean ) : Unit
[+] final def orType ( tp1: Type , tp2: Type , erased: 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.

[+] private def pendingSubTypes_= ( x$1: Set [ ( Type, Type ) ] ) : Unit
[+] private def recCount_= ( x$1: Int ) : Unit
[+] private def recombineAndOr ( tp: AndOrType , 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.

[+] private def secondTry ( 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

[+] 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 successCount_= ( x$1: Int ) : Unit

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

[+] 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.

[+] private def thirdTry ( tp1: Type , tp2: Type ) : Boolean
[+] private def thirdTryNamed ( tp1: Type , tp2: NamedType ) : Boolean
[+] def topLevelSubType ( tp1: Type , tp2: Type ) : Boolean
[+] private def totalCount_= ( x$1: Int ) : Unit
[+] def traceIndented ( str: String ) ( op: => T ) : T

A hook for showing subtype traces. Overridden in ExplainingTypeComparer

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