Regression with generic/recursively defined types

Reproduction Steps
Create a script with the following code:

--!strict
export type PromiseFor<T> = {
	andThen: <U>(
		self: PromiseFor<T>,
		onFulfilled: ((result: T) -> U)?,
		onRejected: ((err: string) -> U)?
	) -> PromiseFor<U>,
	catch: <U>(
		self: PromiseFor<T>,
		onRejected: ((err: string) -> U)?
	) -> PromiseFor<U>,
	finally: <U>(
		self: PromiseFor<T>,
		onResolvedOrRejected: ((wasFulfilled: boolean, resultOrErr: T | string) -> U)
	) -> PromiseFor<U>,
}

This code is a few months old, and it describes a type of a “Promise” object, which can be chained with :andThen() and :catch() statements.

The code used to work without emitting any warnings, and now emits warnings for some reason:

If you type the PromiseFor<U> return types as Promise<any>, you get the same warning.

Expected Behavior
This type should be valid, and used to be valid.

Actual Behavior
The type is no longer valid.
why is there a character limit for each individual field in the bug report wizard

Workaround
The only workaround in this example is to type these PromiseFor<U> return types as any.

Issue Area: Studio
Issue Type: Other
Impact: Moderate
Frequency: Very Rarely
Date First Experienced: 2022-01-06 00:01:00 (-07:00)
Date Last Experienced: 2022-01-06 00:01:00 (-07:00)

2 Likes

This is a really good example of the mix of recursive type functions and nested generics. I’m going to add it to the discussion for lifting the recursive type restriction at RFC: Loosening the recursive type restriction by asajeffrey · Pull Request #86 · Roblox/luau · GitHub

If you want to see the rationale for this change it’s at luau/recursive-type-restriction.md at master · Roblox/luau · GitHub – the tl;DR is that Luau always had this restriction, but previously random things happened if you broke it, whereas now there’s a check for it. This does affect code like PromiseFor, where the old random behaviour happened to do the right thing.

The next step is to settle on a design, if you’d like to take part in that conversation it’s at RFC: Loosening the recursive type restriction by asajeffrey · Pull Request #86 · Roblox/luau · GitHub

7 Likes

Just to keep you in the loop on this… this is still on our radar for fixing, though we’re busy working on other type system issues right now. We’re tracking the issue at RFC: Loosening the recursive type restriction by asajeffrey · Pull Request #86 · Roblox/luau · GitHub, when there’s some activity it’ll get posted there!

6 Likes