-
Notifications
You must be signed in to change notification settings - Fork 327
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
Atom constructors can be private #9692
Conversation
033cd27
to
9750ef8
Compare
bb05165
to
85dca02
Compare
box syntax::tree::Variant::ConstructorDefinition(_) => | ||
syntax::Tree::private(keyword, Some(new_body)), | ||
_ => syntax::Tree::private(keyword, Some(body)) | ||
.with_error("Unsupported private body."), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a user-facing error--it should explain why the syntax is invalid to a user with no knowledge of the parser internals
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.with_error("Unsupported private body."), | |
.with_error("Unsupported private entity."), |
Is this better? Or do you advice to print the whole body content with something like body.code
? Note that body
is of type Tree<'{error}>
here.
match body_opt { | ||
Some(body) => { | ||
let body_ = body.clone(); | ||
let new_body = to_body_statement(body_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this test would fail: expect_invalid_node("private ConstructorOutsideType")
. Whether to_body_statement
is applied must depend on whether the expression is in the top level of a type definition, not the expression's content.
The right solution here is a bit complex because when private_keyword
is called, we don't know yet if the private
invocation occurred in the context of a type-definition body, so we can't tell yet whether the inner expression should be interpreted as a type body statement (and potentially a constructor definition).
What we could do is:
- If the usage of the keyword is not valid in the default (expression) context, wrap it in an
Invalid
node (i.e.with_error("The 'private' keyword cannot be applied to any expression outside of a type definition.")
). - In
to_body_statement
, recognize(Invalid (Private ...))
, discard the outerInvalid
, apply theto_body_statement
transformation to the body of theprivate
, and then check whether it's valid in context, emitting a new error if it isn't a constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this test would fail:
expect_invalid_node("private ConstructorOutsideType")
. Whether to_body_statement is applied must depend on whether the expression is in the top level of a type definition, not the expression's content.
@kazcw Yes, it fails. I have added that test in 395544f.
Your proposed solution would work for private constructors. But in the near future, we would like to support private methods as well. Not only methods in types, but also static methods in top scope in a module. Any suggestions how to support the private constructor and be able to parse also private top-scope method in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expression_to_statement
(where method definitions are recognized) would need a clause analogous to the new logic in to_body_statement
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refactored it, pushed @ 4a11104
@JaroslavTulach Even with There is no |
# Conflicts: # CHANGELOG.md
# Base_Tests import stuff from Helpers sibling project. So we need this property here. | ||
prefer-local-libraries: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
# Note that pattern matching on project-private constructor from a different project | ||
# is a compilation error. So we can only test it for the same project. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice comment. We could leave a link to a corresponding test in the runtime-integration-tests
that tests the compilation error case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Mixing public and private constructor is a semantic error, not a syntax error. | ||
// So parsing should be fine. | ||
parseTest( | ||
""" | ||
type My_Type | ||
private Ctor_1 a b | ||
Ctor_2 c d | ||
"""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate the comment explaining the intention here 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checked the .enso
files and tests checking the overall semantics - all looks good to me
Add support for private methods. Most of the changes are in parser and compiler. The runtime checking of private functions was already present since #9692 # Important Notes - Only top-level methods can be declared `private`. - private method cannot be called from different project - private method cannot be accessed from polyglot code (private method does not exist for polyglot code)
Debugger shows only fields of the current atom constructor: (internal members shown in gray, "public" members shown in bold purple) ![image](https://github.com/user-attachments/assets/21815296-c8aa-4ea2-ae7b-6feac78a221f) (Note that `static_method` is not displayed as a member of `My_Type` - not in scope of this PR) # Important Notes The *interop* contract for `Atom` is changed as follows: - Members are all methods and fields of the current constructor. - All methods are internal members. - If the constructor is project-private, fields are internal members. - All the members are both readable, and invocable. - Fields are field getters, that is, they are just methods. - Fields are not invocable - Constructors and static methods are **not** members of an atom. They should be members of the type. - Note that methods used to be atom members before #9692
Closes #8836
Pull Request Description
Atom constructors can be declared as
private
(project-private). project-private constructors can be called only from the same project. See theencapsulation.md
docs for more info.Important Notes
private
keyword. It now accepts an atom constructors as optional body. Private methods are considered a syntactical error for now.Function
andFunctionSchema
andAtomConstructor
data. No need to fiddle with truffle's frames.Standard.Base.Errors.Common.Private_Access
payload is thrown.Runtime private checks are implemented in such a way, that it should be easy to implement private methods in the future. For private methods, only parser modifications should be necessary.
Checklist
Please ensure that the following checklist has been satisfied before submitting the PR:
Scala,
Java