Skip to content

Add match type #4964

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 49 commits into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
9ef3898
Add MatchType as a type form
odersky Aug 20, 2018
1c17274
Represent literals used as types with SingletonTypeTrees
odersky Aug 20, 2018
24a2f73
Syntax, parsing, and type-checking of match types
odersky Aug 20, 2018
6d472f5
Fix unpickling of match types
odersky Aug 20, 2018
0877a36
Blacklist match type fromtasty test
odersky Aug 20, 2018
bd8b3cd
Classify type defs with matches as RHS as abstract
odersky Aug 22, 2018
993c40c
Implement subtyping for match types
odersky Aug 22, 2018
151a37c
Cache match reduce results
odersky Aug 22, 2018
ffac30e
Cache results of attempts to reduce match types
odersky Aug 23, 2018
e2d8bc3
Use a special type for match aliases
odersky Aug 24, 2018
b261ff7
Applications of erased functions are always pure
odersky Aug 24, 2018
a144c35
Allow user-defined error diagnostics when rewriting
odersky Aug 24, 2018
5147d32
Fix two issues when comparing match types
odersky Aug 24, 2018
fb5c554
MatchType reorg
odersky Aug 27, 2018
400495f
Typelevel natural numbers
odersky Aug 27, 2018
3d3d595
Reduce matches on creation
odersky Aug 27, 2018
38312e0
Handle MatchTypeTrees in ExtractAPI
odersky Aug 29, 2018
a9f9ced
Refine matchtype reduction caching
odersky Aug 29, 2018
2408b54
Coarser variance checking for match types
odersky Aug 29, 2018
7a51259
Add constValue function
odersky Aug 29, 2018
dc669a6
Add NonEmptyTuple abstract class
odersky Aug 29, 2018
d924ef1
More precise derivesFrom for MatchTypes
odersky Aug 29, 2018
0d4a118
Base Tuple computations on types
odersky Aug 29, 2018
189973b
Make MatchTypes value types
odersky Aug 29, 2018
8307685
Fix inlining of parameters of singleton type
odersky Aug 29, 2018
8219a83
Test tuples2 needs to run with -Yno-deep-subtypes
odersky Aug 29, 2018
56759c8
Add constValueOpt method
odersky Aug 29, 2018
45fbf3e
Fix unpickling of match type aliases
odersky Aug 29, 2018
e41bf9a
Survive bottom values in pattern matches
odersky Aug 29, 2018
2d83885
Report rewrite errors at outermost rewrite call
odersky Aug 29, 2018
b53bf1e
Harden Tuple operations against wrong inputs
odersky Aug 29, 2018
71fbc15
Reduce sizes of tuples of tuples2.scala
odersky Aug 29, 2018
2d76382
Allow additional arguments for typelevel.error
odersky Sep 6, 2018
10f2acb
GenericSignatures needs to consult erasedToObject
odersky Sep 6, 2018
03f5c4e
Properly erase NonEmptyTuple
odersky Sep 6, 2018
3657799
Make Tuple types covariant
odersky Sep 6, 2018
d53b3fa
Allow generic tuple operations to be dynamic
odersky Sep 6, 2018
a7ea105
Equate TupleN(...) and *: types
odersky Sep 6, 2018
9897d22
Description and informal spec for match types
odersky Sep 8, 2018
7a0c31f
Fix typo
odersky Sep 8, 2018
0ca095f
Add related work section to match-types.md
odersky Sep 10, 2018
194d85d
Fix matchtype termination
odersky Sep 10, 2018
c7ee07c
Fix `Elem` method for sizes > 23
odersky Sep 12, 2018
00de2f8
Print max constraint under -Ydetailed-stats
odersky Sep 12, 2018
c51a2c0
Normalize when simplifying
odersky Sep 12, 2018
16d1856
Propagate bound into nested match types
odersky Sep 12, 2018
536c350
Match cases in parallel
odersky Sep 12, 2018
5a8ac63
Update rules on match term/type checking
odersky Sep 13, 2018
7b548db
Go back to reducing match types sequentially
odersky Sep 13, 2018
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
10 changes: 6 additions & 4 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
case mdef: TypeDef =>
def isBounds(rhs: Tree): Boolean = rhs match {
case _: TypeBoundsTree => true
case _: MatchTypeTree => true // Typedefs with Match rhs classify as abstract
case LambdaTypeTree(_, body) => isBounds(body)
case _ => false
}
Expand Down Expand Up @@ -392,20 +393,21 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
case Ident(_) =>
refPurity(tree)
case Select(qual, _) =>
refPurity(tree).min(exprPurity(qual))
if (tree.symbol.is(Erased)) Pure
else refPurity(tree).min(exprPurity(qual))
case New(_) =>
SimplyPure
case TypeApply(fn, _) =>
exprPurity(fn)
if (fn.symbol.is(Erased)) Pure else exprPurity(fn)
case Apply(fn, args) =>
def isKnownPureOp(sym: Symbol) =
sym.owner.isPrimitiveValueClass || sym.owner == defn.StringClass
if (tree.tpe.isInstanceOf[ConstantType] && isKnownPureOp(tree.symbol)
// A constant expression with pure arguments is pure.
|| fn.symbol.isStable)
minOf(exprPurity(fn), args.map(exprPurity)) `min` Pure
else
Impure
else if (fn.symbol.is(Erased)) Pure
else Impure
case Typed(expr, _) =>
exprPurity(expr)
case Block(stats, expr) =>
Expand Down
15 changes: 15 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,12 @@ object Trees {
type ThisTree[-T >: Untyped] = LambdaTypeTree[T]
}

