Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
a1b9b69
type alias for numeric generics
guipublic Mar 5, 2025
0c2f4ff
Merge branch 'master' into gd/issue_7272
guipublic Mar 5, 2025
82d639e
fix unit tests
guipublic Mar 5, 2025
ff24516
Merge branch 'master' into gd/issue_7272
guipublic Mar 5, 2025
4d4dabe
use the aliased expression in loop bounds
guipublic Mar 11, 2025
531467a
Merge branch 'master' into gd/issue_7272
guipublic Mar 11, 2025
8f50d5e
code review: get location before parsing semi-column
guipublic Mar 11, 2025
249f71b
code review
guipublic Mar 11, 2025
ca3298f
Code Review: use option instead of an enum
guipublic Mar 11, 2025
7884d9f
Code review
guipublic Mar 11, 2025
e19f7e3
Merge branch 'master' into gd/issue_7272
guipublic Mar 11, 2025
6739cc9
rename typealias
guipublic Mar 12, 2025
7b79b8a
Merge branch 'master' into gd/issue_7272
guipublic Mar 12, 2025
c5e1dcc
Disable numeric type alias composition
guipublic Mar 14, 2025
0074169
Merge branch 'master' into gd/issue_7272
guipublic Mar 14, 2025
44abde3
remove 'custom errors span' in test as it conflict with negative lite…
guipublic Mar 14, 2025
e04ad34
Merge branch 'master' into gd/issue_7272
guipublic Mar 14, 2025
97b7063
format
guipublic Mar 14, 2025
faf9f0c
remove custom error spans from test, completely
guipublic Mar 14, 2025
efcecff
add integration test
guipublic Mar 17, 2025
e1552b4
Merge branch 'master' into gd/issue_7272
guipublic Mar 17, 2025
a4ae121
format numeric type alias
guipublic Mar 18, 2025
e5de933
Merge branch 'master' into gd/issue_7272
guipublic Mar 18, 2025
7522b3a
Merge branch 'master' into gd/issue_7272
guipublic Mar 18, 2025
fd35270
chore: avoid unnecessary mutable sets of `num_expr`
TomAFrench Mar 18, 2025
fc7b048
chore: fix me breaking things
TomAFrench Mar 18, 2025
58b39a9
chore: move tests to `aliases` module and add identity test
TomAFrench Mar 18, 2025
1744fea
code review
guipublic Mar 18, 2025
3eb7c2f
Merge branch 'master' into gd/issue_7272
guipublic Mar 19, 2025
cb8d263
Code review, allow variable as numeric expression
guipublic Mar 19, 2025
44cd174
Merge branch 'master' into gd/issue_7272
TomAFrench Mar 19, 2025
d67a9cb
Strengthen error on type alias referencing other type alias
guipublic Mar 19, 2025
fcc9c04
Merge branch 'master' into gd/issue_7272
guipublic Mar 19, 2025
49d865f
fix composing numeric type aliases
guipublic Mar 20, 2025
fb837af
Code review: more specific errors and more unit tests
guipublic Mar 20, 2025
afa5cc9
Merge branch 'master' into gd/issue_7272
guipublic Mar 20, 2025
02fe712
Merge branch 'master' into gd/issue_7272
guipublic Mar 21, 2025
b60811f
code review
guipublic Jul 14, 2025
7d0f467
Merge branch 'master' into gd/issue_7272
guipublic Jul 14, 2025
5e728d8
format
guipublic Jul 14, 2025
96aa359
fix merge issue with unit tests
guipublic Jul 14, 2025
305a791
fix unit tests from merge
guipublic Jul 14, 2025
64535b8
code review and a few fixes from the merge
guipublic Jul 14, 2025
9da1895
code review
guipublic Jul 15, 2025
471d635
Merge branch 'master' into gd/issue_7272
guipublic Jul 15, 2025
4c71b8c
code review: use location of the bad expression for errors
guipublic Jul 15, 2025
226764a
snapshots
guipublic Jul 16, 2025
0e8349f
Merge branch 'master' into gd/issue_7272
guipublic Jul 16, 2025
e015e64
Merge branch 'master' into gd/issue_7272
guipublic Jul 17, 2025
5624dfb
snapshots
guipublic Jul 17, 2025
6aa1b31
Merge branch 'master' into gd/issue_7272
guipublic Jul 17, 2025
c7561fc
attempt to list failing programs from aliases tests
guipublic Jul 17, 2025
9dfc377
Use `check_errors!`
asterite Jul 17, 2025
64a4b11
More tests and snapshots
asterite Jul 17, 2025
e40a4ec
Snapshots
asterite Jul 17, 2025
2a19c9a
Merge branch 'master' into gd/issue_7272
guipublic Jul 18, 2025
65f94dc
better location for numeric expression in type alias
guipublic Jul 18, 2025
309e58d
better location for numeric expression in type alias
guipublic Jul 18, 2025
e54ee3d
snapshots
guipublic Jul 21, 2025
20d2478
Merge branch 'master' into gd/issue_7272
guipublic Jul 21, 2025
3c4c46b
Merge branch 'master' into gd/issue_7272
asterite Jul 21, 2025
0697813
Handle UnresolvedTypeData::AsTraitPath
asterite Jul 21, 2025
2a96dce
code review
guipublic Jul 29, 2025
826bfca
Merge branch 'master' into gd/issue_7272
guipublic Jul 29, 2025
61f3d2c
Merge branch 'master' into gd/issue_7272
guipublic Aug 1, 2025
251d89b
fix build
guipublic Aug 1, 2025
5e42487
snapshots
guipublic Aug 4, 2025
62cf332
Merge branch 'master' into gd/issue_7272
guipublic Aug 4, 2025
06f3cb6
format
guipublic Aug 4, 2025
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
34 changes: 34 additions & 0 deletions compiler/noirc_frontend/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod traits;
mod type_alias;
mod visitor;

use noirc_errors::Located;
use noirc_errors::Location;
pub use visitor::AttributeTarget;
pub use visitor::Visitor;
Expand All @@ -34,6 +35,7 @@ pub use structure::*;
pub use traits::*;
pub use type_alias::*;

use crate::signed_field::SignedField;
use crate::{
BinaryTypeOperator,
node_interner::{InternedUnresolvedTypeData, QuotedTypeId},
Expand Down Expand Up @@ -544,6 +546,38 @@ impl UnresolvedTypeExpression {
}
}

pub fn to_expression_kind(&self) -> ExpressionKind {
match self {
UnresolvedTypeExpression::Variable(path) => ExpressionKind::Variable(path.clone()),
UnresolvedTypeExpression::Constant(int, _) => {
ExpressionKind::Literal(Literal::Integer(SignedField {
field: *int,
is_negative: false,
}))
}
UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, location) => {
ExpressionKind::Infix(Box::new(InfixExpression {
lhs: Expression { kind: lhs.to_expression_kind(), location: *location },
operator: Located::from(*location, Self::operator_to_binary_op_kind_helper(op)),
rhs: Expression { kind: rhs.to_expression_kind(), location: *location },
}))
}
UnresolvedTypeExpression::AsTraitPath(path) => {
ExpressionKind::AsTraitPath(*path.clone())
}
}
}

fn operator_to_binary_op_kind_helper(op: &BinaryTypeOperator) -> BinaryOpKind {
Comment thread
guipublic marked this conversation as resolved.
Outdated
match op {
BinaryTypeOperator::Addition => BinaryOpKind::Add,
BinaryTypeOperator::Subtraction => BinaryOpKind::Subtract,
BinaryTypeOperator::Multiplication => BinaryOpKind::Multiply,
BinaryTypeOperator::Division => BinaryOpKind::Divide,
BinaryTypeOperator::Modulo => BinaryOpKind::Modulo,
}
}

fn operator_allowed(op: BinaryOpKind) -> bool {
matches!(
op,
Expand Down
75 changes: 73 additions & 2 deletions compiler/noirc_frontend/src/ast/type_alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,89 @@ use noirc_errors::Location;
use std::fmt::Display;

/// Ast node for type aliases
/// A Noir Type Alias can be an alias to a normal type, or to a numeric generic type.
#[derive(Clone, Debug)]
pub struct NoirTypeAlias {
pub enum NoirTypeAlias {
NormalTypeAlias(NormalTypeAlias),
NumericTypeAlias(NumericTypeAlias),
}

impl Display for NoirTypeAlias {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NoirTypeAlias::NormalTypeAlias(alias) => write!(f, "{}", alias),
NoirTypeAlias::NumericTypeAlias(alias) => write!(f, "{}", alias),
}
}
}
#[derive(Clone, Debug)]
pub struct NormalTypeAlias {
pub name: Ident,
pub generics: UnresolvedGenerics,
pub typ: UnresolvedType,
pub visibility: ItemVisibility,
pub location: Location,
}

impl Display for NoirTypeAlias {
impl Display for NormalTypeAlias {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let generics = vecmap(&self.generics, |generic| generic.to_string());
write!(f, "type {}<{}> = {}", self.name, generics.join(", "), self.typ)
}
}

#[derive(Clone, Debug)]
pub struct NumericTypeAlias {
pub type_alias: NormalTypeAlias,
pub numeric_type: UnresolvedType,
Comment thread
guipublic marked this conversation as resolved.
Outdated
}

impl Display for NumericTypeAlias {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let generics = vecmap(&self.type_alias.generics, |generic| generic.to_string());
write!(
f,
"numeric ({}) type {}<{}> = {}",
Comment thread
guipublic marked this conversation as resolved.
Outdated
self.numeric_type,
self.type_alias.name,
generics.join(", "),
self.type_alias.typ
)
}
}
impl NoirTypeAlias {
pub fn name(&self) -> Ident {
match self {
NoirTypeAlias::NormalTypeAlias(alias) => alias.name.clone(),
NoirTypeAlias::NumericTypeAlias(alias) => alias.type_alias.name.clone(),
}
}

pub fn visibility(&self) -> ItemVisibility {
match self {
NoirTypeAlias::NormalTypeAlias(alias) => alias.visibility,
NoirTypeAlias::NumericTypeAlias(alias) => alias.type_alias.visibility,
}
}

pub fn generics(&self) -> &UnresolvedGenerics {
match self {
NoirTypeAlias::NormalTypeAlias(alias) => &alias.generics,
NoirTypeAlias::NumericTypeAlias(alias) => &alias.type_alias.generics,
}
}

pub fn location(&self) -> Location {
match self {
NoirTypeAlias::NormalTypeAlias(alias) => alias.location,
NoirTypeAlias::NumericTypeAlias(alias) => alias.type_alias.location,
}
}

pub fn type_alias(&self) -> &NormalTypeAlias {
match self {
NoirTypeAlias::NormalTypeAlias(alias) => alias,
NoirTypeAlias::NumericTypeAlias(alias) => &alias.type_alias,
}
}
}
7 changes: 6 additions & 1 deletion compiler/noirc_frontend/src/ast/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,12 @@ impl NoirTypeAlias {
}

pub fn accept_children(&self, visitor: &mut impl Visitor) {
self.typ.accept(visitor);
match self {
NoirTypeAlias::NormalTypeAlias(type_alias) => type_alias.typ.accept(visitor),
NoirTypeAlias::NumericTypeAlias(num_type_alias) => {
num_type_alias.type_alias.typ.accept(visitor);
}
}
}
}

