Skip to content

more permissive scrutinee types in virt pattern matching#2

Merged
namin merged 3 commits intonamin:topic-virt-patmat-2.10.0from
TiarkRompf:topic-virt-patmat-2.10.0
Feb 12, 2013
Merged

more permissive scrutinee types in virt pattern matching#2
namin merged 3 commits intonamin:topic-virt-patmat-2.10.0from
TiarkRompf:topic-virt-patmat-2.10.0

Conversation

@TiarkRompf
Copy link

this commit adds support for definitions like this:

def runOrElse[T,U](in: RandVar[T])(matcher: T => RandVar[U]): RandVar[U]

previously, in was restricted to have type T

this commit adds support for definitions like this:

def runOrElse[T,U](in: RandVar[T])(matcher: T => RandVar[U]): RandVar[U]

previously, `in` was restricted to have type `T`
namin added a commit that referenced this pull request Feb 12, 2013
more permissive scrutinee types in virt pattern matching
@namin namin merged commit 59a9138 into namin:topic-virt-patmat-2.10.0 Feb 12, 2013
@namin
Copy link
Owner

namin commented Feb 12, 2013

I guess this three errors for problang3:

virtpatmat_problang3.scala:186: error: not found: value y
    case Friend(Knows(y)) => y
                             ^
virtpatmat_problang3.scala:191: error: not found: value y
    case Likes("Coffee") && Knows(y @ Likes("Coffee")) if x != y =>
                                                               ^
virtpatmat_problang3.scala:196: error: not found: value y
  val coffeeModel1: Rand[String] = uniform("A","B","C","D","E").flatMap({ case ShouldGrabCoffee(y) => always(y) }).flatMap(x=>x)
                                                                                                             ^
three errors found

@TiarkRompf
Copy link
Author

looks like i forgot the .flags and .check file ...

@namin
Copy link
Owner

namin commented Feb 12, 2013

:) nice, it works!

namin pushed a commit that referenced this pull request Sep 7, 2014
blueprint CSS layout modified to 18-column from 24-column, spacing between paragraphs reduced by 1em
namin pushed a commit that referenced this pull request Sep 7, 2014
When an application of a blackbox macro still has undetermined type
parameters after Scala’s type inference algorithm has finished working,
these type parameters are inferred forcedly, in exactly the same manner
as type inference happens for normal methods.

This makes it impossible for blackbox macros to influence type inference,
prohibiting fundep materialization.
namin pushed a commit that referenced this pull request Sep 7, 2014
While fixing the problem with the order of typechecks for whitebox expansions,
I realized that we’re doing redundant work when expanding blackbox macros.
Concretely, typechecking blackbox expansions looked as follows:

  val expanded1 = atPos(enclosingMacroPosition.focus)(Typed(expanded0, TypeTree(innerPt)))
  val expanded2 = typecheck("blackbox typecheck #1", expanded1, innerPt)
  typecheck("blackbox typecheck #2", expanded1, outerPt)

Or, if we reformulate it using quasiquotes (temporarily not taking
positions into account, since they aren’t important here):

  val expanded2 = typed(q”$expanded: $innerPt”, innerPt)
  typed(expanded2, outerPt)

In this formulation, it becomes apparent that the first typecheck is
redundant. If something is ascribed with some type, then typechecking
the ascription against that type does nothing useful.

This is also highlights one of the reasons why it would be really nice
to have quasiquotes used in the compiler. With them, it’s easy to notice
things that would otherwise remain buried behind swaths of boilerplate.
namin pushed a commit that referenced this pull request Sep 7, 2014
[Parts of this patch and some of the commentary are from @paulp]

This took me so long to figure out I can't even tell you. Partly because
there were two different bugs, one which only arose for trait forwarders
and one for mirror class forwarders, and every time I'd make one set
of tests work another set would start failing. The runtime failures
associated with these bugs were fairly well hidden because you usually
have to go through java to encounter them: scala doesn't pay that much
attention to generic signatures, so they can be wrong and scala might still
generate correct code. But java is not so lucky.

Bug #1)

During mixin composition, classes which extend traits receive forwarders
to the implementations. An attempt was made to give these the correct
info (in method "cloneBeforeErasure") but it was prone to giving
the wrong answer, because: the key attribute which the forwarder
must capture is what the underlying method will erase to *where the
implementation is*, not how it appears to the class which contains it.
That means the signature of the forwarder must be no more precise than
the signature of the inherited implementation unless additional measures
will be taken.

