Skip to content
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

Allow two type parameter sections in extension methods. #10950

Closed
wants to merge 22 commits into from

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Dec 29, 2020

We now allow extension methods to be written with type parameter clauses after extension and/or after def. This allows
extension methods to be expressed more naturally, e.g.

   trait Functor[F[_]]:
      extension [A](x: F[A]) def map [B](f: A => B): F[B]

This required quite a lot of changes to internal data structures. Notably, DefDefs take one combined paramss field that
contains both type and value parameters.

For the moment only extension methods can have two type parameter lists. We will most likely lift soon the syntactic restriction that normal methods can only have one type parameter list which must come first. Technically, it would only require a small change in the parser. But we should sort out some questions first before we do this. E.g.

  • should we support curried type parameters? There might still be some residual bugs related to this that would need to be sorted out.
  • should we support partial type applications of functions with curried type parameters? On the one hand, that's the whole point of having curried type parameters in the first place. On the other hand, we need to be aware that this will create a big push to currify libraries in order to allow for some selective type arguments to be inferred. Is that what we recommend? Maybe we should also look at alternatives like named type arguments at the same time?

That's why I recommend that the change to extension methods goes in for RC-1, but the other changes should come after 3.0.

Todos:

  • Sort out the test and community build problems which seem to stem from classpath confusion
  • Update Tasty reflect to allow for multiple type parameters as well, mirroring what the compiler does

@odersky
Copy link
Contributor Author

odersky commented Jan 1, 2021

@nicolasstucki I need your help to push this over the finish line.

The root problem is the asExprOf definition in quotes. Its type parameter [X] needs to go from the extension to the method itself. I did that in 11122ed with non-bootstrapped and bootstrapped versions of Quotes.scala and QuotesImpl.scala. This works, except that macro tests are still failing because they see the non-bootstrapped version of Quotes.scala. Likewise, the community build is failing for the same reason.

Can you try to sort these things out and get everything to green? I believe this is the most important thing to do for 3.0RC1. I see now what a mess the previous restriction on type parameters of extension methods created. If the current state makes it into RC-1, it would be super-hard to change it later.

I disabled the macro tests in 17e693b, so maybe start by reverting that commit and observe what fails.

@odersky
Copy link
Contributor Author

odersky commented Jan 1, 2021

Here's the root problem of all the failing tests:

-- Error: /__w/dotty/dotty/community-build/src/scala/dotty/communitybuild/FieldsImpl.scala:16:62 
Error:  16 |    val selects = symbols.map(Select(projectsTree, _).asExprOf[T])
Error:     |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error:     |method (using x$1: quoted.Type[T]): quoted.Expr[T] does not take type parameters
Error:  -- Error: /__w/dotty/dotty/community-build/src/scala/dotty/communitybuild/projects.scala:620:45 
Error:  620 |def allProjects = projects.reflectedFields.of[CommunityProject].sortBy(_.project)
Error:      |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error:      |    Could not find class dotty.communitybuild.FieldsImpl$ in classpath
Error:      | This location contains code that was inlined from projects.scala:620
Error:      | This location contains code that was inlined from Fields.scala:6
Error:  two errors found
Error:  two errors found

It clearly gets the wrong version of asExprOf, i.e. the one that takes the type parameter after extension. That's the version in
src-non-bootstapped.

@nicolasstucki nicolasstucki self-assigned this Jan 1, 2021
@odersky
Copy link
Contributor Author

odersky commented Jan 1, 2021

Actually, I might have found a workaround in b4dd60b. So if it's just that we might be able to go ahead anyway. But it's still an issue that we seem to do some build steps on the wrong classpath.

EDIT: No, that fix is not sufficient. Now we get failures for sacalatest with asExprOf. It looks like the community build is run with the wrong classpath.

@odersky odersky changed the title Change internal datstructures to allow for multiple type param clauses Allow two type parameter sections in extension methods. Jan 1, 2021
@odersky odersky marked this pull request as ready for review January 1, 2021 12:19
@odersky odersky added this to the 3.0.0-RC1 milestone Jan 1, 2021
@odersky
Copy link
Contributor Author

odersky commented Jan 1, 2021

Rebased to latest master

@odersky
Copy link
Contributor Author

odersky commented Jan 2, 2021

test performance please

@dottybot
Copy link
Member

