Skip to content

Commit

Permalink
SI-7818 Cast our way out of extended existential angst
Browse files Browse the repository at this point in the history
`substituteSymbols` is not sophisticated enough to
operate on `TypeSkolem`-s which are based on one of the
"from" symbols.

The pertinant usage of `substituteSymbols` for this bug in
in `Extender`. Recapping on that transform:

    // orig
    class C[T](...) extends AnyVal { def foo[U] = <rhs> }

    // transform
    class C[T] extends AnyVal { ... }
    object C  { def foo$extension[T', U'] = <rhs'> }

Where `<rhs'>` has been subtituted with, among other things,
`[T, U] ~> [T', U']`.

In this case our expected type contains a new type parameter
(of the extension method), whereas the type of the RHS contains
an existential skolem still pinned to the corresponding class type
parameter.

    tree.tpe         = Observable1#7037[_$1#12344]
    <_$1#12344>.info =  <: T#7040
    pt               = Observable1#7037[T#15644]

The limitation of substution is lamented in the comments
of `adaptMismatchedSkolems`, which faces the harder version of
the issue where the skolems are in the expected type.

But, we're in the "easy" case with the skolems in the tree's type;
we can cast our way out of the problem.

See also f335e44 / ed915c5.
  • Loading branch information
retronym committed Sep 6, 2013
1 parent d46519d commit cb028ba
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 1 deletion.
Expand Up @@ -231,9 +231,14 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
.substituteThis(origThis, extensionThis) .substituteThis(origThis, extensionThis)
.changeOwner(origMeth -> extensionMeth) .changeOwner(origMeth -> extensionMeth)
) )
val castBody =
if (extensionBody.tpe <:< extensionMono.finalResultType)
extensionBody
else
gen.mkCastPreservingAnnotations(extensionBody, extensionMono.finalResultType) // SI-7818 e.g. mismatched existential skolems


// Record the extension method ( FIXME: because... ? ) // Record the extension method ( FIXME: because... ? )
extensionDefs(companion) += atPos(tree.pos)(DefDef(extensionMeth, extensionBody)) extensionDefs(companion) += atPos(tree.pos)(DefDef(extensionMeth, castBody))


// These three lines are assembling Foo.bar$extension[T1, T2, ...]($this) // These three lines are assembling Foo.bar$extension[T1, T2, ...]($this)
// which leaves the actual argument application for extensionCall. // which leaves the actual argument application for extensionCall.
Expand Down
10 changes: 10 additions & 0 deletions test/files/pos/t7818.scala
@@ -0,0 +1,10 @@
class Observable1[+T](val asJava: JObservable[_ <: T]) extends AnyVal {
private def foo[X](a: JObservable[X]): JObservable[X] = ???
// was generating a type error as the type of the RHS included an existential
// skolem based on the class type parameter `T`, which did not conform
// to the typer parameter of the extension method into which the RHS is
// transplanted.
def synchronize: Observable1[T] = new Observable1(foo(asJava))
}

class JObservable[T]

0 comments on commit cb028ba

Please sign in to comment.