Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2309,9 +2309,9 @@ object Types {
}

/** A refined type parent { refinement }
* @param refinedName The name of the refinement declaration
* @param infoFn: A function that produces the info of the refinement declaration,
* given the refined type itself.
* @param parent The type being refined
* @param refinedName The name of the refinement declaration
* @param refinedInfo The info of the refinement declaration
*/
abstract case class RefinedType(parent: Type, refinedName: Name, refinedInfo: Type) extends RefinedOrRecType {

Expand Down Expand Up @@ -2370,6 +2370,31 @@ object Types {
}
}

/** A recursive type. Instances should be constructed via the companion object.
*
* @param parentExp A function that, given a recursive type R, produces a type
* that can refer to R via a `RecThis(R)` node. This is used to
* "tie the knot".
*
* For example, in
* class C { type T1; type T2 }
* type C2 = C { type T1; type T2 = T1 }
*
* The type of `C2` is a recursive type `{(x) => C{T1; T2 = x.T1}}`, written as
*
* RecType(
* RefinedType(
* RefinedType(
* TypeRef(...,class C),
* T1,
* TypeBounds(...)),
* T2,
* TypeBounds(
* TypeRef(RecThis(...),T1),
* TypeRef(RecThis(...),T1))))
*
* Where `RecThis(...)` points back to the enclosing `RecType`.
*/
class RecType(parentExp: RecType => Type) extends RefinedOrRecType with BindingType {

// See discussion in findMember#goRec why these vars are needed
Expand Down Expand Up @@ -2438,7 +2463,7 @@ object Types {
* 1. Nested Rec types on the type's spine are merged with the outer one.
* 2. Any refinement of the form `type T = z.T` on the spine of the type
* where `z` refers to the created rec-type is replaced by
* `type T`. This avoids infinite recursons later when we
* `type T`. This avoids infinite recursions later when we
* try to follow these references.
* TODO: Figure out how to guarantee absence of cycles
* of length > 1
Expand All @@ -2459,6 +2484,8 @@ object Types {
}
unique(rt.derivedRecType(normalize(rt.parent))).checkInst
}

/** Create a `RecType`, but only if the type generated by `parentExp` is indeed recursive. */
def closeOver(parentExp: RecType => Type)(implicit ctx: Context) = {
val rt = this(parentExp)
if (rt.isReferredToBy(rt.parent)) rt else rt.parent
Expand Down