Repository navigation
Conversation
Code outside the type classes took types apart itself: it counted .items, flattened members with flat_map(&:items), read the first member's tag or generic? as the whole type's, and walked members to find methods (castwide#1382). Each of those sites makes an assumption a union or a later type kind can break. Give both classes the restricted interface from castwide#1382 instead: satisfied_by?, conforms_to_unique?, provides_duck_method?, candidate_methods_from, any_generic?, unalias_and_qualify, method_stack_pins, qualify_parts, order_nil_last, combine_via (with TypeMethods.combine_members), reduce_object and reduce_class_type per member, plus the union-only unioned_items, ComplexType.union and ComplexType.flatten_unions. A union is now void or undefined when any member is. Union members dedup by rooted_tags, and the Boolean fold moves into fold_boolean_cases. Remove the Enumerable-style surface (map, each, each_unique_type, first, length, to_a, [], select, all?, any?, bottom? on ComplexType; map, each, all?, any?, to_a on UniqueType) and switch every caller in lib/ to the interface. ApiMap#get_complex_type_methods becomes #candidate_methods_from on the type, with ApiMap#visibility_for left behind for the ancestry check. An unknown name sent to a ComplexType now reaches super and raises even when the union is empty. Ported from castwide#1231 without its intersection type.
Exercise the ComplexType paths no spec reached: unalias_and_qualify, conforms_to_unique? with and without allow_any_match, provides_duck_method?, all_rooted? and the deprecated duck_types_match?, plus UniqueType#nullable? and the UniqueType copy of intersect_with that BaseVariable#adjust_type reaches when #exclude returns a bare UniqueType.
Clip#infer compares result.tags, the whole union, before taking the Class#new BasicObject path. A Class#new returning 'Class, nil' used to match on its first member and come back as BasicObject; this spec pins the union staying intact.
The spec redefined Class#new in source, leaving two Class#new pins. ApiMap#inner_get_methods orders them with an unstable sort by name, so which pin answered depended on the platform's sort: the source pin on macOS, the RBS pin (undefined) on CI's Linux runners. Build the union from core's single Class#new instead: a safe-navigated call on a Class<Class>, nil receiver infers 'Class, nil', which master reported as BasicObject.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Claude: This PR was written by Claude Code on behalf of @apiology.
Problem: Code outside the type classes answers for a whole union from its first member:
The 20 sites in castwide#1382 each take a type apart themselves, and several already give wrong answers for plain unions.
Solution: ComplexType and UniqueType now share the restricted interface from castwide#1382 (satisfied_by?, candidate_methods_from, method_stack_pins, qualify_parts, combine_via, order_nil_last and the rest), the Enumerable-style methods are removed, and every caller in lib/ uses the interface, so each question is answered by the type across all its members.
ApiMap#get_complex_type_methodsis removed in favour oftype.candidate_methods_from(api_map, context, internal). Intersection types from castwide#1231 are not included here.