Skip to content

Local Variable Type Hints #7892

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 30 commits into from
Jul 1, 2025

Conversation

APickledWalrus
Copy link
Member

@APickledWalrus APickledWalrus commented May 23, 2025

Problem

Local variables are essentially accepted wherever they are used. This results in more potential mistakes and (some) strange syntax behavior that is hard to track. Detailed type information for variables helps in two cases:

1. Mismatched types

It's possible you use the wrong variable somewhere. Detailed type information can catch this and print a warning (or error). Consider:

set {_a} to 5
set {_b} to "some string"
... do stuff ...
set {_c} to {_a} in lowercase # oops i used the wrong variable

We can catch that {_a} in lowercase is likely to be invalid and alert the user.

2. Syntax accepting objects

Consider syntax like ExprArithmetic:

set {_a} to "some string"
set {_b} to 1 + {_a}

With detailed type information, we can now identify at parse time that this is an invalid operation, instead of failing at runtime and returning none.

Solution

With systems like ExecutionIntent and multiple return types, we are finally in a position to execute this system well. Type tracking for local variables has been implemented across syntax interacting with variables using a HintManager that is attached to the ParserInstance.

The testing script along with HintManager's documentation provide insight into how hints are managed.

As of now, I believe this system is accurate enough for type issues to be errors rather than warnings. However, there are still scenarios where type hints will fail:

loop x times:
  if ...:
    set {_x} to 10
  if ...:
    # will only see {_x} as a number
    set {_x} to x in lowercase
    # do some terminating statement idk
  if ...:
    set {_x} to "hello world"

