Skip to content

Fixes #30507 #32100

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

Conversation

timsuchanek
Copy link
Contributor

@timsuchanek timsuchanek commented Jun 26, 2019

Fixes #30507

I saw, that when the object expression has incorrect properties, that don't exist on the type, the autocompletion works fine.
The decision, if the constraint type should be taken as the default or not is being made in checker.ts:15733 and as this is about 10 function calls deep when coming from https://github.com/microsoft/TypeScript/blob/master/src/services/completions.ts#L1457 I had to introduce a parameter in all these functions that can be passed down.
I saw, that there was already a ContextFlags type, which can be passed in to getContextualType, so I extended it and to make it accessible from the completions.ts, I had to add it to the TSChecker types in https://github.com/microsoft/TypeScript/compare/master...timsuchanek:genericObjectExpressionCompletion?expand=1#diff-4b8bd1eea29904f1be39cd864e1a45c0R3335

Let me know if I could have achieved this in a different way, but after many hours of debugging, this looked like the "most minimal" change to achieve the goal.

I added 2 tests, all tests are green.

@msftclas
Copy link

msftclas commented Jun 26, 2019

CLA assistant check
All CLA requirements met.

@schickling
Copy link

Very excited to see this fix! Thanks for your work on this @timsuchanek!

@timsuchanek
Copy link
Contributor Author

Sorry to bother, but maybe @ahejlsberg you can have a look as you introduced the ContextFlags. Not sure if I'm "misusing" them.

@weswigham weswigham requested a review from ahejlsberg June 27, 2019 20:35
@AviVahl
Copy link

AviVahl commented Jul 10, 2019

Does it also fix #28470?

@timsuchanek
Copy link
Contributor Author

timsuchanek commented Jul 11, 2019

@AviVahl from my understanding yes! I'll fix the new conflicts tomorrow, then it's again ready to get merged.

I'll also add your example as a test case.

@timsuchanek timsuchanek force-pushed the genericObjectExpressionCompletion branch from 4aaccf6 to 0c38f21 Compare July 12, 2019 09:08
@timsuchanek
Copy link
Contributor Author

timsuchanek commented Jul 12, 2019

@AviVahl I added a fix so that your use-case with the constructor arguments is also supported and also added the 2 examples from #28470 as test cases.

@weswigham @ahejlsberg can you prioritize this PR so that it doesn't get conflicts with master again? Thanks 🙏

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Jul 15, 2019

@timsuchanek would you also be able to add a test for string literal completions too?

declare function get<T, key: K extends keyof T>(obj: T, key: K): T[K];

get({ hello: 123, world: 456 }, "/**/");

This is one of the most-maddening and longest-standing issues we've had in completions. It would be really great to get this reviewed @ahejlsberg @weswigham @andrewbranch.

@timsuchanek
Copy link
Contributor Author

timsuchanek commented Jul 16, 2019

@DanielRosenwasser I just simplified the "binary and" statement and also added your example as a test.

Important to note: Your example also worked before my PR, I added it to the tests nonetheless. I didn't touch the code path for string literals, just the code path for object expressions when coming from the completion service.

Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

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

Looks good to me, so long as others are happy with the public API changes. The failed builds are just API baseline issues after the latest merge with master.

@timsuchanek timsuchanek force-pushed the genericObjectExpressionCompletion branch from d5667fa to ff6ceb5 Compare August 14, 2019 12:17
@timsuchanek
Copy link
Contributor Author

timsuchanek commented Aug 14, 2019

Thanks @andrewbranch! Is there a way that I can accept the baselines and add a commit for that?
Locally on my machine the tests succeed, can't reproduce the baseline failure.

@weswigham
Copy link
Member

Pass --skipPercent=0, and, failing that, set the CI environment variable.

@weswigham
Copy link
Member

(also rebase/merge with master)

@andrewbranch
Copy link
Member

I fixed the baseline merge. @weswigham @ahejlsberg any reservations about exporting ContextFlags in the public API?

@schickling
Copy link

Thanks a lot @andrewbranch. Can’t wait to see this merged! (This is a big deal for us at @prisma.) 🎉

