Skip to content

Conversation

@7h3kk1d
Copy link
Contributor

@7h3kk1d 7h3kk1d commented Oct 17, 2025

Dynamic Feeback

This PR adds a new toggleable feature that provides in-editor type feedback based off the runtime dynamic types observed in program execution. It accomplishes this by running the program and probing any expression with a statically unknown type. Then re-running statics with t he additional typing information.

Example

Screencast.From.2025-11-18.13-45-45.webm

Probe selection

The implementation is integrated with the Probe pinning system so it's possible to get dynamic types for specific function applications by pinning a specific function application in the probe system.
Screencast From 2025-11-18 13-53-21.webm

Todos

  • Handle type inconsistencies with type variables in polymorphic code. i.e. (typfun a -> fun x : a -> x)@<String>("") should not give a dynamic error on x

7h3kk1d and others added 8 commits October 13, 2025 15:16
Added DynamicStatics module for type mapping and integrated ~dynamics parameter across statics functions in Statics.re, Info.re, and CustomStatics.re. This enables dynamic type lookups and overrides in expression derivation, enhancing type inference with runtime-like information for better debugging and analysis.
- Introduce dynamic_info_map and dynamic_error_ids to CachedStatics for handling dynamic analysis
- Update CodeWithStatics to filter and display dynamic errors separately from static ones
- Modify Arms.Errors module to support dynamic error styling and rendering
- Enhance editor UI to show dynamic error decorations alongside static ones for improved code feedback
Add a new `dynamic_feedback` boolean setting to core language settings, allowing users to toggle dynamic error and info computation in the code editor. This feature conditionally enables/disables dynamic statics calculation based on user preference, improving performance and user control. Updated related UI components, shortcuts, and menu for seamless integration.
- Introduce `~probe_unknowns` flag in `Elaborator.elaborate`, `elaborate_pattern`, and `uexp_elab` functions to conditionally enable probing for unknown types in expressions and patterns.
- Update `CachedStatics.elaborate` to accept and pass the flag, using `settings.dynamic_feedback` as the value.
- Modify CLI and test files to explicitly set `~probe_unknowns=false` for consistent behavior.
- This change allows fine-grained control over elaboration behavior, improving flexibility for handling unknown types without always triggering probes.
- Introduce `dynamic_info` field to cursor type in Cursor.re for tracking dynamic information
- Update CodeWithStatics.re to compute and include dynamic info from statics map
- Modify CursorInspector.re to prioritize and display dynamic errors over static info, improving user feedback on runtime issues
@7h3kk1d 7h3kk1d self-assigned this Oct 17, 2025
7h3kk1d and others added 8 commits October 17, 2025 08:49
Changes `calculate_dynamic_type` in derived functions across Info.re,
CustomStatics.re, and Statics.re from returning plain Typ.t to
option(Typ.t). This prevents using invalid types when errors exist in
the map, providing a fallback via Option.value with Unknown(Internal) | Typ.temp.
Replace Typ.consistent_join with Typ.join_all in dynamic type calculations across TypeProj.re, Info.re, and CursorInspector.re. This change improves type joining robustness by handling empty lists with a temporary unknown type, addressing potential inconsistencies in dynamic type inference. Simplify CursorInspector by directly using Info.ty instead of computing from closures.
Add optional `is_dynamic` parameter (defaulting to false) to `view`, `view_segment`, `view_typ`, and `view_any` functions in CodeViewable.re to enable distinguishing dynamic elements in code rendering. Updated the CodeWithStatics.re view call and Arms.Errors.of_ids invocation to pass the required parameters, ensuring compatibility with dynamic features in the Haz3l editor.
@codecov
Copy link

codecov bot commented Nov 4, 2025

Codecov Report

❌ Patch coverage is 35.46326% with 202 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.99%. Comparing base (7e12fdd) to head (7a40c8b).

