Skip to content

Commit

Permalink
Introduce lexical scopes to namespace modules (#5600)
Browse files Browse the repository at this point in the history
## Description

This PR introduces a hierarchy of lexical scopes to namespace modules.

This might still have some bugs to work out, but I don't expect the API
to need to change, so am offloading this right now to be able to unblock
further work we have pending on namespaces/modules.

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
  • Loading branch information
tritao committed Feb 14, 2024
1 parent 304317c commit 65c1927
Show file tree
Hide file tree
Showing 21 changed files with 250 additions and 154 deletions.
4 changes: 2 additions & 2 deletions sway-core/src/ir_generation/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ pub(crate) fn compile_constants(
module: Module,
module_ns: &namespace::Module,
) -> Result<(), CompileError> {
for decl_name in module_ns.items().get_all_declared_symbols() {
for decl_name in module_ns.current_items().get_all_declared_symbols() {
if let Some(ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id, .. })) =
module_ns.items().symbols.get(decl_name)
module_ns.current_items().symbols.get(decl_name)
{
let const_decl = engines.de().get_constant(decl_id);
let call_path = const_decl.call_path.clone();
Expand Down
12 changes: 7 additions & 5 deletions sway-core/src/ir_generation/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub(crate) fn compile_const_decl(
(_, Some(config_val), _) => Ok(Some(config_val)),
(None, None, Some(module_ns)) => {
// See if we it's a global const and whether we can compile it *now*.
let decl = module_ns.items().check_symbol(&call_path.suffix);
let decl = module_ns.current_items().check_symbol(&call_path.suffix);
let const_decl = match const_decl {
Some(decl) => Some(decl),
None => None,
Expand Down Expand Up @@ -1179,10 +1179,12 @@ mod tests {
let handler = Handler::default();
let mut context = Context::new(engines.se(), sway_ir::ExperimentalFlags::default());
let mut md_mgr = MetadataManager::default();
let mut core_lib = namespace::Module::default();
core_lib.name = Some(sway_types::Ident::new_no_span(
"assert_is_constant_test".to_string(),
));
let core_lib = namespace::Module {
name: Some(sway_types::Ident::new_no_span(
"assert_is_constant_test".to_string(),
)),
..Default::default()
};

let r = crate::compile_to_ast(
&handler,
Expand Down
7 changes: 6 additions & 1 deletion sway-core/src/language/call_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,12 @@ impl CallPath {
let mut is_external = false;
let mut is_absolute = false;

if let Some(use_synonym) = namespace.module().items().use_synonyms.get(&self.suffix) {
if let Some(use_synonym) = namespace
.module()
.current_items()
.use_synonyms
.get(&self.suffix)
{
synonym_prefixes = use_synonym.0.clone();
is_absolute = use_synonym.3;
let submodule = namespace.module().submodule(&[use_synonym.0[0].clone()]);
Expand Down
26 changes: 15 additions & 11 deletions sway-core/src/semantic_analysis/ast_node/declaration/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,17 +302,21 @@ impl ty::TyAbiDecl {
all_items.push(TyImplItem::Constant(decl_ref.clone()));
let const_shadowing_mode = ctx.const_shadowing_mode();
let generic_shadowing_mode = ctx.generic_shadowing_mode();
let _ = ctx.namespace.module_mut().items_mut().insert_symbol(
handler,
const_name.clone(),
ty::TyDecl::ConstantDecl(ty::ConstantDecl {
name: const_name,
decl_id: *decl_ref.id(),
decl_span: const_decl.span.clone(),
}),
const_shadowing_mode,
generic_shadowing_mode,
);
let _ = ctx
.namespace
.module_mut()
.current_items_mut()
.insert_symbol(
handler,
const_name.clone(),
ty::TyDecl::ConstantDecl(ty::ConstantDecl {
name: const_name,
decl_id: *decl_ref.id(),
decl_span: const_decl.span.clone(),
}),
const_shadowing_mode,
generic_shadowing_mode,
);
}
ty::TyTraitInterfaceItem::Type(decl_ref) => {
all_items.push(TyImplItem::Type(decl_ref.clone()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ impl<'a, 'b> AutoImplAbiEncodeContext<'a, 'b> {
self.ctx
.namespace
.module_mut()
.items_mut()
.current_items_mut()
.implemented_traits
.check_if_trait_constraints_are_satisfied_for_type(
&handler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ impl TyDecl {
// declarations are not allowed
ctx.namespace
.module_mut()
.items_mut()
.current_items_mut()
.set_storage_declaration(handler, decl_ref.clone())?;
decl_ref.into()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,25 +105,29 @@ impl ty::TyFunctionParameter {
pub fn insert_into_namespace(&self, handler: &Handler, ctx: TypeCheckContext) {
let const_shadowing_mode = ctx.const_shadowing_mode();
let generic_shadowing_mode = ctx.generic_shadowing_mode();
let _ = ctx.namespace.module_mut().items_mut().insert_symbol(
handler,
self.name.clone(),
ty::TyDecl::VariableDecl(Box::new(ty::TyVariableDecl {
name: self.name.clone(),
body: ty::TyExpression {
expression: ty::TyExpressionVariant::FunctionParameter,
let _ = ctx
.namespace
.module_mut()
.current_items_mut()
.insert_symbol(
handler,
self.name.clone(),
ty::TyDecl::VariableDecl(Box::new(ty::TyVariableDecl {
name: self.name.clone(),
body: ty::TyExpression {
expression: ty::TyExpressionVariant::FunctionParameter,
return_type: self.type_argument.type_id,
span: self.name.span(),
},
mutability: ty::VariableMutability::new_from_ref_mut(
self.is_reference,
self.is_mutable,
),
return_type: self.type_argument.type_id,
span: self.name.span(),
},
mutability: ty::VariableMutability::new_from_ref_mut(
self.is_reference,
self.is_mutable,
),
return_type: self.type_argument.type_id,
type_ascription: self.type_argument.clone(),
})),
const_shadowing_mode,
generic_shadowing_mode,
);
type_ascription: self.type_argument.clone(),
})),
const_shadowing_mode,
generic_shadowing_mode,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ fn type_check_trait_implementation(
// supertraits of this trait.
ctx.namespace
.module_mut()
.items_mut()
.current_items_mut()
.implemented_traits
.check_if_trait_constraints_are_satisfied_for_type(
handler,
Expand Down
26 changes: 15 additions & 11 deletions sway-core/src/semantic_analysis/ast_node/declaration/trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,17 +447,21 @@ impl TyTraitDecl {
all_items.push(TyImplItem::Constant(decl_ref.clone()));
let const_shadowing_mode = ctx.const_shadowing_mode();
let generic_shadowing_mode = ctx.generic_shadowing_mode();
let _ = ctx.namespace.module_mut().items_mut().insert_symbol(
handler,
const_name.clone(),
ty::TyDecl::ConstantDecl(ty::ConstantDecl {
name: const_name,
decl_id: *decl_ref.id(),
decl_span: const_decl.span.clone(),
}),
const_shadowing_mode,
generic_shadowing_mode,
);
let _ = ctx
.namespace
.module_mut()
.current_items_mut()
.insert_symbol(
handler,
const_name.clone(),
ty::TyDecl::ConstantDecl(ty::ConstantDecl {
name: const_name,
decl_id: *decl_ref.id(),
decl_span: const_decl.span.clone(),
}),
const_shadowing_mode,
generic_shadowing_mode,
);
}
ty::TyTraitInterfaceItem::Type(decl_ref) => {
all_items.push(TyImplItem::Type(decl_ref.clone()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1027,25 +1027,31 @@ impl ty::TyExpression {
let decl_engine = ctx.engines.de();
let engines = ctx.engines();

if !ctx.namespace.module().items().has_storage_declared() {
if !ctx
.namespace
.module()
.current_items()
.has_storage_declared()
{
return Err(handler.emit_err(CompileError::NoDeclaredStorage { span: span.clone() }));
}

let storage_fields = ctx
.namespace
.module()
.items()
.current_items()
.get_storage_field_descriptors(handler, decl_engine)?;

// Do all namespace checking here!
let (storage_access, mut access_type) = ctx.namespace.module().items().apply_storage_load(
handler,
ctx.engines,
ctx.namespace,
checkee,
&storage_fields,
storage_keyword_span,
)?;
let (storage_access, mut access_type) =
ctx.namespace.module().current_items().apply_storage_load(
handler,
ctx.engines,
ctx.namespace,
checkee,
&storage_fields,
storage_keyword_span,
)?;

// The type of a storage access is `core::storage::StorageKey`. This is
// the path to it.
Expand Down Expand Up @@ -2030,7 +2036,7 @@ impl ty::TyExpression {
};
let names_vec = names_vec.into_iter().rev().collect::<Vec<_>>();
let (ty_of_field, _ty_of_parent) =
ctx.namespace.module().items().find_subfield_type(
ctx.namespace.module().current_items().find_subfield_type(
handler,
ctx.engines(),
ctx.namespace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ fn collect_struct_constructors(
// that we wish to encourage.
namespace
.module()
.items()
.current_items()
.get_items_for_type(engines, struct_type_id)
.iter()
.filter_map(|item| match item {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@ pub(super) type SymbolMap = im::OrdMap<Ident, ty::TyDecl>;
pub(super) type UseSynonyms = im::HashMap<Ident, (Vec<Ident>, GlobImport, ty::TyDecl, bool)>;
pub(super) type UseAliases = im::HashMap<String, Ident>;

/// Represents a lexical scope integer-based identifier, which can be used to reference
/// specific a lexical scope.
pub type LexicalScopeId = usize;

/// Represents a lexical scope path, a vector of lexical scope identifiers, which specifies
/// the path from root to a specific lexical scope in the hierarchy.
pub type LexicalScopePath = Vec<LexicalScopeId>;

/// A `LexicalScope` contains a set of all items that exist within the lexical scope via declaration or
/// importing, along with all its associated hierarchical scopes.
#[derive(Clone, Debug, Default)]
pub struct LexicalScope {
/// The set of symbols, implementations, synonyms and aliases present within this scope.
pub items: Items,
/// The set of available scopes defined inside this scope's hierarchy.
pub children: Vec<LexicalScopeId>,
/// The parent scope associated with this scope. Will be None for a root scope.
pub parent: Option<LexicalScopeId>,
}

/// The set of items that exist within some lexical scope via declaration or importing.
#[derive(Clone, Debug, Default)]
pub struct Items {
Expand Down
4 changes: 2 additions & 2 deletions sway-core/src/semantic_analysis/namespace/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
mod items;
mod lexical_scope;
mod module;
#[allow(clippy::module_inception)]
mod namespace;
mod root;
mod submodule_namespace;
mod trait_map;

pub use items::Items;
pub use lexical_scope::{Items, LexicalScope, LexicalScopeId, LexicalScopePath};
pub use module::Module;
pub use namespace::Namespace;
pub use namespace::TryInsertingTraitImplOnFailure;
Expand Down
Loading

0 comments on commit 65c1927

Please sign in to comment.