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) {
|
||||
// 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)) {
|
||||
return;
|
||||
}
|
||||
|
@ -3073,7 +3073,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
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);
|
||||
namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, propertyAccess.expression, isToplevel, isPrototypeProperty, containerIsClass);
|
||||
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).
|
||||
* 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 {
|
||||
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