This subtle difference will put on an unsubtle show for you in test
run/t3452.scala.

    trait C[T]
    trait Search[M] { def search(input: M): C[Int] = null }
    object StringSearch extends Search[String] { }
    StringSearch.search("test");  // java
    // java.lang.NoSuchMethodError: StringSearch.search(Ljava/lang/String;)LC;

The principled thing to do here would be to create a pair of
methods in the host class: a mixin forwarder with the erased
signature `(String)C[Int]`, and a bridge method with the same
erased signature as the trait interface facet.

But, this turns out to be pretty hard to retrofit onto the
current setup of Mixin and Erasure, mostly due to the fact
that mixin happens after erasure which has already taken
care of bridging.

For a future, release, we should try to move all bridging
after mixin, and pursue this approach. But for now, what can
we do about `LinkageError`s for Java clients?

This commit simply checks if the pre-erasure method signature
that we generate for the trait forward erases identically to
that of the interface method. If so, we can be precise. If not,
we emit the erased signature as the generic signature.

Bug #2) The same principle is at work, at a different location.
During genjvm, objects without declared companion classes
are given static forwarders in the corresponding class, e.g.

    object Foo { def bar = 5 }

which creates these classes (taking minor liberties):

    class Foo$ { static val MODULE$ = new Foo$ ; def bar = 5 }
    class Foo  { static def bar = Foo$.MODULE$.bar }

In generating these, genjvm circumvented the usual process whereby one
creates a symbol and gives it an info, preferring to target the bytecode
directly. However generic signatures are calculated from symbol info
(in this case reusing the info from the module class.) Lacking even the
attempt which was being made in mixin to "clone before erasure", we
would have runtime failures of this kind:

    abstract class Foo {
      type T
      def f(x: T): List[T] = List()
    }
    object Bar extends Foo { type T = String }
    Bar.f("");    // java
    // java.lang.NoSuchMethodError: Bar.f(Ljava/lang/String;)Lscala/collection/immutable/List;

Before/after this commit:

    <   signature                                     f  (Ljava/lang/String;)Lscala/collection/immutable/List<Ljava/lang/String;>;
    ---
    >   signature                                     f  (Ljava/lang/Object;)Lscala/collection/immutable/List<Ljava/lang/Object;>;

This takes the warning count for compiling collections under
`-Ycheck:jvm` from 1521 to 26.
namin pushed a commit that referenced this pull request Sep 7, 2014
Swathes of important logic are duplicated between `findMember`
and `findMembers` after they separated on grounds of irreconcilable
differences about how fast they should run:

    d905558 Variation scala#10 to optimze findMember
    fcb0c01 Attempt scala#9 to opimize findMember.
    71d2ceb Attempt scala#8 to opimize findMember.
    77e5692 Attempty scala#7 to optimize findMember
    275115e Fixing problem that caused fingerprints to fail in
    e94252e Attemmpt scala#6 to optimize findMember
    73e61b8 Attempt #5 to optimize findMember.
    04f0b65 Attempt #4 to optimize findMember
    0e3c70f Attempt #3 to optimize findMember
    41f4497 Attempt #2 to optimize findMember
    1a73aa0 Attempt #1 to optimize findMember

This didn't actually bear fruit, and the intervening years have
seen the implementations drift.

Now is the time to reunite them under the banner of `FindMemberBase`.

Each has a separate subclass to customise the behaviour. This is
primarily used by `findMember` to cache member types and to assemble
the resulting list of symbols in an low-allocation manner.

While there I have introduced some polymorphic calls, the call sites
are only bi-morphic, and our typical pattern of compilation involves
far more `findMember` calls, so I expect that JIT will keep the
virtual call cost to an absolute minimum.

Test results have been updated now that `findMembers` correctly
excludes constructors and doesn't inherit privates.

Coming up next: we can actually fix SI-7475!
namin pushed a commit that referenced this pull request Sep 7, 2014
As per discussion at https://groups.google.com/forum/#!topic/scala-internals/nf_ooEBn6-k,
this commit introduces the new c.enclosingOwner API that is going to serve
two purposes: 1) provide a better controlled alternative to c.enclosingTree,
2) enable low-level tinkering with owner chains without having to cast
to compiler internals.

This solution is not ideal, because: 1) symbols are much more than
I would like to expose about enclosing lexical contexts (after the
aforementioned discussion I’m no longer completely sure whether exposing
nothing is the right thing to do, but exposing symbol completers is definitely
something that should be avoided), 2) we shouldn’t have to do that
low-level stuff in the first place.

However, let’s face the facts. This change represents both an improvement
over the state of the art wrt #1 and a long-awaited capability wrt #2.
I think this pretty much warrants its place in trunk in the spirit of
gradual, evolutionary development of reflection API.
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.

2 participants