Path: blob/main/crates/polars-plan/src/plans/aexpr/function_expr/schema.rs
8391 views
use polars_core::utils::materialize_dyn_int;12use super::*;34impl IRFunctionExpr {5pub(crate) fn get_field(6&self,7_input_schema: &Schema,8fields: &[Field],9) -> PolarsResult<Field> {10use IRFunctionExpr::*;1112let mapper = FieldsMapper { fields };13match self {14// Namespaces15#[cfg(feature = "dtype-array")]16ArrayExpr(func) => func.get_field(mapper),17BinaryExpr(s) => s.get_field(mapper),18#[cfg(feature = "dtype-categorical")]19Categorical(func) => func.get_field(mapper),20#[cfg(feature = "dtype-extension")]21Extension(func) => func.get_field(mapper),22ListExpr(func) => func.get_field(mapper),23#[cfg(feature = "strings")]24StringExpr(s) => s.get_field(mapper),25#[cfg(feature = "dtype-struct")]26StructExpr(s) => s.get_field(mapper),27#[cfg(feature = "temporal")]28TemporalExpr(fun) => fun.get_field(mapper),29#[cfg(feature = "bitwise")]30Bitwise(fun) => fun.get_field(mapper),3132// Other expressions33Boolean(func) => func.get_field(mapper),34#[cfg(feature = "business")]35Business(func) => func.get_field(mapper),36#[cfg(feature = "abs")]37Abs => mapper.with_same_dtype(),38Negate => mapper.with_same_dtype(),39NullCount => mapper.with_dtype(IDX_DTYPE),40Pow(pow_function) => match pow_function {41IRPowFunction::Generic => mapper.pow_dtype(),42_ => mapper.map_numeric_to_float_dtype(true),43},44Coalesce => mapper.map_to_supertype(),45#[cfg(feature = "row_hash")]46Hash(..) => mapper.with_dtype(DataType::UInt64),47#[cfg(feature = "arg_where")]48ArgWhere => mapper.with_dtype(IDX_DTYPE),49#[cfg(feature = "index_of")]50IndexOf => mapper.with_dtype(IDX_DTYPE),51#[cfg(feature = "search_sorted")]52SearchSorted { .. } => mapper.with_dtype(IDX_DTYPE),53#[cfg(feature = "range")]54Range(func) => func.get_field(mapper),55#[cfg(feature = "trigonometry")]56Trigonometry(_) => mapper.map_to_float_dtype(),57#[cfg(feature = "trigonometry")]58Atan2 => mapper.map_to_float_dtype(),59#[cfg(feature = "sign")]60Sign => mapper61.ensure_satisfies(|_, dtype| dtype.is_numeric(), "sign")?62.with_same_dtype(),63FillNull => mapper.map_to_supertype(),64#[cfg(feature = "rolling_window")]65RollingExpr { function, options } => {66use IRRollingFunction::*;67match function {68Min | Max => mapper.with_same_dtype(),69Mean | Quantile | Std => mapper.moment_dtype(),70Var => mapper.var_dtype(),71Sum => mapper.sum_dtype(),72Rank => match options.fn_params {73Some(RollingFnParams::Rank {74method: RollingRankMethod::Average,75..76}) => mapper.with_dtype(DataType::Float64),77Some(RollingFnParams::Rank { .. }) => mapper.with_dtype(IDX_DTYPE),78_ => unreachable!("should be Some(RollingFnParams::Rank)"),79},80#[cfg(feature = "cov")]81CorrCov { .. } => mapper.map_to_float_dtype(),82#[cfg(feature = "moment")]83Skew | Kurtosis => mapper.map_to_float_dtype(),84Map(_) => mapper.try_map_field(|field| {85if options.weights.is_some() {86let dtype = match field.dtype() {87#[cfg(feature = "dtype-f16")]88DataType::Float16 => DataType::Float16,89DataType::Float32 => DataType::Float32,90_ => DataType::Float64,91};92Ok(Field::new(field.name().clone(), dtype))93} else {94Ok(field.clone())95}96}),97}98},99#[cfg(feature = "rolling_window_by")]100RollingExprBy {101function_by,102options,103..104} => {105use IRRollingFunctionBy::*;106match function_by {107MinBy | MaxBy => mapper.with_same_dtype(),108MeanBy | QuantileBy | StdBy => mapper.moment_dtype(),109VarBy => mapper.var_dtype(),110SumBy => mapper.sum_dtype(),111RankBy => match options.fn_params {112Some(RollingFnParams::Rank {113method: RollingRankMethod::Average,114..115}) => mapper.with_dtype(DataType::Float64),116Some(RollingFnParams::Rank { .. }) => mapper.with_dtype(IDX_DTYPE),117_ => unreachable!("should be Some(RollingFnParams::Rank)"),118},119}120},121Rechunk => mapper.with_same_dtype(),122Append { upcast } => {123if *upcast {124mapper.map_to_supertype()125} else {126mapper.with_same_dtype()127}128},129ShiftAndFill => mapper.with_same_dtype(),130DropNans => mapper.with_same_dtype(),131DropNulls => mapper.with_same_dtype(),132#[cfg(feature = "round_series")]133Clip {134has_min: _,135has_max: _,136} => mapper.with_same_dtype(),137#[cfg(feature = "mode")]138Mode { maintain_order: _ } => mapper.with_same_dtype(),139#[cfg(feature = "moment")]140Skew(_) => mapper.with_dtype(DataType::Float64),141#[cfg(feature = "moment")]142Kurtosis(..) => mapper.with_dtype(DataType::Float64),143ArgUnique | ArgMin | ArgMax | ArgSort { .. } => mapper.with_dtype(IDX_DTYPE),144MinBy | MaxBy => mapper.with_same_dtype(),145Product => mapper.map_dtype(|dtype| {146use DataType as T;147match dtype {148#[cfg(feature = "dtype-f16")]149T::Float16 => T::Float16,150T::Float32 => T::Float32,151T::Float64 => T::Float64,152T::UInt64 => T::UInt64,153#[cfg(feature = "dtype-i128")]154T::Int128 => T::Int128,155_ => T::Int64,156}157}),158Repeat => mapper.with_same_dtype(),159#[cfg(feature = "rank")]160Rank { options, .. } => mapper.with_dtype(match options.method {161RankMethod::Average => DataType::Float64,162_ => IDX_DTYPE,163}),164#[cfg(feature = "dtype-struct")]165AsStruct => {166let mut field_names = PlHashSet::with_capacity(fields.len() - 1);167let struct_fields = fields168.iter()169.map(|f| {170polars_ensure!(171field_names.insert(f.name.as_str()),172duplicate_field = f.name()173);174Ok(f.clone())175})176.collect::<PolarsResult<Vec<_>>>()?;177Ok(Field::new(178fields[0].name().clone(),179DataType::Struct(struct_fields),180))181},182#[cfg(feature = "top_k")]183TopK { .. } => mapper.with_same_dtype(),184#[cfg(feature = "top_k")]185TopKBy { .. } => mapper.with_same_dtype(),186#[cfg(feature = "dtype-struct")]187ValueCounts {188sort: _,189parallel: _,190name,191normalize,192} => mapper.map_dtype(|dt| {193let count_dt = if *normalize {194DataType::Float64195} else {196IDX_DTYPE197};198DataType::Struct(vec![199Field::new(fields[0].name().clone(), dt.clone()),200Field::new(name.clone(), count_dt),201])202}),203#[cfg(feature = "unique_counts")]204UniqueCounts => mapper.with_dtype(IDX_DTYPE),205Shift | Reverse => mapper.with_same_dtype(),206#[cfg(feature = "cum_agg")]207CumCount { .. } => mapper.with_dtype(IDX_DTYPE),208#[cfg(feature = "cum_agg")]209CumSum { .. } => mapper.map_dtype(cum::dtypes::cum_sum),210#[cfg(feature = "cum_agg")]211CumProd { .. } => mapper.map_dtype(cum::dtypes::cum_prod),212#[cfg(feature = "cum_agg")]213CumMin { .. } => mapper.with_same_dtype(),214#[cfg(feature = "cum_agg")]215CumMax { .. } => mapper.with_same_dtype(),216#[cfg(feature = "approx_unique")]217ApproxNUnique => mapper.with_dtype(IDX_DTYPE),218#[cfg(feature = "hist")]219Hist {220include_category,221include_breakpoint,222..223} => {224if *include_breakpoint || *include_category {225let mut fields = Vec::with_capacity(3);226if *include_breakpoint {227fields.push(Field::new(228PlSmallStr::from_static("breakpoint"),229DataType::Float64,230));231}232if *include_category {233fields.push(Field::new(234PlSmallStr::from_static("category"),235DataType::from_categories(Categories::global()),236));237}238fields.push(Field::new(PlSmallStr::from_static("count"), IDX_DTYPE));239mapper.with_dtype(DataType::Struct(fields))240} else {241mapper.with_dtype(IDX_DTYPE)242}243},244#[cfg(feature = "diff")]245Diff(_) => mapper.map_dtype(|dt| match dt {246#[cfg(feature = "dtype-datetime")]247DataType::Datetime(tu, _) => DataType::Duration(*tu),248#[cfg(feature = "dtype-date")]249DataType::Date => DataType::Duration(TimeUnit::Microseconds),250#[cfg(feature = "dtype-time")]251DataType::Time => DataType::Duration(TimeUnit::Nanoseconds),252DataType::UInt64 | DataType::UInt32 => DataType::Int64,253DataType::UInt16 => DataType::Int32,254DataType::UInt8 => DataType::Int16,255#[cfg(feature = "dtype-decimal")]256DataType::Decimal(_, scale) => {257DataType::Decimal(polars_compute::decimal::DEC128_MAX_PREC, *scale)258},259dt => dt.clone(),260}),261#[cfg(feature = "pct_change")]262PctChange => mapper.map_dtype(|dt| match dt {263#[cfg(feature = "dtype-f16")]264DataType::Float16 => dt.clone(),265DataType::Float32 => dt.clone(),266_ => DataType::Float64,267}),268#[cfg(feature = "interpolate")]269Interpolate(method) => match method {270InterpolationMethod::Linear => mapper.map_numeric_to_float_dtype(false),271InterpolationMethod::Nearest => mapper.with_same_dtype(),272},273#[cfg(feature = "interpolate_by")]274InterpolateBy => mapper.map_numeric_to_float_dtype(true),275#[cfg(feature = "log")]276Entropy { .. } | Log1p | Exp => mapper.map_to_float_dtype(),277#[cfg(feature = "log")]278Log => mapper.log_dtype(),279Unique(_) => mapper.with_same_dtype(),280#[cfg(feature = "round_series")]281Round { .. } | RoundSF { .. } | Floor | Ceil => mapper.with_same_dtype(),282#[cfg(feature = "fused")]283Fused(_) => mapper.map_to_supertype(),284ConcatExpr(_) => mapper.map_to_supertype(),285#[cfg(feature = "cov")]286Correlation { .. } => mapper.map_to_float_dtype(),287#[cfg(feature = "peaks")]288PeakMin | PeakMax => mapper.with_dtype(DataType::Boolean),289#[cfg(feature = "cutqcut")]290Cut {291include_breaks: false,292..293} => mapper.with_dtype(DataType::from_categories(Categories::global())),294#[cfg(feature = "cutqcut")]295Cut {296include_breaks: true,297..298} => {299let struct_dt = DataType::Struct(vec![300Field::new(PlSmallStr::from_static("breakpoint"), DataType::Float64),301Field::new(302PlSmallStr::from_static("category"),303DataType::from_categories(Categories::global()),304),305]);306mapper.with_dtype(struct_dt)307},308#[cfg(feature = "repeat_by")]309RepeatBy => mapper.map_dtype(|dt| DataType::List(dt.clone().into())),310#[cfg(feature = "dtype-array")]311Reshape(dims) => mapper.try_map_dtype(|dt: &DataType| {312let mut wrapped_dtype = dt.leaf_dtype().clone();313for dim in dims[1..].iter().rev() {314let Some(array_size) = dim.get() else {315polars_bail!(InvalidOperation: "can only infer the first dimension");316};317wrapped_dtype = DataType::Array(Box::new(wrapped_dtype), array_size as usize);318}319Ok(wrapped_dtype)320}),321#[cfg(feature = "cutqcut")]322QCut {323include_breaks: false,324..325} => mapper.with_dtype(DataType::from_categories(Categories::global())),326#[cfg(feature = "cutqcut")]327QCut {328include_breaks: true,329..330} => {331let struct_dt = DataType::Struct(vec![332Field::new(PlSmallStr::from_static("breakpoint"), DataType::Float64),333Field::new(334PlSmallStr::from_static("category"),335DataType::from_categories(Categories::global()),336),337]);338mapper.with_dtype(struct_dt)339},340#[cfg(feature = "rle")]341RLE => mapper.map_dtype(|dt| {342DataType::Struct(vec![343Field::new(PlSmallStr::from_static("len"), IDX_DTYPE),344Field::new(PlSmallStr::from_static("value"), dt.clone()),345])346}),347#[cfg(feature = "rle")]348RLEID => mapper.with_dtype(IDX_DTYPE),349ToPhysical => mapper.to_physical_type(),350#[cfg(feature = "random")]351Random { .. } => mapper.with_same_dtype(),352SetSortedFlag(_) => mapper.with_same_dtype(),353#[cfg(feature = "ffi_plugin")]354FfiPlugin {355flags: _,356lib,357symbol,358kwargs,359} => unsafe { plugin::plugin_field(fields, lib, symbol.as_ref(), kwargs) },360361FoldHorizontal { return_dtype, .. } => match return_dtype {362None => mapper.with_same_dtype(),363Some(dtype) => mapper.with_dtype(dtype.clone()),364},365ReduceHorizontal { return_dtype, .. } => match return_dtype {366None => mapper.map_to_supertype(),367Some(dtype) => mapper.with_dtype(dtype.clone()),368},369#[cfg(feature = "dtype-struct")]370CumReduceHorizontal { return_dtype, .. } => match return_dtype {371None => mapper.with_dtype(DataType::Struct(fields.to_vec())),372Some(dtype) => mapper.with_dtype(DataType::Struct(373fields374.iter()375.map(|f| Field::new(f.name().clone(), dtype.clone()))376.collect(),377)),378},379#[cfg(feature = "dtype-struct")]380CumFoldHorizontal {381return_dtype,382include_init,383..384} => match return_dtype {385None => mapper.with_dtype(DataType::Struct(386fields387.iter()388.skip(usize::from(!include_init))389.map(|f| Field::new(f.name().clone(), fields[0].dtype().clone()))390.collect(),391)),392Some(dtype) => mapper.with_dtype(DataType::Struct(393fields394.iter()395.skip(usize::from(!include_init))396.map(|f| Field::new(f.name().clone(), dtype.clone()))397.collect(),398)),399},400401MaxHorizontal => mapper.map_to_supertype(),402MinHorizontal => mapper.map_to_supertype(),403SumHorizontal { .. } => mapper.map_to_supertype().map(|mut f| {404if f.dtype == DataType::Boolean {405f.dtype = IDX_DTYPE;406}407f408}),409MeanHorizontal { .. } => mapper.map_to_supertype().map(|mut f| {410match f.dtype {411#[cfg(feature = "dtype-f16")]412DataType::Float16 => {},413DataType::Float32 => {},414_ => {415f.dtype = DataType::Float64;416},417}418f419}),420#[cfg(feature = "ewma")]421EwmMean { .. } => mapper.map_numeric_to_float_dtype(true),422#[cfg(feature = "ewma_by")]423EwmMeanBy { .. } => mapper.map_numeric_to_float_dtype(true),424#[cfg(feature = "ewma")]425EwmStd { .. } => mapper.map_numeric_to_float_dtype(true),426#[cfg(feature = "ewma")]427EwmVar { .. } => mapper.var_dtype(),428#[cfg(feature = "replace")]429Replace => mapper.with_same_dtype(),430#[cfg(feature = "replace")]431ReplaceStrict { return_dtype } => mapper.replace_dtype(return_dtype.clone()),432FillNullWithStrategy(_) => mapper.with_same_dtype(),433GatherEvery { .. } => mapper.with_same_dtype(),434#[cfg(feature = "reinterpret")]435Reinterpret(signed) => {436let dt = if *signed {437DataType::Int64438} else {439DataType::UInt64440};441mapper.with_dtype(dt)442},443ExtendConstant => mapper.with_same_dtype(),444445RowEncode(..) => mapper.try_map_field(|_| {446Ok(Field::new(447PlSmallStr::from_static("row_encoded"),448DataType::BinaryOffset,449))450}),451#[cfg(feature = "dtype-struct")]452RowDecode(fields, _) => mapper.with_dtype(DataType::Struct(fields.to_vec())),453}454}455456pub(crate) fn output_name(&self) -> Option<OutputName> {457match self {458#[cfg(feature = "dtype-struct")]459IRFunctionExpr::StructExpr(IRStructFunction::FieldByName(name)) => {460Some(OutputName::Field(name.clone()))461},462_ => None,463}464}465}466467pub struct FieldsMapper<'a> {468fields: &'a [Field],469}470471impl<'a> FieldsMapper<'a> {472pub fn new(fields: &'a [Field]) -> Self {473Self { fields }474}475476pub fn args(&self) -> &[Field] {477self.fields478}479480/// Field with the same dtype.481pub fn with_same_dtype(&self) -> PolarsResult<Field> {482self.map_dtype(|dtype| dtype.clone())483}484485/// Set a dtype.486pub fn with_dtype(&self, dtype: DataType) -> PolarsResult<Field> {487Ok(Field::new(self.fields[0].name().clone(), dtype))488}489490/// Map a single dtype.491pub fn map_dtype(&self, func: impl FnOnce(&DataType) -> DataType) -> PolarsResult<Field> {492let dtype = func(self.fields[0].dtype());493Ok(Field::new(self.fields[0].name().clone(), dtype))494}495496pub fn get_fields_lens(&self) -> usize {497self.fields.len()498}499500/// Map a single field with a potentially failing mapper function.501pub fn try_map_field(502&self,503func: impl FnOnce(&Field) -> PolarsResult<Field>,504) -> PolarsResult<Field> {505func(&self.fields[0])506}507508pub fn var_dtype(&self) -> PolarsResult<Field> {509if self.fields[0].dtype().leaf_dtype().is_duration() {510let map_inner = |dt: &DataType| match dt {511dt if dt.is_temporal() => {512polars_bail!(InvalidOperation: "operation `var` is not supported for `{dt}`")513},514dt => Ok(dt.clone()),515};516517self.try_map_dtype(|dt| match dt {518#[cfg(feature = "dtype-array")]519DataType::Array(inner, _) => map_inner(inner),520DataType::List(inner) => map_inner(inner),521_ => map_inner(dt),522})523} else {524self.moment_dtype()525}526}527528pub fn moment_dtype(&self) -> PolarsResult<Field> {529let map_inner = |dt: &DataType| match dt {530DataType::Boolean => DataType::Float64,531#[cfg(feature = "dtype-f16")]532DataType::Float16 => DataType::Float16,533DataType::Float32 => DataType::Float32,534DataType::Float64 => DataType::Float64,535dt if dt.is_primitive_numeric() => DataType::Float64,536#[cfg(feature = "dtype-date")]537DataType::Date => DataType::Datetime(TimeUnit::Microseconds, None),538#[cfg(feature = "dtype-datetime")]539dt @ DataType::Datetime(_, _) => dt.clone(),540#[cfg(feature = "dtype-duration")]541dt @ DataType::Duration(_) => dt.clone(),542#[cfg(feature = "dtype-time")]543dt @ DataType::Time => dt.clone(),544#[cfg(feature = "dtype-decimal")]545DataType::Decimal(..) => DataType::Float64,546547// All other types get mapped to a single `null` of the same type.548dt => dt.clone(),549};550551self.map_dtype(|dt| match dt {552#[cfg(feature = "dtype-array")]553DataType::Array(inner, _) => map_inner(inner),554DataType::List(inner) => map_inner(inner),555_ => map_inner(dt),556})557}558559/// Map to a float supertype.560pub fn map_to_float_dtype(&self) -> PolarsResult<Field> {561self.map_dtype(|dtype| match dtype {562#[cfg(feature = "dtype-f16")]563DataType::Float16 => DataType::Float16,564DataType::Float32 => DataType::Float32,565_ => DataType::Float64,566})567}568569/// Map to a float supertype if numeric, else preserve570pub fn map_numeric_to_float_dtype(&self, coerce_decimal: bool) -> PolarsResult<Field> {571self.map_dtype(|dt| {572let should_coerce = match dt {573#[cfg(feature = "dtype-f16")]574DataType::Float16 => false,575DataType::Float32 => false,576#[cfg(feature = "dtype-decimal")]577DataType::Decimal(..) => coerce_decimal,578DataType::Boolean => true,579dt => dt.is_primitive_numeric(),580};581582if should_coerce {583DataType::Float64584} else {585dt.clone()586}587})588}589590/// Map to a physical type.591pub fn to_physical_type(&self) -> PolarsResult<Field> {592self.map_dtype(|dtype| dtype.to_physical())593}594595/// Map a single dtype with a potentially failing mapper function.596pub fn try_map_dtype(597&self,598func: impl FnOnce(&DataType) -> PolarsResult<DataType>,599) -> PolarsResult<Field> {600let dtype = func(self.fields[0].dtype())?;601Ok(Field::new(self.fields[0].name().clone(), dtype))602}603604/// Map all dtypes with a potentially failing mapper function.605pub fn try_map_dtypes(606&self,607func: impl FnOnce(&[&DataType]) -> PolarsResult<DataType>,608) -> PolarsResult<Field> {609let mut fld = self.fields[0].clone();610let dtypes = self611.fields612.iter()613.map(|fld| fld.dtype())614.collect::<Vec<_>>();615let new_type = func(&dtypes)?;616fld.coerce(new_type);617Ok(fld)618}619620/// Map the dtype to the "supertype" of all fields.621pub fn map_to_supertype(&self) -> PolarsResult<Field> {622let st = args_to_supertype(self.fields)?;623let mut first = self.fields[0].clone();624first.coerce(st);625Ok(first)626}627628/// Map the dtype to the dtype of the list/array elements.629pub fn map_to_list_and_array_inner_dtype(&self) -> PolarsResult<Field> {630let mut first = self.fields[0].clone();631let dt = first632.dtype()633.inner_dtype()634.cloned()635.unwrap_or_else(|| DataType::Unknown(Default::default()));636first.coerce(dt);637Ok(first)638}639640#[cfg(feature = "dtype-array")]641/// Map the dtype to the dtype of the array elements, with typo validation.642pub fn try_map_to_array_inner_dtype(&self) -> PolarsResult<Field> {643let dt = self.fields[0].dtype();644match dt {645DataType::Array(_, _) => self.map_to_list_and_array_inner_dtype(),646_ => polars_bail!(InvalidOperation: "expected Array type, got: {}", dt),647}648}649650/// Map the dtypes to the "supertype" of a list of lists.651pub fn map_to_list_supertype(&self) -> PolarsResult<Field> {652self.try_map_dtypes(|dts| {653let mut super_type_inner = None;654655for dt in dts {656match dt {657DataType::List(inner) => match super_type_inner {658None => super_type_inner = Some(*inner.clone()),659Some(st_inner) => {660super_type_inner = Some(try_get_supertype(&st_inner, inner)?)661},662},663dt => match super_type_inner {664None => super_type_inner = Some((*dt).clone()),665Some(st_inner) => {666super_type_inner = Some(try_get_supertype(&st_inner, dt)?)667},668},669}670}671Ok(DataType::List(Box::new(super_type_inner.unwrap())))672})673}674675/// Set the timezone of a datetime dtype.676#[cfg(feature = "timezones")]677pub fn map_datetime_dtype_timezone(&self, tz: Option<&TimeZone>) -> PolarsResult<Field> {678self.try_map_dtype(|dt| {679if let DataType::Datetime(tu, _) = dt {680Ok(DataType::Datetime(*tu, tz.cloned()))681} else {682polars_bail!(op = "replace-time-zone", got = dt, expected = "Datetime");683}684})685}686687pub fn sum_dtype(&self) -> PolarsResult<Field> {688use DataType::*;689self.map_dtype(|dtype| match dtype {690Int8 | UInt8 | Int16 | UInt16 => Int64,691Boolean => IDX_DTYPE,692dt => dt.clone(),693})694}695696pub fn nested_sum_type(&self) -> PolarsResult<Field> {697let mut first = self.fields[0].clone();698use DataType::*;699let dt = first.dtype().inner_dtype().cloned().ok_or_else(|| {700polars_err!(701InvalidOperation:"expected List or Array type, got dtype: {}",702first.dtype()703)704})?;705706match dt {707Boolean => first.coerce(IDX_DTYPE),708UInt8 | Int8 | Int16 | UInt16 => first.coerce(Int64),709_ => first.coerce(dt),710}711Ok(first)712}713714pub fn nested_mean_median_type(&self) -> PolarsResult<Field> {715let mut first = self.fields[0].clone();716use DataType::*;717let dt = first.dtype().inner_dtype().cloned().ok_or_else(|| {718polars_err!(719InvalidOperation:"expected List or Array type, got dtype: {}",720first.dtype()721)722})?;723724let new_dt = match dt {725#[cfg(feature = "dtype-datetime")]726Date => Datetime(TimeUnit::Microseconds, None),727dt if dt.is_temporal() => dt,728#[cfg(feature = "dtype-f16")]729Float16 => Float16,730Float32 => Float32,731_ => Float64,732};733first.coerce(new_dt);734Ok(first)735}736737pub(super) fn pow_dtype(&self) -> PolarsResult<Field> {738let dtype1 = self.fields[0].dtype();739let dtype2 = self.fields[1].dtype();740let out_dtype = if dtype1.is_integer() {741if dtype2.is_float() { dtype2 } else { dtype1 }742} else {743dtype1744};745Ok(Field::new(self.fields[0].name().clone(), out_dtype.clone()))746}747748pub(super) fn log_dtype(&self) -> PolarsResult<Field> {749let dtype1 = self.fields[0].dtype();750let dtype2 = self.fields[1].dtype();751let out_dtype = if dtype1.is_float() {752dtype1753} else if dtype2.is_float() {754dtype2755} else {756&DataType::Float64757};758Ok(Field::new(self.fields[0].name().clone(), out_dtype.clone()))759}760761#[cfg(feature = "extract_jsonpath")]762pub fn with_opt_dtype(&self, dtype: Option<DataType>) -> PolarsResult<Field> {763let dtype = dtype.unwrap_or_else(|| DataType::Unknown(Default::default()));764self.with_dtype(dtype)765}766767#[cfg(feature = "replace")]768pub fn replace_dtype(&self, return_dtype: Option<DataType>) -> PolarsResult<Field> {769let dtype = match return_dtype {770Some(dtype) => dtype,771None => {772let new = &self.fields[2];773let default = self.fields.get(3);774775// @HACK: Related to implicit implode see #22149.776let inner_dtype = new.dtype().inner_dtype().unwrap_or(new.dtype());777778match default {779Some(default) => try_get_supertype(default.dtype(), inner_dtype)?,780None => inner_dtype.clone(),781}782},783};784self.with_dtype(dtype)785}786787fn ensure_satisfies(788self,789mut f: impl FnMut(usize, &DataType) -> bool,790op: &'static str,791) -> PolarsResult<Self> {792for (i, field) in self.fields.iter().enumerate() {793polars_ensure!(794f(i, field.dtype()),795opidx = op,796idx = i,797self.fields[i].dtype()798);799}800801Ok(self)802}803}804805pub(crate) fn args_to_supertype<D: AsRef<DataType>>(dtypes: &[D]) -> PolarsResult<DataType> {806let mut st = dtypes[0].as_ref().clone();807for dt in &dtypes[1..] {808st = try_get_supertype(&st, dt.as_ref())?809}810811match (dtypes[0].as_ref(), &st) {812#[cfg(feature = "dtype-categorical")]813(cat @ DataType::Categorical(_, _), DataType::String) => st = cat.clone(),814_ => {815if let DataType::Unknown(kind) = st {816match kind {817UnknownKind::Float => st = DataType::Float64,818UnknownKind::Int(v) => {819st = materialize_dyn_int(v).dtype();820},821UnknownKind::Str => st = DataType::String,822_ => {},823}824}825},826}827828Ok(st)829}830831832