That is, variables in loops whose types are changing across iterations may trigger false-positive errors (in rare cases hidden type changes could cause erroneous runtime failures). To work around this, it is possible to [un]suppress type hints (for a statement or block of code) using a new statement. We may also consider putting this behind an experiment as we continue to improve upon it (maybe whether it's an error?). Variables that cannot have hints and variables that do not have any hints act the same as they do now.

Variables have also been reworked here. When variables are passed to patterns request objects, the possible return types of the variable is simply an array of the known hints. Additionally, when variables are passed to patterns requesting some combination of types, the possible return types of the variable is the intersection of the hints and requested types.

I believe the system is accurate and stable, but further testing is needed. As a result, I have elected to put this behind an experiment. Additionally, it is possible to suppress type hints (in scripts where the experiment is enabled) for specific regions of code.

Change Explanations

  • Fixed an issue where the experimentRegistry (in Skript) was set to null too soon - it could be null even when more script code could run (consider on stop triggers)
  • Added getName to arguments. This is used for providing type hints for named command arguments.
  • Fixed an issue where EffReturn would return an incorrect ExecutionIntent for Functions. It needed to be using StopTrigger as the ReturnableTrigger is stopped in Functions when return is executed.
  • Added EntryNode as a possible return type for ExprNode. This is for ensuring type hints work properly for the syntax.
  • Added beforeChange runnable for loading sections into triggers. This was necessary for proper type hint implementation for these syntaxes. We need to be able to capture the hints and then merge them in once the trigger is loaded (since we copy variables at runtime).
  • Now that some variables may have accurate return types, Variable#getConvertedExpression has been updated to restrict what conversions are allowed on those variables.
  • Fixed an issue where Classes#getSuperClassInfo was not guaranteed to return the exact ClassInfo if one existed.
  • I added a new class, SectionUtils, which includes a static utility method for loading a section's code into a Trigger. More specifically, it handles the type of behavior that is becoming more common: Loading a section into a Trigger to use different context/events, preventing delays, and copying local variables at runtime. With type hints, the need to copy type hints arose, and the behavior became far more complicated. This method serves to handle that behavior and reduce the effort needed by the increasing number of implementing classes.

API Support

Addon developers may need to support this feature if their syntax modifies variables (and results in type changes). First, you can use the HintManager to check if a Variable can use hints:

if (HintManager.canUseHints(variable)) {
    // safe to manage hints
}

If so, you can obtain the active HintManager using the ParserInstance:

ParserInstance.get().getHintManager();

Then, depending on what type of operation your syntax is performing, you can manage hints as necessary:

HintManager hintManager = ParserInstance.get().getHintManager();
// setting the hints (clears previous hints)
hintManager.set(variable, SomeType.class);
// adding a hint
hintManager.add(variable, SomeType.class);
// clearing hints (e.g. `delete {_var}`)
hintManager.delete(variable);

Testing Completed

I have added a basic type hints.sk test (more to come). I plan to implement JUnit testing for HintManager.

Supporting Information

Depends on:


Completes:

Related:

@APickledWalrus APickledWalrus added bug An issue that needs to be fixed. Alternatively, a PR fixing an issue. feature Pull request adding a new feature. needs testing Needs testing to determine current status or issue validity, or for WIP feature pulls. labels May 23, 2025
@sovdeeth sovdeeth moved this to In Progress in 2.12 Release Jun 3, 2025
Variables will always use converters. so this allows us to represent a broader range of types (and likely reduce mistakes)
Type hints have become more advanced, and the goal is now for them to become errors. That is, the system should be opt-out rather than opt-in. Confidence in hint accuracy is high enough.
ContainerExpression behavior was wrong - variables should not be container expressions
@APickledWalrus APickledWalrus moved this to In Review in 2.12 Release Jun 27, 2025
@APickledWalrus APickledWalrus marked this pull request as ready for review June 27, 2025 19:05
@APickledWalrus APickledWalrus requested review from a team as code owners June 27, 2025 19:05
@APickledWalrus APickledWalrus requested review from erenkarakal and removed request for a team June 27, 2025 19:05
@skriptlang-automation skriptlang-automation bot added the needs reviews A PR that needs additional reviews label Jun 27, 2025
Copy link
Contributor

@Absolutionism Absolutionism left a comment

Choose a reason for hiding this comment

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

Looks good to me.
also I think EffZombify may be applicable for hint changing

Copy link
Member

@sovdeeth sovdeeth left a comment

Choose a reason for hiding this comment

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

looking good to me

@skriptlang-automation skriptlang-automation bot added feature-ready A PR/issue that has been approved, tested and can be merged/closed in the next feature version. and removed needs reviews A PR that needs additional reviews labels Jun 27, 2025
@skriptlang-automation skriptlang-automation bot removed the feature-ready A PR/issue that has been approved, tested and can be merged/closed in the next feature version. label Jun 28, 2025
@APickledWalrus APickledWalrus requested a review from Efnilite July 1, 2025 01:00
@github-project-automation github-project-automation bot moved this from In Review to Awaiting Merge in 2.12 Release Jul 1, 2025
@skriptlang-automation skriptlang-automation bot added the feature-ready A PR/issue that has been approved, tested and can be merged/closed in the next feature version. label Jul 1, 2025
@APickledWalrus APickledWalrus merged commit 53e98af into dev/feature Jul 1, 2025
6 checks passed
@skriptlang-automation skriptlang-automation bot added the completed The issue has been fully resolved and the change will be in the next Skript update. label Jul 1, 2025
@github-project-automation github-project-automation bot moved this from Awaiting Merge to Done in 2.12 Release Jul 1, 2025
@skriptlang-automation skriptlang-automation bot removed the feature-ready A PR/issue that has been approved, tested and can be merged/closed in the next feature version. label Jul 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug An issue that needs to be fixed. Alternatively, a PR fixing an issue. completed The issue has been fully resolved and the change will be in the next Skript update. feature Pull request adding a new feature. needs testing Needs testing to determine current status or issue validity, or for WIP feature pulls.
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Local variable type hints. Helps identify local variable return types Variables can be used as function arguments of the wrong type
4 participants