-
-
Notifications
You must be signed in to change notification settings - Fork 431
Fix spurious 'can't reuse name' errors when a multi-file package has a syntax error #5147
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
base: main
Are you sure you want to change the base?
Changes from 3 commits
8f01b98
366324d
0d52bf0
59933c0
29bbb38
984e1a1
051b878
f731f0e
0ea00f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| ## Fix spurious 'can't reuse name' errors when a multi-file package has a syntax error | ||
|
|
||
| Fix [issue 4160](https://github.com/ponylang/ponyc/issues/4160) that contains | ||
| and example reproducing the problem. | ||
| When a package `use`d another package containing multiple `.pony` files, and | ||
| one of these files had a syntax error, the compiler output wrong and extra | ||
| error messages, particularly when the first code had multiple `for` loops | ||
| using the same loop variable. | ||
|
|
||
| The issue was caused by the compiler's package loading logic. When a package | ||
| containing multiple files was loaded, if one file had a syntax error, the | ||
| package was left in a partially-processed state. Subsequent attempts to use | ||
| or "catch up" that package to the current compiler pass would re-run passes | ||
| (like the scope pass) on the existing AST. Since the scope pass had already | ||
| partially populated the symbol tables, re-running it caused it to encounter | ||
| its own previously defined symbols and report them as illegal name reuses. | ||
|
|
||
| The fix sets `AST_FLAG_PRESERVE` on the package when `parse_files_in_dir` fails. | ||
| This stops future passes from visiting the broken package. | ||
|
|
||
| The compiler tests were adapted to support testing with a package containing | ||
| multiple source files. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1052,15 +1052,26 @@ ast_t* package_load(ast_t* from, const char* path, pass_opt_t* opt) | |
| return NULL; | ||
| } else if(magic->mapped_path != NULL) { | ||
| if(!parse_files_in_dir(package, magic->mapped_path, opt)) | ||
| { | ||
| // If source file parsing failed, don't run future passes on the | ||
| // partially-initialised package. | ||
| ast_setflag(package, AST_FLAG_PRESERVE); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use a brief comment here. Even just a pointer to the comment on the other branch below so someone reading this code path doesn't have to go hunting for why the flag is being set.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ping on this. |
||
| return NULL; | ||
| } | ||
| } else { | ||
| return NULL; | ||
| } | ||
| } | ||
| else | ||
| { | ||
| if(!parse_files_in_dir(package, full_path, opt)) | ||
| { | ||
| // If source file parsing failed, don't run future passes on the | ||
| // partially-initialised package, producing spurious errors in | ||
| // those files. | ||
| ast_setflag(package, AST_FLAG_PRESERVE); | ||
| return NULL; | ||
| } | ||
| } | ||
|
|
||
| if(ast_child(package) == NULL) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1446,3 +1446,30 @@ TEST_F(BadPonyTest, MatchArrayPatternWithBareIntegerLiterals) | |
| "couldn't find 'eq' in 'Array'", | ||
| "this pattern element doesn't support structural equality"); | ||
| } | ||
|
|
||
| TEST_F(BadPonyTest, SpuriousErrorMessageGeneration) | ||
| { | ||
| // From issue #4160 | ||
| // A parse error in one file of a package must not produce spurious | ||
| // "can't reuse name" errors in other files of the same package that | ||
| // reuse a loop variable name across consecutive for loops. | ||
| // The fixture package has two files: bad.pony (parse error) comes before | ||
| // good.pony (valid, with consecutive "for i" loops) alphabetically. | ||
| add_package_path("pkg", PONY_TEST_LIBPONYC_DIR "/fixtures/spurious-error-message-generation"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. im not a fan of adding fixtures to a testing style we are trying to move away from. @jemc what are your thoughts?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree about not adding this new external file fixture mechanism in this PR. These should be inlined, and if we wanted to discuss external file fixtures we could discuss adding them in an issue ticket outside the scope of this PR.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are the conclusions?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we are ok with dropping this test. we think it is the most preferable of the options here. |
||
| const char* src = | ||
| "use \"pkg\"\n" | ||
| "actor Main\n" | ||
| " new create(env: Env) =>\n" | ||
| " for i in Range(0, 3) do\n" | ||
| " None\n" | ||
| " end\n" | ||
| " for i in Range(0, 3) do\n" | ||
| " None\n" | ||
| " end"; | ||
|
|
||
| TEST_ERRORS_2(src, | ||
| "syntax error: unexpected token = after type, interface, trait, primitive," | ||
| " class or actor definition", | ||
| "can't load package 'pkg'"); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| // Intentional syntax error: = instead of => | ||
| class Bad | ||
| new create() = | ||
| None |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // Syntactically valid file in the same package as bad.pony. | ||
| // The loop variable 'i' is reused across consecutive for loops; before the | ||
| // fix for issue #4160, a parse error in bad.pony caused spurious | ||
| // "can't reuse name 'i'" errors here. | ||
| class Good | ||
| new create() => | ||
| let a: Array[U8] = Array[U8] | ||
| for i in a.values() do | ||
| None | ||
| end | ||
| for i in a.values() do | ||
| None | ||
| end | ||
| for i in a.values() do | ||
| None | ||
| end |
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.
paragraphs in release notes shouldn't have linebreaks. they should flow to fit the space they are in,