From 1d804b1f42fa4b43b0cbbdbb87d0ea61890d7514 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 11 Dec 2024 11:37:26 +0000 Subject: [PATCH 1/4] Rename `ItemConst.visibility` to `pub_token`. --- sway-ast/src/item/item_const.rs | 4 ++-- sway-lsp/src/traverse/lexed_tree.rs | 2 +- sway-parse/src/item/item_const.rs | 4 ++-- sway-parse/src/item/mod.rs | 2 +- swayfmt/src/items/item_const.rs | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sway-ast/src/item/item_const.rs b/sway-ast/src/item/item_const.rs index 542e8dd3faf..fb1b6c87438 100644 --- a/sway-ast/src/item/item_const.rs +++ b/sway-ast/src/item/item_const.rs @@ -2,7 +2,7 @@ use crate::priv_prelude::*; #[derive(Clone, Debug, Serialize)] pub struct ItemConst { - pub visibility: Option, + pub pub_token: Option, pub const_token: ConstToken, pub name: Ident, pub ty_opt: Option<(ColonToken, Ty)>, @@ -13,7 +13,7 @@ pub struct ItemConst { impl Spanned for ItemConst { fn span(&self) -> Span { - let start = match &self.visibility { + let start = match &self.pub_token { Some(pub_token) => pub_token.span(), None => self.const_token.span(), }; diff --git a/sway-lsp/src/traverse/lexed_tree.rs b/sway-lsp/src/traverse/lexed_tree.rs index fdce32d7e9a..458983ed789 100644 --- a/sway-lsp/src/traverse/lexed_tree.rs +++ b/sway-lsp/src/traverse/lexed_tree.rs @@ -383,7 +383,7 @@ impl Parse for ItemAbi { impl Parse for ItemConst { fn parse(&self, ctx: &ParseContext) { - if let Some(visibility) = &self.visibility { + if let Some(visibility) = &self.pub_token { insert_keyword(ctx, visibility.span()); } insert_keyword(ctx, self.const_token.span()); diff --git a/sway-parse/src/item/item_const.rs b/sway-parse/src/item/item_const.rs index 7efee705102..50e6bd504c0 100644 --- a/sway-parse/src/item/item_const.rs +++ b/sway-parse/src/item/item_const.rs @@ -4,7 +4,7 @@ use sway_ast::ItemConst; impl Parse for ItemConst { fn parse(parser: &mut Parser) -> ParseResult { - let visibility = parser.take(); + let pub_token = parser.take(); let const_token = parser.parse()?; let name = parser.parse()?; let ty_opt = match parser.take() { @@ -24,7 +24,7 @@ impl Parse for ItemConst { // between associated consts and module-level consts. let semicolon_token = parser.peek().unwrap_or_default(); Ok(ItemConst { - visibility, + pub_token, const_token, name, ty_opt, diff --git a/sway-parse/src/item/mod.rs b/sway-parse/src/item/mod.rs index 42d2a872d1c..9686128804d 100644 --- a/sway-parse/src/item/mod.rs +++ b/sway-parse/src/item/mod.rs @@ -57,7 +57,7 @@ impl Parse for ItemKind { } else if let Some(item) = parser.guarded_parse::()? { ItemKind::Abi(item) } else if let Some(mut item) = parser.guarded_parse::()? { - item.visibility = visibility.take(); + item.pub_token = visibility.take(); parser.take::().ok_or_else(|| { parser.emit_error(ParseErrorKind::ExpectedPunct { kinds: vec![sway_types::ast::PunctKind::Semicolon], diff --git a/swayfmt/src/items/item_const.rs b/swayfmt/src/items/item_const.rs index e853f2a97dc..693527434b7 100644 --- a/swayfmt/src/items/item_const.rs +++ b/swayfmt/src/items/item_const.rs @@ -17,7 +17,7 @@ impl Format for ItemConst { let start_len = formatted_code.len(); // Check if visibility token exists if so add it. - if let Some(visibility_token) = &self.visibility { + if let Some(visibility_token) = &self.pub_token { write!(formatted_code, "{} ", visibility_token.span().as_str())?; } @@ -60,7 +60,7 @@ impl Format for ItemConst { impl LeafSpans for ItemConst { fn leaf_spans(&self) -> Vec { let mut collected_spans = Vec::new(); - if let Some(visibility) = &self.visibility { + if let Some(visibility) = &self.pub_token { collected_spans.push(ByteSpan::from(visibility.span())); } collected_spans.push(ByteSpan::from(self.const_token.span())); From cde6126069689dae116e9b18d760fb7c329470db Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 11 Dec 2024 11:37:54 +0000 Subject: [PATCH 2/4] Fix parsing of `pub` visibility token for impl item consts. --- sway-parse/src/item/item_impl.rs | 8 ++++++-- sway-parse/src/parser.rs | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/sway-parse/src/item/item_impl.rs b/sway-parse/src/item/item_impl.rs index 7dc51e86fce..e48e319d925 100644 --- a/sway-parse/src/item/item_impl.rs +++ b/sway-parse/src/item/item_impl.rs @@ -9,10 +9,14 @@ use sway_error::parser_error::ParseErrorKind; impl Parse for ItemImplItem { fn parse(parser: &mut Parser) -> ParseResult { - if parser.peek::().is_some() || parser.peek::().is_some() { + if parser.peek::().is_some() + || (parser.peek::().is_some() && parser.peek_next::().is_some()) + { let fn_decl = parser.parse()?; Ok(ItemImplItem::Fn(fn_decl)) - } else if let Some(_const_keyword) = parser.peek::() { + } else if parser.peek::().is_some() + || (parser.peek::().is_some() && parser.peek_next::().is_some()) + { let const_decl = parser.parse()?; parser.parse::()?; Ok(ItemImplItem::Const(const_decl)) diff --git a/sway-parse/src/parser.rs b/sway-parse/src/parser.rs index 804ead365b3..fdba87cd5d7 100644 --- a/sway-parse/src/parser.rs +++ b/sway-parse/src/parser.rs @@ -78,6 +78,13 @@ impl<'a, 'e> Parser<'a, 'e> { Peeker::with(self.token_trees).map(|(v, _)| v) } + /// Tries to peek a `P` as the second token in its canonical way. + /// + /// Either way, on success or failure, the parser is not advanced. + pub fn peek_next(&self) -> Option

