Skip to content

Rework and fix associated const visibility for impl items #6785

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions sway-ast/src/item/item_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::priv_prelude::*;

#[derive(Clone, Debug, Serialize)]
pub struct ItemConst {
pub visibility: Option<PubToken>,
pub pub_token: Option<PubToken>,
pub const_token: ConstToken,
pub name: Ident,
pub ty_opt: Option<(ColonToken, Ty)>,
Expand All @@ -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(),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
language::{
parsed::{AstNode, AstNodeContent, Declaration, ExpressionKind},
ty::{TyAstNode, TyAstNodeContent},
Visibility,
},
semantic_analysis::{
namespace::Package, symbol_collection_context::SymbolCollectionContext, TypeCheckContext,
Expand Down Expand Up @@ -75,6 +76,7 @@ fn bind_contract_id_in_root_module(
handler,
engines,
const_item,
Visibility::Private,
attributes,
true,
)?;
Expand Down
80 changes: 57 additions & 23 deletions sway-core/src/semantic_analysis/type_resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ pub fn resolve_qualified_call_path(
&qualified_call_path.call_path,
self_type,
)
.map(|(d, _)| d)
} else {
resolve_call_path(
handler,
Expand Down Expand Up @@ -285,7 +286,7 @@ pub fn resolve_call_path(
) -> Result<ResolvedDeclaration, ErrorEmitted> {
let full_path = call_path.to_fullpath_from_mod_path(engines, namespace, &mod_path.to_vec());

let (decl, decl_mod_path) = resolve_symbol_and_mod_path(
let (decl, is_self_type, decl_mod_path) = resolve_symbol_and_mod_path(
handler,
engines,
namespace,
Expand Down Expand Up @@ -313,7 +314,7 @@ pub fn resolve_call_path(
}

// Otherwise, check the visibility modifier
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you update this comment so that it explains what visibility_level means? I'm still confused about it.

Alternatively explain it when visibility_level is declared at the beginning of this function.

if !decl.visibility(engines).is_public() {
if !decl.visibility(engines).is_public() && is_self_type == IsSelfType::No {
handler.emit_err(CompileError::ImportPrivateSymbol {
name: call_path.suffix.clone(),
span: call_path.suffix.span(),
Expand All @@ -332,7 +333,7 @@ pub(super) fn resolve_symbol_and_mod_path(
mod_path: &ModulePath,
symbol: &Ident,
self_type: Option<TypeId>,
) -> Result<(ResolvedDeclaration, Vec<Ident>), ErrorEmitted> {
) -> Result<(ResolvedDeclaration, IsSelfType, Vec<Ident>), ErrorEmitted> {
assert!(!mod_path.is_empty());
if mod_path[0] == *namespace.current_package_name() {
resolve_symbol_and_mod_path_inner(
Expand Down Expand Up @@ -377,7 +378,7 @@ fn resolve_symbol_and_mod_path_inner(
mod_path: &ModulePath,
symbol: &Ident,
self_type: Option<TypeId>,
) -> Result<(ResolvedDeclaration, Vec<Ident>), ErrorEmitted> {
) -> Result<(ResolvedDeclaration, IsSelfType, Vec<Ident>), ErrorEmitted> {
assert!(!mod_path.is_empty());
assert!(root_module.mod_path().len() == 1);
assert!(mod_path[0] == root_module.mod_path()[0]);
Expand All @@ -386,32 +387,40 @@ fn resolve_symbol_and_mod_path_inner(
let mut current_module = root_module;
let mut current_mod_path = vec![mod_path[0].clone()];
let mut decl_opt = None;
let mut is_self_type = IsSelfType::No;
for ident in mod_path.iter().skip(1) {
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,
ident,
decl,
None,
self_type,
)?);
)?;
decl_opt = Some(decl);
if ret_is_self_type == IsSelfType::Yes {
is_self_type = IsSelfType::Yes;
}
} else {
match current_module.submodule(&[ident.clone()]) {
Some(ns) => {
current_module = ns;
current_mod_path.push(ident.clone());
}
None => {
if ident.as_str() == "Self" {
is_self_type = IsSelfType::Yes;
}
let (decl, _) = current_module.resolve_symbol(handler, engines, ident)?;
decl_opt = Some(decl);
}
}
}
}
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,
Expand All @@ -420,14 +429,17 @@ fn resolve_symbol_and_mod_path_inner(
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));
}

root_module
.lookup_submodule(handler, &mod_path[1..])
.and_then(|module| {
let (decl, decl_path) = module.resolve_symbol(handler, engines, symbol)?;
Ok((decl, decl_path))
Ok((decl, is_self_type, decl_path))
})
}

Expand Down Expand Up @@ -465,6 +477,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,
Expand All @@ -474,9 +492,11 @@ fn resolve_associated_item_from_type_id(
type_id: TypeId,
as_trait: Option<CallPath>,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
) -> 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(
Expand All @@ -489,14 +509,15 @@ fn resolve_associated_item_from_type_id(
};
let item_ref =
TraitMap::get_trait_item_for_type(module, 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)]
Expand All @@ -508,7 +529,7 @@ fn resolve_associated_type_or_item(
decl: ResolvedDeclaration,
as_trait: Option<CallPath>,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
) -> Result<(ResolvedDeclaration, IsSelfType), ErrorEmitted> {
let type_info = decl_to_type_info(handler, engines, symbol, decl)?;
let type_id = engines
.te()
Expand All @@ -528,10 +549,11 @@ fn resolve_call_path_and_root_type_id(
mut as_trait: Option<CallPath>,
call_path: &CallPath,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
) -> 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;
Expand All @@ -545,7 +567,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,
Expand All @@ -559,7 +584,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,
Expand All @@ -568,10 +593,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,
Expand All @@ -580,7 +611,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())))
}
Expand Down
40 changes: 35 additions & 5 deletions sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,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(
Expand Down Expand Up @@ -650,7 +656,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(
Expand Down Expand Up @@ -763,7 +775,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(
Expand Down Expand Up @@ -932,7 +950,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(
Expand Down Expand Up @@ -1012,6 +1036,7 @@ pub(crate) fn item_const_to_constant_declaration(
handler: &Handler,
engines: &Engines,
item_const: ItemConst,
default_visibility: Visibility,
attributes: Attributes,
require_expression: bool,
) -> Result<ParsedDeclId<ConstantDeclaration>, ErrorEmitted> {
Expand Down Expand Up @@ -1044,11 +1069,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,
};
Expand Down
2 changes: 1 addition & 1 deletion sway-lsp/src/traverse/lexed_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
4 changes: 2 additions & 2 deletions sway-parse/src/item/item_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use sway_ast::ItemConst;

impl Parse for ItemConst {
fn parse(parser: &mut Parser) -> ParseResult<ItemConst> {
let visibility = parser.take();
let pub_token = parser.take();
let const_token = parser.parse()?;
let name = parser.parse()?;
let ty_opt = match parser.take() {
Expand All @@ -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,
Expand Down
8 changes: 6 additions & 2 deletions sway-parse/src/item/item_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ use sway_error::parser_error::ParseErrorKind;

impl Parse for ItemImplItem {
fn parse(parser: &mut Parser) -> ParseResult<ItemImplItem> {
if parser.peek::<PubToken>().is_some() || parser.peek::<FnToken>().is_some() {
if parser.peek::<FnToken>().is_some()
|| (parser.peek::<PubToken>().is_some() && parser.peek_next::<FnToken>().is_some())
{
let fn_decl = parser.parse()?;
Ok(ItemImplItem::Fn(fn_decl))
} else if let Some(_const_keyword) = parser.peek::<ConstToken>() {
} else if parser.peek::<ConstToken>().is_some()
|| (parser.peek::<PubToken>().is_some() && parser.peek_next::<ConstToken>().is_some())
{
let const_decl = parser.parse()?;
parser.parse::<SemicolonToken>()?;
Ok(ItemImplItem::Const(const_decl))
Expand Down
Loading
Loading