* Avoid circular reference in this-property assignments
To do this, don't check this-property assigments that have the
this-property of the lhs appearing somewhere on the rhs:
```js
class C {
m() {
this.x = 12
this.x = this.x + this.y
}
}
```
I tried suppressing the circularity error, but because we cache the
first type discovered for a property, this still results in an implicit
any for `x` in the previous example. It just doesn't have an error.
Fixes#35099
* Add test case + rename function
* Use isMatchingReference
* Fix crash for private identifier in expando assignments
It does this by disallowing private identifiers from expando assignments
entirely. I haven't thought of a scenario where they make sense, but I
haven't thought about it exhaustively either.
Fixes#37356
* Update baselines
I think the new error is probably better. It's certainly different!
Prevent it from using the (return) type of a function. Could also check
the condition before calling the function, but there are two places that
need the check, and OTOH, all calls check the result so returning
`undefined` should work.
(This problem was introduced in PR#32553.)
Fixes#33741.
* Ignore @private on constructor functions
This was incorrect in the best of circumstances and caused a crash when
the parent of the function had no symbol, because the accessibility
check assumed it was operating on a constructor and that the parent was
always the containing class.
* Non-constructors are always accessible
Previously, all function-like kinds were accessible, which includes
constructors. This was wrong.
Top-level this-assignments do not support computed properties. But the
binder forgets to check for computed properties and tries to bind them
normally. This hits a helpful assert.
This change stop binding this-properties with computed properties at the
top-level. There's nothing sensible we could do with them; we're unable
to late-bind entries to the global scope or to modules.
The constructor function code path in the return type checking of
signatures needs to pass the *merged* symbol of the declaration to
getDeclaredTypeOfClassOrInterface. Other callers of
getDeclaredTypeOfClassOrInterface do this, or used an already-merged
symbol.
Fixes#33993
* Fix crash in expando assignment to alias
This PR disallows expando assignments
Fixes#34493, but disallows the prototype assignment nonetheless.
* Revert mistaken changes
* Fix stack overflow in circular assignment declaration
It also needs to have multiple assignments so that it has a ValueModule
flag.
Fixes#33006
* remove errant comment
* Remove other possible circularity
* Restore fallback with additional condition
* migrate nullish coalescing commit
* add more test case
* add branch type check test
* add more tests
* fix nullish precedence
* update public api
* add rescan question question token to fix regression
* update public api baseline
* Added tests that emit for nullish coalescing operator conforming with grammar restrictions when assertions are used.
* Fixed emit to hoist temporary variables (they previously went undeclared).
Added tests to ensure calls and property accesses are only called once.
* use not equal to null
* rename factory
* add grammar check
* fix more cases
* Fix handling of nullish coalescing oprator in expando objects.
* Fixed classifier to support ?? operator.
* update baseline
* accept baseline
* fix review
* update emitter and more testcase
* update control flow
* make linter happy
* update libs
* avoid unnecessary assert
* fix typooo
* Fixes for control-flow analysis
* Start enabling element access special assignment
* Treat element access assignment as special assignment in JS
* Make declarations for bindable element access expressions
* Fix navigationBar crash
* Add multi-level test for JS
* Propagate element access expressions to more code paths
* Fix property access on `this`
* Add quick info test
* Uhhh I guess this is fine
* Fix module["exports"] and property access chained off element access
* Add test for this property assignment
* Add test for and fix prototype property assignment
* Fix teeeest???
* Update APIs
* Fix element access declarations on `this`
* Fix go-to-definition
* Add declaration emit to tests
* Reconcile with late-bound symbol element access assignment
* Fix baselines
* Add JS declaration back to tests
* Fix JS declaration emit of non-late-bound string literal property names
* Revert accidental auto-format
* Use `isAccessExpression`
* Add underscore escaping member to test
* Fix and test navBar changes
* Support some late-bound special property assignments
* Integrate PR feedback
* PR feedback
* Enable declaration on core tests
* Specialize type of binary expression used for late binding, speculative fix to navigation bar, merge check and type for elem/property accesses
* Add test showing current nav bar behavior (specifically the lack thereof)
* Fix constructor function type reference lookup
I knew I missed some code in the constructor-functions-as-classes PR.
This simplifies the type reference resolution code as well.
* Simplify and document js alias type resolution
* Cache JS inferred class type symbol
Note that many sources merge into a single target, so the *source*
[links] is the one that caches the merged target.
The reason this is a problem is not that many sources merge into a
single target, but that both getTypeOfSymbol and getDeclaredTypeOfSymbol
end up calling mergeJSSymbols with the same [source,target] pair. The
merge should not happen twice.
* Remove more verbose debug assertion message
* Fix isJSConstructor check + update baselines
* inferClassSymbol cache now track multiple targets
* Initial implementation
The original test passes but I haven't run any other tests yet, so I
assume the world is now broken.
* Append constructor function construct sigs
Instead of overwriting them
* Grab bag of improvements.
1. Mark @class-tagged functions with Class too.
2. Only gather local type parameters of constructor functions.
3. Remove getJSClassType calls with getDeclaredTypeOfSymbol.
4. Add a couple more failing tests.
getDeclaredTypeOfClassOrInterface now needs to understand prototype
assignment. That's next, I think.
* Prototype assignments work now
1. Binder marks prototype assignments as Class now.
2. Checker merges prototype assignments using the same merge code as for
functions and their declarations. No more intersections.
Many fewer failing tests now.
* Mark prototype-property assignments as Class
Even if there are no this-property assignments in them. (Then why are
you using a class?).
* Simplify getJSClassType, remove calls to its guts
It's probably not needed because now it's just a conditional call to
getDeclaredTypeOfSymbol, and I think most callers already know whether
they have a JS constructor function beforehand.
* isJSDocConstructor doesn't need to check prototype anymore
Because all the properties are merged during getDeclaredTypeOfSymbol.
* outer type parameter lookup follow prototype assignment
* this-type and -expression support in ctor funcs
Pretty cool!
* Fix remaining tests
* Fix minor lint
* Delete now-unused code
* Add class flag to nested class declarations
Also remove old TODOs
* Property assignment uses parent type annotation
First draft, will write full explanation later.
Also makes sure that jsdoc is ignored in TS. It was not before.
* Update baselines
* Fix infinite loop: module.exports alias detection
Previously, module.exports alias detection in the binder could enter an
infinite recursion. Now it does not.
Notably, there are *two* safeguards: a counter limiter that I set at
100, and an already-seen set. I actually prefer the counter limiter code
because it's foolproof and uses less memory. But it takes 100
iterations to escape from loops.
* fix space lint
* Remove already-seen map
* Restore original code from bind-toplevel-this
With one or two additional comments
* Working in JS, but the symbol is not right.
Still need to
1. Make it work in Typescript.
2. Add test (and make them work) for the other uses of GlobalThis:
window, globalThis, etc.
* Check in TS also; update some tests
Lots of tests still fail, but all but 1 change so far has been correct.
* Update baselines
A couple of tests still fail and need to be fixed.
* Handle type references to globalThis
The type reference must be `typeof globalThis`. Just `globalThis` will
be treated as a value reference in type position -- an error.
* Restore former behaviour of implicitThis errors
I left the noImplicitThis rule for captured use of global this in an
arrow function, even though technically it isn't `any` any more --
it's typeof globalThis. However, you should still use some other method
to access globals inside an arrow, because captured-global-this is super
confusing there.
* Test values with type globalThis
I ran into a problem with intersecting `Window & typeof globalThis`:
1. This adds a new index signature to Window, which is probably not
desired. In fact, with noImplicitAny, it's not desired on globalThis
either I think.
2. Adding this type requires editing TSJS-lib-generator, not this repo.
So I added the test cases and will probably update them later, when
those two problems are fixed.
* Add esnext declaration for globalThis
* Switch to symbol-based approach
I decided I didn't like the import-type-based approach.
Update baselines to reflect the difference.
* Do not suggest globals for completions at toplevel
* Add tests of element and property access
* Look up globalThis using normal resolution
globalThis is no longer constructed lazily. Its synthetic Identifier
node is also now more realistic.
* Update fourslash tests
* Add missed fourslash test update
* Remove esnext.globalthis.d.ts too
* Add chained globalThis self-lookup test
* Attempt at making globalThis readonly
In progress, had to interrupt for other work.
* Add/update tests
* Addres PR comments:
1. Add parameter to tryGetThisTypeAt to exclude globalThis.
2. Use combined Module flag instead combining them in-place.
3. SymbolDisplay doesn't print 'module globalThis' for this expressions
anymore.
Previously, the compiler would crash when binding a non-top-level
property assignment on the symbol of an unresolved module:
```js
import x from 'arglebaz'
{
x.bar = 1
}
```
That's because `x` looks like an alias but doesn't have a
valueDeclaration (since there is no file named 'arglebaz'), and the new
code for binding Object.defineProperty calls forgot to check for an
undefined valueDeclaration.
This change adds the checks for an undefined valueDeclaration.
* Do not merge commonsjs exports onto an alias
getCommonJSExportEquals merges export assignments and export property
assignments. Something like this, which has no equivalent structure in
TS:
```js
module.exports = function() { }
module.exports.expando = 1
```
However, it is sometimes called with an alias, when its
parent, resolveExternalModuleSymbol, is called with dontResolveAlias:
true, and when the initialiser of the export assignment is an alias:
```js
function alias() { }
module.exports = alias
module.exports.expando = 1
```
In this case, (1) the actual value `alias` will have already merged in a
previous call to getCommonJSExportEquals and
(2) getTypeOfSymbol will follow the alias symbol to get the right type.
So getCommonJSExportEquals should do nothing in this case.
This bug manifests in the code for dynamic imports, which calls
getTypeOfSymbol on the incorrectly merged alias, which now has enough
value flags--Function, for example--to take the wrong branch and
subsequently crash.
* Update baselines
In JS, when you assign `module.exports = exports` and the entire module is
wrapped in an IIFE, the resulting `export=` symbol, after following
aliases, is the module itself. This results in trying to merge the
file's exports with itself inside `getCommonJsExportEquals`, since it
thinks that it has found new exports, possibly in an object literal,
that need to be merged with the file's exports.
For example:
```js
(function() {
exports.a = 1
module.exports = exports
})()
```
1. Merge enum with expando.
2. Merge enum member with property assignment.
3. Merge interface-declared method declaration with
prototype-property-assignment method declaration.
The reason that the enum merges crash is that getTypeOfSymbol assumes
that symbol flags are (basically) mutually exclusive. This assumption is
shredded, badly, for JS merges.
One fix is to drop the assumption of exclusivity and instead order cases
by least to most likely. This has the highest chance of working, but is
also slow, since you would prefer to order cases by most likely *first*,
not *last*.
The other fix, which is what I did here, is to add a last-chance
re-dispatch at the bottom of
`getTypeOfVariableOrParameterOrPropertyWorker`. This dispatch uses the
valueDeclaration instead of the symbol flags.
* Add helpers that understand constructor functions
* getEffectiveConstructSignatures gets construct signatures from type, and
call signatures from constructor functions if there are no construct
signatures.
* getEffectiveConstructSignatureReturnType gets the "JS Class type" for
constructor functions, and the return type of signatures for all other
declarations.
This is a first step toward making constructor functions have construct
signatures instead of call signatures, which will also contribute to
fixing instantiation of generic constructor functions, which is basically
broken right now.
Note that the baselines *improve* but, because of the previously
mentioned generic problem, are still not correct. Construct signatures
for constructor functions and generic constructor functions turns out to
be an intertwined problem.
* Correct correct originalBaseType
And, for now, return anyType for generic constructor functions used as
base types. Don't give an incorrect error based on the function's return
type, which is usually void.
* Add error examples to tests
* Add construct signatures instead of getEffective* functions
* Fix typo in baseline
* Remove pesky newline
I thought I got rid of it!
* Test of constructor tag on object literal method
It doesn't work, and shouldn't in the future, because it's a runtime
error.
The check for prototype assignment on constructor functions assumes
that the prototype property, if present, comes from an assignment
declaration, such as:
```js
SomeClass.prototype = { /* methods go here */ }
```
In this case, however, when class SomeClass and var SomeClass merge
(because this is allowed), prototype is the synthetic property from
class SomeClass, which has no valueDeclaration.
The fix is to check that prototype has a valueDeclaration before
checking whether the valueDeclaration is in fact a prototype-assignment
declaration.
I'm surprised we haven't seen more of this; I suspect it's because the
mixed `module.exports=` + `export.foo=` pattern isn't that common.
However, it'll happen any time that the exported symbol is unknown;
getCommonJsExportEquals blithely clones unknownSymbol and proceeds to
stick the `exports.foo=` properties onto it.
This causes problems later, because the compiler checks for
unknownSymbol with `===`. The fix is to not stick properties onto a
clone of unknownSymbol. This makes the correct errors appear and removes
the crash.
* Fix non-toplevel prototype assignment
binder was using the wrong node to lookup the containing class type for
prototype assignment, so it incorrectly put the prototype declaration on
the class' symbol.
This correction to the binder in turn required a change in
getJSClassType in the checker. It now has to look at the "prototype"
property for the prototype instead of looking on the class symbol's exports
(which makes no sense).
* Refactor per PR suggestion
* Fix cross-file merge of assignment decl valueDeclaration
Previously mergeSymbol in the checker always updated valueDeclaration if
target.valueDeclaration was an assignment declaration. The binder only
updates target.valueDeclaration if it is an assignment declaration and
source.valueDeclaration is *not* an assignment declaration. Now the
checker behaves the same way as the binder.
* Update baselines
* Add a fix for #27099
Makes commonjs merge with globals when appropriate.
* Add a separate jsGlobalAugmentations table
Instead of trying to filter these augmentations out of the normal symbol
table of commonjs modules.
* Fix this-type in prototype-assigned object literals
Some cases were missing from tryGetThisTypeAt.
Fixes#26831
* Lookup this in JS only for @constructor+prototype assignments
* Bind non-expando property assignments at toplevel
Previously, only property assignments with expando initialisers were
bound in top-level statements. Now, all property assignments are bound.
This requires a matching change in the checker to make sure that these
assignments remain context sensitive if their valueDeclaration is a
'real' declaration (ie a non assignment-declaration).
* Add baselines for new test
* Allow JSContainers to merge with namespaces
Expando functions marked with JSContainer previously failed to merge
with namespaces. This change adds JSContainer to ValueModuleExcludes,
allowing this kind of merge.
* Improve symbol flags to fix namespace/expando merging
Calls to bindPropertyAssignment now provide which special assignment
kind they originated from. This allows better symbol flags to be set:
1. Property assignments get the FunctionScopedVariable flag, since they are
equivalent to a `namespace` exporting a `var`.
2. Prototype property assignments get the Method flag if the initialiser
is functionlike, and Property otherwise.
3. Prototype assignments get the flag Property.
(3) is still not entirely correct (it's missing the Prototype flag),
but is what existed previously. I'll try adding the Prototype flag to
see whether it changes any baselines.
* Add cross-file merge test
* Update missed baselines
* Namespace declarations are primary for merging purposes
Also, property-assignments go back to being property declarations, not
function-scoped variable declarations
* Revert unneeded changes
* Revert unneeded changes (in a codefix this time)
* Put JSContainer on all assignment declarations
This allows most of the new special-case merge code to go away. It now
uses the JSContainer special-case code, which already exists.
* Missed comment
* Fix extra newline lint
in object literal methods inside an object literal with a type
annotation.
Note that this does not change:
1. The type of `this` in object literal methods.
2. The fact that this-property assignments are still declarations. They
just don't block contextual typing like most declarations do.
This change is a bit expensive. It first calls getThisContainer, which
walks the tree upward. Then it calls checkThisExpression, which will
usually call getContextualType on the object literal method. If the new
code then returns true, it will proceed to redo much of that work.
Calling checkThisExpression should not cause incorrect circularity
failures; we only have to inspect the shape of the object literal and
not the types of its properties to determine its type.
* Declaration emit includes function properties
It does this by printing the type as an object literal type:
```ts
function f() { }
f.p = 1
```
Appears in a d.ts as
```ts
declare var f: {
(): void;
p: number;
}
```
It would also be possible to represent it as a namespace merge. I'm not
sure which is better.
```ts
declare function f(): void;
declare namespace f {
export var p: number;
}
```
In order to avoid a private-name-used error (though I think it was
actually *unused*), I also had to change the nodeBuilder code to match.
This is arguably harder to read. So it's possible that I should instead
keep the nodeBuilder version as `typeof f` and make an exception for
private name use.
* Emit namespace merge instead of object type
This makes the change smaller, overall.
* Fix isJSContainerFunctionDeclaration+namespace merges
Also improve emit style to match other namespace emit.
* Add isPrivate + test case from PR comments
Previously, getWidenedTypedFromJSPropertyAssignment was not called for
Typescript code. Since property assignments on functions, it is. That
meant that property assignments would incorrectly create a JS container
for empty object literals in a property assignment, even in Typescript:
```ts
const one = () => 1
one.p = {}
one.p.q = {} // should not work in Typescript!
```
Now empty object literals never create expando objects in Typescript,
because getJSExpandoObjectType requires the declaration to be in a JS
file.
Previously, they were mistakenly treated as private because of a check
that required all super property accesses (like `super.x()`) to be
references to a MethodDeclaration or MethodSignature. This change also
allows PrototypeProperty special assignment kinds.
* Allow special property assignments in TS
But only for functions and constant variable declarations initialised with
functions.
This specifically excludes class declarations and class expressions,
which differs from Javascript. That's because Typescript supports
`static` properties, which are equivalent to property assignments to a
class.
* Improve contextual typing predicate
Don't think it's right yet, but probably closer?
* More fixes.
The code is still fantastically ugly, but everything works the way it
should.
Also update baselines, even where it is ill-advised.
* Cleanup
* Remove extra whitespace
* Some kind of fix to isAnyDeclarationName
It's not done yet.
Specifically, in TS:
Special property assignments are supposed to be declaration sites (but not all
top-level assignments), and I think I
got them to be. (But not sure).
In JS:
Special property assignments are supposed to be declaration sites (but not all
top-level assignments), and I'm pretty sure ALL top-level assignments
have been declaration sites for some time. This is incorrect, and
probably means the predicate needs to be the same for both dialects.
* Add fourslash and improve isAnyDeclarationName
Now JS behaves the same as TS.
* Cleanup from PR comments
* This-property w/empty object init: use type annotation
* JS initializer type doesn't apply to this-property assignments
* Move getJSExpandoType into getWidenedType* functions
Plus some cleanup.
* Improved style from PR comments
* Parameters are not expando
* Classes can extend JS constructor functions
Now ES6 classes can extend ES5 constructor functions, although only
those written in a JS file.
Note that the static side assignability is checked. I need to write
tests to make sure that instance side assignability is checked too.
I haven't tested generic constructor functions yet either.
* Test static+instance assignability errors+generics
Note that generics do not work.
* Cleanup from PR comments
* Even more cleanup
* Update case of function name
* Fixes#26122.
When `resolveCall` does not resolve in `resolveNewExpression`, the error should only be thrown if there is a *defined* signature that is not-void.
* Fix other baselines to remove erroneous TS2350.
* Properly infer `this` in tagged `@constructor`s.
`c.prototype.method = function() { this }` was already supported.
This commit add support to two more kinds relying on the JSDoc
`@constructor` tag. These are:
1. `/** @constructor */ function Example() { this }`
2. `/** @constructor */ var Example = function() { this }`
* Update the baseline for js constructorFunctions.
C3 and C4 `this` was set as `any`, now it is properly showing as
the class type.
* Fix lint errors
* Add circular initialisers to constructo fn tests.
* Error (`TS2348`) if calling tagged js constructors
When calling a JS function explicitly tagged with either `@class` or
`@constructor` the checker should throw a TS2348 not callable error.
* Don't resolve jsdoc classes with construct sigs.
This undoes the last commit that sought to change how js functions
tagged with `@class` were inferred. For some reason, currently
unknown, giving those functions construct signatures causes issues
in property assignment/member resolution (as seen in the
`typeFromPropertyAssignment12` test case).
Instead of changing the signature resolution, the error is explicitly
generated in `resolveCallExpression` for those functions.
* Only bind module.exports if no local definition exists
Note that this uses `lookupSymbolForNameWorker`, which is really a
best-effort check since it only knows about symbols that it has already
encountered.
As a side-effect, even when `module` is bound as part of a
`module.exports` reference, it only declares it once instead of one
declaration per reference.
* Only type module.exports inside module files
It is an error inside script files, but the binder sometimes creates a
ModuleExports symbol because we doesn't know whether we have a commonjs
module until after binding is done.
* Only bind module.exports in a commonjs module
Note that this, too, is a best-effort check since evidence of
commonjs-ness may be found after a *reference* to module.exports. (A
reference to module.exports alone is not enough evidence that a file is
commonjs. It has to have an assignment to it.)
* Revert "Revert "Explicitly typed special assignments are context sensitive (#25619)""
This reverts commit 16676f2707.
* Revert "Revert "Explicitly typed prototype assignments are context sensitive (#25688)""
This reverts commit ff8c30d636.
* Initial, wasteful, solution
It burns a check flags. Probably necessary, but perhaps not.
I haven't accepted baselines, but they are a bit questionable. I'm not
sure the synthetic type is right, because I expected to see
{ "exports": typeof import("x") } but instead see { "x": typeof
import("x") }.
* Update some baselines
* module.exports= always uses lhs type
Conflicts between exports property assignments and exports assignments
should get a union type instead of an error.
* Fix lint and accept good user baselines
* Add tests based on user tests.
These currently fail.
* Fix all but 1 of user test bugs found by typing module.exports
Still quite messy and full of notes
* Follow merged symbols+allow any object type
This allows exports like `module.exports = new EE` to have properties
added to them.
Still messy, but I'm going to run user tests and look for regressions.
* Update improved user baselines
* Fix infinite recursion when checking module.exports
* Fix bogus use-before-def error
getExportSymbolOfValueSymbolIfExported should always merge its returned
symbol, whether it's symbol.exportSymbol or just symbol.
* Update user test baselines
* Cleanup
* More small cleanup
* Bind `module` of `module.exports` as a special symbol
Previously it was also special, but created during name resolution in
the checker. It made sense when there was only one special symbol for
all files, but now there is one `module` symbol per file.
* Explicitly typed prototype assignments:ctx sensitive
Follow up to #25619: Add the necessary code to type `prototype`
correctly in prototype assignments so that code like
`F.prototype = { ... }` properly makes the object literal context
sensitive.
* Fix lint