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

Implements fully working hierarchical lexical scopes. #6784

Merged
merged 31 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e9bec54
Removes TypeCheckContext.scoped namespace cloning.
esdrubal Dec 3, 2024
2f672e8
Replaces currrent_items usage with root_items where possible.
esdrubal Dec 11, 2024
1c778dc
Refactors TraitMap to conform with lexical scopes and removes im data…
esdrubal Dec 11, 2024
78ca358
Use method application callpath because it contains beter span.
esdrubal Dec 11, 2024
ab323ca
Fixes auto_impl scope usage.
esdrubal Dec 11, 2024
838cd96
Minor fixes.
esdrubal Dec 11, 2024
78df26c
Changes to not use im data structures inside lexical scope.
esdrubal Dec 11, 2024
0e3b0b0
Fix so new lexical scopes share the same symbols_unique_while_collect…
esdrubal Dec 11, 2024
dae76bf
Fixes resolve_symbol to traverse more scopes in case of error.
esdrubal Dec 11, 2024
0f6df18
scoped_and_lexical_scope_id now enters ctx.namespace and ctx.collecti…
esdrubal Dec 11, 2024
216f1cd
Adds visitor_parent to LexicalScope.
esdrubal Dec 11, 2024
c8b14a8
Removes unused imports.
esdrubal Dec 11, 2024
08e8242
Changes insert_symbol to use lexical scopes properly.
esdrubal Dec 12, 2024
ec83b67
Changes some places to use root_items and resolve_symbol.
esdrubal Dec 12, 2024
cf368e9
Minor fixes.
esdrubal Dec 12, 2024
34a1d47
Removes is_impl_type_changeable optimization.
esdrubal Dec 12, 2024
630278b
Adds missing parameter.
esdrubal Dec 12, 2024
d15b2df
Cargo clippy fixes.
esdrubal Dec 12, 2024
e757fba
Updates snapshot with metadata changes.
esdrubal Dec 12, 2024
2af2fc5
Use OrdMap instead of HashMap and sorting.
esdrubal Jan 7, 2025
f77b6d8
Constant cannot be shadowed error points to last const declaraation.
esdrubal Jan 7, 2025
17815ae
Updates configurable_dedup_decode snapshot.
esdrubal Jan 7, 2025
86010ff
Revert "Use OrdMap instead of HashMap and sorting."
esdrubal Jan 7, 2025
3007353
Adds comment explaining why we use HashMap instead of OrdMap.
esdrubal Jan 7, 2025
5de3420
Fixes test.
esdrubal Jan 7, 2025
2eefab0
Fixes flaky test snapshot.
esdrubal Jan 8, 2025
c47a31f
Fixes non deterministic method.
esdrubal Jan 9, 2025
e598c1c
Added comment.
esdrubal Jan 9, 2025
4db723d
Moved get_impl_spans_for_decl into TraitMap.
esdrubal Jan 9, 2025
b572add
Merge branch 'master' into esdrubal/hierarchical_lexical_scopes
tritao Jan 9, 2025
cdef5b5
Merge branch 'master' into esdrubal/hierarchical_lexical_scopes
IGI-111 Jan 10, 2025
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 docs/internals.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,9 @@ pub struct LexicalScope {

/// The set of items that exist within some lexical scope via declaration or importing.
pub struct Items {
/// An ordered map from `Ident`s to their associated parsed declarations.
/// A map from `Ident`s to their associated parsed declarations.
pub(crate) parsed_symbols: ParsedSymbolMap,
/// An ordered map from `Ident`s to their associated typed declarations.
/// A map from `Ident`s to their associated typed declarations.
pub(crate) symbols: SymbolMap,
...
}
Expand Down
8 changes: 4 additions & 4 deletions sway-core/src/ir_generation/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ pub(crate) fn compile_constants(
module: Module,
module_ns: &namespace::Module,
) -> Result<(), CompileError> {
for decl_name in module_ns.current_items().get_all_declared_symbols() {
if let Some(resolved_decl) = module_ns.current_items().symbols.get(decl_name) {
for decl_name in module_ns.root_items().get_all_declared_symbols() {
if let Some(resolved_decl) = module_ns.root_items().symbols.get(decl_name) {
if let ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id, .. }) =
&resolved_decl.expect_typed_ref()
{
Expand Down Expand Up @@ -291,10 +291,10 @@ pub(crate) fn compile_configurables(
messages_types_map: &HashMap<TypeId, MessageId>,
cache: &mut CompiledFunctionCache,
) -> Result<(), CompileError> {
for decl_name in module_ns.current_items().get_all_declared_symbols() {
for decl_name in module_ns.root_items().get_all_declared_symbols() {
if let Some(ResolvedDeclaration::Typed(ty::TyDecl::ConfigurableDecl(
ty::ConfigurableDecl { decl_id, .. },
))) = module_ns.current_items().symbols.get(decl_name)
))) = module_ns.root_items().symbols.get(decl_name)
{
let decl = engines.de().get(decl_id);

Expand Down
2 changes: 1 addition & 1 deletion 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(const_val), _) => Ok(Some(const_val)),
(None, Some(module_ns)) => {
// See if we it's a global const and whether we can compile it *now*.
let decl = module_ns.current_items().check_symbol(&call_path.suffix);
let decl = module_ns.root_items().check_symbol(&call_path.suffix);
let const_decl = match const_decl {
Some(decl) => Some(decl),
None => None,
Expand Down
47 changes: 26 additions & 21 deletions sway-core/src/language/call_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,29 +369,34 @@ impl CallPath {
let mut is_absolute = false;

if let Some(mod_path) = namespace.program_id(engines).read(engines, |m| {
if m.current_items().symbols().contains_key(&self.suffix) {
None
} else if let Some((_, path, _, _)) = m
.current_items()
.use_item_synonyms
.get(&self.suffix)
.cloned()
{
Some(path)
} else if let Some(paths_and_decls) = m
.current_items()
.use_glob_synonyms
.get(&self.suffix)
.cloned()
{
if paths_and_decls.len() == 1 {
Some(paths_and_decls[0].0.clone())
m.walk_scope_chain(|lexical_scope| {
let res = if lexical_scope.items.symbols().contains_key(&self.suffix) {
None
} else if let Some((_, path, _, _)) = lexical_scope
.items
.use_item_synonyms
.get(&self.suffix)
.cloned()
{
Some(path)
} else if let Some(paths_and_decls) = lexical_scope
.items
.use_glob_synonyms
.get(&self.suffix)
.cloned()
{
if paths_and_decls.len() == 1 {
Some(paths_and_decls[0].0.clone())
} else {
None
}
} else {
None
}
} else {
None
}
};
Ok(res)
})
.ok()
.flatten()
}) {
synonym_prefixes.clone_from(&mod_path);
is_absolute = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ impl ReplaceDecls for TyExpressionVariant {
FunctionApplication {
ref mut fn_ref,
ref mut arguments,
call_path,
..
} => {
let mut has_changes = false;
Expand All @@ -825,7 +826,7 @@ impl ReplaceDecls for TyExpressionVariant {
handler,
implementing_for_typeid,
&[],
method.name(),
&call_path.suffix,
method.return_type.type_id,
&arguments
.iter()
Expand Down
6 changes: 3 additions & 3 deletions sway-core/src/semantic_analysis/ast_node/code_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl ty::TyCodeBlock {
if !is_root {
let code_block_result =
ctx.by_ref()
.scoped(handler, Some(code_block.span()), |mut ctx| {
.scoped(handler, Some(code_block.span()), |ctx| {
let evaluated_contents = code_block
.contents
.iter()
Expand Down Expand Up @@ -68,7 +68,7 @@ impl ty::TyCodeBlock {
ctx.by_ref()
.with_collecting_unifications()
.with_code_block_first_pass(true)
.scoped(handler, Some(code_block.span()), |mut ctx| {
.scoped(handler, Some(code_block.span()), |ctx| {
code_block.contents.iter().for_each(|node| {
ty::TyAstNode::type_check(&Handler::default(), ctx.by_ref(), node).ok();
});
Expand All @@ -78,7 +78,7 @@ impl ty::TyCodeBlock {
ctx.engines.te().reapply_unifications(ctx.engines());

ctx.by_ref()
.scoped(handler, Some(code_block.span()), |mut ctx| {
.scoped(handler, Some(code_block.span()), |ctx| {
let evaluated_contents = code_block
.contents
.iter()
Expand Down
6 changes: 3 additions & 3 deletions sway-core/src/semantic_analysis/ast_node/declaration/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl ty::TyAbiDecl {
// A temporary namespace for checking within this scope.
ctx.with_abi_mode(AbiMode::ImplAbiFn(name.clone(), None))
.with_self_type(Some(self_type_id))
.scoped(handler, Some(span.clone()), |mut ctx| {
.scoped(handler, Some(span.clone()), |ctx| {
// Insert the "self" type param into the namespace.
self_type_param.insert_self_type_into_namespace(handler, ctx.by_ref());

Expand Down Expand Up @@ -134,7 +134,7 @@ impl ty::TyAbiDecl {
let method = engines.pe().get_trait_fn(&decl_id);
// check that a super-trait does not define a method
// with the same name as the current interface method
error_on_shadowing_superabi_method(&method.name, &mut ctx);
error_on_shadowing_superabi_method(&method.name, ctx);
let method = ty::TyTraitFn::type_check(handler, ctx.by_ref(), &method)?;
for param in &method.parameters {
if param.is_reference || param.is_mutable {
Expand Down Expand Up @@ -200,7 +200,7 @@ impl ty::TyAbiDecl {
Some(self_type_param.type_id),
)
.unwrap_or_else(|_| ty::TyFunctionDecl::error(&method));
error_on_shadowing_superabi_method(&method.name, &mut ctx);
error_on_shadowing_superabi_method(&method.name, ctx);
for param in &method.parameters {
if param.is_reference || param.is_mutable {
handler.emit_err(CompileError::RefMutableNotAllowedInContractAbi {
Expand Down
40 changes: 30 additions & 10 deletions sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ where
}
assert!(!handler.has_warnings(), "{:?}", handler);

let ctx = self.ctx.by_ref();
let mut ctx = self.ctx.by_ref();
let _r = TyDecl::collect(
&handler,
engines,
Expand All @@ -331,24 +331,22 @@ where
return Err(handler);
}

let ctx = self.ctx.by_ref();
let r = ctx.scoped_and_namespace(&handler, None, |ctx| {
let r = ctx.scoped(&handler, None, |ctx| {
TyDecl::type_check(
&handler,
ctx,
&mut ctx.by_ref(),
parsed::Declaration::FunctionDeclaration(decl),
)
});

// Uncomment this to understand why an entry function was not generated
//println!("{:#?}", handler);

let (decl, namespace) = r.map_err(|_| handler.clone())?;
let decl = r.map_err(|_| handler.clone())?;

if handler.has_errors() || matches!(decl, TyDecl::ErrorRecovery(_, _)) {
Err(handler)
} else {
*self.ctx.namespace = namespace;
Ok(TyAstNode {
span: decl.span(engines),
content: ty::TyAstNodeContent::Declaration(decl),
Expand Down Expand Up @@ -382,7 +380,7 @@ where

assert!(!handler.has_errors(), "{:?}", handler);

let ctx = self.ctx.by_ref();
let mut ctx = self.ctx.by_ref();
let _r = TyDecl::collect(
&handler,
engines,
Expand All @@ -393,19 +391,41 @@ where
return Err(handler);
}

let r = ctx.scoped_and_namespace(&handler, None, |ctx| {
let r = ctx.scoped(&handler, None, |ctx| {
TyDecl::type_check(&handler, ctx, Declaration::ImplSelfOrTrait(decl))
});

// Uncomment this to understand why auto impl failed for a type.
//println!("{:#?}", handler);

let (decl, namespace) = r.map_err(|_| handler.clone())?;
let decl = r.map_err(|_| handler.clone())?;

if handler.has_errors() || matches!(decl, TyDecl::ErrorRecovery(_, _)) {
Err(handler)
} else {
*self.ctx.namespace = namespace;
let impl_trait = if let TyDecl::ImplSelfOrTrait(impl_trait_id) = &decl {
engines.de().get_impl_self_or_trait(&impl_trait_id.decl_id)
} else {
unreachable!();
};

// Insert trait implementation generated in the previous scope into the current scope.
ctx.insert_trait_implementation(
esdrubal marked this conversation as resolved.
Show resolved Hide resolved
&handler,
impl_trait.trait_name.clone(),
impl_trait.trait_type_arguments.clone(),
impl_trait.implementing_for.type_id,
&impl_trait.items,
&impl_trait.span,
impl_trait
.trait_decl_ref
.as_ref()
.map(|decl_ref| decl_ref.decl_span().clone()),
crate::namespace::IsImplSelf::No,
crate::namespace::IsExtendingExistingImpl::No,
)
.ok();

Ok(TyAstNode {
span: decl.span(engines),
content: ty::TyAstNodeContent::Declaration(decl),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
},
CallPath,
},
namespace::{IsExtendingExistingImpl, IsImplSelf},
namespace::{IsExtendingExistingImpl, IsImplSelf, Items},
semantic_analysis::{
symbol_collection_context::SymbolCollectionContext, ConstShadowingMode,
GenericShadowingMode, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext,
Expand Down Expand Up @@ -77,7 +77,7 @@ impl TyDecl {

pub(crate) fn type_check(
handler: &Handler,
mut ctx: TypeCheckContext,
ctx: &mut TypeCheckContext,
decl: parsed::Declaration,
) -> Result<ty::TyDecl, ErrorEmitted> {
let type_engine = ctx.engines.te();
Expand Down Expand Up @@ -157,7 +157,7 @@ impl TyDecl {
let fn_decl = engines.pe().get_function(&decl_id);
let span = fn_decl.span.clone();

let mut ctx = ctx.with_type_annotation(type_engine.new_unknown());
let mut ctx = ctx.by_ref().with_type_annotation(type_engine.new_unknown());
let fn_decl = match ty::TyFunctionDecl::type_check(
handler,
ctx.by_ref(),
Expand Down Expand Up @@ -276,9 +276,10 @@ impl TyDecl {
let decl = engines.de().get(f.id());
let collecting_unifications = ctx.collecting_unifications();
let _ = ctx.namespace.module_mut(ctx.engines()).write(engines, |m| {
m.current_items_mut().insert_typed_symbol(
Items::insert_typed_symbol(
handler,
engines,
m,
Ident::new_no_span(format!(
"__contract_entry_{}",
decl.name.clone()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl ty::TyEnumDecl {

pub fn type_check(
handler: &Handler,
ctx: TypeCheckContext,
mut ctx: TypeCheckContext,
decl: EnumDeclaration,
) -> Result<Self, ErrorEmitted> {
let EnumDeclaration {
Expand All @@ -42,7 +42,7 @@ impl ty::TyEnumDecl {
} = decl;

// create a namespace for the decl, used to create a scope for generics
ctx.scoped(handler, Some(span.clone()), |mut ctx| {
ctx.scoped(handler, Some(span.clone()), |ctx| {
// Type check the type parameters.
let new_type_parameters = TypeParameter::type_check_type_params(
handler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl ty::TyFunctionDecl {
ctx.by_ref()
.with_const_shadowing_mode(ConstShadowingMode::Sequential)
.disallow_functions()
.scoped(handler, Some(span.clone()), |mut ctx| {
.scoped(handler, Some(span.clone()), |ctx| {
// Type check the type parameters.
let new_type_parameters = TypeParameter::type_check_type_params(
handler,
Expand Down Expand Up @@ -198,7 +198,7 @@ impl ty::TyFunctionDecl {
ctx.by_ref()
.with_const_shadowing_mode(ConstShadowingMode::Sequential)
.disallow_functions()
.scoped(handler, Some(fn_decl.span.clone()), |mut ctx| {
.scoped(handler, Some(fn_decl.span.clone()), |ctx| {
let FunctionDeclaration { body, .. } = fn_decl;

let ty::TyFunctionDecl {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl TyImplSelfOrTrait {
.with_const_shadowing_mode(ConstShadowingMode::ItemStyle)
.with_self_type(Some(self_type_id))
.allow_functions()
.scoped(handler, Some(block_span.clone()), |mut ctx| {
.scoped(handler, Some(block_span.clone()), |ctx| {
// Type check the type parameters
let new_impl_type_parameters = TypeParameter::type_check_type_params(
handler,
Expand Down Expand Up @@ -168,6 +168,7 @@ impl TyImplSelfOrTrait {

// Update the context
let mut ctx = ctx
.by_ref()
.with_help_text("")
.with_type_annotation(type_engine.new_unknown())
.with_self_type(Some(implementing_for.type_id));
Expand Down Expand Up @@ -347,7 +348,7 @@ impl TyImplSelfOrTrait {
// create the namespace for the impl
ctx.with_const_shadowing_mode(ConstShadowingMode::ItemStyle)
.allow_functions()
.scoped(handler, Some(block_span.clone()), |mut ctx| {
.scoped(handler, Some(block_span.clone()), |ctx| {
// Create a new type parameter for the self type.
let self_type_param =
// Same as with impl trait or ABI, we take the `block_span` as the `use_site_span`
Expand Down Expand Up @@ -422,6 +423,7 @@ impl TyImplSelfOrTrait {
})?;

let mut ctx = ctx
.by_ref()
.with_help_text("")
.with_type_annotation(type_engine.new_unknown());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl ty::TyStructDecl {

pub(crate) fn type_check(
handler: &Handler,
ctx: TypeCheckContext,
mut ctx: TypeCheckContext,
decl: StructDeclaration,
) -> Result<Self, ErrorEmitted> {
let StructDeclaration {
Expand All @@ -45,7 +45,7 @@ impl ty::TyStructDecl {
} = decl;

// create a namespace for the decl, used to create a scope for generics
ctx.scoped(handler, Some(span.clone()), |mut ctx| {
ctx.scoped(handler, Some(span.clone()), |ctx| {
// Type check the type parameters.
let new_type_parameters = TypeParameter::type_check_type_params(
handler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl TyTraitDecl {

// A temporary namespace for checking within the trait's scope.
ctx.with_self_type(Some(self_type))
.scoped(handler, Some(span.clone()), |mut ctx| {
.scoped(handler, Some(span.clone()), |ctx| {
// Type check the type parameters.
let new_type_parameters = TypeParameter::type_check_type_params(
handler,
Expand Down
Loading
Loading