Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(compiler): imported JSII types are considered defined after other types (and can't be referenced by them) #6221

Merged
merged 8 commits into from
Apr 12, 2024
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
5 changes: 5 additions & 0 deletions examples/tests/valid/bring_jsii.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ assert(jsiiClass.applyClosure(5, (x) => { return x * 2; }) == 10);

let jsiiStruct = jsii_fixture.SomeStruct { field: "struct field" };
assert(jsiiClass.methodWithStructParam(jsiiStruct) == "struct field");

// Use a JSII interface
class X impl jsii_fixture.ISomeInterface {
pub method() {}
}
28 changes: 13 additions & 15 deletions examples/tests/valid/impl_interface.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -84,21 +84,19 @@ let f = inflight () => {
dog.bark();
};

// This should work: extend a JSII interface in a preflight interface
// Commented out because of: https://github.com/winglang/wing/issues/6209
//
// interface ExtendJsiiIface extends jsii_fixture.ISomeInterface {
// inflight inflight_method(): void;
// }
//
// class ImplementJsiiIface impl ExtendJsiiIface {
// pub method() {
// return;
// }
// pub inflight inflight_method() {
// return;
// }
// }
// Extend a JSII interface in a preflight interface
interface ExtendJsiiIface extends jsii_fixture.ISomeInterface {
inflight inflight_method(): void;
}

class ImplementJsiiIface impl ExtendJsiiIface {
pub method() {
return;
}
pub inflight inflight_method() {
return;
}
}

// Implement an inflight interface in a preflight class
inflight interface IInflight {
Expand Down
14 changes: 5 additions & 9 deletions libs/wingc/src/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1567,21 +1567,21 @@ impl Types {
self
.libraries
.lookup_nested_str(&resource_fqn, None)
.expect("Resouce base class to be loaded")
.expect("Resource base class to be loaded")
.0
.as_type()
.expect("Resouce base class to be a type")
.expect("Resource base class to be a type")
}

pub fn resource_base_interface(&self) -> TypeRef {
let resource_fqn = format!("{}.{}", WINGSDK_ASSEMBLY_NAME, WINGSDK_IRESOURCE);
self
.libraries
.lookup_nested_str(&resource_fqn, None)
.expect("Resouce base interface to be loaded")
.expect("Resource base interface to be loaded")
.0
.as_type()
.expect("Resouce base interface to be a type")
.expect("Resource base interface to be a type")
}

pub fn construct_base_type(&self) -> TypeRef {
Expand Down Expand Up @@ -5146,7 +5146,6 @@ impl<'a> TypeChecker<'a> {
assembly_name: assembly_name.to_string(),
namespace_filter,
alias: alias.clone(),
import_statement_idx: stmt.map(|s| s.idx).unwrap_or(0),
});

self
Expand All @@ -5157,10 +5156,7 @@ impl<'a> TypeChecker<'a> {
};

// check if we've already defined the given alias in the current scope
if env
.lookup(&jsii.alias.name.as_str().into(), Some(jsii.import_statement_idx))
.is_some()
{
if env.lookup(&jsii.alias.name.as_str().into(), None).is_some() {
self.spanned_error(alias, format!("\"{}\" is already defined", alias.name));
} else {
let mut importer = JsiiImporter::new(&jsii, self.types, self.jsii_types);
Expand Down
23 changes: 4 additions & 19 deletions libs/wingc/src/type_check/jsii_importer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@ pub struct JsiiImportSpec {
pub namespace_filter: Vec<String>,
/// The name to assign to the module in the Wing type system.
pub alias: Symbol,
/// The index of the import statement that triggered this import. This is required so we'll know
/// later on if types defined by this import come before or after other statements in the code.
/// If type definitions in wing are always location agnostic this doesn't really matter and we
/// might be able to remove this.
pub import_statement_idx: usize,
}

pub struct JsiiImporter<'a> {
Expand Down Expand Up @@ -410,7 +405,7 @@ impl<'a> JsiiImporter<'a> {
None,
SymbolEnvKind::Type(self.wing_types.void()),
Phase::Independent, // structs are phase-independent
self.jsii_spec.import_statement_idx,
0,
),
})),
false => self.wing_types.add_type(Type::Interface(Interface {
Expand All @@ -420,12 +415,7 @@ impl<'a> JsiiImporter<'a> {
extends: vec![],
docs: Docs::from(&jsii_interface.docs),
// Will be replaced below
env: SymbolEnv::new(
None,
SymbolEnvKind::Type(self.wing_types.void()),
phase,
self.jsii_spec.import_statement_idx,
),
env: SymbolEnv::new(None, SymbolEnvKind::Type(self.wing_types.void()), phase, 0),
phase,
})),
};
Expand All @@ -443,12 +433,7 @@ impl<'a> JsiiImporter<'a> {
}
};

