luau icon indicating copy to clipboard operation
luau copied to clipboard

[New Solver] Intersection types do not allow for optional fields

Open luigi-rosso opened this issue 5 months ago • 3 comments

This works on the old solver but fails with the new:

--!strict
type Drawing = {
	update: (() -> boolean)?,
}

type Counter = {
	count: number,
}

function update(): boolean
	return true
end

return function(): Drawing & Counter
	return {
		count = 34,
		update = update,
	}
end

New solver:

luau-analyze --fflags=true optional_methods.luau
./optional_methods.luau(15,9): TypeError: Type
        '{ count: number, update: (...any) -> boolean }'
could not be converted into
        'Counter & Drawing'; 
this is because accessing `update` results in `() -> boolean` and in the 1st component of the intersection, accessing `update` has the 2nd component of the union as `nil`, and `() -> boolean` is not exactly `nil`

luigi-rosso avatar Jul 28 '25 22:07 luigi-rosso

This one keeps coming up for us, is there any workaround we may be missing for allowing "update" in the example above to be optional?

To further explain, if we don't mark it optional everything is fine:

type Drawing = {
	update: () -> boolean,
}

But we want it to be optional, as implementors of an API like are ideally not required to, for example, provide an "update" function. Such that they can return this successfully:

return function(): Drawing & Counter
	return {
		count = 34,
	}
end

These are obviously greatly simplified, Counter/Drawing would have many more required fields.

luigi-rosso avatar Aug 19 '25 18:08 luigi-rosso

This looks like another flavor of issue with bidirectional typechecking. @hgoldstein can you take a look at this when you get the chance?

aatxe avatar Aug 21 '25 21:08 aatxe

Can do, I'll try to find some time to do this soon.

hgoldstein avatar Aug 21 '25 21:08 hgoldstein