Skip to content

Tuple rest sandwich prop #49106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

craigphicks
Copy link

@craigphicks craigphicks commented May 14, 2022

This is for analytic use with issue #49105 (reopened in short form as #49138).

The analysis is complete and the results are written below. The code is no longer being worked on. It remains as a "pull draft" merely fpr analysis purposes.

To summarize the analysis, the way the code is currently written (4.7) there is assumption that array context types
don't necessarily need to expose a length for use in matching. However that won't necessarily work when
trying to match with a bidirectional search. Might be able to get away with negative indices
(distance from the end) and still avoid length. But stretching a rest element to infinite length won't work when a bidirectional search is required.

Rest tuple sandwich implementation

 Changes to be committed:
	modified:   src/compiler/checker.ts
	new file:   tests/baselines/reference/variadicTupleRestSandwich.errors.txt
	new file:   tests/baselines/reference/variadicTupleRestSandwich.js
	new file:   tests/baselines/reference/variadicTupleRestSandwich.symbols
	new file:   tests/baselines/reference/variadicTupleRestSandwich.types
	new file:   tests/cases/conformance/types/tuple/variadicTupleRestSandwich.ts
 Changes to be committed:
	modified:   tests/baselines/reference/variadicTuples1.errors.txt
	modified:   tests/baselines/reference/variadicTuples1.types
	modified:   tests/baselines/reference/variadicTuples2.types

Update basline
@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label May 14, 2022
@craigphicks
Copy link
Author

craigphicks commented May 14, 2022

The code is functionally correct with respect to the baselines tests.

However, the following two kinds of contextualType currently exist in the baseline examples, and end up being passed to checkArrayLiteral but never in a way that invokes the reverse part of the bidirectional search.

  • contextualType && !isTupleLikeType(contextualTypes && isTupleLikeType(contextualTypes)
  • contextualType && !!(contextualType.flags & TypeFlafs.Union)

Here's how length gets handled for those cases:

 const getContextualTypeForElementExpression_altLength=(arrayContextualType: Readonly<Type>): number => {
    Debug.assert(!!arrayContextualType,"!!arrayContextualType");
    if (isTupleType(arrayContextualType)) {
        return arrayContextualType.target.elementFlags.length;
    }
    else if (isTupleLikeType(arrayContextualType)) {
        return maxContextualTypeLength; // It doesn't have to be like this.  There really is a length.
    }
    else if (!!(arrayContextualType.flags && TypeFlags.Union)) {
        return maxContextualTypeLength; // What's going on here???
    }
    else {
        return 1; //  This is an array, am I right?
    }
};

Certainly (I think) at least we could make a test with a TupleLikeType that requires the birectional search. But because we're not currently returning a real length, that kind of test could fail.

Also, as for Unions, I haven't fully analyzed those cases but it is definitely the case a imposing a lenght of 1 causes the some baseline tests to return different type results. (However, in limited testing, didn't notice any actual error yes/no differences.) We also need to consider whether those kinds of tests would need bidirectional search - by default I think the answer should be yes.

 Changes to be committed:
	modified:   tests/baselines/reference/variadicTupleRestSandwich.errors.txt
	modified:   tests/baselines/reference/variadicTupleRestSandwich.js
	modified:   tests/baselines/reference/variadicTupleRestSandwich.symbols
	modified:   tests/baselines/reference/variadicTupleRestSandwich.types
	modified:   tests/cases/conformance/types/tuple/variadicTupleRestSandwich.ts

Improve test file variadicTupleRestSandwich.ts documentation
Update baseline
 Changes to be committed:
	modified:   src/compiler/checker.ts

    Completed unification of old and new code.

    These functions exable the compatibility:
     getContextualTypeForElementExpression_altTypeAndFlag
     getContextualTypeForElementExpression_altLength
     getContextualTypeForElementExpression_altFlags

    Still there is no real length for some types which are not isTupleType.
    See getContextualTypeForElementExpression_altFlags for how that works now
    by returning a large number instead of a real length.

    However, that won't in case of bidirectional search.
    So it's just lucky that the baseline tests don't contain a comnbination
    of a type that has no defined length and the need for a bidirection search.
// arrayContextualType,
// t => getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false),
// /*noReductions*/ true));
const getContextualTypeForElementExpression_altTypeAndFlag=(arrayContextualType: Readonly<Type>, index: number): [Type, ElementFlags] => {
Copy link
Author

@craigphicks craigphicks May 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • getContextualTypeForElementExpression_altTypeAndFlag
  • getContextualTypeForElementExpression_altLength
  • getContextualTypeForElementExpression_altFlags

are workarounds for getContextualTypeForElementExpression which fails when accessing indices beyond the first
index corresponding to a rest index. getContextualTypeForElementExpression returns the value at the first rest index for any index value >= the first rest index. That doesn't work when there are real values beyond the first rest index, which are actually allowed in the current code from createNormalizedTupleType: (checker.ts: function createNormalizedTupleType), see the code corresponding to comments:
// Turn optional elements preceding the last required element into required elements
// Turn elements between first rest and last optional/rest into a single rest element
Proposal: IF an abstract representation is necessary (is it necessary?)
then modify getContextualTypeForElementExpression to accept negeative indices, where -n refers to the nth element from the end, starting at -1. (Same numbering convention as slice).

NOTE!!!
The condition (contextualType.target.elementFlags.length < getTypeArguments(contextualType).length) does occur. It has been observed tp happen when there is tuple type which an unknow generic type in, e.g., [...T] followed by an instantiation of that type, e.g. [...T] = ["hello"]. (There may or may not be other examples), Then the types contained in getTypeArguments(contextualType) are [string, T] (length 2) but contextualType.target.elementFlags is [ElementFlags.Required] (length 1).

Conformance in length is required when reading from the ends of the arrays.

}

{
// Type T12 IS a rest sandwich format - this example shows results that improvably differ between before and after.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Type T12 IS a rest sandwich format - this example shows results that improvably differ between before and after.
// Type T12 IS a rest sandwich format - this example shows results that improbably differ between before and after.

@sandersn
Copy link
Member

sandersn commented Apr 2, 2025

The bug for this PR was fixed in 5.0, so I'm going to close it. Please let me know if it needs to be re-opened.

@sandersn sandersn closed this Apr 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants