Skip to content

Conversation

@milessabin
Copy link
Contributor

Compiling the following,

object Test {
  type Id[T] = T
  def foo(x: Int): Id[x.type] = x

  { lazy val result: 1 = foo(1) }
}

crashes with an unexpected type error during the Fields phase,

error: scala.reflect.internal.Types$TypeError: type mismatch;
 found   : Int
 required: 1

This is because the translation of the local lazy val in Fields maps to a LazyInt which holds an Int value. This is too wide to assign to the 1-typed val and results in a type error when the tree synthesized
during Fields is typechecked.

I've fixed this by inserting a cast to the narrower type, which is eliminated during erasure. In principle we could switch to a scheme similar to LazyUnit for literal typed local lazy vals, ie. eliminating the storage for the value whilst retaining the effects, but this seems like an unlikely enough scenario to not warrant the additional complexity that this optimization would entail.

This fixes scala/bug#10792.

@scala-jenkins scala-jenkins added this to the 2.13.0-M4 milestone Mar 21, 2018
@milessabin milessabin requested a review from adriaanm March 21, 2018 20:36
@adriaanm
Copy link
Contributor

adriaanm commented May 9, 2018

As discussed, we'll review in Berlin and give ourselves until M5 to refine.

@adriaanm adriaanm modified the milestones: 2.13.0-M4, 2.13.0-M5 May 9, 2018
If(initialized, getValue,
if (isUnit) Block(rhsAtComputer :: Nil, Apply(initialize, Nil))
else Apply(initialize, rhsAtComputer :: Nil))))
refineLiteral(
Copy link
Contributor

Choose a reason for hiding this comment

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

it feels weird the unit case is under the cast. Is there a way to cast a smaller expression?

Compiling the following,

  object Test {
    type Id[T] = T
    def foo(x: Int): Id[x.type] = x

    { lazy val result: 1 = foo(1) }
  }

crashes with an unexpected type error during the Fields phase,

  error: scala.reflect.internal.Types$TypeError: type mismatch;
   found   : Int
   required: 1

This is because the translation of the local lazy val in Fields maps to
a `LazyInt` which holds an `Int` value. This is too wide to assign to
the `1`-typed val and results in a type error when the tree synthesized
during Fields phase is typechecked.

I've fixed this by inserting a cast to the narrower type, which is
eliminated during erasure. In principle we could switch to a scheme
similar to LazyUnit for literal typed local lazy vals, ie. eliminating
the storage for the value whilst retaining the effects, but this seems
like an unlikely enough scenario to warrant the additional complexity
that this optimization would entail.

This fixes scala/bug#10792.
@milessabin
Copy link
Contributor Author

Narrowed the scope of the refinement, also rebased.

@milessabin
Copy link
Contributor Author

@adriaanm this is ready to go now if you're happy.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Literal/constant typed local lazy vals result in type errors

3 participants