/** [bound] selector match { cases } */
case class MatchTypeTree[-T >: Untyped] private[ast] (bound: Tree[T], selector: Tree[T], cases: List[CaseDef[T]])
extends TypTree[T] {
type ThisTree[-T >: Untyped] = MatchTypeTree[T]
}

/** => T */
case class ByNameTypeTree[-T >: Untyped] private[ast] (result: Tree[T])
extends TypTree[T] {
Expand Down Expand Up @@ -916,6 +922,7 @@ object Trees {
type RefinedTypeTree = Trees.RefinedTypeTree[T]
type AppliedTypeTree = Trees.AppliedTypeTree[T]
type LambdaTypeTree = Trees.LambdaTypeTree[T]
type MatchTypeTree = Trees.MatchTypeTree[T]
type ByNameTypeTree = Trees.ByNameTypeTree[T]
type TypeBoundsTree = Trees.TypeBoundsTree[T]
type Bind = Trees.Bind[T]
Expand Down Expand Up @@ -1099,6 +1106,10 @@ object Trees {
case tree: LambdaTypeTree if (tparams eq tree.tparams) && (body eq tree.body) => tree
case _ => finalize(tree, untpd.LambdaTypeTree(tparams, body))
}
def MatchTypeTree(tree: Tree)(bound: Tree, selector: Tree, cases: List[CaseDef]): MatchTypeTree = tree match {
case tree: MatchTypeTree if (bound eq tree.bound) && (selector eq tree.selector) && (cases eq tree.cases) => tree
case _ => finalize(tree, untpd.MatchTypeTree(bound, selector, cases))
}
def ByNameTypeTree(tree: Tree)(result: Tree): ByNameTypeTree = tree match {
case tree: ByNameTypeTree if result eq tree.result => tree
case _ => finalize(tree, untpd.ByNameTypeTree(result))
Expand Down Expand Up @@ -1255,6 +1266,8 @@ object Trees {
case LambdaTypeTree(tparams, body) =>
implicit val ctx = localCtx
cpy.LambdaTypeTree(tree)(transformSub(tparams), transform(body))
case MatchTypeTree(bound, selector, cases) =>
cpy.MatchTypeTree(tree)(transform(bound), transform(selector), transformSub(cases))
case ByNameTypeTree(result) =>
cpy.ByNameTypeTree(tree)(transform(result))
case TypeBoundsTree(lo, hi) =>
Expand Down Expand Up @@ -1389,6 +1402,8 @@ object Trees {
case LambdaTypeTree(tparams, body) =>
implicit val ctx = localCtx
this(this(x, tparams), body)
case MatchTypeTree(bound, selector, cases) =>
this(this(this(x, bound), selector), cases)
case ByNameTypeTree(result) =>
this(x, result)
case TypeBoundsTree(lo, hi) =>
Expand Down
18 changes: 12 additions & 6 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}

def CaseDef(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef =
ta.assignType(untpd.CaseDef(pat, guard, body), body)
ta.assignType(untpd.CaseDef(pat, guard, body), pat, body)

def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match =
ta.assignType(untpd.Match(selector, cases), cases)
ta.assignType(untpd.Match(selector, cases), selector, cases)

def Labeled(bind: Bind, expr: Tree)(implicit ctx: Context): Labeled =
ta.assignType(untpd.Labeled(bind, expr))
Expand Down Expand Up @@ -165,6 +165,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def LambdaTypeTree(tparams: List[TypeDef], body: Tree)(implicit ctx: Context): LambdaTypeTree =
ta.assignType(untpd.LambdaTypeTree(tparams, body), tparams, body)

def MatchTypeTree(bound: Tree, selector: Tree, cases: List[CaseDef])(implicit ctx: Context): MatchTypeTree =
ta.assignType(untpd.MatchTypeTree(bound, selector, cases), bound, selector, cases)

def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree =
ta.assignType(untpd.TypeBoundsTree(lo, hi), lo, hi)

Expand Down Expand Up @@ -575,7 +578,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
}


override def Closure(tree: Tree)(env: List[Tree], meth: Tree, tpt: Tree)(implicit ctx: Context): Closure = {
val tree1 = untpd.cpy.Closure(tree)(env, meth, tpt)
tree match {
Expand All @@ -584,19 +586,20 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case _ => ta.assignType(tree1, meth, tpt)
}
}

override def Match(tree: Tree)(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = {
val tree1 = untpd.cpy.Match(tree)(selector, cases)
tree match {
case tree: Match if sameTypes(cases, tree.cases) => tree1.withTypeUnchecked(tree.tpe)
case _ => ta.assignType(tree1, cases)
case _ => ta.assignType(tree1, selector, cases)
}
}

override def CaseDef(tree: Tree)(pat: Tree, guard: Tree, body: Tree)(implicit ctx: Context): CaseDef = {
val tree1 = untpd.cpy.CaseDef(tree)(pat, guard, body)
tree match {
case tree: CaseDef if body.tpe eq tree.body.tpe => tree1.withTypeUnchecked(tree.tpe)
case _ => ta.assignType(tree1, body)
case _ => ta.assignType(tree1, pat, body)
}
}

Expand Down Expand Up @@ -821,7 +824,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {

/** `tree == that` */
def equal(that: Tree)(implicit ctx: Context) =
applyOverloaded(tree, nme.EQ, that :: Nil, Nil, defn.BooleanType)
if (that.tpe.widen.isRef(defn.NothingClass))
Literal(Constant(false))
else
applyOverloaded(tree, nme.EQ, that :: Nil, Nil, defn.BooleanType)

/** `tree.isInstanceOf[tp]`, with special treatment of singleton types */
def isInstance(tp: Type)(implicit ctx: Context): Tree = tp.dealias match {
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def RefinedTypeTree(tpt: Tree, refinements: List[Tree]): RefinedTypeTree = new RefinedTypeTree(tpt, refinements)
def AppliedTypeTree(tpt: Tree, args: List[Tree]): AppliedTypeTree = new AppliedTypeTree(tpt, args)
def LambdaTypeTree(tparams: List[TypeDef], body: Tree): LambdaTypeTree = new LambdaTypeTree(tparams, body)
def MatchTypeTree(bound: Tree, selector: Tree, cases: List[CaseDef]): MatchTypeTree = new MatchTypeTree(bound, selector, cases)
def ByNameTypeTree(result: Tree): ByNameTypeTree = new ByNameTypeTree(result)
def TypeBoundsTree(lo: Tree, hi: Tree): TypeBoundsTree = new TypeBoundsTree(lo, hi)
def Bind(name: Name, body: Tree): Bind = new Bind(name, body)
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ object Config {
final val cacheAsSeenFrom = true
final val cacheMemberNames = true
final val cacheImplicitScopes = true
final val cacheMatchReduced = true

final val checkCacheMembersNamed = false

Expand Down
53 changes: 29 additions & 24 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ trait ConstraintHandling {
/** If the constraint is frozen we cannot add new bounds to the constraint. */
protected var frozenConstraint = false

/** Potentially a type lambda that is still instantiatable, even though the constraint
* is generally frozen.
*/
protected var caseLambda: Type = NoType

/** If set, align arguments `S1`, `S2`when taking the glb
* `T1 { X = S1 } & T2 { X = S2 }` of a constraint upper bound for some type parameter.
* Aligning means computing `S1 =:= S2` which may change the current constraint.
Expand All @@ -47,7 +52,7 @@ trait ConstraintHandling {
*/
protected var comparedTypeLambdas: Set[TypeLambda] = Set.empty

private def addOneBound(param: TypeParamRef, bound: Type, isUpper: Boolean): Boolean =
protected def addOneBound(param: TypeParamRef, bound: Type, isUpper: Boolean): Boolean =
!constraint.contains(param) || {
def occursIn(bound: Type): Boolean = {
val b = bound.dealias
Expand Down Expand Up @@ -167,19 +172,20 @@ trait ConstraintHandling {
isSubType(tp1, tp2)
}

final def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
val saved = frozenConstraint
@forceInline final def inFrozenConstraint[T](op: => T): T = {
val savedFrozen = frozenConstraint
val savedLambda = caseLambda
frozenConstraint = true
try isSubType(tp1, tp2)
finally frozenConstraint = saved
caseLambda = NoType
try op
finally {
frozenConstraint = savedFrozen
caseLambda = savedLambda
}
}

final def isSameTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
val saved = frozenConstraint
frozenConstraint = true
try isSameType(tp1, tp2)
finally frozenConstraint = saved
}
final def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = inFrozenConstraint(isSubType(tp1, tp2))
final def isSameTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = inFrozenConstraint(isSameType(tp1, tp2))

/** Test whether the lower bounds of all parameters in this
* constraint are a solution to the constraint.
Expand Down Expand Up @@ -319,7 +325,7 @@ trait ConstraintHandling {
}

/** The current bounds of type parameter `param` */
final def bounds(param: TypeParamRef): TypeBounds = {
def bounds(param: TypeParamRef): TypeBounds = {
val e = constraint.entry(param)
if (e.exists) e.bounds
else {
Expand Down Expand Up @@ -355,7 +361,7 @@ trait ConstraintHandling {

/** Can `param` be constrained with new bounds? */
final def canConstrain(param: TypeParamRef): Boolean =
!frozenConstraint && (constraint contains param)
(!frozenConstraint || (caseLambda `eq` param.binder)) && constraint.contains(param)

/** Add constraint `param <: bound` if `fromBelow` is false, `param >: bound` otherwise.
* `bound` is assumed to be in normalized form, as specified in `firstTry` and
Expand Down Expand Up @@ -492,19 +498,18 @@ trait ConstraintHandling {
/** Check that constraint is fully propagated. See comment in Config.checkConstraintsPropagated */
def checkPropagated(msg: => String)(result: Boolean): Boolean = {
if (Config.checkConstraintsPropagated && result && addConstraintInvocations == 0) {
val saved = frozenConstraint
frozenConstraint = true
for (p <- constraint.domainParams) {
def check(cond: => Boolean, q: TypeParamRef, ordering: String, explanation: String): Unit =
assert(cond, i"propagation failure for $p $ordering $q: $explanation\n$msg")
for (u <- constraint.upper(p))
check(bounds(p).hi <:< bounds(u).hi, u, "<:", "upper bound not propagated")
for (l <- constraint.lower(p)) {
check(bounds(l).lo <:< bounds(p).hi, l, ">:", "lower bound not propagated")
check(constraint.isLess(l, p), l, ">:", "reverse ordering (<:) missing")
inFrozenConstraint {
for (p <- constraint.domainParams) {
def check(cond: => Boolean, q: TypeParamRef, ordering: String, explanation: String): Unit =
assert(cond, i"propagation failure for $p $ordering $q: $explanation\n$msg")
for (u <- constraint.upper(p))
check(bounds(p).hi <:< bounds(u).hi, u, "<:", "upper bound not propagated")
for (l <- constraint.lower(p)) {
check(bounds(l).lo <:< bounds(p).hi, l, ">:", "lower bound not propagated")
check(constraint.isLess(l, p), l, ">:", "reverse ordering (<:) missing")
}
}
}
frozenConstraint = saved
}
result
}
Expand Down
9 changes: 5 additions & 4 deletions compiler/src/dotty/tools/dotc/core/ConstraintRunInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package dotty.tools.dotc
package core

import Contexts._
import config.Printers.typr
import config.Printers.{default, typr}

trait ConstraintRunInfo { self: Run =>
private[this] var maxSize = 0
Expand All @@ -12,8 +12,9 @@ trait ConstraintRunInfo { self: Run =>
maxSize = size
maxConstraint = c
}
def printMaxConstraint()(implicit ctx: Context) =
if (maxSize > 0) typr.println(s"max constraint = ${maxConstraint.show}")

def printMaxConstraint()(implicit ctx: Context) = {
val printer = if (ctx.settings.YdetailedStats.value) default else typr
if (maxSize > 0) printer.println(s"max constraint = ${maxConstraint.show}")
}
protected def reset() = maxConstraint = null
}
16 changes: 15 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,15 @@ class Definitions {
lazy val Sys_errorR = SysPackage.moduleClass.requiredMethodRef(nme.error)
def Sys_error(implicit ctx: Context) = Sys_errorR.symbol

lazy val TypelevelPackageObjectRef = ctx.requiredModuleRef("scala.typelevel.package")
lazy val TypelevelPackageObject = TypelevelPackageObjectRef.symbol.moduleClass
lazy val Typelevel_errorR = TypelevelPackageObjectRef.symbol.requiredMethodRef(nme.error)
def Typelevel_error(implicit ctx: Context) = Typelevel_errorR.symbol
lazy val Typelevel_constValueR = TypelevelPackageObjectRef.symbol.requiredMethodRef("constValue")
def Typelevel_constValue(implicit ctx: Context) = Typelevel_constValueR.symbol
lazy val Typelevel_constValueOptR = TypelevelPackageObjectRef.symbol.requiredMethodRef("constValueOpt")
def Typelevel_constValueOpt(implicit ctx: Context) = Typelevel_constValueOptR.symbol

/** The `scalaShadowing` package is used to safely modify classes and
* objects in scala so that they can be used from dotty. They will
* be visible as members of the `scala` package, replacing any objects
Expand Down Expand Up @@ -708,6 +717,8 @@ class Definitions {

lazy val TupleTypeRef = ctx.requiredClassRef("scala.Tuple")
def TupleClass(implicit ctx: Context) = TupleTypeRef.symbol.asClass
lazy val NonEmptyTupleTypeRef = ctx.requiredClassRef("scala.NonEmptyTuple")
def NonEmptyTupleClass(implicit ctx: Context) = NonEmptyTupleTypeRef.symbol.asClass

lazy val PairType = ctx.requiredClassRef("scala.*:")
def PairClass(implicit ctx: Context) = PairType.symbol.asClass
Expand Down Expand Up @@ -884,6 +895,9 @@ class Definitions {
}
}

final def isTypelevel_S(sym: Symbol)(implicit ctx: Context) =
sym.name == tpnme.S && sym.owner == TypelevelPackageObject

// ----- Symbol sets ---------------------------------------------------

lazy val AbstractFunctionType = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 0)
Expand Down Expand Up @@ -1213,7 +1227,7 @@ class Definitions {
def isValueSubClass(sym1: Symbol, sym2: Symbol) =
valueTypeEnc(sym2.asClass.name) % valueTypeEnc(sym1.asClass.name) == 0

lazy val erasedToObject = Set[Symbol](AnyClass, AnyValClass, TupleClass, SingletonClass)
lazy val erasedToObject = Set[Symbol](AnyClass, AnyValClass, TupleClass, NonEmptyTupleClass, SingletonClass)

// ----- Initialization ---------------------------------------------------

Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ object StdNames {
final val Object: N = "Object"
final val PartialFunction: N = "PartialFunction"
final val PrefixType: N = "PrefixType"
final val S: N = "S"
final val Serializable: N = "Serializable"
final val Singleton: N = "Singleton"
final val Throwable: N = "Throwable"
Expand Down
16 changes: 10 additions & 6 deletions compiler/src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import util.common._
import Names._
import NameOps._
import NameKinds._
import Constants.Constant
import Flags._
import StdNames.tpnme
import util.Positions.Position
Expand Down Expand Up @@ -337,8 +338,8 @@ class TypeApplications(val self: Type) extends AnyVal {
tl => arg.paramInfos.map(_.subst(arg, tl).bounds),
tl => arg.resultType.subst(arg, tl)
)
case arg @ TypeAlias(alias) =>
arg.derivedTypeAlias(adaptArg(alias))
case arg: AliasingBounds =>
arg.derivedAlias(adaptArg(arg.alias))
case arg @ TypeBounds(lo, hi) =>
arg.derivedTypeBounds(adaptArg(lo), adaptArg(hi))
case _ =>
Expand Down Expand Up @@ -401,8 +402,8 @@ class TypeApplications(val self: Type) extends AnyVal {
dealiased.derivedAndType(dealiased.tp1.appliedTo(args), dealiased.tp2.appliedTo(args))
case dealiased: OrType =>
dealiased.derivedOrType(dealiased.tp1.appliedTo(args), dealiased.tp2.appliedTo(args))
case dealiased: TypeAlias =>
dealiased.derivedTypeAlias(dealiased.alias.appliedTo(args))
case dealiased: AliasingBounds =>
dealiased.derivedAlias(dealiased.alias.appliedTo(args))
case dealiased: TypeBounds =>
dealiased.derivedTypeBounds(dealiased.lo.appliedTo(args), dealiased.hi.appliedTo(args))
case dealiased: LazyRef =>
Expand Down Expand Up @@ -434,10 +435,13 @@ class TypeApplications(val self: Type) extends AnyVal {
appliedTo(args)
}

/** Turns non-bounds types to type aliases */
/** Turns non-bounds types to type bounds.
* A (possible lambda abstracted) match type is turned into an abstract type.
* Every other type is turned into a type alias
*/
final def toBounds(implicit ctx: Context): TypeBounds = self match {
case self: TypeBounds => self // this can happen for wildcard args
case _ => TypeAlias(self)
case _ => if (self.isMatch) MatchAlias(self) else TypeAlias(self)
}

/** Translate a type of the form From[T] to To[T], keep other types as they are.
Expand Down
Loading