@@ -2026,6 +2026,11 @@ declare namespace ts {
*/
runWithCancellationToken<T>(token: CancellationToken, cb: (checker: TypeChecker) => T): T;
}
export enum ContextFlags {
Copy link
Member

Choose a reason for hiding this comment

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

I think this as well as new signature need to be internal

Copy link
Contributor Author

@timsuchanek timsuchanek Sep 10, 2019

Choose a reason for hiding this comment

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

Do you mean we should use something different than the ContextFlags when calling the code from the completion service to prevent this type being exposed?

Copy link
Member

Choose a reason for hiding this comment

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

I think Sheetal means to move ContextFlags into one of the ts namespaces that’s already marked /** @internal */ and then to mark the second parameter of TypeChecker['getContextualType'] as /* @internal */ (or declare it as an internal overload, but the linter might call that an unnecessary overload)

Copy link
Contributor Author

@timsuchanek timsuchanek Sep 10, 2019

Choose a reason for hiding this comment

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

Ok, makes sense! The overload option indeed makes the linter complain:

ERROR: /Users/tim/code/TypeScript/src/compiler/types.ts:3224:61 unified-signatures These overloads can be combined into one signature with an optional parameter.

The non-overload option, which I wrote like this:

        getContextualType(
            node: Expression,
            /* @internal */ contextFlags?: ContextFlags
        ): Type | undefined;

spits out an invalid typescript.d.ts:

        getRootSymbols(symbol: Symbol): ReadonlyArray<Symbol>;
        getContextualType(node: Expression, 
: Type | undefined;
        /**
         * returns unknownSignature in the case of an error.
         * returns undefined if the node is not valid.
         * @param argumentCount Apparent number of arguments, passed in case of a possibly incomplete call. This should come from an ArgumentListInfo. See `signatureHelp.ts`.
         */

Is there a way to ignore the linter in this case?
Or what is the right way to add @internal to a specific argument?

Copy link
Member

Choose a reason for hiding this comment

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

Just filed #33350. I think it would be ok to ignore the line from the linter. @sheetalkamat?

Copy link
Member

Choose a reason for hiding this comment

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

Yes in past we have marked the overload internal and disabled the rule for that line.

Copy link
Contributor Author

@timsuchanek timsuchanek Sep 11, 2019

Choose a reason for hiding this comment

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

Done. Had to adjust the tests because of #32266

Anything else you need from my side to get this merged?
@sheetalkamat @andrewbranch

Copy link
Member

Choose a reason for hiding this comment

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

Cool, this doesn’t even touch the public API baselines now. Would be good to get an approval from another person on the team but I think this is good.

@timsuchanek timsuchanek force-pushed the genericObjectExpressionCompletion branch from a118dc5 to 85ee123 Compare September 11, 2019 08:36
@timsuchanek timsuchanek force-pushed the genericObjectExpressionCompletion branch from 85ee123 to 7883ec6 Compare September 11, 2019 08:48
@@ -16201,7 +16196,8 @@ namespace ts {
const constraint = getConstraintOfTypeParameter(inference.typeParameter);
if (constraint) {
const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper);
if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
const isCompletionContext = contextFlags && (contextFlags & ContextFlags.Completion);
if (!inferredType || isCompletionContext || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't seem like the right place to do this - rather than passing the flag all the way thru signature resolution, if this flag is set, we should just look at the "base signature" (getBaseSignature) rather than starting inference at all, I think. Then again, if we did that we wouldn't get an instantiated constraint which reports more detailed information on circular constraints. Then again again, I'm pretty sure as-is this is caching into the resolvedSignature of a node, which this very much is not - which means requesting completions poisons the cache with incorrect types for later checking.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the feedback @weswigham! Do you have a suggestion how we still could fix the autocompletion for this? This was, unfortunately, the only way I found (with my limited knowledge of the codebase).

Maybe introducing a new method as an alternative to getContextualType just to be used by the completion service?

Copy link
Member

@weswigham weswigham Sep 16, 2019

Choose a reason for hiding this comment

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

I think getContextualType is still right, we just need to avoid using any resolved signature caches.

@orta
Copy link
Contributor

orta commented Sep 24, 2019

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Sep 24, 2019

Heya @orta, I've started to run the tarball bundle task on this PR at 96a782e. You can monitor the build here. It should now contribute to this PR's status checks.

@andrewbranch
Copy link
Member

Hey @timsuchanek, I took a stab at addressing @weswigham’s concerns with some guidance from @DanielRosenwasser. I didn’t want to push a more substantial change here so I branched off of this PR and pushed a new one up at #33937. Would greatly appreciate your input there. Thanks!

@andrewbranch
Copy link
Member

@timsuchanek, thanks for championing this through! Your commits here have been merged into master via #33937. 🏆

@timsuchanek
Copy link
Contributor Author

Thanks a lot, @andrewbranch for pushing this over the finish line!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Autocompletion broken for generic function parameter with optional properties