Skip to content

Conversation

@7h3kk1d
Copy link
Contributor

@7h3kk1d 7h3kk1d commented Aug 3, 2025

Adds a dynamic mode to Type projector and Probes on types

Type projector with dynamic type

Screenshot From 2025-11-19 13-11-50
  • Adds a new dynamic mode to the type projector that shows the runtime type of expressions observed during evaluation

Removed

Probes on types

Screenshot 2025-09-25 at 9 53 25 AM

Allows you to add probes and dyntype probes on types. This works by adding a Probe type similar to the one for patterns and expressions. The Type "observes" any expression that flows through it in an ascription e.g. "Hello" : Probe(?) will add "Hello" to the probe. This also allows for projectors on type to have dynamics enabled as they will get dynamic information during evaluation.

Known issues

  • We optimize away some ascriptions
    • Consistent branches and lists both add ascriptions if the types don't match. If the type could contain a probe we want it to exist so that we get the probe on the type.
    • Sum type constructors don't add ascriptions and instead just rerun statics on the contained expression:
Screenshot From 2025-09-25 10-38-22
  • Ascriptions sometimes evaluate before the scrutinee evaluates
Screenshot From 2025-09-25 10-39-05 * This now has dynamics set to true for the type proj in order to get the dynamic type. Unfortunately this wraps the term in a probe which has the same statics as parens and gets the wrong self type (addressed separately in #2009)

@codecov
Copy link

codecov bot commented Aug 5, 2025

Codecov Report

❌ Patch coverage is 33.58779% with 87 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.34%. Comparing base (77ab798) to head (4ae0e2c).

Files with missing lines Patch % Lines
...c/haz3lcore/projectors/implementations/TypeProj.re 0.00% 49 Missing ⚠️
src/language/term/Typ.re 59.57% 19 Missing ⚠️
src/web/app/common/ProjectorView.re 0.00% 5 Missing ⚠️
src/web/app/editors/code/Code.re 0.00% 5 Missing ⚠️
src/util/Id.re 0.00% 3 Missing ⚠️
src/web/app/editors/code/ContextMenu.re 0.00% 3 Missing ⚠️
src/haz3lcore/pretty/ExpToSegment.re 50.00% 1 Missing ⚠️
src/language/ProjectorKind.re 83.33% 1 Missing ⚠️
src/language/term/IdTagged.re 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #1858      +/-   ##
==========================================
- Coverage   50.38%   50.34%   -0.05%     
==========================================
  Files         230      231       +1     
  Lines       25365    25456      +91     
==========================================
+ Hits        12780    12815      +35     
- Misses      12585    12641      +56     
Files with missing lines Coverage Δ
src/haz3lcore/pretty/PadIds.re 100.00% <100.00%> (ø)
src/haz3lcore/projectors/ProjectorBase.re 6.00% <ø> (ø)
src/haz3lcore/zipper/action/Introduce.re 80.37% <ø> (ø)
src/language/statics/Elaborator.re 81.67% <100.00%> (-0.07%) ⬇️
src/web/app/Cursor.re 0.00% <ø> (ø)
src/web/app/editors/code/CodeWithStatics.re 35.13% <ø> (ø)
src/haz3lcore/pretty/ExpToSegment.re 79.91% <50.00%> (-0.09%) ⬇️
src/language/ProjectorKind.re 89.65% <83.33%> (+0.76%) ⬆️
src/language/term/IdTagged.re 68.75% <0.00%> (-8.67%) ⬇️
src/util/Id.re 32.00% <0.00%> (ø)
... and 5 more

... and 8 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 self-assigned this Aug 12, 2025
Comment on lines 198 to 206
ListUtil.update_nth(idx, map, ((id, entry: Refractors.entry)) =>
(
id,
Refractors.{
kind: entry.kind,
model: new_model,
},
)
),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fix for #2097

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

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

Copilot reviewed 29 out of 29 changed files in this pull request and generated 13 comments.


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

Comment on lines +972 to +976
let pad_ids = (~settings: Settings.t, n: int, ids: list(Id.t)): list(Id.t) => {
let len = List.length(ids);
if (len < n) {
if (settings.raise_if_padding) {
raise(Failure("Padding required but not enough ids provided."));
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

The raise_if_padding setting is added to detect when padding is needed, but the raised exception uses a generic Failure with a string message. Consider defining a specific exception type for padding failures to make error handling more explicit and type-safe.

Suggested change
let pad_ids = (~settings: Settings.t, n: int, ids: list(Id.t)): list(Id.t) => {
let len = List.length(ids);
if (len < n) {
if (settings.raise_if_padding) {
raise(Failure("Padding required but not enough ids provided."));
exception PaddingRequired(string);
let pad_ids = (~settings: Settings.t, n: int, ids: list(Id.t)): list(Id.t) => {
let len = List.length(ids);
if (len < n) {
if (settings.raise_if_padding) {
raise(PaddingRequired("Padding required but not enough ids provided."));

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +27
let ids =
current_ids
@ List.init(needed_ids - List.length(current_ids), _ => Id.mk());
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

The calculation needed_ids - List.length(current_ids) could be negative if current_ids has more elements than needed_ids. While List.init would fail with a negative value, this should be handled more gracefully. Consider using max(0, needed_ids - List.length(current_ids)) to prevent potential issues.

Suggested change
let ids =
current_ids
@ List.init(needed_ids - List.length(current_ids), _ => Id.mk());
let missing_ids = max(0, needed_ids - List.length(current_ids));
let ids =
current_ids
@ List.init(missing_ids, _ => Id.mk());

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +75
let str3 = (id: t) => id |> to_string |> String.sub(_, 0, 3);
let str8 = (id: t) => id |> to_string |> String.sub(_, 0, 8);
let cls = (id: t) => "id" ++ str8(id);

Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

The helper functions str3, str8, and cls are moved before the pp and show functions. While this is generally fine, it breaks the logical grouping where conversion functions (to_string, of_string, compare) were together, followed by formatting functions (pp, show). This change reduces code organization clarity. Consider keeping related functions together or adding a comment to explain the grouping.

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +27
let qcheck_pads_typ_for_exp_to_segment =
QCheck.Test.make(
~name="No ids are needed to be padded during ExpToSegment",
~count=1000,
QCheck_Util.arb_typ(~minimal_idents=false, 30),
typ => {
let padded = PadIds.pad_typ_ids(typ);
let _ =
ExpToSegment.typ_to_segment(
~settings={
secondary: AutoFormat,
parenthesization: Defensive,
label_format: QuoteWhenNecessary,
inline: false,
fold_case_clauses: false,
fold_fn_bodies: `NoFold,
hide_fixpoints: false,
show_filters: true,
show_unknown_as_hole: true,
raise_if_padding: true // Will raise an exception if padding
},
padded,
);
Language.Equality.syntactic.typ(padded, PadIds.pad_typ_ids(padded));
},
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

The test checks that "No ids are needed to be padded during ExpToSegment", but then calls PadIds.pad_typ_ids(padded) at the end, suggesting that padding does occur. The test name and the actual test logic seem inconsistent. If the goal is to verify that padding is idempotent (i.e., padding twice produces the same result), consider renaming the test to better reflect this. Also, the comment on line 22 "Will raise an exception if padding" suggests that padding shouldn't happen, which contradicts the function name and implementation.

Copilot uses AI. Check for mistakes.
@7h3kk1d
Copy link
Contributor Author

7h3kk1d commented Feb 10, 2026

"Add Statics" -> "Add Type probe"

@7h3kk1d 7h3kk1d changed the title Add DynType projector Add dynamic mode to type projector Feb 10, 2026
@7h3kk1d
Copy link
Contributor Author

7h3kk1d commented Feb 10, 2026

The hover text on mode is added. I started doing the resizing and abbreviate isn't implemented on types. Plus the sample lengths are a bit ad-hoc for the length state. I can duplicate all the mouse handling but if we're not going to add some sort of a resizable component this is going to be a maintenance burden. @disconcision if you want to see if our 🤖 overlords can make the type probe resizable that would be great.

@7h3kk1d 7h3kk1d requested a review from cyrus- February 10, 2026 18:44
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