let mut iface_env = SymbolEnv::new(
None,
SymbolEnvKind::Type(wing_type),
phase,
self.jsii_spec.import_statement_idx,
);
let mut iface_env = SymbolEnv::new(None, SymbolEnvKind::Type(wing_type), phase, 0);
iface_env.type_parameters = self.type_param_from_docs(&jsii_interface_fqn, &jsii_interface.docs);

self.add_members_to_class_env(
Expand Down Expand Up @@ -1078,7 +1063,7 @@ impl<'a> JsiiImporter<'a> {
&self.jsii_spec.alias,
SymbolKind::Namespace(ns),
AccessModifier::Private,
StatementIdx::Index(self.jsii_spec.import_statement_idx),
StatementIdx::Top,
)
.unwrap();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ module.exports = function({ $greeting, $stuff_HelloWorld }) {
//# sourceMappingURL=inflight.$Closure1-1.cjs.map
```

## inflight.X-1.cjs
```cjs
"use strict";
const $helpers = require("@winglang/sdk/lib/helpers");
module.exports = function({ }) {
class X {
constructor({ }) {
}
}
return X;
}
//# sourceMappingURL=inflight.X-1.cjs.map
```

## main.tf.json
```json
{
Expand Down Expand Up @@ -92,6 +106,36 @@ class $Root extends $stdlib.std.Resource {
});
}
}
class X extends $stdlib.std.Resource {
constructor($scope, $id, ) {
super($scope, $id);
}
method() {
}
static _toInflightType() {
return `
require("${$helpers.normalPath(__dirname)}/inflight.X-1.cjs")({
})
`;
}
_toInflight() {
return `
(await (async () => {
const XClient = ${X._toInflightType()};
const client = new XClient({
});
if (client.$inflight_init) { await client.$inflight_init(); }
return client;
})())
`;
}
get _liftMap() {
return ({
"$inflight_init": [
],
});
}
}
const hello = new stuff.HelloWorld();
const greeting = (hello.sayHello("wingnuts"));
this.node.root.new("@winglang/sdk.std.Test", std.Test, this, "test:sayHello", new $Closure1(this, "$Closure1"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,23 @@ module.exports = function({ }) {
//# sourceMappingURL=inflight.ImplementInflightIfaceInPreflightClass-1.cjs.map
```

## inflight.ImplementJsiiIface-1.cjs
```cjs
"use strict";
const $helpers = require("@winglang/sdk/lib/helpers");
module.exports = function({ }) {
class ImplementJsiiIface {
constructor({ }) {
}
async inflight_method() {
return;
}
}
return ImplementJsiiIface;
}
//# sourceMappingURL=inflight.ImplementJsiiIface-1.cjs.map
```

## inflight.Terrier-1.cjs
```cjs
"use strict";
Expand Down Expand Up @@ -483,6 +500,39 @@ class $Root extends $stdlib.std.Resource {
});
}
}
class ImplementJsiiIface extends $stdlib.std.Resource {
constructor($scope, $id, ) {
super($scope, $id);
}
method() {
return;
}
static _toInflightType() {
return `
require("${$helpers.normalPath(__dirname)}/inflight.ImplementJsiiIface-1.cjs")({
})
`;
}
_toInflight() {
return `
(await (async () => {
const ImplementJsiiIfaceClient = ${ImplementJsiiIface._toInflightType()};
const client = new ImplementJsiiIfaceClient({
});
if (client.$inflight_init) { await client.$inflight_init(); }
return client;
})())
`;
}
get _liftMap() {
return ({
"inflight_method": [
],
"$inflight_init": [
],
});
}
}
class ImplementInflightIfaceInPreflightClass extends $stdlib.std.Resource {
constructor($scope, $id, ) {
super($scope, $id);
Expand Down
Loading