Skip to content

Check patterns for validity before putting them into pattern ambient modules #875

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 4 commits into from
May 22, 2025

Conversation

andrewbranch
Copy link
Member

@andrewbranch andrewbranch commented May 16, 2025

Fixes #870

Global augmentations are stored as pattern ambient modules with zeroed patterns. Invalid global augmentations were falling through binder cases and getting put into pattern ambient modules, when they should have been skipped.

Verified

This commit was signed with the committer’s verified signature. The key has expired.
andrewbranch Andrew Branch
@Copilot Copilot AI review requested due to automatic review settings May 16, 2025 20:51
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR improves pattern matching by ensuring that only valid patterns are evaluated when searching for the best match.

  • Added a check to skip processing of invalid patterns.

@@ -43,6 +43,9 @@ func FindBestPatternMatch[T any](values []T, getPattern func(v T) Pattern, candi
longestMatchPrefixLength := -1
for _, value := range values {
pattern := getPattern(value)
if !pattern.IsValid() {
Copy link
Preview

Copilot AI May 16, 2025

Choose a reason for hiding this comment

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

Consider adding a log statement or comment to explain why the invalid pattern is silently skipped to assist future debugging and ensure clarity of intent.

Suggested change
if !pattern.IsValid() {
if !pattern.IsValid() {
log.Printf("Skipping invalid pattern: %+v", pattern)

Copilot uses AI. Check for mistakes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Is it just me or are these getting worse and worse

Copy link
Member

Choose a reason for hiding this comment

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

It's not just you, they're awful now

Copy link
Member

Choose a reason for hiding this comment

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

This is one way to do this which I'm not opposed to, but

  1. I would prefer nobody ever match against an invalid pattern to begin with, which leads to
  2. why is declare global landing in the list of patterns anyway? That should be fixed in the binder.

Copy link
Member

@DanielRosenwasser DanielRosenwasser May 16, 2025

Choose a reason for hiding this comment

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

I guess you mentioned

Global augmentations are stored as pattern ambient modules with zeroed patterns.

Was this always how it worked in Strada? Why is it done this way?

Copy link
Member Author

Choose a reason for hiding this comment

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

I was also surprised and thought that might be a bug, but this is how it's designed in Strada. Not a bug.

Copy link
Member Author

Choose a reason for hiding this comment

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

Correction: these conditions happen only under an error, where a declare global occurs in a script file. I misread the Strada binder code that handles this; it does omit it from the array. IOW you're right, my bad ❤️

Copy link
Member

@DanielRosenwasser DanielRosenwasser left a comment

Choose a reason for hiding this comment

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

Needs a test case.

@@ -43,6 +43,9 @@ func FindBestPatternMatch[T any](values []T, getPattern func(v T) Pattern, candi
longestMatchPrefixLength := -1
for _, value := range values {
pattern := getPattern(value)
if !pattern.IsValid() {
Copy link
Member

Choose a reason for hiding this comment

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

This is one way to do this which I'm not opposed to, but

  1. I would prefer nobody ever match against an invalid pattern to begin with, which leads to
  2. why is declare global landing in the list of patterns anyway? That should be fixed in the binder.

@andrewbranch andrewbranch changed the title Check patterns for validity before matching against them Check patterns for validity before putting them into pattern ambient modules May 16, 2025

Verified

This commit was signed with the committer’s verified signature. The key has expired.
andrewbranch Andrew Branch
@andrewbranch andrewbranch enabled auto-merge May 16, 2025 21:53
@@ -806,7 +806,7 @@ func (b *Binder) bindModuleDeclaration(node *ast.Node) {
}
}
symbol := b.declareSymbolAndAddToSymbolTable(node, ast.SymbolFlagsValueModule, ast.SymbolFlagsValueModuleExcludes)
if pattern.StarIndex >= 0 {
if pattern.IsValid() && pattern.StarIndex >= 0 {
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer if we switched to something like

if pattern := core.TryParsePattern(...); pattern.IsValid() {
  if pattern.StarIndex >= 0 {
    b.file.PatternAmbientModules = append(b.file.PatternAmbientModules, &ast.PatternAmbientModule{Pattern: pattern, Symbol: symbol})
  }
} else {
  b.errorOnFirstToken(name, diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, name.AsStringLiteral().Text)
}

Copy link
Member

Choose a reason for hiding this comment

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

(I can't make the suggestion to above lines, I'm sorry)

Copy link
Member Author

Choose a reason for hiding this comment

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

That code isn't correct, though. pattern can be invalid because it contained two stars or because it's the zero struct. The latter case occurs when we don't have a string literal to try to parse with. So that suggestion doesn't work both because we have no argument to pass to TryParsePattern and because the error issued is only valid for the double star case.

Copy link
Member

@DanielRosenwasser DanielRosenwasser May 16, 2025

Choose a reason for hiding this comment

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

I think my intent was to only do this work within if ast.IsStringLiteral(name). Sorry I didn't make that clearer.

Copy link
Member

Choose a reason for hiding this comment

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

andrewbranch#1 is what I had in mind.

DanielRosenwasser and others added 2 commits May 21, 2025 11:11

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Only create and track possible patterns when dealing with string literals.
@andrewbranch andrewbranch added this pull request to the merge queue May 22, 2025
Merged via the queue into microsoft:main with commit 5c0668a May 22, 2025
23 checks passed
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.

Runtime error compiling expo
3 participants