Correctly merge JS decls

Turns out merging was incorrect even for non-nested declarations, but
tests didn't catch it before.
This commit is contained in:
Nathan Shively-Sanders 2018-02-13 14:17:46 -08:00
parent 03d155f622
commit fc08e20da8
8 changed files with 195 additions and 82 deletions

View File

@ -2403,12 +2403,7 @@ namespace ts {
return lookupSymbolForNameWorker(container, node.escapedText);
}
else {
let symbol = lookupSymbolForPropertyAccess(node.expression);
symbol = symbol && isDeclarationOfJavascriptContainerExpression(symbol.valueDeclaration) ? (symbol.valueDeclaration as VariableDeclaration).initializer.symbol :
symbol && isDeclarationOfDefaultedJavascriptContainerExpression(symbol.valueDeclaration) ? ((symbol.valueDeclaration as VariableDeclaration).initializer as BinaryExpression).right.symbol :
symbol && isAssignmentOfDefaultedJavascriptContainerExpression(symbol.valueDeclaration.parent) ? (((symbol.valueDeclaration.parent as BinaryExpression).right as BinaryExpression).right as BinaryExpression).symbol :
symbol && isAssignmentOfJavascriptContainerExpression(symbol.valueDeclaration) ? ((symbol.valueDeclaration.parent as BinaryExpression).right as BinaryExpression).symbol :
symbol;
const symbol = follow(lookupSymbolForPropertyAccess(node.expression));
return symbol && symbol.exports && symbol.exports.get(node.name.escapedText);
}
}
@ -2417,11 +2412,7 @@ namespace ts {
// Look up the property in the local scope, since property assignments should follow the declaration
const symbol = lookupSymbolForPropertyAccess(name);
// TODO: Should be able to structure this with less duplication
let targetSymbol = symbol && isDeclarationOfJavascriptContainerExpression(symbol.valueDeclaration) ? (symbol.valueDeclaration as VariableDeclaration).initializer.symbol :
symbol && isDeclarationOfDefaultedJavascriptContainerExpression(symbol.valueDeclaration) ? ((symbol.valueDeclaration as VariableDeclaration).initializer as BinaryExpression).right.symbol :
symbol && isAssignmentOfDefaultedJavascriptContainerExpression(symbol.valueDeclaration.parent) ? (((symbol.valueDeclaration.parent as BinaryExpression).right as BinaryExpression).right as BinaryExpression).symbol :
symbol && isAssignmentOfJavascriptContainerExpression(symbol.valueDeclaration) ? ((symbol.valueDeclaration.parent as BinaryExpression).right as BinaryExpression).symbol :
symbol;
let targetSymbol = follow(symbol);
Debug.assert(propertyAccess.parent.kind === SyntaxKind.BinaryExpression ||
propertyAccess.parent.kind === SyntaxKind.ExpressionStatement ||
propertyAccess.parent.kind === SyntaxKind.PropertyAccessExpression);
@ -2430,24 +2421,40 @@ namespace ts {
const initializerKind = (propertyAccess.parent as BinaryExpression).right.kind;
isLegalPosition = (initializerKind === SyntaxKind.ClassExpression || initializerKind === SyntaxKind.FunctionExpression) &&
propertyAccess.parent.parent.parent.kind === SyntaxKind.SourceFile;
if (propertyAccess.parent.parent.parent.kind === SyntaxKind.SourceFile && initializerKind === SyntaxKind.BinaryExpression && (((propertyAccess.parent as BinaryExpression).right as BinaryExpression).right.kind === SyntaxKind.ClassExpression || ((propertyAccess.parent as BinaryExpression).right as BinaryExpression).right.kind === SyntaxKind.FunctionExpression)) {
isLegalPosition = true;
}
}
else {
isLegalPosition = propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
}
if (!isPrototypeProperty && (!targetSymbol || !(targetSymbol.flags & SymbolFlags.Namespace)) && isLegalPosition) {
const identifier = isIdentifier(propertyAccess.expression) ? propertyAccess.expression : isIdentifier(propertyAccess.expression.expression) && propertyAccess.expression.expression;
Debug.assert(identifier !== undefined);
const flags = SymbolFlags.Module | SymbolFlags.JSContainer;
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.JSContainer;
if (targetSymbol) {
// TODO: Not sure this is correct for nested declarations -- maybe this should be added to targetSymbol
// Note: add declaration to original symbol, not the special-syntax's symbol, so that namespaces work for type lookup
addDeclarationToSymbol(symbol, identifier, flags);
}
else {
// TODO: Not sure this branch is correct for nested declarations
targetSymbol = declareSymbol(container.locals, /*parent*/ undefined, identifier, flags, excludeFlags);
}
// const startTargetSymbol = !!targetSymbol;
// hm. This is only needed to make namespaced access of types workable. Namespaced access of *values* doesn't work now either, so something is wrong.
// (Note: for the non-nested case, at least, addDeclarationToSymbol is only needed for things that could be further namespaces, because it
// makes the intermediate namespace. However, I think something like it is needed for *all* nested assignments, in case their intermediate namespaces don't exist)
iterateEntityNameExpression(propertyAccess.expression, (id, originalSymbol, available) => {
if (targetSymbol) {
if (available) {
// Note: add declaration to original symbol, not the special-syntax's symbol, so that namespaces work for type lookup
addDeclarationToSymbol(originalSymbol, id, flags);
// TODO: Why can't I overwrite targetSymbol here? I'm having trouble tracking targetSymbol's state.
return originalSymbol;
}
else {
originalSymbol.exports = originalSymbol.exports || createSymbolTable();
targetSymbol = declareSymbol(originalSymbol.exports, originalSymbol, id, flags, excludeFlags);
return targetSymbol;
}
}
else {
Debug.assert(!available);
targetSymbol = declareSymbol(container.locals, /*parent*/ undefined, id, flags, excludeFlags);
return targetSymbol;
}
});
}
if (!targetSymbol || !(targetSymbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.NamespaceModule | SymbolFlags.ObjectLiteral))) {
return;
@ -2462,6 +2469,20 @@ namespace ts {
declareSymbol(symbolTable, targetSymbol, propertyAccess, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
}
function iterateEntityNameExpression(e: EntityNameExpression, action: (e: Identifier, originalSymbol: Symbol, available: boolean) => Symbol): Symbol {
if (isIdentifier(e)) {
const s = lookupSymbolForPropertyAccess(e);
return action(e, s, !!s);
}
else {
const s = follow(iterateEntityNameExpression(e.expression, action));
Debug.assert(!!s, "lost the chant");
Debug.assert(!!s.exports, `${s.escapedName} has no exports???`);
const t = s.exports.get(e.name.escapedText);
return action(e.name, t || s, s.exports.has(e.name.escapedText));
}
}
function bindCallExpression(node: CallExpression) {
// We're only inspecting call expressions to detect CommonJS modules, so we can skip
// this check if we've already seen the module indicator

View File

@ -835,7 +835,7 @@ namespace ts {
function mergeSymbol(target: Symbol, source: Symbol) {
if (!(target.flags & getExcludedSymbolFlags(source.flags)) ||
source.flags & SymbolFlags.JSContainer || target.flags & SymbolFlags.JSContainer) {
(source.flags | target.flags) & SymbolFlags.JSContainer) {
// Javascript static-property-assignment declarations always merge, even though they are also values
if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) {
// reset flag when merging instantiated module into value module that has only const enums
@ -857,6 +857,14 @@ namespace ts {
if (!target.exports) target.exports = createSymbolTable();
mergeSymbolTable(target.exports, source.exports);
}
if ((source.flags | target.flags) & SymbolFlags.JSContainer) {
const fs = follow(source);
const ft = follow(target);
if (fs !== source || ft !== target) {
// also follow the source's valueDeclaration and merge its symbol
mergeSymbol(follow(target), follow(source));
}
}
recordMergedSymbol(target, source);
}
else if (target.flags & SymbolFlags.NamespaceModule) {
@ -14752,14 +14760,12 @@ namespace ts {
// Grammar checking
checkGrammarObjectLiteralExpression(node, inDestructuringPattern);
let propertiesTable = createSymbolTable();
let propertiesTable: SymbolTable;
let propertiesArray: Symbol[] = [];
let spread: Type = emptyObjectType;
let propagatedFlags: TypeFlags = TypeFlags.FreshLiteral;
const isInJSFile = isInJavaScriptFile(node);
// TODO: Might need to skip if isDeclarationOfDefaultedJavascriptContainerExpression(node.parent.parent) instead of just checking node.properties.length > 0
// (actually, it would be better not to skip contextual typing at all, but to do that I need to avoid the checking loop another way)
const contextualType = getApparentTypeOfContextualType(node);
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
@ -14768,11 +14774,15 @@ namespace ts {
let patternWithComputedProperties = false;
let hasComputedStringProperty = false;
let hasComputedNumberProperty = false;
// TODO: This seems like the wrong way to put the assignment-properties into the type (especially the manual call to mergeSymbolTable)
if (isInJSFile && node.symbol && node.symbol.exports) {
mergeSymbolTable(propertiesTable, node.symbol.exports);
node.symbol.exports.forEach(symbol => propertiesArray.push(symbol));
// TODO: This seems like it might be wrong, or at least should come earlier
// (maybe check SymbolFlags.JSContainer? This currently misses normal declarations like `var my = {}`, but shouldn't)
if (isInJSFile && node.symbol && node.symbol.exports && node.properties.length === 0) {
let symbol = node.symbol;
propertiesTable = symbol.exports;
symbol.exports.forEach(symbol => propertiesArray.push(getMergedSymbol(symbol)));
return createObjectLiteralType();
}
propertiesTable = createSymbolTable();
let offset = 0;
for (let i = 0; i < node.properties.length; i++) {

View File

@ -1486,6 +1486,14 @@ namespace ts {
return false;
}
export function follow(symbol: Symbol) {
return symbol && isDeclarationOfJavascriptContainerExpression(symbol.valueDeclaration) ? (symbol.valueDeclaration as VariableDeclaration).initializer.symbol :
symbol && isDeclarationOfDefaultedJavascriptContainerExpression(symbol.valueDeclaration) ? ((symbol.valueDeclaration as VariableDeclaration).initializer as BinaryExpression).right.symbol :
symbol && symbol.valueDeclaration && isAssignmentOfDefaultedJavascriptContainerExpression(symbol.valueDeclaration.parent) ? (((symbol.valueDeclaration.parent as BinaryExpression).right as BinaryExpression).right as BinaryExpression).symbol :
symbol && isAssignmentOfJavascriptContainerExpression(symbol.valueDeclaration) ? ((symbol.valueDeclaration.parent as BinaryExpression).right as BinaryExpression).symbol :
symbol;
}
/**
* Returns true if the node is a variable declaration whose initializer is a function or class expression, or an empty object literal.
* This function does not test if the node is in a JavaScript file or not.

View File

@ -4,7 +4,9 @@ var Outer = {};
=== tests/cases/conformance/salsa/a.js ===
Outer.Inner = class {
>Outer.Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(a.js, 0, 0))
>Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
constructor() {
/** @type {number} */
@ -15,9 +17,29 @@ Outer.Inner = class {
}
}
/** @type {Outer.Inner} */
var local
>local : Symbol(local, Decl(a.js, 8, 3))
local.y
>local.y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
>local : Symbol(local, Decl(a.js, 8, 3))
>y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
var inner = new Outer.Inner()
>inner : Symbol(inner, Decl(a.js, 10, 3))
>Outer.Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(a.js, 0, 0))
>Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
inner.y
>inner.y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
>inner : Symbol(inner, Decl(a.js, 10, 3))
>y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
=== tests/cases/conformance/salsa/b.js ===
/** @type {Outer.Inner} */
var x;
var x
>x : Symbol(x, Decl(b.js, 1, 3))
x.y
@ -25,3 +47,14 @@ x.y
>x : Symbol(x, Decl(b.js, 1, 3))
>y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
var z = new Outer.Inner()
>z : Symbol(z, Decl(b.js, 3, 3))
>Outer.Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(a.js, 0, 0))
>Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
z.y
>z.y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
>z : Symbol(z, Decl(b.js, 3, 3))
>y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))

View File

@ -1,14 +1,14 @@
=== tests/cases/conformance/salsa/def.js ===
var Outer = {};
>Outer : { [x: string]: any; }
>{} : { [x: string]: any; }
>Outer : typeof Outer
>{} : typeof Outer
=== tests/cases/conformance/salsa/a.js ===
Outer.Inner = class {
>Outer.Inner = class { constructor() { /** @type {number} */ this.y = 12 }} : typeof (Anonymous class)
>Outer.Inner : any
>Outer : { [x: string]: any; }
>Inner : any
>Outer.Inner : typeof (Anonymous class)
>Outer : typeof Outer
>Inner : typeof (Anonymous class)
>class { constructor() { /** @type {number} */ this.y = 12 }} : typeof (Anonymous class)
constructor() {
@ -22,9 +22,30 @@ Outer.Inner = class {
}
}
/** @type {Outer.Inner} */
var local
>local : (Anonymous class)
local.y
>local.y : number
>local : (Anonymous class)
>y : number
var inner = new Outer.Inner()
>inner : (Anonymous class)
>new Outer.Inner() : (Anonymous class)
>Outer.Inner : typeof (Anonymous class)
>Outer : typeof Outer
>Inner : typeof (Anonymous class)
inner.y
>inner.y : number
>inner : (Anonymous class)
>y : number
=== tests/cases/conformance/salsa/b.js ===
/** @type {Outer.Inner} */
var x;
var x
>x : (Anonymous class)
x.y
@ -32,3 +53,15 @@ x.y
>x : (Anonymous class)
>y : number
var z = new Outer.Inner()
>z : (Anonymous class)
>new Outer.Inner() : (Anonymous class)
>Outer.Inner : typeof (Anonymous class)
>Outer : typeof Outer
>Inner : typeof (Anonymous class)
z.y
>z.y : number
>z : (Anonymous class)
>y : number

View File

@ -1,12 +1,12 @@
=== tests/cases/conformance/salsa/a.js ===
var my = my || {};
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
/** @param {number} n */
my.method = function(n) {
>my.method : Symbol(method, Decl(a.js, 0, 18))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>method : Symbol(method, Decl(a.js, 0, 18))
>n : Symbol(n, Decl(a.js, 2, 21))
@ -15,27 +15,27 @@ my.method = function(n) {
}
my.number = 1;
>my.number : Symbol(number, Decl(a.js, 4, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>number : Symbol(number, Decl(a.js, 4, 1))
my.object = {};
>my.object : Symbol(object, Decl(a.js, 5, 14))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>object : Symbol(object, Decl(a.js, 5, 14))
my.predicate = my.predicate || {};
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
my.predicate.query = function () {
>my.predicate.query : Symbol(query, Decl(a.js, 7, 34))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>query : Symbol(query, Decl(a.js, 7, 34))
var me = this;
@ -49,17 +49,17 @@ my.predicate.query = function () {
var q = new my.predicate.query();
>q : Symbol(q, Decl(a.js, 12, 3))
>my.predicate.query : Symbol(query, Decl(a.js, 7, 34))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>query : Symbol(query, Decl(a.js, 7, 34))
my.predicate.query.result = 'none'
>my.predicate.query.result : Symbol((Anonymous function).result, Decl(a.js, 12, 33))
>my.predicate.query : Symbol(query, Decl(a.js, 7, 34))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>query : Symbol(query, Decl(a.js, 7, 34))
>result : Symbol((Anonymous function).result, Decl(a.js, 12, 33))
@ -68,14 +68,14 @@ my.predicate.query.result = 'none'
*/
my.predicate.sort = my.predicate.sort || function (first, second) {
>my.predicate.sort : Symbol(sort, Decl(a.js, 13, 34))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>sort : Symbol(sort, Decl(a.js, 13, 34))
>my.predicate.sort : Symbol(sort, Decl(a.js, 13, 34))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>sort : Symbol(sort, Decl(a.js, 13, 34))
>first : Symbol(first, Decl(a.js, 17, 51))
>second : Symbol(second, Decl(a.js, 17, 57))
@ -88,9 +88,9 @@ my.predicate.sort = my.predicate.sort || function (first, second) {
}
my.predicate.type = class {
>my.predicate.type : Symbol(type, Decl(a.js, 19, 1))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 7, 34), Decl(a.js, 19, 1))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 7, 34), Decl(a.js, 13, 34), Decl(a.js, 19, 1))
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 17, 3), Decl(a.js, 20, 3))
>type : Symbol(type, Decl(a.js, 19, 1))
m() { return 101; }
@ -100,22 +100,22 @@ my.predicate.type = class {
// global-ish prefixes
var min = window.min || {};
>min : Symbol(min, Decl(a.js, 26, 3))
>min : Symbol(min, Decl(a.js, 26, 3), Decl(a.js, 26, 27), Decl(a.js, 27, 44))
min.nest = this.min.nest || function () { };
>min.nest : Symbol(nest, Decl(a.js, 26, 27))
>min : Symbol(min, Decl(a.js, 26, 3))
>nest : Symbol(nest, Decl(a.js, 26, 27))
>min.nest : Symbol(nest, Decl(a.js, 26, 27), Decl(a.js, 28, 4))
>min : Symbol(min, Decl(a.js, 26, 3), Decl(a.js, 26, 27), Decl(a.js, 27, 44))
>nest : Symbol(nest, Decl(a.js, 26, 27), Decl(a.js, 28, 4))
min.nest.other = self.min.nest.other || class { };
>min.nest.other : Symbol((Anonymous function).other, Decl(a.js, 27, 44))
>min.nest : Symbol(nest, Decl(a.js, 26, 27))
>min : Symbol(min, Decl(a.js, 26, 3))
>nest : Symbol(nest, Decl(a.js, 26, 27))
>min.nest : Symbol(nest, Decl(a.js, 26, 27), Decl(a.js, 28, 4))
>min : Symbol(min, Decl(a.js, 26, 3), Decl(a.js, 26, 27), Decl(a.js, 27, 44))
>nest : Symbol(nest, Decl(a.js, 26, 27), Decl(a.js, 28, 4))
>other : Symbol((Anonymous function).other, Decl(a.js, 27, 44))
min.property = global.min.property || {};
>min.property : Symbol(property, Decl(a.js, 28, 50))
>min : Symbol(min, Decl(a.js, 26, 3))
>min : Symbol(min, Decl(a.js, 26, 3), Decl(a.js, 26, 27), Decl(a.js, 27, 44))
>property : Symbol(property, Decl(a.js, 28, 50))

View File

@ -1,24 +1,24 @@
=== tests/cases/conformance/salsa/index.js ===
Common.Item = class I {}
>Common.Item : Symbol(Common.Item, Decl(index.js, 0, 0))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3), Decl(roots.js, 0, 12))
>Item : Symbol(Common.Item, Decl(index.js, 0, 0))
>I : Symbol(I, Decl(index.js, 0, 13))
Common.Object = class extends Common.Item {}
>Common.Object : Symbol(Common.Object, Decl(index.js, 0, 24))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3), Decl(roots.js, 0, 12))
>Object : Symbol(Common.Object, Decl(index.js, 0, 24))
>Common.Item : Symbol(Common.Item, Decl(index.js, 0, 0))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3), Decl(roots.js, 0, 12))
>Item : Symbol(Common.Item, Decl(index.js, 0, 0))
Workspace.Object = class extends Common.Object {}
>Workspace.Object : Symbol(Workspace.Object, Decl(index.js, 1, 44))
>Workspace : Symbol(Workspace, Decl(index.js, 1, 44), Decl(roots.js, 1, 3))
>Workspace : Symbol(Workspace, Decl(index.js, 1, 44), Decl(roots.js, 1, 3), Decl(roots.js, 1, 15))
>Object : Symbol(Workspace.Object, Decl(index.js, 1, 44))
>Common.Object : Symbol(Common.Object, Decl(index.js, 0, 24))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3), Decl(roots.js, 0, 12))
>Object : Symbol(Common.Object, Decl(index.js, 0, 24))
/** @type {Workspace.Object} */
@ -27,8 +27,8 @@ var am;
=== tests/cases/conformance/salsa/roots.js ===
var Common = {};
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3), Decl(roots.js, 0, 12))
var Workspace = {};
>Workspace : Symbol(Workspace, Decl(index.js, 1, 44), Decl(roots.js, 1, 3))
>Workspace : Symbol(Workspace, Decl(index.js, 1, 44), Decl(roots.js, 1, 3), Decl(roots.js, 1, 15))

View File

@ -13,7 +13,15 @@ Outer.Inner = class {
}
}
/** @type {Outer.Inner} */
var local
local.y
var inner = new Outer.Inner()
inner.y
// @Filename: b.js
/** @type {Outer.Inner} */
var x;
var x
x.y
var z = new Outer.Inner()
z.y