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: visibility for type aliases #6058

Merged
merged 12 commits into from
Sep 25, 2024
6 changes: 4 additions & 2 deletions compiler/noirc_frontend/src/ast/type_alias.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Ident, UnresolvedGenerics, UnresolvedType};
use super::{Ident, ItemVisibility, UnresolvedGenerics, UnresolvedType};
use iter_extended::vecmap;
use noirc_errors::Span;
use std::fmt::Display;
Expand All @@ -9,6 +9,7 @@ pub struct NoirTypeAlias {
pub name: Ident,
pub generics: UnresolvedGenerics,
pub typ: UnresolvedType,
pub visibility: ItemVisibility,
pub span: Span,
}

Expand All @@ -17,9 +18,10 @@ impl NoirTypeAlias {
name: Ident,
generics: UnresolvedGenerics,
typ: UnresolvedType,
visibility: ItemVisibility,
span: Span,
) -> NoirTypeAlias {
NoirTypeAlias { name, generics, typ, span }
NoirTypeAlias { name, generics, typ, visibility, span }
}
}

Expand Down
22 changes: 19 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 @@ -314,6 +314,7 @@
let doc_comments = type_alias.doc_comments;
let type_alias = type_alias.item;
let name = type_alias.name.clone();
let visibility = type_alias.visibility;

// And store the TypeId -> TypeAlias mapping somewhere it is reachable
let unresolved = UnresolvedTypeAlias {
Expand All @@ -335,8 +336,19 @@
context.def_interner.set_doc_comments(ReferenceId::Alias(type_alias_id), doc_comments);

// Add the type alias to scope so its path can be looked up later
let result = self.def_collector.def_map.modules[self.module_id.0]
.declare_type_alias(name.clone(), type_alias_id);
let result = self.def_collector.def_map.modules[self.module_id.0].declare_type_alias(
name.clone(),
visibility,
type_alias_id,
);

let parent_module_id = ModuleId { krate, local_id: self.module_id };
context.def_interner.usage_tracker.add_unused_item(
parent_module_id,
name.clone(),
UnusedItem::TypeAlias(type_alias_id),
visibility,
);

if let Err((first_def, second_def)) = result {
let err = DefCollectorErrorKind::Duplicate {
Expand Down Expand Up @@ -533,7 +545,11 @@
TraitItem::Type { name } => {
if let Err((first_def, second_def)) = self.def_collector.def_map.modules
[trait_id.0.local_id.0]
.declare_type_alias(name.clone(), TypeAliasId::dummy_id())
.declare_type_alias(
name.clone(),
ItemVisibility::Public,
TypeAliasId::dummy_id(),
)
{
let error = DefCollectorErrorKind::Duplicate {
typ: DuplicateType::TraitAssociatedType,
Expand Down Expand Up @@ -828,7 +844,7 @@
// if it's an inline module, or the first char of a the file if it's an external module.
// - `location` will always point to the token "foo" in `mod foo` regardless of whether
// it's inline or external.
// Eventually the location put in `ModuleData` is used for codelenses about `contract`s,

Check warning on line 847 in compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (codelenses)
// so we keep using `location` so that it continues to work as usual.
let location = Location::new(mod_name.span(), mod_location.file);
let new_module =
Expand Down
3 changes: 2 additions & 1 deletion compiler/noirc_frontend/src/hir/def_map/module_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,10 @@ impl ModuleData {
pub fn declare_type_alias(
&mut self,
name: Ident,
visibility: ItemVisibility,
id: TypeAliasId,
) -> Result<(), (Ident, Ident)> {
self.declare(name, ItemVisibility::Public, id.into(), None)
self.declare(name, visibility, id.into(), None)
}

pub fn declare_trait(
Expand Down
23 changes: 15 additions & 8 deletions compiler/noirc_frontend/src/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,21 @@ fn contract(
fn type_alias_definition() -> impl NoirParser<TopLevelStatementKind> {
use self::Keyword::Type;

let p = ignore_then_commit(keyword(Type), ident());
let p = then_commit(p, function::generics());
let p = then_commit_ignore(p, just(Token::Assign));
let p = then_commit(p, parse_type());

p.map_with_span(|((name, generics), typ), span| {
TopLevelStatementKind::TypeAlias(NoirTypeAlias { name, generics, typ, span })
})
item_visibility()
.then_ignore(keyword(Type))
.then(ident())
.then(function::generics())
.then_ignore(just(Token::Assign))
.then(parse_type())
.map_with_span(|(((visibility, name), generics), typ), span| {
TopLevelStatementKind::TypeAlias(NoirTypeAlias {
name,
generics,
typ,
visibility,
span,
})
})
}

fn self_parameter() -> impl NoirParser<Param> {
Expand Down
26 changes: 25 additions & 1 deletion compiler/noirc_frontend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2333,7 +2333,7 @@
}

#[test]
fn underflowing_u8() {

Check warning on line 2336 in compiler/noirc_frontend/src/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (underflowing)
let src = r#"
fn main() {
let _: u8 = -1;
Expand Down Expand Up @@ -2371,7 +2371,7 @@
}

#[test]
fn underflowing_i8() {

Check warning on line 2374 in compiler/noirc_frontend/src/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (underflowing)
let src = r#"
fn main() {
let _: i8 = -129;
Expand Down Expand Up @@ -2931,7 +2931,7 @@
fn incorrect_generic_count_on_type_alias() {
let src = r#"
struct Foo {}
type Bar = Foo<i32>;
pub type Bar = Foo<i32>;
fn main() {}
"#;

Expand Down Expand Up @@ -3475,6 +3475,30 @@
assert_eq!(*item_type, "trait");
}

#[test]
fn errors_on_unused_type_alias() {
let src = r#"
type Foo = Field;
type Bar = Field;

pub fn bar(_: Bar) {}

fn main() {}
"#;

let errors = get_program_errors(src);
assert_eq!(errors.len(), 1);

let CompilationError::ResolverError(ResolverError::UnusedItem { ident, item_type }) =
&errors[0].0
else {
panic!("Expected an unused item error");
};

assert_eq!(ident.to_string(), "Foo");
assert_eq!(*item_type, "type alias");
}

#[test]
fn constrained_reference_to_unconstrained() {
let src = r#"
Expand Down Expand Up @@ -3516,7 +3540,7 @@
}

#[test]
fn arithmetic_generics_canonicalization_deduplication_regression() {

Check warning on line 3543 in compiler/noirc_frontend/src/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (canonicalization)
let source = r#"
struct ArrData<let N: u32> {
a: [Field; N],
Expand Down
4 changes: 3 additions & 1 deletion compiler/noirc_frontend/src/usage_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
ast::{Ident, ItemVisibility},
hir::def_map::ModuleId,
macros_api::StructId,
node_interner::{FuncId, TraitId},
node_interner::{FuncId, TraitId, TypeAliasId},
};

#[derive(Debug)]
Expand All @@ -13,6 +13,7 @@ pub enum UnusedItem {
Function(FuncId),
Struct(StructId),
Trait(TraitId),
TypeAlias(TypeAliasId),
}

impl UnusedItem {
Expand All @@ -22,6 +23,7 @@ impl UnusedItem {
UnusedItem::Function(_) => "function",
UnusedItem::Struct(_) => "struct",
UnusedItem::Trait(_) => "trait",
UnusedItem::TypeAlias(_) => "type alias",
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions docs/docs/noir/concepts/data_types/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ type Bad2 = Bad1;
// ^^^^^^^^^^^ 'Bad2' recursively depends on itself: Bad2 -> Bad1 -> Bad2
```

By default, like functions, type aliases are private to the module the exist in. You can use `pub`
to make the type alias public or `pub(crate)` to make it public to just its crate:

```rust
// This type alias is now public
pub type Id = u8;
```

## Wildcard Type
Noir can usually infer the type of the variable from the context, so specifying the type of a variable is only required when it cannot be inferred. However, specifying a complex type can be tedious, especially when it has multiple generic arguments. Often some of the generic types can be inferred from the context, and Noir only needs a hint to properly infer the other types. We can partially specify a variable's type by using `_` as a marker, indicating where we still want the compiler to infer the type.

Expand Down
2 changes: 1 addition & 1 deletion noir_stdlib/src/meta/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use crate::hash::poseidon2::Poseidon2Hasher;

// A derive function is one that given a struct definition can
// create us a quoted trait impl from it.
type DeriveFunction = fn(StructDefinition) -> Quoted;
pub type DeriveFunction = fn(StructDefinition) -> Quoted;

// We'll keep a global HANDLERS map to keep track of the derive handler for each trait
comptime mut global HANDLERS: UHashMap<TraitDefinition, DeriveFunction, BuildHasherDefault<Poseidon2Hasher>> = UHashMap::default();
Expand Down
Loading