diff --git a/.gitignore b/.gitignore index 3f7971eb8..5b4e266da 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ package-lock.json node_modules ace *.wasm +.vscode +wasi-sdk-* +**/*/.mypy_cache \ No newline at end of file diff --git a/WIT.md b/WIT.md index 04e0c71a1..c5def124f 100644 --- a/WIT.md +++ b/WIT.md @@ -546,6 +546,13 @@ type foo = u32 type foo = u64 // ERROR: name `foo` already defined ``` +A type and a function may not share the same name either: + +```wit +type foo = u32 +foo: func() // ERROR: name `foo` already defined +``` + Names do not need to be defined before they're used (unlike in C or C++), it's ok to define a type after it's used: diff --git a/crates/parser/src/ast/resolve.rs b/crates/parser/src/ast/resolve.rs index 0f983d2c7..cf99e8cea 100644 --- a/crates/parser/src/ast/resolve.rs +++ b/crates/parser/src/ast/resolve.rs @@ -269,7 +269,17 @@ impl Resolver { } fn register_names(&mut self, fields: &[Item<'_>]) -> Result<()> { - let mut values = HashSet::new(); + // TODO: add span info and generate error message pointing + // original definition in case of duplicates. + #[derive(Debug, Clone)] + enum Definition { + Resource, + Function, + Global, + Type, + } + + let mut values = HashMap::new(); for field in fields { match field { Item::Resource(r) => { @@ -287,6 +297,16 @@ impl Resolver { foreign_module: None, }); self.define_type(&r.name.name, r.name.span, type_id)?; + if let Some(existing) = values.insert(&r.name.name, Definition::Resource) { + return Err(Error { + span: r.name.span, + msg: format!( + "Resource {:?} already defined as a {:?}", + r.name.name, existing + ), + } + .into()); + } } Item::TypeDef(t) => { let docs = self.docs(&t.docs); @@ -299,12 +319,29 @@ impl Resolver { foreign_module: None, }); self.define_type(&t.name.name, t.name.span, id)?; + if let Some(existing) = values.insert(&t.name.name, Definition::Type) { + return Err(Error { + span: t.name.span, + msg: format!( + "Type {:?} already defined as a {:?}", + t.name.name, existing + ), + } + .into()); + } } Item::Value(f) => { - if !values.insert(&f.name.name) { + let kind = match &f.kind { + ValueKind::Function { .. } => Definition::Function, + ValueKind::Global { .. } => Definition::Global, + }; + if let Some(existing) = values.insert(&f.name.name, kind.clone()) { return Err(Error { span: f.name.span, - msg: format!("{:?} defined twice", f.name.name), + msg: format!( + "{:?} {:?} already defined as a {:?}", + kind, f.name.name, existing + ), } .into()); } diff --git a/crates/parser/tests/ui/parse-fail/duplicate-functions.wit.result b/crates/parser/tests/ui/parse-fail/duplicate-functions.wit.result index 1d6aeb05c..9558e7be9 100644 --- a/crates/parser/tests/ui/parse-fail/duplicate-functions.wit.result +++ b/crates/parser/tests/ui/parse-fail/duplicate-functions.wit.result @@ -1,4 +1,4 @@ -"foo" defined twice +Function "foo" already defined as a Function --> tests/ui/parse-fail/duplicate-functions.wit:4:1 | 4 | foo: func() diff --git a/crates/parser/tests/ui/parse-fail/duplicate-value.wit.result b/crates/parser/tests/ui/parse-fail/duplicate-value.wit.result index 7cce26d9a..adf9ee87a 100644 --- a/crates/parser/tests/ui/parse-fail/duplicate-value.wit.result +++ b/crates/parser/tests/ui/parse-fail/duplicate-value.wit.result @@ -1,4 +1,4 @@ -"a" defined twice +Global "a" already defined as a Global --> tests/ui/parse-fail/duplicate-value.wit:3:1 | 3 | a: u32 diff --git a/crates/parser/tests/ui/parse-fail/func-type-collide.wit b/crates/parser/tests/ui/parse-fail/func-type-collide.wit new file mode 100644 index 000000000..9735daab0 --- /dev/null +++ b/crates/parser/tests/ui/parse-fail/func-type-collide.wit @@ -0,0 +1,4 @@ +// parse-fail + +type foo = s32 +foo: func() diff --git a/crates/parser/tests/ui/parse-fail/func-type-collide.wit.result b/crates/parser/tests/ui/parse-fail/func-type-collide.wit.result new file mode 100644 index 000000000..87d17dddc --- /dev/null +++ b/crates/parser/tests/ui/parse-fail/func-type-collide.wit.result @@ -0,0 +1,5 @@ +Function "foo" already defined as a Type + --> tests/ui/parse-fail/func-type-collide.wit:4:1 + | + 4 | foo: func() + | ^-- \ No newline at end of file diff --git a/crates/parser/tests/ui/values.wit b/crates/parser/tests/ui/values.wit index 413bdfdc9..06890234b 100644 --- a/crates/parser/tests/ui/values.wit +++ b/crates/parser/tests/ui/values.wit @@ -1,4 +1,4 @@ a: s32 b: tuple<> -record a {} -c: tuple +record c {} +d: tuple diff --git a/crates/parser/tests/ui/values.wit.result b/crates/parser/tests/ui/values.wit.result index d04150c13..48da2f709 100644 --- a/crates/parser/tests/ui/values.wit.result +++ b/crates/parser/tests/ui/values.wit.result @@ -2,7 +2,7 @@ "types": [ { "idx": 0, - "name": "a", + "name": "c", "record": { "fields": [] } @@ -33,7 +33,7 @@ "ty": "type-1" }, { - "name": "c", + "name": "d", "ty": "type-2" } ] diff --git a/tests/runtime/flavorful/exports.wit b/tests/runtime/flavorful/exports.wit index bc751b961..10da9217c 100644 --- a/tests/runtime/flavorful/exports.wit +++ b/tests/runtime/flavorful/exports.wit @@ -6,10 +6,10 @@ record list-in-record3 { a: string } record list-in-record4 { a: string } type list-in-alias = list-in-record4 -list-in-record1: func(a: list-in-record1) -list-in-record2: func() -> list-in-record2 -list-in-record3: func(a: list-in-record3) -> list-in-record3 -list-in-record4: func(a: list-in-alias) -> list-in-alias +list-in-record1-func: func(a: list-in-record1) +list-in-record2-func: func() -> list-in-record2 +list-in-record3-func: func(a: list-in-record3) -> list-in-record3 +list-in-record4-func: func(a: list-in-alias) -> list-in-alias type list-in-variant1-v1 = option type list-in-variant1-v2 = expected @@ -17,10 +17,10 @@ union list-in-variant1-v3 { string, float32 } list-in-variant1: func(a: list-in-variant1-v1, b: list-in-variant1-v2, c: list-in-variant1-v3) type list-in-variant2 = option -list-in-variant2: func() -> list-in-variant2 +list-in-variant2-func: func() -> list-in-variant2 type list-in-variant3 = option -list-in-variant3: func(a: list-in-variant3) -> list-in-variant3 +list-in-variant3-func: func(a: list-in-variant3) -> list-in-variant3 enum my-errno { success, a, b } errno-result: func() -> expected diff --git a/tests/runtime/flavorful/host.py b/tests/runtime/flavorful/host.py index 6fa7afe2a..55ad7a3ec 100644 --- a/tests/runtime/flavorful/host.py +++ b/tests/runtime/flavorful/host.py @@ -7,17 +7,17 @@ import wasmtime class MyImports: - def list_in_record1(self, a: i.ListInRecord1) -> None: + def list_in_record1_func(self, a: i.ListInRecord1) -> None: pass - def list_in_record2(self) -> i.ListInRecord2: + def list_in_record2_func(self) -> i.ListInRecord2: return i.ListInRecord2('list_in_record2') - def list_in_record3(self, a: i.ListInRecord3) -> i.ListInRecord3: + def list_in_record3_func(self, a: i.ListInRecord3) -> i.ListInRecord3: assert(a.a == 'list_in_record3 input') return i.ListInRecord3('list_in_record3 output') - def list_in_record4(self, a: i.ListInAlias) -> i.ListInAlias: + def list_in_record4_func(self, a: i.ListInAlias) -> i.ListInAlias: assert(a.a == 'input4') return i.ListInRecord4('result4') @@ -26,10 +26,10 @@ def list_in_variant1(self, a: i.ListInVariant1V1, b: i.ListInVariant1V2, c: i.Li assert(b == i.Err('bar')) assert(c == 'baz') - def list_in_variant2(self) -> i.ListInVariant2: + def list_in_variant2_func(self) -> i.ListInVariant2: return 'list_in_variant2' - def list_in_variant3(self, a: i.ListInVariant3) -> i.ListInVariant3: + def list_in_variant3_func(self, a: i.ListInVariant3) -> i.ListInVariant3: assert(a == 'input3') return 'output3' @@ -66,15 +66,15 @@ def run(wasm_file: str) -> None: wasm = Exports(store, linker, module) wasm.test_imports(store) - wasm.list_in_record1(store, e.ListInRecord1("list_in_record1")) - assert(wasm.list_in_record2(store) == e.ListInRecord2(a="list_in_record2")) + wasm.list_in_record1_func(store, e.ListInRecord1("list_in_record1")) + assert(wasm.list_in_record2_func(store) == e.ListInRecord2(a="list_in_record2")) - assert(wasm.list_in_record3(store, e.ListInRecord3("list_in_record3 input")).a == "list_in_record3 output") - assert(wasm.list_in_record4(store, e.ListInRecord4("input4")).a == "result4") + assert(wasm.list_in_record3_func(store, e.ListInRecord3("list_in_record3 input")).a == "list_in_record3 output") + assert(wasm.list_in_record4_func(store, e.ListInRecord4("input4")).a == "result4") wasm.list_in_variant1(store, "foo", e.Err("bar"), 'baz') - assert(wasm.list_in_variant2(store) == "list_in_variant2") - assert(wasm.list_in_variant3(store, "input3") == "output3") + assert(wasm.list_in_variant2_func(store) == "list_in_variant2") + assert(wasm.list_in_variant3_func(store, "input3") == "output3") assert(isinstance(wasm.errno_result(store), e.Err)) diff --git a/tests/runtime/flavorful/host.rs b/tests/runtime/flavorful/host.rs index 8b953e91a..c3af7e0a4 100644 --- a/tests/runtime/flavorful/host.rs +++ b/tests/runtime/flavorful/host.rs @@ -8,24 +8,24 @@ use imports::*; pub struct MyImports; impl Imports for MyImports { - fn list_in_record1(&mut self, ty: ListInRecord1<'_>) { + fn list_in_record1_func(&mut self, ty: ListInRecord1<'_>) { assert_eq!(ty.a, "list_in_record1"); } - fn list_in_record2(&mut self) -> ListInRecord2 { + fn list_in_record2_func(&mut self) -> ListInRecord2 { ListInRecord2 { a: "list_in_record2".to_string(), } } - fn list_in_record3(&mut self, a: ListInRecord3Param<'_>) -> ListInRecord3Result { + fn list_in_record3_func(&mut self, a: ListInRecord3Param<'_>) -> ListInRecord3Result { assert_eq!(a.a, "list_in_record3 input"); ListInRecord3Result { a: "list_in_record3 output".to_string(), } } - fn list_in_record4(&mut self, a: ListInAliasParam<'_>) -> ListInAliasResult { + fn list_in_record4_func(&mut self, a: ListInAliasParam<'_>) -> ListInAliasResult { assert_eq!(a.a, "input4"); ListInRecord4Result { a: "result4".to_string(), @@ -46,11 +46,11 @@ impl Imports for MyImports { } } - fn list_in_variant2(&mut self) -> Option { + fn list_in_variant2_func(&mut self) -> Option { Some("list_in_variant2".to_string()) } - fn list_in_variant3(&mut self, a: ListInVariant3Param<'_>) -> Option { + fn list_in_variant3_func(&mut self, a: ListInVariant3Param<'_>) -> Option { assert_eq!(a.unwrap(), "input3"); Some("output3".to_string()) } @@ -104,17 +104,17 @@ fn run(wasm: &str) -> Result<()> { exports.test_imports(&mut store)?; - exports.list_in_record1( + exports.list_in_record1_func( &mut store, ListInRecord1 { a: "list_in_record1", }, )?; - assert_eq!(exports.list_in_record2(&mut store)?.a, "list_in_record2"); + assert_eq!(exports.list_in_record2_func(&mut store)?.a, "list_in_record2"); assert_eq!( exports - .list_in_record3( + .list_in_record3_func( &mut store, ListInRecord3Param { a: "list_in_record3 input" @@ -126,7 +126,7 @@ fn run(wasm: &str) -> Result<()> { assert_eq!( exports - .list_in_record4(&mut store, ListInAliasParam { a: "input4" })? + .list_in_record4_func(&mut store, ListInAliasParam { a: "input4" })? .a, "result4" ); @@ -138,11 +138,11 @@ fn run(wasm: &str) -> Result<()> { ListInVariant1V3::String("baz"), )?; assert_eq!( - exports.list_in_variant2(&mut store)?, + exports.list_in_variant2_func(&mut store)?, Some("list_in_variant2".to_string()) ); assert_eq!( - exports.list_in_variant3(&mut store, Some("input3"))?, + exports.list_in_variant3_func(&mut store, Some("input3"))?, Some("output3".to_string()) ); diff --git a/tests/runtime/flavorful/host.ts b/tests/runtime/flavorful/host.ts index 1548505e8..77a4a4b19 100644 --- a/tests/runtime/flavorful/host.ts +++ b/tests/runtime/flavorful/host.ts @@ -8,13 +8,13 @@ import * as assert from 'assert'; async function run() { const importObj = {}; const imports: Imports = { - listInRecord1(x) {}, - listInRecord2() { return { a: 'list_in_record2' }; }, - listInRecord3(x) { + listInRecord1Func(x) {}, + listInRecord2Func() { return { a: 'list_in_record2' }; }, + listInRecord3Func(x) { assert.strictEqual(x.a, 'list_in_record3 input'); return { a: 'list_in_record3 output' }; }, - listInRecord4(x) { + listInRecord4Func(x) { assert.strictEqual(x.a, 'input4'); return { a: 'result4' }; }, @@ -23,8 +23,8 @@ async function run() { assert.deepStrictEqual(b, { tag: 'err', val: 'bar' }); assert.deepStrictEqual(c, { tag: 0, val: 'baz' }); }, - listInVariant2() { return 'list_in_variant2'; }, - listInVariant3(x) { + listInVariant2Func() { return 'list_in_variant2'; }, + listInVariant3Func(x) { assert.strictEqual(x, 'input3'); return 'output3'; }, @@ -57,23 +57,23 @@ async function run() { instance = wasm.instance; wasm.testImports(); - wasm.listInRecord1({ a: "list_in_record1" }); - assert.deepStrictEqual(wasm.listInRecord2(), { a: "list_in_record2" }); + wasm.listInRecord1Func({ a: "list_in_record1" }); + assert.deepStrictEqual(wasm.listInRecord2Func(), { a: "list_in_record2" }); assert.deepStrictEqual( - wasm.listInRecord3({ a: "list_in_record3 input" }), + wasm.listInRecord3Func({ a: "list_in_record3 input" }), { a: "list_in_record3 output" }, ); assert.deepStrictEqual( - wasm.listInRecord4({ a: "input4" }), + wasm.listInRecord4Func({ a: "input4" }), { a: "result4" }, ); wasm.listInVariant1("foo", { tag: 'err', val: 'bar' }, { tag: 0, val: 'baz' }); - assert.deepStrictEqual(wasm.listInVariant2(), "list_in_variant2"); - assert.deepStrictEqual(wasm.listInVariant3("input3"), "output3"); + assert.deepStrictEqual(wasm.listInVariant2Func(), "list_in_variant2"); + assert.deepStrictEqual(wasm.listInVariant3Func("input3"), "output3"); assert.deepStrictEqual(wasm.errnoResult().tag, 'err'); diff --git a/tests/runtime/flavorful/imports.wit b/tests/runtime/flavorful/imports.wit index a3deecff5..c7d13c52a 100644 --- a/tests/runtime/flavorful/imports.wit +++ b/tests/runtime/flavorful/imports.wit @@ -4,10 +4,10 @@ record list-in-record3 { a: string } record list-in-record4 { a: string } type list-in-alias = list-in-record4 -list-in-record1: func(a: list-in-record1) -list-in-record2: func() -> list-in-record2 -list-in-record3: func(a: list-in-record3) -> list-in-record3 -list-in-record4: func(a: list-in-alias) -> list-in-alias +list-in-record1-func: func(a: list-in-record1) +list-in-record2-func: func() -> list-in-record2 +list-in-record3-func: func(a: list-in-record3) -> list-in-record3 +list-in-record4-func: func(a: list-in-alias) -> list-in-alias type list-in-variant1-v1 = option type list-in-variant1-v2 = expected @@ -15,10 +15,10 @@ union list-in-variant1-v3 { string, float32 } list-in-variant1: func(a: list-in-variant1-v1, b: list-in-variant1-v2, c: list-in-variant1-v3) type list-in-variant2 = option -list-in-variant2: func() -> list-in-variant2 +list-in-variant2-func: func() -> list-in-variant2 type list-in-variant3 = option -list-in-variant3: func(a: list-in-variant3) -> list-in-variant3 +list-in-variant3-func: func(a: list-in-variant3) -> list-in-variant3 enum my-errno { success, a, b } errno-result: func() -> expected diff --git a/tests/runtime/flavorful/wasm.c b/tests/runtime/flavorful/wasm.c index 522c6ca3d..3f4285424 100644 --- a/tests/runtime/flavorful/wasm.c +++ b/tests/runtime/flavorful/wasm.c @@ -8,10 +8,10 @@ void exports_test_imports() { { imports_list_in_record1_t a; imports_string_set(&a.a, "list_in_record1"); - imports_list_in_record1(&a); + imports_list_in_record1_func(&a); imports_list_in_record2_t b; - imports_list_in_record2(&b); + imports_list_in_record2_func(&b); assert(memcmp(b.a.ptr, "list_in_record2", b.a.len) == 0); imports_list_in_record2_free(&b); } @@ -19,7 +19,7 @@ void exports_test_imports() { { imports_list_in_record3_t a, b; imports_string_set(&a.a, "list_in_record3 input"); - imports_list_in_record3(&a, &b); + imports_list_in_record3_func(&a, &b); assert(memcmp(b.a.ptr, "list_in_record3 output", b.a.len) == 0); imports_list_in_record3_free(&b); } @@ -27,7 +27,7 @@ void exports_test_imports() { { imports_list_in_record4_t a, b; imports_string_set(&a.a, "input4"); - imports_list_in_record4(&a, &b); + imports_list_in_record4_func(&a, &b); assert(memcmp(b.a.ptr, "result4", b.a.len) == 0); imports_list_in_record4_free(&b); } @@ -47,7 +47,7 @@ void exports_test_imports() { { imports_string_t a; - assert(imports_list_in_variant2(&a)); + assert(imports_list_in_variant2_func(&a)); assert(memcmp(a.ptr, "list_in_variant2", a.len) == 0); imports_string_free(&a); } @@ -57,7 +57,7 @@ void exports_test_imports() { a.is_some = true; imports_string_set(&a.val, "input3"); imports_string_t b; - assert(imports_list_in_variant3(&a, &b)); + assert(imports_list_in_variant3_func(&a, &b)); assert(memcmp(b.ptr, "output3", b.len) == 0); imports_string_free(&b); } @@ -127,22 +127,22 @@ void exports_test_imports() { } } -void exports_list_in_record1(exports_list_in_record1_t *a) { +void exports_list_in_record1_func(exports_list_in_record1_t *a) { assert(memcmp(a->a.ptr, "list_in_record1", a->a.len) == 0); exports_list_in_record1_free(a); } -void exports_list_in_record2(exports_list_in_record2_t *ret0) { +void exports_list_in_record2_func(exports_list_in_record2_t *ret0) { exports_string_dup(&ret0->a, "list_in_record2"); } -void exports_list_in_record3(exports_list_in_record3_t *a, exports_list_in_record3_t *ret0) { +void exports_list_in_record3_func(exports_list_in_record3_t *a, exports_list_in_record3_t *ret0) { assert(memcmp(a->a.ptr, "list_in_record3 input", a->a.len) == 0); exports_list_in_record3_free(a); exports_string_dup(&ret0->a, "list_in_record3 output"); } -void exports_list_in_record4(exports_list_in_alias_t *a, exports_list_in_alias_t *ret0) { +void exports_list_in_record4_func(exports_list_in_alias_t *a, exports_list_in_alias_t *ret0) { assert(memcmp(a->a.ptr, "input4", a->a.len) == 0); exports_list_in_alias_free(a); exports_string_dup(&ret0->a, "result4"); @@ -162,12 +162,12 @@ void exports_list_in_variant1(exports_list_in_variant1_v1_t *a, exports_list_in_ exports_list_in_variant1_v3_free(c); } -bool exports_list_in_variant2(exports_string_t *ret0) { +bool exports_list_in_variant2_func(exports_string_t *ret0) { exports_string_dup(ret0, "list_in_variant2"); return true; } -bool exports_list_in_variant3(exports_list_in_variant3_t *a, exports_string_t *ret0) { +bool exports_list_in_variant3_func(exports_list_in_variant3_t *a, exports_string_t *ret0) { assert(a->is_some); assert(memcmp(a->val.ptr, "input3", a->val.len) == 0); exports_list_in_variant3_free(a); diff --git a/tests/runtime/flavorful/wasm.rs b/tests/runtime/flavorful/wasm.rs index 36d3bc882..dde176685 100644 --- a/tests/runtime/flavorful/wasm.rs +++ b/tests/runtime/flavorful/wasm.rs @@ -11,13 +11,13 @@ impl exports::Exports for Exports { let _guard = test_rust_wasm::guard(); - list_in_record1(ListInRecord1 { + list_in_record1_func(ListInRecord1 { a: "list_in_record1", }); - assert_eq!(list_in_record2().a, "list_in_record2"); + assert_eq!(list_in_record2_func().a, "list_in_record2"); assert_eq!( - list_in_record3(ListInRecord3Param { + list_in_record3_func(ListInRecord3Param { a: "list_in_record3 input" }) .a, @@ -25,14 +25,14 @@ impl exports::Exports for Exports { ); assert_eq!( - list_in_record4(ListInAliasParam { a: "input4" }).a, + list_in_record4_func(ListInAliasParam { a: "input4" }).a, "result4" ); list_in_variant1(Some("foo"), Err("bar"), ListInVariant1V3::String("baz")); - assert_eq!(list_in_variant2(), Some("list_in_variant2".to_string())); + assert_eq!(list_in_variant2_func(), Some("list_in_variant2".to_string())); assert_eq!( - list_in_variant3(Some("input3")), + list_in_variant3_func(Some("input3")), Some("output3".to_string()) ); @@ -57,24 +57,24 @@ impl exports::Exports for Exports { assert_eq!(c, [MyErrno::A, MyErrno::B]); } - fn list_in_record1(ty: ListInRecord1) { + fn list_in_record1_func(ty: ListInRecord1) { assert_eq!(ty.a, "list_in_record1"); } - fn list_in_record2() -> ListInRecord2 { + fn list_in_record2_func() -> ListInRecord2 { ListInRecord2 { a: "list_in_record2".to_string(), } } - fn list_in_record3(a: ListInRecord3) -> ListInRecord3 { + fn list_in_record3_func(a: ListInRecord3) -> ListInRecord3 { assert_eq!(a.a, "list_in_record3 input"); ListInRecord3 { a: "list_in_record3 output".to_string(), } } - fn list_in_record4(a: ListInAlias) -> ListInAlias { + fn list_in_record4_func(a: ListInAlias) -> ListInAlias { assert_eq!(a.a, "input4"); ListInRecord4 { a: "result4".to_string(), @@ -90,11 +90,11 @@ impl exports::Exports for Exports { } } - fn list_in_variant2() -> Option { + fn list_in_variant2_func() -> Option { Some("list_in_variant2".to_string()) } - fn list_in_variant3(a: ListInVariant3) -> Option { + fn list_in_variant3_func(a: ListInVariant3) -> Option { assert_eq!(a.unwrap(), "input3"); Some("output3".to_string()) }