Skip to content

Fix parameterized typedefs with lambdas as rhs #1409

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 3 commits into from
Jul 25, 2016
Merged
Show file tree
Hide file tree
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
7 changes: 3 additions & 4 deletions src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,12 @@ class TypeApplications(val self: Type) extends AnyVal {
self.parent.typeParams.filterNot(_.paramName == self.refinedName)
case self: RecType =>
self.parent.typeParams
case _: HKApply | _: SingletonType =>
case _: SingletonType =>
Nil
case self: WildcardType =>
self.optBounds.typeParams
case self: TypeProxy =>
self.underlying.typeParams
self.superType.typeParams
case _ =>
Nil
}
Expand Down Expand Up @@ -312,14 +312,13 @@ class TypeApplications(val self: Type) extends AnyVal {
case self: TypeRef => self.info.isHK
case self: RefinedType => false
case self: TypeLambda => true
case self: HKApply => false
case self: SingletonType => false
case self: TypeVar =>
// Using `origin` instead of `underlying`, as is done for typeParams,
// avoids having to set ephemeral in some cases.
self.origin.isHK
case self: WildcardType => self.optBounds.isHK
case self: TypeProxy => self.underlying.isHK
case self: TypeProxy => self.superType.isHK
case _ => false
}

Expand Down
19 changes: 14 additions & 5 deletions src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
}

/** Fall back to comparing either with `fourthTry` or against the lower
* approximation of the rhs.
* @param tyconLo The type constructor's lower approximation.
*/
def fallback(tyconLo: Type) =
either(fourthTry(tp1, tp2), isSubType(tp1, tyconLo.applyIfParameterized(args2)))

/** Let `tycon2bounds` be the bounds of the RHS type constructor `tycon2`.
* Let `app2 = tp2` where the type constructor of `tp2` is replaced by
* `tycon2bounds.lo`.
Expand All @@ -674,13 +681,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* tp1 <:< tp2 using fourthTry (this might instantiate params in tp1)
* tp1 <:< app2 using isSubType (this might instantiate params in tp2)
*/
def compareLower(tycon2bounds: TypeBounds, tyconIsTypeRef: Boolean): Boolean = {
def app2 = tycon2bounds.lo.applyIfParameterized(args2)
def compareLower(tycon2bounds: TypeBounds, tyconIsTypeRef: Boolean): Boolean =
if (tycon2bounds.lo eq tycon2bounds.hi)
isSubType(tp1, if (tyconIsTypeRef) tp2.superType else app2)
isSubType(tp1,
if (tyconIsTypeRef) tp2.superType
else tycon2bounds.lo.applyIfParameterized(args2))
else
either(fourthTry(tp1, tp2), isSubType(tp1, app2))
}
fallback(tycon2bounds.lo)

tycon2 match {
case param2: PolyParam =>
Expand All @@ -693,6 +700,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
compareLower(tycon2.info.bounds, tyconIsTypeRef = true)
case _: TypeVar | _: AnnotatedType =>
isSubType(tp1, tp2.superType)
case tycon2: HKApply =>
fallback(tycon2.lowerBound)
case _ =>
false
}
Expand Down
1 change: 0 additions & 1 deletion src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2653,7 +2653,6 @@ object Types {
cachedSuper
}

/* (Not needed yet) */
def lowerBound(implicit ctx: Context) = tycon.stripTypeVar match {
case tycon: TypeRef =>
tycon.info match {
Expand Down
12 changes: 5 additions & 7 deletions src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -934,13 +934,8 @@ class Namer { typer: Typer =>
}

def typeDefSig(tdef: TypeDef, sym: Symbol, tparamSyms: List[TypeSymbol])(implicit ctx: Context): Type = {
val isDerived = tdef.rhs.isInstanceOf[untpd.DerivedTypeTree]
//val toParameterize = tparamSyms.nonEmpty && !isDerived
//val needsLambda = sym.allOverriddenSymbols.exists(_ is HigherKinded) && !isDerived
def abstracted(tp: Type): Type =
if (tparamSyms.nonEmpty && !tp.isHK) tp.LambdaAbstract(tparamSyms)
//else if (toParameterize) tp.parameterizeWith(tparamSyms)
else tp
if (tparamSyms.nonEmpty) tp.LambdaAbstract(tparamSyms) else tp

val dummyInfo = abstracted(TypeBounds.empty)
sym.info = dummyInfo
Expand All @@ -954,7 +949,10 @@ class Namer { typer: Typer =>
//
// The scheme critically relies on an implementation detail of isRef, which
// inspects a TypeRef's info, instead of simply dealiasing alias types.
val rhsType = abstracted(typedAheadType(tdef.rhs).tpe)

val isDerived = tdef.rhs.isInstanceOf[untpd.DerivedTypeTree]
val rhsBodyType = typedAheadType(tdef.rhs).tpe
val rhsType = if (isDerived) rhsBodyType else abstracted(rhsBodyType)
val unsafeInfo = rhsType match {
case bounds: TypeBounds => bounds
case alias => TypeAlias(alias, if (sym is Local) sym.variance else 0)
Expand Down
21 changes: 21 additions & 0 deletions tests/pos/nestedLambdas.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Test {

type T = [X] -> [Y] -> (X, Y)

type A[X] = [Y] -> (X, Y)

type B[X] = (X, X)

val x: T[Int][Boolean] = ???

val y: A[Int][Boolean] = x

def f[X <: T[Int]] = ???

f[A[Int]]

def g[X <: T] = ???

g[A]

}