Files with missing lines Patch % Lines
src/language/term/Typ.re 32.22% 61 Missing ⚠️
src/web/app/editors/code/CodeWithStatics.re 3.12% 31 Missing ⚠️
src/web/app/editors/result/EvalResult.re 0.00% 29 Missing ⚠️
src/language/dynamics/Dynamics.re 14.28% 24 Missing ⚠️
src/language/statics/DynamicStatics.re 36.84% 12 Missing ⚠️
src/web/app/editors/code/CodeViewable.re 0.00% 8 Missing ⚠️
src/web/app/common/Widgets.re 0.00% 6 Missing ⚠️
src/web/app/editors/decoration/Arms.re 0.00% 5 Missing ⚠️
.../haz3lcore/projectors/implementations/ProbeProj.re 0.00% 4 Missing ⚠️
src/web/app/editors/result/Theorems.re 0.00% 4 Missing ⚠️
... and 10 more
Additional details and impacted files
@@               Coverage Diff                @@
##           dyntype-proj    #1988      +/-   ##
================================================
+ Coverage         49.92%   49.99%   +0.06%     
================================================
  Files               221      222       +1     
  Lines             23285    23530     +245     
================================================
+ Hits              11626    11763     +137     
- Misses            11659    11767     +108     
Files with missing lines Coverage Δ
src/haz3lcore/zipper/action/Introduce.re 90.52% <100.00%> (ø)
src/language/builtins/BuiltinsADT.re 98.27% <ø> (ø)
src/language/builtins/BuiltinsList.re 99.91% <ø> (ø)
src/language/dynamics/Evaluator.re 92.59% <100.00%> (ø)
src/language/dynamics/ValueChecker.re 0.00% <ø> (ø)
src/language/dynamics/transition/Ascriptions.re 81.59% <100.00%> (-0.62%) ⬇️
src/language/dynamics/transition/Transition.re 64.61% <100.00%> (+0.95%) ⬆️
src/language/statics/CustomStatics.re 87.29% <ø> (ø)
src/language/statics/StaticsBase.re 86.11% <100.00%> (+0.39%) ⬆️
src/language/term/Grammar.re 80.26% <100.00%> (+0.56%) ⬆️
... and 28 more

... and 18 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@7h3kk1d 7h3kk1d requested a review from Copilot November 4, 2025 17:08
Copy link
Contributor

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 implements dynamic feedback in the Hazel editor, which displays runtime type information from evaluation to help users identify type errors discovered during execution. The feature allows types computed at runtime to be displayed alongside static types, with visual differentiation for dynamic errors.

Key Changes:

  • Adds a "Dynamic Feedback" toggle in settings to enable/disable the feature
  • Implements dynamic type inference by running statics on runtime values captured during evaluation
  • Adds visual styling for dynamic errors with animated decorations to distinguish them from static errors

Reviewed Changes

Copilot reviewed 40 out of 40 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
test/evaluator/Test_Evaluator_DynamicFeedback.re New test file verifying dynamic feedback computation for complex expressions
test/evaluator/Test_Evaluator_Probe.re Adds test for probe functionality on constructor patterns
test/evaluator/Test_Evaluator.re Registers new dynamic feedback test suite
src/web/www/style/variables.css Adds CSS variable for dynamic error stroke color
src/web/www/style/editor.css Adds styling and animations for dynamic errors and formatting improvements
src/web/www/style/cursor-inspector.css Adds styling for dynamic error state in cursor inspector
src/web/view/TutorialMode.re Updates to extract values from Calc types and adds dynamic_statics field
src/web/view/NutMenu.re Adds Dynamic Feedback toggle to settings menu
src/web/view/ExerciseMode.re Updates to handle Calc-wrapped dynamics and dynamic_statics
src/web/util/WorkerServer.re Wraps evaluation in timing measurement
src/web/util/WorkerClient.re Increases worker timeout from 20s to 60s
src/web/app/inspector/CursorInspector.re Implements dynamic type display and comparison in inspector
src/web/app/input/Shortcut.re Adds keyboard shortcut for toggling dynamic feedback
src/web/app/helpful-assistant/ChatLSP.re Adds empty dynamics parameter to statics calls
src/web/app/explainthis/ExplainThis.re Adds dynamic_statics field initialization
src/web/app/editors/stepper/*.re Wraps empty dynamics maps in Calc.OldValue
src/web/app/editors/result/EvalResult.re Refactors dynamics extraction from result to use Calc
src/web/app/editors/decoration/Arms.re Adds is_dynamic parameter for rendering dynamic error decorations
src/web/app/editors/code/*.re Implements dynamic statics calculation and rendering
src/web/app/editors/cell/CellEditor.re Adds dynamic_statics field to model
src/web/app/Cursor.re Adds dynamic_info field to cursor type
src/web/Settings.re Adds dynamic_feedback boolean setting
src/util/Calc.re Adds map function for transforming Calc values
src/language/term/Typ.re Refactors diff function to use helper for collecting all IDs
src/language/statics/*.re Threads dynamics parameter through statics and adds dynamic type computation
src/language/dynamics/transition/PatternMatch.re Handles pattern matching with probed constructors
src/language/CoreSettings.re Adds dynamic_feedback setting to core settings
src/haz3lcore/projectors/implementations/TypeProj.re Updates to use join_all instead of consistent_join
src/haz3lcore/derived/CachedStatics.re Adds dynamic_info_map and dynamic_error_ids fields
Comments suppressed due to low confidence (1)

src/language/statics/Statics.re:1

  • The ~expected_labels parameter is missing from this uexp_to_info_map call, while other similar calls in the same function include it. This inconsistency should be verified and corrected to ensure consistent behavior.
/* STATICS.re

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 1 to 2
/* These are very simple tests to make sure we're not
doing exponential blowup in the evaluator */
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The comment describes preventing 'exponential blowup in the evaluator,' but the test is actually about dynamic in-editor feedback functionality, not performance. The comment should be updated to accurately describe the purpose of these tests.

