-
-
Notifications
You must be signed in to change notification settings - Fork 418
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
Disallow type parameter names shadowing other types. #1526
Conversation
@tokenrove Thanks for bringing the issue to our attention! We probably need to discuss and decide on a desired behaviour here. Because Pony disallows shadowing in many other cases where it may cause confusion/bugs, I'd argue that we should disallow a type parameter name from shadowing any type name in the current file scope (whether the type is in @sylvanc @SeanTAllen @Praetonus Thoughts? |
I agree on disallowing name shadowing from type parameters. |
The other upside is that if we disallow all shadowing by type parameter names we can also use the compiler error as an opportunity to provide a useful hint to the user who made the mistake and is probably confused about type parameters vs type arguments. |
601f6a2
to
235cc4f
Compare
When a type parameter is introduced which matches any of the simple UIF names, it causes any other such simple type to be recognized as a type parameter reference, which results in the compiler aborting. In the discussion on ponylang#1526, it was decided that all shadowing by type parameters should be prohibited. Hence, in this patch, if we're resolving a type param whose id is still nominal, we check the nearest module to see if that name is already defined.
I've updated this to check the enclosing module scope for the name of a type param during the Let me know if this is on the right track or if I should take a different approach. Suggestions for more test cases would be helpful, too. |
Oh, also, let me know if I should keep the |
I've removed the "needs discussion during sync" label, as I think the agreement between @Praetonus and I should be sufficient consensus to move forward. |
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.
Looks great, and I agree the names
pass is the right place to get this check done.
I just have a few small style comments.
@@ -178,6 +178,15 @@ static bool names_typeparam(pass_opt_t* opt, ast_t** astp, ast_t* def) | |||
return false; | |||
} | |||
|
|||
if (ast_id(ast) == TK_NOMINAL) { | |||
ast_t* module = ast_nearest(ast, TK_MODULE); | |||
if (module && ast_get(module, ast_name(id), 0)) { |
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.
Can you fix the style/formatting of both of these if
statements to match the surrounding code style?
Specifically, no space between the if
and the (
, and the {
should be on the next line.
It's not my favorite style for if
statements, but it's the style we've got 😉.
ast_t* module = ast_nearest(ast, TK_MODULE); | ||
if (module && ast_get(module, ast_name(id), 0)) { | ||
ast_error(opt->check.errors, def, | ||
"Type parameter shadows existing type"); |
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.
The code style for this error message should be just indented two spaces in from the previous line, as we do in the ast_error
in the code block above.
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.
How embarrassing. I even noted all the oddities (from my perspective) of the style and then promptly forgot to observe them when I revised my changes. Thanks for the heads up.
{ | ||
const char* src = | ||
"class A[I8]" | ||
"let b: U8 = 0"; |
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.
These two lines seem to have extra indentation. Please match the style of the test above, using two spaces for each new level of indentation.
It might be useful to add another test where the shadowed type name was declared in the same file. For example: class B
class A[B] |
When a type parameter is introduced which matches any of the simple UIF names, it causes any other such simple type to be recognized as a type parameter reference, which results in the compiler aborting. In the discussion on ponylang#1526, it was decided that all shadowing by type parameters should be prohibited. Hence, in this patch, if we're resolving a type param whose id is still nominal, we check the nearest module to see if that name is already defined.
235cc4f
to
4bec9ad
Compare
I noticed that there doesn't seem to be a consistent style in error messages, but there seemed to be more which started with a lowercase letter than uppercase, so I revised the message. The suggested test case is a great idea, but already gets caught in the Offhand, it's not a big deal, but it would be nice if there was a style lint and a suggested emacs setup for editing the C source. Maybe these exist and I missed them. |
Yes, I've noticed the varying style as well, and agree that we should clean them up to be consistent. We'd definitely be open to a PR that cleans up the error messages for consistency.
I don't deal a lot with automated style linting, as most projects I work heavily on have a style that's more subjective and difficult to automate for. For styles like that, I prefer to just work socially and pay attention to surrounding code to match style. However, the C source for this project does have a very mechanical style, so I would definitely be open to someone adding a automated style linting tool configuration (for the C source only, I think). As long as it doesn't add any required dependencies for building the project, I think it should be okay. Since I'm going to merge this PR, I'll open a ticket for the style linting question, mention you in it, and mark it for discussion on today's sync call to see if anyone is opposed to such an initiative. |
Thanks for your work on this! |
Thanks for your patience! |
(I'm opening this PR as is, but admittedly this is probably the wrong way to solve this, thus my explicit use of WIP in the commit message. If I can get some guidance on the right way to fix this, I'd be more than happy to contribute a suitable fix, including a more detailed commit message.)
So, this started with me trying to do something stupid (and getting a segfault, on the release compiler), but boiled down, this is sufficient to cause an assert with a debug compiler:
What seems to happen is that if the type parameter for
A
is any of the types named in_str_uif_types
inlibponyc/expr/literals.c
, when we then go to look upU8
(which can be any other type from that same set of builtin types) inuifset_simple_type()
, the structure of the AST we get back is not what we expect (it's become aTK_TYPEPARAMREF
thanks to the call tonames_nominal()
withintypes_builtin()
and friends). As a resultast_childidx(uif, 3)
returns NULL andast_setid()
aborts (or goes on to segfault, in release mode).I don't know enough about either Pony or the compiler to know what the correct behavior should be, but I imagine that having
I8
as a type parameter here should either be forbidden, or it should shadowI8
throughout this definition, and not affectuifset_simple_type()
at all. It seems like other parts of the compiler do the right thing, and the presence of literal type inference causes the snafu, since changing 0 toU8.min_value()
works fine.Advice would be appreciated, even "go read this part of the code".