diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 32c05ad00f4..06bcafc55c9 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -13,7 +13,9 @@ use crate::{ }, hir::{ comptime::{self, InterpreterError}, - resolution::errors::ResolverError, + resolution::{ + errors::ResolverError, import::PathResolutionError, visibility::method_call_is_visible, + }, type_check::{generics::TraitGenerics, TypeCheckError}, }, hir_def::{ @@ -449,6 +451,8 @@ impl<'context> Elaborator<'context> { let method_call = HirMethodCallExpression { method, object, arguments, location, generics }; + self.check_method_call_visibility(func_id, &object_type, &method_call.method); + // Desugar the method call into a normal, resolved function call // so that the backend doesn't need to worry about methods // TODO: update object_type here? @@ -487,6 +491,20 @@ impl<'context> Elaborator<'context> { } } + fn check_method_call_visibility(&mut self, func_id: FuncId, object_type: &Type, name: &Ident) { + if !method_call_is_visible( + object_type, + func_id, + self.module_id(), + self.interner, + self.def_maps, + ) { + self.push_err(ResolverError::PathResolutionError(PathResolutionError::Private( + name.clone(), + ))); + } + } + fn elaborate_constructor( &mut self, constructor: ConstructorExpression, diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index 293b3c2bee1..0be71e39587 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -8,7 +8,8 @@ use crate::{ }, hir::{ resolution::{ - errors::ResolverError, import::PathResolutionError, visibility::struct_field_is_visible, + errors::ResolverError, import::PathResolutionError, + visibility::struct_member_is_visible, }, type_check::{Source, TypeCheckError}, }, @@ -508,7 +509,7 @@ impl<'context> Elaborator<'context> { visibility: ItemVisibility, span: Span, ) { - if !struct_field_is_visible(struct_type, visibility, self.module_id(), self.def_maps) { + if !struct_member_is_visible(struct_type.id, visibility, self.module_id(), self.def_maps) { self.push_err(ResolverError::PathResolutionError(PathResolutionError::Private( Ident::new(field_name.to_string(), span), ))); diff --git a/compiler/noirc_frontend/src/hir/resolution/visibility.rs b/compiler/noirc_frontend/src/hir/resolution/visibility.rs index c0c1429dbca..492f303d2c4 100644 --- a/compiler/noirc_frontend/src/hir/resolution/visibility.rs +++ b/compiler/noirc_frontend/src/hir/resolution/visibility.rs @@ -1,10 +1,11 @@ use crate::graph::CrateId; -use crate::StructType; +use crate::node_interner::{FuncId, NodeInterner, StructId}; +use crate::Type; use std::collections::BTreeMap; use crate::ast::ItemVisibility; -use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}; +use crate::hir::def_map::{CrateDefMap, DefMaps, 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. @@ -64,8 +65,8 @@ fn module_is_parent_of_struct_module( module_data.is_struct && module_data.parent == Some(current) } -pub fn struct_field_is_visible( - struct_type: &StructType, +pub fn struct_member_is_visible( + struct_id: StructId, visibility: ItemVisibility, current_module_id: ModuleId, def_maps: &BTreeMap, @@ -73,10 +74,10 @@ pub fn struct_field_is_visible( match visibility { ItemVisibility::Public => true, ItemVisibility::PublicCrate => { - struct_type.id.parent_module_id(def_maps).krate == current_module_id.krate + struct_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); + let struct_parent_module_id = struct_id.parent_module_id(def_maps); if struct_parent_module_id.krate != current_module_id.krate { return false; } @@ -94,3 +95,47 @@ pub fn struct_field_is_visible( } } } + +pub fn method_call_is_visible( + object_type: &Type, + func_id: FuncId, + current_module: ModuleId, + interner: &NodeInterner, + def_maps: &DefMaps, +) -> bool { + let modifiers = interner.function_modifiers(&func_id); + match modifiers.visibility { + ItemVisibility::Public => true, + ItemVisibility::PublicCrate => { + if object_type.is_primitive() { + current_module.krate.is_stdlib() + } else { + interner.function_module(func_id).krate == current_module.krate + } + } + ItemVisibility::Private => { + if object_type.is_primitive() { + let func_module = interner.function_module(func_id); + can_reference_module_id( + def_maps, + current_module.krate, + current_module.local_id, + func_module, + modifiers.visibility, + ) + } else { + let func_meta = interner.function_meta(&func_id); + if let Some(struct_id) = func_meta.struct_id { + struct_member_is_visible( + struct_id, + modifiers.visibility, + current_module, + def_maps, + ) + } else { + true + } + } + } + } +} diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index 538b5553afd..69e5066c596 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -1041,6 +1041,34 @@ impl Type { } } + pub fn is_primitive(&self) -> bool { + match self.follow_bindings() { + Type::FieldElement + | Type::Array(_, _) + | Type::Slice(_) + | Type::Integer(..) + | Type::Bool + | Type::String(_) + | Type::FmtString(_, _) + | Type::Unit + | Type::Function(..) + | Type::Tuple(..) => true, + Type::Alias(alias_type, generics) => { + alias_type.borrow().get_type(&generics).is_primitive() + } + Type::MutableReference(typ) => typ.is_primitive(), + Type::Struct(..) + | Type::TypeVariable(..) + | Type::TraitAsType(..) + | Type::NamedGeneric(..) + | Type::Forall(..) + | Type::Constant(..) + | Type::Quoted(..) + | Type::InfixExpr(..) + | Type::Error => false, + } + } + pub fn find_numeric_type_vars(&self, found_names: &mut Vec) { // Return whether the named generic has a Kind::Numeric and save its name let named_generic_is_numeric = |typ: &Type, found_names: &mut Vec| { diff --git a/compiler/noirc_frontend/src/tests/visibility.rs b/compiler/noirc_frontend/src/tests/visibility.rs index 7ffa726d019..f02771b3760 100644 --- a/compiler/noirc_frontend/src/tests/visibility.rs +++ b/compiler/noirc_frontend/src/tests/visibility.rs @@ -106,6 +106,61 @@ fn errors_if_trying_to_access_public_function_inside_private_module() { assert_eq!(ident.to_string(), "bar"); } +#[test] +fn warns_if_calling_private_struct_method() { + let src = r#" + mod moo { + pub struct Foo {} + + impl Foo { + fn bar(self) { + let _ = self; + } + } + } + + pub fn method(foo: moo::Foo) { + foo.bar() + } + + 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(), "bar"); +} + +#[test] +fn does_not_warn_if_calling_pub_crate_struct_method_from_same_crate() { + let src = r#" + mod moo { + pub struct Foo {} + + impl Foo { + pub(crate) fn bar(self) { + let _ = self; + } + } + } + + pub fn method(foo: moo::Foo) { + foo.bar() + } + + fn main() {} + "#; + assert_no_errors(src); +} + #[test] fn does_not_error_if_calling_private_struct_function_from_same_struct() { let src = r#" diff --git a/noir_stdlib/src/ec/montcurve.nr b/noir_stdlib/src/ec/montcurve.nr index 21d5a80320c..11b6a964c2d 100644 --- a/noir_stdlib/src/ec/montcurve.nr +++ b/noir_stdlib/src/ec/montcurve.nr @@ -40,7 +40,7 @@ pub mod affine { } // Conversion to CurveGroup coordinates - fn into_group(self) -> curvegroup::Point { + pub fn into_group(self) -> curvegroup::Point { if self.is_zero() { curvegroup::Point::zero() } else { @@ -55,14 +55,14 @@ pub mod affine { } // Negation - fn negate(self) -> Self { + pub fn negate(self) -> Self { let Self {x, y, infty} = self; Self { x, y: 0 - y, infty } } // Map into equivalent Twisted Edwards curve - fn into_tecurve(self) -> TEPoint { + pub fn into_tecurve(self) -> TEPoint { let Self {x, y, infty} = self; if infty | (y * (x + 1) == 0) { @@ -95,7 +95,7 @@ pub mod affine { } // Conversion to CurveGroup coordinates - fn into_group(self) -> curvegroup::Curve { + pub fn into_group(self) -> curvegroup::Curve { curvegroup::Curve::new(self.j, self.k, self.gen.into_group()) } @@ -114,17 +114,17 @@ pub mod affine { // Scalar multiplication with scalar represented by a bit array (little-endian convention). // If k is the natural number represented by `bits`, then this computes p + ... + p k times. - fn bit_mul(self, bits: [u1; N], p: Point) -> Point { + pub fn bit_mul(self, bits: [u1; N], p: Point) -> Point { self.into_tecurve().bit_mul(bits, p.into_tecurve()).into_montcurve() } // Scalar multiplication (p + ... + p n times) - fn mul(self, n: Field, p: Point) -> Point { + pub fn mul(self, n: Field, p: Point) -> Point { self.into_tecurve().mul(n, p.into_tecurve()).into_montcurve() } // Multi-scalar multiplication (n[0]*p[0] + ... + n[N]*p[N], where * denotes scalar multiplication) - fn msm(self, n: [Field; N], p: [Point; N]) -> Point { + pub fn msm(self, n: [Field; N], p: [Point; N]) -> Point { let mut out = Point::zero(); for i in 0..N { @@ -135,12 +135,12 @@ pub mod affine { } // Point subtraction - fn subtract(self, p1: Point, p2: Point) -> Point { + pub fn subtract(self, p1: Point, p2: Point) -> Point { self.add(p1, p2.negate()) } // Conversion to equivalent Twisted Edwards curve - fn into_tecurve(self) -> TECurve { + pub fn into_tecurve(self) -> TECurve { let Self {j, k, gen} = self; TECurve::new((j + 2) / k, (j - 2) / k, gen.into_tecurve()) } @@ -165,7 +165,7 @@ pub mod affine { } // Point mapping from equivalent Short Weierstrass curve - fn map_from_swcurve(self, p: SWPoint) -> Point { + pub fn map_from_swcurve(self, p: SWPoint) -> Point { let SWPoint {x, y, infty} = p; let j = self.j; let k = self.k; @@ -174,7 +174,7 @@ pub mod affine { } // Elligator 2 map-to-curve method; see . - fn elligator2_map(self, u: Field) -> Point { + pub fn elligator2_map(self, u: Field) -> Point { let j = self.j; let k = self.k; let z = ZETA; // Non-square Field element required for map @@ -205,7 +205,7 @@ pub mod affine { } // SWU map-to-curve method (via rational map) - fn swu_map(self, z: Field, u: Field) -> Point { + pub fn swu_map(self, z: Field, u: Field) -> Point { self.map_from_swcurve(self.into_swcurve().swu_map(z, u)) } } @@ -247,7 +247,7 @@ pub mod curvegroup { } // Conversion to affine coordinates - fn into_affine(self) -> affine::Point { + pub fn into_affine(self) -> affine::Point { if self.is_zero() { affine::Point::zero() } else { @@ -262,14 +262,14 @@ pub mod curvegroup { } // Negation - fn negate(self) -> Self { + pub fn negate(self) -> Self { let Self {x, y, z} = self; Point::new(x, 0 - y, z) } // Map into equivalent Twisted Edwards curve - fn into_tecurve(self) -> TEPoint { + pub fn into_tecurve(self) -> TEPoint { self.into_affine().into_tecurve().into_group() } } @@ -297,7 +297,7 @@ pub mod curvegroup { } // Conversion to affine coordinates - fn into_affine(self) -> affine::Curve { + pub fn into_affine(self) -> affine::Curve { affine::Curve::new(self.j, self.k, self.gen.into_affine()) } @@ -316,7 +316,7 @@ pub mod curvegroup { // Scalar multiplication with scalar represented by a bit array (little-endian convention). // If k is the natural number represented by `bits`, then this computes p + ... + p k times. - fn bit_mul(self, bits: [u1; N], p: Point) -> Point { + pub fn bit_mul(self, bits: [u1; N], p: Point) -> Point { self.into_tecurve().bit_mul(bits, p.into_tecurve()).into_montcurve() } @@ -326,7 +326,7 @@ pub mod curvegroup { } // Multi-scalar multiplication (n[0]*p[0] + ... + n[N]*p[N], where * denotes scalar multiplication) - fn msm(self, n: [Field; N], p: [Point; N]) -> Point { + pub fn msm(self, n: [Field; N], p: [Point; N]) -> Point { let mut out = Point::zero(); for i in 0..N { @@ -342,13 +342,13 @@ pub mod curvegroup { } // Conversion to equivalent Twisted Edwards curve - fn into_tecurve(self) -> TECurve { + pub fn into_tecurve(self) -> TECurve { let Self {j, k, gen} = self; TECurve::new((j + 2) / k, (j - 2) / k, gen.into_tecurve()) } // Conversion to equivalent Short Weierstrass curve - fn into_swcurve(self) -> SWCurve { + pub fn into_swcurve(self) -> SWCurve { let j = self.j; let k = self.k; let a0 = (3 - j * j) / (3 * k * k); @@ -363,17 +363,17 @@ pub mod curvegroup { } // Point mapping from equivalent Short Weierstrass curve - fn map_from_swcurve(self, p: SWPoint) -> Point { + pub fn map_from_swcurve(self, p: SWPoint) -> Point { self.into_affine().map_from_swcurve(p.into_affine()).into_group() } // Elligator 2 map-to-curve method - fn elligator2_map(self, u: Field) -> Point { + pub fn elligator2_map(self, u: Field) -> Point { self.into_affine().elligator2_map(u).into_group() } // SWU map-to-curve method (via rational map) - fn swu_map(self, z: Field, u: Field) -> Point { + pub fn swu_map(self, z: Field, u: Field) -> Point { self.into_affine().swu_map(z, u).into_group() } } diff --git a/noir_stdlib/src/ec/swcurve.nr b/noir_stdlib/src/ec/swcurve.nr index 0623c0a22dd..6e1054ad84e 100644 --- a/noir_stdlib/src/ec/swcurve.nr +++ b/noir_stdlib/src/ec/swcurve.nr @@ -36,7 +36,7 @@ pub mod affine { } // Conversion to CurveGroup coordinates - fn into_group(self) -> curvegroup::Point { + pub fn into_group(self) -> curvegroup::Point { let Self {x, y, infty} = self; if infty { @@ -52,7 +52,7 @@ pub mod affine { } // Negation - fn negate(self) -> Self { + pub fn negate(self) -> Self { let Self {x, y, infty} = self; Self { x, y: 0 - y, infty } } @@ -82,7 +82,7 @@ pub mod affine { } // Conversion to CurveGroup coordinates - fn into_group(self) -> curvegroup::Curve { + pub fn into_group(self) -> curvegroup::Curve { let Curve{a, b, gen} = self; curvegroup::Curve { a, b, gen: gen.into_group() } @@ -100,7 +100,7 @@ pub mod affine { } // Mixed point addition, i.e. first argument in affine, second in CurveGroup coordinates. - fn mixed_add(self, p1: Point, p2: curvegroup::Point) -> curvegroup::Point { + pub fn mixed_add(self, p1: Point, p2: curvegroup::Point) -> curvegroup::Point { if p1.is_zero() { p2 } else if p2.is_zero() { @@ -133,7 +133,7 @@ pub mod affine { // Scalar multiplication with scalar represented by a bit array (little-endian convention). // If k is the natural number represented by `bits`, then this computes p + ... + p k times. - fn bit_mul(self, bits: [u1; N], p: Point) -> Point { + pub fn bit_mul(self, bits: [u1; N], p: Point) -> Point { self.into_group().bit_mul(bits, p.into_group()).into_affine() } @@ -161,7 +161,7 @@ pub mod affine { // Simplified Shallue-van de Woestijne-Ulas map-to-curve method; see . // First determine non-square z != -1 in Field s.t. g(x) - z irreducible over Field and g(b/(z*a)) is square, // where g(x) = x^3 + a*x + b. swu_map(c,z,.) then maps a Field element to a point on curve c. - fn swu_map(self, z: Field, u: Field) -> Point { + pub fn swu_map(self, z: Field, u: Field) -> Point { // Check whether curve is admissible assert(self.a * self.b != 0); @@ -236,7 +236,7 @@ pub mod curvegroup { } // Negation - fn negate(self) -> Self { + pub fn negate(self) -> Self { let Self {x, y, z} = self; Self { x, y: 0 - y, z } } @@ -338,7 +338,7 @@ pub mod curvegroup { // Scalar multiplication with scalar represented by a bit array (little-endian convention). // If k is the natural number represented by `bits`, then this computes p + ... + p k times. - fn bit_mul(self, bits: [u1; N], p: Point) -> Point { + pub fn bit_mul(self, bits: [u1; N], p: Point) -> Point { let mut out = Point::zero(); for i in 0..N { @@ -363,7 +363,7 @@ pub mod curvegroup { } // Multi-scalar multiplication (n[0]*p[0] + ... + n[N]*p[N], where * denotes scalar multiplication) - fn msm(self, n: [Field; N], p: [Point; N]) -> Point { + pub fn msm(self, n: [Field; N], p: [Point; N]) -> Point { let mut out = Point::zero(); for i in 0..N { @@ -379,7 +379,7 @@ pub mod curvegroup { } // Simplified SWU map-to-curve method - fn swu_map(self, z: Field, u: Field) -> Point { + pub fn swu_map(self, z: Field, u: Field) -> Point { self.into_affine().swu_map(z, u).into_group() } } diff --git a/noir_stdlib/src/ec/tecurve.nr b/noir_stdlib/src/ec/tecurve.nr index e52096e41e5..0eb1521b19d 100644 --- a/noir_stdlib/src/ec/tecurve.nr +++ b/noir_stdlib/src/ec/tecurve.nr @@ -38,7 +38,7 @@ pub mod affine { } // Conversion to CurveGroup coordinates - fn into_group(self) -> curvegroup::Point { + pub fn into_group(self) -> curvegroup::Point { let Self {x, y} = self; curvegroup::Point::new(x, y, x * y, 1) @@ -50,13 +50,13 @@ pub mod affine { } // Negation - fn negate(self) -> Self { + pub fn negate(self) -> Self { let Self {x, y} = self; Point::new(0 - x, y) } // Map into prime-order subgroup of equivalent Montgomery curve - fn into_montcurve(self) -> MPoint { + pub fn into_montcurve(self) -> MPoint { if self.is_zero() { MPoint::zero() } else { @@ -93,7 +93,7 @@ pub mod affine { } // Conversion to CurveGroup coordinates - fn into_group(self) -> curvegroup::Curve { + pub fn into_group(self) -> curvegroup::Curve { let Curve{a, d, gen} = self; curvegroup::Curve { a, d, gen: gen.into_group() } @@ -111,7 +111,7 @@ pub mod affine { } // Mixed point addition, i.e. first argument in affine, second in CurveGroup coordinates. - fn mixed_add(self, p1: Point, p2: curvegroup::Point) -> curvegroup::Point { + pub fn mixed_add(self, p1: Point, p2: curvegroup::Point) -> curvegroup::Point { let Point{x: x1, y: y1} = p1; let curvegroup::Point{x: x2, y: y2, t: t2, z: z2} = p2; @@ -133,17 +133,17 @@ pub mod affine { // Scalar multiplication with scalar represented by a bit array (little-endian convention). // If k is the natural number represented by `bits`, then this computes p + ... + p k times. - fn bit_mul(self, bits: [u1; N], p: Point) -> Point { + pub fn bit_mul(self, bits: [u1; N], p: Point) -> Point { self.into_group().bit_mul(bits, p.into_group()).into_affine() } // Scalar multiplication (p + ... + p n times) - fn mul(self, n: Field, p: Point) -> Point { + pub fn mul(self, n: Field, p: Point) -> Point { self.into_group().mul(n, p.into_group()).into_affine() } // Multi-scalar multiplication (n[0]*p[0] + ... + n[N]*p[N], where * denotes scalar multiplication) - fn msm(self, n: [Field; N], p: [Point; N]) -> Point { + pub fn msm(self, n: [Field; N], p: [Point; N]) -> Point { let mut out = Point::zero(); for i in 0..N { @@ -154,7 +154,7 @@ pub mod affine { } // Point subtraction - fn subtract(self, p1: Point, p2: Point) -> Point { + pub fn subtract(self, p1: Point, p2: Point) -> Point { self.add(p1, p2.negate()) } @@ -178,17 +178,17 @@ pub mod affine { } // Point mapping from equivalent Short Weierstrass curve - fn map_from_swcurve(self, p: SWPoint) -> Point { + pub fn map_from_swcurve(self, p: SWPoint) -> Point { self.into_montcurve().map_from_swcurve(p).into_tecurve() } // Elligator 2 map-to-curve method (via rational map) - fn elligator2_map(self, u: Field) -> Point { + pub fn elligator2_map(self, u: Field) -> Point { self.into_montcurve().elligator2_map(u).into_tecurve() } // Simplified SWU map-to-curve method (via rational map) - fn swu_map(self, z: Field, u: Field) -> Point { + pub fn swu_map(self, z: Field, u: Field) -> Point { self.into_montcurve().swu_map(z, u).into_tecurve() } } @@ -245,14 +245,14 @@ pub mod curvegroup { } // Negation - fn negate(self) -> Self { + pub fn negate(self) -> Self { let Self {x, y, t, z} = self; Point::new(0 - x, y, 0 - t, z) } // Map into prime-order subgroup of equivalent Montgomery curve - fn into_montcurve(self) -> MPoint { + pub fn into_montcurve(self) -> MPoint { self.into_affine().into_montcurve().into_group() } } @@ -341,7 +341,7 @@ pub mod curvegroup { // Scalar multiplication with scalar represented by a bit array (little-endian convention). // If k is the natural number represented by `bits`, then this computes p + ... + p k times. - fn bit_mul(self, bits: [u1; N], p: Point) -> Point { + pub fn bit_mul(self, bits: [u1; N], p: Point) -> Point { let mut out = Point::zero(); for i in 0..N { @@ -366,7 +366,7 @@ pub mod curvegroup { } // Multi-scalar multiplication (n[0]*p[0] + ... + n[N]*p[N], where * denotes scalar multiplication) - fn msm(self, n: [Field; N], p: [Point; N]) -> Point { + pub fn msm(self, n: [Field; N], p: [Point; N]) -> Point { let mut out = Point::zero(); for i in 0..N { @@ -377,17 +377,17 @@ pub mod curvegroup { } // Point subtraction - fn subtract(self, p1: Point, p2: Point) -> Point { + pub fn subtract(self, p1: Point, p2: Point) -> Point { self.add(p1, p2.negate()) } // Conversion to equivalent Montgomery curve - fn into_montcurve(self) -> MCurve { + pub fn into_montcurve(self) -> MCurve { self.into_affine().into_montcurve().into_group() } // Conversion to equivalent Short Weierstrass curve - fn into_swcurve(self) -> SWCurve { + pub fn into_swcurve(self) -> SWCurve { self.into_montcurve().into_swcurve() } @@ -397,17 +397,17 @@ pub mod curvegroup { } // Point mapping from equivalent short Weierstrass curve - fn map_from_swcurve(self, p: SWPoint) -> Point { + pub fn map_from_swcurve(self, p: SWPoint) -> Point { self.into_montcurve().map_from_swcurve(p).into_tecurve() } // Elligator 2 map-to-curve method (via rational maps) - fn elligator2_map(self, u: Field) -> Point { + pub fn elligator2_map(self, u: Field) -> Point { self.into_montcurve().elligator2_map(u).into_tecurve() } // Simplified SWU map-to-curve method (via rational map) - fn swu_map(self, z: Field, u: Field) -> Point { + pub fn swu_map(self, z: Field, u: Field) -> Point { self.into_montcurve().swu_map(z, u).into_tecurve() } } diff --git a/noir_stdlib/src/hash/sha256.nr b/noir_stdlib/src/hash/sha256.nr index 081f7deb0fa..6c56a722fa7 100644 --- a/noir_stdlib/src/hash/sha256.nr +++ b/noir_stdlib/src/hash/sha256.nr @@ -79,7 +79,6 @@ fn verify_msg_block( } global BLOCK_SIZE = 64; -global ZERO = 0; // Variable size SHA-256 hash pub fn sha256_var(msg: [u8; N], message_size: u64) -> [u8; 32] { diff --git a/noir_stdlib/src/option.nr b/noir_stdlib/src/option.nr index 6b3a2bf2f3c..0c120a71568 100644 --- a/noir_stdlib/src/option.nr +++ b/noir_stdlib/src/option.nr @@ -57,7 +57,7 @@ impl Option { } /// Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value - fn expect(self, message: fmtstr) -> T { + pub fn expect(self, message: fmtstr) -> T { assert(self.is_some(), message); self._value } diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index b1a207bc962..658033fc526 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -26,10 +26,10 @@ use noirc_frontend::{ graph::{CrateId, Dependency}, hir::{ def_map::{CrateDefMap, LocalModuleId, ModuleDefId, ModuleId}, - resolution::visibility::struct_field_is_visible, + resolution::visibility::{method_call_is_visible, struct_member_is_visible}, }, hir_def::traits::Trait, - node_interner::{NodeInterner, ReferenceId}, + node_interner::{NodeInterner, ReferenceId, StructId}, parser::{Item, ItemKind, ParsedSubModule}, token::{CustomAttribute, Token, Tokens}, Kind, ParsedModule, StructType, Type, TypeBinding, @@ -631,6 +631,9 @@ impl<'a> NodeFinder<'a> { return; }; + let struct_id = get_type_struct_id(typ); + let is_primitive = typ.is_primitive(); + for (name, methods) in methods_by_name { for (func_id, method_type) in methods.iter() { if function_kind == FunctionKind::Any { @@ -641,6 +644,31 @@ impl<'a> NodeFinder<'a> { } } + if let Some(struct_id) = struct_id { + let modifiers = self.interner.function_modifiers(&func_id); + let visibility = modifiers.visibility; + if !struct_member_is_visible( + struct_id, + visibility, + self.module_id, + self.def_maps, + ) { + continue; + } + } + + if is_primitive + && !method_call_is_visible( + typ, + func_id, + self.module_id, + self.interner, + self.def_maps, + ) + { + continue; + } + if name_matches(name, prefix) { let completion_items = self.function_completion_items( name, @@ -696,7 +724,8 @@ impl<'a> NodeFinder<'a> { 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) { + if !struct_member_is_visible(struct_type.id, *visibility, self.module_id, self.def_maps) + { continue; } @@ -1701,6 +1730,18 @@ fn get_array_element_type(typ: Type) -> Option { } } +fn get_type_struct_id(typ: &Type) -> Option { + match typ { + Type::Struct(struct_type, _) => Some(struct_type.borrow().id), + Type::Alias(type_alias, generics) => { + let type_alias = type_alias.borrow(); + let typ = type_alias.get_type(generics); + get_type_struct_id(&typ) + } + _ => None, + } +} + /// Returns true if name matches a prefix written in code. /// `prefix` must already be in snake case. /// This method splits both name and prefix by underscore, diff --git a/tooling/lsp/src/requests/completion/tests.rs b/tooling/lsp/src/requests/completion/tests.rs index e9ebc8f1f13..668255eb34d 100644 --- a/tooling/lsp/src/requests/completion/tests.rs +++ b/tooling/lsp/src/requests/completion/tests.rs @@ -1821,6 +1821,37 @@ mod completion_tests { .await; } + #[test] + async fn test_does_not_suggest_private_struct_methods() { + let src = r#" + mod moo { + pub struct Foo {} + + impl Foo { + fn bar(self) {} + } + } + + fn x(f: moo::Foo) { + f.>|<() + } + "#; + assert_completion(src, vec![]).await; + } + + #[test] + async fn test_does_not_suggest_private_primitive_methods() { + let src = r#" + fn foo(x: Field) { + x.>|< + } + "#; + let items = get_completions(src).await; + if items.iter().any(|item| item.label == "__assert_max_bit_size") { + panic!("Private method __assert_max_bit_size was suggested"); + } + } + #[test] async fn test_suggests_pub_use() { let src = r#"