Description
This was implemented in the initial release but relied on mutating
Type
during checking which caused problems in conditional branches and the such. This issues is a second attempt that stores "requests" that are applied at the boundary.
A aim of Ezno is to work without writing type annotations. Variables don't need them because of the value system, return types are based on the body. The final piece is the unknown-ness of inputs to functions.
This can be in several places:
Explicit parameter
function func1(a) {
return a.x // The constraint of `a` should be inferred as `{ x: any }`
}
Non restricted variable
let a = 4;
function func2() {
return Math.sin(a) // The constraint of closed over references `a` should be inferred as number (with strict casts at least)
}
Cycles (recursion)
interface Node {
parent: Node | null,
x:
}
function depth(obj: Node) {
if (obj.parent) {
// `depth` hasn't been checked yet. A restriction should be made
return depth(obj.parent) + 1
} else {
return 0
}
}
See #29
Others
- Throw...
any
as unknown
To better support existing codebases any
should be treated as unknown
. No annotation should be treated as unknown
Combining restrictions
When two restrictions are made they are combined using &
interface X {
readable: boolean
}
interface Y {
name: string
}
function x(p: X) {}
function y(p: Y) {}
function z(param1) {
x(param1)
y(param1)
}
param1
is now restricted to X & Y
.
this might create impossible types (string & number), which is fine but a warning should be raised
Places where constraint inference is done
- Calling a type
- Getting a property
- subtype-ing. If
x
has a unknown restriction andx <: number
is evaluated, thenx
's restriction becomesnumber
I had up to here existing implemented, the hard part is now:
Nesting
function x(obj) {
return obj.prop1.prop2.prop3
}
This needs to place a inference condition on a inference restriction 😅
The non-local unknown
issue
If unknown
is found on a fixed restriction, then a nested dynamic restriction might have to be on a fixed restriction.
interface Something {
prop: any
}
function doSomethingWithSomething(s: Something) {
return Math.sin(s.prop)
}
extended from https://github.com/kaleidawave/ezno/blob/main/checker/docs/inference.md
It is still in progress the best way to tackle this, interested if people have real world parameter inference examples they want supported: