Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support type class extensions #47

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 34 additions & 4 deletions proto/substrait/validator/simple_extensions.proto
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,25 @@ message ExtensionDefinition {
WindowProperties window_function = 9;
}

// For table functions, when defined; to be added to above oneof.
reserved 10;

// Nullability behavior that the function was declared with. Note that the
// patterns have already been desugared to represent this, so this can be
// ignored; it exists only for completeness.
oneof consistency {
// Nullability of toplevel binding and data type patterns of all argument
// and return types was overridden to `??nullable`.
google.protobuf.Empty mirror = 11;

// Nullability of toplevel binding and data type patterns of all argument
// types was overridden to `??nullable`.
google.protobuf.Empty declared_output = 12;

// No desugaring overrides were applied.
google.protobuf.Empty discrete = 13;
}

// Properties common to aggregate and window functions.
message AggregateProperties {
// When specified, the function is decomposable.
Expand Down Expand Up @@ -250,9 +269,8 @@ message ExtensionDefinition {
}
}

// Represents a parameter pack for a user-defined compound type class or a
// function argument slot list. In the latter case, the patterns will only
// ever be passed typenames.
// Represents a positional parameter pack for a user-defined compound type
// class or a function argument slot list.
//
// The order of operations for the various patterns is:
//
Expand Down Expand Up @@ -303,7 +321,7 @@ message ExtensionDefinition {
// for aggregate and window functions.
google.protobuf.Empty literal = 6;

// An data value must be bound to the slot. This is done by means of
// A data value must be bound to the slot. This is done by means of
// binding an expression, but the expression can always be evaluated or
// reduced before the function is invoked. This is used for value
// function arguments that are not marked as constant. The data type of
Expand Down Expand Up @@ -350,6 +368,18 @@ message ExtensionDefinition {
// The maximum number of arguments that can be bound to the slot. Zero
// is treated as unspecified/no upper limit.
uint64 maximum = 2;

// Consistency that the variadic slot was declared with. Note that the
// patterns have already been desugared to represent this, so this can be
// ignored; it exists only for completeness.
oneof consistency {
// No desugaring overrides were applied.
google.protobuf.Empty consistent = 3;

// All consistent bindings in the last argument slot were overridden to
// inconsistent bindings.
google.protobuf.Empty inconsistent = 4;
}
}

// Optional additional constraints to apply when determining whether a
Expand Down
2 changes: 1 addition & 1 deletion rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ serde_yaml = "0.9"
# both the schema and the input, so we need to depend on that as well, even
# though we don't actually do any JSON serialization and deserialization.
jsonschema = { version = "=0.15.0", default-features = false }
serde_json = "1"
serde_json = { version = "1", features = ["preserve_order"] }

# Used for checking identifier syntax (could be removed if regexes don't end up
# being useful elsewhere too).
Expand Down
23 changes: 2 additions & 21 deletions rs/src/export/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,31 +347,12 @@ impl From<&extension::simple::type_class::Reference> for validator::data_type::U
extension_id: node
.definition
.as_ref()
.map(|x| x.extension_id)
.map(|x| x.identifier.extension_id)
.unwrap_or_default(),
}
}
}

impl From<&extension::simple::type_class::Definition>
for validator::data_type::user_defined_type::Definition
{
fn from(node: &extension::simple::type_class::Definition) -> Self {
Self {
structure: node
.structure
.iter()
.map(
|(name, simple)| validator::data_type::user_defined_type::Element {
name: name.to_string(),
kind: simple.into(),
},
)
.collect(),
}
}
}