{ + Peeker::with(&self.token_trees[1..]).map(|(v, _)| v) + } + /// This function will fork the current parse, and call the parsing function. /// If it succeeds it will sync the original parser with the forked one; /// From 3fa112a3ae6b404d6c1877398537118d91d32195 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 11 Dec 2024 11:38:21 +0000 Subject: [PATCH 3/4] Fix default visibility for impl item consts. --- .../namespace/contract_helpers.rs | 1 + .../to_parsed_lang/convert_parse_tree.rs | 40 ++++++++++++++++--- .../src/main.sw | 5 +++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/sway-core/src/semantic_analysis/namespace/contract_helpers.rs b/sway-core/src/semantic_analysis/namespace/contract_helpers.rs index af8a84cbac6..665ac6c9ac4 100644 --- a/sway-core/src/semantic_analysis/namespace/contract_helpers.rs +++ b/sway-core/src/semantic_analysis/namespace/contract_helpers.rs @@ -81,6 +81,7 @@ fn default_with_contract_id_inner( handler, engines, const_item, + Visibility::Private, attributes, true, )?; diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index 9dc3792c07d..0e5fedd3f37 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -232,7 +232,13 @@ pub fn item_to_ast_nodes( } ItemKind::Const(item_const) => decl(Declaration::ConstantDeclaration({ item_const_to_constant_declaration( - context, handler, engines, item_const, attributes, true, + context, + handler, + engines, + item_const, + Visibility::Private, + attributes, + true, )? })), ItemKind::Storage(item_storage) => decl(Declaration::StorageDeclaration( @@ -681,7 +687,13 @@ fn item_trait_to_trait_declaration( .map(TraitItem::TraitFn) } ItemTraitItem::Const(const_decl, _) => item_const_to_constant_declaration( - context, handler, engines, const_decl, attributes, false, + context, + handler, + engines, + const_decl, + Visibility::Public, + attributes, + false, ) .map(TraitItem::Constant), ItemTraitItem::Type(trait_type, _) => trait_type_to_trait_type_declaration( @@ -765,7 +777,13 @@ pub fn item_impl_to_declaration( ) .map(ImplItem::Fn), sway_ast::ItemImplItem::Const(const_item) => item_const_to_constant_declaration( - context, handler, engines, const_item, attributes, false, + context, + handler, + engines, + const_item, + Visibility::Private, + attributes, + false, ) .map(ImplItem::Constant), sway_ast::ItemImplItem::Type(type_item) => trait_type_to_trait_type_declaration( @@ -898,7 +916,13 @@ fn item_abi_to_abi_declaration( Ok(TraitItem::TraitFn(trait_fn)) } ItemTraitItem::Const(const_decl, _) => item_const_to_constant_declaration( - context, handler, engines, const_decl, attributes, false, + context, + handler, + engines, + const_decl, + Visibility::Public, + attributes, + false, ) .map(TraitItem::Constant), ItemTraitItem::Type(type_decl, _) => trait_type_to_trait_type_declaration( @@ -960,6 +984,7 @@ pub(crate) fn item_const_to_constant_declaration( handler: &Handler, engines: &Engines, item_const: ItemConst, + default_visibility: Visibility, attributes: AttributesMap, require_expression: bool, ) -> Result, ErrorEmitted> { @@ -992,11 +1017,16 @@ pub(crate) fn item_const_to_constant_declaration( } }; + let visibility = match item_const.pub_token { + Some(pub_token) => pub_token_opt_to_visibility(Some(pub_token)), + None => default_visibility, + }; + let const_decl = ConstantDeclaration { name: item_const.name, type_ascription, value: expr, - visibility: pub_token_opt_to_visibility(item_const.visibility), + visibility, attributes, span, }; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_trait_default/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_trait_default/src/main.sw index b61e6f93404..3ee5c86d660 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_trait_default/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_trait_default/src/main.sw @@ -10,10 +10,15 @@ impl ConstantId for Struct { const ID: u32 = 5; } +impl Struct { + pub const PUB_ID: u32 = 6; +} + fn main() { } #[test] fn test() { assert_eq(5, Struct::ID); assert_eq(5, ::ID); + assert_eq(6, Struct::PUB_ID); } From c5036b0fda5300dbfcdff7102dabb8279b4b9d33 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 16 Dec 2024 12:51:30 +0000 Subject: [PATCH 4/4] Rework visibility level while doing visibility checking. --- .../ast_node/expression/typed_expression.rs | 1 + .../symbol_resolve_context.rs | 18 ++++ .../semantic_analysis/type_check_context.rs | 20 ++++ .../src/semantic_analysis/type_resolve.rs | 95 ++++++++++++++----- sway-core/src/type_system/monomorphization.rs | 3 +- .../associated_const_visibility/Forc.lock | 3 + .../associated_const_visibility/Forc.toml | 6 ++ .../associated_const_visibility/src/lib.sw | 12 +++ .../associated_const_visibility/src/main.sw | 3 + .../associated_const_visibility/test.toml | 1 + 10 files changed, 138 insertions(+), 24 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/src/lib.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/test.toml diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 06220dcac74..338bd211471 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -1259,6 +1259,7 @@ impl ty::TyExpression { &storage_key_ident.into(), None, VisibilityCheck::No, + Visibility::Public, )?; let storage_key_struct_decl_id = storage_key_decl diff --git a/sway-core/src/semantic_analysis/symbol_resolve_context.rs b/sway-core/src/semantic_analysis/symbol_resolve_context.rs index 7a9155a193a..69f1249496d 100644 --- a/sway-core/src/semantic_analysis/symbol_resolve_context.rs +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -43,6 +43,8 @@ pub struct SymbolResolveContext<'a> { /// /// This is `Disallow` everywhere except while checking type parameters bounds in struct instantiation. generic_shadowing_mode: GenericShadowingMode, + /// Visibility checking level for the current scope. + visibility_level: Visibility, } impl<'a> SymbolResolveContext<'a> { @@ -57,6 +59,7 @@ impl<'a> SymbolResolveContext<'a> { self_type: None, const_shadowing_mode: ConstShadowingMode::ItemStyle, generic_shadowing_mode: GenericShadowingMode::Disallow, + visibility_level: Visibility::Public, } } @@ -75,6 +78,7 @@ impl<'a> SymbolResolveContext<'a> { self_type: self.self_type, const_shadowing_mode: self.const_shadowing_mode, generic_shadowing_mode: self.generic_shadowing_mode, + visibility_level: Visibility::Public, } } @@ -156,6 +160,15 @@ impl<'a> SymbolResolveContext<'a> { } } + /// Map this `SymbolResolveContext` instance to a new one with the given visibility level. + #[allow(unused)] + pub(crate) fn with_visibility_level(self, visibility_level: Visibility) -> Self { + Self { + visibility_level, + ..self + } + } + // A set of accessor methods. We do this rather than making the fields `pub` in order to ensure // that these are only updated via the `with_*` methods that produce a new `SymbolResolveContext`. #[allow(unused)] @@ -173,6 +186,10 @@ impl<'a> SymbolResolveContext<'a> { self.generic_shadowing_mode } + pub(crate) fn visibility_level(&self) -> Visibility { + self.visibility_level + } + /// Get the engines needed for engine threading. pub(crate) fn engines(&self) -> &'a Engines { self.engines @@ -192,6 +209,7 @@ impl<'a> SymbolResolveContext<'a> { call_path, self.self_type(), VisibilityCheck::Yes, + self.visibility_level(), ) } } diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 9078be6ff4d..def1b24aa0c 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -110,6 +110,9 @@ pub struct TypeCheckContext<'a> { // In some nested places of the first pass we want to disable the first pass optimizations // To disable those optimizations we can set this to false. code_block_first_pass: bool, + + /// Visibility checking level for the current scope. + visibility_level: Visibility, } impl<'a> TypeCheckContext<'a> { @@ -139,6 +142,7 @@ impl<'a> TypeCheckContext<'a> { experimental, collecting_unifications: false, code_block_first_pass: false, + visibility_level: Visibility::Public, } } @@ -183,6 +187,7 @@ impl<'a> TypeCheckContext<'a> { experimental, collecting_unifications: false, code_block_first_pass: false, + visibility_level: Visibility::Public, } } @@ -214,6 +219,7 @@ impl<'a> TypeCheckContext<'a> { experimental: self.experimental, collecting_unifications: self.collecting_unifications, code_block_first_pass: self.code_block_first_pass, + visibility_level: self.visibility_level, } } @@ -251,6 +257,7 @@ impl<'a> TypeCheckContext<'a> { experimental: self.experimental, collecting_unifications: self.collecting_unifications, code_block_first_pass: self.code_block_first_pass, + visibility_level: self.visibility_level, }; with_scoped_ctx(ctx) }, @@ -275,6 +282,7 @@ impl<'a> TypeCheckContext<'a> { experimental: self.experimental, collecting_unifications: self.collecting_unifications, code_block_first_pass: self.code_block_first_pass, + visibility_level: self.visibility_level, }; with_scoped_ctx(ctx) } @@ -315,6 +323,7 @@ impl<'a> TypeCheckContext<'a> { experimental: self.experimental, collecting_unifications: self.collecting_unifications, code_block_first_pass: self.code_block_first_pass, + visibility_level: self.visibility_level, }; Ok((with_scoped_ctx(ctx)?, namespace)) }, @@ -339,6 +348,7 @@ impl<'a> TypeCheckContext<'a> { experimental: self.experimental, collecting_unifications: self.collecting_unifications, code_block_first_pass: self.code_block_first_pass, + visibility_level: self.visibility_level, }; Ok((with_scoped_ctx(ctx)?, namespace)) } @@ -565,6 +575,10 @@ impl<'a> TypeCheckContext<'a> { self.code_block_first_pass } + pub(crate) fn visibility_level(&self) -> Visibility { + self.visibility_level + } + /// Get the engines needed for engine threading. pub(crate) fn engines(&self) -> &'a Engines { self.engines @@ -672,6 +686,7 @@ impl<'a> TypeCheckContext<'a> { self.self_type(), &self.subst_ctx(), VisibilityCheck::Yes, + Visibility::Public, ) } @@ -689,6 +704,7 @@ impl<'a> TypeCheckContext<'a> { self.self_type(), &self.subst_ctx(), VisibilityCheck::Yes, + self.visibility_level(), ) .map(|d| d.expect_typed()) } @@ -707,6 +723,7 @@ impl<'a> TypeCheckContext<'a> { &symbol.clone().into(), self.self_type(), VisibilityCheck::No, + Visibility::Public, ) .map(|d| d.expect_typed()) } @@ -725,6 +742,7 @@ impl<'a> TypeCheckContext<'a> { call_path, self.self_type(), VisibilityCheck::Yes, + self.visibility_level(), ) .map(|d| d.expect_typed()) } @@ -743,6 +761,7 @@ impl<'a> TypeCheckContext<'a> { call_path, self.self_type(), VisibilityCheck::No, + self.visibility_level(), ) .map(|d| d.expect_typed()) } @@ -789,6 +808,7 @@ impl<'a> TypeCheckContext<'a> { self.self_type(), &self.subst_ctx(), VisibilityCheck::Yes, + Visibility::Public, ) .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); diff --git a/sway-core/src/semantic_analysis/type_resolve.rs b/sway-core/src/semantic_analysis/type_resolve.rs index 174817fdb5f..124660b5d3e 100644 --- a/sway-core/src/semantic_analysis/type_resolve.rs +++ b/sway-core/src/semantic_analysis/type_resolve.rs @@ -8,7 +8,7 @@ use sway_utils::iter_prefixes; use crate::{ language::{ ty::{self, TyTraitItem}, - CallPath, QualifiedCallPath, + CallPath, QualifiedCallPath, Visibility, }, monomorphization::type_decl_opt_to_type_id, namespace::{Module, ModulePath, ResolvedDeclaration, ResolvedTraitImplItem, Root}, @@ -39,6 +39,7 @@ pub fn resolve_type( self_type: Option, subst_ctx: &SubstTypesContext, check_visibility: VisibilityCheck, + visibility_level: Visibility, ) -> Result { let type_engine = engines.te(); let module_path = type_info_prefix.unwrap_or(mod_path); @@ -56,6 +57,7 @@ pub fn resolve_type( self_type, subst_ctx, check_visibility, + visibility_level, ) .ok(); type_decl_opt_to_type_id( @@ -85,6 +87,7 @@ pub fn resolve_type( self_type, subst_ctx, check_visibility, + Visibility::Public, ) .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); @@ -103,6 +106,7 @@ pub fn resolve_type( self_type, subst_ctx, check_visibility, + Visibility::Public, ) .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); @@ -122,6 +126,7 @@ pub fn resolve_type( self_type, subst_ctx, check_visibility, + Visibility::Public, ) .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); } @@ -169,6 +174,7 @@ pub fn resolve_type( self_type, subst_ctx, check_visibility, + Visibility::Public, ) .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); @@ -193,6 +199,7 @@ pub fn resolve_qualified_call_path( self_type: Option, subst_ctx: &SubstTypesContext, check_visibility: VisibilityCheck, + visibility_level: Visibility, ) -> Result { let type_engine = engines.te(); if let Some(qualified_path_root) = qualified_call_path.clone().qualified_path_root { @@ -210,6 +217,7 @@ pub fn resolve_qualified_call_path( &qualified_call_path.clone().to_call_path(handler)?, self_type, check_visibility, + visibility_level, )?; type_decl_opt_to_type_id( handler, @@ -250,6 +258,7 @@ pub fn resolve_qualified_call_path( &qualified_call_path.call_path, self_type, ) + .map(|(d, _)| d) } else { resolve_call_path( handler, @@ -259,6 +268,7 @@ pub fn resolve_qualified_call_path( &qualified_call_path.call_path, self_type, check_visibility, + visibility_level, ) } } @@ -271,6 +281,7 @@ pub fn resolve_qualified_call_path( /// The `mod_path` is significant here as we assume the resolution is done within the /// context of the module pointed to by `mod_path` and will only check the call path prefixes /// and the symbol's own visibility. +#[allow(clippy::too_many_arguments)] pub fn resolve_call_path( handler: &Handler, engines: &Engines, @@ -279,6 +290,7 @@ pub fn resolve_call_path( call_path: &CallPath, self_type: Option, check_visibility: VisibilityCheck, + mut visibility_level: Visibility, ) -> Result { let symbol_path: Vec<_> = mod_path .iter() @@ -286,7 +298,7 @@ pub fn resolve_call_path( .cloned() .collect(); - let (decl, mod_path) = resolve_symbol_and_mod_path( + let (decl, is_self_type, mod_path) = resolve_symbol_and_mod_path( handler, engines, &root.module, @@ -295,6 +307,10 @@ pub fn resolve_call_path( self_type, )?; + if is_self_type == IsSelfType::Yes { + visibility_level = Visibility::Private; + } + if check_visibility == VisibilityCheck::No { return Ok(decl); } @@ -323,7 +339,7 @@ pub fn resolve_call_path( } // check the visibility of the symbol itself - if !decl.visibility(engines).is_public() { + if !decl.visibility(engines).is_public() && visibility_level.is_public() { handler.emit_err(CompileError::ImportPrivateSymbol { name: call_path.suffix.clone(), span: call_path.suffix.span(), @@ -340,14 +356,15 @@ fn resolve_symbol_and_mod_path( mod_path: &ModulePath, symbol: &Ident, self_type: Option, -) -> Result<(ResolvedDeclaration, Vec), ErrorEmitted> { +) -> Result<(ResolvedDeclaration, IsSelfType, Vec), ErrorEmitted> { let mut current_module = module; // This block tries to resolve associated types let mut current_mod_path = vec![]; let mut decl_opt = None; + let mut is_self_type = IsSelfType::No; for ident in mod_path.iter() { if let Some(decl) = decl_opt { - decl_opt = Some(resolve_associated_type_or_item( + let (decl, ret_is_self_type) = resolve_associated_type_or_item( handler, engines, current_module, @@ -355,7 +372,11 @@ fn resolve_symbol_and_mod_path( decl, None, self_type, - )?); + )?; + decl_opt = Some(decl); + if ret_is_self_type == IsSelfType::Yes { + is_self_type = IsSelfType::Yes; + } } else { match current_module.submodules.get(ident.as_str()) { Some(ns) => { @@ -363,13 +384,16 @@ fn resolve_symbol_and_mod_path( current_mod_path.push(ident.clone()); } None => { + if ident.as_str() == "Self" { + is_self_type = IsSelfType::Yes; + } decl_opt = Some(current_module.resolve_symbol(handler, engines, ident)?); } } } } if let Some(decl) = decl_opt { - let decl = resolve_associated_type_or_item( + let (decl, ret_is_self_type) = resolve_associated_type_or_item( handler, engines, current_module, @@ -378,14 +402,17 @@ fn resolve_symbol_and_mod_path( None, self_type, )?; - return Ok((decl, current_mod_path)); + if ret_is_self_type == IsSelfType::Yes { + is_self_type = IsSelfType::Yes; + } + return Ok((decl, is_self_type, current_mod_path)); } module .lookup_submodule(handler, engines, mod_path) .and_then(|module| { let decl = module.resolve_symbol(handler, engines, symbol)?; - Ok((decl, mod_path.to_vec())) + Ok((decl, is_self_type, mod_path.to_vec())) }) } @@ -423,6 +450,12 @@ fn decl_to_type_info( } } +#[derive(Debug, PartialEq, Eq)] +pub(crate) enum IsSelfType { + Yes, + No, +} + #[allow(clippy::too_many_arguments)] fn resolve_associated_item_from_type_id( handler: &Handler, @@ -432,9 +465,11 @@ fn resolve_associated_item_from_type_id( type_id: TypeId, as_trait: Option, self_type: Option, -) -> Result { +) -> Result<(ResolvedDeclaration, IsSelfType), ErrorEmitted> { + let mut is_self_type = IsSelfType::No; let type_id = if engines.te().get(type_id).is_self_type() { if let Some(self_type) = self_type { + is_self_type = IsSelfType::Yes; self_type } else { return Err(handler.emit_err(CompileError::Internal( @@ -449,14 +484,15 @@ fn resolve_associated_item_from_type_id( .current_items() .implemented_traits .get_trait_item_for_type(handler, engines, symbol, type_id, as_trait)?; - match item_ref { + let resolved = match item_ref { ResolvedTraitImplItem::Parsed(_item) => todo!(), ResolvedTraitImplItem::Typed(item) => match item { - TyTraitItem::Fn(fn_ref) => Ok(ResolvedDeclaration::Typed(fn_ref.into())), - TyTraitItem::Constant(const_ref) => Ok(ResolvedDeclaration::Typed(const_ref.into())), - TyTraitItem::Type(type_ref) => Ok(ResolvedDeclaration::Typed(type_ref.into())), + TyTraitItem::Fn(fn_ref) => ResolvedDeclaration::Typed(fn_ref.into()), + TyTraitItem::Constant(const_ref) => ResolvedDeclaration::Typed(const_ref.into()), + TyTraitItem::Type(type_ref) => ResolvedDeclaration::Typed(type_ref.into()), }, - } + }; + Ok((resolved, is_self_type)) } #[allow(clippy::too_many_arguments)] @@ -468,7 +504,7 @@ fn resolve_associated_type_or_item( decl: ResolvedDeclaration, as_trait: Option, self_type: Option, -) -> Result { +) -> Result<(ResolvedDeclaration, IsSelfType), ErrorEmitted> { let type_info = decl_to_type_info(handler, engines, symbol, decl)?; let type_id = engines .te() @@ -488,10 +524,11 @@ fn resolve_call_path_and_root_type_id( mut as_trait: Option, call_path: &CallPath, self_type: Option, -) -> Result { +) -> Result<(ResolvedDeclaration, IsSelfType), ErrorEmitted> { // This block tries to resolve associated types let mut decl_opt = None; let mut type_id_opt = Some(root_type_id); + let mut is_self_type = IsSelfType::No; for ident in call_path.prefixes.iter() { if let Some(type_id) = type_id_opt { type_id_opt = None; @@ -505,7 +542,10 @@ fn resolve_call_path_and_root_type_id( self_type, )?); as_trait = None; - } else if let Some(decl) = decl_opt { + } else if let Some((decl, ret_is_self_type)) = decl_opt { + if ret_is_self_type == IsSelfType::Yes { + is_self_type = IsSelfType::Yes; + } decl_opt = Some(resolve_associated_type_or_item( handler, engines, @@ -519,7 +559,7 @@ fn resolve_call_path_and_root_type_id( } } if let Some(type_id) = type_id_opt { - let decl = resolve_associated_item_from_type_id( + let (decl, ret_is_self_type) = resolve_associated_item_from_type_id( handler, engines, module, @@ -528,10 +568,16 @@ fn resolve_call_path_and_root_type_id( as_trait, self_type, )?; - return Ok(decl); + if ret_is_self_type == IsSelfType::Yes { + is_self_type = IsSelfType::Yes; + } + return Ok((decl, is_self_type)); } - if let Some(decl) = decl_opt { - let decl = resolve_associated_type_or_item( + if let Some((decl, ret_is_self_type)) = decl_opt { + if ret_is_self_type == IsSelfType::Yes { + is_self_type = IsSelfType::Yes; + } + let (decl, ret_is_self_type) = resolve_associated_type_or_item( handler, engines, module, @@ -540,7 +586,10 @@ fn resolve_call_path_and_root_type_id( as_trait, self_type, )?; - Ok(decl) + if ret_is_self_type == IsSelfType::Yes { + is_self_type = IsSelfType::Yes; + } + Ok((decl, is_self_type)) } else { Err(handler.emit_err(CompileError::Internal("Unexpected error", call_path.span()))) } diff --git a/sway-core/src/type_system/monomorphization.rs b/sway-core/src/type_system/monomorphization.rs index 6eb6581e96a..51082b0f4ec 100644 --- a/sway-core/src/type_system/monomorphization.rs +++ b/sway-core/src/type_system/monomorphization.rs @@ -8,7 +8,7 @@ use crate::{ decl_engine::{engine::DeclEngineGetParsedDeclId, DeclEngineInsert}, language::{ ty::{self}, - CallPath, + CallPath, Visibility, }, namespace::{ModulePath, ResolvedDeclaration}, semantic_analysis::type_resolve::{resolve_type, VisibilityCheck}, @@ -130,6 +130,7 @@ where self_type, subst_ctx, VisibilityCheck::Yes, + Visibility::Public, ) .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/Forc.lock new file mode 100644 index 00000000000..8f8b79180f1 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/Forc.lock @@ -0,0 +1,3 @@ +[[package]] +name = "associated_const_visibility" +source = "member" diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/Forc.toml new file mode 100644 index 00000000000..4f3e0f29837 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/Forc.toml @@ -0,0 +1,6 @@ +[project] +name = "associated_const_visibility" +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +implicit-std = false diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/src/lib.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/src/lib.sw new file mode 100644 index 00000000000..9ab3947c403 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/src/lib.sw @@ -0,0 +1,12 @@ +library; + +pub struct Foo {} +impl Foo { + const MIN: Self = Self {}; +} + +impl Foo { + pub fn foo() { + let x = Self::MIN; + } +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/src/main.sw new file mode 100644 index 00000000000..07872e51408 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/src/main.sw @@ -0,0 +1,3 @@ +library; + +mod lib; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/test.toml new file mode 100644 index 00000000000..0f3f6d7e866 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_visibility/test.toml @@ -0,0 +1 @@ +category = "unit_tests_pass"