diff --git a/Cargo.lock b/Cargo.lock index ad3c74c..dc6a2ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,9 +22,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" [[package]] name = "async-graphql-parser" @@ -78,15 +78,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "memchr", -] - [[package]] name = "bumpalo" version = "3.11.0" @@ -102,12 +93,6 @@ dependencies = [ "serde", ] -[[package]] -name = "camino" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e" - [[package]] name = "cfg-if" version = "1.0.0" @@ -171,12 +156,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "generic-array" version = "0.14.6" @@ -187,19 +166,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "globset" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -358,9 +324,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.44" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" dependencies = [ "unicode-ident", ] @@ -417,15 +383,6 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "serde" version = "1.0.145" @@ -519,6 +476,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "trustfall" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08b46bc8870b30f46d288a48cce399f30d08a39b36ab50489eacb851bb81c85" +dependencies = [ + "anyhow", + "trustfall_core", + "trustfall_derive", +] + [[package]] name = "trustfall-rustdoc-adapter" version = "21.5.2" @@ -529,18 +497,17 @@ dependencies = [ "rustdoc-types", "serde", "serde_json", - "trustfall_core", + "trustfall", ] [[package]] name = "trustfall_core" -version = "0.1.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9270da3f637b107458c4c84a6595a9913aab71fb20a363119d7686e759d11b" +checksum = "7af71d1100b656a92610b4286ed59d06a1ec175f0933cbe208929456fb7854cb" dependencies = [ "async-graphql-parser", "async-graphql-value", - "camino", "chrono", "itertools", "lazy_static", @@ -548,23 +515,19 @@ dependencies = [ "regex", "ron", "serde", - "serde_json", "smallvec", "thiserror", - "trustfall_filetests_macros", ] [[package]] -name = "trustfall_filetests_macros" -version = "0.2.0" +name = "trustfall_derive" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709b815561cd5fc1b4a0572ec2e35d16f9ce65895318f147ee3602bbbf6cb24b" +checksum = "486543a0d60e041e8fdf8595a8a0686173ad0071d07e11d8c228750ab28767df" dependencies = [ - "globset", "proc-macro2", "quote", "syn", - "walkdir", ] [[package]] @@ -591,17 +554,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" @@ -678,15 +630,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index cbdc7ed..756590a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ readme = "./README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -trustfall_core = "0.1.1" +trustfall = "0.3.4" rustdoc-types = "0.17.0" [dev-dependencies] diff --git a/src/adapter.rs b/src/adapter.rs index bddcac6..e051eb9 100644 --- a/src/adapter.rs +++ b/src/adapter.rs @@ -4,10 +4,13 @@ use rustdoc_types::{ Crate, Enum, Function, Id, Impl, Item, ItemEnum, Method, Path, Span, Struct, Trait, Type, Variant, }; -use trustfall_core::{ - interpreter::{Adapter, DataContext, InterpretedQuery}, - ir::{EdgeParameters, Eid, FieldValue, Vid}, - schema::Schema, +use trustfall::{ + provider::{ + resolve_coercion_with, resolve_neighbors_with, resolve_property_with, Adapter, + ContextIterator, ContextOutcomeIterator, EdgeParameters, QueryInfo, Typename, + VertexIterator, + }, + FieldValue, Schema, }; use crate::attributes::{Attribute, AttributeMetaItem}; @@ -137,15 +140,7 @@ pub enum VertexKind<'a> { FunctionParameter(&'a str), } -#[allow(dead_code)] -impl<'a> Vertex<'a> { - fn new_crate(origin: Origin, crate_: &'a IndexedCrate<'a>) -> Self { - Self { - origin, - kind: VertexKind::Crate(crate_), - } - } - +impl<'a> Typename for Vertex<'a> { /// The name of the actual runtime type of this vertex, /// intended to fulfill resolution requests for the __typename property. #[inline] @@ -180,6 +175,16 @@ impl<'a> Vertex<'a> { VertexKind::FunctionParameter(..) => "FunctionParameter", } } +} + +#[allow(dead_code)] +impl<'a> Vertex<'a> { + fn new_crate(origin: Origin, crate_: &'a IndexedCrate<'a>) -> Self { + Self { + origin, + kind: VertexKind::Crate(crate_), + } + } fn as_crate_diff(&self) -> Option<(&'a IndexedCrate<'a>, &'a IndexedCrate<'a>)> { match &self.kind { @@ -340,8 +345,8 @@ impl<'a> From<&'a Span> for VertexKind<'a> { fn get_crate_property(crate_vertex: &Vertex, field_name: &str) -> FieldValue { let crate_item = crate_vertex.as_crate().expect("vertex was not a Crate"); match field_name { - "root" => (&crate_item.root.0).into(), - "crate_version" => (&crate_item.crate_version).into(), + "root" => crate_item.root.0.clone().into(), + "crate_version" => crate_item.crate_version.clone().into(), "includes_private" => crate_item.includes_private.into(), "format_version" => crate_item.format_version.into(), _ => unreachable!("Crate property {field_name}"), @@ -351,10 +356,10 @@ fn get_crate_property(crate_vertex: &Vertex, field_name: &str) -> FieldValue { fn get_item_property(item_vertex: &Vertex, field_name: &str) -> FieldValue { let item = item_vertex.as_item().expect("vertex was not an Item"); match field_name { - "id" => (&item.id.0).into(), - "crate_id" => (&item.crate_id).into(), - "name" => (&item.name).into(), - "docs" => (&item.docs).into(), + "id" => item.id.0.clone().into(), + "crate_id" => item.crate_id.into(), + "name" => item.name.clone().into(), + "docs" => item.docs.clone().into(), "attrs" => item.attrs.clone().into(), "visibility_limit" => match &item.visibility { rustdoc_types::Visibility::Public => "public".into(), @@ -529,29 +534,16 @@ fn get_implemented_trait_property(vertex: &Vertex, field_name: &str) -> FieldVal } } -fn property_mapper<'a>( - ctx: DataContext>, - field_name: &str, - property_getter: fn(&Vertex<'a>, &str) -> FieldValue, -) -> (DataContext>, FieldValue) { - let value = match &ctx.current_token { - Some(vertex) => property_getter(vertex, field_name), - None => FieldValue::Null, - }; - (ctx, value) -} - impl<'a> Adapter<'a> for RustdocAdapter<'a> { - type DataToken = Vertex<'a>; + type Vertex = Vertex<'a>; - fn get_starting_tokens( + fn resolve_starting_vertices( &mut self, - edge: Arc, - _parameters: Option>, - _query_hint: InterpretedQuery, - _vertex_hint: Vid, - ) -> Box + 'a> { - match edge.as_ref() { + edge_name: &Arc, + _parameters: &EdgeParameters, + _query_info: &QueryInfo, + ) -> VertexIterator<'a, Self::Vertex> { + match edge_name.as_ref() { "Crate" => Box::new(std::iter::once(Vertex::new_crate( Origin::CurrentCrate, self.current_crate, @@ -563,20 +555,19 @@ impl<'a> Adapter<'a> for RustdocAdapter<'a> { kind: VertexKind::CrateDiff((self.current_crate, previous_crate)), })) } - _ => unreachable!("{edge}"), + _ => unreachable!("resolve_starting_vertices {edge_name}"), } } - fn project_property( + fn resolve_property( &mut self, - data_contexts: Box> + 'a>, - current_type_name: Arc, - field_name: Arc, - _query_hint: InterpretedQuery, - _vertex_hint: Vid, - ) -> Box, FieldValue)> + 'a> { - if field_name.as_ref() == "__typename" { - Box::new(data_contexts.map(|ctx| match &ctx.current_token { + contexts: ContextIterator<'a, Self::Vertex>, + type_name: &Arc, + property_name: &Arc, + _query_info: &QueryInfo, + ) -> ContextOutcomeIterator<'a, Self::Vertex, FieldValue> { + if property_name.as_ref() == "__typename" { + Box::new(contexts.map(|ctx| match ctx.active_vertex() { Some(vertex) => { let value = vertex.typename().into(); (ctx, value) @@ -584,184 +575,132 @@ impl<'a> Adapter<'a> for RustdocAdapter<'a> { None => (ctx, FieldValue::Null), })) } else { - match current_type_name.as_ref() { - "Crate" => { - Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_crate_property) - })) - } - "Item" => { - Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_item_property) - })) - } + let property_name = property_name.clone(); + match type_name.as_ref() { + "Crate" => resolve_property_with(contexts, move |vertex| { + get_crate_property(vertex, property_name.as_ref()) + }), + "Item" => resolve_property_with(contexts, move |vertex| { + get_item_property(vertex, property_name.as_ref()) + }), "ImplOwner" | "Struct" | "StructField" | "Enum" | "Variant" | "PlainVariant" | "TupleVariant" | "StructVariant" | "Trait" | "Function" | "Method" | "Impl" if matches!( - field_name.as_ref(), + property_name.as_ref(), "id" | "crate_id" | "name" | "docs" | "attrs" | "visibility_limit" ) => { // properties inherited from Item, accesssed on Item subtypes - Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_item_property) - })) - } - "Struct" => Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_struct_property) - })), - "Enum" => { - Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_enum_property) - })) + resolve_property_with(contexts, move |vertex| { + get_item_property(vertex, property_name.as_ref()) + }) } - "Span" => { - Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_span_property) - })) - } - "Path" => { - Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_path_property) - })) - } - "ImportablePath" => Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_importable_path_property) - })), + "Struct" => resolve_property_with(contexts, move |vertex| { + get_struct_property(vertex, property_name.as_ref()) + }), + "Enum" => resolve_property_with(contexts, move |vertex| { + get_enum_property(vertex, property_name.as_ref()) + }), + "Span" => resolve_property_with(contexts, move |vertex| { + get_span_property(vertex, property_name.as_ref()) + }), + "Path" => resolve_property_with(contexts, move |vertex| { + get_path_property(vertex, property_name.as_ref()) + }), + "ImportablePath" => resolve_property_with(contexts, move |vertex| { + get_importable_path_property(vertex, property_name.as_ref()) + }), "FunctionLike" | "Function" | "Method" - if matches!(field_name.as_ref(), "const" | "unsafe" | "async") => + if matches!(property_name.as_ref(), "const" | "unsafe" | "async") => { - Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_function_like_property) - })) - } - "FunctionParameter" => Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_function_parameter_property) - })), - "Impl" => { - Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_impl_property) - })) + resolve_property_with(contexts, move |vertex| { + get_function_like_property(vertex, property_name.as_ref()) + }) } - "Attribute" => Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_attribute_property) - })), - "AttributeMetaItem" => Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_attribute_meta_item_property) - })), - "Trait" => { - Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_trait_property) - })) - } - "ImplementedTrait" => Box::new(data_contexts.map(move |ctx| { - property_mapper(ctx, field_name.as_ref(), get_implemented_trait_property) - })), + "FunctionParameter" => resolve_property_with(contexts, move |vertex| { + get_function_parameter_property(vertex, property_name.as_ref()) + }), + "Impl" => resolve_property_with(contexts, move |vertex| { + get_impl_property(vertex, property_name.as_ref()) + }), + "Attribute" => resolve_property_with(contexts, move |vertex| { + get_attribute_property(vertex, property_name.as_ref()) + }), + "AttributeMetaItem" => resolve_property_with(contexts, move |vertex| { + get_attribute_meta_item_property(vertex, property_name.as_ref()) + }), + "Trait" => resolve_property_with(contexts, move |vertex| { + get_trait_property(vertex, property_name.as_ref()) + }), + "ImplementedTrait" => resolve_property_with(contexts, move |vertex| { + get_implemented_trait_property(vertex, property_name.as_ref()) + }), "RawType" | "ResolvedPathType" | "PrimitiveType" - if matches!(field_name.as_ref(), "name") => + if matches!(property_name.as_ref(), "name") => { - Box::new(data_contexts.map(move |ctx| { - // fields from "RawType" - property_mapper(ctx, field_name.as_ref(), get_raw_type_property) - })) + // fields from "RawType" + resolve_property_with(contexts, move |vertex| { + get_raw_type_property(vertex, property_name.as_ref()) + }) } - _ => unreachable!("project_property {current_type_name} {field_name}"), + _ => unreachable!("resolve_property {type_name} {property_name}"), } } } - fn project_neighbors( + fn resolve_neighbors( &mut self, - data_contexts: Box> + 'a>, - current_type_name: Arc, - edge_name: Arc, - parameters: Option>, - _query_hint: InterpretedQuery, - _vertex_hint: Vid, - _edge_hint: Eid, - ) -> Box< - dyn Iterator< - Item = ( - DataContext, - Box + 'a>, - ), - > + 'a, - > { - match current_type_name.as_ref() { + contexts: ContextIterator<'a, Self::Vertex>, + type_name: &Arc, + edge_name: &Arc, + parameters: &EdgeParameters, + _query_info: &QueryInfo, + ) -> ContextOutcomeIterator<'a, Self::Vertex, VertexIterator<'a, Self::Vertex>> { + match type_name.as_ref() { "CrateDiff" => match edge_name.as_ref() { - "current" => Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = match &ctx - .current_token - { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let crate_tuple = - vertex.as_crate_diff().expect("vertex was not a CrateDiff"); - let neighbor = Vertex::new_crate(Origin::CurrentCrate, crate_tuple.0); - Box::new(std::iter::once(neighbor)) - } - }; - - (ctx, neighbors) - })), - "baseline" => Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = match &ctx - .current_token - { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let crate_tuple = - vertex.as_crate_diff().expect("vertex was not a CrateDiff"); - let neighbor = Vertex::new_crate(Origin::PreviousCrate, crate_tuple.1); - Box::new(std::iter::once(neighbor)) - } - }; - - (ctx, neighbors) - })), + "current" => resolve_neighbors_with(contexts, |vertex| { + let crate_tuple = vertex.as_crate_diff().expect("vertex was not a CrateDiff"); + let neighbor = Vertex::new_crate(Origin::CurrentCrate, crate_tuple.0); + Box::new(std::iter::once(neighbor)) + }), + "baseline" => resolve_neighbors_with(contexts, |vertex| { + let crate_tuple = vertex.as_crate_diff().expect("vertex was not a CrateDiff"); + let neighbor = Vertex::new_crate(Origin::PreviousCrate, crate_tuple.1); + Box::new(std::iter::once(neighbor)) + }), _ => { - unreachable!("project_neighbors {current_type_name} {edge_name} {parameters:?}") + unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}") } }, "Crate" => { match edge_name.as_ref() { - "item" => Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let crate_vertex = - vertex.as_indexed_crate().expect("vertex was not a Crate"); - - let iter = crate_vertex - .inner - .index - .values() - .filter(|item| { - // Filter out item types that are not currently supported. - matches!( - item.inner, - rustdoc_types::ItemEnum::Struct(..) - | rustdoc_types::ItemEnum::StructField(..) - | rustdoc_types::ItemEnum::Enum(..) - | rustdoc_types::ItemEnum::Variant(..) - | rustdoc_types::ItemEnum::Function(..) - | rustdoc_types::ItemEnum::Method(..) - | rustdoc_types::ItemEnum::Impl(..) - | rustdoc_types::ItemEnum::Trait(..) - ) - }) - .map(move |value| origin.make_item_vertex(value)); - Box::new(iter) - } - }; - - (ctx, neighbors) - })), - _ => unreachable!( - "project_neighbors {current_type_name} {edge_name} {parameters:?}" - ), + "item" => resolve_neighbors_with(contexts, |vertex| { + let origin = vertex.origin; + let crate_vertex = + vertex.as_indexed_crate().expect("vertex was not a Crate"); + + let iter = crate_vertex + .inner + .index + .values() + .filter(|item| { + // Filter out item types that are not currently supported. + matches!( + item.inner, + rustdoc_types::ItemEnum::Struct(..) + | rustdoc_types::ItemEnum::StructField(..) + | rustdoc_types::ItemEnum::Enum(..) + | rustdoc_types::ItemEnum::Variant(..) + | rustdoc_types::ItemEnum::Function(..) + | rustdoc_types::ItemEnum::Method(..) + | rustdoc_types::ItemEnum::Impl(..) + | rustdoc_types::ItemEnum::Trait(..) + ) + }) + .map(move |value| origin.make_item_vertex(value)); + Box::new(iter) + }), + _ => unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}"), } } "Importable" | "ImplOwner" | "Struct" | "Enum" | "Trait" | "Function" @@ -771,78 +710,52 @@ impl<'a> Adapter<'a> for RustdocAdapter<'a> { "canonical_path" => { let current_crate = self.current_crate; let previous_crate = self.previous_crate; + resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let item = vertex.as_item().expect("vertex was not an Item"); + let item_id = &item.id; - Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let item = - vertex.as_item().expect("vertex was not an Item"); - let item_id = &item.id; - - if let Some(path) = match origin { - Origin::CurrentCrate => current_crate - .inner - .paths - .get(item_id) - .map(|x| &x.path), - Origin::PreviousCrate => previous_crate - .expect("no baseline provided") - .inner - .paths - .get(item_id) - .map(|x| &x.path), - } { - Box::new(std::iter::once(origin.make_path_vertex(path))) - } else { - Box::new(std::iter::empty()) - } - } - }; - - (ctx, neighbors) - })) + if let Some(path) = match origin { + Origin::CurrentCrate => { + current_crate.inner.paths.get(item_id).map(|x| &x.path) + } + Origin::PreviousCrate => previous_crate + .expect("no baseline provided") + .inner + .paths + .get(item_id) + .map(|x| &x.path), + } { + Box::new(std::iter::once(origin.make_path_vertex(path))) + } else { + Box::new(std::iter::empty()) + } + }) } "importable_path" => { let current_crate = self.current_crate; let previous_crate = self.previous_crate; + resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let item = vertex.as_item().expect("vertex was not an Item"); + let item_id = &item.id; - Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let item = - vertex.as_item().expect("vertex was not an Item"); - let item_id = &item.id; - - let parent_crate = match origin { - Origin::CurrentCrate => current_crate, - Origin::PreviousCrate => { - previous_crate.expect("no baseline provided") - } - }; - - Box::new( - parent_crate - .publicly_importable_names(item_id) - .into_iter() - .map(move |x| { - origin.make_importable_path_vertex(x) - }), - ) - } - }; + let parent_crate = match origin { + Origin::CurrentCrate => current_crate, + Origin::PreviousCrate => { + previous_crate.expect("no baseline provided") + } + }; - (ctx, neighbors) - })) + Box::new( + parent_crate + .publicly_importable_names(item_id) + .into_iter() + .map(move |x| origin.make_importable_path_vertex(x)), + ) + }) } - _ => unreachable!( - "project_neighbors {current_type_name} {edge_name} {parameters:?}" - ), + _ => unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}"), } } "Item" | "ImplOwner" | "Struct" | "StructField" | "Enum" | "Variant" @@ -851,41 +764,23 @@ impl<'a> Adapter<'a> for RustdocAdapter<'a> { if matches!(edge_name.as_ref(), "span" | "attribute") => { match edge_name.as_ref() { - "span" => Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let item = vertex.as_item().expect("vertex was not an Item"); - if let Some(span) = &item.span { - Box::new(std::iter::once(origin.make_span_vertex(span))) - } else { - Box::new(std::iter::empty()) - } - } - }; - - (ctx, neighbors) - })), - "attribute" => Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let item = vertex.as_item().expect("vertex was not an Item"); - Box::new(item.attrs.iter().map(move |attr| { - origin.make_attribute_vertex(Attribute::new(attr.as_str())) - })) - } - }; - - (ctx, neighbors) - })), - _ => unreachable!( - "project_neighbors {current_type_name} {edge_name} {parameters:?}" - ), + "span" => resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let item = vertex.as_item().expect("vertex was not an Item"); + if let Some(span) = &item.span { + Box::new(std::iter::once(origin.make_span_vertex(span))) + } else { + Box::new(std::iter::empty()) + } + }), + "attribute" => resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let item = vertex.as_item().expect("vertex was not an Item"); + Box::new(item.attrs.iter().map(move |attr| { + origin.make_attribute_vertex(Attribute::new(attr.as_str())) + })) + }), + _ => unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}"), } } "ImplOwner" | "Struct" | "Enum" @@ -894,465 +789,367 @@ impl<'a> Adapter<'a> for RustdocAdapter<'a> { let current_crate = self.current_crate; let previous_crate = self.previous_crate; let inherent_impls_only = edge_name.as_ref() == "inherent_impl"; - Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let item_index = match origin { - Origin::CurrentCrate => ¤t_crate.inner.index, - Origin::PreviousCrate => { - &previous_crate - .expect("no previous crate provided") - .inner - .index - } - }; - - // Get the IDs of all the impl blocks. - // Relies on the fact that only structs and enums can have impls, - // so we know that the vertex must represent either a struct or an enum. - let impl_ids = vertex - .as_struct_item() - .map(|(_, s)| &s.impls) - .or_else(|| vertex.as_enum().map(|e| &e.impls)) - .expect("vertex was neither a struct nor an enum"); - - Box::new(impl_ids.iter().filter_map(move |item_id| { - let next_item = item_index.get(item_id); - next_item.and_then(|next_item| match &next_item.inner { - rustdoc_types::ItemEnum::Impl(imp) => { - if !inherent_impls_only || imp.trait_.is_none() { - Some(origin.make_item_vertex(next_item)) - } else { - None - } - } - _ => None, - }) - })) - } - }; - - (ctx, neighbors) - })) - } - "Function" | "Method" | "FunctionLike" if matches!(edge_name.as_ref(), "parameter") => { - Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = match &ctx - .current_token - { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let decl = vertex.as_function().map(|f| &f.decl).unwrap_or_else(|| { - &vertex - .as_method() - .expect("vertex was neither a Function nor a Method") - .decl - }); - - Box::new(decl.inputs.iter().map(move |(name, _type_)| { - origin.make_function_parameter_vertex(name) - })) + resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let item_index = match origin { + Origin::CurrentCrate => ¤t_crate.inner.index, + Origin::PreviousCrate => { + &previous_crate + .expect("no previous crate provided") + .inner + .index } }; - (ctx, neighbors) - })) + // Get the IDs of all the impl blocks. + // Relies on the fact that only structs and enums can have impls, + // so we know that the vertex must represent either a struct or an enum. + let impl_ids = vertex + .as_struct_item() + .map(|(_, s)| &s.impls) + .or_else(|| vertex.as_enum().map(|e| &e.impls)) + .expect("vertex was neither a struct nor an enum"); + + Box::new(impl_ids.iter().filter_map(move |item_id| { + let next_item = item_index.get(item_id); + next_item.and_then(|next_item| match &next_item.inner { + rustdoc_types::ItemEnum::Impl(imp) => { + if !inherent_impls_only || imp.trait_.is_none() { + Some(origin.make_item_vertex(next_item)) + } else { + None + } + } + _ => None, + }) + })) + }) + } + "Function" | "Method" | "FunctionLike" if matches!(edge_name.as_ref(), "parameter") => { + resolve_neighbors_with(contexts, |vertex| { + let origin = vertex.origin; + let decl = vertex.as_function().map(|f| &f.decl).unwrap_or_else(|| { + &vertex + .as_method() + .expect("vertex was neither a Function nor a Method") + .decl + }); + + Box::new( + decl.inputs + .iter() + .map(move |(name, _type_)| origin.make_function_parameter_vertex(name)), + ) + }) } "Struct" => match edge_name.as_ref() { "field" => { let current_crate = self.current_crate; let previous_crate = self.previous_crate; - Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = match &ctx - .current_token - { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let (_, struct_item) = - vertex.as_struct_item().expect("vertex was not a Struct"); - - let item_index = match origin { - Origin::CurrentCrate => ¤t_crate.inner.index, - Origin::PreviousCrate => { - &previous_crate - .expect("no previous crate provided") - .inner - .index - } - }; - - let field_ids_iter: Box> = - match &struct_item.kind { - rustdoc_types::StructKind::Unit => { - Box::new(std::iter::empty()) - } - rustdoc_types::StructKind::Tuple(field_ids) => { - Box::new(field_ids.iter().filter_map(|x| x.as_ref())) - } - rustdoc_types::StructKind::Plain { fields, .. } => { - Box::new(fields.iter()) - } - }; + resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let (_, struct_item) = + vertex.as_struct_item().expect("vertex was not a Struct"); + + let item_index = match origin { + Origin::CurrentCrate => ¤t_crate.inner.index, + Origin::PreviousCrate => { + &previous_crate + .expect("no previous crate provided") + .inner + .index + } + }; - Box::new(field_ids_iter.map(move |field_id| { - origin.make_item_vertex( - item_index.get(field_id).expect("missing item"), - ) - })) + let field_ids_iter: Box> = match &struct_item.kind + { + rustdoc_types::StructKind::Unit => Box::new(std::iter::empty()), + rustdoc_types::StructKind::Tuple(field_ids) => { + Box::new(field_ids.iter().filter_map(|x| x.as_ref())) + } + rustdoc_types::StructKind::Plain { fields, .. } => { + Box::new(fields.iter()) } }; - (ctx, neighbors) - })) + Box::new(field_ids_iter.map(move |field_id| { + origin.make_item_vertex(item_index.get(field_id).expect("missing item")) + })) + }) } _ => { - unreachable!("project_neighbors {current_type_name} {edge_name} {parameters:?}") + unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}") } }, - "Variant" | "PlainVariant" | "TupleVariant" | "StructVariant" => match edge_name - .as_ref() - { - "field" => { - let current_crate = self.current_crate; - let previous_crate = self.previous_crate; - Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(token) => { - let origin = token.origin; - let item = token.as_variant().expect("token was not a Variant"); - let item_index = match origin { - Origin::CurrentCrate => ¤t_crate.inner.index, - Origin::PreviousCrate => { - &previous_crate - .expect("no previous crate provided") - .inner - .index - } - }; - - match item { - Variant::Plain(_) => Box::new(std::iter::empty()), - Variant::Tuple(fields) => { - Box::new(fields.iter().filter(|x| x.is_some()).map( - move |field_id| { - origin.make_item_vertex( - item_index - .get(field_id.as_ref().unwrap()) - .expect("missing item"), - ) - }, - )) - } - Variant::Struct { - fields, - fields_stripped: _, - } => Box::new(fields.iter().map(move |field_id| { - origin.make_item_vertex( - item_index.get(field_id).expect("missing item"), - ) - })), - } + "Variant" | "PlainVariant" | "TupleVariant" | "StructVariant" => { + match edge_name.as_ref() { + "field" => { + let current_crate = self.current_crate; + let previous_crate = self.previous_crate; + resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let item = vertex.as_variant().expect("vertex was not a Variant"); + let item_index = match origin { + Origin::CurrentCrate => ¤t_crate.inner.index, + Origin::PreviousCrate => { + &previous_crate + .expect("no previous crate provided") + .inner + .index } }; - (ctx, neighbors) - })) - } - _ => { - unreachable!("project_neighbors {current_type_name} {edge_name} {parameters:?}") + match item { + Variant::Plain(_) => Box::new(std::iter::empty()), + Variant::Tuple(fields) => Box::new( + fields.iter().filter(|x| x.is_some()).map(move |field_id| { + origin.make_item_vertex( + item_index + .get(field_id.as_ref().unwrap()) + .expect("missing item"), + ) + }), + ), + Variant::Struct { + fields, + fields_stripped: _, + } => Box::new(fields.iter().map(move |field_id| { + origin.make_item_vertex( + item_index.get(field_id).expect("missing item"), + ) + })), + } + }) + } + _ => { + unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}") + } } - }, + } "Enum" => match edge_name.as_ref() { "variant" => { let current_crate = self.current_crate; let previous_crate = self.previous_crate; - Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = match &ctx - .current_token - { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let enum_item = vertex.as_enum().expect("vertex was not an Enum"); - - let item_index = match origin { - Origin::CurrentCrate => ¤t_crate.inner.index, - Origin::PreviousCrate => { - &previous_crate - .expect("no previous crate provided") - .inner - .index - } - }; - Box::new(enum_item.variants.iter().map(move |field_id| { - origin.make_item_vertex( - item_index.get(field_id).expect("missing item"), - ) - })) + resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let enum_item = vertex.as_enum().expect("vertex was not an Enum"); + + let item_index = match origin { + Origin::CurrentCrate => ¤t_crate.inner.index, + Origin::PreviousCrate => { + &previous_crate + .expect("no previous crate provided") + .inner + .index } }; - - (ctx, neighbors) - })) + Box::new(enum_item.variants.iter().map(move |field_id| { + origin.make_item_vertex(item_index.get(field_id).expect("missing item")) + })) + }) } _ => { - unreachable!("project_neighbors {current_type_name} {edge_name} {parameters:?}") + unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}") } }, "StructField" => match edge_name.as_ref() { - "raw_type" => Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let (_, field_type) = vertex - .as_struct_field_item() - .expect("not a StructField vertex"); - Box::new(std::iter::once(origin.make_raw_type_vertex(field_type))) - } - }; - - (ctx, neighbors) - })), + "raw_type" => resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let (_, field_type) = vertex + .as_struct_field_item() + .expect("not a StructField vertex"); + Box::new(std::iter::once(origin.make_raw_type_vertex(field_type))) + }), _ => { - unreachable!("project_neighbors {current_type_name} {edge_name} {parameters:?}") + unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}") } }, - "Impl" => { - match edge_name.as_ref() { - "method" => { - let current_crate = self.current_crate; - let previous_crate = self.previous_crate; - Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = match &ctx - .current_token - { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let item_index = match origin { - Origin::CurrentCrate => ¤t_crate.inner.index, - Origin::PreviousCrate => { - &previous_crate.expect("no previous crate provided").inner.index - } - }; - - let impl_vertex = vertex.as_impl().expect("not an Impl vertex"); - let provided_methods: Box> = if impl_vertex.provided_trait_methods.is_empty() { - Box::new(std::iter::empty()) - } else { - let method_names: BTreeSet<&str> = impl_vertex.provided_trait_methods.iter().map(|x| x.as_str()).collect(); - - let trait_path = impl_vertex.trait_.as_ref().expect("no trait but provided_trait_methods was non-empty"); - let trait_item = item_index.get(&trait_path.id); - - if let Some(trait_item) = trait_item { - if let ItemEnum::Trait(trait_item) = &trait_item.inner { - Box::new(trait_item.items.iter().filter(move |item_id| { - let next_item = &item_index.get(item_id); - if let Some(name) = next_item.and_then(|x| x.name.as_deref()) { - method_names.contains(name) - } else { - false - } - })) - } else { - unreachable!("found a non-trait type {trait_item:?}"); - } - } else { - Box::new(std::iter::empty()) - } - }; - Box::new(provided_methods.chain(impl_vertex.items.iter()).filter_map(move |item_id| { - let next_item = &item_index.get(item_id); - if let Some(next_item) = next_item { - match &next_item.inner { - rustdoc_types::ItemEnum::Method(..) => { - Some(origin.make_item_vertex(next_item)) - } - _ => None, - } - } else { - None - } - })) + "Impl" => match edge_name.as_ref() { + "method" => { + let current_crate = self.current_crate; + let previous_crate = self.previous_crate; + resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let item_index = match origin { + Origin::CurrentCrate => ¤t_crate.inner.index, + Origin::PreviousCrate => { + &previous_crate + .expect("no previous crate provided") + .inner + .index } }; - (ctx, neighbors) - })) - } - "implemented_trait" => { - let current_crate = self.current_crate; - let previous_crate = self.previous_crate; - Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - let item_index = match origin { - Origin::CurrentCrate => ¤t_crate.inner.index, - Origin::PreviousCrate => { - &previous_crate - .expect("no previous crate provided") - .inner - .index - } - }; - - let impl_vertex = - vertex.as_impl().expect("not an Impl vertex"); - - if let Some(path) = &impl_vertex.trait_ { - if let Some(item) = item_index.get(&path.id) { - Box::new(std::iter::once( - origin - .make_implemented_trait_vertex(path, item), - )) + let impl_vertex = vertex.as_impl().expect("not an Impl vertex"); + let provided_methods: Box> = + if impl_vertex.provided_trait_methods.is_empty() { + Box::new(std::iter::empty()) + } else { + let method_names: BTreeSet<&str> = impl_vertex + .provided_trait_methods + .iter() + .map(|x| x.as_str()) + .collect(); + + let trait_path = impl_vertex + .trait_ + .as_ref() + .expect("no trait but provided_trait_methods was non-empty"); + let trait_item = item_index.get(&trait_path.id); + + if let Some(trait_item) = trait_item { + if let ItemEnum::Trait(trait_item) = &trait_item.inner { + Box::new(trait_item.items.iter().filter(move |item_id| { + let next_item = &item_index.get(item_id); + if let Some(name) = + next_item.and_then(|x| x.name.as_deref()) + { + method_names.contains(name) } else { - Box::new(std::iter::empty()) + false } - } else { - Box::new(std::iter::empty()) + })) + } else { + unreachable!("found a non-trait type {trait_item:?}"); + } + } else { + Box::new(std::iter::empty()) + } + }; + Box::new(provided_methods.chain(impl_vertex.items.iter()).filter_map( + move |item_id| { + let next_item = &item_index.get(item_id); + if let Some(next_item) = next_item { + match &next_item.inner { + rustdoc_types::ItemEnum::Method(..) => { + Some(origin.make_item_vertex(next_item)) } + _ => None, } - }; - - (ctx, neighbors) - })) - } - _ => { - unreachable!( - "project_neighbors {current_type_name} {edge_name} {parameters:?}" - ) - } + } else { + None + } + }, + )) + }) } - } - "ImplementedTrait" => match edge_name.as_ref() { - "trait" => Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - - let (_, trait_item) = vertex - .as_implemented_trait() - .expect("vertex was not an ImplementedTrait"); - Box::new(std::iter::once(origin.make_item_vertex(trait_item))) + "implemented_trait" => { + let current_crate = self.current_crate; + let previous_crate = self.previous_crate; + resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + let item_index = match origin { + Origin::CurrentCrate => ¤t_crate.inner.index, + Origin::PreviousCrate => { + &previous_crate + .expect("no previous crate provided") + .inner + .index } }; - (ctx, neighbors) - })), + let impl_vertex = vertex.as_impl().expect("not an Impl vertex"); + if let Some(path) = &impl_vertex.trait_ { + if let Some(item) = item_index.get(&path.id) { + Box::new(std::iter::once( + origin.make_implemented_trait_vertex(path, item), + )) + } else { + Box::new(std::iter::empty()) + } + } else { + Box::new(std::iter::empty()) + } + }) + } _ => { - unreachable!("project_neighbors {current_type_name} {edge_name} {parameters:?}") + unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}") } }, - "Attribute" => match edge_name.as_ref() { - "content" => Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = match &ctx - .current_token - { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - - let attribute = - vertex.as_attribute().expect("vertex was not an Attribute"); - Box::new(std::iter::once( - origin.make_attribute_meta_item_vertex(attribute.content.clone()), - )) - } - }; - - (ctx, neighbors) - })), + "ImplementedTrait" => match edge_name.as_ref() { + "trait" => resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + + let (_, trait_item) = vertex + .as_implemented_trait() + .expect("vertex was not an ImplementedTrait"); + Box::new(std::iter::once(origin.make_item_vertex(trait_item))) + }), _ => { - unreachable!("project_neighbors {current_type_name} {edge_name} {parameters:?}") + unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}") } }, - "AttributeMetaItem" => match edge_name.as_ref() { - "argument" => Box::new(data_contexts.map(move |ctx| { - let neighbors: Box + 'a> = - match &ctx.current_token { - None => Box::new(std::iter::empty()), - Some(vertex) => { - let origin = vertex.origin; - - let meta_item = vertex - .as_attribute_meta_item() - .expect("vertex was not an AttributeMetaItem"); - if let Some(arguments) = meta_item.arguments.clone() { - Box::new(arguments.into_iter().map(move |argument| { - origin.make_attribute_meta_item_vertex(argument) - })) - } else { - Box::new(std::iter::empty()) - } - } - }; - - (ctx, neighbors) - })), + "Attribute" => match edge_name.as_ref() { + "content" => resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + + let attribute = vertex.as_attribute().expect("vertex was not an Attribute"); + Box::new(std::iter::once( + origin.make_attribute_meta_item_vertex(attribute.content.clone()), + )) + }), _ => { - unreachable!("project_neighbors {current_type_name} {edge_name} {parameters:?}") + unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}") } }, - _ => unreachable!("project_neighbors {current_type_name} {edge_name} {parameters:?}"), + "AttributeMetaItem" => { + match edge_name.as_ref() { + "argument" => resolve_neighbors_with(contexts, move |vertex| { + let origin = vertex.origin; + + let meta_item = vertex + .as_attribute_meta_item() + .expect("vertex was not an AttributeMetaItem"); + if let Some(arguments) = meta_item.arguments.clone() { + Box::new(arguments.into_iter().map(move |argument| { + origin.make_attribute_meta_item_vertex(argument) + })) + } else { + Box::new(std::iter::empty()) + } + }), + _ => { + unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}") + } + } + } + _ => unreachable!("resolve_neighbors {type_name} {edge_name} {parameters:?}"), } } - fn can_coerce_to_type( + fn resolve_coercion( &mut self, - data_contexts: Box> + 'a>, - current_type_name: Arc, - coerce_to_type_name: Arc, - _query_hint: InterpretedQuery, - _vertex_hint: Vid, - ) -> Box, bool)> + 'a> { - match current_type_name.as_ref() { + contexts: ContextIterator<'a, Self::Vertex>, + type_name: &Arc, + coerce_to_type: &Arc, + _query_info: &QueryInfo, + ) -> ContextOutcomeIterator<'a, Self::Vertex, bool> { + let coerce_to_type = coerce_to_type.clone(); + match type_name.as_ref() { "Item" | "Variant" | "FunctionLike" | "Importable" | "ImplOwner" | "RawType" | "ResolvedPathType" => { - Box::new(data_contexts.map(move |ctx| { - let can_coerce = match &ctx.current_token { - None => false, - Some(vertex) => { - let actual_type_name = vertex.typename(); - - match coerce_to_type_name.as_ref() { - "Variant" => matches!( - actual_type_name, - "PlainVariant" | "TupleVariant" | "StructVariant" - ), - "ImplOwner" => matches!(actual_type_name, "Struct" | "Enum"), - "ResolvedPathType" => matches!( - actual_type_name, - "ResolvedPathType" | "ImplementedTrait" - ), - _ => { - // The remaining types are final (don't have any subtypes) - // so we can just compare the actual type name to - // the type we are attempting to coerce to. - actual_type_name == coerce_to_type_name.as_ref() - } - } + resolve_coercion_with(contexts, move |vertex| { + let actual_type_name = vertex.typename(); + + match coerce_to_type.as_ref() { + "Variant" => matches!( + actual_type_name, + "PlainVariant" | "TupleVariant" | "StructVariant" + ), + "ImplOwner" => matches!(actual_type_name, "Struct" | "Enum"), + "ResolvedPathType" => { + matches!(actual_type_name, "ResolvedPathType" | "ImplementedTrait") } - }; - - (ctx, can_coerce) - })) + _ => { + // The remaining types are final (don't have any subtypes) + // so we can just compare the actual type name to + // the type we are attempting to coerce to. + actual_type_name == coerce_to_type.as_ref() + } + } + }) } - _ => unreachable!("can_coerce_to_type {current_type_name} {coerce_to_type_name}"), + _ => unreachable!("resolve_coercion {type_name} {coerce_to_type}"), } } }