Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
41baf41700 | |||
76b9a63359 | |||
056930f1c8 | |||
d7c8d3bb97 |
|
@ -985,7 +985,7 @@ namespace ts {
|
|||
return initFlowNode({ flags: FlowFlags.SwitchClause, antecedent, switchStatement, clauseStart, clauseEnd });
|
||||
}
|
||||
|
||||
function createFlowMutation(flags: FlowFlags, antecedent: FlowNode, node: Node): FlowNode {
|
||||
function createFlowMutation(flags: FlowFlags, antecedent: FlowNode, node: Expression | VariableDeclaration | ArrayBindingElement): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
const result = initFlowNode({ flags, antecedent, node });
|
||||
if (currentExceptionTarget) {
|
||||
|
@ -1341,7 +1341,7 @@ namespace ts {
|
|||
// is potentially an assertion and is therefore included in the control flow.
|
||||
if (node.expression.kind === SyntaxKind.CallExpression) {
|
||||
const call = <CallExpression>node.expression;
|
||||
if (isDottedName(call.expression)) {
|
||||
if (isDottedName(call.expression) && call.expression.kind !== SyntaxKind.SuperKeyword) {
|
||||
currentFlow = createFlowCall(currentFlow, call);
|
||||
}
|
||||
}
|
||||
|
@ -1747,6 +1747,9 @@ namespace ts {
|
|||
}
|
||||
else {
|
||||
bindEachChild(node);
|
||||
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
currentFlow = createFlowCall(currentFlow, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
|
@ -2464,6 +2467,9 @@ namespace ts {
|
|||
node.flowNode = currentFlow;
|
||||
}
|
||||
return checkStrictModeIdentifier(<Identifier>node);
|
||||
case SyntaxKind.SuperKeyword:
|
||||
node.flowNode = currentFlow;
|
||||
break;
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
return checkPrivateIdentifier(node as PrivateIdentifier);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
|
|
|
@ -911,6 +911,7 @@ namespace ts {
|
|||
const sharedFlowNodes: FlowNode[] = [];
|
||||
const sharedFlowTypes: FlowType[] = [];
|
||||
const flowNodeReachable: (boolean | undefined)[] = [];
|
||||
const flowNodePostSuper: (boolean | undefined)[] = [];
|
||||
const potentialThisCollisions: Node[] = [];
|
||||
const potentialNewTargetCollisions: Node[] = [];
|
||||
const potentialWeakMapCollisions: Node[] = [];
|
||||
|
@ -20134,7 +20135,7 @@ namespace ts {
|
|||
noCacheCheck = false;
|
||||
}
|
||||
if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation)) {
|
||||
flow = (<FlowAssignment | FlowCondition | FlowArrayMutation | PreFinallyFlow>flow).antecedent;
|
||||
flow = (<FlowAssignment | FlowCondition | FlowArrayMutation>flow).antecedent;
|
||||
}
|
||||
else if (flags & FlowFlags.Call) {
|
||||
const signature = getEffectsSignature((<FlowCall>flow).node);
|
||||
|
@ -20184,6 +20185,51 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
// Return true if the given flow node is preceded by a 'super(...)' call in every possible code path
|
||||
// leading to the node.
|
||||
function isPostSuperFlowNode(flow: FlowNode, noCacheCheck: boolean): boolean {
|
||||
while (true) {
|
||||
const flags = flow.flags;
|
||||
if (flags & FlowFlags.Shared) {
|
||||
if (!noCacheCheck) {
|
||||
const id = getFlowNodeId(flow);
|
||||
const postSuper = flowNodePostSuper[id];
|
||||
return postSuper !== undefined ? postSuper : (flowNodePostSuper[id] = isPostSuperFlowNode(flow, /*noCacheCheck*/ true));
|
||||
}
|
||||
noCacheCheck = false;
|
||||
}
|
||||
if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation | FlowFlags.SwitchClause)) {
|
||||
flow = (<FlowAssignment | FlowCondition | FlowArrayMutation | FlowSwitchClause>flow).antecedent;
|
||||
}
|
||||
else if (flags & FlowFlags.Call) {
|
||||
if ((<FlowCall>flow).node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
return true;
|
||||
}
|
||||
flow = (<FlowCall>flow).antecedent;
|
||||
}
|
||||
else if (flags & FlowFlags.BranchLabel) {
|
||||
// A branching point is post-super if every branch is post-super.
|
||||
return every((<FlowLabel>flow).antecedents, f => isPostSuperFlowNode(f, /*noCacheCheck*/ false));
|
||||
}
|
||||
else if (flags & FlowFlags.LoopLabel) {
|
||||
// A loop is post-super if the control flow path that leads to the top is post-super.
|
||||
flow = (<FlowLabel>flow).antecedents![0];
|
||||
}
|
||||
else if (flags & FlowFlags.ReduceLabel) {
|
||||
const target = (<FlowReduceLabel>flow).target;
|
||||
const saveAntecedents = target.antecedents;
|
||||
target.antecedents = (<FlowReduceLabel>flow).antecedents;
|
||||
const result = isPostSuperFlowNode((<FlowReduceLabel>flow).antecedent, /*noCacheCheck*/ false);
|
||||
target.antecedents = saveAntecedents;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
// Unreachable nodes are considered post-super to silence errors
|
||||
return !!(flags & FlowFlags.Unreachable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, couldBeUninitialized?: boolean) {
|
||||
let key: string | undefined;
|
||||
let keySet = false;
|
||||
|
@ -21583,31 +21629,10 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function findFirstSuperCall(n: Node): SuperCall | undefined {
|
||||
if (isSuperCall(n)) {
|
||||
return n;
|
||||
}
|
||||
else if (isFunctionLike(n)) {
|
||||
return undefined;
|
||||
}
|
||||
return forEachChild(n, findFirstSuperCall);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a cached result if super-statement is already found.
|
||||
* Otherwise, find a super statement in a given constructor function and cache the result in the node-links of the constructor
|
||||
*
|
||||
* @param constructor constructor-function to look for super statement
|
||||
*/
|
||||
function getSuperCallInConstructor(constructor: ConstructorDeclaration): SuperCall | undefined {
|
||||
const links = getNodeLinks(constructor);
|
||||
|
||||
// Only trying to find super-call if we haven't yet tried to find one. Once we try, we will record the result
|
||||
if (links.hasSuperCall === undefined) {
|
||||
links.superCall = findFirstSuperCall(constructor.body!);
|
||||
links.hasSuperCall = links.superCall ? true : false;
|
||||
}
|
||||
return links.superCall!;
|
||||
function findFirstSuperCall(node: Node): SuperCall | undefined {
|
||||
return isSuperCall(node) ? node :
|
||||
isFunctionLike(node) ? undefined :
|
||||
forEachChild(node, findFirstSuperCall);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21630,17 +21655,7 @@ namespace ts {
|
|||
// If a containing class does not have extends clause or the class extends null
|
||||
// skip checking whether super statement is called before "this" accessing.
|
||||
if (baseTypeNode && !classDeclarationExtendsNull(containingClassDecl)) {
|
||||
const superCall = getSuperCallInConstructor(<ConstructorDeclaration>container);
|
||||
|
||||
// We should give an error in the following cases:
|
||||
// - No super-call
|
||||
// - "this" is accessing before super-call.
|
||||
// i.e super(this)
|
||||
// this.x; super();
|
||||
// We want to make sure that super-call is done before accessing "this" so that
|
||||
// "this" is not accessed as a parameter of the super-call.
|
||||
if (!superCall || superCall.end > node.pos) {
|
||||
// In ES6, super inside constructor of class-declaration has to precede "this" accessing
|
||||
if (node.flowNode && !isPostSuperFlowNode(node.flowNode, /*noCacheCheck*/ false)) {
|
||||
error(node, diagnosticMessage);
|
||||
}
|
||||
}
|
||||
|
@ -21865,7 +21880,8 @@ namespace ts {
|
|||
function checkSuperExpression(node: Node): Type {
|
||||
const isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (<CallExpression>node.parent).expression === node;
|
||||
|
||||
let container = getSuperContainer(node, /*stopOnFunctions*/ true);
|
||||
const immediateContainer = getSuperContainer(node, /*stopOnFunctions*/ true);
|
||||
let container = immediateContainer;
|
||||
let needToCaptureLexicalThis = false;
|
||||
|
||||
// adjust the container reference in case if super is used inside arrow functions with arbitrarily deep nesting
|
||||
|
@ -21901,7 +21917,7 @@ namespace ts {
|
|||
return errorType;
|
||||
}
|
||||
|
||||
if (!isCallExpression && container.kind === SyntaxKind.Constructor) {
|
||||
if (!isCallExpression && immediateContainer.kind === SyntaxKind.Constructor) {
|
||||
checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class);
|
||||
}
|
||||
|
||||
|
@ -29898,7 +29914,7 @@ namespace ts {
|
|||
if (getClassExtendsHeritageElement(containingClassDecl)) {
|
||||
captureLexicalThis(node.parent, containingClassDecl);
|
||||
const classExtendsNull = classDeclarationExtendsNull(containingClassDecl);
|
||||
const superCall = getSuperCallInConstructor(node);
|
||||
const superCall = findFirstSuperCall(node.body!);
|
||||
if (superCall) {
|
||||
if (classExtendsNull) {
|
||||
error(superCall, Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null);
|
||||
|
|
|
@ -150,7 +150,7 @@ namespace ts {
|
|||
* returns a falsey value, then returns false.
|
||||
* If no such value is found, the callback is applied to each element of array and `true` is returned.
|
||||
*/
|
||||
export function every<T>(array: readonly T[], callback: (element: T, index: number) => boolean): boolean {
|
||||
export function every<T>(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean {
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (!callback(array[i], i)) {
|
||||
|
|
|
@ -2791,34 +2791,21 @@ namespace ts {
|
|||
}
|
||||
|
||||
export type FlowNode =
|
||||
| AfterFinallyFlow
|
||||
| PreFinallyFlow
|
||||
| FlowStart
|
||||
| FlowLabel
|
||||
| FlowAssignment
|
||||
| FlowCall
|
||||
| FlowCondition
|
||||
| FlowSwitchClause
|
||||
| FlowArrayMutation;
|
||||
| FlowArrayMutation
|
||||
| FlowCall
|
||||
| FlowReduceLabel;
|
||||
|
||||
export interface FlowNodeBase {
|
||||
flags: FlowFlags;
|
||||
id?: number; // Node id used by flow type cache in checker
|
||||
}
|
||||
|
||||
export interface FlowLock {
|
||||
locked?: boolean;
|
||||
}
|
||||
|
||||
export interface AfterFinallyFlow extends FlowNodeBase, FlowLock {
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export interface PreFinallyFlow extends FlowNodeBase {
|
||||
antecedent: FlowNode;
|
||||
lock: FlowLock;
|
||||
}
|
||||
|
||||
// FlowStart represents the start of a control flow. For a function expression or arrow
|
||||
// function, the node property references the function (which in turn has a flowNode
|
||||
// property for the containing control flow).
|
||||
|
@ -4316,8 +4303,6 @@ namespace ts {
|
|||
resolvedJsxElementAttributesType?: Type; // resolved element attributes type of a JSX openinglike element
|
||||
resolvedJsxElementAllAttributesType?: Type; // resolved all element attributes type of a JSX openinglike element
|
||||
resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference
|
||||
hasSuperCall?: boolean; // recorded result when we try to find super-call. We only try to find one if this flag is undefined, indicating that we haven't made an attempt.
|
||||
superCall?: SuperCall; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing
|
||||
switchTypes?: Type[]; // Cached array of switch case expression types
|
||||
jsxNamespace?: Symbol | false; // Resolved jsx namespace symbol for this node
|
||||
contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive
|
||||
|
|
|
@ -1743,21 +1743,11 @@ declare namespace ts {
|
|||
Label = 12,
|
||||
Condition = 96
|
||||
}
|
||||
export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation;
|
||||
export type FlowNode = FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation | FlowCall | FlowReduceLabel;
|
||||
export interface FlowNodeBase {
|
||||
flags: FlowFlags;
|
||||
id?: number;
|
||||
}
|
||||
export interface FlowLock {
|
||||
locked?: boolean;
|
||||
}
|
||||
export interface AfterFinallyFlow extends FlowNodeBase, FlowLock {
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
export interface PreFinallyFlow extends FlowNodeBase {
|
||||
antecedent: FlowNode;
|
||||
lock: FlowLock;
|
||||
}
|
||||
export interface FlowStart extends FlowNodeBase {
|
||||
node?: FunctionExpression | ArrowFunction | MethodDeclaration;
|
||||
}
|
||||
|
|
12
tests/baselines/reference/api/typescript.d.ts
vendored
12
tests/baselines/reference/api/typescript.d.ts
vendored
|
@ -1743,21 +1743,11 @@ declare namespace ts {
|
|||
Label = 12,
|
||||
Condition = 96
|
||||
}
|
||||
export type FlowNode = AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation;
|
||||
export type FlowNode = FlowStart | FlowLabel | FlowAssignment | FlowCall | FlowCondition | FlowSwitchClause | FlowArrayMutation | FlowCall | FlowReduceLabel;
|
||||
export interface FlowNodeBase {
|
||||
flags: FlowFlags;
|
||||
id?: number;
|
||||
}
|
||||
export interface FlowLock {
|
||||
locked?: boolean;
|
||||
}
|
||||
export interface AfterFinallyFlow extends FlowNodeBase, FlowLock {
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
export interface PreFinallyFlow extends FlowNodeBase {
|
||||
antecedent: FlowNode;
|
||||
lock: FlowLock;
|
||||
}
|
||||
export interface FlowStart extends FlowNodeBase {
|
||||
node?: FunctionExpression | ArrowFunction | MethodDeclaration;
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
tests/cases/compiler/captureSuperPropertyAccessInSuperCall01.ts(9,24): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
|
||||
|
||||
==== tests/cases/compiler/captureSuperPropertyAccessInSuperCall01.ts (1 errors) ====
|
||||
class A {
|
||||
constructor(f: () => string) {
|
||||
}
|
||||
public blah(): string { return ""; }
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
constructor() {
|
||||
super(() => { return super.blah(); })
|
||||
~~~~~
|
||||
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(7,18): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(8,18): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(9,18): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(20,22): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(21,22): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(22,22): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(30,30): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(39,22): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(43,18): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(44,18): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(45,18): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(59,27): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts(75,27): error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
|
||||
|
||||
==== tests/cases/compiler/checkSuperCallBeforeThisAccess.ts (13 errors) ====
|
||||
class A {
|
||||
x = 1;
|
||||
}
|
||||
|
||||
class C1 extends A {
|
||||
constructor(n: number) {
|
||||
let a1 = this; // Error
|
||||
~~~~
|
||||
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
let a2 = this.x; // Error
|
||||
~~~~
|
||||
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
let a3 = super.x; // Error
|
||||
~~~~~
|
||||
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
let a4 = () => this;
|
||||
let a5 = () => this.x;
|
||||
let a6 = () => super.x;
|
||||
if (!!true) {
|
||||
super();
|
||||
let b1 = this;
|
||||
let b2 = this.x;
|
||||
let b3 = super.x;
|
||||
}
|
||||
else {
|
||||
let c1 = this; // Error
|
||||
~~~~
|
||||
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
let c2 = this.x; // Error
|
||||
~~~~
|
||||
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
let c3 = super.x; // Error
|
||||
~~~~~
|
||||
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
}
|
||||
if (!!true) {
|
||||
switch (n) {
|
||||
case 1:
|
||||
super();
|
||||
let d1 = this.x;
|
||||
case 2:
|
||||
let d2 = this.x; // Error
|
||||
~~~~
|
||||
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
default:
|
||||
super();
|
||||
let d3 = this.x;
|
||||
}
|
||||
let d4 = this.x;
|
||||
}
|
||||
if (!!true) {
|
||||
let e1 = { w: !!true ? super() : 0 };
|
||||
let e2 = this.x; // Error
|
||||
~~~~
|
||||
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
let e3 = { w: !!true ? super() : super() };
|
||||
let e4 = this.x;
|
||||
}
|
||||
let f1 = this; // Error
|
||||
~~~~
|
||||
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
let f2 = this.x; // Error
|
||||
~~~~
|
||||
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
let f3 = super.x; // Error
|
||||
~~~~~
|
||||
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38512
|
||||
|
||||
export class Foo {
|
||||
constructor(value: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export class BarCorrectlyFails extends Foo {
|
||||
constructor(something: boolean) {
|
||||
if (!something) {
|
||||
const value = this.bar(); // Error
|
||||
~~~~
|
||||
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
super(value);
|
||||
}
|
||||
else {
|
||||
super(1337);
|
||||
}
|
||||
}
|
||||
bar(): number { return 4; }
|
||||
}
|
||||
|
||||
export class BarIncorrectlyWorks extends Foo {
|
||||
constructor(something: boolean) {
|
||||
if (something) {
|
||||
super(1337);
|
||||
}
|
||||
else {
|
||||
const value = this.bar(); // Error
|
||||
~~~~
|
||||
!!! error TS17009: 'super' must be called before accessing 'this' in the constructor of a derived class.
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
bar(): number { return 4; }
|
||||
}
|
||||
|
161
tests/baselines/reference/checkSuperCallBeforeThisAccess.js
Normal file
161
tests/baselines/reference/checkSuperCallBeforeThisAccess.js
Normal file
|
@ -0,0 +1,161 @@
|
|||
//// [checkSuperCallBeforeThisAccess.ts]
|
||||
class A {
|
||||
x = 1;
|
||||
}
|
||||
|
||||
class C1 extends A {
|
||||
constructor(n: number) {
|
||||
let a1 = this; // Error
|
||||
let a2 = this.x; // Error
|
||||
let a3 = super.x; // Error
|
||||
let a4 = () => this;
|
||||
let a5 = () => this.x;
|
||||
let a6 = () => super.x;
|
||||
if (!!true) {
|
||||
super();
|
||||
let b1 = this;
|
||||
let b2 = this.x;
|
||||
let b3 = super.x;
|
||||
}
|
||||
else {
|
||||
let c1 = this; // Error
|
||||
let c2 = this.x; // Error
|
||||
let c3 = super.x; // Error
|
||||
}
|
||||
if (!!true) {
|
||||
switch (n) {
|
||||
case 1:
|
||||
super();
|
||||
let d1 = this.x;
|
||||
case 2:
|
||||
let d2 = this.x; // Error
|
||||
default:
|
||||
super();
|
||||
let d3 = this.x;
|
||||
}
|
||||
let d4 = this.x;
|
||||
}
|
||||
if (!!true) {
|
||||
let e1 = { w: !!true ? super() : 0 };
|
||||
let e2 = this.x; // Error
|
||||
let e3 = { w: !!true ? super() : super() };
|
||||
let e4 = this.x;
|
||||
}
|
||||
let f1 = this; // Error
|
||||
let f2 = this.x; // Error
|
||||
let f3 = super.x; // Error
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38512
|
||||
|
||||
export class Foo {
|
||||
constructor(value: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export class BarCorrectlyFails extends Foo {
|
||||
constructor(something: boolean) {
|
||||
if (!something) {
|
||||
const value = this.bar(); // Error
|
||||
super(value);
|
||||
}
|
||||
else {
|
||||
super(1337);
|
||||
}
|
||||
}
|
||||
bar(): number { return 4; }
|
||||
}
|
||||
|
||||
export class BarIncorrectlyWorks extends Foo {
|
||||
constructor(something: boolean) {
|
||||
if (something) {
|
||||
super(1337);
|
||||
}
|
||||
else {
|
||||
const value = this.bar(); // Error
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
bar(): number { return 4; }
|
||||
}
|
||||
|
||||
|
||||
//// [checkSuperCallBeforeThisAccess.js]
|
||||
class A {
|
||||
constructor() {
|
||||
this.x = 1;
|
||||
}
|
||||
}
|
||||
class C1 extends A {
|
||||
constructor(n) {
|
||||
let a1 = this; // Error
|
||||
let a2 = this.x; // Error
|
||||
let a3 = super.x; // Error
|
||||
let a4 = () => this;
|
||||
let a5 = () => this.x;
|
||||
let a6 = () => super.x;
|
||||
if (!!true) {
|
||||
super();
|
||||
let b1 = this;
|
||||
let b2 = this.x;
|
||||
let b3 = super.x;
|
||||
}
|
||||
else {
|
||||
let c1 = this; // Error
|
||||
let c2 = this.x; // Error
|
||||
let c3 = super.x; // Error
|
||||
}
|
||||
if (!!true) {
|
||||
switch (n) {
|
||||
case 1:
|
||||
super();
|
||||
let d1 = this.x;
|
||||
case 2:
|
||||
let d2 = this.x; // Error
|
||||
default:
|
||||
super();
|
||||
let d3 = this.x;
|
||||
}
|
||||
let d4 = this.x;
|
||||
}
|
||||
if (!!true) {
|
||||
let e1 = { w: !!true ? super() : 0 };
|
||||
let e2 = this.x; // Error
|
||||
let e3 = { w: !!true ? super() : super() };
|
||||
let e4 = this.x;
|
||||
}
|
||||
let f1 = this; // Error
|
||||
let f2 = this.x; // Error
|
||||
let f3 = super.x; // Error
|
||||
}
|
||||
}
|
||||
// Repro from #38512
|
||||
export class Foo {
|
||||
constructor(value) {
|
||||
}
|
||||
}
|
||||
export class BarCorrectlyFails extends Foo {
|
||||
constructor(something) {
|
||||
if (!something) {
|
||||
const value = this.bar(); // Error
|
||||
super(value);
|
||||
}
|
||||
else {
|
||||
super(1337);
|
||||
}
|
||||
}
|
||||
bar() { return 4; }
|
||||
}
|
||||
export class BarIncorrectlyWorks extends Foo {
|
||||
constructor(something) {
|
||||
if (something) {
|
||||
super(1337);
|
||||
}
|
||||
else {
|
||||
const value = this.bar(); // Error
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
bar() { return 4; }
|
||||
}
|
231
tests/baselines/reference/checkSuperCallBeforeThisAccess.symbols
Normal file
231
tests/baselines/reference/checkSuperCallBeforeThisAccess.symbols
Normal file
|
@ -0,0 +1,231 @@
|
|||
=== tests/cases/compiler/checkSuperCallBeforeThisAccess.ts ===
|
||||
class A {
|
||||
>A : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
|
||||
x = 1;
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
}
|
||||
|
||||
class C1 extends A {
|
||||
>C1 : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>A : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
|
||||
constructor(n: number) {
|
||||
>n : Symbol(n, Decl(checkSuperCallBeforeThisAccess.ts, 5, 16))
|
||||
|
||||
let a1 = this; // Error
|
||||
>a1 : Symbol(a1, Decl(checkSuperCallBeforeThisAccess.ts, 6, 11))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
|
||||
let a2 = this.x; // Error
|
||||
>a2 : Symbol(a2, Decl(checkSuperCallBeforeThisAccess.ts, 7, 11))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
|
||||
let a3 = super.x; // Error
|
||||
>a3 : Symbol(a3, Decl(checkSuperCallBeforeThisAccess.ts, 8, 11))
|
||||
>super.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
|
||||
let a4 = () => this;
|
||||
>a4 : Symbol(a4, Decl(checkSuperCallBeforeThisAccess.ts, 9, 11))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
|
||||
let a5 = () => this.x;
|
||||
>a5 : Symbol(a5, Decl(checkSuperCallBeforeThisAccess.ts, 10, 11))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
|
||||
let a6 = () => super.x;
|
||||
>a6 : Symbol(a6, Decl(checkSuperCallBeforeThisAccess.ts, 11, 11))
|
||||
>super.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
|
||||
if (!!true) {
|
||||
super();
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
|
||||
let b1 = this;
|
||||
>b1 : Symbol(b1, Decl(checkSuperCallBeforeThisAccess.ts, 14, 15))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
|
||||
let b2 = this.x;
|
||||
>b2 : Symbol(b2, Decl(checkSuperCallBeforeThisAccess.ts, 15, 15))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
|
||||
let b3 = super.x;
|
||||
>b3 : Symbol(b3, Decl(checkSuperCallBeforeThisAccess.ts, 16, 15))
|
||||
>super.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
}
|
||||
else {
|
||||
let c1 = this; // Error
|
||||
>c1 : Symbol(c1, Decl(checkSuperCallBeforeThisAccess.ts, 19, 15))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
|
||||
let c2 = this.x; // Error
|
||||
>c2 : Symbol(c2, Decl(checkSuperCallBeforeThisAccess.ts, 20, 15))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
|
||||
let c3 = super.x; // Error
|
||||
>c3 : Symbol(c3, Decl(checkSuperCallBeforeThisAccess.ts, 21, 15))
|
||||
>super.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
}
|
||||
if (!!true) {
|
||||
switch (n) {
|
||||
>n : Symbol(n, Decl(checkSuperCallBeforeThisAccess.ts, 5, 16))
|
||||
|
||||
case 1:
|
||||
super();
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
|
||||
let d1 = this.x;
|
||||
>d1 : Symbol(d1, Decl(checkSuperCallBeforeThisAccess.ts, 27, 23))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
|
||||
case 2:
|
||||
let d2 = this.x; // Error
|
||||
>d2 : Symbol(d2, Decl(checkSuperCallBeforeThisAccess.ts, 29, 23))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
|
||||
default:
|
||||
super();
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
|
||||
let d3 = this.x;
|
||||
>d3 : Symbol(d3, Decl(checkSuperCallBeforeThisAccess.ts, 32, 23))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
}
|
||||
let d4 = this.x;
|
||||
>d4 : Symbol(d4, Decl(checkSuperCallBeforeThisAccess.ts, 34, 15))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
}
|
||||
if (!!true) {
|
||||
let e1 = { w: !!true ? super() : 0 };
|
||||
>e1 : Symbol(e1, Decl(checkSuperCallBeforeThisAccess.ts, 37, 15))
|
||||
>w : Symbol(w, Decl(checkSuperCallBeforeThisAccess.ts, 37, 22))
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
|
||||
let e2 = this.x; // Error
|
||||
>e2 : Symbol(e2, Decl(checkSuperCallBeforeThisAccess.ts, 38, 15))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
|
||||
let e3 = { w: !!true ? super() : super() };
|
||||
>e3 : Symbol(e3, Decl(checkSuperCallBeforeThisAccess.ts, 39, 15))
|
||||
>w : Symbol(w, Decl(checkSuperCallBeforeThisAccess.ts, 39, 22))
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
|
||||
let e4 = this.x;
|
||||
>e4 : Symbol(e4, Decl(checkSuperCallBeforeThisAccess.ts, 40, 15))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
}
|
||||
let f1 = this; // Error
|
||||
>f1 : Symbol(f1, Decl(checkSuperCallBeforeThisAccess.ts, 42, 11))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
|
||||
let f2 = this.x; // Error
|
||||
>f2 : Symbol(f2, Decl(checkSuperCallBeforeThisAccess.ts, 43, 11))
|
||||
>this.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>this : Symbol(C1, Decl(checkSuperCallBeforeThisAccess.ts, 2, 1))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
|
||||
let f3 = super.x; // Error
|
||||
>f3 : Symbol(f3, Decl(checkSuperCallBeforeThisAccess.ts, 44, 11))
|
||||
>super.x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(checkSuperCallBeforeThisAccess.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(checkSuperCallBeforeThisAccess.ts, 0, 9))
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38512
|
||||
|
||||
export class Foo {
|
||||
>Foo : Symbol(Foo, Decl(checkSuperCallBeforeThisAccess.ts, 46, 1))
|
||||
|
||||
constructor(value: number) {
|
||||
>value : Symbol(value, Decl(checkSuperCallBeforeThisAccess.ts, 51, 16))
|
||||
}
|
||||
}
|
||||
|
||||
export class BarCorrectlyFails extends Foo {
|
||||
>BarCorrectlyFails : Symbol(BarCorrectlyFails, Decl(checkSuperCallBeforeThisAccess.ts, 53, 1))
|
||||
>Foo : Symbol(Foo, Decl(checkSuperCallBeforeThisAccess.ts, 46, 1))
|
||||
|
||||
constructor(something: boolean) {
|
||||
>something : Symbol(something, Decl(checkSuperCallBeforeThisAccess.ts, 56, 16))
|
||||
|
||||
if (!something) {
|
||||
>something : Symbol(something, Decl(checkSuperCallBeforeThisAccess.ts, 56, 16))
|
||||
|
||||
const value = this.bar(); // Error
|
||||
>value : Symbol(value, Decl(checkSuperCallBeforeThisAccess.ts, 58, 17))
|
||||
>this.bar : Symbol(BarCorrectlyFails.bar, Decl(checkSuperCallBeforeThisAccess.ts, 64, 5))
|
||||
>this : Symbol(BarCorrectlyFails, Decl(checkSuperCallBeforeThisAccess.ts, 53, 1))
|
||||
>bar : Symbol(BarCorrectlyFails.bar, Decl(checkSuperCallBeforeThisAccess.ts, 64, 5))
|
||||
|
||||
super(value);
|
||||
>super : Symbol(Foo, Decl(checkSuperCallBeforeThisAccess.ts, 46, 1))
|
||||
>value : Symbol(value, Decl(checkSuperCallBeforeThisAccess.ts, 58, 17))
|
||||
}
|
||||
else {
|
||||
super(1337);
|
||||
>super : Symbol(Foo, Decl(checkSuperCallBeforeThisAccess.ts, 46, 1))
|
||||
}
|
||||
}
|
||||
bar(): number { return 4; }
|
||||
>bar : Symbol(BarCorrectlyFails.bar, Decl(checkSuperCallBeforeThisAccess.ts, 64, 5))
|
||||
}
|
||||
|
||||
export class BarIncorrectlyWorks extends Foo {
|
||||
>BarIncorrectlyWorks : Symbol(BarIncorrectlyWorks, Decl(checkSuperCallBeforeThisAccess.ts, 66, 1))
|
||||
>Foo : Symbol(Foo, Decl(checkSuperCallBeforeThisAccess.ts, 46, 1))
|
||||
|
||||
constructor(something: boolean) {
|
||||
>something : Symbol(something, Decl(checkSuperCallBeforeThisAccess.ts, 69, 16))
|
||||
|
||||
if (something) {
|
||||
>something : Symbol(something, Decl(checkSuperCallBeforeThisAccess.ts, 69, 16))
|
||||
|
||||
super(1337);
|
||||
>super : Symbol(Foo, Decl(checkSuperCallBeforeThisAccess.ts, 46, 1))
|
||||
}
|
||||
else {
|
||||
const value = this.bar(); // Error
|
||||
>value : Symbol(value, Decl(checkSuperCallBeforeThisAccess.ts, 74, 17))
|
||||
>this.bar : Symbol(BarIncorrectlyWorks.bar, Decl(checkSuperCallBeforeThisAccess.ts, 77, 5))
|
||||
>this : Symbol(BarIncorrectlyWorks, Decl(checkSuperCallBeforeThisAccess.ts, 66, 1))
|
||||
>bar : Symbol(BarIncorrectlyWorks.bar, Decl(checkSuperCallBeforeThisAccess.ts, 77, 5))
|
||||
|
||||
super(value);
|
||||
>super : Symbol(Foo, Decl(checkSuperCallBeforeThisAccess.ts, 46, 1))
|
||||
>value : Symbol(value, Decl(checkSuperCallBeforeThisAccess.ts, 74, 17))
|
||||
}
|
||||
}
|
||||
bar(): number { return 4; }
|
||||
>bar : Symbol(BarIncorrectlyWorks.bar, Decl(checkSuperCallBeforeThisAccess.ts, 77, 5))
|
||||
}
|
||||
|
279
tests/baselines/reference/checkSuperCallBeforeThisAccess.types
Normal file
279
tests/baselines/reference/checkSuperCallBeforeThisAccess.types
Normal file
|
@ -0,0 +1,279 @@
|
|||
=== tests/cases/compiler/checkSuperCallBeforeThisAccess.ts ===
|
||||
class A {
|
||||
>A : A
|
||||
|
||||
x = 1;
|
||||
>x : number
|
||||
>1 : 1
|
||||
}
|
||||
|
||||
class C1 extends A {
|
||||
>C1 : C1
|
||||
>A : A
|
||||
|
||||
constructor(n: number) {
|
||||
>n : number
|
||||
|
||||
let a1 = this; // Error
|
||||
>a1 : this
|
||||
>this : this
|
||||
|
||||
let a2 = this.x; // Error
|
||||
>a2 : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
|
||||
let a3 = super.x; // Error
|
||||
>a3 : number
|
||||
>super.x : number
|
||||
>super : A
|
||||
>x : number
|
||||
|
||||
let a4 = () => this;
|
||||
>a4 : () => this
|
||||
>() => this : () => this
|
||||
>this : this
|
||||
|
||||
let a5 = () => this.x;
|
||||
>a5 : () => number
|
||||
>() => this.x : () => number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
|
||||
let a6 = () => super.x;
|
||||
>a6 : () => number
|
||||
>() => super.x : () => number
|
||||
>super.x : number
|
||||
>super : A
|
||||
>x : number
|
||||
|
||||
if (!!true) {
|
||||
>!!true : true
|
||||
>!true : false
|
||||
>true : true
|
||||
|
||||
super();
|
||||
>super() : void
|
||||
>super : typeof A
|
||||
|
||||
let b1 = this;
|
||||
>b1 : this
|
||||
>this : this
|
||||
|
||||
let b2 = this.x;
|
||||
>b2 : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
|
||||
let b3 = super.x;
|
||||
>b3 : number
|
||||
>super.x : number
|
||||
>super : A
|
||||
>x : number
|
||||
}
|
||||
else {
|
||||
let c1 = this; // Error
|
||||
>c1 : this
|
||||
>this : this
|
||||
|
||||
let c2 = this.x; // Error
|
||||
>c2 : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
|
||||
let c3 = super.x; // Error
|
||||
>c3 : number
|
||||
>super.x : number
|
||||
>super : A
|
||||
>x : number
|
||||
}
|
||||
if (!!true) {
|
||||
>!!true : true
|
||||
>!true : false
|
||||
>true : true
|
||||
|
||||
switch (n) {
|
||||
>n : number
|
||||
|
||||
case 1:
|
||||
>1 : 1
|
||||
|
||||
super();
|
||||
>super() : void
|
||||
>super : typeof A
|
||||
|
||||
let d1 = this.x;
|
||||
>d1 : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
|
||||
case 2:
|
||||
>2 : 2
|
||||
|
||||
let d2 = this.x; // Error
|
||||
>d2 : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
|
||||
default:
|
||||
super();
|
||||
>super() : void
|
||||
>super : typeof A
|
||||
|
||||
let d3 = this.x;
|
||||
>d3 : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
}
|
||||
let d4 = this.x;
|
||||
>d4 : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
}
|
||||
if (!!true) {
|
||||
>!!true : true
|
||||
>!true : false
|
||||
>true : true
|
||||
|
||||
let e1 = { w: !!true ? super() : 0 };
|
||||
>e1 : { w: number | void; }
|
||||
>{ w: !!true ? super() : 0 } : { w: number | void; }
|
||||
>w : number | void
|
||||
>!!true ? super() : 0 : void | 0
|
||||
>!!true : true
|
||||
>!true : false
|
||||
>true : true
|
||||
>super() : void
|
||||
>super : typeof A
|
||||
>0 : 0
|
||||
|
||||
let e2 = this.x; // Error
|
||||
>e2 : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
|
||||
let e3 = { w: !!true ? super() : super() };
|
||||
>e3 : { w: void; }
|
||||
>{ w: !!true ? super() : super() } : { w: void; }
|
||||
>w : void
|
||||
>!!true ? super() : super() : void
|
||||
>!!true : true
|
||||
>!true : false
|
||||
>true : true
|
||||
>super() : void
|
||||
>super : typeof A
|
||||
>super() : void
|
||||
>super : typeof A
|
||||
|
||||
let e4 = this.x;
|
||||
>e4 : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
}
|
||||
let f1 = this; // Error
|
||||
>f1 : this
|
||||
>this : this
|
||||
|
||||
let f2 = this.x; // Error
|
||||
>f2 : number
|
||||
>this.x : number
|
||||
>this : this
|
||||
>x : number
|
||||
|
||||
let f3 = super.x; // Error
|
||||
>f3 : number
|
||||
>super.x : number
|
||||
>super : A
|
||||
>x : number
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38512
|
||||
|
||||
export class Foo {
|
||||
>Foo : Foo
|
||||
|
||||
constructor(value: number) {
|
||||
>value : number
|
||||
}
|
||||
}
|
||||
|
||||
export class BarCorrectlyFails extends Foo {
|
||||
>BarCorrectlyFails : BarCorrectlyFails
|
||||
>Foo : Foo
|
||||
|
||||
constructor(something: boolean) {
|
||||
>something : boolean
|
||||
|
||||
if (!something) {
|
||||
>!something : boolean
|
||||
>something : boolean
|
||||
|
||||
const value = this.bar(); // Error
|
||||
>value : number
|
||||
>this.bar() : number
|
||||
>this.bar : () => number
|
||||
>this : this
|
||||
>bar : () => number
|
||||
|
||||
super(value);
|
||||
>super(value) : void
|
||||
>super : typeof Foo
|
||||
>value : number
|
||||
}
|
||||
else {
|
||||
super(1337);
|
||||
>super(1337) : void
|
||||
>super : typeof Foo
|
||||
>1337 : 1337
|
||||
}
|
||||
}
|
||||
bar(): number { return 4; }
|
||||
>bar : () => number
|
||||
>4 : 4
|
||||
}
|
||||
|
||||
export class BarIncorrectlyWorks extends Foo {
|
||||
>BarIncorrectlyWorks : BarIncorrectlyWorks
|
||||
>Foo : Foo
|
||||
|
||||
constructor(something: boolean) {
|
||||
>something : boolean
|
||||
|
||||
if (something) {
|
||||
>something : boolean
|
||||
|
||||
super(1337);
|
||||
>super(1337) : void
|
||||
>super : typeof Foo
|
||||
>1337 : 1337
|
||||
}
|
||||
else {
|
||||
const value = this.bar(); // Error
|
||||
>value : number
|
||||
>this.bar() : number
|
||||
>this.bar : () => number
|
||||
>this : this
|
||||
>bar : () => number
|
||||
|
||||
super(value);
|
||||
>super(value) : void
|
||||
>super : typeof Foo
|
||||
>value : number
|
||||
}
|
||||
}
|
||||
bar(): number { return 4; }
|
||||
>bar : () => number
|
||||
>4 : 4
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ tests/cases/compiler/superAccess2.ts(11,33): error TS1034: 'super' must be follo
|
|||
tests/cases/compiler/superAccess2.ts(11,40): error TS2336: 'super' cannot be referenced in constructor arguments.
|
||||
tests/cases/compiler/superAccess2.ts(11,40): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
tests/cases/compiler/superAccess2.ts(11,45): error TS1034: 'super' must be followed by an argument list or member access.
|
||||
tests/cases/compiler/superAccess2.ts(11,59): error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
tests/cases/compiler/superAccess2.ts(11,64): error TS1034: 'super' must be followed by an argument list or member access.
|
||||
tests/cases/compiler/superAccess2.ts(15,19): error TS1034: 'super' must be followed by an argument list or member access.
|
||||
tests/cases/compiler/superAccess2.ts(17,15): error TS2576: Property 'y' is a static member of type 'P'
|
||||
|
@ -15,7 +14,7 @@ tests/cases/compiler/superAccess2.ts(20,26): error TS1034: 'super' must be follo
|
|||
tests/cases/compiler/superAccess2.ts(21,15): error TS2339: Property 'x' does not exist on type 'typeof P'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/superAccess2.ts (15 errors) ====
|
||||
==== tests/cases/compiler/superAccess2.ts (14 errors) ====
|
||||
class P {
|
||||
x() { }
|
||||
static y() { }
|
||||
|
@ -45,8 +44,6 @@ tests/cases/compiler/superAccess2.ts(21,15): error TS2339: Property 'x' does not
|
|||
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
~
|
||||
!!! error TS1034: 'super' must be followed by an argument list or member access.
|
||||
~~~~~
|
||||
!!! error TS17011: 'super' must be called before accessing a property of 'super' in the constructor of a derived class.
|
||||
~
|
||||
!!! error TS1034: 'super' must be followed by an argument list or member access.
|
||||
super();
|
||||
|
|
83
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts
Normal file
83
tests/cases/compiler/checkSuperCallBeforeThisAccess.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
// @strict: true
|
||||
// @target: esnext
|
||||
|
||||
class A {
|
||||
x = 1;
|
||||
}
|
||||
|
||||
class C1 extends A {
|
||||
constructor(n: number) {
|
||||
let a1 = this; // Error
|
||||
let a2 = this.x; // Error
|
||||
let a3 = super.x; // Error
|
||||
let a4 = () => this;
|
||||
let a5 = () => this.x;
|
||||
let a6 = () => super.x;
|
||||
if (!!true) {
|
||||
super();
|
||||
let b1 = this;
|
||||
let b2 = this.x;
|
||||
let b3 = super.x;
|
||||
}
|
||||
else {
|
||||
let c1 = this; // Error
|
||||
let c2 = this.x; // Error
|
||||
let c3 = super.x; // Error
|
||||
}
|
||||
if (!!true) {
|
||||
switch (n) {
|
||||
case 1:
|
||||
super();
|
||||
let d1 = this.x;
|
||||
case 2:
|
||||
let d2 = this.x; // Error
|
||||
default:
|
||||
super();
|
||||
let d3 = this.x;
|
||||
}
|
||||
let d4 = this.x;
|
||||
}
|
||||
if (!!true) {
|
||||
let e1 = { w: !!true ? super() : 0 };
|
||||
let e2 = this.x; // Error
|
||||
let e3 = { w: !!true ? super() : super() };
|
||||
let e4 = this.x;
|
||||
}
|
||||
let f1 = this; // Error
|
||||
let f2 = this.x; // Error
|
||||
let f3 = super.x; // Error
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38512
|
||||
|
||||
export class Foo {
|
||||
constructor(value: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export class BarCorrectlyFails extends Foo {
|
||||
constructor(something: boolean) {
|
||||
if (!something) {
|
||||
const value = this.bar(); // Error
|
||||
super(value);
|
||||
}
|
||||
else {
|
||||
super(1337);
|
||||
}
|
||||
}
|
||||
bar(): number { return 4; }
|
||||
}
|
||||
|
||||
export class BarIncorrectlyWorks extends Foo {
|
||||
constructor(something: boolean) {
|
||||
if (something) {
|
||||
super(1337);
|
||||
}
|
||||
else {
|
||||
const value = this.bar(); // Error
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
bar(): number { return 4; }
|
||||
}
|
Loading…
Reference in a new issue