diff --git a/crates/wit-parser/src/ast.rs b/crates/wit-parser/src/ast.rs index c2a93ae2a1..42758920f6 100644 --- a/crates/wit-parser/src/ast.rs +++ b/crates/wit-parser/src/ast.rs @@ -15,22 +15,27 @@ pub mod toposort; pub use lex::validate_id; pub struct Ast<'a> { - pub items: Vec>, + package_id: Option>, + items: Vec>, } impl<'a> Ast<'a> { pub fn parse(lexer: &mut Tokenizer<'a>) -> Result { let mut items = Vec::new(); + let mut package_id = None; + if lexer.eat(Token::Package)? { + package_id = Some(PackageName::parse(lexer)?); + } while lexer.clone().next()?.is_some() { let docs = parse_docs(lexer)?; items.push(AstItem::parse(lexer, docs)?); } - Ok(Self { items }) + Ok(Self { package_id, items }) } fn for_each_path<'b>( &'b self, - mut f: impl FnMut(Option<&'b Id<'a>>, &'b UsePath<'a>, Option<&[UseName<'a>]>) -> Result<()>, + mut f: impl FnMut(Option<&'b Id<'a>>, &'b UsePath<'a>, Option<&'b [UseName<'a>]>) -> Result<()>, ) -> Result<()> { for item in self.items.iter() { match item { @@ -61,7 +66,7 @@ impl<'a> Ast<'a> { Ok(()) } ExternKind::Path(path) => f(None, path, None), - ExternKind::Func(_) => Ok(()), + ExternKind::Func(..) => Ok(()), }; for kind in imports { @@ -79,51 +84,104 @@ impl<'a> Ast<'a> { } } } + AstItem::Use(u) => { + f(None, &u.item, None)?; + } } } Ok(()) } } -pub enum AstItem<'a> { +enum AstItem<'a> { Interface(Interface<'a>), World(World<'a>), + Use(ToplevelUse<'a>), } impl<'a> AstItem<'a> { fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { - let mut clone = tokens.clone(); - let token = match clone.next()? { - Some((_span, Token::Default)) => clone.next()?, - other => other, - }; - match token { + match tokens.clone().next()? { Some((_span, Token::Interface)) => Interface::parse(tokens, docs).map(Self::Interface), Some((_span, Token::World)) => World::parse(tokens, docs).map(Self::World), - other => Err(err_expected(tokens, "`default`, `world` or `interface`", other).into()), + Some((_span, Token::Use)) => ToplevelUse::parse(tokens).map(Self::Use), + other => Err(err_expected(tokens, "`world` or `interface`", other).into()), } } } -pub struct World<'a> { +#[derive(Debug, Clone)] +struct PackageName<'a> { + span: Span, + namespace: Option>, + name: Id<'a>, + version: Option<(Span, u32, u32)>, +} + +impl<'a> PackageName<'a> { + fn parse(tokens: &mut Tokenizer<'a>) -> Result { + let id = parse_id(tokens)?; + if tokens.eat(Token::Colon)? { + let name = parse_id(tokens)?; + let version = parse_opt_version(tokens)?; + Ok(PackageName { + span: Span { + start: id.span.start, + end: version.map(|(s, _, _)| s.end).unwrap_or(name.span.end), + }, + namespace: Some(id), + name, + version, + }) + } else { + Ok(PackageName { + span: id.span, + namespace: None, + name: id, + version: None, + }) + } + } + + fn package_name(&self) -> crate::PackageName { + crate::PackageName { + namespace: self.namespace.as_ref().map(|s| s.name.to_string()), + name: self.name.name.to_string(), + version: self.version.map(|(_, a, b)| (a, b)), + } + } +} + +struct ToplevelUse<'a> { + item: UsePath<'a>, + as_: Option>, +} + +impl<'a> ToplevelUse<'a> { + fn parse(tokens: &mut Tokenizer<'a>) -> Result { + tokens.expect(Token::Use)?; + let item = UsePath::parse(tokens)?; + let as_ = if tokens.eat(Token::As)? { + Some(parse_id(tokens)?) + } else { + None + }; + Ok(ToplevelUse { item, as_ }) + } +} + +struct World<'a> { docs: Docs<'a>, name: Id<'a>, items: Vec>, - default: bool, } impl<'a> World<'a> { fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { - let default = tokens.eat(Token::Default)?; tokens.expect(Token::World)?; let name = parse_id(tokens)?; let items = Self::parse_items(tokens)?; - Ok(World { - docs, - name, - items, - default, - }) + Ok(World { docs, name, items }) } fn parse_items(tokens: &mut Tokenizer<'a>) -> Result>> { @@ -140,7 +198,7 @@ impl<'a> World<'a> { } } -pub enum WorldItem<'a> { +enum WorldItem<'a> { Import(Import<'a>), Export(Export<'a>), Use(Use<'a>), @@ -173,80 +231,84 @@ impl<'a> WorldItem<'a> { } } -pub struct Import<'a> { +struct Import<'a> { docs: Docs<'a>, - name: Id<'a>, kind: ExternKind<'a>, } impl<'a> Import<'a> { fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result> { tokens.expect(Token::Import)?; - let name = parse_id(tokens)?; - tokens.expect(Token::Colon)?; let kind = ExternKind::parse(tokens)?; - Ok(Import { docs, name, kind }) + Ok(Import { docs, kind }) } } -pub struct Export<'a> { +struct Export<'a> { docs: Docs<'a>, - name: Id<'a>, kind: ExternKind<'a>, } impl<'a> Export<'a> { fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result> { tokens.expect(Token::Export)?; - let name = parse_id(tokens)?; - tokens.expect(Token::Colon)?; let kind = ExternKind::parse(tokens)?; - Ok(Export { docs, name, kind }) + Ok(Export { docs, kind }) } } -pub enum ExternKind<'a> { - Interface(Span, Vec>), +enum ExternKind<'a> { + Interface(Id<'a>, Vec>), Path(UsePath<'a>), - Func(Func<'a>), + Func(Id<'a>, Func<'a>), } impl<'a> ExternKind<'a> { fn parse(tokens: &mut Tokenizer<'a>) -> Result> { - match tokens.clone().next()? { - Some((_span, Token::Id | Token::ExplicitId | Token::Pkg | Token::Self_)) => { - UsePath::parse(tokens).map(ExternKind::Path) + let mut clone = tokens.clone(); + let id = parse_id(&mut clone)?; + if clone.eat(Token::Colon)? { + // import foo: func(...) + if clone.clone().eat(Token::Func)? { + *tokens = clone; + return Ok(ExternKind::Func(id, Func::parse(tokens)?)); } - Some((_span, Token::Interface)) => { - let span = tokens.expect(Token::Interface)?; - let items = Interface::parse_items(tokens)?; - Ok(ExternKind::Interface(span, items)) + + // import foo: interface { ... } + if clone.eat(Token::Interface)? { + *tokens = clone; + return Ok(ExternKind::Interface(id, Interface::parse_items(tokens)?)); } - Some((_span, Token::Func)) => Ok(ExternKind::Func(Func::parse(tokens)?)), - other => Err(err_expected(tokens, "path, value, or interface", other).into()), + } + + // import foo + // import foo/bar + // import foo:bar/baz + Ok(ExternKind::Path(UsePath::parse(tokens)?)) + } + + fn span(&self) -> Span { + match self { + ExternKind::Interface(id, _) => id.span, + ExternKind::Path(UsePath::Id(id)) => id.span, + ExternKind::Path(UsePath::Package { name, .. }) => name.span, + ExternKind::Func(id, _) => id.span, } } } -pub struct Interface<'a> { +struct Interface<'a> { docs: Docs<'a>, name: Id<'a>, items: Vec>, - default: bool, } impl<'a> Interface<'a> { fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { - let default = tokens.eat(Token::Default)?; tokens.expect(Token::Interface)?; let name = parse_id(tokens)?; let items = Self::parse_items(tokens)?; - Ok(Interface { - docs, - name, - items, - default, - }) + Ok(Interface { docs, name, items }) } pub(super) fn parse_items(tokens: &mut Tokenizer<'a>) -> Result>> { @@ -263,33 +325,74 @@ impl<'a> Interface<'a> { } } -pub enum InterfaceItem<'a> { +enum InterfaceItem<'a> { TypeDef(TypeDef<'a>), Value(Value<'a>), Use(Use<'a>), } -pub struct Use<'a> { - pub from: UsePath<'a>, - pub names: Vec>, +struct Use<'a> { + from: UsePath<'a>, + names: Vec>, } -pub enum UsePath<'a> { - Self_(Id<'a>), - Package { - doc: Id<'a>, - iface: Option>, - }, - Dependency { - dep: Id<'a>, - doc: Id<'a>, - iface: Option>, - }, +#[derive(Debug)] +enum UsePath<'a> { + Id(Id<'a>), + Package { id: PackageName<'a>, name: Id<'a> }, } -pub struct UseName<'a> { - pub name: Id<'a>, - pub as_: Option>, +impl<'a> UsePath<'a> { + fn parse(tokens: &mut Tokenizer<'a>) -> Result { + let id = parse_id(tokens)?; + if tokens.eat(Token::Colon)? { + // `foo:bar/baz@1.0` + let namespace = id; + let pkg_name = parse_id(tokens)?; + tokens.expect(Token::Slash)?; + let name = parse_id(tokens)?; + let version = parse_opt_version(tokens)?; + Ok(UsePath::Package { + id: PackageName { + span: Span { + start: namespace.span.start, + end: pkg_name.span.end, + }, + namespace: Some(namespace), + name: pkg_name, + version, + }, + name, + }) + } else if tokens.eat(Token::Slash)? { + // `foo/bar` + let name = parse_id(tokens)?; + Ok(UsePath::Package { + id: PackageName { + span: id.span, + namespace: None, + name: id, + version: None, + }, + name, + }) + } else { + // `foo` + Ok(UsePath::Id(id)) + } + } + + fn name(&self) -> &Id<'a> { + match self { + UsePath::Id(id) => id, + UsePath::Package { name, .. } => name, + } + } +} + +struct UseName<'a> { + name: Id<'a>, + as_: Option>, } impl<'a> Use<'a> { @@ -318,50 +421,10 @@ impl<'a> Use<'a> { } } -impl<'a> UsePath<'a> { - fn parse(tokens: &mut Tokenizer<'a>) -> Result { - match tokens.clone().next()? { - Some((_span, Token::Self_)) => { - tokens.expect(Token::Self_)?; - tokens.expect(Token::Period)?; - let name = parse_id(tokens)?; - Ok(UsePath::Self_(name)) - } - Some((_span, Token::Pkg)) => { - tokens.expect(Token::Pkg)?; - tokens.expect(Token::Period)?; - let doc = parse_id(tokens)?; - let mut clone = tokens.clone(); - let iface = if clone.eat(Token::Period)? && !clone.eat(Token::LeftBrace)? { - tokens.expect(Token::Period)?; - Some(parse_id(tokens)?) - } else { - None - }; - Ok(UsePath::Package { doc, iface }) - } - Some((_span, Token::Id | Token::ExplicitId)) => { - let dep = parse_id(tokens)?; - tokens.expect(Token::Period)?; - let doc = parse_id(tokens)?; - let mut clone = tokens.clone(); - let iface = if clone.eat(Token::Period)? && !clone.eat(Token::LeftBrace)? { - tokens.expect(Token::Period)?; - Some(parse_id(tokens)?) - } else { - None - }; - Ok(UsePath::Dependency { dep, doc, iface }) - } - other => return Err(err_expected(tokens, "`self`, `pkg`, or identifier", other).into()), - } - } -} - #[derive(Debug, Clone)] pub struct Id<'a> { - pub name: &'a str, - pub span: Span, + name: &'a str, + span: Span, } impl<'a> From<&'a str> for Id<'a> { @@ -378,7 +441,7 @@ pub struct Docs<'a> { docs: Vec>, } -pub struct TypeDef<'a> { +struct TypeDef<'a> { docs: Docs<'a>, name: Id<'a>, ty: Type<'a>, @@ -462,7 +525,7 @@ struct Stream<'a> { end: Option>>, } -pub struct Value<'a> { +struct Value<'a> { docs: Docs<'a>, name: Id<'a>, kind: ValueKind<'a>, @@ -489,7 +552,7 @@ enum ValueKind<'a> { Func(Func<'a>), } -pub struct Func<'a> { +struct Func<'a> { params: ParamList<'a>, results: ResultList<'a>, } @@ -691,6 +754,21 @@ fn parse_id<'a>(tokens: &mut Tokenizer<'a>) -> Result> { } } +fn parse_opt_version(tokens: &mut Tokenizer<'_>) -> Result> { + Ok(if tokens.eat(Token::At)? { + let major = tokens.expect(Token::Integer)?; + tokens.expect(Token::Period)?; + let minor = tokens.expect(Token::Integer)?; + let span = Span { + start: major.start, + end: minor.end, + }; + Some((span, tokens.parse_u32(major)?, tokens.parse_u32(minor)?)) + } else { + None + }) +} + fn parse_docs<'a>(tokens: &mut Tokenizer<'a>) -> Result> { let mut docs = Docs::default(); let mut clone = tokens.clone(); @@ -894,7 +972,7 @@ pub struct SourceMap { struct Source { offset: u32, path: PathBuf, - name: String, + // name: String, contents: String, } @@ -912,15 +990,7 @@ impl SourceMap { pub fn push_file(&mut self, path: &Path) -> Result<()> { let contents = std::fs::read_to_string(path) .with_context(|| format!("failed to read file {path:?}"))?; - let filename = match path.file_name().and_then(|s| s.to_str()) { - Some(stem) => stem, - None => bail!("no filename for {path:?}"), - }; - let name = match filename.find('.') { - Some(i) => &filename[..i], - None => filename, - }; - self.push(path, name, contents); + self.push(path, contents); Ok(()) } @@ -931,7 +1001,7 @@ impl SourceMap { /// instead only used during error messages. The `name` provided is the name /// of the document within the WIT package and must be a valid WIT /// identifier. - pub fn push(&mut self, path: &Path, name: &str, contents: impl Into) { + pub fn push(&mut self, path: &Path, contents: impl Into) { let mut contents = contents.into(); if path.extension().and_then(|s| s.to_str()) == Some("md") { log::debug!("automatically unwrapping markdown container"); @@ -942,7 +1012,6 @@ impl SourceMap { offset: self.offset, path: path.to_path_buf(), contents, - name: name.to_string(), }); self.offset = new_offset; @@ -988,20 +1057,20 @@ impl SourceMap { /// /// All files previously added are considered documents of the package to be /// returned. - pub fn parse(self, name: &str, url: Option<&str>) -> Result { + pub fn parse(self) -> Result { let mut doc = self.rewrite_error(|| { let mut resolver = Resolver::default(); let mut srcs = self.sources.iter().collect::>(); - srcs.sort_by_key(|src| &src.name); + srcs.sort_by_key(|src| &src.path); for src in srcs { let mut tokens = Tokenizer::new(&src.contents, src.offset) .with_context(|| format!("failed to tokenize path: {}", src.path.display()))?; let ast = Ast::parse(&mut tokens)?; - resolver.push(&src.name, ast).with_context(|| { + resolver.push(ast).with_context(|| { format!("failed to start resolving path: {}", src.path.display()) })?; } - resolver.resolve(name, url) + resolver.resolve() })?; doc.source_map = self; Ok(doc) diff --git a/crates/wit-parser/src/ast/lex.rs b/crates/wit-parser/src/ast/lex.rs index 5023a854a9..b21aff1ecd 100644 --- a/crates/wit-parser/src/ast/lex.rs +++ b/crates/wit-parser/src/ast/lex.rs @@ -46,6 +46,8 @@ pub enum Token { GreaterThan, RArrow, Star, + At, + Slash, Use, Type, @@ -79,16 +81,15 @@ pub enum Token { Static, Interface, Tuple, - Implements, Import, Export, World, - Default, - Pkg, - Self_, + Package, Id, ExplicitId, + + Integer, } #[derive(Eq, PartialEq, Debug)] @@ -145,6 +146,11 @@ impl<'a> Tokenizer<'a> { Ok(id_part) } + pub fn parse_u32(&self, span: Span) -> Result { + let ret = self.get_span(span); + Ok(ret.parse()?) + } + pub fn next(&mut self) -> Result, Error> { loop { match self.next_raw()? { @@ -174,6 +180,7 @@ impl<'a> Tokenizer<'a> { break; } } + Comment // eat a block comment if it's `/*...` } else if self.eatc('*') { let mut depth = 1; @@ -188,11 +195,10 @@ impl<'a> Tokenizer<'a> { _ => {} } } + Comment } else { - return Err(Error::Unexpected(start, ch)); + Slash } - - Comment } '=' => Equals, ',' => Comma, @@ -206,6 +212,7 @@ impl<'a> Tokenizer<'a> { '<' => LessThan, '>' => GreaterThan, '*' => Star, + '@' => At, '-' => { if self.eatc('>') { RArrow @@ -272,16 +279,26 @@ impl<'a> Tokenizer<'a> { "static" => Static, "interface" => Interface, "tuple" => Tuple, - "implements" => Implements, "world" => World, "import" => Import, "export" => Export, - "default" => Default, - "pkg" => Pkg, - "self" => Self_, + "package" => Package, _ => Id, } } + + ch if ch.is_ascii_digit() => { + let mut iter = self.chars.clone(); + while let Some((_, ch)) = iter.next() { + if !ch.is_ascii_digit() { + break; + } + self.chars = iter.clone(); + } + + Integer + } + ch => return Err(Error::Unexpected(start, ch)), }; let end = match self.chars.clone().next() { @@ -504,18 +521,18 @@ impl Token { ExplicitId => "an '%' identifier", RArrow => "`->`", Star => "`*`", + At => "`@`", + Slash => "`/`", As => "keyword `as`", From_ => "keyword `from`", Static => "keyword `static`", Interface => "keyword `interface`", Tuple => "keyword `tuple`", - Implements => "keyword `implements`", Import => "keyword `import`", Export => "keyword `export`", World => "keyword `world`", - Default => "keyword `default`", - Self_ => "keyword `self`", - Pkg => "keyword `pkg`", + Package => "keyword `package`", + Integer => "an integer", } } } diff --git a/crates/wit-parser/src/ast/resolve.rs b/crates/wit-parser/src/ast/resolve.rs index ba499cb532..2e6157e101 100644 --- a/crates/wit-parser/src/ast/resolve.rs +++ b/crates/wit-parser/src/ast/resolve.rs @@ -1,34 +1,80 @@ use super::{Error, ParamList, ResultList, ValueKind}; use crate::ast::toposort::toposort; use crate::*; -use anyhow::{anyhow, bail, Result}; +use anyhow::{bail, Result}; use indexmap::IndexMap; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::mem; #[derive(Default)] pub struct Resolver<'a> { - asts: IndexMap<&'a str, ast::Ast<'a>>, + /// Current package named learned through the ASTs pushed onto this resolver. + package_name: Option, + + /// All WIT files which are going to be resolved together. + asts: Vec>, + + // Arenas that get plumbed to the final `UnresolvedPackage` types: Arena, - anon_types: HashMap, interfaces: Arena, - documents: Arena, worlds: Arena, - document_lookup: IndexMap<&'a str, DocumentId>, - document_interfaces: Vec>, + + // Interning structure for types which-need-not-be-named such as + // `list` and such. + anon_types: HashMap, + + /// The index within `self.ast_items` that lookups should go through. This + /// is updated as the ASTs are walked. + cur_ast_index: usize, + + /// A map per `ast::Ast` which keeps track of the file's top level names in + /// scope. This maps each name onto either a world or an interface, handling + /// things like `use` at the top level. + ast_items: Vec>, + + /// A map for the entire package being created of all names defined within, + /// along with the ID they're mapping to. + package_items: IndexMap<&'a str, AstItem>, + + /// A per-interface map of name to item-in-the-interface. This is the same + /// length as `self.types` and is pushed to whenever `self.types` is pushed + /// to. interface_types: Vec>, - foreign_deps: IndexMap<&'a str, IndexMap<&'a str, DocumentId>>, + + /// Metadata about foreign dependencies which are not defined in this + /// package. This map is keyed by the name of the package being imported + /// from. The next level of key is the name of the interface being imported + /// from, and the final value is the assigned ID of the interface. + foreign_deps: IndexMap>, + + /// All interfaces that are present within `self.foreign_deps`. + foreign_interfaces: HashSet, + + /// The current type lookup scope which will eventually make its way into + /// `self.interface_types`. type_lookup: IndexMap<&'a str, (TypeOrItem, Span)>, + /// An assigned span for where all types inserted into `self.types` as + /// imported from foreign interfaces. These types all show up first in the + /// `self.types` arena and this span is used to generate an error message + /// pointing to it if the item isn't actually defined. unknown_type_spans: Vec, + + /// Spans for each world in `self.world` to assign for each import/export + /// for later error reporting. world_spans: Vec<(Vec, Vec)>, - document_spans: Vec, + + /// The span of each interface's definition which is used for error + /// reporting during the final `Resolve` phase. interface_spans: Vec, + + /// Spans per entry in `self.foreign_deps` for where the dependency was + /// introduced to print an error message if necessary. foreign_dep_spans: Vec, } -#[derive(Copy, Clone)] -enum DocumentItem { +#[derive(Debug, Copy, Clone)] +enum AstItem { Interface(InterfaceId), World(WorldId), } @@ -59,71 +105,90 @@ enum TypeOrItem { } impl<'a> Resolver<'a> { - pub(crate) fn push(&mut self, name: &'a str, ast: ast::Ast<'a>) -> Result<()> { - // Note that this specifically uses `map_err` instead of `with_context` - // since the error returned from `validate_id` is an `Error` which has a - // filename and a line number, but there's no filename or line number - // associated with this error so we just want the string message. - crate::validate_id(name) - .map_err(|e| anyhow!("name of document isn't a valid WIT identifier `{name}`: {e}"))?; - - let prev = self.asts.insert(name, ast); - if prev.is_some() { - bail!("document `{name}` is defined more than once"); + pub(crate) fn push(&mut self, ast: ast::Ast<'a>) -> Result<()> { + // As each WIT file is pushed into this resolver keep track of the + // current package name assigned. Only one file needs to mention it, but + // if multiple mention it then they must all match. + if let Some(cur) = &ast.package_id { + let cur_name = cur.package_name(); + if let Some(prev) = &self.package_name { + if cur_name != *prev { + bail!(Error { + span: cur.span, + msg: format!("package identifier does not match previous"), + }) + } + } + self.package_name = Some(cur_name); } + self.asts.push(ast); Ok(()) } - pub(crate) fn resolve(&mut self, name: &str, url: Option<&str>) -> Result { - self.populate_foreign_deps(); + pub(crate) fn resolve(&mut self) -> Result { + // At least one of the WIT files must have a `package` annotation. + let name = match &self.package_name { + Some(name) => name.clone(), + None => bail!("no `package` header was found in any WIT file for this package"), + }; - // Determine the dependencies between documents in the current package - // we're parsing to perform a topological sort and how to visit the - // documents in order. - let mut doc_deps = IndexMap::new(); - for (name, ast) in self.asts.iter() { - let mut deps = Vec::new(); - ast.for_each_path(|_, path, _names| { - let doc = match path { - ast::UsePath::Package { doc, iface: _ } => doc, - _ => return Ok(()), - }; - // If this document imports from itself using `pkg` syntax - // that's ok and skip this dependency to prevent it from - // otherwise being flagged as cyclic. - if doc.name == *name { - return Ok(()); - } - deps.push(doc.clone()); - Ok(()) - }) - .unwrap(); + // First populate information about foreign dependencies and the general + // structure of the package. This should resolve the "base" of many + // `use` statements and additionally generate a topological ordering of + // all interfaces in the package to visit. + let asts = mem::take(&mut self.asts); + self.populate_foreign_interfaces(&asts); + let order = self.populate_ast_items(&asts)?; + self.populate_foreign_types(&asts)?; - let prev = doc_deps.insert(*name, deps); - assert!(prev.is_none()); + // Use the topological ordering of all interfaces to resolve all + // interfaces in-order. Note that a reverse-mapping from ID to AST is + // generated here to assist with this. + let mut id_to_ast = IndexMap::new(); + for (i, ast) in asts.iter().enumerate() { + for item in ast.items.iter() { + if let ast::AstItem::Interface(interface) = item { + let id = match self.ast_items[i][interface.name.name] { + AstItem::Interface(id) => id, + AstItem::World(_) => unreachable!(), + }; + id_to_ast.insert(id, (interface, i)); + } + } + } + for id in order { + let (interface, i) = &id_to_ast[&id]; + self.cur_ast_index = *i; + self.resolve_interface(id, &interface.items, &interface.docs)?; } - let order = toposort("document", &doc_deps)?; - log::debug!("toposort for documents is {order:?}"); - let mut asts = mem::take(&mut self.asts); - for name in order { - let ast = asts.remove(&name).unwrap(); - self.resolve_document(name, &ast)?; + // With all interfaces out of the way the next order of business is to + // take care of all the worlds. Worlds only depend on interfaces so no + // topological ordering is necessary here. + for (i, ast) in asts.iter().enumerate() { + self.cur_ast_index = i; + for item in ast.items.iter() { + if let ast::AstItem::World(world) = item { + let id = match self.ast_items[i][world.name.name] { + AstItem::World(id) => id, + AstItem::Interface(_) => unreachable!(), + }; + self.resolve_world(id, world)?; + } + } } Ok(UnresolvedPackage { - name: name.to_string(), - url: url.map(|s| s.to_string()), + name, worlds: mem::take(&mut self.worlds), types: mem::take(&mut self.types), interfaces: mem::take(&mut self.interfaces), - documents: mem::take(&mut self.documents), foreign_deps: self .foreign_deps .iter() .map(|(name, deps)| { ( - name.to_string(), + name.clone(), deps.iter() .map(|(name, id)| (name.to_string(), *id)) .collect(), @@ -132,87 +197,256 @@ impl<'a> Resolver<'a> { .collect(), unknown_type_spans: mem::take(&mut self.unknown_type_spans), world_spans: mem::take(&mut self.world_spans), - document_spans: mem::take(&mut self.document_spans), interface_spans: mem::take(&mut self.interface_spans), foreign_dep_spans: mem::take(&mut self.foreign_dep_spans), source_map: SourceMap::default(), }) } - /// Populate "unknown" for all types referenced from foreign packages as - /// well as inserting interfaces for referenced interfaces. + /// Registers all foreign dependencies made within the ASTs provided. /// - /// This will populate the initial set of documents/interfaces/types with - /// everything referenced from foreign packages, or those through - /// `UsePath::Dependency`. The items created here are extracted later via - /// `resolve_path`. - fn populate_foreign_deps(&mut self) { - for (_, ast) in self.asts.iter() { - ast.for_each_path(|_, path, names| { - let (dep, doc, iface) = match path { - ast::UsePath::Dependency { dep, doc, iface } => (dep, doc, iface), + /// This will populate the `self.foreign_{deps,interfaces}` maps with all + /// `UsePath::Package` entries. + fn populate_foreign_interfaces(&mut self, asts: &[ast::Ast<'a>]) { + let mut foreign_deps = mem::take(&mut self.foreign_deps); + let mut foreign_interfaces = mem::take(&mut self.foreign_interfaces); + for ast in asts { + ast.for_each_path(|_, path, _names| { + let (id, name) = match path { + ast::UsePath::Package { id, name } => (id, name), _ => return Ok(()), }; - let deps = self.foreign_deps.entry(dep.name).or_insert_with(|| { - self.foreign_dep_spans.push(dep.span); + let deps = foreign_deps.entry(id.package_name()).or_insert_with(|| { + self.foreign_dep_spans.push(id.span); IndexMap::new() }); - let doc_span = doc.span; - let doc = *deps.entry(doc.name).or_insert_with(|| { - log::trace!("creating a document for foreign dep: {}", dep.name); - self.document_interfaces.push(IndexMap::new()); - self.document_spans.push(doc_span); - self.documents.alloc(Document { - name: doc.name.to_string(), - default_interface: None, - default_world: None, - interfaces: IndexMap::new(), - worlds: IndexMap::new(), - package: None, - }) + let id = *deps.entry(name.name).or_insert_with(|| { + log::trace!( + "creating an interface for foreign dep: {}/{}", + id.package_name(), + name.name + ); + self.alloc_interface(name.span) }); - let iface = match iface { - Some(iface) => { - let item = self.document_interfaces[doc.index()] - .entry(iface.name) - .or_insert_with(|| { - self.interface_types.push(IndexMap::new()); - self.interface_spans.push(iface.span); - let id = self.interfaces.alloc(Interface { - name: Some(iface.name.to_string()), - types: IndexMap::new(), - docs: Docs::default(), - document: doc, - functions: IndexMap::new(), - }); - DocumentItem::Interface(id) - }); - match item { - DocumentItem::Interface(id) => *id, - _ => unreachable!(), + foreign_interfaces.insert(id); + + Ok(()) + }) + .unwrap(); + } + self.foreign_deps = foreign_deps; + self.foreign_interfaces = foreign_interfaces; + } + + fn alloc_interface(&mut self, span: Span) -> InterfaceId { + self.interface_types.push(IndexMap::new()); + self.interface_spans.push(span); + self.interfaces.alloc(Interface { + name: None, + types: IndexMap::new(), + docs: Docs::default(), + functions: IndexMap::new(), + package: None, + }) + } + + /// This method will create a `World` and an `Interface` for all items + /// present in the specified set of ASTs. Additionally maps for each AST are + /// generated for resolving use-paths later on. + fn populate_ast_items(&mut self, asts: &[ast::Ast<'a>]) -> Result> { + let mut package_items = IndexMap::new(); + + // Validate that all worlds and interfaces have unique names within this + // package across all ASTs which make up the package. + let mut ast_namespaces = Vec::new(); + let mut order = IndexMap::new(); + for ast in asts { + let mut ast_ns = IndexMap::new(); + for item in ast.items.iter() { + match item { + ast::AstItem::Interface(i) => { + if package_items.insert(i.name.name, i.name.span).is_some() { + bail!(Error { + span: i.name.span, + msg: format!("duplicate item named `{}`", i.name.name), + }) + } + let prev = ast_ns.insert(i.name.name, ()); + assert!(prev.is_none()); + let prev = order.insert(i.name.name, Vec::new()); + assert!(prev.is_none()); + } + ast::AstItem::World(w) => { + if package_items.insert(w.name.name, w.name.span).is_some() { + bail!(Error { + span: w.name.span, + msg: format!("duplicate item named `{}", w.name.name), + }) } + let prev = ast_ns.insert(w.name.name, ()); + assert!(prev.is_none()); + } + // These are processed down below. + ast::AstItem::Use(_) => {} + } + } + ast_namespaces.push(ast_ns); + } + + // Next record dependencies between interfaces as induced via `use` + // paths. This step is used to perform a topological sort of all + // interfaces to ensure there are no cycles and to generate an ordering + // which we can resolve in. + enum ItemSource<'a> { + Foreign, + Local(ast::Id<'a>), + } + + for ast in asts { + // Record, in the context of this file, what all names are defined + // at the top level and whether they point to other items in this + // package or foreign items. Foreign deps are ignored for + // topological ordering. + let mut ast_ns = IndexMap::new(); + for item in ast.items.iter() { + let (name, src) = match item { + ast::AstItem::Use(u) => { + let name = u.as_.as_ref().unwrap_or(u.item.name()); + let src = match &u.item { + ast::UsePath::Id(id) => ItemSource::Local(id.clone()), + ast::UsePath::Package { .. } => ItemSource::Foreign, + }; + (name, src) } - None => *self.documents[doc] - .default_interface - .get_or_insert_with(|| { - self.interface_types.push(IndexMap::new()); - self.interface_spans.push(doc_span); - self.interfaces.alloc(Interface { - name: None, - types: IndexMap::new(), - docs: Docs::default(), - document: doc, - functions: IndexMap::new(), + ast::AstItem::Interface(i) => (&i.name, ItemSource::Local(i.name.clone())), + ast::AstItem::World(w) => (&w.name, ItemSource::Local(w.name.clone())), + }; + if ast_ns.insert(name.name, (name.span, src)).is_some() { + bail!(Error { + span: name.span, + msg: format!("duplicate name `{}` in this file", name.name), + }); + } + } + + // With this file's namespace information look at all `use` paths + // and record dependencies between interfaces. + ast.for_each_path(|iface, path, _names| { + // If this import isn't contained within an interface then it's + // in a world and it doesn't need to participate in our + // topo-sort. + let iface = match iface { + Some(name) => name, + None => return Ok(()), + }; + let used_name = match path { + ast::UsePath::Id(id) => id, + ast::UsePath::Package { .. } => return Ok(()), + }; + match ast_ns.get(used_name.name) { + Some((_, ItemSource::Foreign)) => return Ok(()), + Some((_, ItemSource::Local(id))) => { + order[iface.name].push(id.clone()); + } + None => match package_items.get(used_name.name) { + Some(_) => { + order[iface.name].push(used_name.clone()); + } + None => { + bail!(Error { + span: used_name.span, + msg: format!("interface not found in package"), }) - }), + } + }, + } + Ok(()) + })?; + } + + let order = toposort("interface", &order)?; + + // Allocate interfaces in-order now that the ordering is defined. This + // is then used to build up internal maps for each AST which are stored + // in `self.ast_items`. + let mut interface_ids = IndexMap::new(); + let mut id_order = Vec::new(); + for name in order { + let id = self.alloc_interface(package_items[name]); + self.interfaces[id].name = Some(name.to_string()); + let prev = interface_ids.insert(name, id); + assert!(prev.is_none()); + id_order.push(id); + } + for ast in asts { + let mut items = IndexMap::new(); + for item in ast.items.iter() { + let (name, ast_item) = match item { + ast::AstItem::Use(u) => { + let name = u.as_.as_ref().unwrap_or(u.item.name()); + let item = match &u.item { + ast::UsePath::Id(name) => { + *interface_ids.get(name.name).ok_or_else(|| Error { + span: name.span, + msg: format!("interface does not exist"), + })? + } + ast::UsePath::Package { id, name } => { + self.foreign_deps[&id.package_name()][name.name] + } + }; + (name.name, AstItem::Interface(item)) + } + ast::AstItem::Interface(i) => { + (i.name.name, AstItem::Interface(interface_ids[i.name.name])) + } + ast::AstItem::World(w) => { + let id = self.worlds.alloc(World { + name: w.name.name.to_string(), + docs: Docs::default(), + exports: IndexMap::new(), + imports: IndexMap::new(), + package: None, + }); + (w.name.name, AstItem::World(id)) + } }; + let prev = items.insert(name, ast_item); + assert!(prev.is_none()); + // Items defined via `use` don't go into the package namespace, + // only the file namespace. + if !matches!(item, ast::AstItem::Use(_)) { + let prev = self.package_items.insert(name, ast_item); + assert!(prev.is_none()); + } + } + self.ast_items.push(items); + } + Ok(id_order) + } + + /// Generate a `Type::Unknown` entry for all types imported from foreign + /// packages. + /// + /// This is done after all interfaces are generated so `self.resolve_path` + /// can be used to determine if what's being imported from is a foreign + /// interface or not. + fn populate_foreign_types(&mut self, asts: &[ast::Ast<'a>]) -> Result<()> { + for (i, ast) in asts.iter().enumerate() { + self.cur_ast_index = i; + ast.for_each_path(|_, path, names| { let names = match names { Some(names) => names, None => return Ok(()), }; + let iface = self.resolve_path(path)?; + if !self.foreign_interfaces.contains(&iface) { + return Ok(()); + } + let lookup = &mut self.interface_types[iface.index()]; for name in names { // If this name has already been defined then use that prior @@ -235,165 +469,14 @@ impl<'a> Resolver<'a> { } Ok(()) - }) - .unwrap(); - } - } - - fn resolve_document(&mut self, name: &'a str, ast: &ast::Ast<'a>) -> Result { - // Verify all top-level names in this document are unique, and save off - // the name of the default interface for drawing topological - // dependencies in a moment. - let mut names = HashMap::new(); - let mut default_interface_name = None; - let mut deps = IndexMap::new(); - for item in ast.items.iter() { - let name = match item { - ast::AstItem::Interface(i) => { - if i.default && default_interface_name.is_none() { - default_interface_name = Some(i.name.name); - } - &i.name - } - ast::AstItem::World(w) => &w.name, - }; - deps.insert(name.name, Vec::new()); - if names.insert(name.name, item).is_some() { - return Err(Error { - span: name.span, - msg: format!("name `{}` previously defined in document", name.name), - } - .into()); - } - } - - // Walk all `UsePath` entries in this AST and record dependencies - // between interfaces. These are dependencies specified via `use - // self...` or via `use pkg.this-doc...`. - ast.for_each_path(|iface, path, _names| { - // If this import isn't contained within an interface then it's in a - // world and it doesn't need to participate in our topo-sort. - let iface = match iface { - Some(name) => name, - None => return Ok(()), - }; - let deps = &mut deps[iface.name]; - match path { - // Self-deps are what we're mostly interested in here. - ast::UsePath::Self_(name) => deps.push(name.clone()), - - // Self-deps via the package happen when the `doc` name listed - // is the same as the name of the document being defined. - ast::UsePath::Package { doc, iface } => { - if doc.name != name { - return Ok(()); - } - let name = match iface { - Some(name) => name.clone(), - None => { - let name = default_interface_name.ok_or_else(|| Error { - span: doc.span, - msg: format!("no `default` interface in document to use from"), - })?; - ast::Id { - span: doc.span, - name, - } - } - }; - deps.push(name); - } - - // Dependencies on other packages don't participate in this - // topological ordering. - ast::UsePath::Dependency { .. } => {} - } - Ok(()) - })?; - let order = toposort("interface", &deps)?; - log::debug!("toposort for interfaces in `{name}` is {order:?}"); - - // Allocate a document ID and then start processing all of the - // interfaces as defined by our `order` to insert new interfaces into - // this. - let document_id = self.documents.alloc(Document { - name: name.to_string(), - default_interface: None, - default_world: None, - interfaces: IndexMap::new(), - worlds: IndexMap::new(), - package: None, - }); - self.document_interfaces.push(IndexMap::new()); - self.document_lookup.insert(name, document_id); - - let mut worlds = Vec::new(); - for name in order { - let interface = match names.remove(&name).unwrap() { - ast::AstItem::Interface(i) => i, - ast::AstItem::World(world) => { - worlds.push((name, world)); - continue; - } - }; - let id = self.resolve_interface( - document_id, - Some(interface.name.name), - &interface.items, - &interface.docs, - )?; - if interface.default { - let prev = &mut self.documents[document_id].default_interface; - if prev.is_some() { - return Err(Error { - span: interface.name.span, - msg: format!("cannot specify more than one `default` interface"), - } - .into()); - } - *prev = Some(id); - } - let prev = self.documents[document_id] - .interfaces - .insert(name.to_string(), id); - assert!(prev.is_none()); + })?; } - - // After all interfaces are defined then process all worlds as all items - // they import from should now be available. - for (name, world) in worlds { - let id = self.resolve_world(document_id, world)?; - if world.default { - let prev = &mut self.documents[document_id].default_world; - if prev.is_some() { - return Err(Error { - span: world.name.span, - msg: format!("cannot specify more than one `default` world"), - } - .into()); - } - *prev = Some(id); - } - let prev = self.documents[document_id] - .worlds - .insert(name.to_string(), id); - assert!(prev.is_none()); - } - - Ok(document_id) + Ok(()) } - fn resolve_world(&mut self, document: DocumentId, world: &ast::World<'a>) -> Result { + fn resolve_world(&mut self, world_id: WorldId, world: &ast::World<'a>) -> Result { let docs = self.docs(&world.docs); - let world_id = self.worlds.alloc(World { - docs, - document, - name: world.name.name.to_string(), - exports: IndexMap::new(), - imports: IndexMap::new(), - }); - self.document_interfaces[document.index()] - .insert(world.name.name, DocumentItem::World(world_id)); + self.worlds[world_id].docs = docs; self.resolve_types( TypeOwner::World(world_id), @@ -422,23 +505,22 @@ impl<'a> Resolver<'a> { } self.worlds[world_id] .imports - .insert(name.to_string(), WorldItem::Type(id)); + .insert(WorldKey::Name(name.to_string()), WorldItem::Type(id)); import_spans.push(*span); } TypeOrItem::Item(_) => unreachable!(), } } - let mut imported_interfaces = HashMap::new(); - let mut exported_interfaces = HashMap::new(); + let mut imported_interfaces = HashSet::new(); + let mut exported_interfaces = HashSet::new(); for item in world.items.iter() { - let (docs, name, kind, desc, spans, interfaces) = match item { + let (docs, kind, desc, spans, interfaces) = match item { // handled in `resolve_types` ast::WorldItem::Use(_) | ast::WorldItem::Type(_) => continue, ast::WorldItem::Import(import) => ( &import.docs, - &import.name, &import.kind, "import", &mut import_spans, @@ -446,35 +528,36 @@ impl<'a> Resolver<'a> { ), ast::WorldItem::Export(export) => ( &export.docs, - &export.name, &export.kind, "export", &mut export_spans, &mut exported_interfaces, ), }; - let prev = used_names.insert(name.name, desc); - if let Some(prev) = prev { - return Err(Error { - span: name.span, - msg: format!( - "{desc} `{name}` conflicts with prior {prev} of same name", - name = name.name - ), + let key = match kind { + ast::ExternKind::Interface(name, _) | ast::ExternKind::Func(name, _) => { + let prev = used_names.insert(name.name, desc); + if let Some(prev) = prev { + return Err(Error { + span: kind.span(), + msg: format!( + "{desc} `{name}` conflicts with prior {prev} of same name", + name = name.name + ), + } + .into()); + } + WorldKey::Name(name.name.to_string()) } - .into()); - } - let world_item = self.resolve_world_item(docs, name.name, document, kind)?; + ast::ExternKind::Path(path) => WorldKey::Interface(self.resolve_path(path)?), + }; + let world_item = self.resolve_world_item(docs, kind)?; if let WorldItem::Interface(id) = world_item { - if interfaces.insert(id, name.name).is_some() { - return Err(Error { - span: name.span, - msg: format!( - "interface `{name}` cannot be {desc}ed more than once", - name = name.name - ), - } - .into()); + if !interfaces.insert(id) { + bail!(Error { + span: kind.span(), + msg: format!("interface cannot be {desc}ed more than once",), + }) } } let dst = if desc == "import" { @@ -482,9 +565,9 @@ impl<'a> Resolver<'a> { } else { &mut self.worlds[world_id].exports }; - let prev = dst.insert(name.name.to_string(), world_item); + let prev = dst.insert(key, world_item); assert!(prev.is_none()); - spans.push(name.span); + spans.push(kind.span()); } self.world_spans.push((import_spans, export_spans)); self.type_lookup.clear(); @@ -495,14 +578,13 @@ impl<'a> Resolver<'a> { fn resolve_world_item( &mut self, docs: &ast::Docs<'a>, - name: &str, - document: DocumentId, kind: &ast::ExternKind<'a>, ) -> Result { match kind { - ast::ExternKind::Interface(_span, items) => { + ast::ExternKind::Interface(name, items) => { let prev = mem::take(&mut self.type_lookup); - let id = self.resolve_interface(document, None, items, docs)?; + let id = self.alloc_interface(name.span); + self.resolve_interface(id, items, docs)?; self.type_lookup = prev; Ok(WorldItem::Interface(id)) } @@ -510,8 +592,8 @@ impl<'a> Resolver<'a> { let id = self.resolve_path(path)?; Ok(WorldItem::Interface(id)) } - ast::ExternKind::Func(func) => { - let func = self.resolve_function(docs, name, func)?; + ast::ExternKind::Func(name, func) => { + let func = self.resolve_function(docs, name.name, func)?; Ok(WorldItem::Function(func)) } } @@ -519,23 +601,12 @@ impl<'a> Resolver<'a> { fn resolve_interface( &mut self, - document: DocumentId, - name: Option<&'a str>, + interface_id: InterfaceId, fields: &[ast::InterfaceItem<'a>], docs: &ast::Docs<'a>, - ) -> Result { + ) -> Result<()> { let docs = self.docs(docs); - let interface_id = self.interfaces.alloc(Interface { - docs, - document, - name: name.map(|s| s.to_string()), - functions: IndexMap::new(), - types: IndexMap::new(), - }); - if let Some(name) = name { - self.document_interfaces[document.index()] - .insert(name, DocumentItem::Interface(interface_id)); - } + self.interfaces[interface_id].docs = docs; self.resolve_types( TypeOwner::Interface(interface_id), @@ -576,10 +647,9 @@ impl<'a> Resolver<'a> { } let lookup = mem::take(&mut self.type_lookup); - assert_eq!(interface_id.index(), self.interface_types.len()); - self.interface_types.push(lookup); + self.interface_types[interface_id.index()] = lookup; - Ok(interface_id) + Ok(()) } fn resolve_types<'b>( @@ -700,60 +770,31 @@ impl<'a> Resolver<'a> { fn resolve_path(&self, path: &ast::UsePath<'a>) -> Result { match path { - ast::UsePath::Self_(iface) => { - match self.document_interfaces.last().unwrap().get(iface.name) { - Some(DocumentItem::Interface(id)) => Ok(*id), - Some(DocumentItem::World(_)) => bail!(Error { - span: iface.span, - msg: format!( - "name `{}` is defined as a world, not an interface", - iface.name - ), - }), - None => bail!(Error { - span: iface.span, - msg: format!("interface does not exist"), - }), - } - } - ast::UsePath::Package { doc, iface } => { - let doc_id = self.document_lookup[doc.name]; - match iface { - // If `iface` was provided then it must have been previously - // processed - Some(id) => { - let lookup = &self.document_interfaces[doc_id.index()]; - match lookup.get(id.name) { - Some(DocumentItem::Interface(id)) => Ok(*id), - Some(DocumentItem::World(_)) => Err(Error { - span: id.span, - msg: format!("cannot import from world `{}`", id.name), - } - .into()), - None => bail!(Error { - span: id.span, - msg: format!("interface does not exist"), - }), - } + ast::UsePath::Id(id) => { + let item = self.ast_items[self.cur_ast_index] + .get(id.name) + .or_else(|| self.package_items.get(id.name)); + match item { + Some(AstItem::Interface(id)) => Ok(*id), + Some(AstItem::World(_)) => { + bail!(Error { + span: id.span, + msg: format!( + "name `{}` is defined as a world, not an interface", + id.name + ), + }) + } + None => { + bail!(Error { + span: id.span, + msg: format!("interface does not exist"), + }) } - None => self.documents[doc_id].default_interface.ok_or_else(|| { - Error { - span: doc.span, - msg: format!("document does not specify a default interface"), - } - .into() - }), } } - ast::UsePath::Dependency { dep, doc, iface } => { - let doc = self.foreign_deps[dep.name][doc.name]; - match iface { - Some(name) => match self.document_interfaces[doc.index()][name.name] { - DocumentItem::Interface(id) => Ok(id), - DocumentItem::World(_) => unreachable!(), - }, - None => Ok(self.documents[doc].default_interface.unwrap()), - } + ast::UsePath::Package { id, name } => { + Ok(self.foreign_deps[&id.package_name()][name.name]) } } } diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs index f697b4200d..d764dbe4a5 100644 --- a/crates/wit-parser/src/lib.rs +++ b/crates/wit-parser/src/lib.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result}; use id_arena::{Arena, Id}; use indexmap::IndexMap; use std::borrow::Cow; @@ -25,7 +25,6 @@ pub fn validate_id(s: &str) -> Result<()> { pub type WorldId = Id; pub type InterfaceId = Id; pub type TypeId = Id; -pub type DocumentId = Id; /// Representation of a parsed WIT package which has not resolved external /// dependencies yet. @@ -54,15 +53,8 @@ pub type DocumentId = Id; /// performing this resolution themselves. #[derive(Clone)] pub struct UnresolvedPackage { - /// Local name for this package. - pub name: String, - - /// Optionally-specified URL for this package. - /// - /// Must be specified for non-local dependencies. Note that this is never - /// automatically set from [`UnresolvedPackage::parse`] methods, and it must - /// be manually configured in the return value. - pub url: Option, + /// The namespace, name, and version information for this package. + pub name: PackageName, /// All worlds from all documents within this package. /// @@ -85,30 +77,69 @@ pub struct UnresolvedPackage { /// other types transitively that are already iterated over. pub types: Arena, - /// All documents found within this package. - /// - /// Documents are sorted topologically in this arena with respect to imports - /// between them. - pub documents: Arena, - /// All foreign dependencies that this package depends on. /// /// These foreign dependencies must be resolved to convert this unresolved /// package into a `Resolve`. The map here is keyed by the name of the - /// foreign package that this depends on, and the sub-map is keyed by a - /// document name followed by the identifier within `self.documents`. The - /// fields of `self.documents` describes the required types, interfaces, - /// etc, that are required from each foreign package. - pub foreign_deps: IndexMap>, + /// foreign package that this depends on, and the sub-map is keyed by an + /// interface name followed by the identifier within `self.interfaces`. The + /// fields of `self.interfaces` describes the required types that are from + /// each foreign interface. + pub foreign_deps: IndexMap>, unknown_type_spans: Vec, world_spans: Vec<(Vec, Vec)>, - document_spans: Vec, interface_spans: Vec, foreign_dep_spans: Vec, source_map: SourceMap, } +/// A structure used to keep track of the name of a package, containing optional +/// information such as a namespace and version information. +/// +/// This is directly encoded as an "ID" in the binary component representation +/// with an interfaced tacked on as well. +#[derive(Debug, Clone, Hash, Eq, PartialEq)] +pub struct PackageName { + /// An optional namespace such as `wasi` in `wasi:foo/bar` + pub namespace: Option, + /// The kebab-name of this package, which is always specified. + pub name: String, + /// Optional major/minor version information. + pub version: Option<(u32, u32)>, +} + +impl PackageName { + /// Returns the ID that this package name would assign the `interface` name + /// specified. + pub fn interface_id(&self, interface: &str) -> String { + let mut s = String::new(); + if let Some(ns) = &self.namespace { + s.push_str(&format!("{ns}:")); + } + s.push_str(&self.name); + s.push_str("/"); + s.push_str(interface); + if let Some((major, minor)) = self.version { + s.push_str(&format!("@{major}.{minor}")); + } + s + } +} + +impl fmt::Display for PackageName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(ns) = &self.namespace { + write!(f, "{ns}:")?; + } + write!(f, "{}", self.name)?; + if let Some((major, minor)) = self.version { + write!(f, "@{major}.{minor}")?; + } + Ok(()) + } +} + #[derive(Debug)] struct Error { span: Span, @@ -130,16 +161,8 @@ impl UnresolvedPackage { /// will not be able to use `pkg` use paths to other documents. pub fn parse(path: &Path, contents: &str) -> Result { let mut map = SourceMap::default(); - let name = path - .file_name() - .and_then(|s| s.to_str()) - .ok_or_else(|| anyhow!("path doesn't end in a valid package name {path:?}"))?; - let name = match name.find('.') { - Some(i) => &name[..i], - None => name, - }; - map.push(path, name, contents); - map.parse(name, None) + map.push(path, contents); + map.parse() } /// Parse a WIT package at the provided path. @@ -171,10 +194,6 @@ impl UnresolvedPackage { /// `path` into the returned package. pub fn parse_dir(path: &Path) -> Result { let mut map = SourceMap::default(); - let name = path - .file_name() - .and_then(|s| s.to_str()) - .ok_or_else(|| anyhow!("path doesn't end in a valid package name {path:?}"))?; let cx = || format!("failed to read directory {path:?}"); for entry in path.read_dir().with_context(&cx)? { let entry = entry.with_context(&cx)?; @@ -197,7 +216,7 @@ impl UnresolvedPackage { } map.push_file(&path)?; } - map.parse(name, None) + map.parse() } /// Returns an iterator over the list of source files that were read when @@ -207,34 +226,6 @@ impl UnresolvedPackage { } } -/// Represents the result of parsing a wit document. -#[derive(Debug, Clone)] -pub struct Document { - pub name: String, - - /// The top-level interfaces contained in the document. - /// - /// The interfaces here are listed in topological order of the - /// dependencies between them. - pub interfaces: IndexMap, - - /// The worlds contained in the document. - pub worlds: IndexMap, - - /// The default interface of this document, if any. - /// - /// This interface will also be listed in `self.interfaces` - pub default_interface: Option, - - /// The default world of this document, if any. - /// - /// This will also be listed in `self.worlds`. - pub default_world: Option, - - /// The package that this document belongs to. - pub package: Option, -} - #[derive(Debug, Clone)] pub struct World { /// The WIT identifier name of this world. @@ -244,13 +235,34 @@ pub struct World { pub docs: Docs, /// All imported items into this interface, both worlds and functions. - pub imports: IndexMap, + pub imports: IndexMap, /// All exported items from this interface, both worlds and functions. - pub exports: IndexMap, + pub exports: IndexMap, - /// The document that owns this world. - pub document: DocumentId, + /// The package that owns this world. + pub package: Option, +} + +/// The key to the import/export maps of a world. Either a kebab-name or a +/// unique interface. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum WorldKey { + /// A kebab-name. + Name(String), + /// An interface which is assigned no kebab-name. + Interface(InterfaceId), +} + +impl WorldKey { + /// Asserts that this is `WorldKey::Name` and returns the name. + #[track_caller] + pub fn unwrap_name(self) -> String { + match self { + WorldKey::Name(name) => name, + WorldKey::Interface(_) => panic!("expected a name, found interface"), + } + } } #[derive(Debug, Clone)] @@ -287,8 +299,8 @@ pub struct Interface { /// Exported functions from this interface. pub functions: IndexMap, - /// The document that this interface belongs to. - pub document: DocumentId, + /// The package that owns this interface. + pub package: Option, } #[derive(Debug, Clone, PartialEq)] diff --git a/crates/wit-parser/src/live.rs b/crates/wit-parser/src/live.rs index 28a755382b..d236cf1ccd 100644 --- a/crates/wit-parser/src/live.rs +++ b/crates/wit-parser/src/live.rs @@ -1,6 +1,4 @@ -use crate::{ - DocumentId, Function, InterfaceId, Resolve, Type, TypeDefKind, TypeId, WorldId, WorldItem, -}; +use crate::{Function, InterfaceId, Resolve, Type, TypeDefKind, TypeId, WorldId, WorldItem}; use indexmap::IndexSet; #[derive(Default)] @@ -17,16 +15,6 @@ impl LiveTypes { self.set.len() } - pub fn add_document(&mut self, resolve: &Resolve, doc: DocumentId) { - let doc = &resolve.documents[doc]; - for (_, id) in doc.interfaces.iter() { - self.add_interface(resolve, *id); - } - for (_, id) in doc.worlds.iter() { - self.add_world(resolve, *id); - } - } - pub fn add_interface(&mut self, resolve: &Resolve, iface: InterfaceId) { let iface = &resolve.interfaces[iface]; for (_, id) in iface.types.iter() { diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs index 4294e70dd3..9faeccc085 100644 --- a/crates/wit-parser/src/resolve.rs +++ b/crates/wit-parser/src/resolve.rs @@ -1,16 +1,14 @@ use crate::ast::lex::Span; use crate::{ - Document, DocumentId, Error, Function, Interface, InterfaceId, Results, Type, TypeDef, - TypeDefKind, TypeId, TypeOwner, UnresolvedPackage, World, WorldId, WorldItem, + Error, Function, Interface, InterfaceId, PackageName, Results, Type, TypeDef, TypeDefKind, + TypeId, TypeOwner, UnresolvedPackage, World, WorldId, WorldItem, WorldKey, }; use anyhow::{anyhow, bail, Context, Result}; use id_arena::{Arena, Id}; use indexmap::{IndexMap, IndexSet}; use std::collections::{HashMap, HashSet}; -use std::fmt::Write; use std::mem; use std::path::{Path, PathBuf}; -use url::Url; /// Representation of a fully resolved set of WIT packages. /// @@ -30,21 +28,26 @@ pub struct Resolve { pub worlds: Arena, pub interfaces: Arena, pub types: Arena, - pub documents: Arena, pub packages: Arena, + pub package_names: IndexMap, } +/// A WIT package within a `Resolve`. +/// +/// A package is a collection of interfaces and worlds. Packages additionally +/// have a unique identifier that affects generated components and uniquely +/// identifiers this particular package. #[derive(Clone)] pub struct Package { - /// Locally-known name of this package. - pub name: String, + /// A unique name corresponding to this package. + pub name: PackageName, - /// Optionally-specified URL of this package, must be specified for remote - /// dependencies. - pub url: Option, + /// All interfaces contained in this packaged, keyed by the interface's + /// name. + pub interfaces: IndexMap, - /// Documents contained within this package, organized by name. - pub documents: IndexMap, + /// All worlds contained in this package, keyed by the world's name. + pub worlds: IndexMap, } pub type PackageId = Id; @@ -58,119 +61,90 @@ impl Resolve { /// Parses the filesystem directory at `path` as a WIT package and returns /// the fully resolved [`PackageId`] as a result. /// - /// This method is intended for testing and convenience for now and isn't - /// the only way to push packages into this [`Resolve`]. This will - /// interpret `path` as a directory where all `*.wit` files in that - /// directory are members of the package. - /// /// Dependencies referenced by the WIT package at `path` will be loaded from - /// a `deps/$name` directory under `path` where `$name` is the name of the - /// dependency loaded. If `deps/$name` does not exist then an error will be - /// returned indicating that the dependency is not defined. All dependencies - /// are listed in a flat namespace under `$path/deps` so they can refer to - /// each other. + /// a `deps/..` directory under `path`. All directories under `deps/` will + /// be parsed as a WIT package. The directory name containing each package + /// is not used as each package is otherwise self-identifying. /// /// This function returns the [`PackageId`] of the root parsed package at /// `path`, along with a list of all paths that were consumed during parsing /// for the root package and all dependency packages. pub fn push_dir(&mut self, path: &Path) -> Result<(PackageId, Vec)> { - // Maintain a `to_parse` stack of packages that have yet to be parsed - // along with an `enqueued` set of all the prior parsed packages and - // packages enqueued to be parsed. These are then used to fill the - // `packages` map with parsed, but unresolved, packages. The `pkg_deps` - // map then tracks dependencies between packages. - let mut to_parse = Vec::new(); - let mut enqueued = HashSet::new(); - let mut packages = IndexMap::new(); - let mut pkg_deps = IndexMap::new(); - to_parse.push((path.to_path_buf(), None)); - enqueued.insert(path.to_path_buf()); - while let Some((pkg_root, url)) = to_parse.pop() { - let mut pkg = UnresolvedPackage::parse_dir(&pkg_root) - .with_context(|| format!("failed to parse package: {}", path.display()))?; - pkg.url = url; - - let mut deps = Vec::new(); - pkg.source_map.rewrite_error(|| { - for (i, (dep, _)) in pkg.foreign_deps.iter().enumerate() { - let path = path.join("deps").join(dep); - let span = pkg.foreign_dep_spans[i]; - // If this is the first request to parse `path` then push it - // onto our stack, otherwise it's already there so skip it. - if enqueued.insert(path.clone()) { - if !path.is_dir() { - bail!(Error { - span, - msg: format!( - "dependency on `{dep}` doesn't exist at: {}", - path.display() - ), - }) - } - let url = Some(format!("path:/{dep}")); - to_parse.push((path.clone(), url)); - } - deps.push((path, span)); - } - Ok(()) - })?; + let pkg = UnresolvedPackage::parse_dir(path) + .with_context(|| format!("failed to parse package: {}", path.display()))?; - let prev = packages.insert(pkg_root.clone(), pkg); - assert!(prev.is_none()); - pkg_deps.insert(pkg_root, deps); - } + let deps = path.join("deps"); + let mut deps = parse_deps_dir(&deps) + .with_context(|| format!("failed to parse dependency directory: {}", deps.display()))?; // Perform a simple topological sort which will bail out on cycles // and otherwise determine the order that packages must be added to // this `Resolve`. let mut order = IndexSet::new(); let mut visiting = HashSet::new(); - for (dep, _) in pkg_deps.iter() { - visit(dep, &pkg_deps, &packages, &mut order, &mut visiting)?; - } + visit(&pkg, &deps, &mut order, &mut visiting)?; // Using the topological ordering insert each package incrementally. // Additionally note that the last item visited here is the root // package, which is the one returned here. - let mut package_ids = IndexMap::new(); let mut last = None; let mut files = Vec::new(); - for path in order { - let pkg = packages.remove(path).unwrap(); - let mut deps = HashMap::new(); - for ((dep, _), (path, _span)) in pkg.foreign_deps.iter().zip(&pkg_deps[path]) { - deps.insert(dep.clone(), package_ids[&**path]); - } + let mut pkg = Some(pkg); + for name in order { + let pkg = deps.remove(&name).unwrap_or_else(|| pkg.take().unwrap()); files.extend(pkg.source_files().map(|p| p.to_path_buf())); - let pkgid = self.push(pkg, &deps)?; - package_ids.insert(path, pkgid); + let pkgid = self.push(pkg)?; last = Some(pkgid); } return Ok((last.unwrap(), files)); + fn parse_deps_dir(path: &Path) -> Result> { + let mut ret = HashMap::new(); + // If there's no `deps` dir, then there's no deps, so return the + // empty set. + if !path.exists() { + return Ok(ret); + } + for dep in path.read_dir()? { + let dep = dep?; + let path = dep.path(); + let pkg = UnresolvedPackage::parse_dir(&path) + .with_context(|| format!("failed to parse package: {}", path.display()))?; + let prev = ret.insert(pkg.name.clone(), pkg); + if let Some(prev) = prev { + bail!("duplicate definitions of package `{}` found", prev.name); + } + } + Ok(ret) + } + fn visit<'a>( - path: &'a Path, - deps: &'a IndexMap>, - pkgs: &IndexMap, - order: &mut IndexSet<&'a Path>, - visiting: &mut HashSet<&'a Path>, + pkg: &'a UnresolvedPackage, + deps: &'a HashMap, + order: &mut IndexSet, + visiting: &mut HashSet<&'a PackageName>, ) -> Result<()> { - if order.contains(path) { + if order.contains(&pkg.name) { return Ok(()); } - pkgs[path].source_map.rewrite_error(|| { - for (dep, span) in deps[path].iter() { + pkg.source_map.rewrite_error(|| { + for (i, (dep, _)) in pkg.foreign_deps.iter().enumerate() { + let span = pkg.foreign_dep_spans[i]; if !visiting.insert(dep) { bail!(Error { - span: *span, + span, msg: format!("package depends on itself"), }); } - visit(dep, deps, pkgs, order, visiting)?; - assert!(visiting.remove(&**dep)); + let dep = deps.get(dep).ok_or_else(|| Error { + span, + msg: format!("failed to find package in `deps` directory"), + })?; + visit(dep, deps, order, visiting)?; + assert!(visiting.remove(&dep.name)); } - assert!(order.insert(path)); + assert!(order.insert(pkg.name.clone())); Ok(()) }) } @@ -184,13 +158,9 @@ impl Resolve { /// /// Any dependency resolution error or otherwise world-elaboration error /// will be returned here. If successful a package identifier is returned. - pub fn push( - &mut self, - mut unresolved: UnresolvedPackage, - deps: &HashMap, - ) -> Result { + pub fn push(&mut self, mut unresolved: UnresolvedPackage) -> Result { let source_map = mem::take(&mut unresolved.source_map); - source_map.rewrite_error(|| Remap::default().append(self, unresolved, deps)) + source_map.rewrite_error(|| Remap::default().append(self, unresolved)) } pub fn all_bits_valid(&self, ty: &Type) -> bool { @@ -255,9 +225,7 @@ impl Resolve { package_map, interface_map, type_map, - doc_map, world_map, - documents_to_add, interfaces_to_add, worlds_to_add, .. @@ -286,8 +254,8 @@ impl Resolve { types, worlds, interfaces, - documents, packages, + package_names, } = resolve; let mut moved_types = Vec::new(); @@ -316,40 +284,44 @@ impl Resolve { for (id, mut world) in worlds { let new_id = world_map.get(&id).copied().unwrap_or_else(|| { moved_worlds.push(id); - for (_, item) in world.imports.iter_mut().chain(&mut world.exports) { - match item { - WorldItem::Function(f) => remap.update_function(f), - WorldItem::Interface(i) => *i = remap.interfaces[i.index()], - WorldItem::Type(i) => *i = remap.types[i.index()], + let update = |map: &mut IndexMap| { + for (mut name, mut item) in mem::take(map) { + remap.update_world_key(&mut name); + match &mut item { + WorldItem::Function(f) => remap.update_function(f), + WorldItem::Interface(i) => *i = remap.interfaces[i.index()], + WorldItem::Type(i) => *i = remap.types[i.index()], + } + map.insert(name, item); } - } + }; + update(&mut world.imports); + update(&mut world.exports); self.worlds.alloc(world) }); assert_eq!(remap.worlds.len(), id.index()); remap.worlds.push(new_id); } - let mut moved_documents = Vec::new(); - for (id, mut doc) in documents { - let new_id = doc_map.get(&id).copied().unwrap_or_else(|| { - moved_documents.push(id); - remap.update_document(&mut doc); - self.documents.alloc(doc) + for (id, mut pkg) in packages { + let new_id = package_map.get(&id).copied().unwrap_or_else(|| { + for (_, id) in pkg.interfaces.iter_mut() { + *id = remap.interfaces[id.index()]; + } + for (_, id) in pkg.worlds.iter_mut() { + *id = remap.worlds[id.index()]; + } + self.packages.alloc(pkg) }); - assert_eq!(remap.documents.len(), id.index()); - remap.documents.push(new_id); + assert_eq!(remap.packages.len(), id.index()); + remap.packages.push(new_id); } - for (id, mut pkg) in packages { - for (_, doc) in pkg.documents.iter_mut() { - *doc = remap.documents[doc.index()]; + for (name, id) in package_names { + let id = remap.packages[id.index()]; + if let Some(prev) = self.package_names.insert(name, id) { + assert_eq!(prev, id); } - let new_id = package_map - .get(&id) - .copied() - .unwrap_or_else(|| self.packages.alloc(pkg)); - assert_eq!(remap.packages.len(), id.index()); - remap.packages.push(new_id); } // Fixup all "parent" links now. @@ -359,21 +331,15 @@ impl Resolve { // lists built incrementally above. The ids in the `moved_*` lists // are ids within `resolve`, so they're translated through `remap` to // ids within `self`. - for id in moved_documents { - let id = remap.documents[id.index()]; - if let Some(pkg) = &mut self.documents[id].package { - *pkg = remap.packages[pkg.index()]; - } - } for id in moved_worlds { let id = remap.worlds[id.index()]; - let doc = &mut self.worlds[id].document; - *doc = remap.documents[doc.index()]; + let pkg = self.worlds[id].package.as_mut().unwrap(); + *pkg = remap.packages[pkg.index()]; } for id in moved_interfaces { let id = remap.interfaces[id.index()]; - let doc = &mut self.interfaces[id].document; - *doc = remap.documents[doc.index()]; + let pkg = self.interfaces[id].package.as_mut().unwrap(); + *pkg = remap.packages[pkg.index()]; } for id in moved_types { let id = remap.types[id.index()]; @@ -384,24 +350,18 @@ impl Resolve { } } - // And finally process documents that were present in `resolve` but were + // And finally process items that were present in `resolve` but were // not present in `self`. This is only done for merged packages as // documents may be added to `self.documents` but wouldn't otherwise be // present in the `documents` field of the corresponding package. - for (name, pkg, doc) in documents_to_add { + for (name, pkg, iface) in interfaces_to_add { let prev = self.packages[pkg] - .documents - .insert(name, remap.documents[doc.index()]); - assert!(prev.is_none()); - } - for (name, doc, iface) in interfaces_to_add { - let prev = self.documents[doc] .interfaces .insert(name, remap.interfaces[iface.index()]); assert!(prev.is_none()); } - for (name, doc, world) in worlds_to_add { - let prev = self.documents[doc] + for (name, pkg, world) in worlds_to_add { + let prev = self.packages[pkg] .worlds .insert(name, remap.worlds[world.index()]); assert!(prev.is_none()); @@ -455,6 +415,8 @@ impl Resolve { if let WorldItem::Interface(id) = import { if let Some(prev) = into_imports_by_id.get(id) { if *prev != name { + let name = self.name_world_key(name); + let prev = self.name_world_key(prev); bail!("import `{name}` conflicts with previous name of `{prev}`"); } } @@ -466,6 +428,8 @@ impl Resolve { // so it's left as an error. if let WorldItem::Interface(id) = export { if let Some(prev) = into_exports_by_id.get(id) { + let name = self.name_world_key(name); + let prev = self.name_world_key(prev); bail!("export `{name}` conflicts with previous name of `{prev}`"); } } @@ -481,7 +445,10 @@ impl Resolve { (WorldItem::Interface(from), WorldItem::Interface(into)) if from == into => { continue } - _ => bail!("duplicate import found for interface `{name}`"), + _ => { + let name = self.name_world_key(name); + bail!("duplicate import found for interface `{name}`"); + } }, None => new_imports.push((name.clone(), from_import.clone())), } @@ -493,7 +460,10 @@ impl Resolve { // if the worlds have disjoint sets of exports. for (name, export) in from_world.exports.iter() { match into_world.exports.get(name) { - Some(_) => bail!("duplicate export found for interface `{name}`"), + Some(_) => { + let name = self.name_world_key(name); + bail!("duplicate export found for interface `{name}`"); + } None => new_exports.push((name.clone(), export.clone())), } } @@ -512,24 +482,24 @@ impl Resolve { Ok(()) } - /// Returns the URL of the specified `interface`, if available. + /// Returns the ID of the specified `interface`. /// - /// This currently creates a URL based on the URL of the package that - /// `interface` resides in. If the package owner of `interface` does not - /// specify a URL then `None` will be returned. - /// - /// If the `interface` specified does not have a name then `None` will be - /// returned as well. - pub fn url_of(&self, interface: InterfaceId) -> Option { + /// Returns `None` for unnamed interfaces. + pub fn id_of(&self, interface: InterfaceId) -> Option { let interface = &self.interfaces[interface]; - let doc = &self.documents[interface.document]; - let package = &self.packages[doc.package.unwrap()]; - let mut base = Url::parse(package.url.as_ref()?).unwrap(); - base.path_segments_mut() - .unwrap() - .push(&doc.name) - .push(interface.name.as_ref()?); - Some(base.to_string()) + let package = &self.packages[interface.package.unwrap()]; + let mut base = String::new(); + if let Some(ns) = &package.name.namespace { + base.push_str(ns); + base.push_str(":"); + } + base.push_str(&package.name.name); + base.push_str("/"); + base.push_str(interface.name.as_ref()?); + if let Some((major, minor)) = package.name.version { + base.push_str(&format!("@{major}.{minor}")); + } + Some(base) } /// Attempts to locate a default world for the `pkg` specified within this @@ -550,44 +520,26 @@ impl Resolve { /// would mean the `default world` of the `foo` document. The name `foo.bar` /// would mean the world named `bar` in the `foo` document. pub fn select_world(&self, pkg: PackageId, world: Option<&str>) -> Result { + let pkg = &self.packages[pkg]; match world { - Some(world) => { - let mut parts = world.splitn(2, '.'); - let doc = parts.next().unwrap(); - let world = parts.next(); - let doc = *self.packages[pkg] - .documents - .get(doc) - .ok_or_else(|| anyhow!("no document named `{doc}` in package"))?; - match world { - Some(name) => self.documents[doc] - .worlds - .get(name) - .copied() - .ok_or_else(|| anyhow!("no world named `{name}` in document")), - None => self.documents[doc] - .default_world - .ok_or_else(|| anyhow!("no default world in document")), - } - } - None => { - if self.packages[pkg].documents.is_empty() { - bail!("no documents found in package") - } - - let mut unique_default_world = None; - for (_name, doc) in &self.packages[pkg].documents { - if let Some(default_world) = self.documents[*doc].default_world { - if unique_default_world.is_some() { - bail!("multiple default worlds found in package, one must be specified") - } else { - unique_default_world = Some(default_world); - } - } - } + Some(world) => pkg + .worlds + .get(world) + .copied() + .ok_or_else(|| anyhow!("no world named `{world}` in package")), + None => match pkg.worlds.len() { + 0 => bail!("no worlds found in package"), + 1 => Ok(*pkg.worlds.values().next().unwrap()), + _ => bail!("multiple worlds found in package: one must be explicitly chosen"), + }, + } + } - unique_default_world.ok_or_else(|| anyhow!("no default world in package")) - } + /// Assigns a human readable name to the `WorldKey` specified. + pub fn name_world_key(&self, key: &WorldKey) -> String { + match key { + WorldKey::Name(s) => s.to_string(), + WorldKey::Interface(i) => self.id_of(*i).expect("unexpected anonymous interface"), } } } @@ -599,7 +551,6 @@ pub struct Remap { pub types: Vec, pub interfaces: Vec, pub worlds: Vec, - pub documents: Vec, pub packages: Vec, } @@ -608,13 +559,11 @@ impl Remap { &mut self, resolve: &mut Resolve, unresolved: UnresolvedPackage, - deps: &HashMap, ) -> Result { - self.process_foreign_deps(resolve, &unresolved, deps)?; + self.process_foreign_deps(resolve, &unresolved)?; let foreign_types = self.types.len(); let foreign_interfaces = self.interfaces.len(); - let foreign_documents = self.documents.len(); let foreign_worlds = self.worlds.len(); // Copy over all types first, updating any intra-type references. Note @@ -675,37 +624,30 @@ impl Remap { } } - // And the final major step is transferring documents to `Resolve` - // which is just updating a few identifiers here and there. - for (id, mut doc) in unresolved.documents.into_iter().skip(foreign_documents) { - self.update_document(&mut doc); - let new_id = resolve.documents.alloc(doc); - assert_eq!(self.documents.len(), id.index()); - self.documents.push(new_id); - } - - // Fixup "parent" ids now that everything has been identifier + // Fixup "parent" ids now that everything has been identified + let pkgid = resolve.packages.alloc(Package { + name: unresolved.name.clone(), + interfaces: Default::default(), + worlds: Default::default(), + }); + let prev = resolve.package_names.insert(unresolved.name.clone(), pkgid); + assert!(prev.is_none()); for id in self.interfaces.iter().skip(foreign_interfaces) { - let doc = &mut resolve.interfaces[*id].document; - *doc = self.documents[doc.index()]; + let iface = &mut resolve.interfaces[*id]; + iface.package = Some(pkgid); + if let Some(name) = &iface.name { + let prev = resolve.packages[pkgid].interfaces.insert(name.clone(), *id); + assert!(prev.is_none()); + } } for id in self.worlds.iter().skip(foreign_worlds) { - let doc = &mut resolve.worlds[*id].document; - *doc = self.documents[doc.index()]; - } - let mut documents = IndexMap::new(); - for id in self.documents.iter().skip(foreign_documents) { - let prev = documents.insert(resolve.documents[*id].name.clone(), *id); + let world = &mut resolve.worlds[*id]; + world.package = Some(pkgid); + let prev = resolve.packages[pkgid] + .worlds + .insert(world.name.clone(), *id); assert!(prev.is_none()); } - let pkgid = resolve.packages.alloc(Package { - name: unresolved.name, - url: unresolved.url, - documents, - }); - for (_, id) in resolve.packages[pkgid].documents.iter() { - resolve.documents[*id].package = Some(pkgid); - } Ok(pkgid) } @@ -713,81 +655,62 @@ impl Remap { &mut self, resolve: &mut Resolve, unresolved: &UnresolvedPackage, - deps: &HashMap, ) -> Result<()> { - // First, connect all references to foreign documents to actual - // documents within `resolve`, building up the initial entries of - // the `self.documents` mapping. - let mut document_to_package = HashMap::new(); - for (i, (pkg, docs)) in unresolved.foreign_deps.iter().enumerate() { - for (doc, unresolved_doc_id) in docs { - let prev = document_to_package.insert( - *unresolved_doc_id, - (pkg, doc, unresolved.foreign_dep_spans[i]), + // Invert the `foreign_deps` map to be keyed by interface id to get + // used in the loops below. + let mut interface_to_package = HashMap::new(); + for (i, (pkg_name, interfaces)) in unresolved.foreign_deps.iter().enumerate() { + for (interface, unresolved_interface_id) in interfaces { + let prev = interface_to_package.insert( + *unresolved_interface_id, + (pkg_name, interface, unresolved.foreign_dep_spans[i]), ); assert!(prev.is_none()); } } - for (unresolved_doc_id, _doc) in unresolved.documents.iter() { - let (pkg, doc, span) = match document_to_package.get(&unresolved_doc_id) { - Some(items) => *items, - None => break, - }; - let pkgid = *deps.get(pkg).ok_or_else(|| Error { - span, - msg: format!("no package dependency specified for `{pkg}`"), - })?; - let package = &resolve.packages[pkgid]; - - let docid = *package.documents.get(doc).ok_or_else(|| Error { - span: unresolved.document_spans[unresolved_doc_id.index()], - msg: format!("package `{pkg}` does not define document `{doc}`"), - })?; - - assert_eq!(self.documents.len(), unresolved_doc_id.index()); - self.documents.push(docid); - } - for (id, _) in unresolved.documents.iter().skip(self.documents.len()) { - assert!( - document_to_package.get(&id).is_none(), - "found foreign document after local documents" - ); - } - // Next, for all documents that are referenced in this `Resolve` - // determine the mapping of all interfaces that they refer to. + // Connect all interfaces referred to in `interface_to_package`, which + // are at the front of `unresolved.interfaces`, to interfaces already + // contained within `resolve`. for (unresolved_iface_id, unresolved_iface) in unresolved.interfaces.iter() { - let doc_id = match self.documents.get(unresolved_iface.document.index()) { - Some(i) => *i, + let (pkg_name, interface, span) = match interface_to_package.get(&unresolved_iface_id) { + Some(items) => *items, // All foreign interfaces are defined first, so the first one // which is defined in a non-foreign document means that all // further interfaces will be non-foreign as well. None => break, }; + let pkgid = resolve + .package_names + .get(pkg_name) + .copied() + .ok_or_else(|| Error { + span, + msg: format!("package not found"), + })?; // Functions can't be imported so this should be empty. assert!(unresolved_iface.functions.is_empty()); - let document = &resolve.documents[doc_id]; + let pkg = &resolve.packages[pkgid]; let span = unresolved.interface_spans[unresolved_iface_id.index()]; - let iface_id = match &unresolved_iface.name { - Some(name) => *document.interfaces.get(name).ok_or_else(|| Error { - span, - msg: format!("interface not defined in document"), - })?, - None => document.default_interface.ok_or_else(|| Error { + let iface_id = pkg + .interfaces + .get(interface) + .copied() + .ok_or_else(|| Error { span, - msg: format!("default interface not specified in document"), - })?, - }; + msg: format!("interface not found in package"), + })?; assert_eq!(self.interfaces.len(), unresolved_iface_id.index()); self.interfaces.push(iface_id); } - for (_, iface) in unresolved.interfaces.iter().skip(self.interfaces.len()) { - if self.documents.get(iface.document.index()).is_some() { - panic!("found foreign interface after local interfaces"); - } + for (id, _) in unresolved.interfaces.iter().skip(self.interfaces.len()) { + assert!( + interface_to_package.get(&id).is_none(), + "found foreign interface after local interface" + ); } // And finally iterate over all foreign-defined types and determine @@ -936,81 +859,61 @@ impl Remap { // Here each import of an interface is recorded and then additionally // explicitly named imports of interfaces are recorded as well for // determining names later on. - let mut explicit_import_names = HashMap::new(); - let mut explicit_export_names = HashMap::new(); - let mut imports = Vec::new(); - let mut exports = Vec::new(); let mut import_funcs = Vec::new(); - let mut export_funcs = Vec::new(); let mut import_types = Vec::new(); - for ((name, item), span) in mem::take(&mut world.imports).into_iter().zip(import_spans) { + for ((mut name, item), span) in mem::take(&mut world.imports).into_iter().zip(import_spans) + { + self.update_world_key(&mut name); match item { WorldItem::Interface(id) => { let id = self.interfaces[id.index()]; - imports.push((id, *span)); - let prev = explicit_import_names.insert(id, name); - assert!(prev.is_none()); + self.add_world_import(resolve, world, name, id); } WorldItem::Function(mut f) => { self.update_function(&mut f); - import_funcs.push((name, f, *span)); + import_funcs.push((name.unwrap_name(), f, *span)); } WorldItem::Type(id) => { let id = self.types[id.index()]; - import_types.push((name, id, *span)); + import_types.push((name.unwrap_name(), id, *span)); + } + } + } + + for (_name, id, _span) in import_types.iter() { + if let TypeDefKind::Type(Type::Id(other)) = resolve.types[*id].kind { + if let TypeOwner::Interface(owner) = resolve.types[other].owner { + let name = WorldKey::Interface(owner); + self.add_world_import(resolve, world, name, owner); } } } - for ((name, item), span) in mem::take(&mut world.exports).into_iter().zip(export_spans) { + + let mut export_funcs = Vec::new(); + for ((mut name, item), span) in mem::take(&mut world.exports).into_iter().zip(export_spans) + { + self.update_world_key(&mut name); match item { WorldItem::Interface(id) => { let id = self.interfaces[id.index()]; - exports.push((id, *span)); - let prev = explicit_export_names.insert(id, name); - assert!(prev.is_none()); + self.add_world_export(resolve, world, name, id); } WorldItem::Function(mut f) => { self.update_function(&mut f); + let name = match name { + WorldKey::Name(name) => name, + WorldKey::Interface(_) => unreachable!(), + }; export_funcs.push((name, f, *span)); } WorldItem::Type(_) => unreachable!(), } } - // Next all imports and their transitive imports are processed. This - // is done through a `stack` of `Action` items which is processed in - // LIFO order, meaning that an action of processing the dependencies - // is pushed after processing the node itself. The dependency processing - // will push more items onto the stack as necessary. - let mut elaborate = WorldElaborator { - resolve, - world, - imports_processed: Default::default(), - exports_processed: Default::default(), - resolving_stack: Default::default(), - explicit_import_names: &explicit_import_names, - explicit_export_names: &explicit_export_names, - names: Default::default(), - }; - for (id, span) in imports { - elaborate.import(id, span)?; - } - for (_name, id, span) in import_types.iter() { - if let TypeDefKind::Type(Type::Id(other)) = resolve.types[*id].kind { - if let TypeOwner::Interface(owner) = resolve.types[other].owner { - elaborate.import(owner, *span)?; - } - } - } - for (id, span) in exports { - elaborate.export(id, span)?; - } - for (name, id, span) in import_types { - let prev = elaborate - .world + let prev = world .imports - .insert(name.clone(), WorldItem::Type(id)); + .insert(WorldKey::Name(name.clone()), WorldItem::Type(id)); if prev.is_some() { bail!(Error { msg: format!("export of type `{name}` shadows previously imported interface"), @@ -1022,7 +925,7 @@ impl Remap { for (name, func, span) in import_funcs { let prev = world .imports - .insert(name.clone(), WorldItem::Function(func)); + .insert(WorldKey::Name(name.clone()), WorldItem::Function(func)); if prev.is_some() { bail!(Error { msg: format!( @@ -1035,8 +938,8 @@ impl Remap { for (name, func, span) in export_funcs { let prev = world .exports - .insert(name.clone(), WorldItem::Function(func)); - if prev.is_some() || world.imports.contains_key(&name) { + .insert(WorldKey::Name(name.clone()), WorldItem::Function(func)); + if prev.is_some() || world.imports.contains_key(&WorldKey::Name(name.clone())) { bail!(Error { msg: format!( "export of function `{name}` shadows previously exported interface" @@ -1052,129 +955,74 @@ impl Remap { Ok(()) } - fn update_document(&self, doc: &mut Document) { - for (_name, iface) in doc.interfaces.iter_mut() { - *iface = self.interfaces[iface.index()]; - } - for (_name, world) in doc.worlds.iter_mut() { - *world = self.worlds[world.index()]; - } - if let Some(default) = &mut doc.default_interface { - *default = self.interfaces[default.index()]; - } - if let Some(default) = &mut doc.default_world { - *default = self.worlds[default.index()]; + fn update_world_key(&self, key: &mut WorldKey) { + match key { + WorldKey::Name(_) => {} + WorldKey::Interface(id) => { + *id = self.interfaces[id.index()]; + } } } -} - -struct WorldElaborator<'a, 'b> { - resolve: &'a Resolve, - world: &'b mut World, - explicit_import_names: &'a HashMap, - explicit_export_names: &'a HashMap, - names: HashMap, - - /// Set of imports which are either imported into the world already or in - /// the `stack` to get processed, used to ensure the same dependency isn't - /// pushed multiple times into the stack. - imports_processed: HashSet, - exports_processed: HashSet, - - /// Dependency chain of why we're importing the top of `stack`, used to - /// print an error message. - resolving_stack: Vec<(InterfaceId, bool)>, -} - -impl<'a> WorldElaborator<'a, '_> { - fn import(&mut self, id: InterfaceId, span: Span) -> Result<()> { - self.recurse(id, span, true) - } - fn export(&mut self, id: InterfaceId, span: Span) -> Result<()> { - self.recurse(id, span, false) - } - - fn recurse(&mut self, id: InterfaceId, span: Span, import: bool) -> Result<()> { - let processed = if import { - &mut self.imports_processed - } else { - &mut self.exports_processed - }; - if !processed.insert(id) { - return Ok(()); - } - - self.resolving_stack.push((id, import)); - for (_, ty) in self.resolve.interfaces[id].types.iter() { - let ty = match self.resolve.types[*ty].kind { - TypeDefKind::Type(Type::Id(id)) => id, - _ => continue, - }; - let dep = match self.resolve.types[ty].owner { - TypeOwner::None => continue, - TypeOwner::Interface(other) => other, - TypeOwner::World(_) => unreachable!(), - }; - let import = import || !self.explicit_export_names.contains_key(&dep); - - self.recurse(dep, span, import)?; + fn add_world_import( + &self, + resolve: &Resolve, + world: &mut World, + key: WorldKey, + id: InterfaceId, + ) { + if world.imports.contains_key(&key) { + return; } - assert_eq!(self.resolving_stack.pop(), Some((id, import))); - let name = self.name_of(id, import); - let prev = self.names.insert(name.clone(), import); + foreach_interface_dep(resolve, id, |dep| { + self.add_world_import(resolve, world, WorldKey::Interface(dep), dep); + }); + let prev = world.imports.insert(key, WorldItem::Interface(id)); + assert!(prev.is_none()); + } - if prev.is_none() { - let set = if import { - &mut self.world.imports - } else { - &mut self.world.exports - }; - let prev = set.insert(name.clone(), WorldItem::Interface(id)); - assert!(prev.is_none()); - return Ok(()); + fn add_world_export( + &self, + resolve: &Resolve, + world: &mut World, + key: WorldKey, + id: InterfaceId, + ) { + if world + .exports + .insert(key, WorldItem::Interface(id)) + .is_some() + { + return; } - let desc = |import: bool| { - if import { - "import" - } else { - "export" + foreach_interface_dep(resolve, id, |dep| { + if !world.exports.contains_key(&WorldKey::Interface(dep)) { + self.add_world_import(resolve, world, WorldKey::Interface(dep), dep); } - }; - - let mut msg = format!("{} of `{}`", desc(import), self.name_of(id, import)); - if self.resolving_stack.is_empty() { - msg.push_str(" "); - } else { - msg.push_str("\n"); - } - for (i, import) in self.resolving_stack.iter().rev() { - writeln!( - msg, - " .. which is depended on by {} `{}`", - desc(*import), - self.name_of(*i, *import) - ) - .unwrap(); - } - writeln!( - msg, - "conflicts with a previous interface using the name `{name}`", - ) - .unwrap(); - bail!(Error { span, msg }) + }); } +} - fn name_of(&self, id: InterfaceId, import: bool) -> &'a String { - let set = if import { - &self.explicit_import_names - } else { - &self.explicit_export_names +fn foreach_interface_dep( + resolve: &Resolve, + interface: InterfaceId, + mut f: impl FnMut(InterfaceId), +) { + for (_, ty) in resolve.interfaces[interface].types.iter() { + let ty = match resolve.types[*ty].kind { + TypeDefKind::Type(Type::Id(id)) => id, + _ => continue, + }; + let dep = match resolve.types[ty].owner { + TypeOwner::None => continue, + TypeOwner::Interface(other) => other, + TypeOwner::World(_) => unreachable!(), }; - set.get(&id) - .unwrap_or_else(|| self.resolve.interfaces[id].name.as_ref().unwrap()) + if dep != interface { + f(dep); + } } } @@ -1191,10 +1039,6 @@ struct MergeMap<'a> { /// found to be equivalent. type_map: HashMap, - /// A map of document ids in `from` to those in `into` for those that are - /// found to be equivalent. - doc_map: HashMap, - /// A map of world ids in `from` to those in `into` for those that are /// found to be equivalent. world_map: HashMap, @@ -1203,68 +1047,46 @@ struct MergeMap<'a> { /// /// The elements here are: /// - /// * The name of the document + /// * The name of the interface/world /// * The ID within `into` of the package being added to - /// * The ID within `from` of the document being added. - documents_to_add: Vec<(String, PackageId, DocumentId)>, - interfaces_to_add: Vec<(String, DocumentId, InterfaceId)>, - worlds_to_add: Vec<(String, DocumentId, WorldId)>, + /// * The ID within `from` of the item being added. + interfaces_to_add: Vec<(String, PackageId, InterfaceId)>, + worlds_to_add: Vec<(String, PackageId, WorldId)>, /// Which `Resolve` is being merged from. from: &'a Resolve, /// Which `Resolve` is being merged into. into: &'a Resolve, - - /// A cache of packages, keyed by name/url, within `into`. - packages_in_into: HashMap<(&'a String, &'a Option), PackageId>, } impl<'a> MergeMap<'a> { fn new(from: &'a Resolve, into: &'a Resolve) -> Result> { - let mut packages_in_into = HashMap::new(); - for (id, package) in into.packages.iter() { - log::trace!("previous package {}/{:?}", package.name, package.url); - if package.url.is_none() { - continue; - } - let prev = packages_in_into.insert((&package.name, &package.url), id); - if prev.is_some() { - bail!( - "found duplicate name/url combination in current resolve: {}/{:?}", - package.name, - package.url - ); - } - } Ok(MergeMap { package_map: Default::default(), interface_map: Default::default(), type_map: Default::default(), - doc_map: Default::default(), world_map: Default::default(), - documents_to_add: Default::default(), interfaces_to_add: Default::default(), worlds_to_add: Default::default(), from, into, - packages_in_into, }) } fn build(&mut self) -> Result<()> { for (from_id, from) in self.from.packages.iter() { - let into_id = match self.packages_in_into.get(&(&from.name, &from.url)) { + let into_id = match self.into.package_names.get(&from.name) { Some(id) => *id, // This package, according to its name and url, is not present // in `self` so it needs to get added below. None => { - log::trace!("adding unique package {} / {:?}", from.name, from.url); + log::trace!("adding unique package {}", from.name); continue; } }; - log::trace!("merging duplicate package {} / {:?}", from.name, from.url); + log::trace!("merging duplicate package {}", from.name); self.build_package(from_id, into_id).with_context(|| { format!("failed to merge package `{}` into existing copy", from.name) @@ -1281,40 +1103,11 @@ impl<'a> MergeMap<'a> { let from = &self.from.packages[from_id]; let into = &self.into.packages[into_id]; - // All documents in `from` should already be present in `into` to get - // merged, or it's assumed `self.from` contains a view of the package - // which happens to contain more files. In this situation the job of - // merging will be to add a new document to the package within - // `self.into` which is queued up with `self.documents_to_add`. - for (name, from_id) in from.documents.iter() { - let into_id = match into.documents.get(name) { - Some(id) => *id, - None => { - self.documents_to_add - .push((name.clone(), into_id, *from_id)); - continue; - } - }; - - self.build_document(*from_id, into_id) - .with_context(|| format!("failed to merge document `{name}` into existing copy"))?; - } - - Ok(()) - } - - fn build_document(&mut self, from_id: DocumentId, into_id: DocumentId) -> Result<()> { - let prev = self.doc_map.insert(from_id, into_id); - assert!(prev.is_none()); - - let from_doc = &self.from.documents[from_id]; - let into_doc = &self.into.documents[into_id]; - - // Like documents above if an interface is present in `from_id` but not - // present in `into_id` then it can be copied over wholesale. That - // copy is scheduled to happen within the `self.interfaces_to_add` list. - for (name, from_interface_id) in from_doc.interfaces.iter() { - let into_interface_id = match into_doc.interfaces.get(name) { + // If an interface is present in `from_id` but not present in `into_id` + // then it can be copied over wholesale. That copy is scheduled to + // happen within the `self.interfaces_to_add` list. + for (name, from_interface_id) in from.interfaces.iter() { + let into_interface_id = match into.interfaces.get(name) { Some(id) => *id, None => { self.interfaces_to_add @@ -1327,8 +1120,8 @@ impl<'a> MergeMap<'a> { .with_context(|| format!("failed to merge interface `{name}`"))?; } - for (name, from_world_id) in from_doc.worlds.iter() { - let into_world_id = match into_doc.worlds.get(name) { + for (name, from_world_id) in from.worlds.iter() { + let into_world_id = match into.worlds.get(name) { Some(id) => *id, None => { self.worlds_to_add @@ -1340,6 +1133,7 @@ impl<'a> MergeMap<'a> { self.build_world(*from_world_id, into_world_id) .with_context(|| format!("failed to merge world `{name}`"))?; } + Ok(()) } @@ -1411,27 +1205,40 @@ impl<'a> MergeMap<'a> { bail!("world contains different number of exports than expected"); } - for (name, from) in from_world.imports.iter() { + for (from_name, from) in from_world.imports.iter() { + let into_name = self.map_name(from_name); + let name_str = self.from.name_world_key(from_name); let into = into_world .imports - .get(name) - .ok_or_else(|| anyhow!("import `{name}` not found in target world"))?; + .get(&into_name) + .ok_or_else(|| anyhow!("import `{name_str}` not found in target world"))?; self.match_world_item(from, into) - .with_context(|| format!("import `{name}` didn't match target world"))?; + .with_context(|| format!("import `{name_str}` didn't match target world"))?; } - for (name, from) in from_world.exports.iter() { + for (from_name, from) in from_world.exports.iter() { + let into_name = self.map_name(from_name); + let name_str = self.from.name_world_key(from_name); let into = into_world .exports - .get(name) - .ok_or_else(|| anyhow!("export `{name}` not found in target world"))?; + .get(&into_name) + .ok_or_else(|| anyhow!("export `{name_str}` not found in target world"))?; self.match_world_item(from, into) - .with_context(|| format!("export `{name}` didn't match target world"))?; + .with_context(|| format!("export `{name_str}` didn't match target world"))?; } Ok(()) } + fn map_name(&self, from_name: &WorldKey) -> WorldKey { + match from_name { + WorldKey::Name(s) => WorldKey::Name(s.clone()), + WorldKey::Interface(id) => { + WorldKey::Interface(self.interface_map.get(id).copied().unwrap_or(*id)) + } + } + } + fn match_world_item(&mut self, from: &WorldItem, into: &WorldItem) -> Result<()> { match (from, into) { (WorldItem::Interface(from), WorldItem::Interface(into)) => { diff --git a/crates/wit-parser/tests/all.rs b/crates/wit-parser/tests/all.rs index 8e41fc5b91..c1c1132c66 100644 --- a/crates/wit-parser/tests/all.rs +++ b/crates/wit-parser/tests/all.rs @@ -106,7 +106,7 @@ impl Runner<'_> { let result = if test.is_dir() { resolve.push_dir(test).map(|(id, _)| id) } else { - UnresolvedPackage::parse_file(test).and_then(|p| resolve.push(p, &Default::default())) + UnresolvedPackage::parse_file(test).and_then(|p| resolve.push(p)) }; let result = if test.iter().any(|s| s == "parse-fail") { diff --git a/crates/wit-parser/tests/ui/comments.wit b/crates/wit-parser/tests/ui/comments.wit index 9b38918e7f..f417093d6b 100644 --- a/crates/wit-parser/tests/ui/comments.wit +++ b/crates/wit-parser/tests/ui/comments.wit @@ -1,3 +1,5 @@ +package comments + // hello // world // why, yes diff --git a/crates/wit-parser/tests/ui/diamond1/deps/dep1/types.wit b/crates/wit-parser/tests/ui/diamond1/deps/dep1/types.wit new file mode 100644 index 0000000000..d17731b5c8 --- /dev/null +++ b/crates/wit-parser/tests/ui/diamond1/deps/dep1/types.wit @@ -0,0 +1,2 @@ +package dep1 +interface types {} diff --git a/crates/wit-parser/tests/ui/diamond1/deps/dep2/types.wit b/crates/wit-parser/tests/ui/diamond1/deps/dep2/types.wit new file mode 100644 index 0000000000..83d8742df7 --- /dev/null +++ b/crates/wit-parser/tests/ui/diamond1/deps/dep2/types.wit @@ -0,0 +1,2 @@ +package dep2 +interface types {} diff --git a/crates/wit-parser/tests/ui/diamond1/join.wit b/crates/wit-parser/tests/ui/diamond1/join.wit new file mode 100644 index 0000000000..f01bf1b94e --- /dev/null +++ b/crates/wit-parser/tests/ui/diamond1/join.wit @@ -0,0 +1,6 @@ +package foo + +world foo { + import dep1/types + import dep2/types +} diff --git a/crates/wit-parser/tests/ui/disambiguate-diamond/shared1.wit b/crates/wit-parser/tests/ui/disambiguate-diamond/shared1.wit index e65165ac2d..f655d9b009 100644 --- a/crates/wit-parser/tests/ui/disambiguate-diamond/shared1.wit +++ b/crates/wit-parser/tests/ui/disambiguate-diamond/shared1.wit @@ -1,3 +1,3 @@ -default interface shared { +interface shared1 { type the-type = u32 } diff --git a/crates/wit-parser/tests/ui/disambiguate-diamond/shared2.wit b/crates/wit-parser/tests/ui/disambiguate-diamond/shared2.wit index e65165ac2d..4e19192462 100644 --- a/crates/wit-parser/tests/ui/disambiguate-diamond/shared2.wit +++ b/crates/wit-parser/tests/ui/disambiguate-diamond/shared2.wit @@ -1,3 +1,3 @@ -default interface shared { +interface shared2 { type the-type = u32 } diff --git a/crates/wit-parser/tests/ui/disambiguate-diamond/world.wit b/crates/wit-parser/tests/ui/disambiguate-diamond/world.wit index 80ab9be490..df84b9e7f9 100644 --- a/crates/wit-parser/tests/ui/disambiguate-diamond/world.wit +++ b/crates/wit-parser/tests/ui/disambiguate-diamond/world.wit @@ -1,11 +1,13 @@ +package diamond + world foo { import foo: interface { - use pkg.shared1.{the-type} + use shared1.{the-type} } import bar: interface { - use pkg.shared2.{the-type} + use shared2.{the-type} } - import shared1: pkg.shared1 - import shared2: pkg.shared2 + import shared1 + import shared2 } diff --git a/crates/wit-parser/tests/ui/embedded.wit.md b/crates/wit-parser/tests/ui/embedded.wit.md index e9ea859192..69560b1bc8 100644 --- a/crates/wit-parser/tests/ui/embedded.wit.md +++ b/crates/wit-parser/tests/ui/embedded.wit.md @@ -3,6 +3,8 @@ containing stuff, and also some code blocks, wit and other. ```wit +package foo + interface foo { ``` diff --git a/crates/wit-parser/tests/ui/empty.wit b/crates/wit-parser/tests/ui/empty.wit index e69de29bb2..609cf0e0a0 100644 --- a/crates/wit-parser/tests/ui/empty.wit +++ b/crates/wit-parser/tests/ui/empty.wit @@ -0,0 +1 @@ +package empty diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/another-pkg/other-doc.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/another-pkg/other-doc.wit index 04933294d2..9c378400b6 100644 --- a/crates/wit-parser/tests/ui/foreign-deps/deps/another-pkg/other-doc.wit +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/another-pkg/other-doc.wit @@ -1 +1,3 @@ +package another-pkg + interface other-interface {} diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/corp/saas.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/corp/saas.wit index 5a2b10d0d0..540744814c 100644 --- a/crates/wit-parser/tests/ui/foreign-deps/deps/corp/saas.wit +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/corp/saas.wit @@ -1,2 +1,4 @@ -default interface saas { +package corp + +interface saas { } diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/different-pkg/the-doc.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/different-pkg/the-doc.wit index f192837fb6..7a880e48fd 100644 --- a/crates/wit-parser/tests/ui/foreign-deps/deps/different-pkg/the-doc.wit +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/different-pkg/the-doc.wit @@ -1 +1,2 @@ -default interface i {} +package different-pkg +interface i {} diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/foreign-pkg/the-doc.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/foreign-pkg/the-doc.wit index 1fb9bad8de..759068da13 100644 --- a/crates/wit-parser/tests/ui/foreign-deps/deps/foreign-pkg/the-doc.wit +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/foreign-pkg/the-doc.wit @@ -1,3 +1,5 @@ -default interface the-default { +package foreign-pkg + +interface the-default { type some-type = u32 } diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/some-pkg/some-doc.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/some-pkg/some-doc.wit index 8228c1d6f0..d277e2e53e 100644 --- a/crates/wit-parser/tests/ui/foreign-deps/deps/some-pkg/some-doc.wit +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/some-pkg/some-doc.wit @@ -1,4 +1,6 @@ -default interface the-default { +package some-pkg + +interface the-default { type from-default = string } diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/clocks.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/clocks.wit index 18a3575649..692eaa5358 100644 --- a/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/clocks.wit +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/clocks.wit @@ -1,3 +1,5 @@ -default interface wasi-clocks { +package wasi + +interface clocks { type timestamp = u64 } diff --git a/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/filesystem.wit b/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/filesystem.wit index b0a97a6cda..fc44e6ded6 100644 --- a/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/filesystem.wit +++ b/crates/wit-parser/tests/ui/foreign-deps/deps/wasi/filesystem.wit @@ -1,4 +1,6 @@ -default interface wasi-filesystem { +package wasi + +interface filesystem { record stat { ino: u64 } diff --git a/crates/wit-parser/tests/ui/foreign-deps/root.wit b/crates/wit-parser/tests/ui/foreign-deps/root.wit index d2325e855a..149e05ea2b 100644 --- a/crates/wit-parser/tests/ui/foreign-deps/root.wit +++ b/crates/wit-parser/tests/ui/foreign-deps/root.wit @@ -1,31 +1,44 @@ +package root + interface foo { - use wasi.clocks.{timestamp} - use wasi.filesystem.{stat} + use wasi/clocks.{timestamp} + use wasi/filesystem.{stat} } world my-world { - import wasi-fs: wasi.filesystem - import wasi-clocks: wasi.clocks + import wasi/filesystem + import wasi/clocks + + export corp/saas +} + +use wasi/filesystem as filesystem +use wasi/clocks as clocks - export saas: corp.saas +world my-world2 { + import filesystem + import clocks + export foo + export corp/saas } interface bar { - use some-pkg.some-doc.{from-default} - use some-pkg.some-doc.some-interface.{another-type} - use some-pkg.some-doc.some-interface.{} - use some-pkg.some-doc.another-interface.{yet-another-type} - use different-pkg.the-doc.{} + use filesystem.{} + use some-pkg/the-default.{from-default} + use some-pkg/some-interface.{another-type} + use some-pkg/some-interface.{} + use some-pkg/another-interface.{yet-another-type} + use different-pkg/i.{} } world bars-world { - import foo: some-pkg.some-doc - import bar: another-pkg.other-doc.other-interface + import some-pkg/the-default + import another-pkg/other-interface } interface use1 { - use foreign-pkg.the-doc.{some-type} + use foreign-pkg/the-default.{some-type} } interface use2 { - use foreign-pkg.the-doc.{some-type} + use foreign-pkg/the-default.{some-type} } diff --git a/crates/wit-parser/tests/ui/functions.wit b/crates/wit-parser/tests/ui/functions.wit index 4ff518ac7e..2e7a2b9cac 100644 --- a/crates/wit-parser/tests/ui/functions.wit +++ b/crates/wit-parser/tests/ui/functions.wit @@ -1,3 +1,5 @@ +package functions + interface functions { f1: func() f2: func(a: u32) diff --git a/crates/wit-parser/tests/ui/many-names/a.wit b/crates/wit-parser/tests/ui/many-names/a.wit new file mode 100644 index 0000000000..e3f9eab0a9 --- /dev/null +++ b/crates/wit-parser/tests/ui/many-names/a.wit @@ -0,0 +1,2 @@ +interface x {} +use x as name diff --git a/crates/wit-parser/tests/ui/many-names/b.wit b/crates/wit-parser/tests/ui/many-names/b.wit new file mode 100644 index 0000000000..44d622d6ca --- /dev/null +++ b/crates/wit-parser/tests/ui/many-names/b.wit @@ -0,0 +1,5 @@ +package name + +world name { + import name: interface {} +} diff --git a/crates/wit-parser/tests/ui/multi-file/bar.wit b/crates/wit-parser/tests/ui/multi-file/bar.wit index 9946d4ba33..0ec4050f94 100644 --- a/crates/wit-parser/tests/ui/multi-file/bar.wit +++ b/crates/wit-parser/tests/ui/multi-file/bar.wit @@ -1,9 +1,11 @@ -default interface irrelevant-name { +package multi-file + +interface irrelevant-name { record a-name {} } interface depends-on-later-item { - use self.depend-on-me.{x} + use depend-on-me.{x} } interface depend-on-me { @@ -11,8 +13,8 @@ interface depend-on-me { } world more-depends-on-later-things { - import foo: self.later-interface - export bar: self.later-interface + import later-interface + export later-interface } interface later-interface { diff --git a/crates/wit-parser/tests/ui/multi-file/cycle-a.wit b/crates/wit-parser/tests/ui/multi-file/cycle-a.wit new file mode 100644 index 0000000000..559ee39238 --- /dev/null +++ b/crates/wit-parser/tests/ui/multi-file/cycle-a.wit @@ -0,0 +1,7 @@ +interface cycle1 { + type t = u32 +} + +interface cycle3 { + use cycle2.{t} +} diff --git a/crates/wit-parser/tests/ui/multi-file/cycle-b.wit b/crates/wit-parser/tests/ui/multi-file/cycle-b.wit new file mode 100644 index 0000000000..85f2612962 --- /dev/null +++ b/crates/wit-parser/tests/ui/multi-file/cycle-b.wit @@ -0,0 +1,3 @@ +interface cycle2 { + use cycle1.{t} +} diff --git a/crates/wit-parser/tests/ui/multi-file/foo.wit b/crates/wit-parser/tests/ui/multi-file/foo.wit index cf9e621b29..9700ed252f 100644 --- a/crates/wit-parser/tests/ui/multi-file/foo.wit +++ b/crates/wit-parser/tests/ui/multi-file/foo.wit @@ -1,15 +1,31 @@ +package multi-file + interface foo { type x = u32 } -default interface something-else { +use foo as foo2 + +interface something-else { type y = u64 } +use depend-on-me as a-different-name + interface bar { - use self.foo.{x} - use pkg.foo.foo.{x as x2} - use pkg.foo.{y} - use self.something-else.{y as y2} - use pkg.bar.{a-name} + use foo.{x} + use foo.{x as x2} + use foo2.{x as x3} + use a-different-name.{x as x4} + use something-else.{y} + use something-else.{y as y2} + use irrelevant-name.{a-name} +} + +world the-world { + import a-different-name + + use a-different-name.{x} + + import foo: func() -> x } diff --git a/crates/wit-parser/tests/ui/package-syntax1.wit b/crates/wit-parser/tests/ui/package-syntax1.wit new file mode 100644 index 0000000000..f52652b1ba --- /dev/null +++ b/crates/wit-parser/tests/ui/package-syntax1.wit @@ -0,0 +1 @@ +package foo diff --git a/crates/wit-parser/tests/ui/package-syntax3.wit b/crates/wit-parser/tests/ui/package-syntax3.wit new file mode 100644 index 0000000000..4e7ea6c552 --- /dev/null +++ b/crates/wit-parser/tests/ui/package-syntax3.wit @@ -0,0 +1 @@ +package foo:bar diff --git a/crates/wit-parser/tests/ui/package-syntax4.wit b/crates/wit-parser/tests/ui/package-syntax4.wit new file mode 100644 index 0000000000..6af2988166 --- /dev/null +++ b/crates/wit-parser/tests/ui/package-syntax4.wit @@ -0,0 +1 @@ +package foo:bar@2.0 diff --git a/crates/wit-parser/tests/ui/parse-fail/alias-no-type.wit.result b/crates/wit-parser/tests/ui/parse-fail/alias-no-type.wit.result index 6b9c20d947..d25b316c26 100644 --- a/crates/wit-parser/tests/ui/parse-fail/alias-no-type.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/alias-no-type.wit.result @@ -1,5 +1 @@ -type `bar` does not exist - --> tests/ui/parse-fail/alias-no-type.wit:3:14 - | - 3 | type foo = bar - | ^-- \ No newline at end of file +no `package` header was found in any WIT file for this package \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-diamond.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-diamond.wit.result deleted file mode 100644 index 71c657210b..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/bad-diamond.wit.result +++ /dev/null @@ -1,8 +0,0 @@ -import of `shared` - .. which is depended on by import `b` -conflicts with a previous interface using the name `shared` - - --> tests/ui/parse-fail/bad-diamond/join.wit:3:10 - | - 3 | import b: pkg.b - | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-diamond/a.wit b/crates/wit-parser/tests/ui/parse-fail/bad-diamond/a.wit deleted file mode 100644 index 0c33f97761..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/bad-diamond/a.wit +++ /dev/null @@ -1,9 +0,0 @@ -interface shared { - type foo = u32 -} - -default interface a { - use self.shared.{foo} - - a: func() -> foo -} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-diamond/b.wit b/crates/wit-parser/tests/ui/parse-fail/bad-diamond/b.wit deleted file mode 100644 index 3aeda1af16..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/bad-diamond/b.wit +++ /dev/null @@ -1,9 +0,0 @@ -interface shared { - type foo = u32 -} - -default interface b { - use self.shared.{foo} - - a: func() -> foo -} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-diamond/join.wit b/crates/wit-parser/tests/ui/parse-fail/bad-diamond/join.wit deleted file mode 100644 index 289cf6df5a..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/bad-diamond/join.wit +++ /dev/null @@ -1,4 +0,0 @@ -world foo { - import a: pkg.a - import b: pkg.b -} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-function.wit b/crates/wit-parser/tests/ui/parse-fail/bad-function.wit index 202abb5a72..8a8db3e3d2 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-function.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-function.wit @@ -1,5 +1,7 @@ // parse-fail +package foo + interface foo { x: func(param: nonexistent) } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-function.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-function.wit.result index a5c199de70..79120745a7 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-function.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-function.wit.result @@ -1,5 +1,5 @@ name `nonexistent` is not defined - --> tests/ui/parse-fail/bad-function.wit:4:18 + --> tests/ui/parse-fail/bad-function.wit:6:18 | - 4 | x: func(param: nonexistent) + 6 | x: func(param: nonexistent) | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit b/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit index c80e3e670f..a9de2b8c8b 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit @@ -1,5 +1,7 @@ // parse-fail +package foo + interface foo { x: func() -> nonexistent } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit.result index e2ea68da10..910a88f41d 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-function2.wit.result @@ -1,5 +1,5 @@ name `nonexistent` is not defined - --> tests/ui/parse-fail/bad-function2.wit:4:16 + --> tests/ui/parse-fail/bad-function2.wit:6:16 | - 4 | x: func() -> nonexistent + 6 | x: func() -> nonexistent | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result index b55b5e3631..1de1141275 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result @@ -1,5 +1,8 @@ -dependency on `nonexistent` doesn't exist at: tests/ui/parse-fail/bad-pkg1/deps/nonexistent - --> tests/ui/parse-fail/bad-pkg1/root.wit:2:7 - | - 2 | use nonexistent.foo.{} - | ^---------- \ No newline at end of file +failed to parse package: tests/ui/parse-fail/bad-pkg1 + +Caused by: + interface not found in package + --> tests/ui/parse-fail/bad-pkg1/root.wit:4:7 + | + 4 | use nonexistent.{} + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg1/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg1/root.wit index 7b0d8a0ff8..586d7365e8 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg1/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg1/root.wit @@ -1,3 +1,5 @@ +package foo + interface foo { - use nonexistent.foo.{} + use nonexistent.{} } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result index 9cd96bd756..404cfae421 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result @@ -1,5 +1,5 @@ -package `bar` does not define document `nonexistent` - --> tests/ui/parse-fail/bad-pkg2/root.wit:2:11 +interface not found in package + --> tests/ui/parse-fail/bad-pkg2/root.wit:4:11 | - 2 | use bar.nonexistent.{} + 4 | use bar/nonexistent.{} | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/deps/bar/empty.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/deps/bar/empty.wit new file mode 100644 index 0000000000..ddac0faf27 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/deps/bar/empty.wit @@ -0,0 +1 @@ +package bar diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/root.wit index eee9664002..c7cc0b1192 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/root.wit @@ -1,3 +1,5 @@ +package foo + interface foo { - use bar.nonexistent.{} + use bar/nonexistent.{} } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result index 432a7dffeb..e87b234787 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result @@ -1,5 +1,5 @@ -default interface not specified in document - --> tests/ui/parse-fail/bad-pkg3/root.wit:2:11 +interface not found in package + --> tests/ui/parse-fail/bad-pkg3/root.wit:4:11 | - 2 | use bar.baz.{} + 4 | use bar/baz.{} | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/deps/bar/baz.wit index e69de29bb2..64d6c1ec1c 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/deps/bar/baz.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/deps/bar/baz.wit @@ -0,0 +1,2 @@ +package bar +world baz {} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/root.wit index 5bc31123f5..842e2099a1 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3/root.wit @@ -1,3 +1,5 @@ +package foo + interface foo { - use bar.baz.{} + use bar/baz.{} } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result index cdf2fba8c3..6e2aeded76 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result @@ -1,5 +1,5 @@ type not defined in interface - --> tests/ui/parse-fail/bad-pkg4/root.wit:2:16 + --> tests/ui/parse-fail/bad-pkg4/root.wit:3:16 | - 2 | use bar.baz.{a-name} + 3 | use bar/baz.{a-name} | ^----- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/deps/bar/baz.wit index baa2185796..999f38dd6e 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/deps/bar/baz.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/deps/bar/baz.wit @@ -1,3 +1,4 @@ -default interface irrelevant-name { +package bar +interface baz { a-name: func() } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/root.wit index f1af5052ee..1294a32160 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4/root.wit @@ -1,3 +1,4 @@ +package foo interface foo { - use bar.baz.{a-name} + use bar/baz.{a-name} } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result index da07d92785..cd1117f801 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result @@ -1,5 +1,5 @@ type not defined in interface - --> tests/ui/parse-fail/bad-pkg5/root.wit:2:16 + --> tests/ui/parse-fail/bad-pkg5/root.wit:3:16 | - 2 | use bar.baz.{nonexistent} + 3 | use bar/baz.{nonexistent} | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/deps/bar/baz.wit index 65ffc3ac20..ecda89d101 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/deps/bar/baz.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/deps/bar/baz.wit @@ -1,2 +1,3 @@ -default interface irrelevant-name { +package bar +interface baz { } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/root.wit index 0f19c0cce9..e5c37d8c78 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5/root.wit @@ -1,3 +1,4 @@ +package foo interface foo { - use bar.baz.{nonexistent} + use bar/baz.{nonexistent} } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result index 91c24db610..7d3fe48d52 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result @@ -1,5 +1,5 @@ -interface not defined in document - --> tests/ui/parse-fail/bad-pkg6/root.wit:2:15 +failed to find package in `deps` directory + --> tests/ui/parse-fail/bad-pkg6/root.wit:3:7 | - 2 | use bar.baz.nonexistent.{} - | ^---------- \ No newline at end of file + 3 | use bar/baz.{} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/deps/bar/baz.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/deps/bar/baz.wit index e69de29bb2..9d17ecc877 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/deps/bar/baz.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/deps/bar/baz.wit @@ -0,0 +1,4 @@ +package baz + +interface bar {} + diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/root.wit b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/root.wit index 7c244a4d42..93f5c86229 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6/root.wit @@ -1,3 +1,4 @@ +package foo interface foo { - use bar.baz.nonexistent.{} + use bar/baz.{} } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit b/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit index 0fbd79fd2e..ed3b231dbc 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit @@ -1,3 +1,4 @@ +package foo world a { type a = u32 import a: func() diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit.result index 3c993d17c0..2b32378d5d 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-world-type1.wit.result @@ -1,5 +1,5 @@ import `a` conflicts with prior import of same name - --> tests/ui/parse-fail/bad-world-type1.wit:3:10 + --> tests/ui/parse-fail/bad-world-type1.wit:4:10 | - 3 | import a: func() + 4 | import a: func() | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-world-type2.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-world-type2.wit.result deleted file mode 100644 index 054382328f..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/bad-world-type2.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -import of function `foo` shadows previously imported interface - --> tests/ui/parse-fail/bad-world-type2.wit:8:10 - | - 8 | import foo: func() - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/conflicting-package.wit.result b/crates/wit-parser/tests/ui/parse-fail/conflicting-package.wit.result new file mode 100644 index 0000000000..cbb0a4f89f --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/conflicting-package.wit.result @@ -0,0 +1,8 @@ +failed to parse package: tests/ui/parse-fail/conflicting-package + +Caused by: + package identifier does not match previous + --> tests/ui/parse-fail/conflicting-package/b.wit:1:9 + | + 1 | package b + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/conflicting-package/a.wit b/crates/wit-parser/tests/ui/parse-fail/conflicting-package/a.wit new file mode 100644 index 0000000000..2a93cdef54 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/conflicting-package/a.wit @@ -0,0 +1 @@ +package a diff --git a/crates/wit-parser/tests/ui/parse-fail/conflicting-package/b.wit b/crates/wit-parser/tests/ui/parse-fail/conflicting-package/b.wit new file mode 100644 index 0000000000..e0836a8839 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/conflicting-package/b.wit @@ -0,0 +1 @@ +package b diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle.wit b/crates/wit-parser/tests/ui/parse-fail/cycle.wit index 707477b7e2..d5df2d813c 100644 --- a/crates/wit-parser/tests/ui/parse-fail/cycle.wit +++ b/crates/wit-parser/tests/ui/parse-fail/cycle.wit @@ -1,4 +1,5 @@ // parse-fail +package foo interface foo { type foo = foo diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle.wit.result b/crates/wit-parser/tests/ui/parse-fail/cycle.wit.result index fbb1a6457a..3639b3c217 100644 --- a/crates/wit-parser/tests/ui/parse-fail/cycle.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/cycle.wit.result @@ -1,5 +1,5 @@ type `foo` depends on itself - --> tests/ui/parse-fail/cycle.wit:4:14 + --> tests/ui/parse-fail/cycle.wit:5:14 | - 4 | type foo = foo + 5 | type foo = foo | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle2.wit b/crates/wit-parser/tests/ui/parse-fail/cycle2.wit index 28e6b6aa1a..a9bb01d7ca 100644 --- a/crates/wit-parser/tests/ui/parse-fail/cycle2.wit +++ b/crates/wit-parser/tests/ui/parse-fail/cycle2.wit @@ -1,4 +1,5 @@ // parse-fail +package foo interface foo { type foo = bar diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle2.wit.result b/crates/wit-parser/tests/ui/parse-fail/cycle2.wit.result index 946175ab6b..2e4a52900e 100644 --- a/crates/wit-parser/tests/ui/parse-fail/cycle2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/cycle2.wit.result @@ -1,5 +1,5 @@ type `bar` depends on itself - --> tests/ui/parse-fail/cycle2.wit:4:14 + --> tests/ui/parse-fail/cycle2.wit:5:14 | - 4 | type foo = bar + 5 | type foo = bar | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle3.wit b/crates/wit-parser/tests/ui/parse-fail/cycle3.wit index 8bcc56666d..507eabf5c9 100644 --- a/crates/wit-parser/tests/ui/parse-fail/cycle3.wit +++ b/crates/wit-parser/tests/ui/parse-fail/cycle3.wit @@ -1,4 +1,5 @@ // parse-fail +package foo interface foo { type foo = bar diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle3.wit.result b/crates/wit-parser/tests/ui/parse-fail/cycle3.wit.result index facc6386e7..ffdfec0aa2 100644 --- a/crates/wit-parser/tests/ui/parse-fail/cycle3.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/cycle3.wit.result @@ -1,5 +1,5 @@ type `bar` depends on itself - --> tests/ui/parse-fail/cycle3.wit:4:14 + --> tests/ui/parse-fail/cycle3.wit:5:14 | - 4 | type foo = bar + 5 | type foo = bar | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle4.wit b/crates/wit-parser/tests/ui/parse-fail/cycle4.wit index 39c6d4bfcf..3fb3649f4c 100644 --- a/crates/wit-parser/tests/ui/parse-fail/cycle4.wit +++ b/crates/wit-parser/tests/ui/parse-fail/cycle4.wit @@ -1,4 +1,5 @@ // parse-fail +package foo interface foo { type foo = bar diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle4.wit.result b/crates/wit-parser/tests/ui/parse-fail/cycle4.wit.result index 45e9c17a0f..67325b779f 100644 --- a/crates/wit-parser/tests/ui/parse-fail/cycle4.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/cycle4.wit.result @@ -1,5 +1,5 @@ type `bar` depends on itself - --> tests/ui/parse-fail/cycle4.wit:4:14 + --> tests/ui/parse-fail/cycle4.wit:5:14 | - 4 | type foo = bar + 5 | type foo = bar | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle5.wit b/crates/wit-parser/tests/ui/parse-fail/cycle5.wit index 3c26d9b249..d3527d4ab3 100644 --- a/crates/wit-parser/tests/ui/parse-fail/cycle5.wit +++ b/crates/wit-parser/tests/ui/parse-fail/cycle5.wit @@ -1,4 +1,5 @@ // parse-fail +package foo interface foo { type foo = bar diff --git a/crates/wit-parser/tests/ui/parse-fail/cycle5.wit.result b/crates/wit-parser/tests/ui/parse-fail/cycle5.wit.result index 0fd4f5c82b..22064dac1e 100644 --- a/crates/wit-parser/tests/ui/parse-fail/cycle5.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/cycle5.wit.result @@ -1,5 +1,5 @@ type `bar` depends on itself - --> tests/ui/parse-fail/cycle5.wit:4:14 + --> tests/ui/parse-fail/cycle5.wit:5:14 | - 4 | type foo = bar + 5 | type foo = bar | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/default-interface1.wit b/crates/wit-parser/tests/ui/parse-fail/default-interface1.wit deleted file mode 100644 index c6c4238802..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/default-interface1.wit +++ /dev/null @@ -1,3 +0,0 @@ -// parse-fail -default interface foo {} -default interface bar {} diff --git a/crates/wit-parser/tests/ui/parse-fail/default-interface1.wit.result b/crates/wit-parser/tests/ui/parse-fail/default-interface1.wit.result deleted file mode 100644 index a98ae7d335..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/default-interface1.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -cannot specify more than one `default` interface - --> tests/ui/parse-fail/default-interface1.wit:3:19 - | - 3 | default interface bar {} - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/default-world1.wit b/crates/wit-parser/tests/ui/parse-fail/default-world1.wit deleted file mode 100644 index df2d36e299..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/default-world1.wit +++ /dev/null @@ -1,3 +0,0 @@ -// parse-fail -default world foo {} -default world bar {} diff --git a/crates/wit-parser/tests/ui/parse-fail/default-world1.wit.result b/crates/wit-parser/tests/ui/parse-fail/default-world1.wit.result deleted file mode 100644 index e46b2538f2..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/default-world1.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -cannot specify more than one `default` world - --> tests/ui/parse-fail/default-world1.wit:3:15 - | - 3 | default world bar {} - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit index 6b63355eb9..25258525d3 100644 --- a/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit @@ -1,5 +1,7 @@ // parse-fail +package foo + interface foo { foo: func() foo: func() diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit.result index c0ab243fa6..30ec5002b4 100644 --- a/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-functions.wit.result @@ -1,5 +1,5 @@ name `foo` is defined more than once - --> tests/ui/parse-fail/duplicate-functions.wit:5:3 + --> tests/ui/parse-fail/duplicate-functions.wit:7:3 | - 5 | foo: func() + 7 | foo: func() | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit index c58d11fa01..b8e5f1c74b 100644 --- a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit @@ -1,4 +1,6 @@ // parse-fail +package foo + interface foo {} interface foo {} diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit.result index 293005fe64..f6351f30e1 100644 --- a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface.wit.result @@ -1,5 +1,5 @@ -name `foo` previously defined in document - --> tests/ui/parse-fail/duplicate-interface.wit:4:11 +duplicate item named `foo` + --> tests/ui/parse-fail/duplicate-interface.wit:6:11 | - 4 | interface foo {} + 6 | interface foo {} | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2.wit.result new file mode 100644 index 0000000000..7ed7ec2b29 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2.wit.result @@ -0,0 +1,8 @@ +failed to parse package: tests/ui/parse-fail/duplicate-interface2 + +Caused by: + duplicate item named `foo` + --> tests/ui/parse-fail/duplicate-interface2/foo2.wit:3:11 + | + 3 | interface foo {} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo.wit new file mode 100644 index 0000000000..82d7b8f14e --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo.wit @@ -0,0 +1,3 @@ +package foo + +interface foo {} diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo2.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo2.wit new file mode 100644 index 0000000000..82d7b8f14e --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2/foo2.wit @@ -0,0 +1,3 @@ +package foo + +interface foo {} diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit index 7b23f438b1..75e1515be6 100644 --- a/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit @@ -1,4 +1,5 @@ // parse-fail +package foo interface foo { type foo = s32 diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit.result index 9efd0d2c4f..09187e9f52 100644 --- a/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-type.wit.result @@ -1,5 +1,5 @@ name `foo` is defined more than once - --> tests/ui/parse-fail/duplicate-type.wit:5:8 + --> tests/ui/parse-fail/duplicate-type.wit:6:8 | - 5 | type foo = s32 + 6 | type foo = s32 | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit b/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit index abf7c1197f..72308fa4a1 100644 --- a/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit +++ b/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit @@ -1,4 +1,5 @@ // parse-fail +package foo interface foo { enum t {} diff --git a/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit.result b/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit.result index 9347fca423..894a82a00d 100644 --- a/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/empty-enum.wit.result @@ -1,5 +1,5 @@ empty enum - --> tests/ui/parse-fail/empty-enum.wit:4:8 + --> tests/ui/parse-fail/empty-enum.wit:5:8 | - 4 | enum t {} + 5 | enum t {} | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/empty-union.wit b/crates/wit-parser/tests/ui/parse-fail/empty-union.wit index 84e8f9ecec..8557d50776 100644 --- a/crates/wit-parser/tests/ui/parse-fail/empty-union.wit +++ b/crates/wit-parser/tests/ui/parse-fail/empty-union.wit @@ -1,4 +1,5 @@ // parse-fail +package foo interface foo { union t {} diff --git a/crates/wit-parser/tests/ui/parse-fail/empty-union.wit.result b/crates/wit-parser/tests/ui/parse-fail/empty-union.wit.result index af11fb72c4..14189756bb 100644 --- a/crates/wit-parser/tests/ui/parse-fail/empty-union.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/empty-union.wit.result @@ -1,5 +1,5 @@ empty union - --> tests/ui/parse-fail/empty-union.wit:4:9 + --> tests/ui/parse-fail/empty-union.wit:5:9 | - 4 | union t {} + 5 | union t {} | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit b/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit index 8081a45ad2..3a1150833d 100644 --- a/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit +++ b/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit @@ -1,4 +1,5 @@ // parse-fail +package foo interface foo { variant t {} diff --git a/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit.result b/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit.result index 68bdc00808..9c42ba4c0f 100644 --- a/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/empty-variant1.wit.result @@ -1,5 +1,5 @@ empty variant - --> tests/ui/parse-fail/empty-variant1.wit:4:11 + --> tests/ui/parse-fail/empty-variant1.wit:5:11 | - 4 | variant t {} + 5 | variant t {} | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/export-twice.wit b/crates/wit-parser/tests/ui/parse-fail/export-twice.wit new file mode 100644 index 0000000000..eeee976fe3 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/export-twice.wit @@ -0,0 +1,8 @@ +package foo + +interface foo {} + +world bar { + export foo + export foo +} diff --git a/crates/wit-parser/tests/ui/parse-fail/export-twice.wit.result b/crates/wit-parser/tests/ui/parse-fail/export-twice.wit.result new file mode 100644 index 0000000000..d796998a16 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/export-twice.wit.result @@ -0,0 +1,5 @@ +interface cannot be exported more than once + --> tests/ui/parse-fail/export-twice.wit:7:10 + | + 7 | export foo + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit index 4e865f9033..601d4ad21a 100644 --- a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit +++ b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit @@ -1,3 +1,4 @@ +package foo world foo { import a: func() export a: func() diff --git a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit.result index 838baa6ee3..27caf399c3 100644 --- a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap1.wit.result @@ -1,5 +1,5 @@ export `a` conflicts with prior import of same name - --> tests/ui/parse-fail/import-export-overlap1.wit:3:10 + --> tests/ui/parse-fail/import-export-overlap1.wit:4:10 | - 3 | export a: func() + 4 | export a: func() | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit index 1680efebb2..f38d72a2d2 100644 --- a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit +++ b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit @@ -1,3 +1,4 @@ +package foo world foo { import a: func() export a: interface {} diff --git a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit.result index af16080e10..88ca1c1997 100644 --- a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap2.wit.result @@ -1,5 +1,5 @@ export `a` conflicts with prior import of same name - --> tests/ui/parse-fail/import-export-overlap2.wit:3:10 + --> tests/ui/parse-fail/import-export-overlap2.wit:4:10 | - 3 | export a: interface {} + 4 | export a: interface {} | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap3.wit b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap3.wit deleted file mode 100644 index 183e991594..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap3.wit +++ /dev/null @@ -1,11 +0,0 @@ -interface a { - type t = u32 -} - -world foo { - import b: interface { - use self.a.{t} - } - export a: interface {} -} - diff --git a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap3.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-export-overlap3.wit.result deleted file mode 100644 index 677d5a9640..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/import-export-overlap3.wit.result +++ /dev/null @@ -1,6 +0,0 @@ -export of `a` conflicts with a previous interface using the name `a` - - --> tests/ui/parse-fail/import-export-overlap3.wit:9:10 - | - 9 | export a: interface {} - | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-twice.wit b/crates/wit-parser/tests/ui/parse-fail/import-twice.wit new file mode 100644 index 0000000000..6d50bc5dfd --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-twice.wit @@ -0,0 +1,8 @@ +package foo + +interface foo {} + +world bar { + import foo + import foo +} diff --git a/crates/wit-parser/tests/ui/parse-fail/import-twice.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-twice.wit.result new file mode 100644 index 0000000000..7dfe127a4a --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/import-twice.wit.result @@ -0,0 +1,5 @@ +interface cannot be imported more than once + --> tests/ui/parse-fail/import-twice.wit:7:10 + | + 7 | import foo + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-md.wit.result b/crates/wit-parser/tests/ui/parse-fail/invalid-md.wit.result index 6a5becd6b6..8980f6d466 100644 --- a/crates/wit-parser/tests/ui/parse-fail/invalid-md.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-md.wit.result @@ -1,4 +1,4 @@ -expected `default`, `world` or `interface`, found keyword `type` +expected `world` or `interface`, found keyword `type` --> tests/ui/parse-fail/invalid-md.md:6:1 | 6 | type foo = bar diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit index da9286726d..8ab2408e28 100644 --- a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit @@ -1,3 +1,5 @@ +package foo + interface foo { x: func() diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit.result b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit.result index 1c872a1c05..d7861f14f4 100644 --- a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference.wit.result @@ -1,5 +1,5 @@ type `x` does not exist - --> tests/ui/parse-fail/invalid-type-reference.wit:6:8 + --> tests/ui/parse-fail/invalid-type-reference.wit:8:8 | - 6 | a: x + 8 | a: x | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit index c2f7393c61..8df71e6974 100644 --- a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit @@ -1,3 +1,5 @@ +package foo + interface foo { x: func() y: func() -> x diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit.result b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit.result index 6637a36a23..f3899ab548 100644 --- a/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/invalid-type-reference2.wit.result @@ -1,5 +1,5 @@ cannot use function `x` as a type - --> tests/ui/parse-fail/invalid-type-reference2.wit:3:16 + --> tests/ui/parse-fail/invalid-type-reference2.wit:5:16 | - 3 | y: func() -> x + 5 | y: func() -> x | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid@filename.wit b/crates/wit-parser/tests/ui/parse-fail/invalid@filename.wit deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/wit-parser/tests/ui/parse-fail/invalid@filename.wit.result b/crates/wit-parser/tests/ui/parse-fail/invalid@filename.wit.result deleted file mode 100644 index 461cca9d53..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/invalid@filename.wit.result +++ /dev/null @@ -1,4 +0,0 @@ -failed to start resolving path: tests/ui/parse-fail/invalid@filename.wit - -Caused by: - name of document isn't a valid WIT identifier `invalid@filename`: invalid character in identifier '@' \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2/deps/bar/.gitkeep b/crates/wit-parser/tests/ui/parse-fail/missing-package.wit similarity index 100% rename from crates/wit-parser/tests/ui/parse-fail/bad-pkg2/deps/bar/.gitkeep rename to crates/wit-parser/tests/ui/parse-fail/missing-package.wit diff --git a/crates/wit-parser/tests/ui/parse-fail/missing-package.wit.result b/crates/wit-parser/tests/ui/parse-fail/missing-package.wit.result new file mode 100644 index 0000000000..d25b316c26 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/missing-package.wit.result @@ -0,0 +1 @@ +no `package` header was found in any WIT file for this package \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use.wit.result b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use.wit.result new file mode 100644 index 0000000000..fceaa94013 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use.wit.result @@ -0,0 +1,8 @@ +failed to parse package: tests/ui/parse-fail/no-access-to-sibling-use + +Caused by: + interface does not exist + --> tests/ui/parse-fail/no-access-to-sibling-use/foo.wit:3:5 + | + 3 | use bar-renamed + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/bar.wit b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/bar.wit new file mode 100644 index 0000000000..a08b230595 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/bar.wit @@ -0,0 +1 @@ +use bar as bar-renamed diff --git a/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/foo.wit b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/foo.wit new file mode 100644 index 0000000000..2e157e2276 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use/foo.wit @@ -0,0 +1,5 @@ +package foo + +use bar-renamed + +interface bar {} diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result index d7fbbe1104..aa6be74b0d 100644 --- a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result @@ -1,5 +1,5 @@ package depends on itself - --> tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit:2:7 + --> tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit:3:7 | - 2 | use a1.foo.{} + 3 | use a1/foo.{} | ^- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit index 9a23dbfd35..62176c2327 100644 --- a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit @@ -1,3 +1,4 @@ +package a1 interface foo { - use a1.foo.{} + use a1/foo.{} } diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/root.wit b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/root.wit index 9a23dbfd35..ea5cc46446 100644 --- a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle/root.wit @@ -1,3 +1,4 @@ +package foo interface foo { - use a1.foo.{} + use a1/foo.{} } diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result index b7ccf5a080..e579e3abce 100644 --- a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result @@ -1,5 +1,5 @@ package depends on itself - --> tests/ui/parse-fail/pkg-cycle2/deps/a2/root.wit:2:7 + --> tests/ui/parse-fail/pkg-cycle2/deps/a2/root.wit:3:7 | - 2 | use a1.foo.{} + 3 | use a1/foo.{} | ^- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a1/root.wit b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a1/root.wit index 9e8ae2bbfd..7adcc28754 100644 --- a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a1/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a1/root.wit @@ -1,3 +1,4 @@ +package a1 interface foo { - use a2.foo.{} + use a2/foo.{} } diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a2/root.wit b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a2/root.wit index 9a23dbfd35..db8aebe9ab 100644 --- a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a2/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/deps/a2/root.wit @@ -1,3 +1,4 @@ +package a2 interface foo { - use a1.foo.{} + use a1/foo.{} } diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/root.wit b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/root.wit index 9a23dbfd35..045c752c68 100644 --- a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/root.wit +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2/root.wit @@ -1,3 +1,4 @@ +package root interface foo { - use a1.foo.{} + use a1/foo.{} } diff --git a/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit b/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit index 7467f94de6..6e7e1b2961 100644 --- a/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit +++ b/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit @@ -1,4 +1,5 @@ // parse-fail +package foo interface foo { type foo = bar diff --git a/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit.result b/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit.result index aba06b4bc2..162404ae7c 100644 --- a/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/undefined-typed.wit.result @@ -1,5 +1,5 @@ type `bar` does not exist - --> tests/ui/parse-fail/undefined-typed.wit:4:14 + --> tests/ui/parse-fail/undefined-typed.wit:5:14 | - 4 | type foo = bar + 5 | type foo = bar | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit b/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit index 8fe521bfb5..63e07622a7 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit @@ -1,5 +1,7 @@ // parse-fail +package foo + world foo { - import bar: self.bar + import bar } diff --git a/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit.result b/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit.result index 143852253c..c71a004c0b 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unknown-interface.wit.result @@ -1,5 +1,5 @@ interface does not exist - --> tests/ui/parse-fail/unknown-interface.wit:4:20 + --> tests/ui/parse-fail/unknown-interface.wit:6:10 | - 4 | import bar: self.bar - | ^-- \ No newline at end of file + 6 | import bar + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit index cc1b6ae35f..ef3880caee 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit @@ -1,5 +1,7 @@ // parse-fail +package foo + world foo { - import foo: self.foo + import foo } diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit.result index dc6cea3c5d..13bfe93286 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface1.wit.result @@ -1,5 +1,5 @@ name `foo` is defined as a world, not an interface - --> tests/ui/parse-fail/unresolved-interface1.wit:4:20 + --> tests/ui/parse-fail/unresolved-interface1.wit:6:10 | - 4 | import foo: self.foo - | ^-- \ No newline at end of file + 6 | import foo + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit index 8a67d92f00..f65b8e6df8 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit @@ -1,6 +1,8 @@ // parse-fail +package foo + world foo { - import foo: self.bar + import bar } diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit.result index f230df6eb8..f7ab5118b1 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface2.wit.result @@ -1,5 +1,5 @@ interface does not exist - --> tests/ui/parse-fail/unresolved-interface2.wit:4:20 + --> tests/ui/parse-fail/unresolved-interface2.wit:6:10 | - 4 | import foo: self.bar - | ^-- \ No newline at end of file + 6 | import bar + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit index 61683dde44..af254a69f2 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit @@ -1,5 +1,5 @@ // parse-fail -world foo { - import foo: pkg.foo.bar -} +package foo + +use bar as foo diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit.result index b7c4ba676c..00f2066917 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface3.wit.result @@ -1,5 +1,5 @@ -document `foo` does not exist - --> tests/ui/parse-fail/unresolved-interface3.wit:4:19 +interface does not exist + --> tests/ui/parse-fail/unresolved-interface3.wit:5:5 | - 4 | import foo: pkg.foo.bar - | ^-- \ No newline at end of file + 5 | use bar as foo + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit index 29817a23be..5574bdc8db 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit @@ -1,5 +1,7 @@ // parse-fail +package foo + world foo { - import foo: pkg.unresolved-interface4 + import some:dependency/iface } diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit.result index e3f55f5ba0..3e772ae61a 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface4.wit.result @@ -1,5 +1,5 @@ -document does not specify a default interface - --> tests/ui/parse-fail/unresolved-interface4.wit:4:19 +package not found + --> tests/ui/parse-fail/unresolved-interface4.wit:6:10 | - 4 | import foo: pkg.unresolved-interface4 - | ^-------------------- \ No newline at end of file + 6 | import some:dependency/iface + | ^-------------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface5.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface5.wit deleted file mode 100644 index fa943c2a59..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface5.wit +++ /dev/null @@ -1,5 +0,0 @@ -// parse-fail - -world foo { - import foo: pkg.unresolved-interface5.bar -} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface5.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-interface5.wit.result deleted file mode 100644 index fc5a01ae26..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-interface5.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -interface does not exist - --> tests/ui/parse-fail/unresolved-interface5.wit:4:41 - | - 4 | import foo: pkg.unresolved-interface5.bar - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit index f4b7dd5bef..b81acd1330 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit @@ -1,5 +1,7 @@ // parse-fail +package foo + interface foo { - use self.bar.{x} + use bar.{x} } diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit.result index 33708bc6c9..52c568a317 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use1.wit.result @@ -1,5 +1,5 @@ -interface `bar` does not exist - --> tests/ui/parse-fail/unresolved-use1.wit:4:12 +interface not found in package + --> tests/ui/parse-fail/unresolved-use1.wit:6:7 | - 4 | use self.bar.{x} - | ^-- \ No newline at end of file + 6 | use bar.{x} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result index bb1504e286..df68a38728 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result @@ -1,8 +1,8 @@ failed to parse package: tests/ui/parse-fail/unresolved-use10 Caused by: - document does not specify a default interface - --> tests/ui/parse-fail/unresolved-use10/bar.wit:2:11 + name `thing` is not defined + --> tests/ui/parse-fail/unresolved-use10/bar.wit:4:12 | - 2 | use pkg.foo.{thing} - | ^-- \ No newline at end of file + 4 | use foo.{thing} + | ^---- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use10/bar.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10/bar.wit index 82806f689e..25c624d903 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use10/bar.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10/bar.wit @@ -1,3 +1,5 @@ +package foo + interface bar { - use pkg.foo.{thing} + use foo.{thing} } diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use11.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use11.wit.result deleted file mode 100644 index afdbcf6f66..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use11.wit.result +++ /dev/null @@ -1,8 +0,0 @@ -failed to parse package: tests/ui/parse-fail/unresolved-use11 - -Caused by: - name `thing` is not defined - --> tests/ui/parse-fail/unresolved-use11/bar.wit:2:16 - | - 2 | use pkg.foo.{thing} - | ^---- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use11/bar.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use11/bar.wit deleted file mode 100644 index 82806f689e..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use11/bar.wit +++ /dev/null @@ -1,3 +0,0 @@ -interface bar { - use pkg.foo.{thing} -} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use11/foo.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use11/foo.wit deleted file mode 100644 index 3e6a7e9ced..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use11/foo.wit +++ /dev/null @@ -1,2 +0,0 @@ -default interface foo { -} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit index 402c72b61c..d393838a99 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit @@ -1,7 +1,9 @@ // parse-fail +package foo + interface foo { - use self.bar.{x} + use bar.{x} } interface bar { diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit.result index 3a43a8feb3..f44ca7cf2e 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use2.wit.result @@ -1,5 +1,5 @@ name `x` is not defined - --> tests/ui/parse-fail/unresolved-use2.wit:4:17 + --> tests/ui/parse-fail/unresolved-use2.wit:6:12 | - 4 | use self.bar.{x} - | ^ \ No newline at end of file + 6 | use bar.{x} + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit index 6b34d6cac4..ca3ecf4ff1 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit @@ -1,7 +1,9 @@ // parse-fail +package foo + interface foo { - use self.bar.{x} + use bar.{x} } interface bar { diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit.result index 3d82f08104..9f29adbd34 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use3.wit.result @@ -1,5 +1,5 @@ cannot import function `x` - --> tests/ui/parse-fail/unresolved-use3.wit:4:17 + --> tests/ui/parse-fail/unresolved-use3.wit:6:12 | - 4 | use self.bar.{x} - | ^ \ No newline at end of file + 6 | use bar.{x} + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use4.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use4.wit deleted file mode 100644 index a82a94b450..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use4.wit +++ /dev/null @@ -1,5 +0,0 @@ -// parse-fail - -interface foo { - use pkg.something-that-does-not-exist.{x} -} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use4.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use4.wit.result deleted file mode 100644 index 43bffddede..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use4.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -document `something-that-does-not-exist` does not exist - --> tests/ui/parse-fail/unresolved-use4.wit:4:11 - | - 4 | use pkg.something-that-does-not-exist.{x} - | ^---------------------------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use5.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use5.wit deleted file mode 100644 index f349f39f0d..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use5.wit +++ /dev/null @@ -1,6 +0,0 @@ -// parse-fail - -interface foo { - use pkg.unresolved-use5.{x} -} - diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use5.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use5.wit.result deleted file mode 100644 index e361c989ae..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use5.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -no `default` interface in document to use from - --> tests/ui/parse-fail/unresolved-use5.wit:4:11 - | - 4 | use pkg.unresolved-use5.{x} - | ^-------------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use6.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use6.wit deleted file mode 100644 index 125b2e3dcf..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use6.wit +++ /dev/null @@ -1,5 +0,0 @@ -// parse-fail - -interface foo { - use pkg.unresolved-use6.nonexistent.{x} -} diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use6.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use6.wit.result deleted file mode 100644 index e174fa5426..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use6.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -interface `nonexistent` does not exist - --> tests/ui/parse-fail/unresolved-use6.wit:4:27 - | - 4 | use pkg.unresolved-use6.nonexistent.{x} - | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit index c08f490950..d393838a99 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit @@ -1,7 +1,9 @@ // parse-fail +package foo + interface foo { - use pkg.unresolved-use7.bar.{x} + use bar.{x} } interface bar { diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit.result index 418dd27c65..acb4720e3c 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use7.wit.result @@ -1,5 +1,5 @@ name `x` is not defined - --> tests/ui/parse-fail/unresolved-use7.wit:4:32 + --> tests/ui/parse-fail/unresolved-use7.wit:6:12 | - 4 | use pkg.unresolved-use7.bar.{x} - | ^ \ No newline at end of file + 6 | use bar.{x} + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit index dad0d2eb28..bcb211e916 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit @@ -1,7 +1,9 @@ // parse-fail +package foo + world foo { import foo: interface { - use self.foo.{i32} + use foo.{i32} } } diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit.result index 8ed307231f..5ebb30c8db 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use8.wit.result @@ -1,5 +1,5 @@ name `foo` is defined as a world, not an interface - --> tests/ui/parse-fail/unresolved-use8.wit:5:14 + --> tests/ui/parse-fail/unresolved-use8.wit:7:9 | - 5 | use self.foo.{i32} - | ^-- \ No newline at end of file + 7 | use foo.{i32} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit b/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit index 83ba81ad7c..9a175c5ec7 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit @@ -1,7 +1,9 @@ // parse-fail +package foo + world foo { import foo: interface { - use self.bar.{i32} + use bar.{i32} } } diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit.result index 7bcfad2e5a..55455fc33a 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use9.wit.result @@ -1,5 +1,5 @@ interface does not exist - --> tests/ui/parse-fail/unresolved-use9.wit:5:14 + --> tests/ui/parse-fail/unresolved-use9.wit:7:9 | - 5 | use self.bar.{i32} - | ^-- \ No newline at end of file + 7 | use bar.{i32} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit b/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit index 20e158e133..0ff53fa1cc 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit @@ -1,9 +1,11 @@ // parse-fail +package foo + interface foo { type x = u32 } interface bar { - use self.foo.{x, x} + use foo.{x, x} } diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit.result index 2cbe95d2e2..aab7474e7c 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict.wit.result @@ -1,5 +1,5 @@ name `x` is defined more than once - --> tests/ui/parse-fail/use-conflict.wit:8:20 + --> tests/ui/parse-fail/use-conflict.wit:10:15 | - 8 | use self.foo.{x, x} - | ^ \ No newline at end of file + 10 | use foo.{x, x} + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit b/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit index 11a16519bd..b89e37d543 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit @@ -1,11 +1,13 @@ // parse-fail +package foo + interface foo { type x = u32 } interface bar { - use self.foo.{x} + use foo.{x} type x = s64 } diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit.result index 3c70f63445..623febeee9 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict2.wit.result @@ -1,5 +1,5 @@ name `x` is defined more than once - --> tests/ui/parse-fail/use-conflict2.wit:10:8 + --> tests/ui/parse-fail/use-conflict2.wit:12:8 | - 10 | type x = s64 + 12 | type x = s64 | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit b/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit index 53a85b0318..e7ca1bfe1a 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit @@ -1,11 +1,13 @@ // parse-fail +package foo + interface foo { type x = u32 } interface bar { - use self.foo.{x} + use foo.{x} x: func() } diff --git a/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit.result index c9e7e41e21..2928d26aa2 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/use-conflict3.wit.result @@ -1,5 +1,5 @@ name `x` is defined more than once - --> tests/ui/parse-fail/use-conflict3.wit:10:3 + --> tests/ui/parse-fail/use-conflict3.wit:12:3 | - 10 | x: func() + 12 | x: func() | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit b/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit index a1abaeca50..e51d3fb63e 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit +++ b/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit @@ -1,5 +1,7 @@ // parse-fail +package foo + interface foo { - use self.foo.{bar} + use foo.{bar} } diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit.result index 8c7950ed91..c0150a6008 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/use-cycle1.wit.result @@ -1,5 +1,5 @@ interface `foo` depends on itself - --> tests/ui/parse-fail/use-cycle1.wit:4:12 + --> tests/ui/parse-fail/use-cycle1.wit:5:11 | - 4 | use self.foo.{bar} - | ^-- \ No newline at end of file + 5 | interface foo { + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle2.wit b/crates/wit-parser/tests/ui/parse-fail/use-cycle2.wit deleted file mode 100644 index 7d416e30eb..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/use-cycle2.wit +++ /dev/null @@ -1,5 +0,0 @@ -// parse-fail - -interface foo { - use pkg.use-cycle2.foo.{bar} -} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle2.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-cycle2.wit.result deleted file mode 100644 index 8af25543a8..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/use-cycle2.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -interface `foo` depends on itself - --> tests/ui/parse-fail/use-cycle2.wit:4:22 - | - 4 | use pkg.use-cycle2.foo.{bar} - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle3.wit b/crates/wit-parser/tests/ui/parse-fail/use-cycle3.wit deleted file mode 100644 index 7edf782278..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/use-cycle3.wit +++ /dev/null @@ -1,6 +0,0 @@ -// parse-fail - -default interface foo { - // TODO: this could use a better error message - use pkg.use-cycle3.{bar} -} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle3.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-cycle3.wit.result deleted file mode 100644 index ff6d459c48..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/use-cycle3.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -interface `foo` depends on itself - --> tests/ui/parse-fail/use-cycle3.wit:5:11 - | - 5 | use pkg.use-cycle3.{bar} - | ^--------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit b/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit index 9fe1fbae34..045c124d7e 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit +++ b/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit @@ -1,13 +1,14 @@ // parse-fail +package foo interface foo { - use self.bar.{y} + use bar.{y} type x = u32 } interface bar { - use self.foo.{x} + use foo.{x} type y = u32 } diff --git a/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit.result index 65b739418c..79b327045d 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/use-cycle4.wit.result @@ -1,5 +1,5 @@ interface `bar` depends on itself - --> tests/ui/parse-fail/use-cycle4.wit:4:12 + --> tests/ui/parse-fail/use-cycle4.wit:10:11 | - 4 | use self.bar.{y} - | ^-- \ No newline at end of file + 10 | interface bar { + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-from-package-world.wit b/crates/wit-parser/tests/ui/parse-fail/use-from-package-world.wit deleted file mode 100644 index 5fdf01a23e..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/use-from-package-world.wit +++ /dev/null @@ -1,8 +0,0 @@ -// parse-fail - -world foo { -} - -interface bar { - use pkg.use-from-package-world.foo.{x} -} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-from-package-world.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-from-package-world.wit.result deleted file mode 100644 index e1dc970fa6..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/use-from-package-world.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -interface does not exist - --> tests/ui/parse-fail/use-from-package-world.wit:7:34 - | - 7 | use pkg.use-from-package-world.foo.{x} - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-from-package-world2.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-from-package-world2.wit.result deleted file mode 100644 index 95608cfb58..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/use-from-package-world2.wit.result +++ /dev/null @@ -1,8 +0,0 @@ -failed to parse package: tests/ui/parse-fail/use-from-package-world2 - -Caused by: - cannot import from world `foo` - --> tests/ui/parse-fail/use-from-package-world2/bar.wit:2:15 - | - 2 | use pkg.foo.foo.{thing} - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-from-package-world2/bar.wit b/crates/wit-parser/tests/ui/parse-fail/use-from-package-world2/bar.wit deleted file mode 100644 index 078c0c348f..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/use-from-package-world2/bar.wit +++ /dev/null @@ -1,3 +0,0 @@ -interface bar { - use pkg.foo.foo.{thing} -} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-from-package-world2/foo.wit b/crates/wit-parser/tests/ui/parse-fail/use-from-package-world2/foo.wit deleted file mode 100644 index c2e6c53e73..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/use-from-package-world2/foo.wit +++ /dev/null @@ -1,2 +0,0 @@ -world foo { -} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit b/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit new file mode 100644 index 0000000000..4a8736ad9e --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit @@ -0,0 +1,7 @@ +package foo + +use foo as bar + +interface foo {} + +interface bar {} diff --git a/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit.result new file mode 100644 index 0000000000..cdce8b4cc4 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/use-shadow1.wit.result @@ -0,0 +1,5 @@ +duplicate name `bar` in this file + --> tests/ui/parse-fail/use-shadow1.wit:7:11 + | + 7 | interface bar {} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import1.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-implicit-import1.wit.result deleted file mode 100644 index a8e23a5c6c..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import1.wit.result +++ /dev/null @@ -1,6 +0,0 @@ -import of `foo` conflicts with a previous interface using the name `foo` - - --> tests/ui/parse-fail/world-implicit-import1.wit:9:10 - | - 9 | import foo: interface {} - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import2.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-implicit-import2.wit.result deleted file mode 100644 index e6d9a48076..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import2.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -import of function `foo` shadows previously imported interface - --> tests/ui/parse-fail/world-implicit-import2.wit:8:10 - | - 8 | import foo: func() -> g - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import3.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-implicit-import3.wit.result deleted file mode 100644 index fac2c20c45..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import3.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -export of function `foo` shadows previously exported interface - --> tests/ui/parse-fail/world-implicit-import3.wit:8:10 - | - 8 | export foo: func() -> g - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit b/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit index edc358f041..ab44cd1f23 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit +++ b/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit @@ -1,2 +1,3 @@ +package foo interface foo {} world foo {} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit.result index 396ada61ad..c8159d3e52 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/world-interface-clash.wit.result @@ -1,5 +1,5 @@ -name `foo` previously defined in document - --> tests/ui/parse-fail/world-interface-clash.wit:2:7 +duplicate item named `foo + --> tests/ui/parse-fail/world-interface-clash.wit:3:7 | - 2 | world foo {} + 3 | world foo {} | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields.wit b/crates/wit-parser/tests/ui/parse-fail/world-same-fields.wit deleted file mode 100644 index 8906f0d526..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/world-same-fields.wit +++ /dev/null @@ -1,9 +0,0 @@ -// parse-fail - -interface foo {} -interface bar {} - -world a { - import foo: self.foo - import foo: self.bar -} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-same-fields.wit.result deleted file mode 100644 index a21a34d807..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/world-same-fields.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -import `foo` conflicts with prior import of same name - --> tests/ui/parse-fail/world-same-fields.wit:8:10 - | - 8 | import foo: self.bar - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit b/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit index 5fc043a011..25f511eb5e 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit +++ b/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit @@ -1,5 +1,7 @@ // parse-fail +package foo + world a { import foo: interface {} import foo: interface {} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit.result index fbf18162eb..3498be115f 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/world-same-fields2.wit.result @@ -1,5 +1,5 @@ import `foo` conflicts with prior import of same name - --> tests/ui/parse-fail/world-same-fields2.wit:5:10 + --> tests/ui/parse-fail/world-same-fields2.wit:7:10 | - 5 | import foo: interface {} + 7 | import foo: interface {} | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit b/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit index e48a2aedb5..0b4d0cbcbb 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit +++ b/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit @@ -1,5 +1,7 @@ // parse-fail +package foo + world a { export foo: interface {} export foo: interface {} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit.result index 60b1d3c5e8..bf4a4bc61b 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/world-same-fields3.wit.result @@ -1,5 +1,5 @@ export `foo` conflicts with prior export of same name - --> tests/ui/parse-fail/world-same-fields3.wit:5:10 + --> tests/ui/parse-fail/world-same-fields3.wit:7:10 | - 5 | export foo: interface {} + 7 | export foo: interface {} | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields4.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-same-fields4.wit.result deleted file mode 100644 index 26d54e6159..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/world-same-fields4.wit.result +++ /dev/null @@ -1,8 +0,0 @@ -import of `shared` - .. which is depended on by export `a-name` -conflicts with a previous interface using the name `shared` - - --> tests/ui/parse-fail/world-same-fields4.wit:7:10 - | - 7 | export a-name: interface { - | ^----- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-import.wit b/crates/wit-parser/tests/ui/parse-fail/world-same-import.wit deleted file mode 100644 index fedaaa76ca..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/world-same-import.wit +++ /dev/null @@ -1,6 +0,0 @@ -interface foo {} - -world bar { - import foo: self.foo - import bar: self.foo -} diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-import.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-same-import.wit.result deleted file mode 100644 index 750845b7a4..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/world-same-import.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -interface `bar` cannot be imported more than once - --> tests/ui/parse-fail/world-same-import.wit:5:10 - | - 5 | import bar: self.foo - | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit index 7bf7e5fce9..e34e72a6b2 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit +++ b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit @@ -1,3 +1,4 @@ +package foo world foo { import foo: func() import foo: func() diff --git a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit.result index 4a54d901b2..8eb1cc53f9 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func.wit.result @@ -1,5 +1,5 @@ import `foo` conflicts with prior import of same name - --> tests/ui/parse-fail/world-top-level-func.wit:3:10 + --> tests/ui/parse-fail/world-top-level-func.wit:4:10 | - 3 | import foo: func() + 4 | import foo: func() | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit index d872f06792..87f74ccffd 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit +++ b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit @@ -1,3 +1,4 @@ +package foo world foo { import foo: func(a: b) } diff --git a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit.result b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit.result index 8e845ca0c3..1fe06a9326 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/world-top-level-func2.wit.result @@ -1,5 +1,5 @@ name `b` is not defined - --> tests/ui/parse-fail/world-top-level-func2.wit:2:23 + --> tests/ui/parse-fail/world-top-level-func2.wit:3:23 | - 2 | import foo: func(a: b) + 3 | import foo: func(a: b) | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/worlds-same-fields5.wit.result b/crates/wit-parser/tests/ui/parse-fail/worlds-same-fields5.wit.result deleted file mode 100644 index cc854dab4b..0000000000 --- a/crates/wit-parser/tests/ui/parse-fail/worlds-same-fields5.wit.result +++ /dev/null @@ -1,9 +0,0 @@ -import of `i1` - .. which is depended on by import `i2` - .. which is depended on by export `i5` -conflicts with a previous interface using the name `i1` - - --> tests/ui/parse-fail/worlds-same-fields5.wit:15:10 - | - 15 | export i5: self.i3 - | ^- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/shared-types.wit b/crates/wit-parser/tests/ui/shared-types.wit index be072d9e76..1ab99cff67 100644 --- a/crates/wit-parser/tests/ui/shared-types.wit +++ b/crates/wit-parser/tests/ui/shared-types.wit @@ -1,3 +1,5 @@ +package shared + world foo { import foo: interface { a: func() -> list diff --git a/crates/wit-parser/tests/ui/type-then-eof.wit b/crates/wit-parser/tests/ui/type-then-eof.wit index e4c454399b..1c2e2f5e75 100644 --- a/crates/wit-parser/tests/ui/type-then-eof.wit +++ b/crates/wit-parser/tests/ui/type-then-eof.wit @@ -1,3 +1,5 @@ +package foo + interface foo { foo: func() -> string } diff --git a/crates/wit-parser/tests/ui/types.wit b/crates/wit-parser/tests/ui/types.wit index c9082389c6..6244576db9 100644 --- a/crates/wit-parser/tests/ui/types.wit +++ b/crates/wit-parser/tests/ui/types.wit @@ -1,3 +1,5 @@ +package types + interface types { type t1 = u8 type t2 = u16 diff --git a/crates/wit-parser/tests/ui/use-chain.wit b/crates/wit-parser/tests/ui/use-chain.wit new file mode 100644 index 0000000000..0248c01a59 --- /dev/null +++ b/crates/wit-parser/tests/ui/use-chain.wit @@ -0,0 +1,11 @@ +package name + +interface foo { + record foo {} +} + +use foo as bar + +interface name { + use bar.{foo} +} diff --git a/crates/wit-parser/tests/ui/use.wit b/crates/wit-parser/tests/ui/use.wit index af27a7c32a..cdb5e01ff5 100644 --- a/crates/wit-parser/tests/ui/use.wit +++ b/crates/wit-parser/tests/ui/use.wit @@ -1,5 +1,7 @@ +package foo + interface foo { - use self.bar.{the-type} + use bar.{the-type} } interface bar { @@ -7,27 +9,26 @@ interface bar { } interface baz { - use self.foo.{the-type} - use self.bar.{the-type as test} + use foo.{the-type} + use bar.{the-type as test} } interface empty { } interface use-from-empty { - use self.empty.{} - use pkg.%use.empty.{} + use empty.{} + use empty.{} } - interface use-multiple { - use self.baz.{the-type, test} + use baz.{the-type, test} some-function: func(x: the-type) -> test } interface trailing-comma { - use self.foo.{the-type,} + use foo.{the-type,} record the-foo { a: the-type } } diff --git a/crates/wit-parser/tests/ui/versions/deps/a1/foo.wit b/crates/wit-parser/tests/ui/versions/deps/a1/foo.wit new file mode 100644 index 0000000000..5f09ada36c --- /dev/null +++ b/crates/wit-parser/tests/ui/versions/deps/a1/foo.wit @@ -0,0 +1,5 @@ +package a:a@1.0 + +interface foo { + type t = u32 +} diff --git a/crates/wit-parser/tests/ui/versions/deps/a2/foo.wit b/crates/wit-parser/tests/ui/versions/deps/a2/foo.wit new file mode 100644 index 0000000000..7daa9cfc04 --- /dev/null +++ b/crates/wit-parser/tests/ui/versions/deps/a2/foo.wit @@ -0,0 +1,5 @@ +package a:a@2.0 + +interface foo { + type t = u32 +} diff --git a/crates/wit-parser/tests/ui/versions/foo.wit b/crates/wit-parser/tests/ui/versions/foo.wit new file mode 100644 index 0000000000..98c2a1834a --- /dev/null +++ b/crates/wit-parser/tests/ui/versions/foo.wit @@ -0,0 +1,7 @@ +package versions + +interface foo { + use a:a/foo@1.0.{t} + use a:a/foo@2.0.{t as t2} +} + diff --git a/crates/wit-parser/tests/ui/wasi.wit b/crates/wit-parser/tests/ui/wasi.wit index 4edfbaeec9..df2bf0f434 100644 --- a/crates/wit-parser/tests/ui/wasi.wit +++ b/crates/wit-parser/tests/ui/wasi.wit @@ -1,3 +1,5 @@ +package wasi:filesystem + interface wasi { enum clockid { // The clock measuring real time. Time value zero corresponds with diff --git a/crates/wit-parser/tests/ui/world-diamond.wit b/crates/wit-parser/tests/ui/world-diamond.wit index 5de78b35c5..2d571b0686 100644 --- a/crates/wit-parser/tests/ui/world-diamond.wit +++ b/crates/wit-parser/tests/ui/world-diamond.wit @@ -1,20 +1,22 @@ +package foo + interface shared { type foo = u32 } interface i1 { - use self.shared.{foo} + use shared.{foo} a: func() -> foo } interface i2 { - use self.shared.{foo} + use shared.{foo} a: func() -> foo } world the-world { - import i1: self.i1 - import i2: self.i2 + import i1 + import i2 } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-world-type2.wit b/crates/wit-parser/tests/ui/world-iface-no-collide.wit similarity index 72% rename from crates/wit-parser/tests/ui/parse-fail/bad-world-type2.wit rename to crates/wit-parser/tests/ui/world-iface-no-collide.wit index 42cd3248a6..731009ea0a 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-world-type2.wit +++ b/crates/wit-parser/tests/ui/world-iface-no-collide.wit @@ -1,9 +1,11 @@ +package foo + interface foo { type t = u32 } world bar { - use self.foo.{t} + use foo.{t} import foo: func() } diff --git a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import1.wit b/crates/wit-parser/tests/ui/world-implicit-import1.wit similarity index 79% rename from crates/wit-parser/tests/ui/parse-fail/world-implicit-import1.wit rename to crates/wit-parser/tests/ui/world-implicit-import1.wit index cbaedc8bc9..74f2fb1c41 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import1.wit +++ b/crates/wit-parser/tests/ui/world-implicit-import1.wit @@ -1,10 +1,12 @@ +package foo + interface foo { type a = u32 } world the-world { import bar: interface { - use self.foo.{a} + use foo.{a} } import foo: interface {} } diff --git a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import2.wit b/crates/wit-parser/tests/ui/world-implicit-import2.wit similarity index 73% rename from crates/wit-parser/tests/ui/parse-fail/world-implicit-import2.wit rename to crates/wit-parser/tests/ui/world-implicit-import2.wit index 5740f82601..524b3d4591 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import2.wit +++ b/crates/wit-parser/tests/ui/world-implicit-import2.wit @@ -1,9 +1,11 @@ +package foo + interface foo { type g = char } world w { - use self.foo.{g} + use foo.{g} import foo: func() -> g } diff --git a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import3.wit b/crates/wit-parser/tests/ui/world-implicit-import3.wit similarity index 73% rename from crates/wit-parser/tests/ui/parse-fail/world-implicit-import3.wit rename to crates/wit-parser/tests/ui/world-implicit-import3.wit index b02afa3d9b..242e0002dc 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-implicit-import3.wit +++ b/crates/wit-parser/tests/ui/world-implicit-import3.wit @@ -1,9 +1,11 @@ +package foo + interface foo { type g = char } world w { - use self.foo.{g} + use foo.{g} export foo: func() -> g } diff --git a/crates/wit-parser/tests/ui/parse-fail/world-same-fields4.wit b/crates/wit-parser/tests/ui/world-same-fields4.wit similarity index 78% rename from crates/wit-parser/tests/ui/parse-fail/world-same-fields4.wit rename to crates/wit-parser/tests/ui/world-same-fields4.wit index 766d29fbc3..70bc6926ce 100644 --- a/crates/wit-parser/tests/ui/parse-fail/world-same-fields4.wit +++ b/crates/wit-parser/tests/ui/world-same-fields4.wit @@ -1,3 +1,5 @@ +package foo + interface shared { type a = u32 } @@ -5,7 +7,7 @@ interface shared { world foo { import shared: interface {} export a-name: interface { - use self.shared.{a} + use shared.{a} } } diff --git a/crates/wit-parser/tests/ui/world-top-level-funcs.wit b/crates/wit-parser/tests/ui/world-top-level-funcs.wit index afcd693ce8..c9bc1b9fbb 100644 --- a/crates/wit-parser/tests/ui/world-top-level-funcs.wit +++ b/crates/wit-parser/tests/ui/world-top-level-funcs.wit @@ -1,3 +1,5 @@ +package foo + world foo { import foo: func() export foo2: func() diff --git a/crates/wit-parser/tests/ui/parse-fail/worlds-same-fields5.wit b/crates/wit-parser/tests/ui/worlds-same-fields5.wit similarity index 58% rename from crates/wit-parser/tests/ui/parse-fail/worlds-same-fields5.wit rename to crates/wit-parser/tests/ui/worlds-same-fields5.wit index f460e1f51d..d29a19c3d4 100644 --- a/crates/wit-parser/tests/ui/parse-fail/worlds-same-fields5.wit +++ b/crates/wit-parser/tests/ui/worlds-same-fields5.wit @@ -1,16 +1,17 @@ +package foo interface i1 { type t = u32 } interface i2 { - use self.i1.{t} + use i1.{t} } interface i3 { - use self.i2.{t} + use i2.{t} } world test { import i1: interface {} - export i4: self.i1 - export i5: self.i3 + export i1 + export i3 } diff --git a/crates/wit-parser/tests/ui/worlds-with-types.wit b/crates/wit-parser/tests/ui/worlds-with-types.wit index 3ca4903a8f..e6507ce328 100644 --- a/crates/wit-parser/tests/ui/worlds-with-types.wit +++ b/crates/wit-parser/tests/ui/worlds-with-types.wit @@ -1,3 +1,5 @@ +package foo + world foo { type a = u32 type b = a @@ -11,9 +13,9 @@ interface disambiguate { } world bar { - import disambiguate2: self.disambiguate + import disambiguate - use self.disambiguate.{t} + use disambiguate.{t} export foo: func() -> t } diff --git a/crates/wit-parser/tests/ui/worlds.wit b/crates/wit-parser/tests/ui/worlds.wit index a42b5224cc..de6940833d 100644 --- a/crates/wit-parser/tests/ui/worlds.wit +++ b/crates/wit-parser/tests/ui/worlds.wit @@ -1,40 +1,37 @@ +package foo + interface foo {} interface bar {} world the-world { - import foo: self.foo - import bar: self.bar + import foo + import bar import baz: interface { foo: func() } - export foo2: self.foo - export bar2: self.bar + export foo + export bar export baz2: interface { foo: func() } } -default world a-different-world { - import foo: self.foo +world a-different-world { + import foo } interface i1 { type t = u32 } interface i2 { - use self.i1.{t} + use i1.{t} } interface i3 { - use self.i2.{t} + use i2.{t} } world test { - import i3: self.i3 - - export i4: self.i1 - - // This should insert an implicit dependency on `i2` as an import, and then - // i2's dependency on i1 should be wired up to i3's implicit imported - // dependency on i1. - export i5: self.i3 + import i3 + export i1 + export i3 }