Skip to content

Nil.type widens to Nil$ #4987

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
nicolasstucki opened this issue Aug 22, 2018 · 7 comments
Closed

Nil.type widens to Nil$ #4987

nicolasstucki opened this issue Aug 22, 2018 · 7 comments

Comments

@nicolasstucki
Copy link
Contributor

object Foo {

  class Expr[T]

  abstract class Liftable[T] {
    def toExpr(x: T): Expr[T]
  }

  implicit class LiftExprOps[T](val x: T) extends AnyVal {
    def toExpr(implicit ev: Liftable[T]): Expr[T] = ev.toExpr(x)
  }

  implicit def NilIsLiftable: Liftable[Nil.type] = ???

  Nil.toExpr(NilIsLiftable)
  (Nil.toExpr: Expr[Nil.type])
  Nil.toExpr
}

fails with

-- Error: Foo.scala:49:12 ------------------------------------------------------
49 |  Nil.toExpr
   |            ^
   |no implicit argument of type Foo.Liftable[scala.collection.immutable.Nil] was found for parameter ev of method toExpr in class LiftExprOps

the last case inferes the type scala.collection.immutable.Nil$ instead of collection.immutable.Nil.type for the type parameter of the implicit class LiftExprOps.

This can be seen after typer

result of Foo.scala after frontend:
package <empty> {
  final lazy module val Foo: Foo$ = new Foo$()
  final module class Foo$() extends Object() { this: Foo.type => 
    class Expr[T >: Nothing <: Any]() extends Object() { 
       T
    }
    abstract class Liftable[T >: Nothing <: Any]() extends Object() { 
       T
      def toExpr(x: Liftable.this.T): Foo.Expr[Liftable.this.T]
    }
    final class LiftExprOps[T >: Nothing <: Any](x: T) extends AnyVal() { 
       T
      val x: T
      def toExpr(implicit ev: Foo.Liftable[LiftExprOps.this.T]): 
        Foo.Expr[LiftExprOps.this.T]
       = ev.toExpr(LiftExprOps.this.x)
    }
    final lazy module val LiftExprOps: Foo.LiftExprOps$ = new Foo.LiftExprOps$()
    final module class LiftExprOps$() extends Object() { 
      this: Foo.LiftExprOps.type =>
    }
    implicit def LiftExprOps[T >: Nothing <: Any](x: T): Foo.LiftExprOps[T] = 
      new Foo.LiftExprOps[T](x)
    implicit def NilIsLiftable: Foo.Liftable[Nil.type] = ???
    Foo.LiftExprOps[=> collection.immutable.Nil.type(Nil)](Nil).toExpr(
      Foo.NilIsLiftable
    )
    Foo.LiftExprOps[=> collection.immutable.Nil.type(Nil)](Nil).toExpr(
      Foo.NilIsLiftable
    ): Foo.Expr[Nil.type]
    Foo.LiftExprOps[scala.collection.immutable.Nil$](Nil).toExpr(
      /* missing */implicitly[<notype>]
    )
  }
}

This code does compile on Scala 2.

@Blaisorblade
Copy link
Contributor

@abeln @smarter Does this relate to the inference issues you were looking together at?

@smarter
Copy link
Member

smarter commented Aug 22, 2018

Don't think so. Type inference usually widen singleton types but shouldn't do that for objects so it's probably a missing condition

@smarter smarter closed this as completed in 0f7a02e Mar 8, 2020
smarter added a commit that referenced this issue Mar 8, 2020
Fix #4987: Avoid widening instantiations to module classes
@nicolasstucki nicolasstucki reopened this Aug 7, 2020
@nicolasstucki
Copy link
Contributor Author

This is still happening. It seems that when we widen Nil.type it becomes Nil$.

@nicolasstucki nicolasstucki changed the title Wrong type inferred for Nil Nil.type widens to Nill$ Aug 7, 2020
@nicolasstucki nicolasstucki changed the title Nil.type widens to Nill$ Nil.type widens to Nil$ Aug 7, 2020
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Aug 7, 2020
@smarter
Copy link
Member

smarter commented Aug 7, 2020

Yes, but type inference no longer does that widening, so what's the issue?

@bishabosha
Copy link
Member

bishabosha commented Sep 17, 2020

widen strips all singletons, widenInferred then recovers module value singleton type from a reference to the module class, I suggest we preserve module values unless you really really need to remove singletons

@bishabosha
Copy link
Member

also, the code in the example compiles, so perhaps a new issue should be opened?

@odersky
Copy link
Contributor

odersky commented Apr 5, 2022

Yes, sure, widening Nil.type gives Nil$. What else did we expect?

@odersky odersky closed this as completed Apr 5, 2022
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

5 participants