diff --git a/rs/src/output/diagnostic.rs b/rs/src/output/diagnostic.rs index 473f55a1..f231c850 100644 --- a/rs/src/output/diagnostic.rs +++ b/rs/src/output/diagnostic.rs @@ -237,6 +237,9 @@ pub enum Classification { #[strum(props(HiddenDescription = "use of anchor zero"))] LinkAnchorZero = 3005, + #[strum(props(Description = "failed to resolve type variation name & class pair"))] + LinkMissingTypeVariationNameAndClass = 3006, + // Type-related diagnostics (group 4). #[strum(props(HiddenDescription = "type-related diagnostics"))] Type = 4000, diff --git a/rs/src/output/extension.rs b/rs/src/output/extension.rs index f379217f..fef2d2e5 100644 --- a/rs/src/output/extension.rs +++ b/rs/src/output/extension.rs @@ -168,6 +168,9 @@ pub struct YamlData { /// Reference to the parsed YAML data, if any. pub data: tree::NodeReference, + /// YAML extension files that this extension depends on. + pub dependencies: HashMap, + /// Functions defined in this YAML file. Names are stored in lower case /// (Substrait's name resolution is case-insensitive). pub functions: HashMap>, @@ -178,9 +181,7 @@ pub struct YamlData { /// Type variations defined in this YAML file. Names are stored in lower /// case (Substrait's name resolution is case-insensitive). - /// FIXME: this declaration to definition map is insufficient. See - /// - pub type_variations: HashMap>, + pub type_variations: HashMap>, } impl YamlData { @@ -194,6 +195,7 @@ impl YamlData { path: path::Path::Root("").to_path_buf(), node: Arc::new(tree::NodeType::YamlMap.into()), }, + dependencies: HashMap::default(), functions: HashMap::default(), types: HashMap::default(), type_variations: HashMap::default(), @@ -213,27 +215,44 @@ impl YamlData { }) } - /// Resolves a function defined in this YAML data block by name. Returns an - /// unresolved reference if it does not exist. + /// Resolves a function defined in this YAML data block by the given + /// lowercase name. Returns an unresolved reference if it does not exist. pub fn resolve_function(&self, name: S) -> Arc> { let name = name.to_string(); let maybe_def = self.functions.get(&name).cloned(); self.local_reference(name, maybe_def) } - /// Resolves a type defined in this YAML data block by name. Returns an - /// unresolved reference if it does not exist. + /// Resolves a type defined in this YAML data block by the given lowercase + /// name. Returns an unresolved reference if it does not exist. pub fn resolve_type(&self, name: S) -> data::class::UserDefined { let name = name.to_string(); let maybe_def = self.types.get(&name).cloned(); self.local_reference(name, maybe_def) } - /// Resolves a type variation defined in this YAML data block by name. - /// Returns an unresolved reference if it does not exist. - pub fn resolve_type_variation(&self, name: S) -> data::variation::UserDefined { + /// Resolves all type variations defined in this YAML data block by the + /// given lowercase name. Returns an unresolved reference if none exist. + pub fn resolve_type_variations_by_name( + &self, + name: S, + ) -> data::variation::UserDefinedByName { let name = name.to_string(); - let maybe_def = self.type_variations.get(&name).cloned(); + let maybe_def = self + .type_variations + .get(&name) + .filter(|x| !x.variations.is_empty()) + .cloned(); self.local_reference(name, maybe_def) } + + /// Resolves all type variations defined in this YAML data block by the + /// given lowercase name. Returns an unresolved reference if none exist. + pub fn resolve_type_variation( + &self, + name: S, + base: &data::Class, + ) -> data::variation::UserDefined { + data::variation::resolve_by_class(&self.resolve_type_variations_by_name(name), base) + } } diff --git a/rs/src/output/type_system/data/variation.rs b/rs/src/output/type_system/data/variation.rs index 05bc8799..ce06c156 100644 --- a/rs/src/output/type_system/data/variation.rs +++ b/rs/src/output/type_system/data/variation.rs @@ -84,3 +84,32 @@ impl Default for FunctionBehavior { FunctionBehavior::Inherits } } + +/// A reference to one or more user-defined type variations going by the same +/// name, distinguished by their base type class. +pub type UserDefinedByName = Arc>; + +/// A group of one or more variation definitions using a single name. Note: +/// multiple variations can be defined with the same name, because names are +/// scoped to the type class they are defined for. See +/// . +#[derive(Clone, Debug, PartialEq, Eq, Default)] +pub struct UserDefinedDefinitions { + pub variations: Vec>, +} + +/// Resolve a reference to a set of variations going by the same name to a +/// single variation indexed by its base class. Returns an unresolved reference +/// if it does not exist. +pub fn resolve_by_class(variations: &UserDefinedByName, base: &data::Class) -> UserDefined { + let definition = variations + .definition + .as_ref() + .and_then(|x| x.variations.iter().find(|x| &x.base == base)) + .cloned(); + Arc::new(extension::Reference { + name: variations.name.clone(), + uri: variations.uri.clone(), + definition, + }) +} diff --git a/rs/src/parse/context.rs b/rs/src/parse/context.rs index e4703085..86b9ee20 100644 --- a/rs/src/parse/context.rs +++ b/rs/src/parse/context.rs @@ -305,7 +305,7 @@ impl<'a> Context<'a> { &mut self.state.types } - /// Registers a type definition. Shorthand for fns().define(), using the + /// Registers a type definition. Shorthand for types().define(), using the /// current path as the registration path. pub fn define_type( &mut self, @@ -318,17 +318,17 @@ impl<'a> Context<'a> { } /// Returns the resolver for type variation anchors and references. - pub fn tvars(&mut self) -> &mut Resolver { + pub fn tvars(&mut self) -> &mut Resolver { &mut self.state.type_variations } - /// Registers a type definition. Shorthand for fns().define(), using the + /// Registers a type definition. Shorthand for tvars().define(), using the /// current path as the registration path. pub fn define_tvar( &mut self, anchor: u32, - variation: data::variation::UserDefined, - ) -> Result<(), (data::variation::UserDefined, path::PathBuf)> { + variation: data::variation::UserDefinedByName, + ) -> Result<(), (data::variation::UserDefinedByName, path::PathBuf)> { self.state .type_variations .define(anchor, variation, self.breadcrumb.path.to_path_buf()) @@ -493,7 +493,7 @@ pub struct State { pub types: Resolver, /// YAML-defined type variation anchor resolver. - pub type_variations: Resolver, + pub type_variations: Resolver, /// Protobuf Any type URL resolver. pub proto_any_types: Resolver, diff --git a/rs/src/parse/expressions/literals.rs b/rs/src/parse/expressions/literals.rs index 29239e2b..8858f1f4 100644 --- a/rs/src/parse/expressions/literals.rs +++ b/rs/src/parse/expressions/literals.rs @@ -312,27 +312,54 @@ impl std::fmt::Display for Literal { } } +/// Resolves a variation by class. +fn resolve_variation( + y: &mut context::Context, + variations: Option, + class: &data::Class, +) -> data::Variation { + if let Some(variations) = variations { + let variation = data::variation::resolve_by_class(&variations, class); + if variations.definition.is_some() && variation.definition.is_none() { + diagnostic!( + y, + Error, + LinkMissingTypeVariationNameAndClass, + "the specified variation is not defined for {}", + class + ) + } + data::Variation::UserDefined(variation) + } else { + data::Variation::SystemPreferred + } +} + /// Parses a boolean literal. fn parse_boolean( x: &bool, - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { Literal::new_simple( LiteralValue::Boolean(*x), data::class::Simple::Boolean, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::Boolean), + ), ) } /// Parses an i8 literal. fn parse_i8( x: &i32, - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { let x = i8::try_from(*x) .map_err(|_| cause!(ExpressionIllegalLiteralValue, "i8 value out of range"))?; @@ -340,16 +367,16 @@ fn parse_i8( LiteralValue::Integer(x as i64), data::class::Simple::I8, nullable, - variation, + resolve_variation(y, variations, &data::Class::Simple(data::class::Simple::I8)), ) } /// Parses an i16 literal. fn parse_i16( x: &i32, - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { let x = i16::try_from(*x) .map_err(|_| cause!(ExpressionIllegalLiteralValue, "i16 value out of range"))?; @@ -357,97 +384,125 @@ fn parse_i16( LiteralValue::Integer(x as i64), data::class::Simple::I16, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::I16), + ), ) } /// Parses an i32 literal. fn parse_i32( x: &i32, - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { Literal::new_simple( LiteralValue::Integer(*x as i64), data::class::Simple::I32, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::I32), + ), ) } /// Parses an i64 literal. fn parse_i64( x: &i64, - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { Literal::new_simple( LiteralValue::Integer(*x), data::class::Simple::I64, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::I64), + ), ) } /// Parses an fp32 literal. fn parse_fp32( x: &f32, - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { Literal::new_simple( LiteralValue::Float(*x as f64), data::class::Simple::Fp32, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::Fp32), + ), ) } /// Parses an fp64 literal. fn parse_fp64( x: &f64, - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { Literal::new_simple( LiteralValue::Float(*x), data::class::Simple::Fp64, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::Fp64), + ), ) } /// Parses a string literal. fn parse_string( x: &str, - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { Literal::new_simple( LiteralValue::String(x.to_string()), data::class::Simple::String, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::String), + ), ) } /// Parses a binary literal. fn parse_binary( x: &[u8], - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { Literal::new_simple( LiteralValue::Binary(x.to_owned()), data::class::Simple::Binary, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::Binary), + ), ) } @@ -456,7 +511,7 @@ fn parse_timestamp( x: &i64, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { let dt = to_date_time(*x)?; if dt < chrono::NaiveDate::from_ymd(1000, 1, 1).and_hms(0, 0, 0) @@ -473,7 +528,11 @@ fn parse_timestamp( LiteralValue::Integer(*x), data::class::Simple::Timestamp, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::Timestamp), + ), ) } @@ -482,7 +541,7 @@ fn parse_timestamp_tz( x: &i64, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { let dt = to_date_time(*x)?; if dt < chrono::NaiveDate::from_ymd(1000, 1, 1).and_hms(0, 0, 0) @@ -499,7 +558,11 @@ fn parse_timestamp_tz( LiteralValue::Integer(*x), data::class::Simple::TimestampTz, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::TimestampTz), + ), ) } @@ -508,7 +571,7 @@ fn parse_date( x: &i32, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { let dt = to_date_time((*x as i64).saturating_mul(24 * 60 * 60 * 1_000_000))?; if dt < chrono::NaiveDate::from_ymd(1000, 1, 1).and_hms(0, 0, 0) @@ -525,7 +588,11 @@ fn parse_date( LiteralValue::Integer(*x as i64), data::class::Simple::Date, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::Date), + ), ) } @@ -534,7 +601,7 @@ fn parse_time( x: &i64, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { if *x < 0 || *x >= 24 * 60 * 60 * 1_000_000 { diagnostic!( @@ -548,7 +615,11 @@ fn parse_time( LiteralValue::Integer(*x), data::class::Simple::Time, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::Time), + ), ) } @@ -557,9 +628,8 @@ fn parse_interval_year_to_month( x: &substrait::expression::literal::IntervalYearToMonth, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { - // FIXME: see FIXME for associated type. proto_primitive_field!(x, y, years, |x, _| { if *x < -10000 || *x > 10000 { Err(cause!( @@ -593,7 +663,11 @@ fn parse_interval_year_to_month( LiteralValue::Interval(x.years.into(), x.months.into()), data::class::Simple::IntervalYear, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::IntervalYear), + ), ) } @@ -602,9 +676,8 @@ fn parse_interval_day_to_second( x: &substrait::expression::literal::IntervalDayToSecond, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { - // FIXME: see FIXME for associated type. proto_primitive_field!(x, y, days, |x, _| { if *x < -3650000 || *x > 3650000 { Err(cause!( @@ -625,23 +698,31 @@ fn parse_interval_day_to_second( ), data::class::Simple::IntervalDay, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::IntervalDay), + ), ) } /// Parses a UUID literal. fn parse_uuid( x: &[u8], - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { if let Ok(x) = x.try_into() { Literal::new_simple( LiteralValue::Data16(i128::from_ne_bytes(x)), data::class::Simple::Uuid, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Simple(data::class::Simple::Uuid), + ), ) } else { Err(cause!( @@ -655,15 +736,19 @@ fn parse_uuid( /// Parses a fixed-length string literal. fn parse_fixed_char( x: &str, - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { Literal::new_compound( LiteralValue::String(x.to_string()), data::class::Compound::FixedChar, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Compound(data::class::Compound::FixedChar), + ), vec![i64::try_from(x.len()).unwrap()], ) } @@ -673,7 +758,7 @@ fn parse_var_char( x: &substrait::expression::literal::VarChar, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { proto_primitive_field!(x, y, length); let len: u32 = x.length; @@ -691,7 +776,11 @@ fn parse_var_char( LiteralValue::String(x.value.clone()), data::class::Compound::VarChar, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Compound(data::class::Compound::VarChar), + ), vec![len as i64], ) } @@ -699,15 +788,19 @@ fn parse_var_char( /// Parses a fixed-length binary literal. fn parse_fixed_binary( x: &[u8], - _y: &mut context::Context, + y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { Literal::new_compound( LiteralValue::Binary(x.to_owned()), data::class::Compound::FixedBinary, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Compound(data::class::Compound::FixedBinary), + ), vec![i64::try_from(x.len()).unwrap()], ) } @@ -717,7 +810,7 @@ fn parse_decimal( x: &substrait::expression::literal::Decimal, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { proto_primitive_field!(x, y, precision, |x, _| { if *x < 0 { @@ -757,7 +850,11 @@ fn parse_decimal( LiteralValue::Data16(val), data::class::Compound::Decimal, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Compound(data::class::Compound::Decimal), + ), vec![precision, scale], ) } @@ -771,7 +868,7 @@ fn parse_struct_int( x: &substrait::expression::literal::Struct, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { let (values, types): (Vec<_>, Vec<_>) = proto_repeated_field!(x, y, fields, parse_literal) .1 @@ -786,7 +883,11 @@ fn parse_struct_int( LiteralValue::Items(values), data::class::Compound::Struct, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Compound(data::class::Compound::Struct), + ), types, ) } @@ -796,9 +897,9 @@ pub fn parse_struct( x: &substrait::expression::literal::Struct, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { - let literal = parse_struct_int(x, y, nullable, variation)?; + let literal = parse_struct_int(x, y, nullable, variations)?; y.set_data_type(literal.data_type().clone()); Ok(literal) } @@ -808,7 +909,7 @@ fn parse_list( x: &substrait::expression::literal::List, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { let values: Vec<_> = proto_required_repeated_field!(x, y, values, parse_literal) .1 @@ -834,7 +935,11 @@ fn parse_list( LiteralValue::Items(values), data::class::Compound::List, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Compound(data::class::Compound::List), + ), vec![data_type], ) } @@ -844,7 +949,7 @@ fn parse_map( x: &substrait::expression::literal::Map, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { let values: Vec<_> = proto_required_repeated_field!(x, y, key_values, |x, y| { let key = proto_required_field!(x, y, key, parse_literal) @@ -885,7 +990,11 @@ fn parse_map( LiteralValue::Pairs(values), data::class::Compound::Map, nullable, - variation, + resolve_variation( + y, + variations, + &data::Class::Compound(data::class::Compound::Map), + ), vec![key_type, value_type], ) } @@ -941,7 +1050,7 @@ fn parse_user_defined( x: &substrait::expression::literal::UserDefined, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { let extension_type = proto_primitive_field!( x, @@ -951,18 +1060,15 @@ fn parse_user_defined( ) .1; proto_required_field!(x, y, value, extensions::advanced::parse_functional_any); + let class = if let Some(extension_type) = extension_type { + data::Class::UserDefined(extension_type) + } else { + data::Class::Unresolved + }; + let variation = resolve_variation(y, variations, &class); Ok(Literal { value: LiteralValue::UserDefined, - data_type: data::new_type( - if let Some(extension_type) = extension_type { - data::Class::UserDefined(extension_type) - } else { - data::Class::Unresolved - }, - nullable, - variation, - vec![], - )?, + data_type: data::new_type(class, nullable, variation, vec![])?, }) } @@ -971,41 +1077,41 @@ fn parse_literal_type( x: &substrait::expression::literal::LiteralType, y: &mut context::Context, nullable: bool, - variation: data::Variation, + variations: Option, ) -> diagnostic::Result { use substrait::expression::literal::LiteralType; match x { - LiteralType::Boolean(x) => parse_boolean(x, y, nullable, variation), - LiteralType::I8(x) => parse_i8(x, y, nullable, variation), - LiteralType::I16(x) => parse_i16(x, y, nullable, variation), - LiteralType::I32(x) => parse_i32(x, y, nullable, variation), - LiteralType::I64(x) => parse_i64(x, y, nullable, variation), - LiteralType::Fp32(x) => parse_fp32(x, y, nullable, variation), - LiteralType::Fp64(x) => parse_fp64(x, y, nullable, variation), - LiteralType::String(x) => parse_string(x, y, nullable, variation), - LiteralType::Binary(x) => parse_binary(x, y, nullable, variation), - LiteralType::Timestamp(x) => parse_timestamp(x, y, nullable, variation), - LiteralType::TimestampTz(x) => parse_timestamp_tz(x, y, nullable, variation), - LiteralType::Date(x) => parse_date(x, y, nullable, variation), - LiteralType::Time(x) => parse_time(x, y, nullable, variation), + LiteralType::Boolean(x) => parse_boolean(x, y, nullable, variations), + LiteralType::I8(x) => parse_i8(x, y, nullable, variations), + LiteralType::I16(x) => parse_i16(x, y, nullable, variations), + LiteralType::I32(x) => parse_i32(x, y, nullable, variations), + LiteralType::I64(x) => parse_i64(x, y, nullable, variations), + LiteralType::Fp32(x) => parse_fp32(x, y, nullable, variations), + LiteralType::Fp64(x) => parse_fp64(x, y, nullable, variations), + LiteralType::String(x) => parse_string(x, y, nullable, variations), + LiteralType::Binary(x) => parse_binary(x, y, nullable, variations), + LiteralType::Timestamp(x) => parse_timestamp(x, y, nullable, variations), + LiteralType::TimestampTz(x) => parse_timestamp_tz(x, y, nullable, variations), + LiteralType::Date(x) => parse_date(x, y, nullable, variations), + LiteralType::Time(x) => parse_time(x, y, nullable, variations), LiteralType::IntervalYearToMonth(x) => { - parse_interval_year_to_month(x, y, nullable, variation) + parse_interval_year_to_month(x, y, nullable, variations) } LiteralType::IntervalDayToSecond(x) => { - parse_interval_day_to_second(x, y, nullable, variation) + parse_interval_day_to_second(x, y, nullable, variations) } - LiteralType::Uuid(x) => parse_uuid(x, y, nullable, variation), - LiteralType::FixedChar(x) => parse_fixed_char(x, y, nullable, variation), - LiteralType::VarChar(x) => parse_var_char(x, y, nullable, variation), - LiteralType::FixedBinary(x) => parse_fixed_binary(x, y, nullable, variation), - LiteralType::Decimal(x) => parse_decimal(x, y, nullable, variation), - LiteralType::Struct(x) => parse_struct_int(x, y, nullable, variation), - LiteralType::List(x) => parse_list(x, y, nullable, variation), - LiteralType::Map(x) => parse_map(x, y, nullable, variation), + LiteralType::Uuid(x) => parse_uuid(x, y, nullable, variations), + LiteralType::FixedChar(x) => parse_fixed_char(x, y, nullable, variations), + LiteralType::VarChar(x) => parse_var_char(x, y, nullable, variations), + LiteralType::FixedBinary(x) => parse_fixed_binary(x, y, nullable, variations), + LiteralType::Decimal(x) => parse_decimal(x, y, nullable, variations), + LiteralType::Struct(x) => parse_struct_int(x, y, nullable, variations), + LiteralType::List(x) => parse_list(x, y, nullable, variations), + LiteralType::Map(x) => parse_map(x, y, nullable, variations), LiteralType::EmptyList(x) => parse_empty_list(x, y), LiteralType::EmptyMap(x) => parse_empty_map(x, y), LiteralType::Null(x) => parse_null(x, y), - LiteralType::UserDefined(x) => parse_user_defined(x, y, nullable, variation), + LiteralType::UserDefined(x) => parse_user_defined(x, y, nullable, variations), } } @@ -1056,12 +1162,12 @@ pub fn parse_literal( } // Parse variation. - let variation = if attributes_here { + let variations = if attributes_here { proto_primitive_field!( x, y, type_variation_reference, - extensions::simple::parse_type_variation_reference + extensions::simple::parse_type_variation_reference_without_class ) .1 .unwrap_or_default() @@ -1084,7 +1190,7 @@ pub fn parse_literal( } Ok(()) }); - data::Variation::SystemPreferred + None }; // Parse the literal value. @@ -1094,7 +1200,7 @@ pub fn parse_literal( literal_type, parse_literal_type, x.nullable, - variation + variations ) .1 .unwrap_or_default(); diff --git a/rs/src/parse/extensions/simple/mod.rs b/rs/src/parse/extensions/simple/mod.rs index c7cfc6d0..d32d364d 100644 --- a/rs/src/parse/extensions/simple/mod.rs +++ b/rs/src/parse/extensions/simple/mod.rs @@ -90,16 +90,29 @@ fn describe_reference(y: &mut context::Context, reference: &Arc Result { match y.tvars().resolve(x).cloned() { - Some((variation, path)) => { + Some((variations_by_name, path)) => { + let variation = data::variation::resolve_by_class(&variations_by_name, class); describe_reference(y, &variation); link!(y, path, "Type variation anchor is defined here"); - Ok(data::Variation::UserDefined(variation)) + if variations_by_name.definition.is_some() && variation.definition.is_none() { + Err(cause!( + LinkMissingTypeVariationNameAndClass, + "type variations going by the name {} exist for {}, but not for class {}", + variations_by_name.name, + variations_by_name.uri, + class + )) + } else { + Ok(data::Variation::UserDefined(variation)) + } } None => { if x == &0 { @@ -109,7 +122,32 @@ pub fn parse_type_variation_reference( describe!(y, Misc, "Unresolved type variation"); Err(cause!( LinkMissingAnchor, - "Type variation anchor {x} does not exist" + "type variation anchor {x} does not exist" + )) + } + } + } +} + +/// Parse a type variation reference and resolve it to the set of variations +/// defined with that name in a given simple extension. Note that there can be +/// more than one of those, because names are scoped to a type class. None +/// is returned to reference the system-preferred variation. +pub fn parse_type_variation_reference_without_class( + x: &u32, + y: &mut context::Context, +) -> Result> { + match y.tvars().resolve(x).cloned() { + Some((variations_by_name, _)) => Ok(Some(variations_by_name)), + None => { + if x == &0 { + describe!(y, Misc, "System-preferred variation"); + Ok(None) + } else { + describe!(y, Misc, "Unresolved type variation"); + Err(cause!( + LinkMissingAnchor, + "type variation anchor {x} does not exist" )) } } @@ -126,7 +164,7 @@ pub fn parse_type_reference(x: &u32, y: &mut context::Context) -> Result { describe!(y, Misc, "Unresolved type"); - Err(cause!(LinkMissingAnchor, "Type anchor {x} does not exist")) + Err(cause!(LinkMissingAnchor, "type anchor {x} does not exist")) } } } @@ -146,7 +184,7 @@ pub fn parse_function_reference( describe!(y, Misc, "Unresolved function"); Err(cause!( LinkMissingAnchor, - "Function anchor {x} does not exist" + "function anchor {x} does not exist" )) } } diff --git a/rs/src/parse/relations/read.rs b/rs/src/parse/relations/read.rs index aa275097..848c5a69 100644 --- a/rs/src/parse/relations/read.rs +++ b/rs/src/parse/relations/read.rs @@ -39,7 +39,7 @@ fn parse_virtual_table( // Parse rows, ensuring that they all have the same type. proto_repeated_field!(x, y, values, |x, y| { - let result = literals::parse_struct(x, y, false, data::Variation::SystemPreferred); + let result = literals::parse_struct(x, y, false, None); data_type = types::assert_equal( y, &y.data_type(), diff --git a/rs/src/parse/types.rs b/rs/src/parse/types.rs index 80dcbb08..6666eb09 100644 --- a/rs/src/parse/types.rs +++ b/rs/src/parse/types.rs @@ -53,7 +53,8 @@ macro_rules! parse_simple_type { $input, $context, type_variation_reference, - extensions::simple::parse_type_variation_reference + extensions::simple::parse_type_variation_reference_with_class, + &data::Class::Simple(data::class::Simple::$typ) ) .1; @@ -197,7 +198,8 @@ macro_rules! parse_compound_type_with_length { $input, $context, type_variation_reference, - extensions::simple::parse_type_variation_reference + extensions::simple::parse_type_variation_reference_with_class, + &data::Class::Compound(data::class::Compound::$typ) ) .1; @@ -268,7 +270,8 @@ pub fn parse_decimal( x, y, type_variation_reference, - extensions::simple::parse_type_variation_reference + extensions::simple::parse_type_variation_reference_with_class, + &data::Class::Compound(data::class::Compound::Decimal) ) .1; @@ -317,7 +320,8 @@ pub fn parse_struct( x, y, type_variation_reference, - extensions::simple::parse_type_variation_reference + extensions::simple::parse_type_variation_reference_with_class, + &data::Class::Compound(data::class::Compound::Struct) ) .1; @@ -361,7 +365,8 @@ pub fn parse_list(x: &substrait::r#type::List, y: &mut context::Context) -> diag x, y, type_variation_reference, - extensions::simple::parse_type_variation_reference + extensions::simple::parse_type_variation_reference_with_class, + &data::Class::Compound(data::class::Compound::List) ) .1; @@ -410,7 +415,8 @@ pub fn parse_map(x: &substrait::r#type::Map, y: &mut context::Context) -> diagno x, y, type_variation_reference, - extensions::simple::parse_type_variation_reference + extensions::simple::parse_type_variation_reference_with_class, + &data::Class::Compound(data::class::Compound::Map) ) .1; @@ -524,7 +530,8 @@ pub fn parse_user_defined( x, y, type_variation_reference, - extensions::simple::parse_type_variation_reference + extensions::simple::parse_type_variation_reference_with_class, + &data::Class::UserDefined(user_type.as_ref().cloned().unwrap_or_default()) ) .1; let parameters = proto_repeated_field!(x, y, type_parameters, parse_type_parameter)