Skip to content
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

Fix js missing type arguments on existing nodes and jsdoc object literal declaration emit #38368

Merged
merged 4 commits into from
May 8, 2020

Conversation

weswigham
Copy link
Member

Fixes #38356

@DanielRosenwasser
Copy link
Member

Not sure if we baseline outputs for .d.ts files but

@typescript-bot test this
@typescript-bot user test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 6, 2020

Heya @DanielRosenwasser, I've started to run the parallelized community code test suite on this PR at c827007. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 6, 2020

Heya @DanielRosenwasser, I've started to run the extended test suite on this PR at c827007. You can monitor the build here.

@weswigham
Copy link
Member Author

Not sure if we baseline outputs for .d.ts files

We do not. Extended test suites are entirely useless for observing changes in jsdoc declaration emit~

@DanielRosenwasser
Copy link
Member

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 6, 2020

Heya @DanielRosenwasser, I've started to run the tarball bundle task on this PR at c827007. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master.

@weswigham
Copy link
Member Author

@typescript-bot cherry-pick this to release-3.9

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 6, 2020

Heya @weswigham, I've started to run the task to cherry-pick this into release-3.9 on this PR at c827007. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

Hey @weswigham, I've opened #38372 for you.

typescript-bot pushed a commit to typescript-bot/TypeScript that referenced this pull request May 6, 2020
Component commits:
c827007 Fix js missing type arguments on existing nodes and jsdoc object literal declaration emit
@@ -5503,6 +5503,10 @@ namespace ts {
return symbol.declarations && find(symbol.declarations, s => !!getEffectiveTypeAnnotationNode(s) && (!enclosingDeclaration || !!findAncestor(s, n => n === enclosingDeclaration)));
}

