@@ -1252,12 +1252,70 @@ fn create_synthetic_resource(
1252
1252
. expressions
1253
1253
// If dup_res_decl is concrete, do not inherit virtual functions
1254
1254
. retain ( |e| dup_res_is_virtual || !e. is_virtual_function ( ) ) ;
1255
- if !global_exprs. insert ( Expression :: Decl ( Declaration :: Type ( Box :: new ( dup_res_decl) ) ) ) {
1256
- return Err ( InternalError :: new ( ) . into ( ) ) ;
1255
+ if !global_exprs. insert ( Expression :: Decl ( Declaration :: Type ( Box :: new (
1256
+ dup_res_decl. clone ( ) ,
1257
+ ) ) ) ) {
1258
+ // The callers should be handling the situation where the same resource was declared at the
1259
+ // same level of inheritance, but this can arise if a parent associated a resource and a
1260
+ // child associated the same resource. We should find them and return and error message
1261
+ return match make_duplicate_associate_error ( types, dom_info, & res_name) {
1262
+ Some ( e) => Err ( e. into ( ) ) ,
1263
+ None => Err ( InternalError :: new ( ) . into ( ) ) ,
1264
+ } ;
1257
1265
}
1258
1266
Ok ( res_name)
1259
1267
}
1260
1268
1269
+ fn make_duplicate_associate_error (
1270
+ types : & TypeMap ,
1271
+ child_domain : & TypeInfo ,
1272
+ res_name : & CascadeString ,
1273
+ ) -> Option < CompileError > {
1274
+ let mut parent_ti = None ;
1275
+ let mut parent_associate_range = None ;
1276
+ for p in child_domain. get_all_parent_names ( types) {
1277
+ if let Some ( p_ti) = types. get ( p. as_ref ( ) ) {
1278
+ parent_associate_range = p_ti. explicitly_associates ( res_name. as_ref ( ) ) ;
1279
+ if parent_associate_range. is_some ( ) {
1280
+ parent_ti = Some ( p_ti) ;
1281
+ break ;
1282
+ }
1283
+ }
1284
+ }
1285
+ let current_associate_range = match child_domain. explicitly_associates ( res_name. as_ref ( ) ) {
1286
+ Some ( r) => r,
1287
+ None => {
1288
+ // This is an association via nested declaration, so find that
1289
+ child_domain. decl . as_ref ( ) ?. expressions . iter ( ) . find_map ( |e|
1290
+ if let Expression :: Decl ( Declaration :: Type ( td) ) = e {
1291
+ if & td. name == res_name {
1292
+ td. name . get_range ( )
1293
+ } else {
1294
+ None
1295
+ }
1296
+ } else {
1297
+ None
1298
+ } ) ?
1299
+ }
1300
+ } ;
1301
+
1302
+ // If anything we need for a real error is None, all we can do is InternalError, so unwrap
1303
+ // everything, returning InternalError on failure
1304
+ let child_file = child_domain. declaration_file . as_ref ( ) ?;
1305
+ let parent_file = parent_ti?. declaration_file . as_ref ( ) ?;
1306
+ let parent_associate_range = parent_associate_range?;
1307
+
1308
+ Some ( CompileError :: new (
1309
+ "This resource is explicitly associated to both the parent and child. (Perhaps you meant to extend the existing resource in the child?)" ,
1310
+ child_file,
1311
+ current_associate_range,
1312
+ "Associated in the child here" )
1313
+ . add_additional_message (
1314
+ parent_file,
1315
+ parent_associate_range,
1316
+ "But it was already associated in this parent" ) )
1317
+ }
1318
+
1261
1319
fn interpret_associate (
1262
1320
global_exprs : & mut HashSet < Expression > ,
1263
1321
local_exprs : & mut HashSet < Expression > ,
0 commit comments