-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Direct representation of higher-kinded types #1343
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
Changes from 1 commit
5866d0d
d30f441
5d03186
cdb4a1c
850dc6f
af43d32
aa7f66d
08a0ea6
178e90e
4bf43f8
5daae27
e56bd1f
e61b80a
a7d61c0
d0f82a5
c136af1
ae1f248
939d9da
c35f817
e36a36a
6a7e466
8e84fb0
68e73e8
463e99a
0a5f839
31af865
5041e93
f1bf78b
830b724
6414f3b
e749d83
d1f809f
60d81f8
3490e01
f6efd99
97e84e6
73dd039
02ce995
c28dd1b
c1e27a0
98b466c
0965e1a
65c26ba
1e48758
960ea75
e0db04d
de5d8fe
8805dd4
646bf97
09f7ab1
9a90e81
dca1052
4093e13
bb59931
dc5be65
31ecad5
9d9965c
a23c1a4
6bd7ba9
ae360e9
6abde38
68abba1
30e15ab
b6a8bc7
32c0135
34a068b
beff8f8
eebb4b0
fd62c7b
4693a78
2ddb849
c541ef9
78b2672
223705d
5e90215
540b38c
a200695
6d7bc49
055726e
a6a142e
1792c9e
cdebd91
84a1a7a
c7f3b45
7df0fa5
1443fd4
f50cb20
0ff5354
18b3080
82fc27f
a737b47
894c9fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
When applying a type alias of a type lambda, keep the original application instead of reducing. But reduce anyway if - the reduced type is an application where the type constructor has the same kind as the original type constructor, or - some of the arguments are wildcards.
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -338,10 +338,10 @@ class TypeApplications(val self: Type) extends AnyVal { | |
| * | ||
| * TODO: Handle parameterized lower bounds | ||
| */ | ||
| def LambdaAbstract(tparams: List[TypeParamInfo])(implicit ctx: Context): Type = { | ||
| def LambdaAbstract(tparams: List[Symbol])(implicit ctx: Context): Type = { | ||
| def expand(tp: Type) = | ||
| TypeLambda( | ||
| tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.paramVariance))( | ||
| tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.variance))( | ||
| tl => tparams.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds), | ||
| tl => tl.lifted(tparams, tp)) | ||
| assert(!isHK, self) | ||
|
|
@@ -439,20 +439,13 @@ class TypeApplications(val self: Type) extends AnyVal { | |
| } | ||
| } | ||
|
|
||
| /** Encode | ||
| /** The type representing | ||
| * | ||
| * T[U1, ..., Un] | ||
| * | ||
| * where | ||
| * @param self = `T` | ||
| * @param args = `U1,...,Un` | ||
| * performing the following simplifications | ||
| * | ||
| * 1. If `T` is an eta expansion `[X1,..,Xn] -> C[X1,...,Xn]` of class `C` compute | ||
| * `C[U1, ..., Un]` instead. | ||
| * 2. If `T` is some other type lambda `[X1,...,Xn] -> S` none of the arguments | ||
| * `U1,...,Un` is a wildcard, compute `[X1:=U1, ..., Xn:=Un]S` instead. | ||
| * 3. If `T` is a polytype, instantiate it to `U1,...,Un`. | ||
| */ | ||
| final def appliedTo(args: List[Type])(implicit ctx: Context): Type = /*>|>*/ track("appliedTo") /*<|<*/ { | ||
| val typParams = self.typeParams | ||
|
|
@@ -469,30 +462,52 @@ class TypeApplications(val self: Type) extends AnyVal { | |
| } | ||
| case nil => t | ||
| } | ||
| val stripped = self.stripTypeVar | ||
| val dealiased = stripped.safeDealias | ||
| if (args.isEmpty || ctx.erasedTypes) self | ||
| else self.stripTypeVar.safeDealias match { | ||
| case self: TypeLambda => | ||
| if (!args.exists(_.isInstanceOf[TypeBounds])) self.instantiate(args) | ||
| else { | ||
| val reducer = new Reducer(self, args) | ||
| val reduced = reducer(self.resType) | ||
| if (reducer.allReplaced) reduced | ||
| else HKApply(self, args) | ||
| } | ||
| case self: PolyType => | ||
| self.instantiate(args) | ||
| case self: AndOrType => | ||
| self.derivedAndOrType(self.tp1.appliedTo(args), self.tp2.appliedTo(args)) | ||
| case self: TypeAlias => | ||
| self.derivedTypeAlias(self.alias.appliedTo(args)) | ||
| case self: TypeBounds => | ||
| self.derivedTypeBounds(self.lo, self.hi.appliedTo(args)) | ||
| case self: LazyRef => | ||
| LazyRef(() => self.ref.appliedTo(args)) | ||
| case self: WildcardType => | ||
| self | ||
| case self: TypeRef if self.symbol == defn.NothingClass => | ||
| self | ||
| else dealiased match { | ||
| case dealiased: TypeLambda => | ||
| def tryReduce = | ||
| if (!args.exists(_.isInstanceOf[TypeBounds])) { | ||
| val reduced = dealiased.instantiate(args) | ||
| if (dealiased eq stripped) reduced | ||
| else reduced match { | ||
| case AppliedType(tycon, args) if variancesConform(typParams, tycon.typeParams) => | ||
| // Reducing is safe for type inference, as kind of type constructor does not change | ||
|
||
| //println(i"reduced: $reduced instead of ${HKApply(self, args)}") | ||
| reduced | ||
| case _ => | ||
| // Reducing changes kind, keep hk application instead | ||
| //println(i"fallback: ${HKApply(self, args)} instead of $reduced") | ||
| HKApply(self, args) | ||
| } | ||
| } | ||
| else dealiased.resType match { | ||
| case AppliedType(tycon, args1) if tycon.safeDealias ne tycon => | ||
| dealiased | ||
| .derivedTypeLambda(resType = tycon.safeDealias.appliedTo(args1)) | ||
| .appliedTo(args) | ||
| case _ => | ||
| val reducer = new Reducer(dealiased, args) | ||
| val reduced = reducer(dealiased.resType) | ||
| if (reducer.allReplaced) reduced | ||
| else HKApply(dealiased, args) | ||
| } | ||
| tryReduce | ||
| case dealiased: PolyType => | ||
| dealiased.instantiate(args) | ||
| case dealiased: AndOrType => | ||
| dealiased.derivedAndOrType(dealiased.tp1.appliedTo(args), dealiased.tp2.appliedTo(args)) | ||
| case dealiased: TypeAlias => | ||
| dealiased.derivedTypeAlias(dealiased.alias.appliedTo(args)) | ||
| case dealiased: TypeBounds => | ||
| dealiased.derivedTypeBounds(dealiased.lo, dealiased.hi.appliedTo(args)) | ||
| case dealiased: LazyRef => | ||
| LazyRef(() => dealiased.ref.appliedTo(args)) | ||
| case dealiased: WildcardType => | ||
| dealiased | ||
| case dealiased: TypeRef if dealiased.symbol == defn.NothingClass => | ||
| dealiased | ||
| case _ if typParams.isEmpty || typParams.head.isInstanceOf[LambdaParam] => | ||
| HKApply(self, args) | ||
| case dealiased => | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -117,6 +117,7 @@ object Types { | |
| case _ => this1.symbol eq sym | ||
| } | ||
| case this1: RefinedOrRecType => this1.parent.isRef(sym) | ||
| case this1: HKApply => this1.superType.isRef(sym) | ||
| case _ => false | ||
| } | ||
|
|
||
|
|
@@ -857,6 +858,10 @@ object Types { | |
| tp.derivedAnnotatedType(tp.tpe.dealias, tp.annot) | ||
| case tp: LazyRef => | ||
| tp.ref.dealias | ||
| case app @ HKApply(tycon, args) => | ||
| val tycon1 = tycon.dealias | ||
| if (tycon1 ne tycon) app.superType.dealias | ||
| else this | ||
| case _ => this | ||
| } | ||
|
|
||
|
|
@@ -2586,7 +2591,7 @@ object Types { | |
| lazy val typeParams: List[LambdaParam] = | ||
| paramNames.indices.toList.map(new LambdaParam(this, _)) | ||
|
|
||
| def derivedTypeLambda(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type = | ||
| def derivedTypeLambda(paramNames: List[TypeName] = paramNames, paramBounds: List[TypeBounds] = paramBounds, resType: Type)(implicit ctx: Context): Type = | ||
|
||
| resType match { | ||
| case resType @ TypeAlias(alias) => | ||
| resType.derivedTypeAlias(duplicate(paramNames, paramBounds, alias)) | ||
|
|
@@ -2640,12 +2645,21 @@ object Types { | |
| abstract case class HKApply(tycon: Type, args: List[Type]) | ||
| extends CachedProxyType with ValueType { | ||
|
|
||
| private var validSuper: Period = Nowhere | ||
| private var cachedSuper: Type = _ | ||
|
|
||
| override def underlying(implicit ctx: Context): Type = tycon | ||
|
|
||
| override def superType(implicit ctx: Context): Type = tycon match { | ||
| case tp: TypeLambda => defn.AnyType | ||
| case tp: TypeProxy => tp.superType.applyIfParameterized(args) | ||
| case _ => defn.AnyType | ||
| override def superType(implicit ctx: Context): Type = { | ||
| if (ctx.period != validSuper) { | ||
| cachedSuper = tycon match { | ||
| case tp: TypeLambda => defn.AnyType | ||
| case tp: TypeProxy => tp.superType.applyIfParameterized(args) | ||
| case _ => defn.AnyType | ||
| } | ||
| validSuper = ctx.period | ||
| } | ||
| cachedSuper | ||
| } | ||
| /* | ||
| def lowerBound(implicit ctx: Context): Type = tycon.stripTypeVar match { | ||
|
||
|
|
@@ -2760,7 +2774,11 @@ object Types { | |
| else bounds(paramNum) | ||
| } | ||
| // no customized hashCode/equals needed because cycle is broken in PolyType | ||
| override def toString = s"PolyParam($paramName)" | ||
| override def toString = | ||
| try s"PolyParam($paramName)" | ||
| catch { | ||
| case ex: IndexOutOfBoundsException => s"PolyParam(<bad index: $paramNum>)" | ||
| } | ||
|
|
||
| override def computeHash = doHash(paramNum, binder.identityHash) | ||
|
|
||
|
|
||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package test | ||
|
|
||
| object Tags { | ||
| type Tagged[A, T] = {type Tag = T; type Self = A} | ||
|
|
||
| type @@[T, Tag] = Tagged[T, Tag] | ||
|
|
||
| trait Disjunction | ||
|
|
||
| def meh[M[_], A](ma: M[A]): M[A] = ma | ||
| meh(null: Int @@ Disjunction)//.asInstanceOf[Int @@ Disjunction]) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was on my TODO list also :). So far I've only noticed one method that expects only the upper-bound to be a lambda:
adaptHkVariances