@@ -181,11 +181,29 @@ impl<'a> AstResolver<'a> {
181181 }
182182 }
183183
184+ // If there's a target world in the directive, validate the composition
185+ // conforms to the target
186+ if let Some ( path) = & self . document . directive . targets {
187+ let item = self . resolve_package_export ( & mut state, path) ?;
188+ match item {
189+ ItemKind :: Type ( Type :: World ( world) ) => {
190+ self . validate_target ( & state, path, world) ?;
191+ }
192+ _ => {
193+ return Err ( Error :: NotWorld {
194+ name : path. string . to_owned ( ) ,
195+ kind : item. as_str ( & self . definitions ) . to_owned ( ) ,
196+ span : path. span ,
197+ } ) ;
198+ }
199+ }
200+ }
201+
184202 assert ! ( state. scopes. is_empty( ) ) ;
185203
186204 Ok ( Composition {
187- package : self . document . package . name . to_owned ( ) ,
188- version : self . document . package . version . clone ( ) ,
205+ package : self . document . directive . package . name . to_owned ( ) ,
206+ version : self . document . directive . package . version . clone ( ) ,
189207 definitions : self . definitions ,
190208 packages : state. packages ,
191209 items : state. current . items ,
@@ -227,13 +245,8 @@ impl<'a> AstResolver<'a> {
227245 ast:: ImportType :: Ident ( id) => ( state. local_item ( id) ?. 1 . kind ( ) , stmt. id . span ) ,
228246 } ;
229247
230- // Promote function types, instance types, and component types to functions, instances, and components
231- let kind = match kind {
232- ItemKind :: Type ( Type :: Func ( id) ) => ItemKind :: Func ( id) ,
233- ItemKind :: Type ( Type :: Interface ( id) ) => ItemKind :: Instance ( id) ,
234- ItemKind :: Type ( Type :: World ( id) ) => ItemKind :: Component ( id) ,
235- _ => kind,
236- } ;
248+ // Promote any types to their corresponding item kind
249+ let kind = kind. promote ( ) ;
237250
238251 let ( name, span) = if let Some ( name) = & stmt. name {
239252 // Override the span to the `as` clause string
@@ -505,8 +518,8 @@ impl<'a> AstResolver<'a> {
505518 fn id ( & self , name : & str ) -> String {
506519 format ! (
507520 "{pkg}/{name}{version}" ,
508- pkg = self . document. package. name,
509- version = if let Some ( version) = & self . document. package. version {
521+ pkg = self . document. directive . package. name,
522+ version = if let Some ( version) = & self . document. directive . package. version {
510523 format!( "@{version}" )
511524 } else {
512525 String :: new( )
@@ -1551,7 +1564,7 @@ impl<'a> AstResolver<'a> {
15511564 path : & ' a ast:: PackagePath < ' a > ,
15521565 ) -> ResolutionResult < ItemKind > {
15531566 // Check for reference to local item
1554- if path. name == self . document . package . name {
1567+ if path. name == self . document . directive . package . name {
15551568 return self . resolve_local_export ( state, path) ;
15561569 }
15571570
@@ -1704,7 +1717,7 @@ impl<'a> AstResolver<'a> {
17041717 state : & mut State < ' a > ,
17051718 expr : & ' a ast:: NewExpr < ' a > ,
17061719 ) -> ResolutionResult < ItemId > {
1707- if expr. package . name == self . document . package . name {
1720+ if expr. package . name == self . document . directive . package . name {
17081721 return Err ( Error :: UnknownPackage {
17091722 name : expr. package . name . to_string ( ) ,
17101723 span : expr. package . span ,
@@ -2248,4 +2261,68 @@ impl<'a> AstResolver<'a> {
22482261 aliases. insert ( name. to_owned ( ) , id) ;
22492262 Ok ( Some ( id) )
22502263 }
2264+
2265+ fn validate_target (
2266+ & self ,
2267+ state : & State ,
2268+ path : & ast:: PackagePath ,
2269+ world : WorldId ,
2270+ ) -> ResolutionResult < ( ) > {
2271+ let world = & self . definitions . worlds [ world] ;
2272+
2273+ let mut checker = SubtypeChecker :: new ( & self . definitions , & state. packages ) ;
2274+
2275+ // The output is allowed to import a subset of the world's imports
2276+ for ( name, import) in & state. imports {
2277+ let expected = world
2278+ . imports
2279+ . get ( name)
2280+ . ok_or_else ( || Error :: ImportNotInTarget {
2281+ name : name. clone ( ) ,
2282+ world : path. string . to_owned ( ) ,
2283+ span : import. span ,
2284+ } ) ?;
2285+
2286+ checker
2287+ . is_subtype (
2288+ expected. promote ( ) ,
2289+ state. root_scope ( ) . items [ import. item ] . kind ( ) ,
2290+ )
2291+ . map_err ( |e| Error :: TargetMismatch {
2292+ kind : ExternKind :: Import ,
2293+ name : name. clone ( ) ,
2294+ world : path. string . to_owned ( ) ,
2295+ span : import. span ,
2296+ source : e,
2297+ } ) ?;
2298+ }
2299+
2300+ // The output must export every export in the world
2301+ for ( name, expected) in & world. exports {
2302+ let export = state
2303+ . exports
2304+ . get ( name)
2305+ . ok_or_else ( || Error :: MissingTargetExport {
2306+ name : name. clone ( ) ,
2307+ world : path. string . to_owned ( ) ,
2308+ kind : expected. as_str ( & self . definitions ) . to_string ( ) ,
2309+ span : path. span ,
2310+ } ) ?;
2311+
2312+ checker
2313+ . is_subtype (
2314+ expected. promote ( ) ,
2315+ state. root_scope ( ) . items [ export. item ] . kind ( ) ,
2316+ )
2317+ . map_err ( |e| Error :: TargetMismatch {
2318+ kind : ExternKind :: Export ,
2319+ name : name. clone ( ) ,
2320+ world : path. string . to_owned ( ) ,
2321+ span : export. span ,
2322+ source : e,
2323+ } ) ?;
2324+ }
2325+
2326+ Ok ( ( ) )
2327+ }
22512328}
0 commit comments