Type System
The types are defined in dotty/tools/dotc/core/Types.scala
Class diagram
 PDF, generated with a fork of scaladiagrams
Proxy types and ground types
A type which inherits TypeProxy
is a proxy for another type accessible using the underlying
method, other types are called ground types and inherit CachedGroundType
or UncachedGroundType
.
Here's a diagram, copied from dotty/tools/dotc/core/Types.scala:
Type + ProxyType + NamedType + TypeRef
  \
 + SingletonType++ TermRef
  
  + ThisType
  + SuperType
  + ConstantType
  + TermParamRef
  +RecThis
  + SkolemType
 + TypeParamRef
 + RefinedOrRecType + RefinedType
  + RecType
 + AppliedType
 + TypeBounds
 + ExprType
 + AnnotatedType
 + TypeVar
 + HKTypeLambda
 + MatchType
 + FlexibleType

+ GroundType + AndType
+ OrType
+ MethodOrPoly + PolyType
 + MethodType
+ ClassInfo

+ NoType
+ NoPrefix
+ ErrorType
+ WildcardType
Representations of types
Type  Representation 

p.x.type 
TermRef(p, x) 
p#T 
TypeRef(p, T) 
p.x.T == p.x.type#T 
TypeRef(TermRef(p, x), T) 
this.type 
ThisType 
A & B 
AndType(A, B) 
A  B 
OrType(A, B) 
=> T 
ExprType(T) 
p { refinedName } 
RefinedType(p, refinedName) 
type of the value super 
SuperType 
type T >: A <: B 
TypeRef with underlying type RealTypeBounds(A, B) 
type T = A 
TypeRef with underlying type TypeAlias(A) 
class p.C ... 
ClassInfo(p, C, ...) 
Representation of methods
def f[A, B <: Ord[A]](x: A, y: B): Unit
is represented as:
val p = PolyType(List("A", "B"))(
List(TypeBounds(Nothing, Any),
TypeBounds(Nothing,
RefinedType(Ordering,
scala$math$Ordering$$T, TypeAlias(PolyParam(p, 0))))),
m)
val m = MethodType(List("x", "y"),
List(PolyParam(p, 0), PolyParam(p, 1)))(Unit)
(This is a slightly simplified version, e.g. we write Unit
instead of TypeRef(TermRef(ThisType(TypeRef(NoPrefix,<root>)),scala),Unit)
).
Note that a PolyParam refers to a type parameter using its index (here A is 0 and B is 1).
Subtyping checks
topLevelSubType(tp1, tp2)
in dotty/tools/dotc/core/TypeComparer.scala checks if tp1
is a subtype of tp2
.
Type rebasing
FIXME: This section is no longer accurate because https://github.com/scala/scala3/pull/331 changed the handling of refined types.
Consider tests/pos/refinedSubtyping.scala
class Test {
class C { type T; type Coll }
type T1 = C { type T = Int }
type T11 = T1 { type Coll = Set[Int] }
type T2 = C { type Coll = Set[T] }
type T22 = T2 { type T = Int }
var x: T11 = _
var y: T22 = _
x = y
y = x
}
We want to do the subtyping checks recursively, since it would be nice if we could check if T22 <: T11
by first checking if T2 <: T1
. To achieve this recursive subtyping check, we remember that T2#T
is really T22#T
. This procedure is called rebasing and is done by storing refined names in pendingRefinedBases
and looking them up using rebase
.
Type caching
TODO
Type inference via constraint solving
TODO