Skip to content

extension method seen on first compilation, but not second in the repl #7182

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
johnynek opened this issue Sep 8, 2019 · 3 comments
Closed
Assignees
Labels
area:repl itype:bug stat:needs minimization Needs a self contained minimization
Milestone

Comments

@johnynek
Copy link

johnynek commented Sep 8, 2019

minimized code

// unfortunately       
// opaque type Fix[F[_]] = F[Fix[F]]
// won't work (no recursion in opaque type), but this implementation is safe, but scary due to asInstanceOf
object FixImpl {
  type Fix[F[_]]

  inline def fix[F[_]](f: F[Fix[F]]): Fix[F] = f.asInstanceOf[Fix[F]]
  inline def unfix[F[_]](f: Fix[F]): F[Fix[F]] = f.asInstanceOf[F[Fix[F]]]
}

import FixImpl._

type OrNull[A <: AnyRef] = A | Null
// List[A] = null | (A, null) | (A, (A, null)) | (A, (A, (A, null))) | ...
opaque type List[A] = Fix[[X] =>> OrNull[(A, X)]]

object List {
  def empty[A]: List[A] = fix(null)
}

given ListOps {
  def (head: A) ::[A](self: List[A]): List[A] =
    fix((head, self))
} 

In the repl, I can use :: the first time, but not the second time:

scala> List.empty[Int]
val res0: List[Int] = null

scala> 1 :: res0
val res1: List[Int] = (1,null)

scala> 1 :: res0
1 |1 :: res0
  |  ^^^^^^^
  |  value :: is not a member of List[Int] - did you mean res0.==?

expectation

Notice, the first time I use :: it works, the second time with the exact same syntax, it fails.

seems possibly related to #7181

@som-snytt
Copy link
Contributor

As top-level in a named or empty package, if List is opaque:

scala> { import i7182._
     | 42 :: res0
     | }
2 |42 :: res0
  |   ^^^^^^^
  |   value :: is not a member of i7182.List[Int].
  |   An extension method was tried, but could not be fully constructed:
  |
  |       i7182.::[A](res0)

That is after deleting the disallowed inline and writing :: as extension.

I remember that top level opaque means opaque in the package object, but it's not obvious why compilation fails.

It works if not opaque or not top level:

scala> { import i7182.repro._
     | List.empty[Int]
     | }
val res0: i7182.repro.List[Int] = null

scala> { import i7182.repro._
     | 42 :: res0
     | }
val res1: i7182.repro.List[Int] = (42,null)

scala> { import i7182.repro._
     | 42 :: res0
     | }
val res2: i7182.repro.List[Int] = (42,null)

Actually it occurs to me that it's easier to rename the type for purposes of this experiment:

scala> import i7182.repro._

scala> Lost.empty[Int]
val res0: i7182.repro.Lost[Int] = null

scala> 42 :: res0
val res1: i7182.repro.Lost[Int] = (42,null)

scala> 42 :: res0
val res2: i7182.repro.Lost[Int] = (42,null)

@Kordyjan Kordyjan self-assigned this Jun 8, 2021
@Kordyjan
Copy link
Contributor

Kordyjan commented Jun 8, 2021

I've tried to reproduce this issue during the Spree, and have the same conclusions as @som-snytt above. Putting the example in an object body and removing the inlines, fixes it. The bug has been probably fixed along the way, but should be checked again as soon as #12748 #9879 is fixed.

@Kordyjan Kordyjan removed their assignment Jun 8, 2021
@anatoliykmetyuk anatoliykmetyuk added the stat:needs minimization Needs a self contained minimization label Jul 13, 2021
@dwijnand dwijnand self-assigned this Jul 13, 2021
@dwijnand dwijnand reopened this Jul 28, 2021
@dwijnand
Copy link
Member

I renamed List to LList and defined the extension method as such:

extension [A](head: A)
  def ::(self: LList[A]): LList[A] =
    fix((head, self))

and it's broken in 3.0.1 (not even the first call succeeds), but it seems to be fixed in 3.0.2-RC1:

$ scalac -3.0.2-RC1 i7182.scala -d out/
$ scala -3.0.2-RC1 -cp out
scala> LList.empty[Int]
val res0: LList[Int] = null

scala> 1 :: res0
val res1: LList[Int] = (1,null)

scala> 1 :: res0
val res2: LList[Int] = (1,null)

@SethTisue SethTisue added this to the 3.0.2-RC1 milestone Jul 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:repl itype:bug stat:needs minimization Needs a self contained minimization
Projects
None yet
Development

No branches or pull requests

7 participants