44
55import java .util .*;
66
7- import org .basex .io .in .DataInput ;
7+ import org .basex .io .in .* ;
88import org .basex .query .*;
9- import org .basex .query .expr .path .*;
109import org .basex .query .value .*;
1110import org .basex .query .value .item .*;
1211import org .basex .util .*;
1918 */
2019public final class ChoiceItemType implements Type {
2120 /** Alternative item types. */
22- public final List <SeqType > types ;
21+ public final List <Type > types ;
2322 /** Common ancestor type. */
2423 private final Type union ;
2524
@@ -30,31 +29,31 @@ public final class ChoiceItemType implements Type {
3029 * Constructor.
3130 * @param types alternative item types
3231 */
33- private ChoiceItemType (final List <SeqType > types ) {
32+ private ChoiceItemType (final List <Type > types ) {
3433 this .types = types ;
35- Type tp = null ;
36- for (final SeqType st : this .types ) {
37- tp = tp == null ? st . type : tp .union (st . type );
34+ Type ut = null ;
35+ for (final Type tp : this .types ) {
36+ ut = ut == null ? tp : ut .union (tp );
3837 }
39- union = tp ;
38+ union = ut ;
4039 }
4140
4241 /**
4342 * Creates a choice item type.
4443 * @param types alternative item types
4544 * @return choice item type
4645 */
47- public static Type get (final SeqType ... types ) {
46+ public static Type get (final Type ... types ) {
4847 final Builder builder = new Builder ();
49- for (final SeqType st : types ) builder .add (st );
48+ for (final Type tp : types ) builder .add (tp );
5049 return builder .build ();
5150 }
5251
5352 @ Override
5453 public Value cast (final Item item , final QueryContext qc , final InputInfo info )
5554 throws QueryException {
56- for (final SeqType st : types ) {
57- final Value val = st .cast (item , false , qc , info );
55+ for (final Type tp : types ) {
56+ final Value val = tp . seqType () .cast (item , false , qc , info );
5857 if (val != null ) return val ;
5958 }
6059 throw FUNCCAST_X_X_X .get (info , item .type , this , item );
@@ -63,9 +62,9 @@ public Value cast(final Item item, final QueryContext qc, final InputInfo info)
6362 @ Override
6463 public Value cast (final Object value , final QueryContext qc , final InputInfo info )
6564 throws QueryException {
66- for (final SeqType st : types ) {
65+ for (final Type tp : types ) {
6766 try {
68- return st . type .cast (value , qc , info );
67+ return tp .cast (value , qc , info );
6968 } catch (final QueryException ex ) {
7069 Util .debug (ex );
7170 }
@@ -90,25 +89,48 @@ public boolean eq(final Type type) {
9089 return this == type || type instanceof final ChoiceItemType cit && types .equals (cit .types );
9190 }
9291
92+ @ Override
93+ public boolean instanceOf (final Type type ) {
94+ final Type norm = expand (type );
95+ if (norm instanceof final ChoiceItemType ct ) {
96+ for (final Type tp : types ) {
97+ if (!ct .hasInstance (tp )) return false ;
98+ }
99+ } else {
100+ for (final Type tp : types ) {
101+ if (!tp .instanceOf (norm )) return false ;
102+ }
103+ }
104+ return true ;
105+ }
106+
93107 /**
94- * Checks if this choice item type is an instance of the specified sequence type.
95- * @param seqType sequence type to check
108+ * Checks if this choice type is a supertype of the given type.
109+ * @param type type to be checked
96110 * @return result of check
97111 */
98- public boolean instanceOf (final SeqType seqType ) {
99- if (!seqType .one ()) throw Util .notExpected ();
100- for (final SeqType st : types ) {
101- if (!st .instanceOf (seqType )) return false ;
112+ boolean hasInstance (final Type type ) {
113+ final Type norm = expand (type );
114+ if (norm instanceof final ChoiceItemType ct ) return ct .instanceOf (this );
115+ for (final Type tp : types ) {
116+ if (norm .instanceOf (tp )) return true ;
102117 }
103- return true ;
118+ return false ;
104119 }
105120
106- @ Override
107- public boolean instanceOf (final Type type ) {
108- for (final SeqType st : types ) {
109- if (!st .type .instanceOf (type )) return false ;
110- }
111- return true ;
121+ /**
122+ * Expand the given type for comparison with choice item types, if necessary, as specified in the
123+ * subtyping rules for choice item types.
124+ * @param type type to expand
125+ * @return expanded type
126+ */
127+ private static Type expand (final Type type ) {
128+ if (type == BasicType .NUMERIC ) return Types .NUMERIC_EXPANSION ;
129+ if (type == BasicType .ANY_ATOMIC_TYPE ) return Types .ANY_ATOMIC_TYPE_EXPANSION ;
130+ if (type == BasicType .ITEM ) return Types .ITEM_EXPANSION ;
131+ if (type == NodeType .NODE ) return Types .NODE_EXPANSION ;
132+ if (type == NodeType .GNODE ) return Types .GNODE_EXPANSION ;
133+ return type ;
112134 }
113135
114136 @ Override
@@ -119,9 +141,9 @@ public Type union(final Type type) {
119141 @ Override
120142 public Type intersect (final Type type ) {
121143 final Builder builder = new Builder ();
122- for (final SeqType st : types ) {
123- final Type tp = type .intersect (st . type );
124- if (tp != null ) builder .add (tp . seqType () );
144+ for (final Type tp : types ) {
145+ final Type is = type .intersect (tp );
146+ if (is != null ) builder .add (is );
125147 }
126148 return builder .types .isEmpty () ? null : builder .build ();
127149 }
@@ -133,7 +155,7 @@ public boolean isNumber() {
133155
134156 @ Override
135157 public boolean isUntyped () {
136- return union .isNumberOrUntyped ();
158+ return union .isUntyped ();
137159 }
138160
139161 @ Override
@@ -163,41 +185,8 @@ public ID id() {
163185
164186 @ Override
165187 public boolean nsSensitive () {
166- for (final SeqType st : types ) {
167- if (st .type .nsSensitive ()) return true ;
168- }
169- return false ;
170- }
171-
172- /**
173- * Checks if the given type is an instance of this type.
174- * @param type type to be checked
175- * @return result of check
176- */
177- boolean hasInstance (final Type type ) {
178- for (final SeqType st : types ) {
179- if (type .instanceOf (st .type )) return true ;
180- }
181- return false ;
182- }
183-
184- /**
185- * Checks if the given sequence type is an instance of this type.
186- * @param seqType sequence type to be checked
187- * @return result of check
188- */
189- boolean hasInstance (final SeqType seqType ) {
190- if (!seqType .one ()) throw Util .notExpected ();
191- if (seqType .type instanceof final NodeType nt ) {
192- if (nt .test instanceof final UnionTest ut ) {
193- for (final Test t : ut .tests ) {
194- if (!hasInstance (NodeType .get (t ))) return false ;
195- }
196- return true ;
197- }
198- }
199- for (final SeqType st : types ) {
200- if (seqType .instanceOf (st )) return true ;
188+ for (final Type tp : types ) {
189+ if (tp .nsSensitive ()) return true ;
201190 }
202191 return false ;
203192 }
@@ -219,7 +208,7 @@ public String name() {
219208
220209 @ Override
221210 public String toString () {
222- return toString ("|" , (Object []) types .toArray (SeqType []::new ));
211+ return toString ("|" , (Object []) types .toArray (Type []::new ));
223212 }
224213
225214 /**
@@ -229,66 +218,66 @@ public String toString() {
229218 */
230219 public static final class Builder {
231220 /** Alternative item types. */
232- private final ArrayList <SeqType > types = new ArrayList <>();
221+ private final ArrayList <Type > types = new ArrayList <>();
233222
234223 /**
235224 * Builds and returns the resulting choice item type.
236225 * @return choice item type, or the single item type if the list contains only one type
237226 */
238227 public Type build () {
239- if (types .size () != 1 ) types .remove (Types . ERROR_O );
228+ if (types .size () != 1 ) types .remove (BasicType . ERROR );
240229 return switch (types .size ()) {
241230 case 0 -> throw Util .notExpected ();
242- case 1 -> types .get (0 ). type ;
231+ case 1 -> types .get (0 );
243232 default -> new ChoiceItemType (types );
244233 };
245234 }
246235
247236 /**
248- * Adds the specified sequence type to this builder, merging enum types only if consecutive, and
249- * merging document, element, attribute, and pi types anywhere in the list, ignoring duplicates,
250- * and flattening nested ChoiceItemTypes.
251- * @param st sequence type to be added
237+ * Adds the specified type to this builder, merging enum types only if consecutive, and merging
238+ * document, element, attribute, and pi types anywhere in the list, ignoring duplicates, and
239+ * flattening nested ChoiceItemTypes.
240+ * @param type type to be added
252241 * @return this builder
253242 */
254- public Builder add (final SeqType st ) {
243+ public Builder add (final Type type ) {
255244 // flatten nested ChoiceItemTypes
256- if (st . type instanceof ChoiceItemType ct ) {
257- for (final SeqType s : ct .types ) add (s );
245+ if (type instanceof final ChoiceItemType ct ) {
246+ for (final Type tp : ct .types ) add (tp );
258247 return this ;
259248 }
260249 // ignore duplicates
261- if (types .contains (st )) return this ;
250+ if (types .contains (type )) return this ;
262251 // non-mergeable types or first entry
263- final Type .ID id = st . type .id ();
252+ final Type .ID id = type .id ();
264253 if (types .isEmpty ()
265254 || !id .oneOf (Type .ID .ENM , Type .ID .DOC , Type .ID .ELM , Type .ID .ATT , Type .ID .PI )) {
266- types .add (st );
255+ types .add (type );
267256 return this ;
268257 }
269258 // enums: merge consecutive entries only, to preserve position of alternatives
270259 if (id == Type .ID .ENM ) {
271260 final int last = types .size () - 1 ;
272- final Type tp = types .get (last ). type ;
261+ final Type tp = types .get (last );
273262 if (tp .id () == Type .ID .ENM ) {
274263 // remove and re-add, for duplicate removal
275264 types .remove (last );
276- return add (tp .union (st . type ). seqType ( ));
265+ return add (tp .union (type ));
277266 }
278- // not consecutive: add as-is
279- types .add (st );
267+ // not consecutive: add as-is
268+ types .add (type );
280269 return this ;
281270 }
282271 // nodes (DOC/ELM/ATT/PI): merge with existing alternative of same kind anywhere, in-place
283272 for (int i = 0 ; i < types .size (); i ++) {
284- final SeqType existing = types .get (i );
285- if (existing .type . id () == id ) {
286- types .set (i , existing .type . union (st . type ). seqType ( ));
273+ final Type existing = types .get (i );
274+ if (existing .id () == id ) {
275+ types .set (i , existing .union (type ));
287276 return this ;
288277 }
289278 }
290279 // no existing node kind found
291- types .add (st );
280+ types .add (type );
292281 return this ;
293282 }
294283 }
0 commit comments