Merge branch 'js-prototype-assignment' into js-object-literal-assignments-as-declarations

This commit is contained in:
Nathan Shively-Sanders 2018-02-23 09:24:09 -08:00
commit 5d32a3145e
27 changed files with 867 additions and 125 deletions

View File

@ -2042,6 +2042,9 @@ namespace ts {
case SpecialPropertyAssignmentKind.PrototypeProperty:
bindPrototypePropertyAssignment((node as BinaryExpression).left as PropertyAccessEntityNameExpression, node);
break;
case SpecialPropertyAssignmentKind.Prototype:
bindPrototypeAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.ThisProperty:
bindThisPropertyAssignment(node as BinaryExpression);
break;
@ -2360,15 +2363,23 @@ namespace ts {
}
}
/** For `x.prototype = { p, ... }`, declare members p,... if `x` is function/class/{}, or not declared. */
function bindPrototypeAssignment(node: BinaryExpression) {
node.left.parent = node;
node.right.parent = node;
const lhs = node.left as PropertyAccessEntityNameExpression;
bindPropertyAssignment(lhs, lhs, /*isPrototypeProperty*/ false);
}
/**
* For '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 classPrototype = lhs.expression as PropertyAccessEntityNameExpression;
const constructorFunction = classPrototype.expression as Identifier;
const constructorFunction = classPrototype.expression;
// Fix up parent pointers since we're going to use these nodes before we bind into them
lhs.parent = parent;
@ -2382,7 +2393,8 @@ namespace ts {
function bindSpecialPropertyAssignment(node: BinaryExpression) {
const lhs = node.left as PropertyAccessEntityNameExpression;
// Fix up parent pointers since we're going to use these nodes before we bind into them
lhs.parent = node;
node.left.parent = node;
node.right.parent = node;
if (isIdentifier(lhs.expression) && container === file && isNameOfExportsOrModuleExportsAliasDeclaration(file, lhs.expression)) {
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
// var util = module.exports;
@ -2433,7 +2445,9 @@ namespace ts {
(symbol.exports || (symbol.exports = createSymbolTable()));
// Declare the method/property
declareSymbol(symbolTable, symbol, propertyAccess, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
const symbolFlags = SymbolFlags.Property | (isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0);
const symbolExcludes = SymbolFlags.PropertyExcludes & ~(isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0);
declareSymbol(symbolTable, symbol, propertyAccess, symbolFlags, symbolExcludes);
}
function lookupSymbolForPropertyAccess(node: EntityNameExpression): Symbol | undefined {

View File

@ -2002,21 +2002,7 @@ namespace ts {
}
}
else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) {
let left: EntityNameOrEntityNameExpression;
if (name.kind === SyntaxKind.QualifiedName) {
left = name.left;
}
else if (name.kind === SyntaxKind.PropertyAccessExpression) {
left = name.expression;
}
else {
// If the expression in property-access expression is not entity-name or parenthsizedExpression (e.g. it is a call expression), it won't be able to successfully resolve the name.
// This is the case when we are trying to do any language service operation in heritage clauses. By return undefined, the getSymbolOfEntityNameOrPropertyAccessExpression
// will attempt to checkPropertyAccessExpression to resolve symbol.
// i.e class C extends foo()./*do language service operation here*/B {}
return undefined;
}
const left = name.kind === SyntaxKind.QualifiedName ? name.left : name.expression;
const right = name.kind === SyntaxKind.QualifiedName ? name.right : name.name;
let namespace = resolveEntityName(left, SymbolFlags.Namespace, ignoreErrors, /*dontResolveAlias*/ false, location);
if (!namespace || nodeIsMissing(right)) {
@ -2025,8 +2011,11 @@ namespace ts {
else if (namespace === unknownSymbol) {
return namespace;
}
if (isInJavaScriptFile(name) && isDeclarationOfFunctionOrClassExpression(namespace)) {
namespace = getSymbolOfNode((namespace.valueDeclaration as VariableDeclaration).initializer);
if (isInJavaScriptFile(name)) {
const initializer = getDeclaredJavascriptInitializer(namespace.valueDeclaration);
if (initializer) {
namespace = getSymbolOfNode(initializer);
}
}
symbol = getSymbol(getExportsOfSymbol(namespace), right.escapedText, meaning);
if (!symbol) {
@ -4186,7 +4175,7 @@ namespace ts {
}
function getWidenedTypeFromJSSpecialPropertyDeclarations(symbol: Symbol) {
// function/class/{} assignments are fresh declarations, not property assignments, so return immediately
// function/class/{} assignments are fresh declarations, not property assignments, so only add prototype assignments
const specialDeclaration = getAssignedJavascriptInitializer(symbol.valueDeclaration);
if (specialDeclaration) {
return getWidenedLiteralType(checkExpressionCached(specialDeclaration));
@ -7246,12 +7235,11 @@ namespace ts {
// A jsdoc TypeReference may have resolved to a value (as opposed to a type). If
// the symbol is a constructor function, return the inferred class type; otherwise,
// the type of this reference is just the type of the value we resolved to.
const assignedType = getAssignedClassType(symbol);
const valueType = getTypeOfSymbol(symbol);
if (valueType.symbol && !isInferredClassType(valueType)) {
const referenceType = getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
if (referenceType) {
return referenceType;
}
const referenceType = valueType.symbol && !isInferredClassType(valueType) && getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
if (referenceType || assignedType) {
return referenceType && assignedType ? getIntersectionType([assignedType, referenceType]) : referenceType || assignedType;
}
// Resolve the type reference as a Type for the purpose of reporting errors.
@ -14254,6 +14242,7 @@ namespace ts {
case SpecialPropertyAssignmentKind.ModuleExports:
case SpecialPropertyAssignmentKind.PrototypeProperty:
case SpecialPropertyAssignmentKind.ThisProperty:
case SpecialPropertyAssignmentKind.Prototype:
return false;
default:
Debug.assertNever(kind);
@ -17893,20 +17882,54 @@ namespace ts {
}
function getJavaScriptClassType(symbol: Symbol): Type | undefined {
if (isDeclarationOfFunctionOrClassExpression(symbol)) {
symbol = getSymbolOfNode((<VariableDeclaration>symbol.valueDeclaration).initializer);
const initializer = getDeclaredJavascriptInitializer(symbol.valueDeclaration);
if (initializer) {
symbol = getSymbolOfNode(initializer);
}
let inferred: Type | undefined;
if (isJavaScriptConstructor(symbol.valueDeclaration)) {
return getInferredClassType(symbol);
inferred = getInferredClassType(symbol);
}
if (symbol.flags & SymbolFlags.Variable) {
const valueType = getTypeOfSymbol(symbol);
if (valueType.symbol && !isInferredClassType(valueType) && isJavaScriptConstructor(valueType.symbol.valueDeclaration)) {
return getInferredClassType(valueType.symbol);
const assigned = getAssignedClassType(symbol);
const valueType = getTypeOfSymbol(symbol);
if (valueType.symbol && !isInferredClassType(valueType) && isJavaScriptConstructor(valueType.symbol.valueDeclaration)) {
inferred = getInferredClassType(valueType.symbol);
}
return assigned && inferred ?
getIntersectionType([inferred, assigned]) :
assigned || inferred;
}
function getAssignedClassType(symbol: Symbol) {
const decl = symbol.valueDeclaration;
const assignmentSymbol = decl && decl.parent &&
(isBinaryExpression(decl.parent) && getSymbolOfNode(decl.parent.left) ||
isVariableDeclaration(decl.parent) && getSymbolOfNode(decl.parent));
if (assignmentSymbol) {
const prototype = forEach(assignmentSymbol.declarations, getAssignedJavascriptPrototype);
if (prototype) {
return checkExpression(prototype);
}
}
}
function getAssignedJavascriptPrototype(node: Node) {
if (!node.parent) {
return false;
}
let parent: Node = node.parent;
while (parent && parent.kind === SyntaxKind.PropertyAccessExpression) {
parent = parent.parent;
}
return parent && isBinaryExpression(parent) &&
isPropertyAccessExpression(parent.left) &&
parent.left.name.escapedText === "prototype" &&
parent.operatorToken.kind === SyntaxKind.EqualsToken &&
isObjectLiteralExpression(parent.right) &&
parent.right;
}
function getInferredClassType(symbol: Symbol) {
const links = getSymbolLinks(symbol);
if (!links.inferredClassType) {

View File

@ -3243,8 +3243,8 @@ namespace ts {
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | JSContainer,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias | JSContainer,
Namespace = ValueModule | NamespaceModule | Enum,
Module = ValueModule | NamespaceModule,
Accessor = GetAccessor | SetAccessor,
@ -3964,7 +3964,9 @@ namespace ts {
/// this.name = expr
ThisProperty,
// F.name = expr
Property
Property,
// F.prototype = { ... }
Prototype,
}
export interface JsFileExtensionInfo {

View File

@ -1471,18 +1471,6 @@ namespace ts {
return getSourceTextOfNodeFromSourceFile(sourceFile, str).charCodeAt(0) === CharacterCodes.doubleQuote;
}
/**
* Returns true if the node is a variable declaration whose initializer is a function or class expression.
* This function does not test if the node is in a JavaScript file or not.
*/
export function isDeclarationOfFunctionOrClassExpression(s: Symbol) {
if (s.valueDeclaration && isVariableDeclaration(s.valueDeclaration)) {
return s.valueDeclaration.initializer &&
(s.valueDeclaration.initializer.kind === SyntaxKind.FunctionExpression || s.valueDeclaration.initializer.kind === SyntaxKind.ClassExpression);
}
return false;
}
export function getJSInitializerSymbol(symbol: Symbol) {
if (!symbol || !symbol.valueDeclaration) {
return symbol;
@ -1511,9 +1499,12 @@ namespace ts {
const e = skipParentheses(initializer.expression);
return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer : undefined;
}
if (initializer.kind === SyntaxKind.FunctionExpression ||
initializer.kind === SyntaxKind.ClassExpression ||
isObjectLiteralExpression(initializer) && initializer.properties.length === 0) {
if (initializer.kind === SyntaxKind.FunctionExpression || initializer.kind === SyntaxKind.ClassExpression) {
return initializer;
}
if (isObjectLiteralExpression(initializer) &&
(initializer.properties.length === 0 ||
isBinaryExpression(initializer.parent) && isPropertyAccessExpression(initializer.parent.left) && initializer.parent.left.name.escapedText === "prototype")) {
return initializer;
}
}
@ -1576,6 +1567,9 @@ namespace ts {
return SpecialPropertyAssignmentKind.None;
}
const lhs = expr.left;
if (lhs.expression.kind === SyntaxKind.ThisKeyword) {
return SpecialPropertyAssignmentKind.ThisProperty;
}
if (isIdentifier(lhs.expression)) {
if (lhs.expression.escapedText === "exports") {
// exports.name = expr
@ -1585,28 +1579,27 @@ namespace ts {
// module.exports = expr
return SpecialPropertyAssignmentKind.ModuleExports;
}
else {
// F.x = expr
return SpecialPropertyAssignmentKind.Property;
}
if (isEntityNameExpression(lhs.expression)) {
if (lhs.name.escapedText === "prototype" && isObjectLiteralExpression(expr.right)) {
// F.prototype = { ... }
return SpecialPropertyAssignmentKind.Prototype;
}
}
else if (lhs.expression.kind === SyntaxKind.ThisKeyword) {
return SpecialPropertyAssignmentKind.ThisProperty;
}
else if (isPropertyAccessExpression(lhs.expression)) {
// chained dot, e.g. x.y.z = expr; this var is the 'x.y' part
if (isIdentifier(lhs.expression.expression)) {
// module.exports.name = expr
if (lhs.expression.expression.escapedText === "module" && lhs.expression.name.escapedText === "exports") {
else if (isPropertyAccessExpression(lhs.expression)) {
// chained dot, e.g. x.y.z = expr; this var is the 'x.y' part
if (isIdentifier(lhs.expression.expression) &&
lhs.expression.expression.escapedText === "module" &&
lhs.expression.name.escapedText === "exports") {
// module.exports.name = expr
return SpecialPropertyAssignmentKind.ExportsProperty;
}
if (lhs.expression.name.escapedText === "prototype") {
// F.G....prototype.x = expr
return SpecialPropertyAssignmentKind.PrototypeProperty;
}
}
if (isEntityNameExpression(lhs.expression)) {
return SpecialPropertyAssignmentKind.Property;
}
// F.G...x = expr
return SpecialPropertyAssignmentKind.Property;
}
return SpecialPropertyAssignmentKind.None;

View File

@ -275,6 +275,7 @@ namespace ts.NavigationBar {
case SpecialPropertyAssignmentKind.ExportsProperty:
case SpecialPropertyAssignmentKind.ModuleExports:
case SpecialPropertyAssignmentKind.PrototypeProperty:
case SpecialPropertyAssignmentKind.Prototype:
addNodeWithRecursiveChild(node, (node as BinaryExpression).right);
break;
case SpecialPropertyAssignmentKind.ThisProperty:

View File

@ -16,8 +16,9 @@ namespace ts.refactor.convertFunctionToES6Class {
return undefined;
}
if (isDeclarationOfFunctionOrClassExpression(symbol)) {
symbol = (symbol.valueDeclaration as VariableDeclaration).initializer.symbol;
const initializer = getDeclaredJavascriptInitializer(symbol.valueDeclaration);
if (initializer) {
symbol = initializer.symbol;
}
if ((symbol.flags & SymbolFlags.Function) && symbol.members && (symbol.members.size > 0)) {
@ -264,4 +265,4 @@ namespace ts.refactor.convertFunctionToES6Class {
const token = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false);
return checker.getSymbolAtLocation(token);
}
}
}

View File

@ -370,6 +370,8 @@ namespace ts {
case SpecialPropertyAssignmentKind.Property:
// static method / property
return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement;
case SpecialPropertyAssignmentKind.Prototype:
return ScriptElementKind.localClassElement;
default: {
assertTypeIsNever(kind);
return ScriptElementKind.unknown;

View File

@ -1956,28 +1956,28 @@ declare namespace ts {
JSContainer = 67108864,
Enum = 384,
Variable = 3,
Value = 107455,
Type = 793064,
Value = 67216319,
Type = 67901928,
Namespace = 1920,
Module = 1536,
Accessor = 98304,
FunctionScopedVariableExcludes = 107454,
BlockScopedVariableExcludes = 107455,
ParameterExcludes = 107455,
FunctionScopedVariableExcludes = 67216318,
BlockScopedVariableExcludes = 67216319,
ParameterExcludes = 67216319,
PropertyExcludes = 0,
EnumMemberExcludes = 900095,
FunctionExcludes = 106927,
ClassExcludes = 899519,
InterfaceExcludes = 792968,
RegularEnumExcludes = 899327,
ConstEnumExcludes = 899967,
ValueModuleExcludes = 106639,
EnumMemberExcludes = 68008959,
FunctionExcludes = 67215791,
ClassExcludes = 68008383,
InterfaceExcludes = 67901832,
RegularEnumExcludes = 68008191,
ConstEnumExcludes = 68008831,
ValueModuleExcludes = 67215503,
NamespaceModuleExcludes = 0,
MethodExcludes = 99263,
GetAccessorExcludes = 41919,
SetAccessorExcludes = 74687,
TypeParameterExcludes = 530920,
TypeAliasExcludes = 793064,
MethodExcludes = 67208127,
GetAccessorExcludes = 67150783,
SetAccessorExcludes = 67183551,
TypeParameterExcludes = 67639784,
TypeAliasExcludes = 67901928,
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,

View File

@ -1956,28 +1956,28 @@ declare namespace ts {
JSContainer = 67108864,
Enum = 384,
Variable = 3,
Value = 107455,
Type = 793064,
Value = 67216319,
Type = 67901928,
Namespace = 1920,
Module = 1536,
Accessor = 98304,
FunctionScopedVariableExcludes = 107454,
BlockScopedVariableExcludes = 107455,
ParameterExcludes = 107455,
FunctionScopedVariableExcludes = 67216318,
BlockScopedVariableExcludes = 67216319,
ParameterExcludes = 67216319,
PropertyExcludes = 0,
EnumMemberExcludes = 900095,
FunctionExcludes = 106927,
ClassExcludes = 899519,
InterfaceExcludes = 792968,
RegularEnumExcludes = 899327,
ConstEnumExcludes = 899967,
ValueModuleExcludes = 106639,
EnumMemberExcludes = 68008959,
FunctionExcludes = 67215791,
ClassExcludes = 68008383,
InterfaceExcludes = 67901832,
RegularEnumExcludes = 68008191,
ConstEnumExcludes = 68008831,
ValueModuleExcludes = 67215503,
NamespaceModuleExcludes = 0,
MethodExcludes = 99263,
GetAccessorExcludes = 41919,
SetAccessorExcludes = 74687,
TypeParameterExcludes = 530920,
TypeAliasExcludes = 793064,
MethodExcludes = 67208127,
GetAccessorExcludes = 67150783,
SetAccessorExcludes = 67183551,
TypeParameterExcludes = 67639784,
TypeAliasExcludes = 67901928,
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,

View File

@ -0,0 +1,52 @@
=== tests/cases/conformance/salsa/module.js ===
var Inner = function() {}
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
Inner.prototype = {
>Inner.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
m() { },
>m : Symbol(m, Decl(module.js, 1, 19))
i: 1
>i : Symbol(i, Decl(module.js, 2, 12))
}
// incremental assignments still work
Inner.prototype.j = 2
>Inner.prototype : Symbol(Inner.j, Decl(module.js, 4, 1))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>j : Symbol(Inner.j, Decl(module.js, 4, 1))
/** @type {string} */
Inner.prototype.k;
>Inner.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
var inner = new Inner()
>inner : Symbol(inner, Decl(module.js, 9, 3))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
inner.m()
>inner.m : Symbol(m, Decl(module.js, 1, 19))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>m : Symbol(m, Decl(module.js, 1, 19))
inner.i
>inner.i : Symbol(i, Decl(module.js, 2, 12))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>i : Symbol(i, Decl(module.js, 2, 12))
inner.j
>inner.j : Symbol(Inner.j, Decl(module.js, 4, 1))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>j : Symbol(Inner.j, Decl(module.js, 4, 1))
inner.k
>inner.k : Symbol(Inner.k, Decl(module.js, 6, 21))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>k : Symbol(Inner.k, Decl(module.js, 6, 21))

View File

@ -0,0 +1,63 @@
=== tests/cases/conformance/salsa/module.js ===
var Inner = function() {}
>Inner : () => void
>function() {} : () => void
Inner.prototype = {
>Inner.prototype = { m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
>Inner.prototype : any
>Inner : () => void
>prototype : any
>{ m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
m() { },
>m : () => void
i: 1
>i : number
>1 : 1
}
// incremental assignments still work
Inner.prototype.j = 2
>Inner.prototype.j = 2 : 2
>Inner.prototype.j : any
>Inner.prototype : any
>Inner : () => void
>prototype : any
>j : any
>2 : 2
/** @type {string} */
Inner.prototype.k;
>Inner.prototype.k : any
>Inner.prototype : any
>Inner : () => void
>prototype : any
>k : any
var inner = new Inner()
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>new Inner() : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>Inner : () => void
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>m : () => void
inner.i
>inner.i : number
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>i : number
inner.j
>inner.j : number
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>j : number
inner.k
>inner.k : string
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>k : string

View File

@ -1,34 +1,35 @@
=== tests/cases/conformance/salsa/module.js ===
var Outer = function(element, config) {};
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 41))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(usage.js, 0, 0))
>element : Symbol(element, Decl(module.js, 0, 21))
>config : Symbol(config, Decl(module.js, 0, 29))
=== tests/cases/conformance/salsa/usage.js ===
/** @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))
>Outer.Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(usage.js, 0, 0))
>Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
>line : Symbol(line, Decl(usage.js, 1, 22))
>ch : Symbol(ch, Decl(usage.js, 1, 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))
>Outer.Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(usage.js, 0, 0))
>Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
>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 : Symbol(pos, Decl(usage.js, 4, 3))
>Outer.Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(usage.js, 0, 0))
>Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
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))
>pos.line : Symbol((Anonymous function).line, Decl(usage.js, 1, 35))
>pos : Symbol(pos, Decl(usage.js, 4, 3))
>line : Symbol((Anonymous function).line, Decl(usage.js, 1, 35))

View File

@ -1,15 +1,16 @@
=== 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; }
>Outer : typeof Outer
>function(element, config) {} : typeof Outer
>element : any
>config : any
=== tests/cases/conformance/salsa/usage.js ===
/** @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; }
>Outer : typeof Outer
>Pos : (line: any, ch: any) => void
>function (line, ch) {} : (line: any, ch: any) => void
>line : any
@ -20,7 +21,7 @@ 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; }
>Outer : typeof Outer
>Pos : (line: any, ch: any) => void
>prototype : any
>line : any
@ -29,7 +30,7 @@ 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; }
>Outer : typeof Outer
>Pos : (line: any, ch: any) => void
>1 : 1
>'x' : "x"

View File

@ -0,0 +1,65 @@
=== tests/cases/conformance/salsa/module.js ===
var Outer = {}
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
Outer.Inner = function() {}
>Outer.Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
>Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
Outer.Inner.prototype = {
>Outer.Inner.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Outer.Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
>Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
m() { },
>m : Symbol(m, Decl(module.js, 2, 25))
i: 1
>i : Symbol(i, Decl(module.js, 3, 12))
}
// incremental assignments still work
Outer.Inner.prototype.j = 2
>Outer.Inner.prototype : Symbol((Anonymous function).j, Decl(module.js, 5, 1))
>Outer.Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
>Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>j : Symbol((Anonymous function).j, Decl(module.js, 5, 1))
/** @type {string} */
Outer.Inner.prototype.k;
>Outer.Inner.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Outer.Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
>Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
var inner = new Outer.Inner()
>inner : Symbol(inner, Decl(module.js, 10, 3))
>Outer.Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
>Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
inner.m()
>inner.m : Symbol(m, Decl(module.js, 2, 25))
>inner : Symbol(inner, Decl(module.js, 10, 3))
>m : Symbol(m, Decl(module.js, 2, 25))
inner.i
>inner.i : Symbol(i, Decl(module.js, 3, 12))
>inner : Symbol(inner, Decl(module.js, 10, 3))
>i : Symbol(i, Decl(module.js, 3, 12))
inner.j
>inner.j : Symbol((Anonymous function).j, Decl(module.js, 5, 1))
>inner : Symbol(inner, Decl(module.js, 10, 3))
>j : Symbol((Anonymous function).j, Decl(module.js, 5, 1))
inner.k
>inner.k : Symbol((Anonymous function).k, Decl(module.js, 7, 27))
>inner : Symbol(inner, Decl(module.js, 10, 3))
>k : Symbol((Anonymous function).k, Decl(module.js, 7, 27))

View File

@ -0,0 +1,78 @@
=== tests/cases/conformance/salsa/module.js ===
var Outer = {}
>Outer : { [x: string]: any; Inner: () => void; }
>{} : { [x: string]: any; Inner: () => void; }
Outer.Inner = function() {}
>Outer.Inner = function() {} : () => void
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>function() {} : () => void
Outer.Inner.prototype = {
>Outer.Inner.prototype = { m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>prototype : any
>{ m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
m() { },
>m : () => void
i: 1
>i : number
>1 : 1
}
// incremental assignments still work
Outer.Inner.prototype.j = 2
>Outer.Inner.prototype.j = 2 : 2
>Outer.Inner.prototype.j : any
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>prototype : any
>j : any
>2 : 2
/** @type {string} */
Outer.Inner.prototype.k;
>Outer.Inner.prototype.k : any
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>prototype : any
>k : any
var inner = new Outer.Inner()
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>new Outer.Inner() : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>m : () => void
inner.i
>inner.i : number
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>i : number
inner.j
>inner.j : number
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>j : number
inner.k
>inner.k : string
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>k : string

View File

@ -0,0 +1,57 @@
=== tests/cases/conformance/salsa/def.js ===
var Outer = {};
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
=== tests/cases/conformance/salsa/work.js ===
Outer.Inner = function () {}
>Outer.Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
>Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
Outer.Inner.prototype = {
>Outer.Inner.prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
>Outer.Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
>Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
x: 1,
>x : Symbol(x, Decl(work.js, 1, 25))
m() { }
>m : Symbol(m, Decl(work.js, 2, 9))
}
=== tests/cases/conformance/salsa/use.js ===
/** @type {Outer.Inner} */
var inner
>inner : Symbol(inner, Decl(use.js, 1, 3))
inner.x
>inner.x : Symbol(x, Decl(work.js, 1, 25))
>inner : Symbol(inner, Decl(use.js, 1, 3))
>x : Symbol(x, Decl(work.js, 1, 25))
inner.m()
>inner.m : Symbol(m, Decl(work.js, 2, 9))
>inner : Symbol(inner, Decl(use.js, 1, 3))
>m : Symbol(m, Decl(work.js, 2, 9))
var inno = new Outer.Inner()
>inno : Symbol(inno, Decl(use.js, 4, 3))
>Outer.Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
>Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
inno.x
>inno.x : Symbol(x, Decl(work.js, 1, 25))
>inno : Symbol(inno, Decl(use.js, 4, 3))
>x : Symbol(x, Decl(work.js, 1, 25))
inno.m()
>inno.m : Symbol(m, Decl(work.js, 2, 9))
>inno : Symbol(inno, Decl(use.js, 4, 3))
>m : Symbol(m, Decl(work.js, 2, 9))

View File

@ -0,0 +1,66 @@
=== tests/cases/conformance/salsa/def.js ===
var Outer = {};
>Outer : typeof Outer
>{} : typeof Outer
=== tests/cases/conformance/salsa/work.js ===
Outer.Inner = function () {}
>Outer.Inner = function () {} : () => void
>Outer.Inner : () => void
>Outer : typeof Outer
>Inner : () => void
>function () {} : () => void
Outer.Inner.prototype = {
>Outer.Inner.prototype = { x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : typeof Outer
>Inner : () => void
>prototype : any
>{ x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
x: 1,
>x : number
>1 : 1
m() { }
>m : () => void
}
=== tests/cases/conformance/salsa/use.js ===
/** @type {Outer.Inner} */
var inner
>inner : { [x: string]: any; x: number; m(): void; }
inner.x
>inner.x : number
>inner : { [x: string]: any; x: number; m(): void; }
>x : number
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { [x: string]: any; x: number; m(): void; }
>m : () => void
var inno = new Outer.Inner()
>inno : { [x: string]: any; x: number; m(): void; }
>new Outer.Inner() : { [x: string]: any; x: number; m(): void; }
>Outer.Inner : () => void
>Outer : typeof Outer
>Inner : () => void
inno.x
>inno.x : number
>inno : { [x: string]: any; x: number; m(): void; }
>x : number
inno.m()
>inno.m() : void
>inno.m : () => void
>inno : { [x: string]: any; x: number; m(): void; }
>m : () => void

View File

@ -0,0 +1,49 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15))
Outer.Inner = class {
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15))
>Inner : Symbol(Inner, Decl(a.js, 0, 15))
constructor() {
this.x = 1
>this.x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
>this : Symbol((Anonymous class), Decl(a.js, 2, 13))
>x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
}
m() { }
>m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
}
/** @type {Outer.Inner} */
var inner
>inner : Symbol(inner, Decl(a.js, 10, 3))
inner.x
>inner.x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
>inner : Symbol(inner, Decl(a.js, 10, 3))
>x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
inner.m()
>inner.m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
>inner : Symbol(inner, Decl(a.js, 10, 3))
>m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
var inno = new Outer.Inner()
>inno : Symbol(inno, Decl(a.js, 13, 3))
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15))
>Inner : Symbol(Inner, Decl(a.js, 0, 15))
inno.x
>inno.x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
>inno : Symbol(inno, Decl(a.js, 13, 3))
>x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
inno.m()
>inno.m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
>inno : Symbol(inno, Decl(a.js, 13, 3))
>m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))

View File

@ -0,0 +1,57 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : { [x: string]: any; Inner: typeof (Anonymous class); }
>{} : { [x: string]: any; Inner: typeof (Anonymous class); }
Outer.Inner = class {
>Outer.Inner = class { constructor() { this.x = 1 } m() { }} : typeof (Anonymous class)
>Outer.Inner : typeof (Anonymous class)
>Outer : { [x: string]: any; Inner: typeof (Anonymous class); }
>Inner : typeof (Anonymous class)
>class { constructor() { this.x = 1 } m() { }} : typeof (Anonymous class)
constructor() {
this.x = 1
>this.x = 1 : 1
>this.x : number
>this : this
>x : number
>1 : 1
}
m() { }
>m : () => void
}
/** @type {Outer.Inner} */
var inner
>inner : (Anonymous class)
inner.x
>inner.x : number
>inner : (Anonymous class)
>x : number
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : (Anonymous class)
>m : () => void
var inno = new Outer.Inner()
>inno : (Anonymous class)
>new Outer.Inner() : (Anonymous class)
>Outer.Inner : typeof (Anonymous class)
>Outer : { [x: string]: any; Inner: typeof (Anonymous class); }
>Inner : typeof (Anonymous class)
inno.x
>inno.x : number
>inno : (Anonymous class)
>x : number
inno.m()
>inno.m() : void
>inno.m : () => void
>inno : (Anonymous class)
>m : () => void

View File

@ -0,0 +1,53 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
Outer.Inner = function () {}
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
>Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
Outer.Inner.prototype = {
>Outer.Inner.prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
>Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
x: 1,
>x : Symbol(x, Decl(a.js, 3, 25))
m() { }
>m : Symbol(m, Decl(a.js, 4, 9))
}
/** @type {Outer.Inner} */
var inner
>inner : Symbol(inner, Decl(a.js, 9, 3))
inner.x
>inner.x : Symbol(x, Decl(a.js, 3, 25))
>inner : Symbol(inner, Decl(a.js, 9, 3))
>x : Symbol(x, Decl(a.js, 3, 25))
inner.m()
>inner.m : Symbol(m, Decl(a.js, 4, 9))
>inner : Symbol(inner, Decl(a.js, 9, 3))
>m : Symbol(m, Decl(a.js, 4, 9))
var inno = new Outer.Inner()
>inno : Symbol(inno, Decl(a.js, 12, 3))
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
>Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
inno.x
>inno.x : Symbol(x, Decl(a.js, 3, 25))
>inno : Symbol(inno, Decl(a.js, 12, 3))
>x : Symbol(x, Decl(a.js, 3, 25))
inno.m()
>inno.m : Symbol(m, Decl(a.js, 4, 9))
>inno : Symbol(inno, Decl(a.js, 12, 3))
>m : Symbol(m, Decl(a.js, 4, 9))

View File

@ -0,0 +1,62 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : { [x: string]: any; Inner: () => void; }
>{} : { [x: string]: any; Inner: () => void; }
Outer.Inner = function () {}
>Outer.Inner = function () {} : () => void
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>function () {} : () => void
Outer.Inner.prototype = {
>Outer.Inner.prototype = { x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>prototype : any
>{ x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
x: 1,
>x : number
>1 : 1
m() { }
>m : () => void
}
/** @type {Outer.Inner} */
var inner
>inner : { [x: string]: any; x: number; m(): void; }
inner.x
>inner.x : number
>inner : { [x: string]: any; x: number; m(): void; }
>x : number
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { [x: string]: any; x: number; m(): void; }
>m : () => void
var inno = new Outer.Inner()
>inno : { [x: string]: any; x: number; m(): void; }
>new Outer.Inner() : { [x: string]: any; x: number; m(): void; }
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
inno.x
>inno.x : number
>inno : { [x: string]: any; x: number; m(): void; }
>x : number
inno.m()
>inno.m() : void
>inno.m : () => void
>inno : { [x: string]: any; x: number; m(): void; }
>m : () => void

View File

@ -0,0 +1,19 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @target: es6
// @Filename: module.js
var Inner = function() {}
Inner.prototype = {
m() { },
i: 1
}
// incremental assignments still work
Inner.prototype.j = 2
/** @type {string} */
Inner.prototype.k;
var inner = new Inner()
inner.m()
inner.i
inner.j
inner.k

View File

@ -4,6 +4,7 @@
// @target: es6
// @Filename: module.js
var Outer = function(element, config) {};
// @Filename: usage.js
/** @constructor */
Outer.Pos = function (line, ch) {};
/** @type {number} */

View File

@ -0,0 +1,20 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @target: es6
// @Filename: module.js
var Outer = {}
Outer.Inner = function() {}
Outer.Inner.prototype = {
m() { },
i: 1
}
// incremental assignments still work
Outer.Inner.prototype.j = 2
/** @type {string} */
Outer.Inner.prototype.k;
var inner = new Outer.Inner()
inner.m()
inner.i
inner.j
inner.k

View File

@ -0,0 +1,23 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @Filename: def.js
var Outer = {};
// @Filename: work.js
Outer.Inner = function () {}
Outer.Inner.prototype = {
x: 1,
m() { }
}
// @Filename: use.js
/** @type {Outer.Inner} */
var inner
inner.x
inner.m()
var inno = new Outer.Inner()
inno.x
inno.m()

View File

@ -0,0 +1,20 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @Filename: a.js
var Outer = {};
Outer.Inner = class {
constructor() {
this.x = 1
}
m() { }
}
/** @type {Outer.Inner} */
var inner
inner.x
inner.m()
var inno = new Outer.Inner()
inno.x
inno.m()

View File

@ -0,0 +1,19 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @Filename: a.js
var Outer = {};
Outer.Inner = function () {}
Outer.Inner.prototype = {
x: 1,
m() { }
}
/** @type {Outer.Inner} */
var inner
inner.x
inner.m()
var inno = new Outer.Inner()
inno.x
inno.m()