Skip to content
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

Refining a return type in a sub-trait loses type information #10725

Open
szeiger opened this issue Feb 16, 2018 · 2 comments
Open

Refining a return type in a sub-trait loses type information #10725

szeiger opened this issue Feb 16, 2018 · 2 comments

Comments

@szeiger
Copy link
Member

szeiger commented Feb 16, 2018

In this following code the overridden declaration of fact in Iterable makes type inference fail for g and h The version in f where the additional type information is deliberately dropped, compiles successfully.

object IterableTest {
  trait IterableOps[+CC[_]] {
    def fact: IterableFactory[CC]
  }

  trait Iterable[+A] extends IterableOps[Iterable] {
    override def fact: IterableFactory[Iterable]
  }

  trait IterableFactory[+CC[_]]

  def f[CC[_] <: Iterable[_] with IterableOps[CC]](from: CC[_]): IterableFactory[CC] = (from:                  IterableOps[CC]).fact
  def g[CC[_] <: Iterable[_] with IterableOps[CC]](from: CC[_]): IterableFactory[CC] = (from: Iterable[_] with IterableOps[CC]).fact
  def h[CC[_] <: Iterable[_] with IterableOps[CC]](from: CC[_]): IterableFactory[CC] = (from                                  ).fact
}

This fails to compile (tested with Scala 2.12.2, 2.12.4 and 2.13.0-M3) with:

IterableTest.scala:13: error: type mismatch;
 found   : IterableTest.IterableFactory[IterableTest.Iterable]
 required: IterableTest.IterableFactory[CC]
  def g[CC[_] <: Iterable[_] with IterableOps[CC]](from: CC[_]): IterableFactory[CC] = (from: Iterable[_] with IterableOps[CC]).fact
                                                                                                                                ^
IterableTest.scala:14: error: type mismatch;
 found   : IterableTest.IterableFactory[IterableTest.Iterable]
 required: IterableTest.IterableFactory[CC]
  def h[CC[_] <: Iterable[_] with IterableOps[CC]](from: CC[_]): IterableFactory[CC] = (from                                  ).fact

It works in Dotty (current master branch).

@szeiger
Copy link
Member Author

szeiger commented Feb 16, 2018

Gitter discussion about this issue starting at https://gitter.im/scala/contributors?at=5a86e43b76ced47639edd6de

@Blaisorblade
Copy link

Blaisorblade commented Feb 16, 2018

The issue is that the type of from.fact is the one of Iterable.fact and not of IterableOps.fact. This might be according to the spec. Relevant quotes:

From https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#designators:

If r is a stable identifier of type T, the selection r.x refers statically to a term member m of r that is identified in T by the name x.
The type of a designator is the type T of the entity it refers to [which I think, from context, must be m]
The selection's result is then the member of r that is either defined by m or defined by a definition overriding m.

To figure out members of Iterable[_] with IterableOps[CC] let's look at https://www.scala-lang.org/files/archive/spec/2.11/03-types.html#compound-types:

If a declaration or definition overrides a declaration or definition in one of the component types T1,…,Tn, the usual rules for overriding apply

Finally, the rules for overriding say that:

A member M of class C that matches a non-private member M′ of a base class of C is said to override that member. In this case the binding of the overriding member M must subsume the binding of the overridden member M′.

I'd say that Iterable[_].fact does not subsume IterableOps[CC].fact at the location of the compound type Iterable[_] with IterableOps[CC]. OTOH, the spec talks about the binding of Iterable[_].fact, which does subsume the binding of IterableOps[CC].fact.

It appears the use of the subsumption relation must be refined using asSeenFrom to account for type arguments (https://www.scala-lang.org/files/archive/spec/2.11/03-types.html#base-types-and-member-definitions), and that the spec language might be insufficiently precise here.

EDIT: https://gitter.im/scala/contributors?at=5a87389b76ced47639f07bcf

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants