Skip to content

Commit

Permalink
fix(frontend): Disallow signed numeric generics (#5572)
Browse files Browse the repository at this point in the history
# Description

## Problem\*

Resolves #5552

## Summary\*

This temporarily disallows signed numeric generics as to prevent the
panic in the issue until they are fully supported. In general type-level
integers need to be updated to support numeric generics. It is deceiving
to not ban them until type-level integers are updated as otherwise users
can declare signed numeric generics but not actually use them as per the
linked issue.

For the code in the issue we now get this error:
<img width="697" alt="Screenshot 2024-07-19 at 5 41 13 PM"
src="https://github.com/user-attachments/assets/17979de7-8c82-40af-aa0f-a32f73992d48">


## Additional Context



## Documentation\*

Check one:
- [] No documentation needed.
- [ ] Documentation included in this PR.
- [X] **[For Experimental Features]** Documentation to be submitted in a
separate PR.

# PR Checklist\*

- [X] I have tested the changes locally.
- [X] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.
  • Loading branch information
vezenovm authored Jul 20, 2024
1 parent 4e2c08d commit 2b4853e
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 11 deletions.
12 changes: 5 additions & 7 deletions compiler/noirc_frontend/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,13 +323,11 @@ impl UnresolvedTypeExpression {

fn from_expr_helper(expr: Expression) -> Result<UnresolvedTypeExpression, Expression> {
match expr.kind {
ExpressionKind::Literal(Literal::Integer(int, sign)) => {
assert!(!sign, "Negative literal is not allowed here");
match int.try_to_u32() {
Some(int) => Ok(UnresolvedTypeExpression::Constant(int, expr.span)),
None => Err(expr),
}
}
// TODO(https://github.com/noir-lang/noir/issues/5571): The `sign` bool from `Literal::Integer` should be used to construct the constant type expression.
ExpressionKind::Literal(Literal::Integer(int, _)) => match int.try_to_u32() {
Some(int) => Ok(UnresolvedTypeExpression::Constant(int, expr.span)),
None => Err(expr),
},
ExpressionKind::Variable(path, _) => Ok(UnresolvedTypeExpression::Variable(path)),
ExpressionKind::Prefix(prefix) if prefix.operator == UnaryOp::Minus => {
let lhs = Box::new(UnresolvedTypeExpression::Constant(0, expr.span));
Expand Down
4 changes: 4 additions & 0 deletions compiler/noirc_frontend/src/parser/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ pub enum ParserErrorReason {
InvalidBitSize(u32),
#[error("{0}")]
Lexer(LexerErrorKind),
// TODO(https://github.com/noir-lang/noir/issues/5571): This error can be removed once support is expanded for type-level integers.
// This error reason was added to prevent the panic outline in this issue: https://github.com/noir-lang/noir/issues/5552.
#[error("Only unsigned integers allowed for numeric generics")]
SignedNumericGeneric,
}

/// Represents a parsing error, or a parsing error in the making.
Expand Down
26 changes: 22 additions & 4 deletions compiler/noirc_frontend/src/parser/parser/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ use super::{
parameter_name_recovery, parameter_recovery, parenthesized, parse_type, pattern,
self_parameter, where_clause, NoirParser,
};
use crate::ast::{
FunctionDefinition, FunctionReturnType, ItemVisibility, NoirFunction, Param, Visibility,
};
use crate::parser::spanned;
use crate::token::{Keyword, Token};
use crate::{
ast::{UnresolvedGeneric, UnresolvedGenerics},
ast::{
FunctionDefinition, FunctionReturnType, ItemVisibility, NoirFunction, Param, Visibility,
},
macros_api::UnresolvedTypeData,
parser::{ParserError, ParserErrorReason},
};
use crate::{
ast::{Signedness, UnresolvedGeneric, UnresolvedGenerics},
parser::labels::ParsingRuleLabel,
};

Expand Down Expand Up @@ -85,6 +89,19 @@ pub(super) fn numeric_generic() -> impl NoirParser<UnresolvedGeneric> {
.then_ignore(just(Token::Colon))
.then(parse_type())
.map(|(ident, typ)| UnresolvedGeneric::Numeric { ident, typ })
.validate(|generic, span, emit| {
if let UnresolvedGeneric::Numeric { typ, .. } = &generic {
if let UnresolvedTypeData::Integer(signedness, _) = typ.typ {
if matches!(signedness, Signedness::Signed) {
emit(ParserError::with_reason(
ParserErrorReason::SignedNumericGeneric,
span,
));
}
}
}
generic
})
}

pub(super) fn generic_type() -> impl NoirParser<UnresolvedGeneric> {
Expand Down Expand Up @@ -233,6 +250,7 @@ mod test {
"fn func_name<let T:>(y: T) {}",
"fn func_name<T:>(y: T) {}",
"fn func_name<T: u64>(y: T) {}",
"fn func_name<let N: i8>() {}",
],
);
}
Expand Down

0 comments on commit 2b4853e

Please sign in to comment.