Skip to content

Fix problems with higher-kinded implicits #716

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
19 changes: 13 additions & 6 deletions src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -467,16 +467,23 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}

/** If `projection` is of the form T # Apply where `T` is an instance of a Lambda class,
* and `other` is not a type lambda projection, then convert `other` to a type lambda `U`, and
* continue with `T <:< U` if `inOrder` is true and `U <:< T` otherwise.
* then
* (1) if `other` is not a (possibly projected) type lambda, convert `other` to a type lambda `U`,
* and continue with `T <:< U` if `inOrder` is true and `U <:< T` otherwise.
* (2) if `other` is a already a type lambda,
* continue with `T <:< other` if `inOrder` is true and `other <:< T` otherwise.
*/
def compareHK(projection: NamedType, other: Type, inOrder: Boolean) =
projection.name == tpnme.Apply && {
val lambda = projection.prefix.LambdaClass(forcing = true)
lambda.exists && !other.isLambda &&
other.testLifted(lambda.typeParams,
if (inOrder) isSubType(projection.prefix, _) else isSubType(_, projection.prefix),
if (inOrder) Nil else classBounds(projection.prefix))
lambda.exists && {
if (!other.isLambda)
other.testLifted(lambda.typeParams,
if (inOrder) isSubType(projection.prefix, _) else isSubType(_, projection.prefix),
if (inOrder) Nil else classBounds(projection.prefix))
else if (inOrder) isSubType(projection.prefix, other)
else isSubType(other, projection.prefix)
}
}

/** The class symbols bounding the type of the `Apply` member of `tp` */
Expand Down
8 changes: 7 additions & 1 deletion src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,13 @@ object Types {
case SkolemType(tp) =>
tp.lookupRefined(name)
case pre: WildcardType =>
WildcardType
pre.optBounds match {
case TypeBounds(lo, hi) if name.isTypeName =>
// for term names, forming a Termref with just the name risks losing overloaded instance
WildcardType(TypeBounds(NamedType(lo, name), NamedType(hi, name)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on https://github.com/dotty-staging/dotty/blob/fix/shuffle/src/dotty/tools/dotc/core/Types.scala#L1423-L1424 is now wrong since the wildcard is now bounded, not unbounded. it'd be nice to update it and maybe also document the handling of wildcard in lookupRefined itself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, does this mean that we consider (_ >: Foo <: Bar)#T to be equivalent to _ >: Foo#T <: Bar#T ? If so, isn't this wrong in general? For example, if T is contravariant we may have Foo <: Bar but Foo#T >: Bar#T so the bounds _ >: Foo#T <: Bar#T would not be satisfiable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that having a few test cases would be helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smarter Good point about the change in lookupRefined. I have backed out of it, and replaced it with a different solution.

Test cases: We have Random.shuffle, I think that's already a good one. If you have more, please add them.

case _ =>
WildcardType
}
case pre: TypeRef =>
pre.info match {
case TypeAlias(alias) => loop(alias, resolved)
Expand Down
7 changes: 7 additions & 0 deletions tests/pos/i553-shuffle.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import scala.util.Random
object Test {
def test = {
val rand = new Random
rand.shuffle(List(1,2))// infers implicit argument list (List.canBuildFrom[Int])
}
}
File renamed without changes.