diff --git a/compiler/noirc_frontend/src/ast/structure.rs b/compiler/noirc_frontend/src/ast/structure.rs index 1675629ff14..8c8fe6e6387 100644 --- a/compiler/noirc_frontend/src/ast/structure.rs +++ b/compiler/noirc_frontend/src/ast/structure.rs @@ -19,8 +19,15 @@ pub struct NoirStruct { pub span: Span, } +impl NoirStruct { + pub fn is_abi(&self) -> bool { + self.attributes.iter().any(|attr| attr.is_abi()) + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub struct StructField { + pub visibility: ItemVisibility, pub name: Ident, pub typ: UnresolvedType, } diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 30249a10ed5..32c05ad00f4 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -7,9 +7,9 @@ use rustc_hash::FxHashSet as HashSet; use crate::{ ast::{ ArrayLiteral, BlockExpression, CallExpression, CastExpression, ConstructorExpression, - Expression, ExpressionKind, Ident, IfExpression, IndexExpression, InfixExpression, Lambda, - Literal, MemberAccessExpression, MethodCallExpression, PrefixExpression, StatementKind, - UnaryOp, UnresolvedTypeData, UnresolvedTypeExpression, + Expression, ExpressionKind, Ident, IfExpression, IndexExpression, InfixExpression, + ItemVisibility, Lambda, Literal, MemberAccessExpression, MethodCallExpression, + PrefixExpression, StatementKind, UnaryOp, UnresolvedTypeData, UnresolvedTypeExpression, }, hir::{ comptime::{self, InterpreterError}, @@ -549,7 +549,7 @@ impl<'context> Elaborator<'context> { let generics = struct_generics.clone(); let fields = constructor.fields; - let field_types = r#type.borrow().get_fields(&struct_generics); + let field_types = r#type.borrow().get_fields_with_visibility(&struct_generics); let fields = self.resolve_constructor_expr_fields(struct_type.clone(), field_types, fields, span); let expr = HirExpression::Constructor(HirConstructorExpression { @@ -577,7 +577,7 @@ impl<'context> Elaborator<'context> { fn resolve_constructor_expr_fields( &mut self, struct_type: Shared, - field_types: Vec<(String, Type)>, + field_types: Vec<(String, ItemVisibility, Type)>, fields: Vec<(Ident, Expression)>, span: Span, ) -> Vec<(Ident, ExprId)> { @@ -589,10 +589,11 @@ impl<'context> Elaborator<'context> { let expected_field_with_index = field_types .iter() .enumerate() - .find(|(_, (name, _))| name == &field_name.0.contents); - let expected_index = expected_field_with_index.map(|(index, _)| index); + .find(|(_, (name, _, _))| name == &field_name.0.contents); + let expected_index_and_visibility = + expected_field_with_index.map(|(index, (_, visibility, _))| (index, visibility)); let expected_type = - expected_field_with_index.map(|(_, (_, typ))| typ).unwrap_or(&Type::Error); + expected_field_with_index.map(|(_, (_, _, typ))| typ).unwrap_or(&Type::Error); let field_span = field.span; let (resolved, field_type) = self.elaborate_expression(field); @@ -619,11 +620,21 @@ impl<'context> Elaborator<'context> { }); } - if let Some(expected_index) = expected_index { + if let Some((index, visibility)) = expected_index_and_visibility { + let struct_type = struct_type.borrow(); + let field_span = field_name.span(); + let field_name = &field_name.0.contents; + self.check_struct_field_visibility( + &struct_type, + field_name, + *visibility, + field_span, + ); + self.interner.add_struct_member_reference( - struct_type.borrow().id, - expected_index, - Location::new(field_name.span(), self.file), + struct_type.id, + index, + Location::new(field_span, self.file), ); } diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index ddbb80e2bfc..a9173621fc7 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -3,7 +3,7 @@ use std::{ rc::Rc, }; -use crate::ast::ItemVisibility; +use crate::{ast::ItemVisibility, StructField}; use crate::{ ast::{ BlockExpression, FunctionKind, GenericTypeArgs, Ident, NoirFunction, NoirStruct, Param, @@ -751,7 +751,7 @@ impl<'context> Elaborator<'context> { ); if is_entry_point { - self.mark_parameter_type_as_used(&typ); + self.mark_type_as_used(&typ); } let pattern = self.elaborate_pattern_and_store_ids( @@ -832,33 +832,33 @@ impl<'context> Elaborator<'context> { self.current_item = None; } - fn mark_parameter_type_as_used(&mut self, typ: &Type) { + fn mark_type_as_used(&mut self, typ: &Type) { match typ { - Type::Array(_n, typ) => self.mark_parameter_type_as_used(typ), - Type::Slice(typ) => self.mark_parameter_type_as_used(typ), + Type::Array(_n, typ) => self.mark_type_as_used(typ), + Type::Slice(typ) => self.mark_type_as_used(typ), Type::Tuple(types) => { for typ in types { - self.mark_parameter_type_as_used(typ); + self.mark_type_as_used(typ); } } Type::Struct(struct_type, generics) => { self.mark_struct_as_constructed(struct_type.clone()); for generic in generics { - self.mark_parameter_type_as_used(generic); + self.mark_type_as_used(generic); } for (_, typ) in struct_type.borrow().get_fields(generics) { - self.mark_parameter_type_as_used(&typ); + self.mark_type_as_used(&typ); } } Type::Alias(alias_type, generics) => { - self.mark_parameter_type_as_used(&alias_type.borrow().get_type(generics)); + self.mark_type_as_used(&alias_type.borrow().get_type(generics)); } Type::MutableReference(typ) => { - self.mark_parameter_type_as_used(typ); + self.mark_type_as_used(typ); } Type::InfixExpr(left, _op, right) => { - self.mark_parameter_type_as_used(left); - self.mark_parameter_type_as_used(right); + self.mark_type_as_used(left); + self.mark_type_as_used(right); } Type::FieldElement | Type::Integer(..) @@ -1277,6 +1277,13 @@ impl<'context> Elaborator<'context> { self.local_module = typ.module_id; let fields = self.resolve_struct_fields(&typ.struct_def, *type_id); + + if typ.struct_def.is_abi() { + for field in &fields { + self.mark_type_as_used(&field.typ); + } + } + let fields_len = fields.len(); self.interner.update_struct(*type_id, |struct_def| { struct_def.set_fields(fields); @@ -1315,7 +1322,7 @@ impl<'context> Elaborator<'context> { &mut self, unresolved: &NoirStruct, struct_id: StructId, - ) -> Vec<(Ident, Type)> { + ) -> Vec { self.recover_generics(|this| { this.current_item = Some(DependencyId::Struct(struct_id)); @@ -1327,7 +1334,8 @@ impl<'context> Elaborator<'context> { let fields = vecmap(&unresolved.fields, |field| { let ident = &field.item.name; let typ = &field.item.typ; - (ident.clone(), this.resolve_type(typ.clone())) + let visibility = field.item.visibility; + StructField { visibility, name: ident.clone(), typ: this.resolve_type(typ.clone()) } }); this.resolving_ids.remove(&struct_id); diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index bb8d041eab4..0f6cb78fae7 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -4,7 +4,8 @@ use rustc_hash::FxHashSet as HashSet; use crate::{ ast::{ - Expression, ExpressionKind, Ident, Path, Pattern, TypePath, UnresolvedType, ERROR_IDENT, + Expression, ExpressionKind, Ident, ItemVisibility, Path, Pattern, TypePath, UnresolvedType, + ERROR_IDENT, }, hir::{ def_collector::dc_crate::CompilationError, @@ -272,7 +273,9 @@ impl<'context> Elaborator<'context> { let mut unseen_fields = struct_type.borrow().field_names(); for (field, pattern) in fields { - let field_type = expected_type.get_field_type(&field.0.contents).unwrap_or(Type::Error); + let (field_type, visibility) = expected_type + .get_field_type_and_visibility(&field.0.contents) + .unwrap_or((Type::Error, ItemVisibility::Public)); let resolved = self.elaborate_pattern_mut( pattern, field_type, @@ -286,6 +289,13 @@ impl<'context> Elaborator<'context> { if unseen_fields.contains(&field) { unseen_fields.remove(&field); seen_fields.insert(field.clone()); + + self.check_struct_field_visibility( + &struct_type.borrow(), + &field.0.contents, + visibility, + field.span(), + ); } else if seen_fields.contains(&field) { // duplicate field self.push_err(ResolverError::DuplicateField { field: field.clone() }); diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index 6d5d0c9b467..293b3c2bee1 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -3,11 +3,13 @@ use noirc_errors::{Location, Span, Spanned}; use crate::{ ast::{ AssignStatement, BinaryOpKind, ConstrainKind, ConstrainStatement, Expression, - ExpressionKind, ForLoopStatement, ForRange, InfixExpression, LValue, LetStatement, Path, - Statement, StatementKind, + ExpressionKind, ForLoopStatement, ForRange, Ident, InfixExpression, ItemVisibility, LValue, + LetStatement, Path, Statement, StatementKind, }, hir::{ - resolution::errors::ResolverError, + resolution::{ + errors::ResolverError, import::PathResolutionError, visibility::struct_field_is_visible, + }, type_check::{Source, TypeCheckError}, }, hir_def::{ @@ -18,7 +20,7 @@ use crate::{ }, }, node_interner::{DefinitionId, DefinitionKind, GlobalId, StmtId}, - Type, + StructType, Type, }; use super::{lints, Elaborator}; @@ -439,10 +441,12 @@ impl<'context> Elaborator<'context> { match &lhs_type { Type::Struct(s, args) => { let s = s.borrow(); - if let Some((field, index)) = s.get_field(field_name, args) { + if let Some((field, visibility, index)) = s.get_field(field_name, args) { let reference_location = Location::new(span, self.file); self.interner.add_struct_member_reference(s.id, index, reference_location); + self.check_struct_field_visibility(&s, field_name, visibility, span); + return Some((field, index)); } } @@ -497,6 +501,20 @@ impl<'context> Elaborator<'context> { None } + pub(super) fn check_struct_field_visibility( + &mut self, + struct_type: &StructType, + field_name: &str, + visibility: ItemVisibility, + span: Span, + ) { + if !struct_field_is_visible(struct_type, visibility, self.module_id(), self.def_maps) { + self.push_err(ResolverError::PathResolutionError(PathResolutionError::Private( + Ident::new(field_name.to_string(), span), + ))); + } + } + fn elaborate_comptime_statement(&mut self, statement: Statement) -> (HirStatement, Type) { let span = statement.span; let (hir_statement, _typ) = diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index ec6b5eb0870..170cd67e146 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -19,8 +19,8 @@ use rustc_hash::FxHashMap as HashMap; use crate::{ ast::{ ArrayLiteral, BlockExpression, ConstrainKind, Expression, ExpressionKind, ForRange, - FunctionKind, FunctionReturnType, Ident, IntegerBitSize, LValue, Literal, Pattern, - Signedness, Statement, StatementKind, UnaryOp, UnresolvedType, UnresolvedTypeData, + FunctionKind, FunctionReturnType, Ident, IntegerBitSize, ItemVisibility, LValue, Literal, + Pattern, Signedness, Statement, StatementKind, UnaryOp, UnresolvedType, UnresolvedTypeData, Visibility, }, hir::{ @@ -32,10 +32,9 @@ use crate::{ def_collector::dc_crate::CollectedItems, def_map::ModuleDefId, }, - hir_def::{ - expr::{HirExpression, HirLiteral}, - function::FunctionBody, - }, + hir_def::expr::{HirExpression, HirLiteral}, + hir_def::function::FunctionBody, + hir_def::{self}, node_interner::{DefinitionKind, NodeInterner, TraitImplKind}, parser::{Parser, StatementOrExpressionOrLValue}, token::{Attribute, SecondaryAttribute, Token}, @@ -498,9 +497,9 @@ fn struct_def_fields( let mut fields = im::Vector::new(); - for (name, typ) in struct_def.get_fields_as_written() { - let name = Value::Quoted(Rc::new(vec![Token::Ident(name)])); - let typ = Value::Type(typ); + for field in struct_def.get_fields_as_written() { + let name = Value::Quoted(Rc::new(vec![Token::Ident(field.name.to_string())])); + let typ = Value::Type(field.typ); fields.push_back(Value::Tuple(vec![name, typ])); } @@ -567,7 +566,11 @@ fn struct_def_set_fields( match name_tokens.first() { Some(Token::Ident(name)) if name_tokens.len() == 1 => { - Ok((Ident::new(name.clone(), field_location.span), typ)) + Ok(hir_def::types::StructField { + visibility: ItemVisibility::Public, + name: Ident::new(name.clone(), field_location.span), + typ, + }) } _ => { let value = name_value.display(interner).to_string(); diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index ba1075dfb30..65912023661 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -1013,12 +1013,14 @@ pub fn collect_struct( let parent_module_id = ModuleId { krate, local_id: module_id }; - interner.usage_tracker.add_unused_item( - parent_module_id, - name.clone(), - UnusedItem::Struct(id), - visibility, - ); + if !unresolved.struct_def.is_abi() { + interner.usage_tracker.add_unused_item( + parent_module_id, + name.clone(), + UnusedItem::Struct(id), + visibility, + ); + } if let Err((first_def, second_def)) = result { let error = DefCollectorErrorKind::Duplicate { diff --git a/compiler/noirc_frontend/src/hir/resolution/import.rs b/compiler/noirc_frontend/src/hir/resolution/import.rs index f0b7f941ef8..93039b1ea7f 100644 --- a/compiler/noirc_frontend/src/hir/resolution/import.rs +++ b/compiler/noirc_frontend/src/hir/resolution/import.rs @@ -12,6 +12,7 @@ use crate::ast::{Ident, ItemVisibility, Path, PathKind, PathSegment}; use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleDefId, ModuleId, PerNs}; use super::errors::ResolverError; +use super::visibility::can_reference_module_id; #[derive(Debug, Clone)] pub struct ImportDirective { @@ -169,7 +170,7 @@ fn resolve_path_to_ns( import_path, import_directive.module_id, def_maps, - true, + true, // plain or crate usage_tracker, path_references, ); @@ -199,7 +200,7 @@ fn resolve_path_to_ns( import_path, import_directive.module_id, def_maps, - true, + true, // plain or crate usage_tracker, path_references, ) @@ -224,7 +225,7 @@ fn resolve_path_to_ns( import_path, parent_module_id, def_maps, - false, + false, // plain or crate usage_tracker, path_references, ) @@ -253,7 +254,7 @@ fn resolve_path_from_crate_root( import_path, starting_mod, def_maps, - false, + true, // plain or crate usage_tracker, path_references, ) @@ -266,7 +267,7 @@ fn resolve_name_in_module( import_path: &[PathSegment], starting_mod: LocalModuleId, def_maps: &BTreeMap, - plain: bool, + plain_or_crate: bool, usage_tracker: &mut UsageTracker, path_references: &mut Option<&mut Vec>, ) -> NamespaceResolutionResult { @@ -331,9 +332,9 @@ fn resolve_name_in_module( }; warning = warning.or_else(|| { - // If the path is plain, the first segment will always refer to + // If the path is plain or crate, the first segment will always refer to // something that's visible from the current module. - if (plain && index == 0) + if (plain_or_crate && index == 0) || can_reference_module_id( def_maps, importing_crate, @@ -424,61 +425,3 @@ fn resolve_external_dep( path_references, ) } - -// Returns false if the given private function is being called from a non-child module, or -// if the given pub(crate) function is being called from another crate. Otherwise returns true. -pub fn can_reference_module_id( - def_maps: &BTreeMap, - importing_crate: CrateId, - current_module: LocalModuleId, - target_module: ModuleId, - visibility: ItemVisibility, -) -> bool { - // Note that if the target module is in a different crate from the current module then we will either - // return true as the target module is public or return false as it is private without looking at the `CrateDefMap` in either case. - let same_crate = target_module.krate == importing_crate; - let target_crate_def_map = &def_maps[&target_module.krate]; - - match visibility { - ItemVisibility::Public => true, - ItemVisibility::PublicCrate => same_crate, - ItemVisibility::Private => { - same_crate - && (module_descendent_of_target( - target_crate_def_map, - target_module.local_id, - current_module, - ) || module_is_parent_of_struct_module( - target_crate_def_map, - current_module, - target_module.local_id, - )) - } - } -} - -// Returns true if `current` is a (potentially nested) child module of `target`. -// This is also true if `current == target`. -fn module_descendent_of_target( - def_map: &CrateDefMap, - target: LocalModuleId, - current: LocalModuleId, -) -> bool { - if current == target { - return true; - } - - def_map.modules[current.0] - .parent - .map_or(false, |parent| module_descendent_of_target(def_map, target, parent)) -} - -/// Returns true if `target` is a struct and its parent is `current`. -fn module_is_parent_of_struct_module( - def_map: &CrateDefMap, - current: LocalModuleId, - target: LocalModuleId, -) -> bool { - let module_data = &def_map.modules[target.0]; - module_data.is_struct && module_data.parent == Some(current) -} diff --git a/compiler/noirc_frontend/src/hir/resolution/mod.rs b/compiler/noirc_frontend/src/hir/resolution/mod.rs index 01a3fe856e5..223b88b5c5d 100644 --- a/compiler/noirc_frontend/src/hir/resolution/mod.rs +++ b/compiler/noirc_frontend/src/hir/resolution/mod.rs @@ -8,3 +8,4 @@ pub mod errors; pub mod import; pub mod path_resolver; +pub mod visibility; diff --git a/compiler/noirc_frontend/src/hir/resolution/visibility.rs b/compiler/noirc_frontend/src/hir/resolution/visibility.rs new file mode 100644 index 00000000000..c0c1429dbca --- /dev/null +++ b/compiler/noirc_frontend/src/hir/resolution/visibility.rs @@ -0,0 +1,96 @@ +use crate::graph::CrateId; +use crate::StructType; + +use std::collections::BTreeMap; + +use crate::ast::ItemVisibility; +use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}; + +// Returns false if the given private function is being called from a non-child module, or +// if the given pub(crate) function is being called from another crate. Otherwise returns true. +pub fn can_reference_module_id( + def_maps: &BTreeMap, + importing_crate: CrateId, + current_module: LocalModuleId, + target_module: ModuleId, + visibility: ItemVisibility, +) -> bool { + // Note that if the target module is in a different crate from the current module then we will either + // return true as the target module is public or return false as it is private without looking at the `CrateDefMap` in either case. + let same_crate = target_module.krate == importing_crate; + + match visibility { + ItemVisibility::Public => true, + ItemVisibility::PublicCrate => same_crate, + ItemVisibility::Private => { + let target_crate_def_map = &def_maps[&target_module.krate]; + same_crate + && (module_descendent_of_target( + target_crate_def_map, + target_module.local_id, + current_module, + ) || module_is_parent_of_struct_module( + target_crate_def_map, + current_module, + target_module.local_id, + )) + } + } +} + +// Returns true if `current` is a (potentially nested) child module of `target`. +// This is also true if `current == target`. +pub(crate) fn module_descendent_of_target( + def_map: &CrateDefMap, + target: LocalModuleId, + current: LocalModuleId, +) -> bool { + if current == target { + return true; + } + + def_map.modules[current.0] + .parent + .map_or(false, |parent| module_descendent_of_target(def_map, target, parent)) +} + +/// Returns true if `target` is a struct and its parent is `current`. +fn module_is_parent_of_struct_module( + def_map: &CrateDefMap, + current: LocalModuleId, + target: LocalModuleId, +) -> bool { + let module_data = &def_map.modules[target.0]; + module_data.is_struct && module_data.parent == Some(current) +} + +pub fn struct_field_is_visible( + struct_type: &StructType, + visibility: ItemVisibility, + current_module_id: ModuleId, + def_maps: &BTreeMap, +) -> bool { + match visibility { + ItemVisibility::Public => true, + ItemVisibility::PublicCrate => { + struct_type.id.parent_module_id(def_maps).krate == current_module_id.krate + } + ItemVisibility::Private => { + let struct_parent_module_id = struct_type.id.parent_module_id(def_maps); + if struct_parent_module_id.krate != current_module_id.krate { + return false; + } + + if struct_parent_module_id.local_id == current_module_id.local_id { + return true; + } + + let def_map = &def_maps[¤t_module_id.krate]; + module_descendent_of_target( + def_map, + struct_parent_module_id.local_id, + current_module_id.local_id, + ) + } + } +} diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index 910204dd93d..6390f8dcc65 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -8,7 +8,7 @@ use std::{ use acvm::{AcirField, FieldElement}; use crate::{ - ast::IntegerBitSize, + ast::{IntegerBitSize, ItemVisibility}, hir::type_check::{generics::TraitGenerics, TypeCheckError}, node_interner::{ExprId, NodeInterner, TraitId, TypeAliasId}, }; @@ -305,7 +305,6 @@ pub type TypeBindings = HashMap; /// Represents a struct type in the type system. Each instance of this /// rust struct will be shared across all Type::Struct variants that represent /// the same struct type. -#[derive(Eq)] pub struct StructType { /// A unique id representing this struct type. Used to check if two /// struct types are equal. @@ -316,12 +315,18 @@ pub struct StructType { /// Fields are ordered and private, they should only /// be accessed through get_field(), get_fields(), or instantiate() /// since these will handle applying generic arguments to fields as well. - fields: Vec<(Ident, Type)>, + fields: Vec, pub generics: Generics, pub location: Location, } +pub struct StructField { + pub visibility: ItemVisibility, + pub name: Ident, + pub typ: Type, +} + /// Corresponds to generic lists such as `` in the source program. /// Used mainly for resolved types which no longer need information such /// as names or kinds @@ -365,6 +370,8 @@ impl std::hash::Hash for StructType { } } +impl Eq for StructType {} + impl PartialEq for StructType { fn eq(&self, other: &Self) -> bool { self.id == other.id @@ -389,7 +396,7 @@ impl StructType { name: Ident, location: Location, - fields: Vec<(Ident, Type)>, + fields: Vec, generics: Generics, ) -> StructType { StructType { id, fields, name, location, generics } @@ -399,7 +406,7 @@ impl StructType { /// fields are resolved strictly after the struct itself is initially /// created. Therefore, this method is used to set the fields once they /// become known. - pub fn set_fields(&mut self, fields: Vec<(Ident, Type)>) { + pub fn set_fields(&mut self, fields: Vec) { self.fields = fields; } @@ -407,12 +414,16 @@ impl StructType { self.fields.len() } - /// Returns the field matching the given field name, as well as its field index. - pub fn get_field(&self, field_name: &str, generic_args: &[Type]) -> Option<(Type, usize)> { + /// Returns the field matching the given field name, as well as its visibility and field index. + pub fn get_field( + &self, + field_name: &str, + generic_args: &[Type], + ) -> Option<(Type, ItemVisibility, usize)> { assert_eq!(self.generics.len(), generic_args.len()); - self.fields.iter().enumerate().find(|(_, (name, _))| name.0.contents == field_name).map( - |(i, (_, typ))| { + self.fields.iter().enumerate().find(|(_, field)| field.name.0.contents == field_name).map( + |(i, field)| { let substitutions = self .generics .iter() @@ -425,28 +436,46 @@ impl StructType { }) .collect(); - (typ.substitute(&substitutions), i) + (field.typ.substitute(&substitutions), field.visibility, i) }, ) } /// Returns all the fields of this type, after being applied to the given generic arguments. + pub fn get_fields_with_visibility( + &self, + generic_args: &[Type], + ) -> Vec<(String, ItemVisibility, Type)> { + let substitutions = self.get_fields_substitutions(generic_args); + + vecmap(&self.fields, |field| { + let name = field.name.0.contents.clone(); + (name, field.visibility, field.typ.substitute(&substitutions)) + }) + } + pub fn get_fields(&self, generic_args: &[Type]) -> Vec<(String, Type)> { + let substitutions = self.get_fields_substitutions(generic_args); + + vecmap(&self.fields, |field| { + let name = field.name.0.contents.clone(); + (name, field.typ.substitute(&substitutions)) + }) + } + + fn get_fields_substitutions( + &self, + generic_args: &[Type], + ) -> HashMap { assert_eq!(self.generics.len(), generic_args.len()); - let substitutions = self - .generics + self.generics .iter() .zip(generic_args) .map(|(old, new)| { (old.type_var.id(), (old.type_var.clone(), old.type_var.kind(), new.clone())) }) - .collect(); - - vecmap(&self.fields, |(name, typ)| { - let name = name.0.contents.clone(); - (name, typ.substitute(&substitutions)) - }) + .collect() } /// Returns the name and raw types of each field of this type. @@ -455,23 +484,27 @@ impl StructType { /// /// This method is almost never what is wanted for type checking or monomorphization, /// prefer to use `get_fields` whenever possible. - pub fn get_fields_as_written(&self) -> Vec<(String, Type)> { - vecmap(&self.fields, |(name, typ)| (name.0.contents.clone(), typ.clone())) + pub fn get_fields_as_written(&self) -> Vec { + vecmap(&self.fields, |field| StructField { + visibility: field.visibility, + name: field.name.clone(), + typ: field.typ.clone(), + }) } /// Returns the field at the given index. Panics if no field exists at the given index. - pub fn field_at(&self, index: usize) -> &(Ident, Type) { + pub fn field_at(&self, index: usize) -> &StructField { &self.fields[index] } pub fn field_names(&self) -> BTreeSet { - self.fields.iter().map(|(name, _)| name.clone()).collect() + self.fields.iter().map(|field| field.name.clone()).collect() } /// Search the fields of a struct for any types with a `TypeKind::Numeric` pub fn find_numeric_generics_in_fields(&self, found_names: &mut Vec) { - for (_, field) in self.fields.iter() { - field.find_numeric_type_vars(found_names); + for field in self.fields.iter() { + field.typ.find_numeric_type_vars(found_names); } } @@ -1903,8 +1936,8 @@ impl Type { // only to have to call .into_iter again afterward. Trying to elide // collecting to a Vec leads to us dropping the temporary Ref before // the iterator is returned - Type::Struct(def, args) => vecmap(&def.borrow().fields, |(name, _)| { - let name = &name.0.contents; + Type::Struct(def, args) => vecmap(&def.borrow().fields, |field| { + let name = &field.name.0.contents; let typ = def.borrow().get_field(name, args).unwrap().0; (name.clone(), typ) }), @@ -1919,14 +1952,20 @@ impl Type { /// Retrieves the type of the given field name /// Panics if the type is not a struct or tuple. - pub fn get_field_type(&self, field_name: &str) -> Option { + pub fn get_field_type_and_visibility( + &self, + field_name: &str, + ) -> Option<(Type, ItemVisibility)> { match self.follow_bindings() { - Type::Struct(def, args) => { - def.borrow().get_field(field_name, &args).map(|(typ, _)| typ) - } + Type::Struct(def, args) => def + .borrow() + .get_field(field_name, &args) + .map(|(typ, visibility, _)| (typ, visibility)), Type::Tuple(fields) => { let mut fields = fields.into_iter().enumerate(); - fields.find(|(i, _)| i.to_string() == *field_name).map(|(_, typ)| typ) + fields + .find(|(i, _)| i.to_string() == *field_name) + .map(|(_, typ)| (typ, ItemVisibility::Public)) } _ => None, } diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index c4c31a2dd8a..4037135a889 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -995,6 +995,10 @@ impl SecondaryAttribute { _ => false, } } + + pub(crate) fn is_abi(&self) -> bool { + matches!(self, SecondaryAttribute::Abi(_)) + } } impl fmt::Display for SecondaryAttribute { diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index f3439316538..48660142d0a 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -47,7 +47,10 @@ impl NodeInterner { ReferenceId::StructMember(id, field_index) => { let struct_type = self.get_struct(id); let struct_type = struct_type.borrow(); - Location::new(struct_type.field_at(field_index).0.span(), struct_type.location.file) + Location::new( + struct_type.field_at(field_index).name.span(), + struct_type.location.file, + ) } ReferenceId::Trait(id) => { let trait_type = self.get_trait(id); diff --git a/compiler/noirc_frontend/src/parser/parser/structs.rs b/compiler/noirc_frontend/src/parser/parser/structs.rs index 6775cf35a78..5514a33ef0d 100644 --- a/compiler/noirc_frontend/src/parser/parser/structs.rs +++ b/compiler/noirc_frontend/src/parser/parser/structs.rs @@ -61,17 +61,24 @@ impl<'a> Parser<'a> { fn parse_struct_field(&mut self) -> Option> { let mut doc_comments; let name; + let mut visibility; // Loop until we find an identifier, skipping anything that's not one loop { let doc_comments_start_span = self.current_token_span; doc_comments = self.parse_outer_doc_comments(); + visibility = self.parse_item_visibility(); + if let Some(ident) = self.eat_ident() { name = ident; break; } + if visibility != ItemVisibility::Private { + self.expected_identifier(); + } + if !doc_comments.is_empty() { self.push_error( ParserErrorReason::DocCommentDoesNotDocumentAnything, @@ -97,7 +104,7 @@ impl<'a> Parser<'a> { self.eat_or_error(Token::Colon); let typ = self.parse_type_or_error(); - Some(Documented::new(StructField { name, typ }, doc_comments)) + Some(Documented::new(StructField { visibility, name, typ }, doc_comments)) } fn empty_struct( diff --git a/compiler/noirc_frontend/src/tests/unused_items.rs b/compiler/noirc_frontend/src/tests/unused_items.rs index 80b6c7db09a..c89670a9043 100644 --- a/compiler/noirc_frontend/src/tests/unused_items.rs +++ b/compiler/noirc_frontend/src/tests/unused_items.rs @@ -231,3 +231,33 @@ fn no_warning_on_inner_struct_when_parent_is_used() { let errors = get_program_errors(src); assert_eq!(errors.len(), 0); } + +#[test] +fn no_warning_on_struct_if_it_has_an_abi_attribute() { + let src = r#" + #[abi(functions)] + struct Foo { + a: Field, + } + + fn main() {} + "#; + assert_no_errors(src); +} + +#[test] +fn no_warning_on_indirect_struct_if_it_has_an_abi_attribute() { + let src = r#" + struct Bar { + field: Field, + } + + #[abi(functions)] + struct Foo { + bar: Bar, + } + + fn main() {} + "#; + assert_no_errors(src); +} diff --git a/compiler/noirc_frontend/src/tests/visibility.rs b/compiler/noirc_frontend/src/tests/visibility.rs index 30a01818879..7ffa726d019 100644 --- a/compiler/noirc_frontend/src/tests/visibility.rs +++ b/compiler/noirc_frontend/src/tests/visibility.rs @@ -146,3 +146,146 @@ fn does_not_error_if_calling_private_struct_function_from_same_module() { "#; assert_no_errors(src); } + +#[test] +fn error_when_accessing_private_struct_field() { + let src = r#" + mod moo { + pub struct Foo { + x: Field + } + } + + fn foo(foo: moo::Foo) -> Field { + foo.x + } + + fn main() {} + "#; + + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + + let CompilationError::ResolverError(ResolverError::PathResolutionError( + PathResolutionError::Private(ident), + )) = &errors[0].0 + else { + panic!("Expected a private error"); + }; + + assert_eq!(ident.to_string(), "x"); +} + +#[test] +fn does_not_error_when_accessing_private_struct_field_from_nested_module() { + let src = r#" + struct Foo { + x: Field + } + + mod nested { + fn foo(foo: super::Foo) -> Field { + foo.x + } + } + + fn main() { + let _ = Foo { x: 1 }; + } + "#; + assert_no_errors(src); +} + +#[test] +fn does_not_error_when_accessing_pub_crate_struct_field_from_nested_module() { + let src = r#" + mod moo { + pub(crate) struct Foo { + pub(crate) x: Field + } + } + + fn foo(foo: moo::Foo) -> Field { + foo.x + } + + fn main() { + let _ = moo::Foo { x: 1 }; + } + "#; + assert_no_errors(src); +} + +#[test] +fn error_when_using_private_struct_field_in_constructor() { + let src = r#" + mod moo { + pub struct Foo { + x: Field + } + } + + fn main() { + let _ = moo::Foo { x: 1 }; + } + "#; + + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + + let CompilationError::ResolverError(ResolverError::PathResolutionError( + PathResolutionError::Private(ident), + )) = &errors[0].0 + else { + panic!("Expected a private error"); + }; + + assert_eq!(ident.to_string(), "x"); +} + +#[test] +fn error_when_using_private_struct_field_in_struct_pattern() { + let src = r#" + mod moo { + pub struct Foo { + x: Field + } + } + + fn foo(foo: moo::Foo) -> Field { + let moo::Foo { x } = foo; + x + } + + fn main() { + } + "#; + + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + + let CompilationError::ResolverError(ResolverError::PathResolutionError( + PathResolutionError::Private(ident), + )) = &errors[0].0 + else { + panic!("Expected a private error"); + }; + + assert_eq!(ident.to_string(), "x"); +} + +#[test] +fn does_not_error_if_referring_to_top_level_private_module_via_crate() { + let src = r#" + mod foo { + pub fn bar() {} + } + + use crate::foo::bar; + + fn main() { + bar() + } + "#; + assert_no_errors(src); +} diff --git a/docs/docs/noir/concepts/data_types/index.md b/docs/docs/noir/concepts/data_types/index.md index 11f51e2b65a..0f2db2b2d75 100644 --- a/docs/docs/noir/concepts/data_types/index.md +++ b/docs/docs/noir/concepts/data_types/index.md @@ -105,7 +105,7 @@ 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` +By default, like functions, type aliases are private to the module they exist in. You can use `pub` to make the type alias public or `pub(crate)` to make it public to just its crate: ```rust diff --git a/docs/docs/noir/concepts/data_types/structs.md b/docs/docs/noir/concepts/data_types/structs.md index e529347f27d..29951ae843a 100644 --- a/docs/docs/noir/concepts/data_types/structs.md +++ b/docs/docs/noir/concepts/data_types/structs.md @@ -69,7 +69,9 @@ fn get_octopus() -> Animal { The new variables can be bound with names different from the original struct field names, as showcased in the `legs --> feet` binding in the example above. -By default, like functions, structs are private to the module the exist in. You can use `pub` +### Visibility + +By default, like functions, structs are private to the module they exist in. You can use `pub` to make the struct public or `pub(crate)` to make it public to just its crate: ```rust @@ -79,4 +81,16 @@ pub struct Animal { legs: Field, eyes: u8, } +``` + +The same applies to struct fields: by default they are private to the module they exist in, +but they can be made `pub` or `pub(crate)`: + +```rust +// This struct is now public +pub struct Animal { + hands: Field, // private to its module + pub(crate) legs: Field, // accessible from the entire crate + pub eyes: u8, // accessible from anywhere +} ``` \ No newline at end of file diff --git a/docs/docs/noir/concepts/globals.md b/docs/docs/noir/concepts/globals.md index 1145c55dfc7..6b8314399a2 100644 --- a/docs/docs/noir/concepts/globals.md +++ b/docs/docs/noir/concepts/globals.md @@ -73,7 +73,7 @@ function performs side-effects like `println`, as these will still occur on each ### Visibility -By default, like functions, globals are private to the module the exist in. You can use `pub` +By default, like functions, globals are private to the module they exist in. You can use `pub` to make the global public or `pub(crate)` to make it public to just its crate: ```rust diff --git a/docs/docs/noir/concepts/traits.md b/docs/docs/noir/concepts/traits.md index 5d07e0c68f0..b3235a1a29b 100644 --- a/docs/docs/noir/concepts/traits.md +++ b/docs/docs/noir/concepts/traits.md @@ -466,7 +466,7 @@ unwrapping of values when converting to and from the `Wrapper` and `Foo` types. ### Visibility -By default, like functions, traits are private to the module the exist in. You can use `pub` +By default, like functions, traits are private to the module they exist in. You can use `pub` to make the trait public or `pub(crate)` to make it public to just its crate: ```rust diff --git a/docs/docs/noir/modules_packages_crates/modules.md b/docs/docs/noir/modules_packages_crates/modules.md index 05399c38b4c..14aa1f0579a 100644 --- a/docs/docs/noir/modules_packages_crates/modules.md +++ b/docs/docs/noir/modules_packages_crates/modules.md @@ -212,7 +212,7 @@ In this example, the module `some_module` re-exports two public names defined in ### Visibility -By default, like functions, modules are private to the module (or crate) the exist in. You can use `pub` +By default, like functions, modules are private to the module (or crate) they exist in. You can use `pub` to make the module public or `pub(crate)` to make it public to just its crate: ```rust diff --git a/noir_stdlib/src/collections/vec.nr b/noir_stdlib/src/collections/vec.nr index f24ed4ac783..1e641c384f0 100644 --- a/noir_stdlib/src/collections/vec.nr +++ b/noir_stdlib/src/collections/vec.nr @@ -1,5 +1,5 @@ pub struct Vec { - slice: [T] + pub(crate) slice: [T] } // A mutable vector type implemented as a wrapper around immutable slices. // A separate type is technically not needed but helps differentiate which operations are mutable. diff --git a/noir_stdlib/src/ec/consts/te.nr b/noir_stdlib/src/ec/consts/te.nr index 8c49226071f..f2425f6a786 100644 --- a/noir_stdlib/src/ec/consts/te.nr +++ b/noir_stdlib/src/ec/consts/te.nr @@ -2,9 +2,9 @@ use crate::ec::tecurve::affine::Point as TEPoint; use crate::ec::tecurve::affine::Curve as TECurve; pub struct BabyJubjub { - curve: TECurve, - base8: TEPoint, - suborder: Field, + pub curve: TECurve, + pub base8: TEPoint, + pub suborder: Field, } #[field(bn254)] diff --git a/noir_stdlib/src/ec/montcurve.nr b/noir_stdlib/src/ec/montcurve.nr index b8077b6b639..21d5a80320c 100644 --- a/noir_stdlib/src/ec/montcurve.nr +++ b/noir_stdlib/src/ec/montcurve.nr @@ -16,16 +16,16 @@ pub mod affine { // Curve specification pub struct Curve { // Montgomery Curve configuration (ky^2 = x^3 + j*x^2 + x) - j: Field, - k: Field, + pub j: Field, + pub k: Field, // Generator as point in Cartesian coordinates - gen: Point + pub gen: Point } // Point in Cartesian coordinates pub struct Point { - x: Field, - y: Field, - infty: bool // Indicator for point at infinity + pub x: Field, + pub y: Field, + pub infty: bool // Indicator for point at infinity } impl Point { @@ -223,16 +223,16 @@ pub mod curvegroup { use crate::cmp::Eq; pub struct Curve { // Montgomery Curve configuration (ky^2 z = x*(x^2 + j*x*z + z*z)) - j: Field, - k: Field, + pub j: Field, + pub k: Field, // Generator as point in projective coordinates - gen: Point + pub gen: Point } // Point in projective coordinates pub struct Point { - x: Field, - y: Field, - z: Field + pub x: Field, + pub y: Field, + pub z: Field } impl Point { diff --git a/noir_stdlib/src/ec/swcurve.nr b/noir_stdlib/src/ec/swcurve.nr index 9c40ddd1adc..0623c0a22dd 100644 --- a/noir_stdlib/src/ec/swcurve.nr +++ b/noir_stdlib/src/ec/swcurve.nr @@ -12,16 +12,16 @@ pub mod affine { // Curve specification pub struct Curve { // Short Weierstrass curve // Coefficients in defining equation y^2 = x^3 + ax + b - a: Field, - b: Field, + pub a: Field, + pub b: Field, // Generator as point in Cartesian coordinates - gen: Point + pub gen: Point } // Point in Cartesian coordinates pub struct Point { - x: Field, - y: Field, - infty: bool // Indicator for point at infinity + pub x: Field, + pub y: Field, + pub infty: bool // Indicator for point at infinity } impl Point { @@ -196,16 +196,16 @@ pub mod curvegroup { // Curve specification pub struct Curve { // Short Weierstrass curve // Coefficients in defining equation y^2 = x^3 + axz^4 + bz^6 - a: Field, - b: Field, + pub a: Field, + pub b: Field, // Generator as point in Cartesian coordinates - gen: Point + pub gen: Point } // Point in three-dimensional Jacobian coordinates pub struct Point { - x: Field, - y: Field, - z: Field // z = 0 corresponds to point at infinity. + pub x: Field, + pub y: Field, + pub z: Field // z = 0 corresponds to point at infinity. } impl Point { diff --git a/noir_stdlib/src/ec/tecurve.nr b/noir_stdlib/src/ec/tecurve.nr index c37b7c94a54..e52096e41e5 100644 --- a/noir_stdlib/src/ec/tecurve.nr +++ b/noir_stdlib/src/ec/tecurve.nr @@ -14,15 +14,15 @@ pub mod affine { // Curve specification pub struct Curve { // Twisted Edwards curve // Coefficients in defining equation ax^2 + y^2 = 1 + dx^2y^2 - a: Field, - d: Field, + pub a: Field, + pub d: Field, // Generator as point in Cartesian coordinates - gen: Point + pub gen: Point } // Point in Cartesian coordinates pub struct Point { - x: Field, - y: Field + pub x: Field, + pub y: Field } impl Point { @@ -207,17 +207,17 @@ pub mod curvegroup { // Curve specification pub struct Curve { // Twisted Edwards curve // Coefficients in defining equation a(x^2 + y^2)z^2 = z^4 + dx^2y^2 - a: Field, - d: Field, + pub a: Field, + pub d: Field, // Generator as point in projective coordinates - gen: Point + pub gen: Point } // Point in extended twisted Edwards coordinates pub struct Point { - x: Field, - y: Field, - t: Field, - z: Field + pub x: Field, + pub y: Field, + pub t: Field, + pub z: Field } impl Point { diff --git a/noir_stdlib/src/embedded_curve_ops.nr b/noir_stdlib/src/embedded_curve_ops.nr index f5e7c7e8528..ad7196b4494 100644 --- a/noir_stdlib/src/embedded_curve_ops.nr +++ b/noir_stdlib/src/embedded_curve_ops.nr @@ -5,9 +5,9 @@ use crate::cmp::Eq; /// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field. /// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false. pub struct EmbeddedCurvePoint { - x: Field, - y: Field, - is_infinite: bool + pub x: Field, + pub y: Field, + pub is_infinite: bool } impl EmbeddedCurvePoint { @@ -57,8 +57,8 @@ impl Eq for EmbeddedCurvePoint { /// By definition, the scalar field of the embedded curve is base field of the proving system curve. /// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs. pub struct EmbeddedCurveScalar { - lo: Field, - hi: Field, + pub lo: Field, + pub hi: Field, } impl EmbeddedCurveScalar { diff --git a/noir_stdlib/src/uint128.nr b/noir_stdlib/src/uint128.nr index 9cb94567d94..4a035ef91ef 100644 --- a/noir_stdlib/src/uint128.nr +++ b/noir_stdlib/src/uint128.nr @@ -4,8 +4,8 @@ use crate::cmp::{Eq, Ord, Ordering}; global pow64 : Field = 18446744073709551616; //2^64; global pow63 : Field = 9223372036854775808; // 2^63; pub struct U128 { - lo: Field, - hi: Field, + pub(crate) lo: Field, + pub(crate) hi: Field, } impl U128 { diff --git a/test_programs/compile_success_contract/abi_attribute/src/main.nr b/test_programs/compile_success_contract/abi_attribute/src/main.nr index 164512b03db..c4d4a24e3c2 100644 --- a/test_programs/compile_success_contract/abi_attribute/src/main.nr +++ b/test_programs/compile_success_contract/abi_attribute/src/main.nr @@ -1,9 +1,9 @@ contract Foo { #[abi(foo)] - global foo: Field = 42; + pub global foo: Field = 42; #[abi(bar)] - struct Bar { + pub struct Bar { inner: Field } } diff --git a/test_programs/compile_success_contract/contract_with_impl/src/main.nr b/test_programs/compile_success_contract/contract_with_impl/src/main.nr index 1c6b6c217c4..9d45b88fbc9 100644 --- a/test_programs/compile_success_contract/contract_with_impl/src/main.nr +++ b/test_programs/compile_success_contract/contract_with_impl/src/main.nr @@ -1,7 +1,9 @@ contract Foo { - struct T { x: [Field] } + pub struct T { x: [Field] } impl T { - fn t(self) {} + fn t(self) { + let _ = self; + } } } diff --git a/test_programs/compile_success_contract/non_entry_point_method/src/main.nr b/test_programs/compile_success_contract/non_entry_point_method/src/main.nr index b768653262a..f49c2f14f9d 100644 --- a/test_programs/compile_success_contract/non_entry_point_method/src/main.nr +++ b/test_programs/compile_success_contract/non_entry_point_method/src/main.nr @@ -1,6 +1,6 @@ contract Foo { - struct PlaceholderStruct{x : u32 } + pub struct PlaceholderStruct{x : u32 } #[contract_library_method] - fn has_mut(_context: &mut PlaceholderStruct) {} + pub fn has_mut(_context: &mut PlaceholderStruct) {} } diff --git a/test_programs/compile_success_contract/simple_contract/src/main.nr b/test_programs/compile_success_contract/simple_contract/src/main.nr index 7412e1386bf..7742ed6139b 100644 --- a/test_programs/compile_success_contract/simple_contract/src/main.nr +++ b/test_programs/compile_success_contract/simple_contract/src/main.nr @@ -10,7 +10,7 @@ contract Foo { } // Regression for issue #3344 #[contract_library_method] - fn foo(x: u8) -> u8 { + pub fn foo(x: u8) -> u8 { x } } diff --git a/test_programs/compile_success_empty/arithmetic_generics/src/main.nr b/test_programs/compile_success_empty/arithmetic_generics/src/main.nr index 0a7d319485c..9a002356144 100644 --- a/test_programs/compile_success_empty/arithmetic_generics/src/main.nr +++ b/test_programs/compile_success_empty/arithmetic_generics/src/main.nr @@ -97,7 +97,7 @@ fn mul_add() -> Equiv, (), W< } // (N + 1) * N == N * N + N -fn demo_proof() -> Equiv, (Equiv, (), W, ()>, Equiv, (Equiv, (), W, ()>, Equiv, (), W<(N * (N + 1))>, ()>), W, (Equiv, (), W<(N * (N + 1))>, ()>, Equiv, (), W, ()>)>), W, (Equiv, (Equiv, (), W, ()>, Equiv, (), W<(N * (N + 1))>, ()>), W, (Equiv, (), W<(N * (N + 1))>, ()>, Equiv, (), W, ()>)>, Equiv, (), W, ()>)> { +pub fn demo_proof() -> Equiv, (Equiv, (), W, ()>, Equiv, (Equiv, (), W, ()>, Equiv, (), W<(N * (N + 1))>, ()>), W, (Equiv, (), W<(N * (N + 1))>, ()>, Equiv, (), W, ()>)>), W, (Equiv, (Equiv, (), W, ()>, Equiv, (), W<(N * (N + 1))>, ()>), W, (Equiv, (), W<(N * (N + 1))>, ()>, Equiv, (), W, ()>)>, Equiv, (), W, ()>)> { let p1: Equiv, (), W, ()> = mul_comm(); let p2: Equiv, (), W, ()> = mul_add::(); let p3_sub: Equiv, (), W, ()> = mul_one_r(); diff --git a/test_programs/compile_success_empty/attribute_args/src/main.nr b/test_programs/compile_success_empty/attribute_args/src/main.nr index 6178df5e749..492afd9e2f1 100644 --- a/test_programs/compile_success_empty/attribute_args/src/main.nr +++ b/test_programs/compile_success_empty/attribute_args/src/main.nr @@ -1,7 +1,7 @@ #[attr_with_args(1, 2)] #[varargs(1, 2)] #[varargs(1, 2, 3, 4)] -struct Foo {} +pub struct Foo {} comptime fn attr_with_args(s: StructDefinition, a: Field, b: Field) { // Ensure all variables are in scope. diff --git a/test_programs/compile_success_empty/attributes_struct/src/main.nr b/test_programs/compile_success_empty/attributes_struct/src/main.nr index 5c82145b431..f02e7973878 100644 --- a/test_programs/compile_success_empty/attributes_struct/src/main.nr +++ b/test_programs/compile_success_empty/attributes_struct/src/main.nr @@ -1,6 +1,6 @@ #['some_attribute] #['another_attribute] -struct SomeStruct { +pub struct SomeStruct { a: Field, b: Field } @@ -11,7 +11,7 @@ fn main() {} #[abi(something)] #[add_attribute] -struct Foo { +pub struct Foo { } diff --git a/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr b/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr index a1a2c4b125a..86bde1c5eba 100644 --- a/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr +++ b/test_programs/compile_success_empty/comptime_global_using_trait/src/main.nr @@ -1,3 +1,3 @@ -comptime global FOO: i32 = Default::default(); +pub comptime global FOO: i32 = Default::default(); fn main() {} diff --git a/test_programs/compile_success_empty/comptime_struct_definition/src/main.nr b/test_programs/compile_success_empty/comptime_struct_definition/src/main.nr index da2871a253d..97d99d0de6b 100644 --- a/test_programs/compile_success_empty/comptime_struct_definition/src/main.nr +++ b/test_programs/compile_success_empty/comptime_struct_definition/src/main.nr @@ -1,11 +1,11 @@ #[my_comptime_fn] -struct MyType { +pub struct MyType { field1: [A; 10], field2: (B, C), } #[mutate_struct_fields] -struct I32AndField { +pub struct I32AndField { z: i8, } @@ -26,14 +26,14 @@ comptime fn mutate_struct_fields(s: StructDefinition) { mod foo { #[attr] - struct Foo {} + pub struct Foo {} comptime fn attr(s: StructDefinition) { assert_eq(s.module().name(), quote { foo }); } #[add_generic] - struct Bar {} + pub struct Bar {} // docs:start:add-generic-example comptime fn add_generic(s: StructDefinition) { diff --git a/test_programs/compile_success_empty/comptime_trait_constraint/src/main.nr b/test_programs/compile_success_empty/comptime_trait_constraint/src/main.nr index 448da96a460..43075058480 100644 --- a/test_programs/compile_success_empty/comptime_trait_constraint/src/main.nr +++ b/test_programs/compile_success_empty/comptime_trait_constraint/src/main.nr @@ -1,4 +1,4 @@ -use std::hash::{Hash, Hasher}; +use std::hash::Hasher; trait TraitWithGenerics { fn foo(self) -> (A, B); diff --git a/test_programs/compile_success_empty/comptime_trait_impl/src/main.nr b/test_programs/compile_success_empty/comptime_trait_impl/src/main.nr index 87b48e7a357..8498e75d7f4 100644 --- a/test_programs/compile_success_empty/comptime_trait_impl/src/main.nr +++ b/test_programs/compile_success_empty/comptime_trait_impl/src/main.nr @@ -1,9 +1,7 @@ -use std::meta::type_of; - trait SomeTrait { fn foo(); } -struct SomeStruct { +pub struct SomeStruct { } diff --git a/test_programs/compile_success_empty/comptime_traits/src/main.nr b/test_programs/compile_success_empty/comptime_traits/src/main.nr index 7d1e116dd0c..60fe264c57c 100644 --- a/test_programs/compile_success_empty/comptime_traits/src/main.nr +++ b/test_programs/compile_success_empty/comptime_traits/src/main.nr @@ -26,7 +26,7 @@ impl Neg for MyType { } } -fn neg_at_comptime() { +pub fn neg_at_comptime() { comptime { let value = MyType { value: 1 }; diff --git a/test_programs/compile_success_empty/comptime_type/src/main.nr b/test_programs/compile_success_empty/comptime_type/src/main.nr index 2b1bd215960..68c3477b027 100644 --- a/test_programs/compile_success_empty/comptime_type/src/main.nr +++ b/test_programs/compile_success_empty/comptime_type/src/main.nr @@ -7,13 +7,13 @@ struct Foo { trait SomeTrait { } -struct StructImplementsSomeTrait { +pub struct StructImplementsSomeTrait { } impl SomeTrait for StructImplementsSomeTrait {} -struct StructDoesNotImplementSomeTrait { +pub struct StructDoesNotImplementSomeTrait { } @@ -160,7 +160,7 @@ fn main() { } // docs:start:implements_example -fn function_with_where(_x: T) where T: SomeTrait { +pub fn function_with_where(_x: T) where T: SomeTrait { comptime { let t = quote { T }.as_type(); diff --git a/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr b/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr index 616ac7ef6ee..207869e5291 100644 --- a/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr +++ b/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr @@ -1,7 +1,6 @@ // Tests may be checked against https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/tree/main/poc use std::ec::tecurve::affine::Curve as AffineCurve; use std::ec::tecurve::affine::Point as Gaffine; -use std::ec::tecurve::curvegroup::Curve; use std::ec::tecurve::curvegroup::Point as G; use std::ec::swcurve::affine::Point as SWGaffine; diff --git a/test_programs/compile_success_empty/embedded_curve_add_simplification/src/main.nr b/test_programs/compile_success_empty/embedded_curve_add_simplification/src/main.nr index 39992a6454b..5a619906775 100644 --- a/test_programs/compile_success_empty/embedded_curve_add_simplification/src/main.nr +++ b/test_programs/compile_success_empty/embedded_curve_add_simplification/src/main.nr @@ -1,4 +1,4 @@ -use std::embedded_curve_ops::{EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul}; +use std::embedded_curve_ops::EmbeddedCurvePoint; fn main() { let zero = EmbeddedCurvePoint::point_at_infinity(); diff --git a/test_programs/compile_success_empty/function_attribute/src/main.nr b/test_programs/compile_success_empty/function_attribute/src/main.nr index ec22b730d3f..1bc524d4cb5 100644 --- a/test_programs/compile_success_empty/function_attribute/src/main.nr +++ b/test_programs/compile_success_empty/function_attribute/src/main.nr @@ -1,5 +1,5 @@ #[function_attr] -fn foo() {} +pub fn foo() {} struct Foo {} diff --git a/test_programs/compile_success_empty/method_call_regression/src/main.nr b/test_programs/compile_success_empty/method_call_regression/src/main.nr index de58271cae6..26493c4836b 100644 --- a/test_programs/compile_success_empty/method_call_regression/src/main.nr +++ b/test_programs/compile_success_empty/method_call_regression/src/main.nr @@ -9,7 +9,9 @@ struct Struct { a: A, b: B } // Before the fix, this candidate is searched first, binding ? to `u8` permanently. impl Struct { - fn foo(self) {} + fn foo(self) { + let _ = self; + } } // Then this candidate would be searched next but would not be a valid @@ -19,5 +21,7 @@ impl Struct { // method is actually selected. So this candidate is now valid since // `Struct` unifies with `Struct` with `? = u32`. impl Struct { - fn foo(self) {} + fn foo(self) { + let _ = self; + } } diff --git a/test_programs/compile_success_empty/mod_nr_entrypoint/src/foo/mod.nr b/test_programs/compile_success_empty/mod_nr_entrypoint/src/foo/mod.nr index 4eac6cb8514..216294fbf08 100644 --- a/test_programs/compile_success_empty/mod_nr_entrypoint/src/foo/mod.nr +++ b/test_programs/compile_success_empty/mod_nr_entrypoint/src/foo/mod.nr @@ -1,4 +1,4 @@ -mod bar; +pub mod bar; pub fn in_foo_mod() -> Field { 1 diff --git a/test_programs/compile_success_empty/no_duplicate_methods/src/main.nr b/test_programs/compile_success_empty/no_duplicate_methods/src/main.nr index 3ca9c841a8c..8b809715529 100644 --- a/test_programs/compile_success_empty/no_duplicate_methods/src/main.nr +++ b/test_programs/compile_success_empty/no_duplicate_methods/src/main.nr @@ -7,7 +7,7 @@ trait ToField2 { fn to_field(self) -> Field; } -struct Foo { x: Field } +pub struct Foo { x: Field } impl ToField for Foo { fn to_field(self) -> Field { diff --git a/test_programs/compile_success_empty/numeric_generics_explicit/src/main.nr b/test_programs/compile_success_empty/numeric_generics_explicit/src/main.nr index 5c618e9db36..c940e28dac2 100644 --- a/test_programs/compile_success_empty/numeric_generics_explicit/src/main.nr +++ b/test_programs/compile_success_empty/numeric_generics_explicit/src/main.nr @@ -85,7 +85,7 @@ trait Deserialize { fn deserialize(fields: [Field; N]) -> Self; } -struct PublicStorage {} +pub struct PublicStorage {} impl PublicStorage { fn read() -> T where T: Deserialize { @@ -102,10 +102,10 @@ impl PublicStorage { // Check that we can thread numeric generics into nested structs // and also that we can handle nested structs with numeric generics // which are declared after the parent struct -struct NestedNumeric { +pub struct NestedNumeric { a: Field, b: InnerNumeric } -struct InnerNumeric { +pub struct InnerNumeric { inner: [u32; N], } diff --git a/test_programs/compile_success_empty/regression_2099/src/main.nr b/test_programs/compile_success_empty/regression_2099/src/main.nr index 660f72f56e5..b390daec8c8 100644 --- a/test_programs/compile_success_empty/regression_2099/src/main.nr +++ b/test_programs/compile_success_empty/regression_2099/src/main.nr @@ -1,13 +1,5 @@ use std::ec::tecurve::affine::Curve as AffineCurve; use std::ec::tecurve::affine::Point as Gaffine; -use std::ec::tecurve::curvegroup::Curve; -use std::ec::tecurve::curvegroup::Point as G; - -use std::ec::swcurve::affine::Point as SWGaffine; -use std::ec::swcurve::curvegroup::Point as SWG; - -use std::ec::montcurve::affine::Point as MGaffine; -use std::ec::montcurve::curvegroup::Point as MG; fn main() { // Define Baby Jubjub (ERC-2494) parameters in affine representation diff --git a/test_programs/compile_success_empty/regression_4436/src/main.nr b/test_programs/compile_success_empty/regression_4436/src/main.nr index 336d0f1f4ed..30e4a942bdf 100644 --- a/test_programs/compile_success_empty/regression_4436/src/main.nr +++ b/test_programs/compile_success_empty/regression_4436/src/main.nr @@ -3,15 +3,15 @@ trait LibTrait { fn get_constant() -> Field; } -global STRUCT_A_LEN: u32 = 3; -global STRUCT_B_LEN: u32 = 5; +pub global STRUCT_A_LEN: u32 = 3; +pub global STRUCT_B_LEN: u32 = 5; -struct StructA; -struct StructB; +pub struct StructA; +pub struct StructB; impl LibTrait for StructA { fn broadcast() { - Self::get_constant(); + let _ = Self::get_constant(); } fn get_constant() -> Field { @@ -20,7 +20,7 @@ impl LibTrait for StructA { } impl LibTrait for StructB { fn broadcast() { - Self::get_constant(); + let _ = Self::get_constant(); } fn get_constant() -> Field { diff --git a/test_programs/compile_success_empty/schnorr_simplification/src/main.nr b/test_programs/compile_success_empty/schnorr_simplification/src/main.nr index e1095cd7fe2..1a9023e2d7a 100644 --- a/test_programs/compile_success_empty/schnorr_simplification/src/main.nr +++ b/test_programs/compile_success_empty/schnorr_simplification/src/main.nr @@ -1,5 +1,3 @@ -use std::embedded_curve_ops; - // Note: If main has any unsized types, then the verifier will never be able // to figure out the circuit instance fn main() { diff --git a/test_programs/compile_success_empty/slice_init_with_complex_type/src/main.nr b/test_programs/compile_success_empty/slice_init_with_complex_type/src/main.nr index 01ccf2fdeff..27339f812e7 100644 --- a/test_programs/compile_success_empty/slice_init_with_complex_type/src/main.nr +++ b/test_programs/compile_success_empty/slice_init_with_complex_type/src/main.nr @@ -4,14 +4,14 @@ struct strct1 { fn main() { let var1: [[i32; 1]] = [[0]]; - let var2: [[i32; 1]] = var1; + let _var2: [[i32; 1]] = var1; let var1: [(i32, u8)] = [(1, 2)]; - let var2: [(i32, u8)] = var1; + let _var2: [(i32, u8)] = var1; let var3: [strct1] = [strct1 { elem1: 1321351 }]; - let var4: [strct1] = var3; + let _var4: [strct1] = var3; let var1: [i32; 1] = [0]; - let var2: [[i32; 1]] = [var1]; + let _var2: [[i32; 1]] = [var1]; } diff --git a/test_programs/compile_success_empty/static_assert/src/main.nr b/test_programs/compile_success_empty/static_assert/src/main.nr index e61d9388ceb..11d30e4e069 100644 --- a/test_programs/compile_success_empty/static_assert/src/main.nr +++ b/test_programs/compile_success_empty/static_assert/src/main.nr @@ -9,7 +9,7 @@ global GLOBAL_THREE = GLOBAL_ONE + GLOBAL_TWO; global GLOBAL_ARRAY_PAIR = [GLOBAL_ONE, GLOBAL_TWO]; global GLOBAL_SLICE_PAIR = &[GLOBAL_ONE, GLOBAL_TWO]; -struct Foo { +pub struct Foo { field: Field, array: [Field; 3], slice: [Field], diff --git a/test_programs/compile_success_empty/struct_public_field/Nargo.toml b/test_programs/compile_success_empty/struct_public_field/Nargo.toml new file mode 100644 index 00000000000..37307b94af5 --- /dev/null +++ b/test_programs/compile_success_empty/struct_public_field/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "struct_public_field" +type = "bin" +authors = [""] + +[dependencies] +dependency = {path = "dependency"} \ No newline at end of file diff --git a/test_programs/compile_success_empty/struct_public_field/dependency/Nargo.toml b/test_programs/compile_success_empty/struct_public_field/dependency/Nargo.toml new file mode 100644 index 00000000000..2e471678a44 --- /dev/null +++ b/test_programs/compile_success_empty/struct_public_field/dependency/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "dependency" +type = "lib" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/test_programs/compile_success_empty/struct_public_field/dependency/src/lib.nr b/test_programs/compile_success_empty/struct_public_field/dependency/src/lib.nr new file mode 100644 index 00000000000..0e9bd4bd9f8 --- /dev/null +++ b/test_programs/compile_success_empty/struct_public_field/dependency/src/lib.nr @@ -0,0 +1,4 @@ +pub struct Point { + pub x: Field, + pub y: Field, +} diff --git a/test_programs/compile_success_empty/struct_public_field/src/main.nr b/test_programs/compile_success_empty/struct_public_field/src/main.nr new file mode 100644 index 00000000000..c269c474de7 --- /dev/null +++ b/test_programs/compile_success_empty/struct_public_field/src/main.nr @@ -0,0 +1,8 @@ +use dependency::Point; + +fn main() { + let point = Point { x: 1, y: 2 }; + let _ = point.x; + let Point { x, y } = point; + let _ = (x, y); +} diff --git a/test_programs/compile_success_empty/trait_allowed_item_name_matches/src/main.nr b/test_programs/compile_success_empty/trait_allowed_item_name_matches/src/main.nr index 44cad58c2a6..4104ca71037 100644 --- a/test_programs/compile_success_empty/trait_allowed_item_name_matches/src/main.nr +++ b/test_programs/compile_success_empty/trait_allowed_item_name_matches/src/main.nr @@ -1,22 +1,22 @@ -trait Trait1 { +pub trait Trait1 { // types and consts with the same name are allowed type Tralala; let Tralala: u32; } -trait Trait2 { +pub trait Trait2 { // consts and types with the same name are allowed let Tralala: u32; type Tralala; } -trait Trait3 { +pub trait Trait3 { // types and functions with the same name are allowed type Tralala; fn Tralala(); } -trait Trait4 { +pub trait Trait4 { // functions and types with the same name are allowed fn Tralala(); type Tralala; diff --git a/test_programs/compile_success_empty/trait_as_constraint/src/main.nr b/test_programs/compile_success_empty/trait_as_constraint/src/main.nr index 1911f045c27..b516376aae5 100644 --- a/test_programs/compile_success_empty/trait_as_constraint/src/main.nr +++ b/test_programs/compile_success_empty/trait_as_constraint/src/main.nr @@ -1,5 +1,5 @@ #[test_as_constraint] -trait Foo {} +pub trait Foo {} comptime fn test_as_constraint(t: TraitDefinition) { let constraint = t.as_trait_constraint(); diff --git a/test_programs/compile_success_empty/trait_associated_member_names_clashes/src/main.nr b/test_programs/compile_success_empty/trait_associated_member_names_clashes/src/main.nr index 412a75010f6..06bf311aa3c 100644 --- a/test_programs/compile_success_empty/trait_associated_member_names_clashes/src/main.nr +++ b/test_programs/compile_success_empty/trait_associated_member_names_clashes/src/main.nr @@ -6,7 +6,7 @@ trait Trait2 { fn tralala() -> Field; } -struct Struct1 { +pub struct Struct1 { } impl Struct1 { diff --git a/test_programs/compile_success_empty/trait_call_full_path/src/main.nr b/test_programs/compile_success_empty/trait_call_full_path/src/main.nr index 2d4b003f2ad..aea0f436dce 100644 --- a/test_programs/compile_success_empty/trait_call_full_path/src/main.nr +++ b/test_programs/compile_success_empty/trait_call_full_path/src/main.nr @@ -1,5 +1,5 @@ mod foo { - trait Trait { + pub trait Trait { fn me(self) -> Self; } diff --git a/test_programs/compile_success_empty/trait_function_calls/src/main.nr b/test_programs/compile_success_empty/trait_function_calls/src/main.nr index 62af0e756cd..352f18a74c0 100644 --- a/test_programs/compile_success_empty/trait_function_calls/src/main.nr +++ b/test_programs/compile_success_empty/trait_function_calls/src/main.nr @@ -26,6 +26,7 @@ trait Trait1a { self.trait_method2() * 7892 - self.vl } fn trait_method2(self) -> Field { + let _ = self; 43278 } } @@ -43,6 +44,7 @@ trait Trait1b { struct Struct1b { vl: Field } impl Trait1b for Struct1b { fn trait_method2(self) -> Field { + let _ = self; 2394 } } @@ -56,6 +58,7 @@ trait Trait1c { struct Struct1c { vl: Field } impl Trait1c for Struct1c { fn trait_method2(self) -> Field { + let _ = self; 5485 } } @@ -65,6 +68,7 @@ trait Trait1d { self.trait_method2() * 2825 - self.vl } fn trait_method2(self) -> Field { + let _ = self; 29341 } } @@ -89,6 +93,7 @@ impl Trait1e for Struct1e { self.trait_method2() * 47324 - self.vl } fn trait_method2(self) -> Field { + let _ = self; 58945 } } @@ -105,6 +110,7 @@ impl Trait1f for Struct1f { self.trait_method2() * 34875 - self.vl } fn trait_method2(self) -> Field { + let _ = self; 5748 } } @@ -112,6 +118,7 @@ impl Trait1f for Struct1f { trait Trait1g { fn trait_method1(self) -> Field; fn trait_method2(self) -> Field { + let _ = self; 37845 } } @@ -134,6 +141,7 @@ impl Trait1h for Struct1h { self.trait_method2() * 3482 - self.vl } fn trait_method2(self) -> Field { + let _ = self; 8542 } } @@ -148,6 +156,7 @@ impl Trait1i for Struct1i { self.trait_method2() * 23478 - self.vl } fn trait_method2(self) -> Field { + let _ = self; 98543 } } @@ -290,6 +299,7 @@ trait Trait3a { b.trait_method2() * 8344 - b.vl + a } fn trait_method2(self) -> Field { + let _ = self; 19212 } } @@ -307,6 +317,7 @@ trait Trait3b { struct Struct3b { vl: Field } impl Trait3b for Struct3b { fn trait_method2(self) -> Field { + let _ = self; 2392 } } @@ -320,6 +331,7 @@ trait Trait3c { struct Struct3c { vl: Field } impl Trait3c for Struct3c { fn trait_method2(self) -> Field { + let _ = self; 7743 } } @@ -329,6 +341,7 @@ trait Trait3d { b.trait_method2() * 291 - b.vl + a } fn trait_method2(self) -> Field { + let _ = self; 3328 } } @@ -353,6 +366,7 @@ impl Trait3e for Struct3e { b.trait_method2() * 81232 - b.vl + a } fn trait_method2(self) -> Field { + let _ = self; 80002 } } @@ -369,6 +383,7 @@ impl Trait3f for Struct3f { b.trait_method2() * 29223 - b.vl + a } fn trait_method2(self) -> Field { + let _ = self; 63532 } } @@ -376,6 +391,7 @@ impl Trait3f for Struct3f { trait Trait3g { fn trait_function1(a: Field, b: Self) -> Field; fn trait_method2(self) -> Field { + let _ = self; 8887 } } @@ -398,6 +414,7 @@ impl Trait3h for Struct3h { b.trait_method2() * 74747 - b.vl + a } fn trait_method2(self) -> Field { + let _ = self; 6283 } } @@ -412,6 +429,7 @@ impl Trait3i for Struct3i { b.trait_method2() * 1237 - b.vl + a } fn trait_method2(self) -> Field { + let _ = self; 84352 } } @@ -425,7 +443,7 @@ trait Trait4a { 2932 } } -struct Struct4a { vl: Field } +pub struct Struct4a { vl: Field } impl Trait4a for Struct4a {} // 4b) trait default function -> trait overriden function trait Trait4b { @@ -436,7 +454,7 @@ trait Trait4b { 2932 } } -struct Struct4b { vl: Field } +pub struct Struct4b { vl: Field } impl Trait4b for Struct4b { fn trait_function2() -> Field { 9353 @@ -449,7 +467,7 @@ trait Trait4c { } fn trait_function2() -> Field; } -struct Struct4c { vl: Field } +pub struct Struct4c { vl: Field } impl Trait4c for Struct4c { fn trait_function2() -> Field { 2928 @@ -464,7 +482,7 @@ trait Trait4d { 9332 } } -struct Struct4d { vl: Field } +pub struct Struct4d { vl: Field } impl Trait4d for Struct4d { fn trait_function1() -> Field { Self::trait_function2() * 8374 @@ -479,7 +497,7 @@ trait Trait4e { 28328 } } -struct Struct4e { vl: Field } +pub struct Struct4e { vl: Field } impl Trait4e for Struct4e { fn trait_function1() -> Field { Self::trait_function2() * 12323 @@ -495,7 +513,7 @@ trait Trait4f { } fn trait_function2() -> Field; } -struct Struct4f { vl: Field } +pub struct Struct4f { vl: Field } impl Trait4f for Struct4f { fn trait_function1() -> Field { Self::trait_function2() * 21392 @@ -511,7 +529,7 @@ trait Trait4g { 2932 } } -struct Struct4g { vl: Field } +pub struct Struct4g { vl: Field } impl Trait4g for Struct4g { fn trait_function1() -> Field { Self::trait_function2() * 3345 @@ -524,7 +542,7 @@ trait Trait4h { 5756 } } -struct Struct4h { vl: Field } +pub struct Struct4h { vl: Field } impl Trait4h for Struct4h { fn trait_function1() -> Field { Self::trait_function2() * 6478 @@ -538,7 +556,7 @@ trait Trait4i { fn trait_function1() -> Field; fn trait_function2() -> Field; } -struct Struct4i { vl: Field } +pub struct Struct4i { vl: Field } impl Trait4i for Struct4i { fn trait_function1() -> Field { Self::trait_function2() * 8239 diff --git a/test_programs/compile_success_empty/trait_multi_module_test/src/module1.nr b/test_programs/compile_success_empty/trait_multi_module_test/src/module1.nr index 4d41ff2909a..b5c05d69378 100644 --- a/test_programs/compile_success_empty/trait_multi_module_test/src/module1.nr +++ b/test_programs/compile_success_empty/trait_multi_module_test/src/module1.nr @@ -1,2 +1,2 @@ -trait MyTrait { +pub trait MyTrait { } diff --git a/test_programs/compile_success_empty/trait_multi_module_test/src/module2.nr b/test_programs/compile_success_empty/trait_multi_module_test/src/module2.nr index 3cadb6d78cb..c1335fe95e4 100644 --- a/test_programs/compile_success_empty/trait_multi_module_test/src/module2.nr +++ b/test_programs/compile_success_empty/trait_multi_module_test/src/module2.nr @@ -1,2 +1,2 @@ -struct MyStruct { +pub struct MyStruct { } diff --git a/test_programs/compile_success_empty/trait_multi_module_test/src/module4.nr b/test_programs/compile_success_empty/trait_multi_module_test/src/module4.nr index f9458e83c4a..f1e3c407531 100644 --- a/test_programs/compile_success_empty/trait_multi_module_test/src/module4.nr +++ b/test_programs/compile_success_empty/trait_multi_module_test/src/module4.nr @@ -1,2 +1,2 @@ -trait MyTrait4 { +pub trait MyTrait4 { } diff --git a/test_programs/compile_success_empty/trait_multi_module_test/src/module5.nr b/test_programs/compile_success_empty/trait_multi_module_test/src/module5.nr index cd9b7f0bf39..8c1c41ea25e 100644 --- a/test_programs/compile_success_empty/trait_multi_module_test/src/module5.nr +++ b/test_programs/compile_success_empty/trait_multi_module_test/src/module5.nr @@ -1,2 +1,2 @@ -struct MyStruct5 { +pub struct MyStruct5 { } diff --git a/test_programs/compile_success_empty/trait_where_clause/src/main.nr b/test_programs/compile_success_empty/trait_where_clause/src/main.nr index 655450d05ac..86e7f70a3a3 100644 --- a/test_programs/compile_success_empty/trait_where_clause/src/main.nr +++ b/test_programs/compile_success_empty/trait_where_clause/src/main.nr @@ -42,6 +42,7 @@ impl StaticTrait for Static100 { struct Static200 {} impl StaticTrait for Static200 { fn static_function(slf: Self) -> Field { + let _ = slf; 200 } } diff --git a/test_programs/compile_success_empty/trait_where_clause/src/the_trait.nr b/test_programs/compile_success_empty/trait_where_clause/src/the_trait.nr index c5cac4a1186..6390856731e 100644 --- a/test_programs/compile_success_empty/trait_where_clause/src/the_trait.nr +++ b/test_programs/compile_success_empty/trait_where_clause/src/the_trait.nr @@ -1,9 +1,10 @@ -trait Asd { +pub trait Asd { fn asd(self) -> Field; } -trait StaticTrait { +pub trait StaticTrait { fn static_function(slf: Self) -> Field { + let _ = slf; 100 } } diff --git a/test_programs/compile_success_empty/type_path/src/main.nr b/test_programs/compile_success_empty/type_path/src/main.nr index 96f3a29d96b..968812801c6 100644 --- a/test_programs/compile_success_empty/type_path/src/main.nr +++ b/test_programs/compile_success_empty/type_path/src/main.nr @@ -8,7 +8,7 @@ fn main() { } } -struct Foo {} +pub struct Foo {} impl Foo { fn static() {} diff --git a/test_programs/compile_success_empty/unary_operators/src/main.nr b/test_programs/compile_success_empty/unary_operators/src/main.nr index ef622fd3eb9..8793086c1c1 100644 --- a/test_programs/compile_success_empty/unary_operators/src/main.nr +++ b/test_programs/compile_success_empty/unary_operators/src/main.nr @@ -3,5 +3,5 @@ fn main() { assert(x == 1 - 2); let y: i32 = -1; - assert(x == 1 - 2); + assert(y == 1 - 2); } diff --git a/test_programs/compile_success_empty/unquote_function/src/main.nr b/test_programs/compile_success_empty/unquote_function/src/main.nr index 273a091b26d..7b6442abe8a 100644 --- a/test_programs/compile_success_empty/unquote_function/src/main.nr +++ b/test_programs/compile_success_empty/unquote_function/src/main.nr @@ -3,7 +3,7 @@ fn main() { } #[output_function] -fn foo() {} +pub fn foo() {} comptime fn output_function(_f: FunctionDefinition) -> Quoted { quote { diff --git a/test_programs/compile_success_empty/unquote_multiple_items_from_annotation/src/main.nr b/test_programs/compile_success_empty/unquote_multiple_items_from_annotation/src/main.nr index 04f07f038e5..11d50fc2ab5 100644 --- a/test_programs/compile_success_empty/unquote_multiple_items_from_annotation/src/main.nr +++ b/test_programs/compile_success_empty/unquote_multiple_items_from_annotation/src/main.nr @@ -1,5 +1,5 @@ #[foo] -struct Foo {} +pub struct Foo {} fn main() { assert_eq(ONE, 1); diff --git a/test_programs/compile_success_empty/unused_variables/src/main.nr b/test_programs/compile_success_empty/unused_variables/src/main.nr index f82cace0509..2fb57e3b275 100644 --- a/test_programs/compile_success_empty/unused_variables/src/main.nr +++ b/test_programs/compile_success_empty/unused_variables/src/main.nr @@ -1 +1,4 @@ -fn main(x: Field, y: pub Field) {} +fn main(x: Field, y: pub Field) { + let _ = x; + let _ = y; +} diff --git a/test_programs/compile_success_empty/use_callers_scope/src/main.nr b/test_programs/compile_success_empty/use_callers_scope/src/main.nr index b4e8a7f7c4d..30db6c48f7c 100644 --- a/test_programs/compile_success_empty/use_callers_scope/src/main.nr +++ b/test_programs/compile_success_empty/use_callers_scope/src/main.nr @@ -1,7 +1,7 @@ #[bar::struct_attr] -struct Foo {} +pub struct Foo {} -struct Bar {} +pub struct Bar {} #[bar::fn_attr] fn main() {} diff --git a/test_programs/compile_success_empty/workspace_reexport_bug/library/src/lib.nr b/test_programs/compile_success_empty/workspace_reexport_bug/library/src/lib.nr index e3a1539ea65..e56c127f562 100644 --- a/test_programs/compile_success_empty/workspace_reexport_bug/library/src/lib.nr +++ b/test_programs/compile_success_empty/workspace_reexport_bug/library/src/lib.nr @@ -1,2 +1,2 @@ // Re-export -use library2::ReExportMeFromAnotherLib; +pub use library2::ReExportMeFromAnotherLib; diff --git a/test_programs/compile_success_empty/workspace_reexport_bug/library2/src/lib.nr b/test_programs/compile_success_empty/workspace_reexport_bug/library2/src/lib.nr index 7e5a29a1424..c38c7bd1675 100644 --- a/test_programs/compile_success_empty/workspace_reexport_bug/library2/src/lib.nr +++ b/test_programs/compile_success_empty/workspace_reexport_bug/library2/src/lib.nr @@ -1,5 +1,5 @@ // When we re-export this type from another library and then use it in // main, we get a panic -struct ReExportMeFromAnotherLib { +pub struct ReExportMeFromAnotherLib { x : Field, } diff --git a/test_programs/test_libraries/exporting_lib/src/lib.nr b/test_programs/test_libraries/exporting_lib/src/lib.nr index fdd9f139d41..7da75ce5413 100644 --- a/test_programs/test_libraries/exporting_lib/src/lib.nr +++ b/test_programs/test_libraries/exporting_lib/src/lib.nr @@ -1,8 +1,8 @@ -struct MyStruct { - inner: Field +pub struct MyStruct { + pub inner: Field } -type FooStruct = MyStruct; +pub type FooStruct = MyStruct; pub fn is_struct_zero(val: MyStruct) -> bool { val.inner == 0 diff --git a/test_programs/test_libraries/reexporting_lib/src/lib.nr b/test_programs/test_libraries/reexporting_lib/src/lib.nr index 1bced548304..f106971028d 100644 --- a/test_programs/test_libraries/reexporting_lib/src/lib.nr +++ b/test_programs/test_libraries/reexporting_lib/src/lib.nr @@ -1,3 +1,3 @@ -use exporting_lib::{MyStruct, FooStruct}; +pub use exporting_lib::{MyStruct, FooStruct}; -use exporting_lib as lib; +pub use exporting_lib as lib; diff --git a/tooling/lsp/src/requests/code_action/fill_struct_fields.rs b/tooling/lsp/src/requests/code_action/fill_struct_fields.rs index be8602d99a9..739f0bf4a21 100644 --- a/tooling/lsp/src/requests/code_action/fill_struct_fields.rs +++ b/tooling/lsp/src/requests/code_action/fill_struct_fields.rs @@ -31,8 +31,8 @@ impl<'a> CodeActionFinder<'a> { let mut fields = struct_type.get_fields_as_written(); // Remove the ones that already exists in the constructor - for (field, _) in &constructor.fields { - fields.retain(|(name, _)| name != &field.0.contents); + for (constructor_field, _) in &constructor.fields { + fields.retain(|field| field.name.0.contents != constructor_field.0.contents); } if fields.is_empty() { @@ -93,7 +93,7 @@ impl<'a> CodeActionFinder<'a> { new_text.push(' '); } - for (index, (name, _)) in fields.iter().enumerate() { + for (index, field) in fields.iter().enumerate() { if index > 0 { new_text.push(','); if let Some(line_indent) = &line_indent { @@ -103,7 +103,7 @@ impl<'a> CodeActionFinder<'a> { new_text.push(' '); } } - new_text.push_str(name); + new_text.push_str(&field.name.0.contents); new_text.push_str(": ()"); } diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index 2882cb143bf..b1a207bc962 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -24,10 +24,12 @@ use noirc_frontend::{ UseTreeKind, Visitor, }, graph::{CrateId, Dependency}, - hir::def_map::{CrateDefMap, LocalModuleId, ModuleDefId, ModuleId}, + hir::{ + def_map::{CrateDefMap, LocalModuleId, ModuleDefId, ModuleId}, + resolution::visibility::struct_field_is_visible, + }, hir_def::traits::Trait, - node_interner::NodeInterner, - node_interner::ReferenceId, + node_interner::{NodeInterner, ReferenceId}, parser::{Item, ItemKind, ParsedSubModule}, token::{CustomAttribute, Token, Tokens}, Kind, ParsedModule, StructType, Type, TypeBinding, @@ -202,14 +204,14 @@ impl<'a> NodeFinder<'a> { // Remove the ones that already exists in the constructor for (used_name, _) in &constructor_expression.fields { - fields.retain(|(_, (name, _))| name != &used_name.0.contents); + fields.retain(|(_, field)| field.name.0.contents != used_name.0.contents); } let self_prefix = false; - for (field_index, (field, typ)) in &fields { + for (field_index, field) in &fields { self.completion_items.push(self.struct_field_completion_item( - field, - typ, + &field.name.0.contents, + &field.typ, struct_type.id, *field_index, self_prefix, @@ -691,16 +693,24 @@ impl<'a> NodeFinder<'a> { prefix: &str, self_prefix: bool, ) { - for (field_index, (name, typ)) in struct_type.get_fields(generics).iter().enumerate() { - if name_matches(name, prefix) { - self.completion_items.push(self.struct_field_completion_item( - name, - typ, - struct_type.id, - field_index, - self_prefix, - )); + for (field_index, (name, visibility, typ)) in + struct_type.get_fields_with_visibility(generics).iter().enumerate() + { + if !struct_field_is_visible(struct_type, *visibility, self.module_id, self.def_maps) { + continue; } + + if !name_matches(name, prefix) { + continue; + } + + self.completion_items.push(self.struct_field_completion_item( + name, + typ, + struct_type.id, + field_index, + self_prefix, + )); } } diff --git a/tooling/lsp/src/requests/completion/tests.rs b/tooling/lsp/src/requests/completion/tests.rs index bc8bb75e10c..e9ebc8f1f13 100644 --- a/tooling/lsp/src/requests/completion/tests.rs +++ b/tooling/lsp/src/requests/completion/tests.rs @@ -1071,6 +1071,22 @@ mod completion_tests { assert_completion(src, vec![field_completion_item("bar", "i32")]).await; } + #[test] + async fn test_does_not_suggest_private_struct_field() { + let src = r#" + mod moo { + pub struct Some { + property: i32, + } + } + + fn foo(s: moo::Some) { + s.>|< + } + "#; + assert_completion(src, vec![]).await; + } + #[test] async fn test_suggests_struct_impl_method() { let src = r#" diff --git a/tooling/lsp/src/requests/hover.rs b/tooling/lsp/src/requests/hover.rs index 7b1fa7352a6..5087955ea77 100644 --- a/tooling/lsp/src/requests/hover.rs +++ b/tooling/lsp/src/requests/hover.rs @@ -137,11 +137,11 @@ fn format_struct(id: StructId, args: &ProcessRequestCallbackArgs) -> String { string.push_str(&struct_type.name.0.contents); format_generics(&struct_type.generics, &mut string); string.push_str(" {\n"); - for (field_name, field_type) in struct_type.get_fields_as_written() { + for field in struct_type.get_fields_as_written() { string.push_str(" "); - string.push_str(&field_name); + string.push_str(&field.name.0.contents); string.push_str(": "); - string.push_str(&format!("{}", field_type)); + string.push_str(&format!("{}", field.typ)); string.push_str(",\n"); } string.push_str(" }"); @@ -158,7 +158,7 @@ fn format_struct_member( ) -> String { let struct_type = args.interner.get_struct(id); let struct_type = struct_type.borrow(); - let (field_name, field_type) = struct_type.field_at(field_index); + let field = struct_type.field_at(field_index); let mut string = String::new(); if format_parent_module(ReferenceId::Struct(id), args, &mut string) { @@ -167,10 +167,10 @@ fn format_struct_member( string.push_str(&struct_type.name.0.contents); string.push('\n'); string.push_str(" "); - string.push_str(&field_name.0.contents); + string.push_str(&field.name.0.contents); string.push_str(": "); - string.push_str(&format!("{}", field_type)); - string.push_str(&go_to_type_links(field_type, args.interner, args.files)); + string.push_str(&format!("{}", field.typ)); + string.push_str(&go_to_type_links(&field.typ, args.interner, args.files)); append_doc_comments(args.interner, ReferenceId::StructMember(id, field_index), &mut string); diff --git a/tooling/lsp/src/requests/inlay_hint.rs b/tooling/lsp/src/requests/inlay_hint.rs index e119ee0d5b6..f7b3e6a748d 100644 --- a/tooling/lsp/src/requests/inlay_hint.rs +++ b/tooling/lsp/src/requests/inlay_hint.rs @@ -97,8 +97,8 @@ impl<'a> InlayHintCollector<'a> { ReferenceId::StructMember(struct_id, field_index) => { let struct_type = self.interner.get_struct(struct_id); let struct_type = struct_type.borrow(); - let (_field_name, field_type) = struct_type.field_at(field_index); - self.push_type_hint(lsp_location, field_type, false); + let field = struct_type.field_at(field_index); + self.push_type_hint(lsp_location, &field.typ, false); } ReferenceId::Module(_) | ReferenceId::Struct(_) diff --git a/tooling/lsp/src/visibility.rs b/tooling/lsp/src/visibility.rs index d6e26f7bc48..207302f327e 100644 --- a/tooling/lsp/src/visibility.rs +++ b/tooling/lsp/src/visibility.rs @@ -5,7 +5,7 @@ use noirc_frontend::{ graph::CrateId, hir::{ def_map::{CrateDefMap, ModuleId}, - resolution::import::can_reference_module_id, + resolution::visibility::can_reference_module_id, }, }; diff --git a/tooling/nargo_cli/build.rs b/tooling/nargo_cli/build.rs index 9f694080cf5..50f022f64ed 100644 --- a/tooling/nargo_cli/build.rs +++ b/tooling/nargo_cli/build.rs @@ -240,6 +240,8 @@ fn generate_compile_success_empty_tests(test_file: &mut File, test_data_dir: &Pa if !output.status.success() {{ panic!("`nargo info` failed with: {}", String::from_utf8(output.stderr).unwrap_or_default()); }} + + nargo.assert().success().stderr(predicate::str::contains("warning:").not()); // `compile_success_empty` tests should be able to compile down to an empty circuit. let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap_or_else(|e| {{ @@ -284,7 +286,7 @@ fn generate_compile_success_contract_tests(test_file: &mut File, test_data_dir: &test_dir, r#" nargo.arg("compile").arg("--force"); - nargo.assert().success();"#, + nargo.assert().success().stderr(predicate::str::contains("warning:").not());"#, ); } writeln!(test_file, "}}").unwrap(); diff --git a/tooling/nargo_fmt/tests/expected/struct.nr b/tooling/nargo_fmt/tests/expected/struct.nr index 8fc642f7cd5..f3651de607d 100644 --- a/tooling/nargo_fmt/tests/expected/struct.nr +++ b/tooling/nargo_fmt/tests/expected/struct.nr @@ -5,7 +5,7 @@ struct Foo { struct Pair { first: Foo, - second: Field, + pub second: Field, } impl Foo { diff --git a/tooling/nargo_fmt/tests/input/struct.nr b/tooling/nargo_fmt/tests/input/struct.nr index 5e3530e8364..2e5fff47f9e 100644 --- a/tooling/nargo_fmt/tests/input/struct.nr +++ b/tooling/nargo_fmt/tests/input/struct.nr @@ -5,7 +5,7 @@ struct Foo { struct Pair { first: Foo, - second: Field, + pub second: Field, } impl Foo {