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

Separate prelude imports from star imports #6971

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
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
13 changes: 13 additions & 0 deletions sway-core/src/semantic_analysis/namespace/lexical_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub(super) type SymbolUniqueMap = HashMap<IdentUnique, ResolvedDeclaration>;

type SourceIdent = Ident;

pub(super) type PreludeSynonyms = HashMap<Ident, (ModulePathBuf, ResolvedDeclaration)>;
pub(super) type GlobSynonyms =
HashMap<Ident, Vec<(ModulePathBuf, ResolvedDeclaration, Visibility)>>;
pub(super) type ItemSynonyms = HashMap<
Expand Down Expand Up @@ -94,6 +95,13 @@ pub struct Items {
pub(crate) symbols_unique_while_collecting_unifications: Arc<RwLock<SymbolUniqueMap>>,

pub(crate) implemented_traits: TraitMap,
/// Contains symbols imported from the standard library preludes.
///
/// The import are asserted to never have a name clash. The imported names are always private
/// rather than public (`use ...` rather than `pub use ...`), since the bindings cannot be
/// accessed from outside the importing module. The preludes are asserted to not contain name
/// clashes.
pub(crate) prelude_synonyms: PreludeSynonyms,
/// Contains symbols imported using star imports (`use foo::*`.).
///
/// When star importing from multiple modules the same name may be imported more than once. This
Expand Down Expand Up @@ -206,6 +214,11 @@ impl Items {
}
}

// Check prelude imports
if let Some((decl_path, decl)) = self.prelude_synonyms.get(symbol) {
return Ok(Some((decl.clone(), decl_path.clone())));
}

Ok(None)
}

Expand Down
9 changes: 3 additions & 6 deletions sway-core/src/semantic_analysis/namespace/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,34 +222,31 @@ impl Namespace {
} else if package_name == STD {
// Import core::prelude::*
assert!(self.root.exists_as_external(&core_string));
self.root.star_import(
self.root.prelude_import(
handler,
engines,
&[core_ident, prelude_ident],
&self.current_mod_path,
Visibility::Private,
)?
} else {
// Import core::prelude::* and std::prelude::*
if self.root.exists_as_external(&core_string) {
self.root.star_import(
self.root.prelude_import(
handler,
engines,
&[core_ident, prelude_ident.clone()],
&self.current_mod_path,
Visibility::Private,
)?;
}

let std_string = STD.to_string();
// Only import std::prelude::* if std exists as a dependency
if self.root.exists_as_external(&std_string) {
self.root.star_import(
self.root.prelude_import(
handler,
engines,
&[Ident::new_no_span(std_string), prelude_ident],
&self.current_mod_path,
Visibility::Private,
)?
}
}
Expand Down
81 changes: 81 additions & 0 deletions sway-core/src/semantic_analysis/namespace/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,85 @@ impl Root {

////// IMPORT //////

/// Given a path to a prelude in the standard library, create synonyms to every symbol in that prelude to the given
/// `dst` module.
///
/// This is used when a new module is created in order to pupulate the module with implicit
/// imports from the standard library preludes.
///
/// Paths are assumed to be absolute.
pub(super) fn prelude_import(
&mut self,
handler: &Handler,
engines: &Engines,
src: &ModulePath,
dst: &ModulePath,
) -> Result<(), ErrorEmitted> {
let src_mod = self.require_module(handler, &src.to_vec())?;

let mut imports = vec![];

// A prelude should not declare its own items
assert!(src_mod.root_items().symbols.is_empty());

// Collect those item-imported items that the source module reexports
let mut symbols = src_mod
.root_items()
.use_item_synonyms
.keys()
.clone()
.collect::<Vec<_>>();
symbols.sort();
for symbol in symbols {
let (_, path, decl, src_visibility) = &src_mod.root_items().use_item_synonyms[symbol];
// Preludes reexport all their imports
// EXCEPT: In our IR generation tests we compile core in a way that causes forc-pkg to
// insert a CONTRACT_ID declaration into core. This gets imported into core::prelude,
// but does not get reexported. Hence, in those particular tests we do in fact have a
// symbol in core::prelude that does not get reexported...
assert!(
matches!(src_visibility, Visibility::Public) || symbol.as_str() == "CONTRACT_ID"
);
imports.push((symbol.clone(), decl.clone(), path.clone()))
}

// Collect those glob-imported items that the source module reexports. There should be no
// name clashes in a prelude, so item reexports and glob reexports can be treated the same
// way.
let mut symbols = src_mod
.root_items()
.use_glob_synonyms
.keys()
.clone()
.collect::<Vec<_>>();
symbols.sort();
for symbol in symbols {
let bindings = &src_mod.root_items().use_glob_synonyms[symbol];
for (path, decl, src_visibility) in bindings.iter() {
// Preludes reexport all their imports
assert!(matches!(src_visibility, Visibility::Public));
imports.push((symbol.clone(), decl.clone(), path.clone()))
}
}

let implemented_traits = src_mod.root_items().implemented_traits.clone();
let dst_mod = self.require_module_mut_in_current_package(handler, &dst.to_vec())?;

dst_mod
.current_items_mut()
.implemented_traits
.extend(implemented_traits, engines);

let dst_prelude_synonyms = &mut dst_mod.current_items_mut().prelude_synonyms;
imports.iter().for_each(|(symbol, decl, path)| {
// Preludes should not contain name clashes
assert!(!dst_prelude_synonyms.contains_key(symbol));
dst_prelude_synonyms.insert(symbol.clone(), (path.clone(), decl.clone()));
});

Ok(())
}

/// Given a path to a `src` module, create synonyms to every symbol in that module to the given
/// `dst` module.
///
Expand Down Expand Up @@ -523,6 +602,8 @@ impl Root {
span: item.span(),
}));
}
} else if let Some((path, decl)) = src_items.prelude_synonyms.get(item) {
(decl.clone(), path.clone(), Visibility::Private)
} else {
// Symbol not found
return Err(handler.emit_err(CompileError::SymbolNotFound {
Expand Down
Loading