Skip to content

Commit

Permalink
Refactor TypeCheckContext::scoped to take a closure (#5592)
Browse files Browse the repository at this point in the history
## Description

This PR refactors the interface for changing the namespace in a type
checking context.

This change is preparatory work for the collecting context work and will
be used in upcoming PRs.

No functional changes intended.

## 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 12, 2024
1 parent 996a351 commit 76e407a
Show file tree
Hide file tree
Showing 14 changed files with 1,304 additions and 1,230 deletions.
7 changes: 5 additions & 2 deletions sway-core/src/semantic_analysis/ast_node/code_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ impl ty::TyCodeBlock {
.contents
.iter()
.filter_map(|node| {
let ctx = ctx.by_ref().scoped(&mut code_block_namespace);
ty::TyAstNode::type_check(handler, ctx, node.clone()).ok()
ctx.by_ref()
.scoped(&mut code_block_namespace, |ctx| {
ty::TyAstNode::type_check(handler, ctx, node.clone())
})
.ok()
})
.collect::<Vec<ty::TyAstNode>>();

Expand Down
277 changes: 140 additions & 137 deletions sway-core/src/semantic_analysis/ast_node/declaration/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,61 +54,136 @@ impl ty::TyAbiDecl {

// A temporary namespace for checking within this scope.
let mut abi_namespace = ctx.namespace.clone();
let mut ctx = ctx
.scoped(&mut abi_namespace)
.with_abi_mode(AbiMode::ImplAbiFn(name.clone(), None))
.with_self_type(Some(self_type_id));
ctx.with_abi_mode(AbiMode::ImplAbiFn(name.clone(), None))
.with_self_type(Some(self_type_id))
.scoped(&mut abi_namespace, |mut ctx| {
// Insert the "self" type param into the namespace.
self_type_param.insert_self_type_into_namespace(handler, ctx.by_ref());

// Insert the "self" type param into the namespace.
self_type_param.insert_self_type_into_namespace(handler, ctx.by_ref());
// Recursively make the interface surfaces and methods of the
// supertraits available to this abi.
insert_supertraits_into_namespace(
handler,
ctx.by_ref(),
self_type_id,
&supertraits,
&SupertraitOf::Abi(span.clone()),
)?;

// Recursively make the interface surfaces and methods of the
// supertraits available to this abi.
insert_supertraits_into_namespace(
handler,
ctx.by_ref(),
self_type_id,
&supertraits,
&SupertraitOf::Abi(span.clone()),
)?;
// Type check the interface surface.
let mut new_interface_surface = vec![];

// Type check the interface surface.
let mut new_interface_surface = vec![];
let mut ids: HashSet<Ident> = HashSet::default();

let mut ids: HashSet<Ident> = HashSet::default();
let error_on_shadowing_superabi_method =
|method_name: &Ident, ctx: &mut TypeCheckContext| {
if let Ok(superabi_impl_method_ref) = ctx.find_method_for_type(
&Handler::default(),
self_type_id,
&[],
&method_name.clone(),
ctx.type_annotation(),
&Default::default(),
None,
TryInsertingTraitImplOnFailure::No,
) {
let superabi_impl_method =
ctx.engines.de().get_function(&superabi_impl_method_ref);
if let Some(ty::TyDecl::AbiDecl(abi_decl)) =
&superabi_impl_method.implementing_type
{
handler.emit_err(CompileError::AbiShadowsSuperAbiMethod {
span: method_name.span(),
superabi: abi_decl.name.clone(),
});
}
}
};

let error_on_shadowing_superabi_method =
|method_name: &Ident, ctx: &mut TypeCheckContext| {
if let Ok(superabi_impl_method_ref) = ctx.find_method_for_type(
&Handler::default(),
self_type_id,
&[],
&method_name.clone(),
ctx.type_annotation(),
&Default::default(),
None,
TryInsertingTraitImplOnFailure::No,
) {
let superabi_impl_method =
ctx.engines.de().get_function(&superabi_impl_method_ref);
if let Some(ty::TyDecl::AbiDecl(abi_decl)) =
&superabi_impl_method.implementing_type
{
handler.emit_err(CompileError::AbiShadowsSuperAbiMethod {
span: method_name.span(),
superabi: abi_decl.name.clone(),
for item in interface_surface.into_iter() {
let decl_name = match item {
TraitItem::TraitFn(method) => {
// 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);
let method = ty::TyTraitFn::type_check(handler, ctx.by_ref(), method)?;
for param in &method.parameters {
if param.is_reference || param.is_mutable {
handler.emit_err(
CompileError::RefMutableNotAllowedInContractAbi {
param_name: param.name.clone(),
span: param.name.span(),
},
);
}
}
new_interface_surface.push(ty::TyTraitInterfaceItem::TraitFn(
ctx.engines.de().insert(method.clone()),
));
method.name.clone()
}
TraitItem::Constant(decl_id) => {
let const_decl = engines.pe().get_constant(&decl_id).as_ref().clone();
let const_decl =
ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl)?;
let decl_ref = ctx.engines.de().insert(const_decl.clone());
new_interface_surface
.push(ty::TyTraitInterfaceItem::Constant(decl_ref.clone()));

let const_name = const_decl.call_path.suffix.clone();
ctx.insert_symbol(
handler,
const_name.clone(),
ty::TyDecl::ConstantDecl(ty::ConstantDecl {
name: const_name.clone(),
decl_id: *decl_ref.id(),
decl_span: const_decl.span.clone(),
}),
)?;

const_name
}
TraitItem::Type(decl_id) => {
let type_decl = engines.pe().get_trait_type(&decl_id).as_ref().clone();
handler.emit_err(CompileError::AssociatedTypeNotSupportedInAbi {
span: type_decl.span.clone(),
});

let type_decl =
ty::TyTraitType::type_check(handler, ctx.by_ref(), type_decl)?;
let decl_ref = ctx.engines().de().insert(type_decl.clone());
new_interface_surface
.push(ty::TyTraitInterfaceItem::Type(decl_ref.clone()));

type_decl.name
}
TraitItem::Error(_, _) => {
continue;
}
};

if !ids.insert(decl_name.clone()) {
handler.emit_err(CompileError::MultipleDefinitionsOfName {
name: decl_name.clone(),
span: decl_name.span(),
});
}
}
};

for item in interface_surface.into_iter() {
let decl_name = match item {
TraitItem::TraitFn(method) => {
// check that a super-trait does not define a method
// with the same name as the current interface method
// Type check the items.
let mut new_items = vec![];
for method_id in methods.into_iter() {
let method = engines.pe().get_function(&method_id);
let method = ty::TyFunctionDecl::type_check(
handler,
ctx.by_ref(),
&method,
false,
false,
Some(self_type_param.type_id),
)
.unwrap_or_else(|_| ty::TyFunctionDecl::error(&method));
error_on_shadowing_superabi_method(&method.name, &mut ctx);
let method = ty::TyTraitFn::type_check(handler, ctx.by_ref(), method)?;
for param in &method.parameters {
if param.is_reference || param.is_mutable {
handler.emit_err(CompileError::RefMutableNotAllowedInContractAbi {
Expand All @@ -117,100 +192,28 @@ impl ty::TyAbiDecl {
});
}
}
new_interface_surface.push(ty::TyTraitInterfaceItem::TraitFn(
ctx.engines.de().insert(method.clone()),
));
method.name.clone()
}
TraitItem::Constant(decl_id) => {
let const_decl = engines.pe().get_constant(&decl_id).as_ref().clone();
let const_decl =
ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl)?;
let decl_ref = ctx.engines.de().insert(const_decl.clone());
new_interface_surface
.push(ty::TyTraitInterfaceItem::Constant(decl_ref.clone()));

let const_name = const_decl.call_path.suffix.clone();
ctx.insert_symbol(
handler,
const_name.clone(),
ty::TyDecl::ConstantDecl(ty::ConstantDecl {
name: const_name.clone(),
decl_id: *decl_ref.id(),
decl_span: const_decl.span.clone(),
}),
)?;

const_name
}
TraitItem::Type(decl_id) => {
let type_decl = engines.pe().get_trait_type(&decl_id).as_ref().clone();
handler.emit_err(CompileError::AssociatedTypeNotSupportedInAbi {
span: type_decl.span.clone(),
});

let type_decl = ty::TyTraitType::type_check(handler, ctx.by_ref(), type_decl)?;
let decl_ref = ctx.engines().de().insert(type_decl.clone());
new_interface_surface.push(ty::TyTraitInterfaceItem::Type(decl_ref.clone()));

type_decl.name
}
TraitItem::Error(_, _) => {
continue;
}
};

if !ids.insert(decl_name.clone()) {
handler.emit_err(CompileError::MultipleDefinitionsOfName {
name: decl_name.clone(),
span: decl_name.span(),
});
}
}

// Type check the items.
let mut new_items = vec![];
for method_id in methods.into_iter() {
let method = engines.pe().get_function(&method_id);
let method = ty::TyFunctionDecl::type_check(
handler,
ctx.by_ref(),
&method,
false,
false,
Some(self_type_param.type_id),
)
.unwrap_or_else(|_| ty::TyFunctionDecl::error(&method));
error_on_shadowing_superabi_method(&method.name, &mut ctx);
for param in &method.parameters {
if param.is_reference || param.is_mutable {
handler.emit_err(CompileError::RefMutableNotAllowedInContractAbi {
param_name: param.name.clone(),
span: param.name.span(),
});
if !ids.insert(method.name.clone()) {
handler.emit_err(CompileError::MultipleDefinitionsOfName {
name: method.name.clone(),
span: method.name.span(),
});
}
new_items.push(TyTraitItem::Fn(ctx.engines.de().insert(method)));
}
}
if !ids.insert(method.name.clone()) {
handler.emit_err(CompileError::MultipleDefinitionsOfName {
name: method.name.clone(),
span: method.name.span(),
});
}
new_items.push(TyTraitItem::Fn(ctx.engines.de().insert(method)));
}

// Compared to regular traits, we do not insert recursively methods of ABI supertraits
// into the interface surface, we do not want supertrait methods to be available to
// the ABI user, only the contract methods can use supertrait methods
let abi_decl = ty::TyAbiDecl {
interface_surface: new_interface_surface,
supertraits,
items: new_items,
name,
span,
attributes,
};
Ok(abi_decl)
// Compared to regular traits, we do not insert recursively methods of ABI supertraits
// into the interface surface, we do not want supertrait methods to be available to
// the ABI user, only the contract methods can use supertrait methods
let abi_decl = ty::TyAbiDecl {
interface_surface: new_interface_surface,
supertraits,
items: new_items,
name,
span,
attributes,
};
Ok(abi_decl)
})
}

pub(crate) fn insert_interface_surface_and_items_into_namespace(
Expand Down
58 changes: 31 additions & 27 deletions sway-core/src/semantic_analysis/ast_node/declaration/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,40 @@ impl ty::TyEnumDecl {

// create a namespace for the decl, used to create a scope for generics
let mut decl_namespace = ctx.namespace.clone();
let mut ctx = ctx.scoped(&mut decl_namespace);

// Type check the type parameters.
let new_type_parameters =
TypeParameter::type_check_type_params(handler, ctx.by_ref(), type_parameters, None)?;
ctx.scoped(&mut decl_namespace, |mut ctx| {
// Type check the type parameters.
let new_type_parameters = TypeParameter::type_check_type_params(
handler,
ctx.by_ref(),
type_parameters,
None,
)?;

// type check the variants
let mut variants_buf = vec![];
for variant in variants {
variants_buf.push(
match ty::TyEnumVariant::type_check(handler, ctx.by_ref(), variant.clone()) {
Ok(res) => res,
Err(_) => continue,
},
);
}
// type check the variants
let mut variants_buf = vec![];
for variant in variants {
variants_buf.push(
match ty::TyEnumVariant::type_check(handler, ctx.by_ref(), variant.clone()) {
Ok(res) => res,
Err(_) => continue,
},
);
}

let mut call_path: CallPath = name.into();
call_path = call_path.to_fullpath(ctx.namespace);
let mut call_path: CallPath = name.into();
call_path = call_path.to_fullpath(ctx.namespace);

// create the enum decl
let decl = ty::TyEnumDecl {
call_path,
type_parameters: new_type_parameters,
variants: variants_buf,
span,
attributes,
visibility,
};
Ok(decl)
// create the enum decl
let decl = ty::TyEnumDecl {
call_path,
type_parameters: new_type_parameters,
variants: variants_buf,
span,
attributes,
visibility,
};
Ok(decl)
})
}
}

Expand Down
Loading

0 comments on commit 76e407a

Please sign in to comment.