Do not register ambient classes to the TS scope (#10352)

This commit is contained in:
Nicolò Ribaudo 2019-08-21 00:22:47 +02:00 committed by Brian Ng
parent 11ed2e2bf5
commit 15aa511b8e
10 changed files with 468 additions and 8 deletions

View File

@ -20,6 +20,7 @@ import {
SCOPE_OTHER, SCOPE_OTHER,
SCOPE_SIMPLE_CATCH, SCOPE_SIMPLE_CATCH,
SCOPE_SUPER, SCOPE_SUPER,
type BindingTypes,
} from "../util/scopeflags"; } from "../util/scopeflags";
const loopLabel = { kind: "loop" }, const loopLabel = { kind: "loop" },
@ -1611,11 +1612,12 @@ export default class StatementParser extends ExpressionParser {
node: N.Class, node: N.Class,
isStatement: boolean, isStatement: boolean,
optionalId: ?boolean, optionalId: ?boolean,
bindingType: BindingTypes = BIND_CLASS,
): void { ): void {
if (this.match(tt.name)) { if (this.match(tt.name)) {
node.id = this.parseIdentifier(); node.id = this.parseIdentifier();
if (isStatement) { if (isStatement) {
this.checkLVal(node.id, BIND_CLASS, undefined, "class name"); this.checkLVal(node.id, bindingType, undefined, "class name");
} }
} else { } else {
if (optionalId || !isStatement) { if (optionalId || !isStatement) {

View File

@ -14,8 +14,9 @@ import {
BIND_TS_CONST_ENUM, BIND_TS_CONST_ENUM,
BIND_TS_TYPE, BIND_TS_TYPE,
BIND_TS_INTERFACE, BIND_TS_INTERFACE,
BIND_TS_FN_TYPE, BIND_TS_AMBIENT,
BIND_TS_NAMESPACE, BIND_TS_NAMESPACE,
BIND_CLASS,
} from "../../util/scopeflags"; } from "../../util/scopeflags";
import TypeScriptScopeHandler from "./scope"; import TypeScriptScopeHandler from "./scope";
@ -1278,6 +1279,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
/* declarationPosition */ true, /* declarationPosition */ true,
); );
case tt._class: case tt._class:
// While this is also set by tsParseExpressionStatement, we need to set it
// before parsing the class declaration to now how to register it in the scope.
nany.declare = true;
return this.parseClass( return this.parseClass(
nany, nany,
/* isStatement */ true, /* isStatement */ true,
@ -1552,7 +1556,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
checkFunctionStatementId(node: N.Function): void { checkFunctionStatementId(node: N.Function): void {
if (!node.body && node.id) { if (!node.body && node.id) {
this.checkLVal(node.id, BIND_TS_FN_TYPE, null, "function name"); this.checkLVal(node.id, BIND_TS_AMBIENT, null, "function name");
} else { } else {
super.checkFunctionStatementId(...arguments); super.checkFunctionStatementId(...arguments);
} }
@ -1988,7 +1992,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return; return;
} }
super.parseClassId(...arguments); super.parseClassId(
node,
isStatement,
optionalId,
(node: any).declare ? BIND_TS_AMBIENT : BIND_CLASS,
);
const typeParameters = this.tsTryParseTypeParameters(); const typeParameters = this.tsTryParseTypeParameters();
if (typeParameters) node.typeParameters = typeParameters; if (typeParameters) node.typeParameters = typeParameters;
} }

View File

@ -25,7 +25,7 @@ class TypeScriptScope extends Scope {
// classes (which are also in .lexical) and interface (which are also in .types) // classes (which are also in .lexical) and interface (which are also in .types)
classes: string[] = []; classes: string[] = [];
// namespaces and bodyless-functions are too difficult to track, // namespaces and ambient functions (or classes) are too difficult to track,
// especially without type analysis. // especially without type analysis.
// We need to track them anyway, to avoid "X is not defined" errors // We need to track them anyway, to avoid "X is not defined" errors
// when exporting them. // when exporting them.

View File

@ -62,14 +62,14 @@ export const BIND_CLASS = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_
BIND_TS_INTERFACE = 0 | BIND_KIND_TYPE | 0 | BIND_FLAGS_CLASS , BIND_TS_INTERFACE = 0 | BIND_KIND_TYPE | 0 | BIND_FLAGS_CLASS ,
BIND_TS_TYPE = 0 | BIND_KIND_TYPE | 0 | 0 , BIND_TS_TYPE = 0 | BIND_KIND_TYPE | 0 | 0 ,
BIND_TS_ENUM = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_LEXICAL | BIND_FLAGS_TS_ENUM, BIND_TS_ENUM = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_LEXICAL | BIND_FLAGS_TS_ENUM,
BIND_TS_FN_TYPE = 0 | 0 | 0 | BIND_FLAGS_TS_EXPORT_ONLY, BIND_TS_AMBIENT = 0 | 0 | 0 | BIND_FLAGS_TS_EXPORT_ONLY,
// These bindings don't introduce anything in the scope. They are used for assignments and // These bindings don't introduce anything in the scope. They are used for assignments and
// function expressions IDs. // function expressions IDs.
BIND_NONE = 0 | 0 | 0 | BIND_FLAGS_NONE , BIND_NONE = 0 | 0 | 0 | BIND_FLAGS_NONE ,
BIND_OUTSIDE = BIND_KIND_VALUE | 0 | 0 | BIND_FLAGS_NONE , BIND_OUTSIDE = BIND_KIND_VALUE | 0 | 0 | BIND_FLAGS_NONE ,
BIND_TS_CONST_ENUM = BIND_TS_ENUM | BIND_FLAGS_TS_CONST_ENUM, BIND_TS_CONST_ENUM = BIND_TS_ENUM | BIND_FLAGS_TS_CONST_ENUM,
BIND_TS_NAMESPACE = BIND_TS_FN_TYPE; BIND_TS_NAMESPACE = 0 | 0 | 0 | BIND_FLAGS_TS_EXPORT_ONLY;
export type BindingTypes = export type BindingTypes =
| typeof BIND_NONE | typeof BIND_NONE
@ -81,5 +81,5 @@ export type BindingTypes =
| typeof BIND_TS_INTERFACE | typeof BIND_TS_INTERFACE
| typeof BIND_TS_TYPE | typeof BIND_TS_TYPE
| typeof BIND_TS_ENUM | typeof BIND_TS_ENUM
| typeof BIND_TS_FN_TYPE | typeof BIND_TS_AMBIENT
| typeof BIND_TS_NAMESPACE; | typeof BIND_TS_NAMESPACE;

View File

@ -0,0 +1,2 @@
declare class C { }
declare function C(): void;

View File

@ -0,0 +1,151 @@
{
"type": "File",
"start": 0,
"end": 47,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 27
}
},
"program": {
"type": "Program",
"start": 0,
"end": 47,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 27
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start": 0,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 19
}
},
"id": {
"type": "Identifier",
"start": 14,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 14
},
"end": {
"line": 1,
"column": 15
},
"identifierName": "C"
},
"name": "C"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start": 16,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 19
}
},
"body": []
},
"declare": true
},
{
"type": "TSDeclareFunction",
"start": 20,
"end": 47,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 27
}
},
"id": {
"type": "Identifier",
"start": 37,
"end": 38,
"loc": {
"start": {
"line": 2,
"column": 17
},
"end": {
"line": 2,
"column": 18
},
"identifierName": "C"
},
"name": "C"
},
"generator": false,
"async": false,
"params": [],
"returnType": {
"type": "TSTypeAnnotation",
"start": 40,
"end": 46,
"loc": {
"start": {
"line": 2,
"column": 20
},
"end": {
"line": 2,
"column": 26
}
},
"typeAnnotation": {
"type": "TSVoidKeyword",
"start": 42,
"end": 46,
"loc": {
"start": {
"line": 2,
"column": 22
},
"end": {
"line": 2,
"column": 26
}
}
}
},
"declare": true
}
],
"directives": []
}
}

