Skip to content

Commit

Permalink
fix(compiler): using super() in an inflight constructor compiles bu…
Browse files Browse the repository at this point in the history
…t fails at runtime (#7007)

fixes: #6940
Compiled output of the `SuperClass` (slightly different class than the one in the example):
<img width="473" alt="image" src="https://github.com/user-attachments/assets/37854a53-1ce0-49c1-9391-b5b999ce3b5b">

Test results:
<img width="535" alt="image" src="https://github.com/user-attachments/assets/7bb525a4-b81a-44f9-9b63-aa8da0c909d0">



## Checklist

- [ ] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [ ] Description explains motivation and solution
- [ ] Tests added (always)
- [ ] Docs updated (only required for features)
- [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
tsuf239 authored Aug 12, 2024
1 parent f57a913 commit a636e08
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 9 deletions.
28 changes: 28 additions & 0 deletions examples/tests/valid/super_inflight_class.test.w
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
bring expect;

class BaseClass {
pub inflight x: num;
inflight new() {
log("BaseClass.inflight new");
this.x = 2;
}

pub inflight add(a: num, b: num): num {
return a + b;
}
}

class SuperClass extends BaseClass {
inflight new() {
super();
this.x += 1;
log("SuperClass.inflight new");
}
}

let c = new SuperClass();

test "counter works" {
expect.equal(c.add(2, 3), 5);
expect.equal(c.x, 3);
}
34 changes: 25 additions & 9 deletions libs/wingc/src/jsify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1027,15 +1027,31 @@ impl<'a> JSifier<'a> {
},
StmtKind::SuperConstructor { arg_list } => {
let args = self.jsify_arg_list(&arg_list, None, None, ctx);
match parent_class_phase(ctx) {
Phase::Inflight => code.line(new_code!(
&arg_list.span,
"await this.super_",
CLASS_INFLIGHT_INIT_NAME,
"?.(",
args,
");"
)),
match ctx.visit_ctx.current_phase() {
// does class have any inflight constructor?
Phase::Inflight => {
// yes- and it's an inflight class
if parent_class_phase(ctx) == Phase::Inflight {
code.line(new_code!(
&arg_list.span,
"await this.",
SUPER_CLASS_INFLIGHT_INIT_NAME,
"?.(",
args,
");"
))
} else {
// yes- and it's a preflight class
code.line(new_code!(
&arg_list.span,
"await super.",
CLASS_INFLIGHT_INIT_NAME,
"?.(",
args,
");"
))
}
}
Phase::Preflight => code.line(new_code!(
&arg_list.span,
format!("super({SCOPE_PARAM}, $id, "),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ module.exports = function({ $jsii_fixture_JsiiClass }) {
constructor(x, y){
super(x);
this.$inflight_init = async () => {
await super.$inflight_init?.(x);
this.foo_str = String.raw({ raw: ["", " ", ""] }, y, x);
this.foo_num = (await this.get_six());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# [super_inflight_class.test.w](../../../../../examples/tests/valid/super_inflight_class.test.w) | compile | tf-aws

## inflight.$Closure1-1.cjs
```cjs
"use strict";
const $helpers = require("@winglang/sdk/lib/helpers");
const $macros = require("@winglang/sdk/lib/macros");
module.exports = function({ $c, $expect_Util }) {
class $Closure1 {
constructor($args) {
const { } = $args;
const $obj = (...args) => this.handle(...args);
Object.setPrototypeOf($obj, this);
return $obj;
}
async handle() {
(await $expect_Util.equal((await $c.add(2, 3)), 5));
(await $expect_Util.equal($c.x, 3));
}
}
return $Closure1;
}
//# sourceMappingURL=inflight.$Closure1-1.cjs.map
```

## inflight.BaseClass-1.cjs
```cjs
"use strict";
const $helpers = require("@winglang/sdk/lib/helpers");
const $macros = require("@winglang/sdk/lib/macros");
module.exports = function({ }) {
class BaseClass {
async add(a, b) {
return (a + b);
}
async $inflight_init() {
console.log("BaseClass.inflight new");
this.x = 2;
}
}
return BaseClass;
}
//# sourceMappingURL=inflight.BaseClass-1.cjs.map
```

## inflight.SuperClass-1.cjs
```cjs
"use strict";
const $helpers = require("@winglang/sdk/lib/helpers");
const $macros = require("@winglang/sdk/lib/macros");
module.exports = function({ $BaseClass }) {
class SuperClass extends $BaseClass {
async $inflight_init() {
await super.$inflight_init?.();
this.x += 1;
console.log("SuperClass.inflight new");
}
}
return SuperClass;
}
//# sourceMappingURL=inflight.SuperClass-1.cjs.map
```
## main.tf.json
```json
{
"//": {
"metadata": {
"backend": "local",
"stackName": "root"
},
"outputs": {}
},
"provider": {
"aws": [
{}
]
}
}
```
## preflight.cjs
```cjs
"use strict";
const $stdlib = require('@winglang/sdk');
const $macros = require("@winglang/sdk/lib/macros");
const $platforms = ((s) => !s ? [] : s.split(';'))(process.env.WING_PLATFORMS);
const $outdir = process.env.WING_SYNTH_DIR ?? ".";
const $wing_is_test = process.env.WING_IS_TEST === "true";
const std = $stdlib.std;
const $helpers = $stdlib.helpers;
const $extern = $helpers.createExternRequire(__dirname);
const $PlatformManager = new $stdlib.platform.PlatformManager({platformPaths: $platforms});
class $Root extends $stdlib.std.Resource {
constructor($scope, $id) {
super($scope, $id);
$helpers.nodeof(this).root.$preflightTypesMap = { };
let $preflightTypesMap = {};
const expect = $stdlib.expect;
$helpers.nodeof(this).root.$preflightTypesMap = $preflightTypesMap;
class BaseClass extends $stdlib.std.Resource {
constructor($scope, $id, ) {
super($scope, $id);
}
static _toInflightType() {
return `
require("${$helpers.normalPath(__dirname)}/inflight.BaseClass-1.cjs")({
})
`;
}
get _liftMap() {
return ({
"add": [
],
"$inflight_init": [
],
"x": [
],
});
}
}
class SuperClass extends BaseClass {
constructor($scope, $id, ) {
super($scope, $id);
}
static _toInflightType() {
return `
require("${$helpers.normalPath(__dirname)}/inflight.SuperClass-1.cjs")({
$BaseClass: ${$stdlib.core.liftObject(BaseClass)},
})
`;
}
get _liftMap() {
return $stdlib.core.mergeLiftDeps(super._liftMap, {
"$inflight_init": [
],
});
}
}
class $Closure1 extends $stdlib.std.AutoIdResource {
_id = $stdlib.core.closureId();
constructor($scope, $id, ) {
super($scope, $id);
$helpers.nodeof(this).hidden = true;
}
static _toInflightType() {
return `
require("${$helpers.normalPath(__dirname)}/inflight.$Closure1-1.cjs")({
$c: ${$stdlib.core.liftObject(c)},
$expect_Util: ${$stdlib.core.liftObject($stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"))},
})
`;
}
get _liftMap() {
return ({
"handle": [
[$stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"), ["equal"]],
[c, [].concat(["add"], ["x"])],
],
"$inflight_init": [
[$stdlib.core.toLiftableModuleType(globalThis.$ClassFactory.resolveType("@winglang/sdk.expect.Util") ?? expect.Util, "@winglang/sdk/expect", "Util"), []],
[c, []],
],
});
}
}
const c = new SuperClass(this, "SuperClass");
globalThis.$ClassFactory.new("@winglang/sdk.std.Test", std.Test, this, "test:counter works", new $Closure1(this, "$Closure1"));
}
}
const $APP = $PlatformManager.createApp({ outdir: $outdir, name: "super_inflight_class.test", rootConstruct: $Root, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] });
$APP.synth();
//# sourceMappingURL=preflight.cjs.map
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# [super_inflight_class.test.w](../../../../../examples/tests/valid/super_inflight_class.test.w) | test | sim

## stdout.log
```log
[INFO] counter works | BaseClass.inflight new
[INFO] counter works | SuperClass.inflight new
pass ─ super_inflight_class.test.wsim » root/Default/test:counter works
Tests 1 passed (1)
Snapshots 1 skipped
Test Files 1 passed (1)
Duration <DURATION>
```

0 comments on commit a636e08

Please sign in to comment.