Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 61 additions & 54 deletions src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3439,64 +3439,71 @@ namespace ts {
function visitCallExpressionWithPotentialCapturedThisAssignment(node: CallExpression, assignToCapturedThis: boolean): CallExpression | BinaryExpression {
// We are here either because SuperKeyword was used somewhere in the expression, or
// because we contain a SpreadElementExpression.
if (node.transformFlags & TransformFlags.ContainsSpread ||
node.expression.kind === SyntaxKind.SuperKeyword ||
isSuperProperty(skipOuterExpressions(node.expression))) {

const { target, thisArg } = createCallBinding(node.expression, hoistVariableDeclaration);
if (node.expression.kind === SyntaxKind.SuperKeyword) {
setEmitFlags(thisArg, EmitFlags.NoSubstitution);
}
let resultingCall: CallExpression | BinaryExpression;
if (node.transformFlags & TransformFlags.ContainsSpread) {
// [source]
// f(...a, b)
// x.m(...a, b)
// super(...a, b)
// super.m(...a, b) // in static
// super.m(...a, b) // in instance
//
// [output]
// f.apply(void 0, a.concat([b]))
// (_a = x).m.apply(_a, a.concat([b]))
// _super.apply(this, a.concat([b]))
// _super.m.apply(this, a.concat([b]))
// _super.prototype.m.apply(this, a.concat([b]))

resultingCall = createFunctionApply(
visitNode(target, callExpressionVisitor, isExpression),
visitNode(thisArg, visitor, isExpression),
transformAndSpreadElements(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false, /*hasTrailingComma*/ false)
);
}
else {
// [source]
// super(a)
// super.m(a) // in static
// super.m(a) // in instance
//
// [output]
// _super.call(this, a)
// _super.m.call(this, a)
// _super.prototype.m.call(this, a)
resultingCall = createFunctionCall(
visitNode(target, callExpressionVisitor, isExpression),
visitNode(thisArg, visitor, isExpression),
visitNodes(node.arguments, visitor, isExpression),
/*location*/ node
);
}
const { target, thisArg } = createCallBinding(node.expression, hoistVariableDeclaration);
if (node.expression.kind === SyntaxKind.SuperKeyword) {
setEmitFlags(thisArg, EmitFlags.NoSubstitution);
}

if (node.expression.kind === SyntaxKind.SuperKeyword) {
const actualThis = createThis();
setEmitFlags(actualThis, EmitFlags.NoSubstitution);
const initializer =
createLogicalOr(
resultingCall,
actualThis
let resultingCall: CallExpression | BinaryExpression;
if (node.transformFlags & TransformFlags.ContainsSpread) {
// [source]
// f(...a, b)
// x.m(...a, b)
// super(...a, b)
// super.m(...a, b) // in static
// super.m(...a, b) // in instance
//
// [output]
// f.apply(void 0, a.concat([b]))
// (_a = x).m.apply(_a, a.concat([b]))
// _super.apply(this, a.concat([b]))
// _super.m.apply(this, a.concat([b]))
// _super.prototype.m.apply(this, a.concat([b]))

resultingCall = createFunctionApply(
visitNode(target, callExpressionVisitor, isExpression),
visitNode(thisArg, visitor, isExpression),
transformAndSpreadElements(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false, /*hasTrailingComma*/ false)
);
}
else {
// [source]
// super(a)
// super.m(a) // in static
// super.m(a) // in instance
//
// [output]
// _super.call(this, a)
// _super.m.call(this, a)
// _super.prototype.m.call(this, a)
resultingCall = createFunctionCall(
visitNode(target, callExpressionVisitor, isExpression),
visitNode(thisArg, visitor, isExpression),
visitNodes(node.arguments, visitor, isExpression),
/*location*/ node
);
resultingCall = assignToCapturedThis
? createAssignment(createIdentifier("_this"), initializer)
: initializer;
}

if (node.expression.kind === SyntaxKind.SuperKeyword) {
const actualThis = createThis();
setEmitFlags(actualThis, EmitFlags.NoSubstitution);
const initializer =
createLogicalOr(
resultingCall,
actualThis
);
resultingCall = assignToCapturedThis
? createAssignment(createIdentifier("_this"), initializer)
: initializer;
}
return setOriginalNode(resultingCall, node);
}
return setOriginalNode(resultingCall, node);

return visitEachChild(node, visitor, context);
}

/**
Expand Down
5 changes: 2 additions & 3 deletions tests/baselines/reference/superElementAccess.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,15 @@ var MyDerived = /** @class */ (function (_super) {
}
MyDerived.prototype.foo = function () {
_super.prototype["m1"].call(this, "hi"); // Should be allowed, method on base prototype
var l2 = (_a = _super.prototype["m1"]).bind.call(_a, this); // Should be allowed, can access properties as well as invoke
var l2 = _super.prototype["m1"].bind(this); // Should be allowed, can access properties as well as invoke
var x = _super.prototype["m1"]; // Should be allowed, can assign to var with compatible signature
(_b = _super.prototype["m2"]).bind.call(_b, this); // Should error, instance property, not a public instance member function
_super.prototype["m2"].bind(this); // Should error, instance property, not a public instance member function
_super.prototype["p1"].call(this); // Should error, private not public instance member function
var l1 = _super.prototype["d1"]; // Should error, instance data property not a public instance member function
var l1 = _super.prototype["d2"]; // Should error, instance data property not a public instance member function
_super.prototype["m1"] = function (a) { return ""; }; // Should be allowed, we will not restrict assignment
_super.prototype["value"] = 0; // Should error, instance data property not a public instance member function
var z = _super.prototype["value"]; // Should error, instance data property not a public instance member function
var _a, _b;
};
return MyDerived;
}(MyBase));
5 changes: 2 additions & 3 deletions tests/baselines/reference/superPropertyAccess.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,15 @@ var MyDerived = /** @class */ (function (_super) {
}
MyDerived.prototype.foo = function () {
_super.prototype.m1.call(this, "hi"); // Should be allowed, method on base prototype
var l2 = (_a = _super.prototype.m1).bind.call(_a, this); // Should be allowed, can access properties as well as invoke
var l2 = _super.prototype.m1.bind(this); // Should be allowed, can access properties as well as invoke
var x = _super.prototype.m1; // Should be allowed, can assign to var with compatible signature
(_b = _super.prototype.m2).bind.call(_b, this); // Should error, instance property, not a public instance member function
_super.prototype.m2.bind(this); // Should error, instance property, not a public instance member function
_super.prototype.p1.call(this); // Should error, private not public instance member function
var l1 = _super.prototype.d1; // Should error, instance data property not a public instance member function
var l1 = _super.prototype.d2; // Should error, instance data property not a public instance member function
_super.prototype.m1 = function (a) { return ""; }; // Should be allowed, we will not restrict assignment
_super.prototype.value = 0; // Should error, instance data property not a public instance member function
var z = _super.prototype.value; // Should error, instance data property not a public instance member function
var _a, _b;
};
return MyDerived;
}(MyBase));