Skip to content

Refactor: Make FieldName a composite of ClassName and SimpleFieldName. #4946

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

Merged
merged 1 commit into from
Feb 17, 2024

Conversation

sjrd
Copy link
Member

@sjrd sjrd commented Feb 17, 2024

Previously, FieldName only represented the simple name of a field. It was complemented everywhere with the enclosing ClassName, for namespacing purposes.

We now make FieldName a composite, like MethodName. It contains a ClassName and a SimpleFieldName. Structurally, SimpleFieldName is the same as the old FieldName.

This removes the need to pass additional, out-of-band ClassNames everywhere a FieldName or FieldIdent was used.

In addition to the readability improvements, this might improve performance. We previously often had to create (temporary) pairs of (ClassName, FieldName) as keys of maps. Now, we can directly use the FieldNames instead.

While the IR names, types and trees are significantly impacted by this change, the .sjsir format is unchanged.

@sjrd sjrd requested a review from gzm0 February 17, 2024 10:34
* (And no, this is not dead code.)
*/
val recordField = recordType.findField(field.name.simpleName)
val sel = RecordSelect(newQual, SimpleFieldIdent(recordField.name))(recordField.tpe)
Copy link
Member Author

Choose a reason for hiding this comment

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

This snippet is worth paying particular attention to. The change does not alter the logic AFAICT, but it does highlight that there is/was something fishy going on.

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like records only use simple field names. Maybe this will blow up:

class A {
  private var x: Int
  def foo = x
}

@inline
class B extends A {
  private var x: String
}

new B().foo

Copy link
Contributor

Choose a reason for hiding this comment

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

I have checked this, and it seems to work fine. What I've tested:

class A {
  private var x: Int = 1
  def foo = x
}

@inline
class B extends A {
  private var x: String = "f"
  def bar = x
}

object HelloWorld {
  @noinline
  def p(x: Any) = println(x)

  def main(args: Array[String]): Unit = {
    val b = new B()

    p(b.foo)
    p(b.bar)
  }
}

Relevant generated code:

$c_Lhelloworld_HelloWorld$.prototype.main__AT__V = (function(args) {
  var x = 0;
  var x$1 = null;
  x = 1;
  x$1 = "f";
  this.p__O__V(x);
  this.p__O__V(x$1);
});

Copy link
Member Author

Choose a reason for hiding this comment

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

Weird. Perhaps that specific example does not run into that particular code path.

Copy link
Contributor

@gzm0 gzm0 left a comment

Choose a reason for hiding this comment

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

NICE! Just some minor stuff.

@@ -1738,9 +1754,28 @@ object Serializers {
LabelIdent(readLabelName())
}

def readSimpleFieldIdent(): SimpleFieldIdent = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Unused? Seems like we do not actually ever read records :P

* (And no, this is not dead code.)
*/
val recordField = recordType.findField(field.name.simpleName)
val sel = RecordSelect(newQual, SimpleFieldIdent(recordField.name))(recordField.tpe)
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like records only use simple field names. Maybe this will blow up:

class A {
  private var x: Int
  def foo = x
}

@inline
class B extends A {
  private var x: String
}

new B().foo

genFieldNameCache.getOrElseUpdate(name, {
genName(name.className) + "__f_" + genName(name.simpleName)
})
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I would not cache this for now, to avoid changing performance behavior. (Also see comments RE duplicate caching of simple field names).

Previously, `FieldName` only represented the *simple* name of a
field. It was complemented everywhere with the enclosing
`ClassName`, for namespacing purposes.

We now make `FieldName` a composite, like `MethodName`. It contains
a `ClassName` and a `SimpleFieldName`. Structurally,
`SimpleFieldName` is the same as the old `FieldName`.

This removes the need to pass additional, out-of-band `ClassName`s
everywhere a `FieldName` or `FieldIdent` was used.

In addition to the readability improvements, this might improve
performance. We previously often had to create (temporary) pairs of
`(ClassName, FieldName)` as keys of maps. Now, we can directly use
the `FieldName`s instead.

While the IR names, types and trees are significantly impacted by
this change, the `.sjsir` format is unchanged.
@sjrd sjrd force-pushed the composite-field-name branch from 61302e8 to 723663b Compare February 17, 2024 14:09
@sjrd sjrd requested a review from gzm0 February 17, 2024 14:09
@gzm0
Copy link
Contributor

gzm0 commented Feb 17, 2024

@sjrd I'll let you merge this, so you can sequence with #4942 as you see fit.

@sjrd sjrd merged commit c887d78 into scala-js:main Feb 17, 2024
@sjrd sjrd deleted the composite-field-name branch February 17, 2024 15:51
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