Adds support for looking up past Blocks in expando objects (#38031)
* Adds support for looking up past Blocks in expando objects * Adds JS tests to validate the JS parsing also works * Get the top level block expando tests green
This commit is contained in:
parent
d9ad27f2dd
commit
0258db2210
|
@ -2964,7 +2964,7 @@ namespace ts {
|
||||||
|
|
||||||
function bindSpecialPropertyAssignment(node: BindablePropertyAssignmentExpression) {
|
function bindSpecialPropertyAssignment(node: BindablePropertyAssignmentExpression) {
|
||||||
// Class declarations in Typescript do not allow property declarations
|
// Class declarations in Typescript do not allow property declarations
|
||||||
const parentSymbol = lookupSymbolForPropertyAccess(node.left.expression);
|
const parentSymbol = lookupSymbolForPropertyAccess(node.left.expression, container) || lookupSymbolForPropertyAccess(node.left.expression, blockScopeContainer) ;
|
||||||
if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) {
|
if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3073,7 +3073,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
function bindPropertyAssignment(name: BindableStaticNameExpression, propertyAccess: BindableStaticAccessExpression, isPrototypeProperty: boolean, containerIsClass: boolean) {
|
function bindPropertyAssignment(name: BindableStaticNameExpression, propertyAccess: BindableStaticAccessExpression, isPrototypeProperty: boolean, containerIsClass: boolean) {
|
||||||
let namespaceSymbol = lookupSymbolForPropertyAccess(name);
|
let namespaceSymbol = lookupSymbolForPropertyAccess(name, container) || lookupSymbolForPropertyAccess(name, blockScopeContainer);
|
||||||
const isToplevel = isTopLevelNamespaceAssignment(propertyAccess);
|
const isToplevel = isTopLevelNamespaceAssignment(propertyAccess);
|
||||||
namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, propertyAccess.expression, isToplevel, isPrototypeProperty, containerIsClass);
|
namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, propertyAccess.expression, isToplevel, isPrototypeProperty, containerIsClass);
|
||||||
bindPotentiallyNewExpandoMemberToNamespace(propertyAccess, namespaceSymbol, isPrototypeProperty);
|
bindPotentiallyNewExpandoMemberToNamespace(propertyAccess, namespaceSymbol, isPrototypeProperty);
|
||||||
|
|
|
@ -2016,7 +2016,7 @@ namespace ts {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the assignment 'initializer' -- the righthand side-- when the initializer is container-like (See getExpandoInitializer).
|
* Get the assignment 'initializer' -- the righthand side-- when the initializer is container-like (See getExpandoInitializer).
|
||||||
* We treat the right hand side of assignments with container-like initalizers as declarations.
|
* We treat the right hand side of assignments with container-like initializers as declarations.
|
||||||
*/
|
*/
|
||||||
export function getAssignedExpandoInitializer(node: Node | undefined): Expression | undefined {
|
export function getAssignedExpandoInitializer(node: Node | undefined): Expression | undefined {
|
||||||
if (node && node.parent && isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
|
if (node && node.parent && isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||||
|
|
100
tests/baselines/reference/topLevelBlockExpando.symbols
Normal file
100
tests/baselines/reference/topLevelBlockExpando.symbols
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
=== tests/cases/compiler/check.ts ===
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/31972
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/31972
|
||||||
|
interface Person {
|
||||||
|
>Person : Symbol(Person, Decl(check.ts, 0, 0))
|
||||||
|
|
||||||
|
first: string;
|
||||||
|
>first : Symbol(Person.first, Decl(check.ts, 5, 18))
|
||||||
|
|
||||||
|
last: string;
|
||||||
|
>last : Symbol(Person.last, Decl(check.ts, 6, 16))
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const dice = () => Math.floor(Math.random() * 6);
|
||||||
|
>dice : Symbol(dice, Decl(check.ts, 11, 7))
|
||||||
|
>Math.floor : Symbol(Math.floor, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||||
|
>floor : Symbol(Math.floor, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||||
|
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||||
|
|
||||||
|
dice.first = 'Rando';
|
||||||
|
>dice.first : Symbol(dice.first, Decl(check.ts, 11, 51))
|
||||||
|
>dice : Symbol(dice, Decl(check.ts, 11, 7))
|
||||||
|
>first : Symbol(dice.first, Decl(check.ts, 11, 51))
|
||||||
|
|
||||||
|
dice.last = 'Calrissian';
|
||||||
|
>dice.last : Symbol(dice.last, Decl(check.ts, 12, 23))
|
||||||
|
>dice : Symbol(dice, Decl(check.ts, 11, 7))
|
||||||
|
>last : Symbol(dice.last, Decl(check.ts, 12, 23))
|
||||||
|
|
||||||
|
const diceP: Person = dice;
|
||||||
|
>diceP : Symbol(diceP, Decl(check.ts, 14, 7))
|
||||||
|
>Person : Symbol(Person, Decl(check.ts, 0, 0))
|
||||||
|
>dice : Symbol(dice, Decl(check.ts, 11, 7))
|
||||||
|
}
|
||||||
|
|
||||||
|
=== tests/cases/compiler/check.js ===
|
||||||
|
// Creates a type { first:string, last: string }
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Human - creates a new type named 'SpecialType'
|
||||||
|
* @property {string} first - a string property of SpecialType
|
||||||
|
* @property {string} last - a number property of SpecialType
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Human} param used as a validation tool
|
||||||
|
*/
|
||||||
|
function doHumanThings(param) {}
|
||||||
|
>doHumanThings : Symbol(doHumanThings, Decl(check.js, 0, 0))
|
||||||
|
>param : Symbol(param, Decl(check.js, 10, 23))
|
||||||
|
|
||||||
|
const dice1 = () => Math.floor(Math.random() * 6);
|
||||||
|
>dice1 : Symbol(dice1, Decl(check.js, 12, 5), Decl(check.js, 12, 50))
|
||||||
|
>Math.floor : Symbol(Math.floor, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||||
|
>floor : Symbol(Math.floor, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||||
|
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||||
|
|
||||||
|
// dice1.first = 'Rando';
|
||||||
|
dice1.last = 'Calrissian';
|
||||||
|
>dice1.last : Symbol(dice1.last, Decl(check.js, 12, 50))
|
||||||
|
>dice1 : Symbol(dice1, Decl(check.js, 12, 5), Decl(check.js, 12, 50))
|
||||||
|
>last : Symbol(dice1.last, Decl(check.js, 12, 50))
|
||||||
|
|
||||||
|
// doHumanThings(dice)
|
||||||
|
|
||||||
|
// but inside a block... you can't call a human
|
||||||
|
{
|
||||||
|
const dice2 = () => Math.floor(Math.random() * 6);
|
||||||
|
>dice2 : Symbol(dice2, Decl(check.js, 20, 7))
|
||||||
|
>Math.floor : Symbol(Math.floor, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||||
|
>floor : Symbol(Math.floor, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||||
|
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||||
|
|
||||||
|
dice2.first = 'Rando';
|
||||||
|
>dice2.first : Symbol(dice2.first, Decl(check.js, 20, 52))
|
||||||
|
>dice2 : Symbol(dice2, Decl(check.js, 20, 7))
|
||||||
|
>first : Symbol(dice2.first, Decl(check.js, 20, 52))
|
||||||
|
|
||||||
|
dice2.last = 'Calrissian';
|
||||||
|
>dice2.last : Symbol(dice2.last, Decl(check.js, 21, 24))
|
||||||
|
>dice2 : Symbol(dice2, Decl(check.js, 20, 7))
|
||||||
|
>last : Symbol(dice2.last, Decl(check.js, 21, 24))
|
||||||
|
|
||||||
|
doHumanThings(dice2)
|
||||||
|
>doHumanThings : Symbol(doHumanThings, Decl(check.js, 0, 0))
|
||||||
|
>dice2 : Symbol(dice2, Decl(check.js, 20, 7))
|
||||||
|
}
|
||||||
|
|
123
tests/baselines/reference/topLevelBlockExpando.types
Normal file
123
tests/baselines/reference/topLevelBlockExpando.types
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
=== tests/cases/compiler/check.ts ===
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/31972
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/31972
|
||||||
|
interface Person {
|
||||||
|
first: string;
|
||||||
|
>first : string
|
||||||
|
|
||||||
|
last: string;
|
||||||
|
>last : string
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const dice = () => Math.floor(Math.random() * 6);
|
||||||
|
>dice : { (): number; first: string; last: string; }
|
||||||
|
>() => Math.floor(Math.random() * 6) : { (): number; first: string; last: string; }
|
||||||
|
>Math.floor(Math.random() * 6) : number
|
||||||
|
>Math.floor : (x: number) => number
|
||||||
|
>Math : Math
|
||||||
|
>floor : (x: number) => number
|
||||||
|
>Math.random() * 6 : number
|
||||||
|
>Math.random() : number
|
||||||
|
>Math.random : () => number
|
||||||
|
>Math : Math
|
||||||
|
>random : () => number
|
||||||
|
>6 : 6
|
||||||
|
|
||||||
|
dice.first = 'Rando';
|
||||||
|
>dice.first = 'Rando' : "Rando"
|
||||||
|
>dice.first : string
|
||||||
|
>dice : { (): number; first: string; last: string; }
|
||||||
|
>first : string
|
||||||
|
>'Rando' : "Rando"
|
||||||
|
|
||||||
|
dice.last = 'Calrissian';
|
||||||
|
>dice.last = 'Calrissian' : "Calrissian"
|
||||||
|
>dice.last : string
|
||||||
|
>dice : { (): number; first: string; last: string; }
|
||||||
|
>last : string
|
||||||
|
>'Calrissian' : "Calrissian"
|
||||||
|
|
||||||
|
const diceP: Person = dice;
|
||||||
|
>diceP : Person
|
||||||
|
>dice : { (): number; first: string; last: string; }
|
||||||
|
}
|
||||||
|
|
||||||
|
=== tests/cases/compiler/check.js ===
|
||||||
|
// Creates a type { first:string, last: string }
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Human - creates a new type named 'SpecialType'
|
||||||
|
* @property {string} first - a string property of SpecialType
|
||||||
|
* @property {string} last - a number property of SpecialType
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Human} param used as a validation tool
|
||||||
|
*/
|
||||||
|
function doHumanThings(param) {}
|
||||||
|
>doHumanThings : (param: Human) => void
|
||||||
|
>param : Human
|
||||||
|
|
||||||
|
const dice1 = () => Math.floor(Math.random() * 6);
|
||||||
|
>dice1 : { (): number; last: string; }
|
||||||
|
>() => Math.floor(Math.random() * 6) : { (): number; last: string; }
|
||||||
|
>Math.floor(Math.random() * 6) : number
|
||||||
|
>Math.floor : (x: number) => number
|
||||||
|
>Math : Math
|
||||||
|
>floor : (x: number) => number
|
||||||
|
>Math.random() * 6 : number
|
||||||
|
>Math.random() : number
|
||||||
|
>Math.random : () => number
|
||||||
|
>Math : Math
|
||||||
|
>random : () => number
|
||||||
|
>6 : 6
|
||||||
|
|
||||||
|
// dice1.first = 'Rando';
|
||||||
|
dice1.last = 'Calrissian';
|
||||||
|
>dice1.last = 'Calrissian' : "Calrissian"
|
||||||
|
>dice1.last : string
|
||||||
|
>dice1 : { (): number; last: string; }
|
||||||
|
>last : string
|
||||||
|
>'Calrissian' : "Calrissian"
|
||||||
|
|
||||||
|
// doHumanThings(dice)
|
||||||
|
|
||||||
|
// but inside a block... you can't call a human
|
||||||
|
{
|
||||||
|
const dice2 = () => Math.floor(Math.random() * 6);
|
||||||
|
>dice2 : { (): number; first: string; last: string; }
|
||||||
|
>() => Math.floor(Math.random() * 6) : { (): number; first: string; last: string; }
|
||||||
|
>Math.floor(Math.random() * 6) : number
|
||||||
|
>Math.floor : (x: number) => number
|
||||||
|
>Math : Math
|
||||||
|
>floor : (x: number) => number
|
||||||
|
>Math.random() * 6 : number
|
||||||
|
>Math.random() : number
|
||||||
|
>Math.random : () => number
|
||||||
|
>Math : Math
|
||||||
|
>random : () => number
|
||||||
|
>6 : 6
|
||||||
|
|
||||||
|
dice2.first = 'Rando';
|
||||||
|
>dice2.first = 'Rando' : "Rando"
|
||||||
|
>dice2.first : string
|
||||||
|
>dice2 : { (): number; first: string; last: string; }
|
||||||
|
>first : string
|
||||||
|
>'Rando' : "Rando"
|
||||||
|
|
||||||
|
dice2.last = 'Calrissian';
|
||||||
|
>dice2.last = 'Calrissian' : "Calrissian"
|
||||||
|
>dice2.last : string
|
||||||
|
>dice2 : { (): number; first: string; last: string; }
|
||||||
|
>last : string
|
||||||
|
>'Calrissian' : "Calrissian"
|
||||||
|
|
||||||
|
doHumanThings(dice2)
|
||||||
|
>doHumanThings(dice2) : void
|
||||||
|
>doHumanThings : (param: Human) => void
|
||||||
|
>dice2 : { (): number; first: string; last: string; }
|
||||||
|
}
|
||||||
|
|
49
tests/cases/compiler/topLevelBlockExpando.ts
Normal file
49
tests/cases/compiler/topLevelBlockExpando.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/31972
|
||||||
|
|
||||||
|
// @allowJs: true
|
||||||
|
// @noEmit: true
|
||||||
|
// @checkJs: true
|
||||||
|
|
||||||
|
// @filename: check.ts
|
||||||
|
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/31972
|
||||||
|
interface Person {
|
||||||
|
first: string;
|
||||||
|
last: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const dice = () => Math.floor(Math.random() * 6);
|
||||||
|
dice.first = 'Rando';
|
||||||
|
dice.last = 'Calrissian';
|
||||||
|
const diceP: Person = dice;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @filename: check.js
|
||||||
|
|
||||||
|
// Creates a type { first:string, last: string }
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Human - creates a new type named 'SpecialType'
|
||||||
|
* @property {string} first - a string property of SpecialType
|
||||||
|
* @property {string} last - a number property of SpecialType
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Human} param used as a validation tool
|
||||||
|
*/
|
||||||
|
function doHumanThings(param) {}
|
||||||
|
|
||||||
|
const dice1 = () => Math.floor(Math.random() * 6);
|
||||||
|
// dice1.first = 'Rando';
|
||||||
|
dice1.last = 'Calrissian';
|
||||||
|
|
||||||
|
// doHumanThings(dice)
|
||||||
|
|
||||||
|
// but inside a block... you can't call a human
|
||||||
|
{
|
||||||
|
const dice2 = () => Math.floor(Math.random() * 6);
|
||||||
|
dice2.first = 'Rando';
|
||||||
|
dice2.last = 'Calrissian';
|
||||||
|
|
||||||
|
doHumanThings(dice2)
|
||||||
|
}
|
Loading…
Reference in a new issue