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