use syn::{Ident, Path, parse_quote};
use crate::{
correlations::{CorrelationId, Correlations},
part::TablePath,
path_ext::PathExt,
scopes::{ScopeId, Scopes},
};
#[derive(Debug)]
pub enum InferredType<'a> {
RustType(&'a Path),
Scope {
scope_id: ScopeId,
table: Option<&'a Ident>,
column: &'a Ident,
},
Correlation {
correlation_id: CorrelationId,
column: &'a Ident,
nullable: bool,
},
TableColumn {
table_path: &'a TablePath,
column: &'a Ident,
},
}
#[must_use]
pub fn resolve_type(
correlations: &Correlations<'_>,
scopes: &Scopes<'_>,
correlation_id: CorrelationId,
column: &Ident,
) -> Option<Path> {
let mut inferred_type = correlations.infer_type(correlation_id, column)?;
let mut combined_nullable = false;
for _ in 0..1024 {
match inferred_type {
InferredType::RustType(rust_type) => return Some(rust_type.clone()),
InferredType::Scope {
scope_id,
table,
column,
} => {
inferred_type = scopes.infer_type(scope_id, table, column)?;
}
InferredType::Correlation {
correlation_id,
column,
nullable,
} => {
combined_nullable = combined_nullable || nullable;
inferred_type = correlations.infer_type(correlation_id, column)?;
}
InferredType::TableColumn { table_path, column } => {
let table_path = table_path.as_path().to_call_site(1);
if combined_nullable {
return Some(
parse_quote!(::core::option::Option<#table_path::columns::#column::TypeNotNull>),
);
}
return Some(parse_quote!(#table_path::columns::#column::Type));
}
}
}
panic!("infinite type inference loop detected");
}