Add support for Optional Chaining (#33294)

* Add support for Optional Chaining

* Add grammar error for invalid tagged template, more tests

* Prototype

* PR feedback

* Add errors for invalid assignments and a trailing '?.'

* Add additional signature help test, fix lint warnings

* Fix to insert text for completions

* Add initial control-flow analysis for optional chains

* PR Feedback and more tests

* Update to control flow

* Remove mangled smart quotes in comments

* Fix lint, PR feedback

* Updates to control flow

* Switch to FlowCondition for CFA of optional chains

* Fix ?. insertion for completions on type variables

* Accept API baseline change

* Clean up types

* improve control-flow debug output

* Revert Debug.formatControlFlowGraph helper
This commit is contained in:
Ron Buckton
2019-09-30 12:33:28 -07:00
committed by GitHub
parent 7ce793c5b8
commit fcd9334f57
76 changed files with 6422 additions and 885 deletions

View File

@@ -76,6 +76,7 @@
"unittests/evaluation/awaiter.ts",
"unittests/evaluation/forAwaitOf.ts",
"unittests/evaluation/forOf.ts",
"unittests/evaluation/optionalCall.ts",
"unittests/evaluation/objectRest.ts",
"unittests/services/cancellableLanguageServiceOperations.ts",
"unittests/services/colorization.ts",

View File

@@ -0,0 +1,191 @@
describe("unittests:: evaluation:: optionalCall", () => {
it("f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
function f(a) {
output.push(a);
output.push(this);
}
export const output: any[] = [];
f?.(1);
`);
assert.strictEqual(result.output[0], 1);
assert.isUndefined(result.output[1]);
});
it("o.f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
f(a) {
output.push(a);
output.push(this);
}
};
export const output: any[] = [];
o.f?.(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o);
});
it("o.x.f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
x: {
f(a) {
output.push(a);
output.push(this);
}
}
};
export const output: any[] = [];
o.x.f?.(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o.x);
});
it("o?.f()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
f(a) {
output.push(a);
output.push(this);
}
};
export const output: any[] = [];
o?.f(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o);
});
it("o?.f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
f(a) {
output.push(a);
output.push(this);
}
};
export const output: any[] = [];
o?.f?.(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o);
});
it("o.x?.f()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
x: {
f(a) {
output.push(a);
output.push(this);
}
}
};
export const output: any[] = [];
o.x?.f(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o.x);
});
it("o?.x.f()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
x: {
f(a) {
output.push(a);
output.push(this);
}
}
};
export const output: any[] = [];
o?.x.f(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o.x);
});
it("o?.x?.f()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
x: {
f(a) {
output.push(a);
output.push(this);
}
}
};
export const output: any[] = [];
o?.x?.f(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o.x);
});
it("o?.x?.f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
x: {
f(a) {
output.push(a);
output.push(this);
}
}
};
export const output: any[] = [];
o?.x?.f?.(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o.x);
});
it("f?.()?.()", async () => {
const result = evaluator.evaluateTypeScript(`
function g(a) {
output.push(a);
output.push(this);
}
function f(a) {
output.push(a);
return g;
}
export const output: any[] = [];
f?.(1)?.(2)
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], 2);
assert.isUndefined(result.output[2]);
});
it("f?.().f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
f(a) {
output.push(a);
output.push(this);
}
};
function f(a) {
output.push(a);
return o;
}
export const output: any[] = [];
f?.(1).f?.(2)
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], 2);
assert.strictEqual(result.output[2], result.o);
});
it("f?.()?.f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
f(a) {
output.push(a);
output.push(this);
}
};
function f(a) {
output.push(a);
return o;
}
export const output: any[] = [];
f?.(1)?.f?.(2)
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], 2);
assert.strictEqual(result.output[2], result.o);
});
});