aboutsummaryrefslogtreecommitdiff
path: root/docs/docs/internals/type-system.md
blob: eda1cfbdea56c51cd41f980f9be9903ce1cc57a2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
---
layout: doc-page
title: "Type System"
---

The types are defined in [dotty/tools/dotc/core/Types.scala][1]

## Class diagram ##
- [PDF][2], generated with [a fork of scaladiagrams][3]

## 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][1]:

```
Type -+- ProxyType --+- NamedType ----+--- TypeRef
      |              |                 \
      |              +- SingletonType-+-+- TermRef
      |              |                |
      |              |                +--- ThisType
      |              |                +--- SuperType
      |              |                +--- ConstantType
      |              |                +--- MethodParam
      |              |                +----RecThis
      |              |                +--- SkolemType
      |              +- PolyParam
      |              +- RefinedOrRecType -+-- RefinedType
      |              |                   -+-- RecType
      |              +- HKApply
      |              +- TypeBounds
      |              +- ExprType
      |              +- AnnotatedType
      |              +- TypeVar
      |              +- PolyType
      |
      +- GroundType -+- AndType
                     +- OrType
                     +- MethodType -----+- ImplicitMethodType
                     |                  +- JavaMethodType
                     +- 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 ###
```scala
def f[A, B <: Ord[A]](x: A, y: B): Unit
```
is represented as:

```scala
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][4]
checks if `tp1` is a subtype of `tp2`.

### Type rebasing ###
**FIXME**: This section is no longer accurate because
https://github.com/lampepfl/dotty/pull/331 changed the handling of refined
types.

Consider [tests/pos/refinedSubtyping.scala][5]
```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

[1]: https://github.com/lampepfl/dotty/blob/master/src/dotty/tools/dotc/core/Types.scala
[2]: https://github.com/samuelgruetter/dotty/blob/classdiagrampdf/dotty-types.pdf
[3]: https://github.com/samuelgruetter/scaladiagrams/tree/print-descendants
[4]: https://github.com/lampepfl/dotty/blob/master/src/dotty/tools/dotc/core/TypeComparer.scala
[5]: https://github.com/lampepfl/dotty/blob/master/tests/pos/refinedSubtyping.scala