View File

@ -0,0 +1,2 @@
declare class C { }
function C() { }

View File

@ -0,0 +1,137 @@
{
"type": "File",
"start": 0,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 16
}
},
"program": {
"type": "Program",
"start": 0,
"end": 36,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 16
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start": 0,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 19
}
},
"declare": true,
"id": {
"type": "Identifier",
"start": 14,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 14
},
"end": {
"line": 1,
"column": 15
},
"identifierName": "C"
},
"name": "C"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start": 16,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 19
}
},
"body": []
}
},
{
"type": "FunctionDeclaration",
"start": 20,
"end": 36,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 16
}
},
"id": {
"type": "Identifier",
"start": 29,
"end": 30,
"loc": {
"start": {
"line": 2,
"column": 9
},
"end": {
"line": 2,
"column": 10
},
"identifierName": "C"
},
"name": "C"
},
"generator": false,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 33,
"end": 36,
"loc": {
"start": {
"line": 2,
"column": 13
},
"end": {
"line": 2,
"column": 16
}
},
"body": [],
"directives": []
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
import Something from './somewhere.js'
declare class Something {}

View File

@ -0,0 +1,154 @@
{
"type": "File",
"start": 0,
"end": 66,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 26
}
},
"program": {
"type": "Program",
"start": 0,
"end": 66,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 26
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start": 0,
"end": 38,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 38
}
},
"specifiers": [
{
"type": "ImportDefaultSpecifier",
"start": 7,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 7
},
"end": {
"line": 1,
"column": 16
}
},
"local": {
"type": "Identifier",
"start": 7,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 7
},
"end": {
"line": 1,
"column": 16
},
"identifierName": "Something"
},
"name": "Something"
}
}
],
"source": {
"type": "StringLiteral",
"start": 22,
"end": 38,
"loc": {
"start": {
"line": 1,
"column": 22
},
"end": {
"line": 1,
"column": 38
}
},
"extra": {
"rawValue": "./somewhere.js",
"raw": "'./somewhere.js'"
},
"value": "./somewhere.js"
}
},
{
"type": "ClassDeclaration",
"start": 40,
"end": 66,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 26
}
},
"declare": true,
"id": {
"type": "Identifier",
"start": 54,
"end": 63,
"loc": {
"start": {
"line": 3,
"column": 14
},
"end": {
"line": 3,
"column": 23
},
"identifierName": "Something"
},
"name": "Something"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start": 64,
"end": 66,
"loc": {
"start": {
"line": 3,
"column": 24
},
"end": {
"line": 3,
"column": 26
}
},
"body": []
}
}
],
"directives": []
}
}