Skip to content
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

Eliminate alias map from lexical scope #5931

Merged
merged 6 commits into from
May 2, 2024
Merged
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
29 changes: 16 additions & 13 deletions sway-core/src/language/call_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,27 +311,30 @@ impl CallPath {
let mut is_external = false;
let mut is_absolute = false;

if let Some(use_synonym) = namespace.module_id(engines).read(engines, |m| {
if m.current_items()
if let Some(mod_path) = namespace.module_id(engines).read(engines, |m| {
if let Some((_, path, _)) = m
.current_items()
.use_item_synonyms
.contains_key(&self.suffix)
.get(&self.suffix)
.cloned()
{
m.current_items()
.use_item_synonyms
.get(&self.suffix)
.cloned()
Some(path)
} else if let Some((path, _)) = m
.current_items()
.use_glob_synonyms
.get(&self.suffix)
.cloned()
{
Some(path)
} else {
m.current_items()
.use_glob_synonyms
.get(&self.suffix)
.cloned()
None
}
}) {
synonym_prefixes = use_synonym.0.clone();
synonym_prefixes = mod_path.clone();
is_absolute = true;
let submodule = namespace
.module(engines)
.submodule(engines, &[use_synonym.0[0].clone()]);
.submodule(engines, &[mod_path[0].clone()]);
if let Some(submodule) = submodule {
is_external = submodule.read(engines, |m| m.is_external);
}
Expand Down
21 changes: 10 additions & 11 deletions sway-core/src/semantic_analysis/namespace/lexical_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,9 @@ impl ResolvedFunctionDecl {

pub(super) type ParsedSymbolMap = im::OrdMap<Ident, Declaration>;
pub(super) type SymbolMap = im::OrdMap<Ident, ty::TyDecl>;
// The `Vec<Ident>` path is absolute.
pub(super) type GlobSynonyms = im::HashMap<Ident, (Vec<Ident>, ty::TyDecl)>;
pub(super) type ItemSynonyms = im::HashMap<Ident, (Vec<Ident>, ty::TyDecl)>;
pub(super) type UseAliases = im::HashMap<String, Ident>;
type SourceIdent = Ident;
pub(super) type GlobSynonyms = im::HashMap<Ident, (ModulePathBuf, ty::TyDecl)>;
pub(super) type ItemSynonyms = im::HashMap<Ident, (Option<SourceIdent>, ModulePathBuf, ty::TyDecl)>;

/// Represents a lexical scope integer-based identifier, which can be used to reference
/// specific a lexical scope.
Expand Down Expand Up @@ -77,13 +76,11 @@ pub struct Items {
///
/// use_glob_synonyms contains symbols imported using star imports (`use foo::*`.).
/// use_item_synonyms contains symbols imported using item imports (`use foo::bar`).
///
/// For aliased item imports `use ::foo::bar::Baz as Wiz` the map key is `Wiz`. `Baz` is stored
/// as the optional source identifier for error reporting purposes.
pub(crate) use_glob_synonyms: GlobSynonyms,
pub(crate) use_item_synonyms: ItemSynonyms,
/// Represents an alternative name for an imported symbol.
///
/// Aliases are introduced with syntax like `use foo::bar as baz;` syntax, where `baz` is an
/// alias for `bar`.
pub(crate) use_aliases: UseAliases,
/// If there is a storage declaration (which are only valid in contracts), store it here.
pub(crate) declared_storage: Option<DeclRefStorage>,
}
Expand Down Expand Up @@ -287,12 +284,14 @@ impl Items {
append_shadowing_error(ident, decl, false, false, &item, const_shadowing_mode);
}

if let Some((ident, (_, decl))) = self.use_item_synonyms.get_key_value(&name) {
if let Some((ident, (imported_ident, _, decl))) =
self.use_item_synonyms.get_key_value(&name)
{
append_shadowing_error(
ident,
decl,
true,
self.use_aliases.get(&name.to_string()).is_some(),
imported_ident.is_some(),
&item,
const_shadowing_mode,
);
Expand Down
119 changes: 55 additions & 64 deletions sway-core/src/semantic_analysis/namespace/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,12 @@ impl Root {
dst_mod
.current_items_mut()
.implemented_traits
.extend(implemented_traits, engines); // TODO: No difference made between imported and declared items
.extend(implemented_traits, engines);
for symbol_and_decl in symbols_and_decls {
dst_mod.current_items_mut().use_glob_synonyms.insert(
// TODO: No difference made between imported and declared items
symbol_and_decl.0,
(src.to_vec(), symbol_and_decl.1),
);
dst_mod
.current_items_mut()
.use_glob_synonyms
.insert(symbol_and_decl.0, (src.to_vec(), symbol_and_decl.1));
}

Ok(())
Expand Down Expand Up @@ -161,25 +160,26 @@ impl Root {
}
// no matter what, import it this way though.
let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?;
let add_synonym = |name| {
if let Some((_, _)) = dst_mod.current_items().use_item_synonyms.get(name) {
let check_name_clash = |name| {
if let Some((_, _, _)) = dst_mod.current_items().use_item_synonyms.get(name) {
handler.emit_err(CompileError::ShadowsOtherSymbol { name: name.into() });
}
dst_mod.current_items_mut().use_item_synonyms.insert(
// TODO: No difference made between imported and declared items
name.clone(),
(src.to_vec(), decl),
);
};
match alias {
Some(alias) => {
add_synonym(&alias);
check_name_clash(&alias);
dst_mod
.current_items_mut()
.use_item_synonyms
.insert(alias.clone(), (Some(item.clone()), src.to_vec(), decl))
}
None => {
check_name_clash(item);
dst_mod
.current_items_mut()
.use_aliases
.insert(alias.as_str().to_string(), item.clone()); // TODO: No difference made between imported and declared items
.use_item_synonyms
.insert(item.clone(), (None, src.to_vec(), decl))
}
None => add_synonym(item),
};
}
None => {
Expand All @@ -194,7 +194,7 @@ impl Root {
dst_mod
.current_items_mut()
.implemented_traits
.extend(impls_to_insert, engines); // TODO: No difference made between imported and declared items
.extend(impls_to_insert, engines);

Ok(())
}
Expand Down Expand Up @@ -245,37 +245,44 @@ impl Root {
{
// import it this way.
let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?;
let mut add_synonym = |name| {
if let Some((_, _)) =
dst_mod.current_items().use_item_synonyms.get(name)
{
let check_name_clash = |name| {
if dst_mod.current_items().use_item_synonyms.contains_key(name) {
handler.emit_err(CompileError::ShadowsOtherSymbol {
name: name.into(),
});
}
dst_mod.current_items_mut().use_item_synonyms.insert(
// TODO: No difference made between imported and declared items
name.clone(),
(
src.to_vec(),
TyDecl::EnumVariantDecl(ty::EnumVariantDecl {
enum_ref: enum_ref.clone(),
variant_name: variant_name.clone(),
variant_decl_span: variant_decl.span.clone(),
}),
),
);
};
match alias {
Some(alias) => {
add_synonym(&alias);
dst_mod
.current_items_mut()
.use_aliases
.insert(alias.as_str().to_string(), variant_name.clone());
// TODO: No difference made between imported and declared items
check_name_clash(&alias);
dst_mod.current_items_mut().use_item_synonyms.insert(
alias.clone(),
(
Some(variant_name.clone()),
src.to_vec(),
TyDecl::EnumVariantDecl(ty::EnumVariantDecl {
enum_ref: enum_ref.clone(),
variant_name: variant_name.clone(),
variant_decl_span: variant_decl.span.clone(),
}),
),
);
}
None => {
check_name_clash(variant_name);
dst_mod.current_items_mut().use_item_synonyms.insert(
variant_name.clone(),
(
None,
src.to_vec(),
TyDecl::EnumVariantDecl(ty::EnumVariantDecl {
enum_ref: enum_ref.clone(),
variant_name: variant_name.clone(),
variant_decl_span: variant_decl.span.clone(),
}),
),
);
}
None => add_synonym(variant_name),
};
} else {
return Err(handler.emit_err(CompileError::SymbolNotFound {
Expand Down Expand Up @@ -345,7 +352,6 @@ impl Root {
// import it this way.
let dst_mod = self.module.lookup_submodule_mut(handler, engines, dst)?;
dst_mod.current_items_mut().use_glob_synonyms.insert(
// TODO: No difference made between imported and declared items
variant_name.clone(),
(
src.to_vec(),
Expand Down Expand Up @@ -403,7 +409,7 @@ impl Root {
for (symbol, (_, decl)) in src_mod.current_items().use_glob_synonyms.iter() {
all_symbols_and_decls.push((symbol.clone(), decl.clone()));
}
for (symbol, (_, decl)) in src_mod.current_items().use_item_synonyms.iter() {
for (symbol, (_, _, decl)) in src_mod.current_items().use_item_synonyms.iter() {
all_symbols_and_decls.push((symbol.clone(), decl.clone()));
}
for (symbol, decl) in src_mod.current_items().symbols.iter() {
Expand All @@ -429,7 +435,7 @@ impl Root {
path
};

for (symbol, (mod_path, decl)) in use_item_synonyms {
for (symbol, (_, mod_path, decl)) in use_item_synonyms {
symbols_paths_and_decls.push((symbol, get_path(mod_path), decl));
}
for (symbol, (mod_path, decl)) in use_glob_synonyms {
Expand All @@ -440,7 +446,7 @@ impl Root {
dst_mod
.current_items_mut()
.implemented_traits
.extend(implemented_traits, engines); // TODO: No difference made between imported and declared items
.extend(implemented_traits, engines);

let mut try_add = |symbol, path, decl: ty::TyDecl| {
dst_mod
Expand Down Expand Up @@ -635,9 +641,7 @@ impl Root {
current_mod_path.push(ident.clone());
}
None => {
decl_opt = Some(
self.resolve_symbol_helper(handler, engines, ident, module, self_type)?,
);
decl_opt = Some(self.resolve_symbol_helper(handler, ident, module)?);
}
}
}
Expand All @@ -651,8 +655,7 @@ impl Root {
self.module
.lookup_submodule(handler, engines, mod_path)
.and_then(|module| {
let decl =
self.resolve_symbol_helper(handler, engines, symbol, module, self_type)?;
let decl = self.resolve_symbol_helper(handler, symbol, module)?;
Ok((decl, mod_path.to_vec()))
})
}
Expand Down Expand Up @@ -802,29 +805,17 @@ impl Root {
fn resolve_symbol_helper(
&self,
handler: &Handler,
engines: &Engines,
symbol: &Ident,
module: &Module,
self_type: Option<TypeId>,
) -> Result<ResolvedDeclaration, ErrorEmitted> {
let true_symbol = module
.current_items()
.use_aliases
.get(symbol.as_str())
.unwrap_or(symbol);
// Check locally declared items. Any name clash with imports will have already been reported as an error.
if let Some(decl) = module.current_items().symbols.get(true_symbol) {
if let Some(decl) = module.current_items().symbols.get(symbol) {
return Ok(ResolvedDeclaration::Typed(decl.clone()));
}
// Check item imports
if let Some((_, decl @ ty::TyDecl::EnumVariantDecl { .. })) =
module.current_items().use_item_synonyms.get(symbol)
{
if let Some((_, _, decl)) = module.current_items().use_item_synonyms.get(symbol) {
return Ok(ResolvedDeclaration::Typed(decl.clone()));
}
if let Some((src_path, _)) = module.current_items().use_item_synonyms.get(symbol) {
return self.resolve_symbol(handler, engines, src_path, true_symbol, self_type);
}
// Check glob imports
if let Some((_, decl)) = module.current_items().use_glob_synonyms.get(symbol) {
return Ok(ResolvedDeclaration::Typed(decl.clone()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,31 @@ script;
// This tests importing other files.

mod foo;
mod wiz;

use foo::Foo as MyFoo;

use wiz::Wiz as WizWiz;

// This is fine - the imported Wiz name is aliased, so no name clash
struct Wiz {
local_wiz: bool
}

fn main() -> u64 {
let foo = MyFoo {
foo: 42,
};
foo.foo
let wiz = WizWiz {
wiz: 128
};
let local_wiz = Wiz { // This should resolve to the locally defined Wiz
local_wiz: true
};
if local_wiz.local_wiz {
foo.foo + wiz.wiz
}
else {
0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
library;

// Dead code analysis disabled due to a bug.
// See https://github.com/FuelLabs/sway/issues/5902#issuecomment-2079212717
#[allow(dead_code)]
pub struct Wiz {
pub wiz: u64,
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
category = "run"
expected_result = { action = "return", value = 42 }
expected_result_new_encoding = { action = "return_data", value = "000000000000002A" }
expected_result = { action = "return", value = 170 }
expected_result_new_encoding = { action = "return_data", value = "00000000000000AA" }
validate_abi = true
Loading