Skip to content

Inferred generic (poly type) constraints #35

Open
@kaleidawave

Description

@kaleidawave

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 and x <: number is evaluated, then x's restriction becomes number

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:

Metadata

Metadata

Assignees

Labels

checkingIssues around checkingfeedback-neededExtra attention/consensus is needed

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions