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: Explicit Associated Types & Constants #5739

Merged
merged 49 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
523beef
Parse associated constants
jfecher Jul 16, 2024
2c7eb02
Merge branch 'master' into jf/associated-constants
jfecher Aug 6, 2024
7901f66
Add features to the AST
jfecher Aug 6, 2024
38e09ef
Some progress
jfecher Aug 6, 2024
b862af3
Resolve associated type paths from Self
jfecher Aug 7, 2024
9f1402b
Break everything
jfecher Aug 8, 2024
2b16d75
Overhaul resolution of generics
jfecher Aug 9, 2024
98e0db6
It compiles!
jfecher Aug 12, 2024
21baa22
Update some tests
jfecher Aug 12, 2024
91a80a7
Fix merge conflicts
jfecher Aug 12, 2024
bda71e0
Fix name shadowing test
jfecher Aug 13, 2024
11864a2
Get some programs compiling w/ type annotations
jfecher Aug 13, 2024
488db35
Add TraitGenerics
jfecher Aug 13, 2024
a35d718
Fix interpreter builtins
jfecher Aug 13, 2024
e0a3d2b
Make type spans mandatory
jfecher Aug 14, 2024
480a91d
Start trying to resolve AsTraitPaths
jfecher Aug 14, 2024
2553e31
Get associated types mostly working
jfecher Aug 15, 2024
ea4a31e
Try to solve math
jfecher Aug 15, 2024
cef4256
Get Serialize working
jfecher Aug 16, 2024
f4b29a9
Add test programs
jfecher Aug 16, 2024
f73d550
Merge branch 'master' into jf/associated-constants2
jfecher Aug 16, 2024
5dabf3c
Remove comment; fix bad merge
jfecher Aug 16, 2024
a514799
Add location to panic
jfecher Aug 16, 2024
b5fb036
Merge branch 'master' into jf/associated-constants2
jfecher Aug 16, 2024
a2542fd
Fix let-inferred type issue
jfecher Aug 16, 2024
c6d1829
Fix auto deref
jfecher Aug 16, 2024
98597e4
unsafe::zeroed -> mem::zeroed
jfecher Aug 16, 2024
c71e1d1
Merge branch 'master' into jf/associated-constants2
jfecher Aug 16, 2024
3f3f050
Fix formatter
jfecher Aug 16, 2024
ff41698
Format the formatter
jfecher Aug 16, 2024
9b41358
Remove dbg
jfecher Aug 16, 2024
0721cb2
Fix formatter again
jfecher Aug 16, 2024
ca65712
Don't crash the linker
jfecher Aug 19, 2024
c6739c3
Merge branch 'jf/associated-constants2' of https://github.com/noir-la…
jfecher Aug 19, 2024
3ba02e6
Merge branch 'master' into jf/associated-constants2
jfecher Aug 19, 2024
d67a9f0
Add a missing `follow_bindings` call
asterite Aug 19, 2024
81c764e
Add frontend tests
jfecher Aug 19, 2024
e25565f
Merge branch 'master' into jf/associated-constants2
TomAFrench Aug 20, 2024
d1661fd
Merge branch 'jf/associated-constants2' of https://github.com/noir-la…
jfecher Aug 20, 2024
e174c7d
Store TraitGenerics in a TraitConstraint
jfecher Aug 20, 2024
4471eea
Type hints aren't needed!
jfecher Aug 20, 2024
7de6992
Fix lint
jfecher Aug 20, 2024
f444b58
Fix tests, add another
jfecher Aug 20, 2024
b804228
Add docs
jfecher Aug 20, 2024
becadba
Remove experimental warnings
jfecher Aug 20, 2024
c91dffb
Fix merge conflicts
jfecher Aug 20, 2024
f0331ba
Merge branch 'master' into jf/associated-constants2
jfecher Aug 21, 2024
c9558cc
Merge branch 'master' into jf/associated-constants2
TomAFrench Aug 22, 2024
4bd91a1
Limit max parallel threads
jfecher Aug 22, 2024
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
3 changes: 2 additions & 1 deletion aztec_macros/src/transforms/note_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub fn generate_note_interface_impl(
let mut note_fields = vec![];
let note_interface_generics = trait_impl
.trait_generics
.ordered_args
.iter()
.map(|gen| match gen.typ.clone() {
UnresolvedTypeData::Named(path, _, _) => Ok(path.last_name().to_string()),
Expand Down Expand Up @@ -120,7 +121,7 @@ pub fn generate_note_interface_impl(
ident("header"),
make_type(UnresolvedTypeData::Named(
chained_dep!("aztec", "note", "note_header", "NoteHeader"),
vec![],
Default::default(),
false,
)),
);
Expand Down
32 changes: 19 additions & 13 deletions aztec_macros/src/transforms/storage.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use acvm::acir::AcirField;
use noirc_errors::Span;
use noirc_frontend::ast::{
BlockExpression, Expression, ExpressionKind, FunctionDefinition, Ident, Literal, NoirFunction,
NoirStruct, Pattern, StatementKind, TypeImpl, UnresolvedType, UnresolvedTypeData,
BlockExpression, Expression, ExpressionKind, FunctionDefinition, GenericTypeArgs, Ident,
Literal, NoirFunction, NoirStruct, Pattern, StatementKind, TypeImpl, UnresolvedType,
UnresolvedTypeData,
};
use noirc_frontend::{
graph::CrateId,
Expand Down Expand Up @@ -54,13 +55,13 @@ pub fn check_for_storage_definition(
fn inject_context_in_storage_field(field: &mut UnresolvedType) -> Result<(), AztecMacroError> {
match &mut field.typ {
UnresolvedTypeData::Named(path, generics, _) => {
generics.push(make_type(UnresolvedTypeData::Named(
generics.ordered_args.push(make_type(UnresolvedTypeData::Named(
ident_path("Context"),
vec![],
GenericTypeArgs::default(),
false,
)));
match path.last_name() {
"Map" => inject_context_in_storage_field(&mut generics[1]),
"Map" => inject_context_in_storage_field(&mut generics.ordered_args[1]),
_ => Ok(()),
}
}
Expand Down Expand Up @@ -144,7 +145,10 @@ pub fn generate_storage_field_constructor(
generate_storage_field_constructor(
// Map is expected to have three generic parameters: key, value and context (i.e.
// Map<K, V, Context>. Here `get(1)` fetches the value type.
&(type_ident.clone(), generics.get(1).unwrap().clone()),
&(
type_ident.clone(),
generics.ordered_args.get(1).unwrap().clone(),
),
variable("slot"),
)?,
),
Expand Down Expand Up @@ -219,8 +223,11 @@ pub fn generate_storage_implementation(

// This is the type over which the impl is generic.
let generic_context_ident = ident("Context");
let generic_context_type =
make_type(UnresolvedTypeData::Named(ident_path("Context"), vec![], true));
let generic_context_type = make_type(UnresolvedTypeData::Named(
ident_path("Context"),
GenericTypeArgs::default(),
true,
));

let init = NoirFunction::normal(FunctionDefinition::normal(
&ident("init"),
Expand All @@ -231,13 +238,12 @@ pub fn generate_storage_implementation(
&return_type(chained_path!("Self")),
));

let ordered_args = vec![generic_context_type.clone()];
let generics = GenericTypeArgs { ordered_args, named_args: Vec::new() };

let storage_impl = TypeImpl {
object_type: UnresolvedType {
typ: UnresolvedTypeData::Named(
chained_path!(storage_struct_name),
vec![generic_context_type.clone()],
true,
),
typ: UnresolvedTypeData::Named(chained_path!(storage_struct_name), generics, true),
span: Span::default(),
},
type_span: Span::default(),
Expand Down
30 changes: 22 additions & 8 deletions aztec_macros/src/utils/parse_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ use noirc_frontend::{
ast::{
ArrayLiteral, AssignStatement, BlockExpression, CallExpression, CastExpression,
ConstrainStatement, ConstructorExpression, Expression, ExpressionKind, ForLoopStatement,
ForRange, FunctionReturnType, Ident, IfExpression, IndexExpression, InfixExpression,
LValue, Lambda, LetStatement, Literal, MemberAccessExpression, MethodCallExpression,
ModuleDeclaration, NoirFunction, NoirStruct, NoirTrait, NoirTraitImpl, NoirTypeAlias, Path,
PathSegment, Pattern, PrefixExpression, Statement, StatementKind, TraitImplItem, TraitItem,
TypeImpl, UnresolvedGeneric, UnresolvedGenerics, UnresolvedTraitConstraint, UnresolvedType,
UnresolvedTypeData, UnresolvedTypeExpression, UseTree, UseTreeKind,
ForRange, FunctionReturnType, GenericTypeArgs, Ident, IfExpression, IndexExpression,
InfixExpression, LValue, Lambda, LetStatement, Literal, MemberAccessExpression,
MethodCallExpression, ModuleDeclaration, NoirFunction, NoirStruct, NoirTrait,
NoirTraitImpl, NoirTypeAlias, Path, PathSegment, Pattern, PrefixExpression, Statement,
StatementKind, TraitImplItem, TraitItem, TypeImpl, UnresolvedGeneric, UnresolvedGenerics,
UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression,
UseTree, UseTreeKind,
},
parser::{Item, ItemKind, ParsedSubModule, ParserError},
ParsedModule,
Expand Down Expand Up @@ -297,6 +298,14 @@ fn empty_unresolved_types(unresolved_types: &mut [UnresolvedType]) {
}
}

fn empty_type_args(generics: &mut GenericTypeArgs) {
empty_unresolved_types(&mut generics.ordered_args);
for (name, typ) in &mut generics.named_args {
empty_ident(name);
empty_unresolved_type(typ);
}
}

fn empty_unresolved_type(unresolved_type: &mut UnresolvedType) {
unresolved_type.span = Default::default();

Expand All @@ -318,11 +327,11 @@ fn empty_unresolved_type(unresolved_type: &mut UnresolvedType) {
}
UnresolvedTypeData::Named(path, unresolved_types, _) => {
empty_path(path);
empty_unresolved_types(unresolved_types);
empty_type_args(unresolved_types);
}
UnresolvedTypeData::TraitAsType(path, unresolved_types) => {
empty_path(path);
empty_unresolved_types(unresolved_types);
empty_type_args(unresolved_types);
}
UnresolvedTypeData::MutableReference(unresolved_type) => {
empty_unresolved_type(unresolved_type)
Expand Down Expand Up @@ -543,5 +552,10 @@ fn empty_unresolved_type_expression(unresolved_type_expression: &mut UnresolvedT
empty_unresolved_type_expression(rhs);
}
UnresolvedTypeExpression::Constant(_, _) => (),
UnresolvedTypeExpression::AsTraitPath(path) => {
empty_unresolved_type(&mut path.typ);
empty_path(&mut path.trait_path);
empty_ident(&mut path.impl_item);
}
}
}
96 changes: 78 additions & 18 deletions compiler/noirc_frontend/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ pub enum UnresolvedTypeData {
Parenthesized(Box<UnresolvedType>),

/// A Named UnresolvedType can be a struct type or a type variable
Named(Path, Vec<UnresolvedType>, /*is_synthesized*/ bool),
Named(Path, GenericTypeArgs, /*is_synthesized*/ bool),

/// A Trait as return type or parameter of function, including its generics
TraitAsType(Path, Vec<UnresolvedType>),
TraitAsType(Path, GenericTypeArgs),

/// &mut T
MutableReference(Box<UnresolvedType>),
Expand Down Expand Up @@ -151,6 +151,46 @@ pub struct UnresolvedType {
pub span: Span,
}

/// An argument to a generic type or trait.
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum GenericTypeArg {
/// An ordered argument, e.g. `<A, B, C>`
Ordered(UnresolvedType),

/// A named argument, e.g. `<A = B, C = D, E = F>`.
/// Used for associated types.
Named(Ident, UnresolvedType),
}

#[derive(Debug, Default, PartialEq, Eq, Clone, Hash)]
pub struct GenericTypeArgs {
/// Each ordered argument, e.g. `<A, B, C>`
pub ordered_args: Vec<UnresolvedType>,

/// All named arguments, e.g. `<A = B, C = D, E = F>`.
/// Used for associated types.
pub named_args: Vec<(Ident, UnresolvedType)>,
}

impl GenericTypeArgs {
pub fn is_empty(&self) -> bool {
self.ordered_args.is_empty() && self.named_args.is_empty()
}
}

impl From<Vec<GenericTypeArg>> for GenericTypeArgs {
fn from(args: Vec<GenericTypeArg>) -> Self {
let mut this = GenericTypeArgs::default();
for arg in args {
match arg {
GenericTypeArg::Ordered(typ) => this.ordered_args.push(typ),
GenericTypeArg::Named(name, typ) => this.named_args.push((name, typ)),
}
}
this
}
}

/// Type wrapper for a member access
pub struct UnaryRhsMemberAccess {
pub method_or_field: Ident,
Expand All @@ -176,6 +216,7 @@ pub enum UnresolvedTypeExpression {
Box<UnresolvedTypeExpression>,
Span,
),
AsTraitPath(Box<AsTraitPath>),
}

impl Recoverable for UnresolvedType {
Expand All @@ -184,6 +225,32 @@ impl Recoverable for UnresolvedType {
}
}

impl std::fmt::Display for GenericTypeArg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GenericTypeArg::Ordered(typ) => typ.fmt(f),
GenericTypeArg::Named(name, typ) => write!(f, "{name} = {typ}"),
}
}
}

impl std::fmt::Display for GenericTypeArgs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_empty() {
Ok(())
} else {
let mut args = vecmap(&self.ordered_args, ToString::to_string).join(", ");

if !self.ordered_args.is_empty() && !self.named_args.is_empty() {
args += ", ";
}

args += &vecmap(&self.named_args, |(name, typ)| format!("{name} = {typ}")).join(", ");
write!(f, "<{args}>")
}
}
}

impl std::fmt::Display for UnresolvedTypeData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use UnresolvedTypeData::*;
Expand All @@ -195,22 +262,8 @@ impl std::fmt::Display for UnresolvedTypeData {
Signedness::Signed => write!(f, "i{num_bits}"),
Signedness::Unsigned => write!(f, "u{num_bits}"),
},
Named(s, args, _) => {
let args = vecmap(args, |arg| ToString::to_string(&arg.typ));
if args.is_empty() {
write!(f, "{s}")
} else {
write!(f, "{}<{}>", s, args.join(", "))
}
}
TraitAsType(s, args) => {
let args = vecmap(args, |arg| ToString::to_string(&arg.typ));
if args.is_empty() {
write!(f, "impl {s}")
} else {
write!(f, "impl {}<{}>", s, args.join(", "))
}
}
Named(s, args, _) => write!(f, "{s}{args}"),
TraitAsType(s, args) => write!(f, "impl {s}{args}"),
Tuple(elements) => {
let elements = vecmap(elements, ToString::to_string);
write!(f, "({})", elements.join(", "))
Expand Down Expand Up @@ -263,6 +316,7 @@ impl std::fmt::Display for UnresolvedTypeExpression {
UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, _) => {
write!(f, "({lhs} {op} {rhs})")
}
UnresolvedTypeExpression::AsTraitPath(path) => write!(f, "{path}"),
}
}
}
Expand Down Expand Up @@ -334,6 +388,9 @@ impl UnresolvedTypeExpression {
UnresolvedTypeExpression::Variable(path) => path.span(),
UnresolvedTypeExpression::Constant(_, span) => *span,
UnresolvedTypeExpression::BinaryOperation(_, _, _, span) => *span,
UnresolvedTypeExpression::AsTraitPath(path) => {
path.trait_path.span.merge(path.impl_item.span())
}
}
}

Expand Down Expand Up @@ -376,6 +433,9 @@ impl UnresolvedTypeExpression {
};
Ok(UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, expr.span))
}
ExpressionKind::AsTraitPath(path) => {
Ok(UnresolvedTypeExpression::AsTraitPath(Box::new(path)))
}
_ => Err(expr),
}
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/noirc_frontend/src/ast/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use iter_extended::vecmap;
use noirc_errors::{Span, Spanned};

use super::{
BlockExpression, Expression, ExpressionKind, IndexExpression, MemberAccessExpression,
MethodCallExpression, UnresolvedType,
BlockExpression, Expression, ExpressionKind, GenericTypeArgs, IndexExpression,
MemberAccessExpression, MethodCallExpression, UnresolvedType,
};
use crate::elaborator::types::SELF_TYPE_NAME;
use crate::lexer::token::SpannedToken;
Expand Down Expand Up @@ -371,6 +371,7 @@ impl UseTree {
pub struct AsTraitPath {
pub typ: UnresolvedType,
pub trait_path: Path,
pub trait_generics: GenericTypeArgs,
pub impl_item: Ident,
}

Expand Down
19 changes: 7 additions & 12 deletions compiler/noirc_frontend/src/ast/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use crate::ast::{
use crate::macros_api::SecondaryAttribute;
use crate::node_interner::TraitId;

use super::GenericTypeArgs;

/// AST node for trait definitions:
/// `trait name<generics> { ... items ... }`
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -62,7 +64,8 @@ pub struct NoirTraitImpl {
pub impl_generics: UnresolvedGenerics,

pub trait_name: Path,
pub trait_generics: Vec<UnresolvedType>,

pub trait_generics: GenericTypeArgs,

pub object_type: UnresolvedType,

Expand All @@ -88,7 +91,7 @@ pub struct UnresolvedTraitConstraint {
pub struct TraitBound {
pub trait_path: Path,
pub trait_id: Option<TraitId>, // initially None, gets assigned during DC
pub trait_generics: Vec<UnresolvedType>,
pub trait_generics: GenericTypeArgs,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -179,21 +182,13 @@ impl Display for UnresolvedTraitConstraint {

impl Display for TraitBound {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let generics = vecmap(&self.trait_generics, |generic| generic.to_string());
if !generics.is_empty() {
write!(f, "{}<{}>", self.trait_path, generics.join(", "))
} else {
write!(f, "{}", self.trait_path)
}
write!(f, "{}{}", self.trait_path, self.trait_generics)
}
}

impl Display for NoirTraitImpl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let generics = vecmap(&self.trait_generics, |generic| generic.to_string());
let generics = generics.join(", ");

writeln!(f, "impl {}<{}> for {} {{", self.trait_name, generics, self.object_type)?;
writeln!(f, "impl {}{} for {} {{", self.trait_name, self.trait_generics, self.object_type)?;

for item in self.items.iter() {
let item = item.to_string();
Expand Down
Loading
Loading