Copilot uses AI. Check for mistakes.
Comment on lines +251 to +254
@keyframes stroke-pulse {
0%, 100% { stroke-dashoffset: 0; opacity: 1; }
50% { stroke-dashoffset: 4; opacity: 0.7; }
}
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The magic number '4' for stroke-dashoffset should be defined as a CSS variable (e.g., --dynamic-error-pulse-offset) for maintainability and consistency with the rest of the codebase.

Copilot uses AI. Check for mistakes.
~calculate_dynamic_type=
uexp => {
let (ie, m) =
uexp_to_info_map(~ctx, uexp, StaticsBase.Map.empty);
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

Missing ~dynamics parameter in uexp_to_info_map call. The function signature requires ~dynamics as indicated by other calls in the same file. This will cause a compilation error or incorrect behavior.

Suggested change
uexp_to_info_map(~ctx, uexp, StaticsBase.Map.empty);
uexp_to_info_map(~dynamics, ~ctx, uexp, StaticsBase.Map.empty);

Copilot uses AI. Check for mistakes.
Comment on lines 1127 to 1138
let get_ids = () => {
let ids = ref([]);
let _ =
Grammar.map_typ_annotation(
(t: IdTagged.IdTag.t) => {
ids := t.ids @ ids^;
t;
},
ty': t,
);
ids^;
};
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The variable name 'get_ids' is misleading as it's a function that mutates a ref rather than just 'getting' IDs. Consider renaming to 'collect_all_ids' or refactoring to avoid the mutable ref pattern.

Copilot uses AI. Check for mistakes.
: statics;

let ctx_init: Language.Ctx.t = Language.Builtins.ctx_init(Some(Int));
// This should be a fold over the dynamics map getitng the type for each value
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

Corrected spelling of 'getitng' to 'getting'.

Suggested change
// This should be a fold over the dynamics map getitng the type for each value
// This should be a fold over the dynamics map getting the type for each value

Copilot uses AI. Check for mistakes.
Extract the inline `calculate_dynamic_type` function into a shared method in the `ExpressionStatics` module to eliminate code duplication and centralize the logic for determining dynamic types in static contexts. This refactor improves maintainability by reducing repetitive code across CustomStatics and Statics modules.
Base automatically changed from dyntype-type-proj to dyntype-proj November 19, 2025 18:07
@7h3kk1d 7h3kk1d marked this pull request as ready for review November 21, 2025 19:10
Add optional warning parameter to toggle_named widget to display ⚠️ icon with tooltip for cautioned settings. Updated settings menu to include performance warning for "Dynamic Feedback" toggle, informing users of potential slowdowns. This enhances user experience by providing upfront guidance on resource-intensive features.
@7h3kk1d
Copy link
Contributor Author

7h3kk1d commented Dec 5, 2025

Move the lightning bolt in the error message to the right side of the cursor inspector

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.

2 participants