8000 Fix #3953: mistyping when using PartialFunction with HKT alias by errikos · Pull Request #3960 · scala-js/scala-js · GitHub
[go: up one dir, main page]

Skip to content

Fix #3953: mistyping when using PartialFunction with HKT alias #3960

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

Closed
wants to merge 1 commit into from

Conversation

errikos
Copy link
Contributor
@errikos errikos commented Feb 12, 2020

The issue occurs due to a bug in scalac, where Defdef vparamss and the
respective symbol have inconsistent types. For more information, please
see: scala/bug#11884

This commit is a workaround for the aforementioned issue, until the latter
is fixed in the scala compiler.

It consists of a very dirty hack, where, after the IR Tree generation, we go
and patch the types of the locals to correspond to the types found in the
Defdef's symbol (which are the correct ones).

The issue occurs due to a bug in scalac, where Defdef vparamss and the
respective symbol have inconsistent types. For more information, please
see: scala/bug#11884
@errikos errikos requested a review from sjrd February 12, 2020 17:23
@sjrd
Copy link
Member
sjrd commented Feb 12, 2020

You should definitely add the reproduction from the issue as a test case. ;)

@gzm0
Copy link
Contributor
gzm0 commented Feb 12, 2020

Have we assessed the feasibility of fixing this in scalac proper? I'm not a fan of simply postprocessing practically everything we generate.

If this is really necessary, could we at least investigate a deeper integration that correctly translates an Ident from the start (in this case).

NB to reply to @errikos from #3960

Plus, the easiest way to do this is to patch the IR Tree after it has been generated, in order to avoid touching the generation process itself, which would probably introduce far more code changes.

IMHO this is the wrong way to look at it. We should not code in a way that it easy, but in a way that yields the easiest to understand and maintain result. The difficulty of the code and the review are secondary. A good end result is the primary goal.

From the little I can see, we can create a Map[Symbol, Symbol], put it in a scoped variable and use it when we translate an Ident. Wouldn't that work and be simpler?

@errikos
Copy link
Contributor Author
errikos commented Feb 12, 2020

IMHO this is the wrong way to look at it. We should not code in a way that it easy, but in a way that yields the easiest to understand and maintain result. The difficulty of the code and the review are secondary. A good end result is the primary goal.

Thanks for the feedback! I totally agree that this is far from the ideal way. That's why I said "easiest" instead of "better". But, it is the simplest one, since it only requires patching at a single code position and this is what I was going after, given that my familiarity with the Scala.js codebase is minimal.

From the little I can see, we can create a Map[Symbol, Symbol], put it in a scoped variable and use it when we translate an Ident. Wouldn't that work and be simpler?

I will look into this and see if it leads into a more elegant solution. As @sjrd said, ideally we would like that the bug is fixed in scalac.

Copy link
Member
@sjrd sjrd left a comment

Choose a reason for hiding this comment

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

I've left a few comments to improve the overall quality of this hack.

That said, I agree with @gzm0 that, before merging this in Scala.js, we should at least attempt a fix in scalac.

Comment on lines +1848 to +1850
val symParamTypes =
if (sym.paramss.isEmpty) Nil
else sym.paramss.head.map(p => toIRType(p.tpe))
Copy link
Member

Choose a reason for hiding this comment

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

I believe you can just use sym.tpe.params.map(p => toIRType(p.tpe)).

@@ -1906,6 +1921,38 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
newBody)(methodDef.optimizerHints, None)(methodDef.pos)
}

private def patchTypesOfLocals(methodDef: js.MethodDef,
patches: mutable.Map[LocalName, ir.Types.Type]) = {
Copy link
Member
8000

Choose a reason for hiding this comment

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

This should be an immutable Map. It's never mutated.

Copy link
Member

Choose a reason for hiding this comment

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

Also, it's usually better to explicitly specify the result type of a function that is a bit long, even when it is private. It helps the reader.

"symParams and vparams have different lengths")

val patchedParamTypes = collection.mutable.Map(
(params.map(encodeLocalSym(_).name) zip symParamTypes): _*)
Copy link
Member

Choose a reason for hiding this comment

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

You can use methodDefWithoutUselessVars.args instead of params here. That's better because we already have their LocalName, hence we don't need to re-encode the local syms.

Moreover, and more importantly, we should filter out the parameters for which the IR type is already correct (i.e., the (arg: js.ParamDef).ptpe == symParamType). If the resulting list is empty, which is the overwhelmingly common case, we should not call patchTypesOfLocals at all!

@sjrd
Copy link
Member
sjrd commented Jul 16, 2021

Superseded by #4533.

@sjrd sjrd closed this Jul 16, 2021
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.

3 participants
0