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

Re-design Env of the global object init checker #24107

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

Conversation

Copy link
Contributor

@EnzeXing EnzeXing commented Sep 29, 2025

When the global object init checker models lazy fields and by-name parameters, initially it creates an environment for each symbol of the lazy field/by-name parameter. For by-name parameters, the environment includes all the possible environments that pass to the parameter as outer environments. This PR modifies the design of environments to take the tree to evaluate as the argument. Therefore, the same of argument tree passed to a by-name parameter will share the same environment, and there will be multiple environments for the same by-name parameter. This facilitates the process of finding local variables in the argument tree. Now the process of evaluating by-name args in multiple-by-name.scala will behave similarly to evaluating closure arguments in multiple-func-arg.scala

(using State.Data, EnvMap.EnvMapMutableData, Trace): EnvRef =
assert((sym.is(Flags.Param) && sym.info.isInstanceOf[ExprType]) || sym.is(Flags.Lazy));
_of(Map.empty, tree, thisV, outerEnv)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is OK, but is there a rationale for the inconsistency that we use the rhs as the tree to identify a lazy val but the overall DefDef as the tree to identify a method (as opposed to the rhs of the method)?

If there is a rationale, it would be good to record it in a comment.

Copy link
Contributor Author

@EnzeXing EnzeXing Oct 2, 2025

Choose a reason for hiding this comment

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

Documented the rationale. We must use the overall DefDef as the tree to identify a method (as opposed to the rhs of the method) because resolveEnvByMethod looks for the symbol of the DefDef to see it if matches the target method

ref.valValue(target)
else if target.hasSource then
val rhs = target.defTree.asInstanceOf[ValDef].rhs
given Scope = Env.ofByName(target, rhs, ref, Env.NoEnv)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is the outerEnv NoEnv? Can't the rhs of a lazy val refer to things from the enclosing scope of its definition site?

Copy link
Contributor Author

@EnzeXing EnzeXing Oct 1, 2025

Choose a reason for hiding this comment

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

For lazy fields, their outer scope is a template and they can refer to other fields. However, currently we do not create environments that encapsulate states of instances, so the outerEnv is NoEnv for lazy fields. The values of other fields can be found by searching through thisV instead, and thisV is an InstanceRef with its fields and outer environments.

Another possible design is to store all outer environments as a chain in EnvMap and bypasses the InstanceRef, or even creates environments for instantiation. Do you prefer any of these designs? Maybe we can modify it in another PR

Copy link
Contributor

@olhotak olhotak Oct 2, 2025

Choose a reason for hiding this comment

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

OK, that makes sense. Thanks for the explanation. We can keep the current design.

val byNameEnv = scope match {
case ref: Ref => Env.ofByName(sym, thisV, Env.NoEnv)
case env: Env.EnvRef => Env.ofByName(sym, thisV, Env.EnvSet(Set(env)))
case ref: Ref => Env.ofByName(sym, code, thisV, Env.NoEnv)// for by-name arguments of constructors
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above: why NoEnv?

case class EnvRef(tree: Tree, owner: ClassSymbol)(using Trace) extends Scope:
def show(using Context) =
"meth: " + meth.show + "\n" +
"tree: " + tree.show + "\n" +
Copy link
Contributor

@liufengyun liufengyun Sep 30, 2025

Choose a reason for hiding this comment

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

The document for the class EnvRef is outdated.

Copy link
Contributor

@liufengyun liufengyun Sep 30, 2025

Choose a reason for hiding this comment

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

Will there a problem with equality? The tree will have structural equality, while previously the symbol has reference equality.

Copy link
Contributor Author

@EnzeXing EnzeXing Oct 1, 2025

Choose a reason for hiding this comment

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

The document for the class EnvRef is outdated.

Updated the document

Copy link
Contributor Author

@EnzeXing EnzeXing Oct 1, 2025

Choose a reason for hiding this comment

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

Will there a problem with equality? The tree will have structural equality, while previously the symbol has reference equality.

Defined the equals method, which checks reference equality of the trees

liufengyun reacted with thumbs up emoji
@EnzeXing EnzeXing force-pushed the fix-global-init-checker-resolve-env branch from 54205cf to 480a6d5 Compare October 1, 2025 18:41
Copy link
Contributor

@liufengyun liufengyun left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@olhotak olhotak left a comment

Choose a reason for hiding this comment

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

LGTM now.

@EnzeXing EnzeXing force-pushed the fix-global-init-checker-resolve-env branch from 480a6d5 to 98d2ed5 Compare October 2, 2025 13:14
@olhotak olhotak merged commit cdcc5c1 into scala:main Oct 2, 2025
49 checks passed
@olhotak olhotak deleted the fix-global-init-checker-resolve-env branch October 2, 2025 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Reviewers

@liufengyun liufengyun liufengyun approved these changes

@olhotak olhotak olhotak approved these changes

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

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /