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: type alias for numeric generics #7583

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open

feat: type alias for numeric generics #7583

wants to merge 37 commits into from

Conversation

guipublic
Copy link
Contributor

Description

Problem*

Resolves #7272

Summary*

Allow type alias to reference numeric generic expression.

Additional Context

Changes are minimal, more use cases need to be tested. In particular there is no documentation. It can be added as a subsequent PR (or even in this one).
The PR is done in order to validate the approach taken.

Documentation*

Check one:

  • No documentation needed.
  • Documentation included in this PR.
  • [For Experimental Features] Documentation to be submitted in a separate PR.

PR Checklist*

  • I have tested the changes locally.
  • I have formatted the changes with Prettier and/or cargo fmt on default settings.

Sorry, something went wrong.

@guipublic guipublic requested a review from a team March 5, 2025 11:23
@guipublic guipublic changed the title type alias for numeric generics feat: type alias for numeric generics Mar 5, 2025
@guipublic
Copy link
Contributor Author

I am not sure why I had to update some unit tests.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Test Suite Duration'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: 02fe712 Previous: d8ea3a4 Ratio
zkemail_zkemail.nr_lib 3 s 1 s 3

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench

Comment on lines +147 to +149
fn noir_type_alias_with_file(noir_type_alias: TypeAlias, file: FileId) -> TypeAlias {
type_alias_with_file(noir_type_alias, file)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? This function is private so we should be able to update all the references to it pretty cleanly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it was needed when I used an enum to distinguish numeric type aliases, but it's probably not needed anymore, indeed. I will check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets remove this before merging

let (typ, num_expr) = if let Some(num_type) = alias.type_alias_def.numeric_type {
let num_type = self.resolve_type(num_type);
let kind = Kind::numeric(num_type);
let num_expr = if let UnresolvedTypeData::Expression(expr) =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks to be the issue with the identity alias. This is a pretty fragile check it seems as we can avoid it by just ensuring that the last step is an expression and it doesn't look deeper?

type Quadruple<let N: u32>: u32 = Double<N> + Double<N>;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a stronger test which only authorised numeric expressions for the type alias to reference.
Such type aliases did cause stack overflow during resolution so I had to return an error type.

@TomAFrench
Copy link
Member

I'm a little sus by how loose we're being with the various kinds of type aliases now.

e.g. Foo is now considered an arithmetic generic type alias by the compiler.

type Foo: u32 = u32;

This errors with

error: Cannot use a type alias inside a type alias
  ┌─ src/main.nr:6:1
  │
6 │ type Foo: Bar = u32;
  │ -------------------
  │

but really we should be rejecting it as an invalid type alias off the bat.

@TomAFrench
Copy link
Member

Can you add some unit tests for the cases where composing numeric type aliases results in issues? Ideally we'd have tests that we can use to determine when we can remove the block on nested numeric type aliases

Copy link
Contributor

@jfecher jfecher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple more things I found before we merge.

@@ -22,7 +22,7 @@ fn errors_if_type_alias_aliases_more_private_type() {
let src = r#"
struct Foo {}
pub type Bar = Foo;
^^^ Type `Foo` is more private than item `Bar`
^^^^^^^^^^^^^^^^^^ Type `Foo` is more private than item `Bar`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these locations be changed back to just the item? As is now we're highlighting the entire line which I don't think is as helpful

Comment on lines +147 to +149
fn noir_type_alias_with_file(noir_type_alias: TypeAlias, file: FileId) -> TypeAlias {
type_alias_with_file(noir_type_alias, file)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets remove this before merging

}

#[test]
fn disallows_numeric_type_aliases_to_expression_with_alias_1() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn disallows_numeric_type_aliases_to_expression_with_alias_1() {
fn disallows_numeric_type_aliases_to_expression_with_alias_2() {

Comment on lines +154 to +155
type Quadruple<let N: u32>: u32 = N*(Double::<N>+3);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot use a type alias inside a type alias
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this location be changed so that it is just on Double::<N>?

Comment on lines +295 to +298
let mut diag = Diagnostic::simple_error(
format!("duplicate definitions of {name} found"),
"second definition found here".to_string(),
*second_location,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the formatter broke in this file? Not sure what happened here

Comment on lines +64 to +72
pub(crate) fn resolve_type_with_kind(&mut self, typ: UnresolvedType, kind: &Kind) -> Type {
let location = typ.location;
let resolved_type = self.resolve_type_inner(typ, kind);
if resolved_type.is_nested_slice() {
self.push_err(ResolverError::NestedSlices { location });
}
resolved_type
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this added from this PR? We used to have this method although it looks like it was removed a while back. Just flagging this in case it was the result of a merge and we don't need it any more.

Comment on lines +102 to +104
// Type alias to numeric generics are aliases to some global value
// Therefore we allow this case although we cannot provide the value yet
return Ok((DefinitionId::dummy_id(), item));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks potentially suspicious - when are these dummy ids filled in? If we assign each numeric type alias a DefinitionId we can probably do away with the dummy ids here.

Comment on lines +544 to +545
if expr.id == DefinitionId::dummy_id() {
if let Some(PathResolutionItem::TypeAlias(alias)) = item {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the outer == dummy_id check necessary here? Seems like all numeric type aliases are expected to have that ID anyway and only checking for PathResolutionItem::TypeAlias would be more clear I think.

}
}

fn operator_to_binary_op_kind_helper(op: &BinaryTypeOperator) -> BinaryOpKind {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a method on BinaryTypeOperator


pub(crate) fn is_valid_expression(&self) -> bool {
match self {
UnresolvedTypeExpression::Variable(path) => path.is_ident(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment in elaborator/mod.rs mentions this function should allow globals & constants. We can have multiple segment paths that still resolve to constants or globals. E.g. crate::CONSTANT or foo::bar::my_global, but this method disallows these.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Type aliases for numeric types
4 participants