mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 11:35:42 -06:00
Support nested prototype declarations
And add a test for them
This commit is contained in:
parent
5af91a9e69
commit
116a8a8cff
@ -2040,7 +2040,7 @@ namespace ts {
|
||||
bindModuleExportsAssignment(node as BinaryExpression);
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.PrototypeProperty:
|
||||
bindPrototypePropertyAssignment(node as BinaryExpression);
|
||||
bindPrototypePropertyAssignment((node as BinaryExpression).left as PropertyAccessEntityNameExpression, node);
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.ThisProperty:
|
||||
bindThisPropertyAssignment(node as BinaryExpression);
|
||||
@ -2347,31 +2347,37 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindSpecialPropertyDeclaration(node: PropertyAccessExpression) {
|
||||
Debug.assert(isInJavaScriptFile(node));
|
||||
if (node.expression.kind === SyntaxKind.ThisKeyword) {
|
||||
bindThisPropertyAssignment(node);
|
||||
}
|
||||
else if ((node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression) &&
|
||||
node.parent.parent.kind === SyntaxKind.SourceFile) {
|
||||
else if (isEntityNameExpression(node) &&
|
||||
isPropertyAccessExpression(node.expression) &&
|
||||
node.expression.name.escapedText === "prototype" &&
|
||||
node.parent.parent.kind === SyntaxKind.SourceFile) {
|
||||
bindPrototypePropertyAssignment(node as PropertyAccessEntityNameExpression, node.parent);
|
||||
}
|
||||
else if (isEntityNameExpression(node) && node.parent.parent.kind === SyntaxKind.SourceFile) {
|
||||
bindStaticPropertyAssignment(node as PropertyAccessEntityNameExpression);
|
||||
}
|
||||
}
|
||||
|
||||
function bindPrototypePropertyAssignment(node: BinaryExpression) {
|
||||
// We saw a node of the form 'x.prototype.y = z'. Declare a 'member' y on x if x is a function or class, or not declared.
|
||||
|
||||
/**
|
||||
* For 'x.prototype.y = z', declare a 'member' y on x if x is a function or class, or not declared.
|
||||
* Note that jsdoc preceding an ExpressionStatement like `x.prototype.y;` is also treated as a declaration.
|
||||
*/
|
||||
function bindPrototypePropertyAssignment(lhs: PropertyAccessEntityNameExpression, parent: Node) {
|
||||
// Look up the function in the local scope, since prototype assignments should
|
||||
// follow the function declaration
|
||||
const leftSideOfAssignment = node.left as PropertyAccessEntityNameExpression;
|
||||
const classPrototype = leftSideOfAssignment.expression as PropertyAccessEntityNameExpression;
|
||||
// TODO: This cast is now insufficient for original case+nested case
|
||||
const classPrototype = lhs.expression as PropertyAccessEntityNameExpression;
|
||||
const constructorFunction = classPrototype.expression as Identifier;
|
||||
|
||||
// Fix up parent pointers since we're going to use these nodes before we bind into them
|
||||
leftSideOfAssignment.parent = node;
|
||||
lhs.parent = parent;
|
||||
constructorFunction.parent = classPrototype;
|
||||
classPrototype.parent = leftSideOfAssignment;
|
||||
classPrototype.parent = lhs;
|
||||
|
||||
bindPropertyAssignment(constructorFunction, leftSideOfAssignment, /*isPrototypeProperty*/ true);
|
||||
bindPropertyAssignment(constructorFunction, lhs, /*isPrototypeProperty*/ true);
|
||||
}
|
||||
|
||||
|
||||
@ -2448,10 +2454,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
const s = getJSInitializerSymbol(forEachIdentifierInEntityName(e.expression, action));
|
||||
if (!s || !s.exports) {
|
||||
// Not a valid nested special assignment
|
||||
return undefined;
|
||||
}
|
||||
Debug.assert(!!s && !!s.exports);
|
||||
return action(e.name, s.exports.get(e.name.escapedText));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
=== tests/cases/conformance/salsa/module.js ===
|
||||
var Outer = function(element, config) {};
|
||||
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 41))
|
||||
>element : Symbol(element, Decl(module.js, 0, 21))
|
||||
>config : Symbol(config, Decl(module.js, 0, 29))
|
||||
|
||||
/** @constructor */
|
||||
Outer.Pos = function (line, ch) {};
|
||||
>Outer.Pos : Symbol(Outer.Pos, Decl(module.js, 0, 41))
|
||||
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 41))
|
||||
>Pos : Symbol(Outer.Pos, Decl(module.js, 0, 41))
|
||||
>line : Symbol(line, Decl(module.js, 2, 22))
|
||||
>ch : Symbol(ch, Decl(module.js, 2, 27))
|
||||
|
||||
/** @type {number} */
|
||||
Outer.Pos.prototype.line;
|
||||
>Outer.Pos.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
|
||||
>Outer.Pos : Symbol(Outer.Pos, Decl(module.js, 0, 41))
|
||||
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 41))
|
||||
>Pos : Symbol(Outer.Pos, Decl(module.js, 0, 41))
|
||||
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
var pos = new Outer.Pos(1, 'x');
|
||||
>pos : Symbol(pos, Decl(module.js, 5, 3))
|
||||
>Outer.Pos : Symbol(Outer.Pos, Decl(module.js, 0, 41))
|
||||
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 41))
|
||||
>Pos : Symbol(Outer.Pos, Decl(module.js, 0, 41))
|
||||
|
||||
pos.line;
|
||||
>pos.line : Symbol((Anonymous function).line, Decl(module.js, 2, 35))
|
||||
>pos : Symbol(pos, Decl(module.js, 5, 3))
|
||||
>line : Symbol((Anonymous function).line, Decl(module.js, 2, 35))
|
||||
|
||||
|
||||
42
tests/baselines/reference/typeFromPropertyAssignment12.types
Normal file
42
tests/baselines/reference/typeFromPropertyAssignment12.types
Normal file
@ -0,0 +1,42 @@
|
||||
=== tests/cases/conformance/salsa/module.js ===
|
||||
var Outer = function(element, config) {};
|
||||
>Outer : { (element: any, config: any): void; Pos: (line: any, ch: any) => void; }
|
||||
>function(element, config) {} : { (element: any, config: any): void; Pos: (line: any, ch: any) => void; }
|
||||
>element : any
|
||||
>config : any
|
||||
|
||||
/** @constructor */
|
||||
Outer.Pos = function (line, ch) {};
|
||||
>Outer.Pos = function (line, ch) {} : (line: any, ch: any) => void
|
||||
>Outer.Pos : (line: any, ch: any) => void
|
||||
>Outer : { (element: any, config: any): void; Pos: (line: any, ch: any) => void; }
|
||||
>Pos : (line: any, ch: any) => void
|
||||
>function (line, ch) {} : (line: any, ch: any) => void
|
||||
>line : any
|
||||
>ch : any
|
||||
|
||||
/** @type {number} */
|
||||
Outer.Pos.prototype.line;
|
||||
>Outer.Pos.prototype.line : any
|
||||
>Outer.Pos.prototype : any
|
||||
>Outer.Pos : (line: any, ch: any) => void
|
||||
>Outer : { (element: any, config: any): void; Pos: (line: any, ch: any) => void; }
|
||||
>Pos : (line: any, ch: any) => void
|
||||
>prototype : any
|
||||
>line : any
|
||||
|
||||
var pos = new Outer.Pos(1, 'x');
|
||||
>pos : { line: number; }
|
||||
>new Outer.Pos(1, 'x') : { line: number; }
|
||||
>Outer.Pos : (line: any, ch: any) => void
|
||||
>Outer : { (element: any, config: any): void; Pos: (line: any, ch: any) => void; }
|
||||
>Pos : (line: any, ch: any) => void
|
||||
>1 : 1
|
||||
>'x' : "x"
|
||||
|
||||
pos.line;
|
||||
>pos.line : number
|
||||
>pos : { line: number; }
|
||||
>line : number
|
||||
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
// @noEmit: true
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @target: es6
|
||||
// @Filename: module.js
|
||||
var Outer = function(element, config) {};
|
||||
/** @constructor */
|
||||
Outer.Pos = function (line, ch) {};
|
||||
/** @type {number} */
|
||||
Outer.Pos.prototype.line;
|
||||
var pos = new Outer.Pos(1, 'x');
|
||||
pos.line;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user