Expand Down
32 changes: 24 additions & 8 deletions compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{

use crate::{
DataType, StructField, TypeBindings,
ast::{ItemVisibility, UnresolvedType},
ast::{ItemVisibility, UnresolvedType, UnresolvedTypeExpression},
graph::CrateGraph,
hir_def::traits::ResolvedTraitBound,
node_interner::GlobalValue,
Expand Down Expand Up @@ -1643,19 +1643,35 @@ impl<'context> Elaborator<'context> {
fn define_type_alias(&mut self, alias_id: TypeAliasId, alias: UnresolvedTypeAlias) {
self.local_module = alias.module_id;

let name = &alias.type_alias_def.name;
let visibility = alias.type_alias_def.visibility;
let location = alias.type_alias_def.typ.location;
let name = &alias.type_alias_def.name();
let visibility = alias.type_alias_def.visibility();
let location = alias.type_alias_def.location();

let generics = self.add_generics(&alias.type_alias_def.generics);
let generics = self.add_generics(alias.type_alias_def.generics());
self.current_item = Some(DependencyId::Alias(alias_id));
let typ = self.resolve_type(alias.type_alias_def.typ);

let mut num_expr = None;
let typ = match alias.type_alias_def {
crate::ast::NoirTypeAlias::NormalTypeAlias(type_alias) => {
self.resolve_type(type_alias.typ)
}
crate::ast::NoirTypeAlias::NumericTypeAlias(numeric_type_alias) => {
let num_type = self.resolve_type(numeric_type_alias.numeric_type);
let kind = Kind::numeric(num_type);
if let UnresolvedTypeData::Expression(expr) =
numeric_type_alias.type_alias.typ.typ.clone()
{
let expr_kind = UnresolvedTypeExpression::to_expression_kind(&expr);
num_expr = Some(expr_kind);
}
self.resolve_type_with_kind(numeric_type_alias.type_alias.typ, &kind)
}
};

if visibility != ItemVisibility::Private {
self.check_type_is_not_more_private_then_item(name, visibility, &typ, location);
}

self.interner.set_type_alias(alias_id, typ, generics);
self.interner.set_type_alias(alias_id, typ, generics, num_expr);
self.generics.clear();
}

Expand Down
23 changes: 22 additions & 1 deletion compiler/noirc_frontend/src/elaborator/patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,11 +535,23 @@ impl Elaborator<'_> {

pub(super) fn elaborate_variable(&mut self, variable: Path) -> (ExprId, Type) {
let unresolved_turbofish = variable.segments.last().unwrap().generics.clone();

let location = variable.location;
let (expr, item) = self.resolve_variable(variable);
let definition_id = expr.id;

if expr.id == DefinitionId::dummy_id() {
if let Some(PathResolutionItem::TypeAlias(alias)) = item {
Comment thread
guipublic marked this conversation as resolved.
Outdated
// A type alias to a numeric generics is considered like a variable
// but it is not a real variable so it does not resolve to a valid Identifier
// In order to handle this, we retrieve the numeric generics expression that the type aliases to
let type_alias = self.interner.get_type_alias(alias);
if let Some(expr) = type_alias.borrow().numeric_expr.clone() {
let expr = Expression::new(expr, type_alias.borrow().location);
return self.elaborate_expression(expr);
}
}
}

let type_generics = item.map(|item| self.resolve_item_turbofish(item)).unwrap_or_default();

let definition_kind =
Expand Down Expand Up @@ -839,6 +851,15 @@ impl Elaborator<'_> {
Err(_) => error,
},
None => match self.lookup_global(path) {
Ok((dummy_id, PathResolutionItem::TypeAlias(type_alias_id)))
if dummy_id == DefinitionId::dummy_id() =>
{
// Allow path which resolves to a type alias
return (
(HirIdent::non_trait_method(dummy_id, location), 4),
Some(PathResolutionItem::TypeAlias(type_alias_id)),
);
}
Ok((id, item)) => {
return ((HirIdent::non_trait_method(id, location), 0), Some(item));
}
Expand Down
23 changes: 17 additions & 6 deletions compiler/noirc_frontend/src/elaborator/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,25 @@ impl Elaborator<'_> {
return Ok((self.interner.function_definition_id(function), item));
}

if let PathResolutionItem::Global(global) = item {
let global = self.interner.get_global(global);
return Ok((global.definition_id, item));
}

let expected = "global variable";
let got = "local variable";
Err(ResolverError::Expected { location, expected, got })
match item {
PathResolutionItem::Global(global) => {
let global = self.interner.get_global(global);
Ok((global.definition_id, item))
}
PathResolutionItem::TypeAlias(type_alias_id) => {
let type_alias = self.interner.get_type_alias(type_alias_id);

if type_alias.borrow().numeric_expr.is_some() {
// 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));
Comment thread
jfecher marked this conversation as resolved.
}
Err(ResolverError::Expected { location, expected, got })
}
_ => Err(ResolverError::Expected { location, expected, got }),
}
}

pub fn push_scope(&mut self) {
Expand Down
18 changes: 17 additions & 1 deletion compiler/noirc_frontend/src/elaborator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ impl Elaborator<'_> {
resolved_type
}

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
}

Comment thread
jfecher marked this conversation as resolved.
Outdated
/// Translates an UnresolvedType into a Type and appends any
/// freshly created TypeVariables created to new_variables.
pub fn resolve_type_inner(&mut self, typ: UnresolvedType, kind: &Kind) -> Type {
Expand Down Expand Up @@ -512,7 +521,14 @@ impl Elaborator<'_> {
) -> Type {
match length {
UnresolvedTypeExpression::Variable(path) => {
let typ = self.resolve_named_type(path, GenericTypeArgs::default());
let mut ab = GenericTypeArgs::default();
// Use generics from path, if they exist
if let Some(last_segment) = path.segments.last() {
if let Some(generics) = &last_segment.generics {
ab.ordered_args = generics.clone();
}
}
let typ = self.resolve_named_type(path, ab);
self.check_kind(typ, expected_kind, location)
}
UnresolvedTypeExpression::Constant(int, _span) => {
Expand Down
6 changes: 3 additions & 3 deletions compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,9 @@ impl ModCollector<'_> {
for type_alias in type_aliases {
let doc_comments = type_alias.doc_comments;
let type_alias = type_alias.item;
let name = type_alias.name.clone();
let name = type_alias.name();
let location = Location::new(name.span(), self.file_id);
let visibility = type_alias.visibility;
let visibility = type_alias.visibility();

// And store the TypeId -> TypeAlias mapping somewhere it is reachable
let unresolved = UnresolvedTypeAlias {
Expand All @@ -373,7 +373,7 @@ impl ModCollector<'_> {

let resolved_generics = Context::resolve_generics(
&context.def_interner,
&unresolved.type_alias_def.generics,
unresolved.type_alias_def.generics(),
&mut errors,
);

Expand Down
14 changes: 11 additions & 3 deletions compiler/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use proptest_derive::Arbitrary;
use acvm::{AcirField, FieldElement};

use crate::{
ast::{IntegerBitSize, ItemVisibility},
ast::{ExpressionKind, IntegerBitSize, ItemVisibility},
hir::type_check::{TypeCheckError, generics::TraitGenerics},
node_interner::{ExprId, NodeInterner, TraitId, TypeAliasId},
signed_field::{AbsU128, SignedField},
Expand Down Expand Up @@ -682,6 +682,8 @@ pub struct TypeAlias {
pub typ: Type,
pub generics: Generics,
pub location: Location,
/// Optional expression, used by type aliases to numeric generics
pub numeric_expr: Option<ExpressionKind>,
}

impl std::hash::Hash for TypeAlias {
Expand Down Expand Up @@ -722,13 +724,19 @@ impl TypeAlias {
typ: Type,
generics: Generics,
) -> TypeAlias {
TypeAlias { id, typ, name, location, generics }
TypeAlias { id, typ, name, location, generics, numeric_expr: None }
}

pub fn set_type_and_generics(&mut self, new_typ: Type, new_generics: Generics) {
pub fn set_type_and_generics(
&mut self,
new_typ: Type,
new_generics: Generics,
num_expr: Option<ExpressionKind>,
) {
assert_eq!(self.typ, Type::Error);
self.typ = new_typ;
self.generics = new_generics;
self.numeric_expr = num_expr;
}

pub fn get_type(&self, generic_args: &[Type]) -> Type {
Expand Down
Loading