Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Fix ClassCastException in SAM conversion with call-by-name argument [ci: last-only]#10830

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
som-snytt wants to merge4 commits intoscala:2.13.x
base:2.13.x
Choose a base branch
Loading
fromsom-snytt:issue/11237-CCE-value-class-SAM

Conversation

som-snytt
Copy link
Contributor

@som-snyttsom-snytt commentedAug 9, 2024
edited
Loading

Follow lrytz advice to consult symbol of fun tree (for fidelity to cbn). It's just used to notice that an arg needsnoApply between transforms. (The symbol yields cbn, the tree yields not cbn.) The full advice was to also usefun.symbol.info for varargs (stay tuned). The two sets for tracking "pass-thru by-name args" and "unwrapped by-name arg in() => arg" are combined, which may work after all.

Fixesscala/bug#11237

@scala-jenkinsscala-jenkins added this to the2.13.16 milestoneAug 9, 2024
@som-snyttsom-snytt marked this pull request as ready for reviewAugust 10, 2024 01:32
@SethTisueSethTisue modified the milestones:2.13.16,2.13.15Aug 13, 2024
@@ -242,7 +245,16 @@ abstract class UnCurry extends InfoTransform
val typedNewFun = localTyper.typedPos(fun.pos)(Block(liftedMethod :: Nil, super.transform(newFun)))
if (mustExpand) {
val Block(stats, expr : Function) = typedNewFun: @unchecked
treeCopy.Block(typedNewFun, stats, gen.expandFunction(localTyper)(expr, inConstructorFlag))
Copy link
Member

Choose a reason for hiding this comment

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

Spent too much time on understanding this thing... comparing with

  def f(x: => Int) = 0  def g(x: => Int) = f(x)

here it's notnoApply that is in the works, but thex tree is added tobyNameArgs.

I was wondering why it doesn't work here.

The compiler first creates((x1: Box, x2: () => Box) => $anonfun$run(x1, x2)), runssuper.transform on it, and then translates that into the anonymous class withdef append(f1: Box, f2: () => Box): Box = $anonfun$run(f1, f2.apply()).

The.apply() is the bug. The issue is thatbyNameArgs no longer works on the second transformation.

https://github.com/scala/scala/blob/v2.13.14/src/compiler/scala/tools/nsc/transform/UnCurry.scala#L499-L501

because at the second pass,fn.tpe already has the post-uncurry type, I guess from here

https://github.com/scala/scala/blob/v2.13.14/src/compiler/scala/tools/nsc/transform/UnCurry.scala#L557.

sofnParams no longer has by name=> Box, but() => Box. Then thef2 argument tree is not added tobyNameArgs, and theapply is added.

Your fix looks fine, I was just not 100% it would only ever trigger in that case we are looking at, or if it might cause other changes. So I went into the rabbit hole.

Maybe you have more thoughts..

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Sorry, I ought to have written it up. I spent a day to understand LL220, and wasn't confident in the desired behavior until I saw that dotty does the same thing (that is, the same result as this PR).

I think I had a different approach but finally did LL250 when I ran out of patience. This looks too brute-force or ad-hoc to me now. Maybe it seemed natural after looking at the trees for hours.

I remember wondering why L223 doesn't useattachments.contains, and assumed I would make another pass here, but didn't want to spend a half-day on subtleties about attachments. (contains does not use retronym's hand-rolled set function.)

At a minimum, I'll respool and document.

Copy link
Member

@lrytzlrytzAug 21, 2024
edited
Loading

Choose a reason for hiding this comment

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

This would be the right fix I thinkhttps://github.com/scala/scala/compare/2.13.x...lrytz:scala:pr10830?expand=1

But it needs to be fixed for multiple param lists,Apply(Apply(f), args0), args1) we need to get the second params.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I'll make some time now for the more thoughts you asked for.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

"I spent too much time" etc. I think my previous idea was to pass a flag to say "this is just a forwarder", but today I noticed that you can detect it because the forwarder has(x: () => T) => R instead of(x: => T) => R. The method param and the function param happen to be mismatched. More precisely, thevparam.tpt is a function type, while thesymbol.info is cbn. I exploit that to tag references withPreserveArg attachment. (That could be improved to do only cbn args, but I think for a forwarder that is always the case.)

Today I was looking at the change inTreeGen, which I previously avoided. I looked again at howbyNameArgs is used and it's still not clear to me. Maybe if I take a quick power nap first.

Copy link
Member

Choose a reason for hiding this comment

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

I think the current logic in UnCurry is fine and we don't need anything specific for this bug.

The underlying issue is that thecheckisByNameParamType(param.info) tests aparam of aMethodType that went through theuncurry type map, which replaces by-name params (DesugaredParameterType).

If we get theparam symbol from the method symbol (and not from the AST), then it has a full type history and we see (during uncurry) that it's by-name. And it cleans up the thing explained in the comment ("Read the param symbols beforetransform(fn)...").

@som-snyttsom-snytt changed the titleAlways just forward args in function expansionAlways just forward args in function expansion [ci: last-only]Aug 20, 2024
@som-snyttsom-snyttforce-pushed theissue/11237-CCE-value-class-SAM branch 3 times, most recently from88d0d02 to9cc281eCompareAugust 22, 2024 00:16
@som-snyttsom-snytt reopened thisOct 31, 2024
@som-snyttsom-snyttforce-pushed theissue/11237-CCE-value-class-SAM branch from9cc281e toadea02cCompareOctober 31, 2024 21:38
@SethTisue
Copy link
Member

@som-snytt is this ready for review?

@SethTisueSethTisue changed the titleAlways just forward args in function expansion [ci: last-only]FixClassCastException on call to trait method with call-by-name argument, if implemented as SAMNov 6, 2024
@som-snytt
Copy link
ContributorAuthor

change title toFix CCE on CBN arg if SAM.

I'll redraft to review the summertime review.

@som-snyttsom-snytt marked this pull request as draftNovember 6, 2024 20:05
@SethTisueSethTisue modified the milestones:2.13.16,2.13.17Dec 12, 2024
@som-snyttsom-snyttforce-pushed theissue/11237-CCE-value-class-SAM branch 2 times, most recently frombc2da58 toc17d9ccCompareJune 4, 2025 04:12
@som-snytt
Copy link
ContributorAuthor

The current tweak avoids the moving parts by just intervening after the "expansion" of the function into the sam class that just forwards to a method with the function body for a rhs. The forwarding expression should never apply any by-name args, so for simplicity all of the args are added tonoApply.

@som-snyttsom-snytt marked this pull request as ready for reviewJune 4, 2025 04:19
body.last match {
case dd: DefDef =>
treeInfo.dissectApplied(dd.rhs).argss match {
case args :: _ => args.foreach(noApply.addOne)
Copy link
Member

Choose a reason for hiding this comment

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

could we put thenoApply tag directly when the trees are created ingen.expandFunction, by makingnoApply a tree attachment?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I think that was the previous version? but I'll look again with so-called fresh eyes.

@som-snyttsom-snyttforce-pushed theissue/11237-CCE-value-class-SAM branch fromc17d9cc to7a77a6aCompareJune 21, 2025 07:50
@som-snyttsom-snytt changed the titleFixClassCastException on call to trait method with call-by-name argument, if implemented as SAMFixClassCastException on call to trait method with call-by-name argument, if implemented as SAM [ci: last-only]Jun 21, 2025
@som-snyttsom-snyttforce-pushed theissue/11237-CCE-value-class-SAM branch from7a77a6a to7580983CompareJune 21, 2025 07:51
@som-snyttsom-snytt changed the titleFixClassCastException on call to trait method with call-by-name argument, if implemented as SAM [ci: last-only]Fix ClassCastException in SAM conversion with call-by-name argument [ci: last-only]Jun 21, 2025
@som-snyttsom-snytt marked this pull request as draftJune 21, 2025 14:58
@som-snyttsom-snyttforce-pushed theissue/11237-CCE-value-class-SAM branch from7580983 tofb3461aCompareJune 21, 2025 15:12
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@lrytzlrytzlrytz left review comments

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
2.13.17
Development

Successfully merging this pull request may close these issues.

ClassCastException when calling a trait method with call-by-name argument if implemented as single abstract method
4 participants
@som-snytt@SethTisue@lrytz@scala-jenkins

[8]ページ先頭

©2009-2025 Movatter.jp