@@ -799,7 +799,7 @@ fn compute_direct_supertypes(
799799) -> std:: collections:: BTreeMap < node_types:: TypeName , BTreeSet < & str > > {
800800 let mut supertypes = std:: collections:: BTreeMap :: new ( ) ;
801801 for node in nodes. values ( ) {
802- if let node_types:: EntryKind :: Union { members } = & node. kind {
802+ if let node_types:: EntryKind :: Union { members, .. } = & node. kind {
803803 for member in members {
804804 supertypes
805805 . entry ( member. clone ( ) )
@@ -841,12 +841,9 @@ fn same_predicate_signature(a: &ql::Predicate, b: &ql::Predicate) -> bool {
841841 a. name == b. name && a. return_type == b. return_type && a. formal_parameters == b. formal_parameters
842842}
843843
844- /// Computes, for each tree-sitter supertype (union) node, the list of
845- /// predicates that are guaranteed to be defined identically (in terms of
846- /// name, return type, and formal parameters, though not necessarily body) by
847- /// every one of its members. These are the predicates that can be hoisted to
848- /// an `abstract` predicate on the union's class, with the corresponding
849- /// predicates on its members becoming `override`s.
844+ /// Computes the predicates explicitly exposed by a node. For a table these are
845+ /// its field predicates; for a union they are the predicates declared by the
846+ /// fields on that supertype.
850847///
851848/// The result for a given node is memoized in `cache` (keyed by its QL class
852849/// name), and also used to answer the query for any other node that
@@ -869,24 +866,8 @@ fn compute_exposed_predicates<'a, 'b>(
869866 Some ( node_types:: EntryKind :: Table { .. } ) => {
870867 field_predicates. get ( type_name) . cloned ( ) . unwrap_or_default ( )
871868 }
872- Some ( node_types:: EntryKind :: Union { members } ) => {
873- let mut members = members. iter ( ) ;
874- let mut common = match members. next ( ) {
875- Some ( first) => {
876- compute_exposed_predicates ( first, nodes, field_predicates, cache) . clone ( )
877- }
878- None => Vec :: new ( ) ,
879- } ;
880- for member in members {
881- let member_predicates =
882- compute_exposed_predicates ( member, nodes, field_predicates, cache) ;
883- common. retain ( |predicate| {
884- member_predicates
885- . iter ( )
886- . any ( |other| same_predicate_signature ( predicate, other) )
887- } ) ;
888- }
889- common
869+ Some ( node_types:: EntryKind :: Union { .. } ) => {
870+ field_predicates. get ( type_name) . cloned ( ) . unwrap_or_default ( )
890871 }
891872 Some ( node_types:: EntryKind :: Token { .. } ) | None => Vec :: new ( ) ,
892873 } ;
@@ -930,25 +911,24 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec<ql::TopLevel<'_>> {
930911 }
931912 }
932913
933- // First, compute the field-getter predicates (and the expressions used by
934- // `getAFieldOrChild`) for every table node, without yet knowing whether
935- // any of them will need to be marked `override`. These are needed both
936- // to build the final classes below, and to figure out which fields are
937- // shared identically by all the members of a supertype.
914+ // First, compute field-getter predicates for tables and the explicitly
915+ // declared field predicates for supertypes.
938916 let mut field_predicates: BTreeMap < & node_types:: TypeName , Vec < ql:: Predicate < ' _ > > > =
939917 BTreeMap :: new ( ) ;
940918 let mut get_child_exprs: BTreeMap < & node_types:: TypeName , Vec < ql:: Expression < ' _ > > > =
941919 BTreeMap :: new ( ) ;
942920 for ( type_name, node) in nodes {
943- if let node_types:: EntryKind :: Table {
944- name : main_table_name,
945- fields,
946- } = & node. kind
947- {
948- if fields. is_empty ( ) {
949- panic ! ( "Encountered node '{}' with no fields" , type_name. kind) ;
921+ let ( main_table_name, fields, has_storage) = match & node. kind {
922+ node_types:: EntryKind :: Table { name, fields } => ( name. as_str ( ) , fields, true ) ,
923+ node_types:: EntryKind :: Union { fields, .. } => {
924+ ( node. dbscheme_name . as_str ( ) , fields, false )
950925 }
951-
926+ node_types:: EntryKind :: Token { .. } => continue ,
927+ } ;
928+ if has_storage && fields. is_empty ( ) {
929+ panic ! ( "Encountered node '{}' with no fields" , type_name. kind) ;
930+ }
931+ if !fields. is_empty ( ) {
952932 // Count how many columns there will be in the main table. There
953933 // will be one for the id, plus one for each field that's stored
954934 // as a column.
@@ -969,20 +949,18 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec<ql::TopLevel<'_>> {
969949 nodes,
970950 ) ;
971951 predicates. extend ( get_preds) ;
972- if let Some ( get_child_expr) = get_child_expr {
952+ if has_storage && let Some ( get_child_expr) = get_child_expr {
973953 exprs. push ( get_child_expr)
974954 }
975955 }
976956 field_predicates. insert ( type_name, predicates) ;
977- get_child_exprs. insert ( type_name, exprs) ;
957+ if has_storage {
958+ get_child_exprs. insert ( type_name, exprs) ;
959+ }
978960 }
979961 }
980962
981- // Next, for every supertype (union) node, compute the predicates that are
982- // guaranteed to be defined identically (in name, return type, and formal
983- // parameters) by every one of its members. Such predicates can be hoisted
984- // to an `abstract` predicate on the supertype's class, with the
985- // corresponding predicates on its members becoming `override`s.
963+ // Next, collect the predicates explicitly exposed by every supertype.
986964 let mut exposed_predicates: BTreeMap < & str , Vec < ql:: Predicate < ' _ > > > = BTreeMap :: new ( ) ;
987965 for ( type_name, node) in nodes {
988966 if let node_types:: EntryKind :: Union { .. } = & node. kind {
@@ -1017,10 +995,10 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec<ql::TopLevel<'_>> {
1017995 } ) ) ;
1018996 }
1019997 }
1020- node_types:: EntryKind :: Union { members : _ } => {
998+ node_types:: EntryKind :: Union { .. } => {
1021999 // It's a tree-sitter supertype node, so we're wrapping a dbscheme
1022- // union type. Any predicate that's identically defined by every
1023- // member becomes an `abstract` predicate here.
1000+ // union type. Fields declared on the supertype become abstract
1001+ // predicates here.
10241002 let predicates = exposed_predicates
10251003 . get ( node. ql_class_name . as_str ( ) )
10261004 . cloned ( )
@@ -1215,3 +1193,110 @@ pub fn create_print_ast_module(nodes: &node_types::NodeTypeMap) -> ql::TopLevel<
12151193 overlay : None ,
12161194 } )
12171195}
1196+
1197+ #[ cfg( test) ]
1198+ mod tests {
1199+ use super :: * ;
1200+
1201+ #[ test]
1202+ fn supertype_exposes_only_declared_fields ( ) {
1203+ let node_types = r#"[
1204+ {
1205+ "type": "container",
1206+ "named": true,
1207+ "subtypes": [
1208+ { "type": "alpha", "named": true },
1209+ { "type": "beta", "named": true }
1210+ ],
1211+ "fields": {
1212+ "item": {
1213+ "multiple": true,
1214+ "required": false,
1215+ "types": [{ "type": "item", "named": true }]
1216+ }
1217+ }
1218+ },
1219+ {
1220+ "type": "alpha",
1221+ "named": true,
1222+ "fields": {
1223+ "hidden": {
1224+ "multiple": false,
1225+ "required": true,
1226+ "types": [{ "type": "item", "named": true }]
1227+ },
1228+ "item": {
1229+ "multiple": true,
1230+ "required": false,
1231+ "types": [{ "type": "item", "named": true }]
1232+ }
1233+ }
1234+ },
1235+ {
1236+ "type": "beta",
1237+ "named": true,
1238+ "fields": {
1239+ "hidden": {
1240+ "multiple": false,
1241+ "required": true,
1242+ "types": [{ "type": "item", "named": true }]
1243+ },
1244+ "item": {
1245+ "multiple": true,
1246+ "required": false,
1247+ "types": [{ "type": "item", "named": true }]
1248+ }
1249+ }
1250+ },
1251+ { "type": "item", "named": true, "fields": {} }
1252+ ]"# ;
1253+ let nodes = node_types:: read_node_types_str ( "test" , node_types) . unwrap ( ) ;
1254+ let classes = convert_nodes ( & nodes) ;
1255+
1256+ let container = classes
1257+ . iter ( )
1258+ . find_map ( |top_level| match top_level {
1259+ ql:: TopLevel :: Class ( class) if class. name == "Container" => Some ( class) ,
1260+ _ => None ,
1261+ } )
1262+ . unwrap ( ) ;
1263+ assert_eq ! (
1264+ container
1265+ . predicates
1266+ . iter( )
1267+ . map( |predicate| predicate. name)
1268+ . collect:: <BTreeSet <_>>( ) ,
1269+ BTreeSet :: from( [ "getAnItem" , "getItem" ] ) ,
1270+ ) ;
1271+ assert ! (
1272+ container
1273+ . predicates
1274+ . iter( )
1275+ . all( |predicate| predicate. body. is_none( ) && !predicate. is_final)
1276+ ) ;
1277+
1278+ let alpha = classes
1279+ . iter ( )
1280+ . find_map ( |top_level| match top_level {
1281+ ql:: TopLevel :: Class ( class) if class. name == "Alpha" => Some ( class) ,
1282+ _ => None ,
1283+ } )
1284+ . unwrap ( ) ;
1285+ assert ! (
1286+ alpha
1287+ . predicates
1288+ . iter( )
1289+ . find( |predicate| predicate. name == "getItem" )
1290+ . unwrap( )
1291+ . overridden
1292+ ) ;
1293+ assert ! (
1294+ !alpha
1295+ . predicates
1296+ . iter( )
1297+ . find( |predicate| predicate. name == "getHidden" )
1298+ . unwrap( )
1299+ . overridden
1300+ ) ;
1301+ }
1302+ }
0 commit comments