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

Refactor dependent function refinement logic #18305

Conversation

nicolasstucki
Copy link
Contributor

@nicolasstucki nicolasstucki commented Jul 28, 2023

This fixes inconsistencies with refined dependent function types and poly functions representing methods with erased parameters.

This PR has many commits on purpose. These changes proved to be extremely fragile. Therefore it was decided that it would be better to do smaller incremental changes to be able to pinpoint any undetected regression in the future.

The first commits reflect the code to split the logic into base abstractions for function types. These aim to remove ad-hoc behavior of function-type extractors and homogenize them. Once this was done, we moved towards representing function types homogeneously using MethodTypes as their base representation. This representation is more robust as it forces us to consider dependent function types explicitly. Finally, some fixes were made where we did not handle function types correctly. Some todos are left where we could generalize to dependent function types, but this could go out of the bounds of the current spec for dependent function types (to be followed-up).

@nicolasstucki nicolasstucki force-pushed the refactor-dependent-refinemet-logic branch 7 times, most recently from 9504f3c to 1969f39 Compare August 3, 2023 08:03
@nicolasstucki nicolasstucki changed the title Refactor dependent refinement logic Refactor dependent function refinement logic Aug 3, 2023
@nicolasstucki nicolasstucki force-pushed the refactor-dependent-refinemet-logic branch 9 times, most recently from 934255f to a325ff7 Compare August 7, 2023 12:06
@nicolasstucki nicolasstucki marked this pull request as ready for review August 7, 2023 19:09
@nicolasstucki nicolasstucki requested a review from smarter August 7, 2023 19:10
@nicolasstucki
Copy link
Contributor Author

The current conflict is trivially fixable in a7f1966. I will rebase once I had some feedback on these changes.

Comment on lines +1119 to +1120
val methodType = if isContextual then ContextualMethodType else MethodType
Some(methodType(argTypes, resultType))
Copy link
Member

Choose a reason for hiding this comment

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

This is nice from a conceptual viewpoint, but I'm a bit worried about the performance impact of creating all these method types given that they are uncached types. Maybe the name of the extractor could make it clearer that there's a conversion, e.g. if we call it FromMethod (and we call have a corresponding apply to go in the other direction).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Followup in #18443

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree it's good to make the conversion explicit in the name. The performance aspects are probably OK since the alternative is usually to take the list of AppliedType arguments and split it into inits and last, which is also expensive.

* dependent refinements. Optionally returns a triple consisting of the argument
* types `As`, the result type `B` and a whether the type is an erased context function.
*/
object ContextFunctionType:
Copy link
Member

Choose a reason for hiding this comment

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

Isn't it still nice for convenience to keep an extractor just for context functions?

approxTp.dealias.stripPoly match
case defn.FunctionOf(mt)
if mt.isContextualMethod && (
mt.isResultDependent || // in this case `resType` is lying, gives us only the non-dependent upper bound
Copy link
Member

Choose a reason for hiding this comment

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

Hmm if we have an extractor that returns a MethodType I would really expect it to take dependencies into account properly

@nicolasstucki
Copy link
Contributor Author

Test performance please

nicolasstucki added a commit to dotty-staging/dotty that referenced this pull request Aug 17, 2023
This provides variant to `defn.FunctionOf` that only deals with proper
`FunctionN` and `ContextFunctionN` types. This avoids some overhead. A
difference between the two `unapply`s is that this one does not dealias
the type, it needs to be dealiased at call site.

Part of scala#18305
nicolasstucki added a commit that referenced this pull request Aug 21, 2023
This makes it possible to know for example that if we have a
`MethodType` and we use `derivedLambdaType` we get another `MethodType`.

Part of #18305
@nicolasstucki nicolasstucki force-pushed the refactor-dependent-refinemet-logic branch from 9eb04f0 to 18114f0 Compare August 22, 2023 12:58
odersky added a commit that referenced this pull request Aug 29, 2023
Make `isJava` by default `false` and remove `dropLast` argument.

Part of #18305. Note that the use of `toFunctionType` will increase, and
most will not be java functions.
odersky added a commit that referenced this pull request Aug 29, 2023
nicolasstucki added a commit to dotty-staging/dotty that referenced this pull request Aug 30, 2023
This provides variant to `defn.FunctionOf` that only deals with proper
`FunctionN` and `ContextFunctionN` types. This avoids some overhead. A
difference between the two `unapply`s is that this one does not dealias
the type, it needs to be dealiased at call site.

Part of scala#18305
@nicolasstucki nicolasstucki force-pushed the refactor-dependent-refinemet-logic branch from 18114f0 to 47eb542 Compare August 30, 2023 09:49
nicolasstucki added a commit that referenced this pull request Aug 31, 2023
The interpreter was dropping all arguments in the list if one of them
was erased. Now we filter out only the erased arguments.


Part of #18305
nicolasstucki added a commit that referenced this pull request Aug 31, 2023
nicolasstucki added a commit that referenced this pull request Nov 14, 2023
Add `FunctionTypeOfMethod` extractor that matches any kind of function
and return its method type.

We use this extractor instead of `ContextFunctionType` to all of
 * `ContextFunctionN[...]`
* `ContextFunctionN[...] { def apply(using ...): R }` where `R` might be
dependent on the parameters.
* `PolyFunction { def apply(using ...): R }` where `R` might be
dependent on the parameters. Currently this one would have at least one
erased parameter.

The naming of the extractor follows the idea in
#18305 (comment).
nicolasstucki added a commit that referenced this pull request Nov 14, 2023
This provides variant to `defn.FunctionOf` that only deals with proper
`FunctionN` and `ContextFunctionN` types. This avoids some overhead. A
difference between the two `unapply`s is that this one does not dealias
the type, it needs to be dealiased at call site.

Part of #18305
WojciechMazur added a commit that referenced this pull request Jun 24, 2024
This provides variant to `defn.FunctionOf` that only deals with proper
`FunctionN` and `ContextFunctionN` types. This avoids some overhead. A
difference between the two `unapply`s is that this one does not dealias
the type, it needs to be dealiased at call site.

Part of #18305

[Cherry-picked d78c157][modified]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants