fn can_flatten_selections()

in compiler/crates/relay-transforms/src/flatten.rs [395:533]


    fn can_flatten_selections(
        &self,
        flattened_selections: &mut Vec<Selection>,
        selections: &[Selection],
        parent_type: Type,
    ) -> DiagnosticsResult<()> {
        for selection in selections {
            if self.should_validate_fragment_spreads {
                if let Selection::FragmentSpread(spread) = selection {
                    let fragment_definition =
                        self.fragments
                            .get(&spread.fragment.item)
                            .ok_or(Diagnostic::error(
                                ValidationMessage::UndefinedFragment(spread.fragment.item),
                                spread.fragment.location,
                            ))?;
                    if fragment_definition.type_condition == parent_type {
                        self.can_flatten_selections(
                            flattened_selections,
                            &fragment_definition.selections,
                            fragment_definition.type_condition,
                        )?;
                    }
                    continue;
                }
            }

            if let Selection::InlineFragment(inline_fragment) = selection {
                // We will iterate through a selection of inline fragments
                // (ignoring its directives) if this inline fragment doesn't
                // have a type condition or type condition is the same as `parent_type`.
                // The one exception for the latter case is @module directive.
                // These are specially validated: they don't have conflicts in selections
                // but may have conflicts in directive arguments.
                if inline_fragment.type_condition.is_none()
                    || (inline_fragment.type_condition == Some(parent_type)
                        && inline_fragment
                            .directives
                            .named(ModuleMetadata::directive_name())
                            .is_none())
                {
                    self.can_flatten_selections(
                        flattened_selections,
                        &inline_fragment.selections,
                        parent_type,
                    )?;
                    continue;
                }
            }

            let flattened_selection = flattened_selections.iter_mut().find(|sel| {
                sel.ptr_eq(selection) || NodeIdentifier::are_equal(&self.schema, sel, selection)
            });
            match flattened_selection {
                None => {
                    flattened_selections.push(selection.clone());
                }
                Some(flattened_selection) => {
                    if flattened_selection.ptr_eq(selection) {
                        continue;
                    }
                    match flattened_selection {
                        Selection::InlineFragment(flattened_node) => {
                            let node = match selection {
                                Selection::InlineFragment(node) => node,
                                _ => unreachable!("FlattenTransform: Expected an InlineFragment."),
                            };
                            if let Some(flattened_module_metadata) =
                                ModuleMetadata::find(&flattened_node.directives)
                            {
                                if let Some(module_metadata) =
                                    ModuleMetadata::find(&node.directives)
                                {
                                    if flattened_module_metadata.key != module_metadata.key
                                        || flattened_module_metadata.module_name
                                            != module_metadata.module_name
                                        || flattened_module_metadata.fragment_name
                                            != module_metadata.fragment_name
                                    {
                                        let error = Diagnostic::error(
                                            ValidationMessage::ConflictingModuleSelections,
                                            module_metadata.location,
                                        )
                                        .annotate(
                                            "conflicts with",
                                            flattened_module_metadata.location,
                                        );
                                        return Err(vec![error]);
                                    }
                                }
                            }
                            let type_condition =
                                flattened_node.type_condition.unwrap_or(parent_type);
                            let flattened_node_mut = Arc::make_mut(flattened_node);
                            self.can_flatten_selections(
                                &mut flattened_node_mut.selections,
                                &node.selections,
                                type_condition,
                            )?;
                        }
                        Selection::LinkedField(flattened_node) => {
                            let node = match selection {
                                Selection::LinkedField(node) => node,
                                _ => unreachable!("FlattenTransform: Expected a LinkedField."),
                            };
                            let type_ = self
                                .schema
                                .field(flattened_node.definition.item)
                                .type_
                                .inner();

                            let flattened_node_mut = Arc::make_mut(flattened_node);
                            self.can_flatten_selections(
                                &mut flattened_node_mut.selections,
                                &node.selections,
                                type_,
                            )?;
                        }
                        Selection::Condition(flattened_node) => {
                            let node = match selection {
                                Selection::Condition(node) => node,
                                _ => unreachable!("FlattenTransform: Expected a Condition."),
                            };

                            let flattened_node_mut = Arc::make_mut(flattened_node);
                            self.can_flatten_selections(
                                &mut flattened_node_mut.selections,
                                &node.selections,
                                parent_type,
                            )?;
                        }
                        Selection::ScalarField(_) | Selection::FragmentSpread(_) => {}
                    };
                }
            }
        }

        Ok(())
    }