Skip to content
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

iterator.repeat improvements and string.repeat #356

Merged
merged 5 commits into from
Sep 24, 2024

Conversation

irh
Copy link
Contributor

@irh irh commented Sep 24, 2024

This PR prevents a case where iterator.repeat could be easily misused.

For example:

[1, 2].repeat(3).to_list()

It would be reasonable to expect a result here of [[1, 2], [1, 2], [1, 2]], but instead it causes an infinite loop.

  • The runtime falls back to the iterator module when a matching item can't be found in list.
  • The list [1, 2] is passed to iterator.repeat as the instance for the call.
  • iterator.repeat is intended to be used as a standalone function and ignores the instance.
  • 3 is then treated as the value to repeat, without a count, producing an endless iterator.

The solution here is to have iterator.repeat check that it's being used as a standalone function. iterator.generate is less prone to misuse, but is now similarly restricted. The check is a bit hacky, it checks that the instance is either null or the iterator module, which means that repeat won't work if it's added to another module and then called there. A more flexible solution would involve reworking the module system, which isn't a problem for today.

The PR also adds a specialized version of repeat for strings, which seems useful enough to treat as a special case, e.g.

'abc'.repeat 3
# -> abcabcabc

Additionally, checking for standalone use of repeat exposed a flaw where temporary values were left around and ending up in the instance register for standalone calls, so some work has gone into improving the use of temporary registers in lookup chains, and in ensuring that the instance register is cleared when necessary.

@irh irh force-pushed the avoid-iterator-repeat-footgun branch from 8b469d3 to 27339fb Compare September 24, 2024 08:02
…tion

- Temporary registers are reused more effectively while moving through the
  chain's nodes.
- CallInstance has been added to ensure that the frame base is correctly
  initialized, in particular the frame base needs to be set to null when a
  standalone function is called.
- If the instance register is at the top of the register stack then it gets
  used directly as the frame base, avoiding an unnecessary copy.
This avoids the footgun of calling something like
`[1, 2, 3].repeat(5).to_list()`, expecting a repeated list.

Instead what happens is that the instance (i.e. [1, 2, 3]) is ignored and the
repeat count (5) is then interpreted as being the argument to repeat endlessly.
@irh irh force-pushed the avoid-iterator-repeat-footgun branch from 27339fb to 56f9bde Compare September 24, 2024 08:32
@irh irh merged commit a4e2e3b into main Sep 24, 2024
8 checks passed
@irh irh deleted the avoid-iterator-repeat-footgun branch September 24, 2024 08:37
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.

1 participant