DanielXMoore / Civet

A TypeScript superset that favors more types and less typing
https://civet.dev
MIT License
1.33k stars 28 forks source link

`<` is weirdly sensitive to being less-than or extends in SAFE #1225

Open bbrk24 opened 1 month ago

bbrk24 commented 1 month ago

These two functions are not compiled alike:

x := &: number < 0 ? -1 : 1
y := &: number < 0 ? -1 : &
const x = ($: number extends 0 ? -1 : 1) => $;
const y = ($1: number) => ($1 < 0 ? -1 : $1);

Even more strangely, if you swap them (defining y before x), that's a ParseError.

edemaine commented 1 month ago

I'm not sure what the issue is exactly. The first example is a valid type, so is treated as such, while the second isn't, so the longest possible prefix that's a type gets used. In general, Civet (Hera/PEG) greedily matches what it can for a given rule.

What was the behavior you expected? Are you suggesting we e.g. disable < as extends shorthand in &, maybe without parens?

bbrk24 commented 1 month ago

One issue is when one of the branches is a call:

x := &: number < 0 ? -1 : Math.sqrt 5
y := &: number < 0 ? Math.sqrt 5 : 1
const x = ($: number extends 0 ? -1 : Math.sqrt) => $(5);
const y = ($1: number) => ($1 < 0 ? Math.sqrt(5) : 1);

Really this just caught me off-guard: I forgot < could also mean extends, and I had to look at the output to understand the slew of errors TS gave me. This is pretty trivially worked around by wrapping &: number in parens.

edemaine commented 1 month ago

Another option that comes to mind is requiring a typed & to use parentheses, as in (&: number). The current syntax is partly a holdover from when & couldn't be lifted outside parentheses like it can now. Of course, now that we have a parenless version, it's tempting to have it... After all, the point of & is to be more concise than an arrow function.

bbrk24 commented 1 month ago

We could allow the parenless version for simple types like number, but require parens for conditional types.