function getExistingNodeHasNoTypeParametersOrMatchingTypeParameters(existing: TypeNode, type: Type) {
return !(getObjectFlags(type) & ObjectFlags.Reference) || !isTypeReferenceNode(existing) || length(existing.typeArguments) >= getMinTypeArgumentCount((type as TypeReference).target.typeParameters);
Copy link
Member

Choose a reason for hiding this comment

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

This is kinda surprising to me - this checks whether the existing type has more type arguments which I'd assume to be the opposite condition.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, if the existing declaration provides the minimum required or more, it's good to reuse; how's that surprising?

Copy link
Member

Choose a reason for hiding this comment

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

Maybe it's a naming issue? What is the meaning of hasNoTypeParameters in this case?

@@ -5503,6 +5503,10 @@ namespace ts {
return symbol.declarations && find(symbol.declarations, s => !!getEffectiveTypeAnnotationNode(s) && (!enclosingDeclaration || !!findAncestor(s, n => n === enclosingDeclaration)));
}

function getExistingNodeHasNoTypeParametersOrMatchingTypeParameters(existing: TypeNode, type: Type) {
Copy link
Member

Choose a reason for hiding this comment

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

Should this start with the word get?

Copy link
Member Author

@weswigham weswigham May 7, 2020

Choose a reason for hiding this comment

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

By convention, yes - pretty much all of our complex internal functions start with verbs, get, create, serialize, and so on.

It makes completions easier to trigger, tbh.

Copy link
Member

@DanielRosenwasser DanielRosenwasser May 7, 2020

Choose a reason for hiding this comment

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

What about predicate functions like typeHasCallOrConstructSignatures? Doesn't seem appropriate to start with a get here IMO

Copy link
Member

Choose a reason for hiding this comment

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

but emacs doesn't show completions until I've typed 3 characters!

Copy link
Member Author

Choose a reason for hiding this comment

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

I renamed it to existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount which surely isn't a mouthful. I hope the removal of the verb is to your liking?

Copy link
Member

Choose a reason for hiding this comment

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

named perfectly!

@Jack-Works
Copy link
Contributor

Hi! @weswigham There're also some invalid JSDoc basic type generation, can you also check this out?

/** @type {Boolean} */const bool = true;
/** @type {bool} */const bool2 = true;

/** @type {Object} */const obj = true;

/** @type {String} */const str = true;

/** @type {Function} */const f = true;
/** @type {function} */const f2 = true;

/** @type {class} */const clz = true;

/** @type {int} */const x3 = true;
/** @type {float} */const x4 = true;
/** @type {Number} */const x5 = true;
/** @type {integer} */const x6 = true;

Code

/** @type {Boolean} */ declare const bool: Boolean; // expect boolean
/** @type {bool} */ declare const bool2: bool; // expect boolean

/** @type {Object} */ declare const obj: Object; // expect object

/** @type {String} */ declare const str: String; // expect string

/** @type {Function} */ declare const f: Function; // expect (...args:  any[]) => any
/** @type {function} */ declare const f2: function; // ! Invalid output ! expect (...args:  any[]) => any

/** @type {class} */ declare const clz: any; // expect { new (...args: any[]): any }

/** @type {int} */ declare const x3: any; // expect number
/** @type {float} */ declare const x4: any; // expect number
/** @type {Number} */ declare const x5: Number; // expect number
/** @type {integer} */ declare const x6: any; // expect number

I found this when I generate types for a real world JSDoc project, it's nice if TypeScript can handle this.

(My code generation project)
image

@weswigham
Copy link
Member Author

I... Don't think we recognize int or float. But the others... Yeah, ok.

@weswigham
Copy link
Member Author

@Jack-Works I've added an explicit testcase for our declaration emit for all the special lookups (as enumerated in our codebase), and included extra entries for the types you mention which we don't currently recognize, including class, bool, int, integer, float, and event (all of which are lookup failures, except event which is coincidentally the name of a global we return the type of, Event | undefined).

/** @type {function} */ declare const h: Function;
/** @type {array} */ declare const i: any[];
/** @type {promise} */ declare const j: Promise<any>;
/** @type {Object<string, string>} */ declare const k: {
Copy link
Contributor

@Jack-Works Jack-Works May 8, 2020

Choose a reason for hiding this comment

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

What about add a Object => object?

Copy link
Member Author

Choose a reason for hiding this comment

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

That's actually not a thing we interpret - Object with type arguments is interpreted as an index signature, without isn't recognized special (so it looks up the global Object constructor type, which is the apparent type of... pretty much everything except null and undefined) except when noImplicitAny is false, where it is any.

getIntendedTypeFromJSDocTypeReference in the checker has the special jsdoc types that we lookup in it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, but the handbook says

Don’t ever use the types Number, String, Boolean, Symbol, or Object These types refer to non-primitive boxed objects that are almost never used appropriately in JavaScript code.

Instead of Object, use the non-primitive object type (added in TypeScript 2.2).

Copy link
Member

@DanielRosenwasser DanielRosenwasser May 8, 2020

Choose a reason for hiding this comment

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

I think that the point is to test out stuff might people write in JSDoc, because people often write terrible stuff in JSDoc because it was terribly specified.

@@ -40,14 +40,14 @@ lf.Transaction = function() {};
* @return {!IThenable}
*/
lf.Transaction.prototype.begin = function(scope) {};
>lf.Transaction.prototype.begin = function(scope) {} : (scope: Array<lf.schema.Table>) => any
>lf.Transaction.prototype.begin = function(scope) {} : (scope: Array<any>) => any
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it a regression?

Copy link
Member Author

Choose a reason for hiding this comment

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

lf.schema.Table doesn't actually exist in the test, so we were preserving a node that failed to resolve anyway. Technically we could keep it (since it's an error anyway), but since i changed the default for jsdoc type which fail to resolve in not-jsdoc to serialize the resolved type, it now prints back as the any the failed resolution returns.

@@ -1,7 +1,7 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/** @param {Image} image */
function process(image) {
>process : (image: Image) => HTMLImageElement
>process : (image: new (width?: number, height?: number) => HTMLImageElement) => HTMLImageElement
Copy link
Contributor

Choose a reason for hiding this comment

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

👀

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, Image is a constructor with no associated interface, and jsdoc lookup is strange. So, in TS, (image: Image) => HTMLImageElement will issue a Image is not a type error (because it's not). So we gotta serialize the type the jsdoc resolver resolved to instead of keeping the input node.

@DanielRosenwasser
Copy link
Member

@typescript-bot cherry-pick this to release-3.9

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 8, 2020

Heya @DanielRosenwasser, I've started to run the task to cherry-pick this into release-3.9 on this PR at 04e6b6f. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

Hey @DanielRosenwasser, I couldn't open a PR with the cherry-pick. (You can check the log here). You may need to squash and pick this PR into release-3.9 manually.

typescript-bot pushed a commit to typescript-bot/TypeScript that referenced this pull request May 8, 2020
Component commits:
c827007 Fix js missing type arguments on existing nodes and jsdoc object literal declaration emit

128ef93 Merge branch 'master' into js-declaration-fixes-mk2

a90f97c Add special lookups test case, rename helper

04e6b6f Accept slightly modified baselines
@weswigham weswigham merged commit 7b03835 into microsoft:master May 8, 2020
DanielRosenwasser added a commit that referenced this pull request May 8, 2020
🤖 Pick PR #38368 (Fix js missing type arguments on ex...) into release-3.9
cangSDARM added a commit to cangSDARM/TypeScript that referenced this pull request May 12, 2020
* upstream/master: (54 commits)
  LEGO: check in for master to temporary branch.
  LEGO: check in for master to temporary branch.
  Fix for jsdoc modifiers on constructor params (microsoft#38403)
  Improve assert message in binder (microsoft#38270)
  fix broken regex on "src/services/completions.ts#getCompletionData" (microsoft#37546)
  report error for duplicate @type declaration (microsoft#38340)
  fix(38073): hide 'Extract to function in global scope' action for arrow functions which use 'this' (microsoft#38107)
  Update user baselines (microsoft#38472)
  Update user baselines (microsoft#38405)
  Changed template strings to emit void 0 instead of undefined (microsoft#38430)
  Fix js missing type arguments on existing nodes and jsdoc object literal declaration emit (microsoft#38368)
  LEGO: check in for master to temporary branch.
  Make isDynamicFileName available publicly (microsoft#38269)
  LEGO: check in for master to temporary branch.
  LEGO: check in for master to temporary branch.
  Exclude arrays and tuples from full intersection property check (microsoft#38395)
  Fix crash caused by assertion with evolving array type (microsoft#38398)
  Update user baselines (microsoft#38128)
  LEGO: check in for master to temporary branch.
  moveToNewFile: handle namespace imports too
  ...

# Conflicts:
#	src/compiler/types.ts
#	src/compiler/utilities.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Regression: DTS emit
7 participants