impl From<&data::Variation> for validator::data_type::Variation {
fn from(node: &data::Variation) -> Self {
match node {
Expand All @@ -388,7 +369,7 @@ impl From<&data::Variation> for validator::data_type::Variation {
extension_id: variation
.definition
.as_ref()
.map(|x| x.extension_id)
.map(|x| x.identifier.extension_id)
.unwrap_or_default(),
},
)
Expand Down
16 changes: 1 addition & 15 deletions rs/src/input/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ fn resolve_with_curl(uri: &str) -> Result<Vec<u8>, curl::Error> {
}

/// Configuration structure.
#[derive(Default)]
pub struct Config {
/// When set, do not generate warnings for unknown protobuf fields that are
/// set to their protobuf-defined default value.
Expand Down Expand Up @@ -86,21 +87,6 @@ pub struct Config {
pub max_uri_resolution_depth: Option<usize>,
}

// TODO: enable URI resolution by default once all that works. Then this can
// be derived again. Also still need to expose the depth option in extensions.
impl Default for Config {
fn default() -> Self {
Self {
ignore_unknown_fields: Default::default(),
allowed_proto_any_urls: Default::default(),
diagnostic_level_overrides: Default::default(),
uri_overrides: Default::default(),
uri_resolver: Default::default(),
max_uri_resolution_depth: Some(0),
}
}
}

impl Config {
/// Creates a default configuration.
pub fn new() -> Self {
Expand Down
3 changes: 3 additions & 0 deletions rs/src/output/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@ pub enum Classification {
#[strum(props(HiddenDescription = "invalid compound vs. simple function name usage"))]
LinkCompoundVsSimpleFunctionName = 3010,

#[strum(props(Description = "discouraged name"))]
LinkDiscouragedName = 3011,

// Type-related diagnostics (group 4).
#[strum(props(HiddenDescription = "type-related diagnostics"))]
Type = 4000,
Expand Down
34 changes: 22 additions & 12 deletions rs/src/output/extension/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,22 @@ impl<T> ResolutionResult<T> {
self.expect(parse_context, if_not_applicable, |_, _| true, true, false)
}

/// Emits an error if one or more definitions were found for this name
/// resolution, to be used just before defining a new item.
pub fn expect_not_yet_defined(&self, parse_context: &mut context::Context) {
if !self.visible.is_empty() {
traversal::push_diagnostic(
parse_context,
diagnostic::Level::Error,
cause!(
LinkDuplicateDefinition,
"{} is already defined",
self.unresolved_reference
),
);
}
}

/// Silently returns the first matching item, if any. If there are none,
/// this just returns an unresolved reference. Use
/// filter_items().expect_one() to formulate error messages if there are
Expand Down Expand Up @@ -568,17 +584,11 @@ impl<T> ResolutionResult<T> {
.flatten()
}

/// Return an error if one or more definitions were found for this name
/// resolution, to be used just before defining a new item.
pub fn expect_not_yet_defined(&self) -> diagnostic::Result<()> {
if self.visible.is_empty() {
Ok(())
} else {
Err(cause!(
LinkDuplicateDefinition,
"{} is already defined",
self.unresolved_reference
))
}
/// Calls the given function for each visible item.
pub fn for_each_visible_item<F: FnMut(&T)>(&self, mut f: F) {
self.visible
.iter()
.filter_map(|x| x.1.as_item())
.for_each(|x| f(&x))
}
}
9 changes: 5 additions & 4 deletions rs/src/output/extension/reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use crate::output::path;
use crate::util;
use std::sync::Arc;

/// Represents an identifier that was used to reference something. It is
/// stored along with a resolution result to retain information about the
/// reference even if the resolution failed, and is generally only used for
/// identity/equality checks and diagnostic information.
/// Represents an identifier that was used to reference an extension at the
/// protobuf level. It is stored along with a resolution result to retain
/// information about the reference even if the resolution failed, and is
/// generally only used for identity/equality checks and diagnostic
/// information.
#[derive(Clone, Debug, Default)]
pub struct Identifier {
/// The name of the object being referred to, if known. Always stored using
Expand Down
33 changes: 33 additions & 0 deletions rs/src/output/extension/simple/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: Apache-2.0

//! Module for the common types involved with representing extension
//! definitions.

use crate::output;

/// Identifying information associated with an extension, that can be used to
/// refer to the extension from elsewhere.
#[derive(Clone, Debug)]
pub struct Identifier {
/// The URI that the extension was declared with. Matched case-sensitively.
pub uri: String,

/// One or more aliases for this extension within the scope of the URI.
/// Matched case-insensitively.
pub names: Vec<String>,

/// Unique number for the extension, generated during traversal. The
/// number is only unique within the scope of a single run of the
/// validator, and may change between runs.
pub extension_id: u64,

/// The path that the extension is defined in.
pub definition_path: output::path::PathBuf,
}

/// Non-functional metadata common to all extension types.
#[derive(Clone, Debug, Default)]
pub struct Metadata {
// Optional description of the extension. Only serves as documentation.
pub description: String,
}
8 changes: 5 additions & 3 deletions rs/src/output/extension/simple/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ use std::sync::Arc;
/// The definition of a function implementation.
#[derive(Clone, Debug)]
pub struct Definition {
/// Unique number within the tree that can be used to refer to this
/// extension when exporting in protobuf form.
pub extension_id: u64,
/// Identifier for the extension.
pub identifier: extension::simple::common::Identifier,

/// Common metadata for the extension.
pub metadata: extension::simple::common::Metadata,

/// Link to information common to a set of function implementations going by
/// the same name.
Expand Down
1 change: 1 addition & 0 deletions rs/src/output/extension/simple/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

//! Module for representing simple extensions.

pub mod common;
pub mod function;
pub mod module;
pub mod type_class;
Expand Down
11 changes: 5 additions & 6 deletions rs/src/output/extension/simple/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,13 @@ impl<T: Scope> DynScope for T {
}

/// A parsed simple extension module/file.
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct Definition {
/// Unique number within the tree that can be used to refer to this
/// extension when exporting in protobuf form.
pub extension_id: u64,
/// Identifier for the extension.
pub identifier: extension::simple::common::Identifier,

/// Description of the module.
pub description: String,
/// Common metadata for the extension.
pub metadata: extension::simple::common::Metadata,

/// The URI that was actually used to resolve the module.
pub actual_uri: String,
Expand Down
Loading