dottybot commented Jan 2, 2021

performance test scheduled: 1 job(s) in queue, 0 running.

@dottybot
Copy link
Member

dottybot commented Jan 2, 2021

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/10950/ to see the changes.

Benchmarks is based on merging with master (141bf9e)

Copy link
Collaborator

@julienrf julienrf left a comment

Choose a reason for hiding this comment

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

This is great work! I have minor questions about the specification.

(x: X) // <-- extensionParam
(using d: D) // <-- trailingUsing
def +:: (y: Y)(using e: E)(z: Z) // <-- otherParams
```
Copy link
Collaborator

Choose a reason for hiding this comment

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

How would such a method be called?

(y)(z) +:: x

?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would be (y +:: x)(z).

only if the method is referenced as a regular method:
```scala
map[Int](List(1, 2, 3))(_ + 1)
```
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we pass both type parameters? Int and String?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, map[Int](List(1, 2, 3))[String](_ + 1).

docs/docs/reference/contextual/extension-methods.md Outdated Show resolved Hide resolved
odersky added a commit to dotty-staging/dotty that referenced this pull request Jan 2, 2021
Formulate newExpr without recourse to IntegratedTypeArgs. Since with scala#10950
extension methods no lonnger require IntegratedTypeArgs either it means we will
be able to drop it altogether.
@odersky odersky mentioned this pull request Jan 2, 2021
@nicolasstucki
Copy link
Contributor

@nicolasstucki I need your help to push this over the finish line.

The root problem is the asExprOf definition in quotes. Its type parameter [X] needs to go from the extension to the method itself. I did that in 11122ed with non-bootstrapped and bootstrapped versions of Quotes.scala and QuotesImpl.scala. This works, except that macro tests are still failing because they see the non-bootstrapped version of Quotes.scala. Likewise, the community build is failing for the same reason.

Can you try to sort these things out and get everything to green? I believe this is the most important thing to do for 3.0RC1. I see now what a mess the previous restriction on type parameters of extension methods created. If the current state makes it into RC-1, it would be super-hard to change it later.

I disabled the macro tests in 17e693b, so maybe start by reverting that commit and observe what fails.

I added a commit with the fix and reenabled the tests. The issue is that there were two definitions of asExprOf and only one was updated.

@odersky
Copy link
Contributor Author

odersky commented Jan 4, 2021

@nicolasstucki Doh! I should have seen that! Instead I tried lots of other things...

@soronpo
Copy link
Contributor

soronpo commented Jan 4, 2021

That's why I recommend that the change to extension methods goes in for RC-1, but the other changes should come after 3.0.

I don't know the internals, but IMO, it's at least worthy verifying that TASTy supports the data structure now. The functionality can be added much later.

@odersky
Copy link
Contributor Author

odersky commented Jan 4, 2021

TASTy supports it already.

@odersky
Copy link
Contributor Author

odersky commented Jan 4, 2021

@nicolasstucki I think this is ready for review now.

@nicolasstucki
Copy link
Contributor

nicolasstucki commented Jan 5, 2021

@odersky This PR will need to be rebased on #10998 once that PR is merged. That PR is there to make sure we do not lose the history of Quotes.scala and IArray.scala when moved to src-bootstrapped.

Rebasing should be simple, just keep all the changes from this branch in the files of src-bootstrapped and keep the files from origin in src-non-bootstrapped.

@nicolasstucki
Copy link
Contributor

I can do the rebasing

odersky and others added 22 commits January 5, 2021 14:11
Leading using clauses now scope over both left and right parameter.
This is a first step towards passing reference trees for all parameters
together.
Using two different tags for empty parameter lists and parameter splits
leads to a more straightforward encoding.

Also: shift tags around to create more free slots for single element trees.
Macro tests seem to use the wrong version of Quotes (non-bootstrapped, where it should
be bootstrapped).
To do this, get rid of all uses of `decomposeCall`.
Add tests with dependencies from second type parameter clause to
first type parameter and extension parameter clauses.
Make overloading resulution work in the case where type parameters follow
value parameters.
@odersky
Copy link
Contributor Author

odersky commented Jan 6, 2021

I think we should concentrate to get #10940 in, which subsumes this PR.

@odersky
Copy link
Contributor Author

odersky commented Jan 6, 2021

Subsumed by #10940

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.

None yet

5 participants