Skip to content

Commit

Permalink
Introduce the collection context in the type check context. (#6460)
Browse files Browse the repository at this point in the history
## Description

This PR does a couple things:

* Creates all of the necessary lexical scopes in the collection context
namespace
* Introduces the collection context in the type check context
* Updates type checking code to enter the corresponding lexical scope in
the collection context
* Introduces a mapping from a span to a lexical scope in the namespace
* Implements collection steps for so far unimplemented AST nodes

This prepares the compiler for a future PR where the additional
namespace will be able to be removed from the type checking, and with it
the cloning we do as we type check.

## 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).
- [ ] If my change requires substantial documentation changes, I have
[requested support from the DevRel
team](https://github.com/FuelLabs/devrel-requests/issues/new/choose)
- [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.

---------

Co-authored-by: Joshua Batty <joshpbatty@gmail.com>
Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 19, 2024
1 parent 613f129 commit d178613
Show file tree
Hide file tree
Showing 35 changed files with 1,123 additions and 453 deletions.
6 changes: 6 additions & 0 deletions sway-core/src/engine_threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@ impl<T: DebugWithEngines> DebugWithEngines for Vec<T> {
}
}

impl DebugWithEngines for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
DisplayWithEngines::fmt(self, f, engines)
}
}

pub trait HashWithEngines {
fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines);
}
Expand Down
2 changes: 0 additions & 2 deletions sway-core/src/language/parsed/declaration/function.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::{
engine_threading::*,
language::{parsed::*, *},
namespace::LexicalScopeId,
transform::{self, AttributeKind},
type_system::*,
};
Expand Down Expand Up @@ -29,7 +28,6 @@ pub struct FunctionDeclaration {
pub where_clause: Vec<(Ident, Vec<TraitConstraint>)>,
pub kind: FunctionDeclarationKind,
pub implementing_type: Option<Declaration>,
pub lexical_scope: LexicalScopeId,
}

impl EqWithEngines for FunctionDeclaration {}
Expand Down
40 changes: 13 additions & 27 deletions sway-core/src/language/ty/declaration/variable.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
use std::hash::{Hash, Hasher};

use sway_error::handler::{ErrorEmitted, Handler};
use sway_types::Ident;
use sway_types::{Ident, Named, Spanned};

use crate::{
engine_threading::*,
language::{parsed::VariableDeclaration, ty::*},
semantic_analysis::{
TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckFinalization,
TypeCheckFinalizationContext,
},
type_system::*,
};

Expand All @@ -26,6 +21,18 @@ impl TyDeclParsedType for TyVariableDecl {
type ParsedType = VariableDeclaration;
}

impl Named for TyVariableDecl {
fn name(&self) -> &sway_types::BaseIdent {
&self.name
}
}

impl Spanned for TyVariableDecl {
fn span(&self) -> sway_types::Span {
self.name.span()
}
}

impl EqWithEngines for TyVariableDecl {}
impl PartialEqWithEngines for TyVariableDecl {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
Expand Down Expand Up @@ -65,24 +72,3 @@ impl SubstTypes for TyVariableDecl {
self.body.subst(type_mapping, ctx)
}
}

impl TypeCheckAnalysis for TyVariableDecl {
fn type_check_analyze(
&self,
handler: &Handler,
ctx: &mut TypeCheckAnalysisContext,
) -> Result<(), ErrorEmitted> {
self.body.type_check_analyze(handler, ctx)?;
Ok(())
}
}

impl TypeCheckFinalization for TyVariableDecl {
fn type_check_finalize(
&mut self,
handler: &Handler,
ctx: &mut TypeCheckFinalizationContext,
) -> Result<(), ErrorEmitted> {
self.body.type_check_finalize(handler, ctx)
}
}
3 changes: 2 additions & 1 deletion sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,14 +570,15 @@ pub fn parsed_to_ast(

let namespace = Namespace::init_root(initial_namespace);
// Collect the program symbols.
let _collection_ctx =
let mut collection_ctx =
ty::TyProgram::collect(handler, engines, parse_program, namespace.clone())?;

// Type check the program.
let typed_program_opt = ty::TyProgram::type_check(
handler,
engines,
parse_program,
&mut collection_ctx,
namespace,
package_name,
build_config,
Expand Down
65 changes: 36 additions & 29 deletions sway-core/src/semantic_analysis/ast_node/code_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ impl ty::TyCodeBlock {
ctx: &mut SymbolCollectionContext,
code_block: &CodeBlock,
) -> Result<(), ErrorEmitted> {
let _ = code_block
.contents
.iter()
.map(|node| ty::TyAstNode::collect(handler, engines, ctx, node))
.filter_map(|res| res.ok())
.collect::<Vec<_>>();

let _ = ctx.scoped(engines, code_block.whole_block_span.clone(), |scoped_ctx| {
let _ = code_block
.contents
.iter()
.map(|node| ty::TyAstNode::collect(handler, engines, scoped_ctx, node))
.filter_map(|res| res.ok())
.collect::<Vec<_>>();
Ok(())
});
Ok(())
}

Expand All @@ -28,17 +30,21 @@ impl ty::TyCodeBlock {
is_root: bool,
) -> Result<Self, ErrorEmitted> {
if !is_root {
let code_block_result = ctx.by_ref().scoped(|mut ctx| {
let evaluated_contents = code_block
.contents
.iter()
.filter_map(|node| ty::TyAstNode::type_check(handler, ctx.by_ref(), node).ok())
.collect::<Vec<ty::TyAstNode>>();
Ok(ty::TyCodeBlock {
contents: evaluated_contents,
whole_block_span: code_block.whole_block_span.clone(),
})
})?;
let code_block_result =
ctx.by_ref()
.scoped(handler, Some(code_block.span()), |mut ctx| {
let evaluated_contents = code_block
.contents
.iter()
.filter_map(|node| {
ty::TyAstNode::type_check(handler, ctx.by_ref(), node).ok()
})
.collect::<Vec<ty::TyAstNode>>();
Ok(ty::TyCodeBlock {
contents: evaluated_contents,
whole_block_span: code_block.whole_block_span.clone(),
})
})?;

return Ok(code_block_result);
}
Expand All @@ -57,7 +63,7 @@ impl ty::TyCodeBlock {
ctx.by_ref()
.with_collecting_unifications()
.with_code_block_first_pass(true)
.scoped(|mut ctx| {
.scoped(handler, Some(code_block.span()), |mut ctx| {
code_block.contents.iter().for_each(|node| {
ty::TyAstNode::type_check(&Handler::default(), ctx.by_ref(), node).ok();
});
Expand All @@ -66,18 +72,19 @@ impl ty::TyCodeBlock {

ctx.engines.te().reapply_unifications(ctx.engines());

ctx.by_ref().scoped(|mut ctx| {
let evaluated_contents = code_block
.contents
.iter()
.filter_map(|node| ty::TyAstNode::type_check(handler, ctx.by_ref(), node).ok())
.collect::<Vec<ty::TyAstNode>>();
ctx.by_ref()
.scoped(handler, Some(code_block.span()), |mut ctx| {
let evaluated_contents = code_block
.contents
.iter()
.filter_map(|node| ty::TyAstNode::type_check(handler, ctx.by_ref(), node).ok())
.collect::<Vec<ty::TyAstNode>>();

Ok(ty::TyCodeBlock {
contents: evaluated_contents,
whole_block_span: code_block.whole_block_span.clone(),
Ok(ty::TyCodeBlock {
contents: evaluated_contents,
whole_block_span: code_block.whole_block_span.clone(),
})
})
})
}

pub fn compute_return_type_and_span(
Expand Down
42 changes: 36 additions & 6 deletions sway-core/src/semantic_analysis/ast_node/declaration/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ use sway_error::error::CompileError;
use sway_types::{Ident, Named, Span, Spanned};

use crate::{
decl_engine::{DeclEngineGetParsedDeclId, DeclEngineInsert, DeclEngineInsertArc, DeclId},
language::ty::TyAbiDecl,
decl_engine::{
parsed_id::ParsedDeclId, DeclEngineGetParsedDeclId, DeclEngineInsert, DeclEngineInsertArc,
DeclId,
},
language::ty::{TyAbiDecl, TyFunctionDecl},
namespace::{IsExtendingExistingImpl, IsImplSelf, TryInsertingTraitImplOnFailure},
semantic_analysis::{
TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckFinalization,
TypeCheckFinalizationContext,
symbol_collection_context::SymbolCollectionContext, TypeCheckAnalysis,
TypeCheckAnalysisContext, TypeCheckFinalization, TypeCheckFinalizationContext,
},
TypeParameter,
Engines, TypeParameter,
};
use sway_error::handler::{ErrorEmitted, Handler};

Expand All @@ -29,6 +32,33 @@ use crate::{
};

impl ty::TyAbiDecl {
pub(crate) fn collect(
handler: &Handler,
engines: &Engines,
ctx: &mut SymbolCollectionContext,
decl_id: &ParsedDeclId<AbiDeclaration>,
) -> Result<(), ErrorEmitted> {
let abi_decl = engines.pe().get_abi(decl_id);
ctx.insert_parsed_symbol(
handler,
engines,
abi_decl.name.clone(),
Declaration::AbiDeclaration(*decl_id),
)?;

let _ = ctx.scoped(engines, abi_decl.span.clone(), |scoped_ctx| {
abi_decl.interface_surface.iter().for_each(|item| {
let _ = TyTraitItem::collect(handler, engines, scoped_ctx, item);
});

abi_decl.methods.iter().for_each(|decl_id| {
let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, decl_id);
});
Ok(())
});
Ok(())
}

pub(crate) fn type_check(
handler: &Handler,
ctx: TypeCheckContext,
Expand All @@ -55,7 +85,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(|mut ctx| {
.scoped(handler, Some(span.clone()), |mut ctx| {
// Insert the "self" type param into the namespace.
self_type_param.insert_self_type_into_namespace(handler, ctx.by_ref());

Expand Down
25 changes: 23 additions & 2 deletions sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,18 @@ where
assert!(!handler.has_warnings(), "{:?}", handler);

let ctx = self.ctx.by_ref();
let r = ctx.scoped_and_namespace(|ctx| {
let _r = TyDecl::collect(
&handler,
engines,
ctx.collection_ctx,
Declaration::FunctionDeclaration(decl),
);
if handler.has_errors() {
return Err(handler);
}

let ctx = self.ctx.by_ref();
let r = ctx.scoped_and_namespace(&handler, None, |ctx| {
TyDecl::type_check(
&handler,
ctx,
Expand Down Expand Up @@ -375,7 +386,17 @@ where
assert!(!handler.has_errors(), "{:?}", handler);

let ctx = self.ctx.by_ref();
let r = ctx.scoped_and_namespace(|ctx| {
let _r = TyDecl::collect(
&handler,
engines,
ctx.collection_ctx,
Declaration::ImplSelfOrTrait(decl),
);
if handler.has_errors() {
return Err(handler);
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,42 @@ use sway_error::{
warning::{CompileWarning, Warning},
};
use sway_types::{style::is_screaming_snake_case, Spanned};
use symbol_collection_context::SymbolCollectionContext;

use crate::{
decl_engine::{DeclEngineGetParsedDeclId, DeclEngineInsert, ReplaceDecls},
decl_engine::{
parsed_id::ParsedDeclId, DeclEngineGetParsedDeclId, DeclEngineInsert, ReplaceDecls,
},
language::{
parsed::*,
ty::{self, TyConfigurableDecl},
ty::{self, TyConfigurableDecl, TyExpression},
CallPath,
},
semantic_analysis::{type_check_context::EnforceTypeArguments, *},
SubstTypes, SubstTypesContext, TypeArgument, TypeBinding, TypeCheckTypeBinding, TypeInfo,
Engines, SubstTypes, SubstTypesContext, TypeArgument, TypeBinding, TypeCheckTypeBinding,
TypeInfo,
};

impl ty::TyConfigurableDecl {
pub(crate) fn collect(
handler: &Handler,
engines: &Engines,
ctx: &mut SymbolCollectionContext,
decl_id: &ParsedDeclId<ConfigurableDeclaration>,
) -> Result<(), ErrorEmitted> {
let configurable_decl = engines.pe().get_configurable(decl_id);
ctx.insert_parsed_symbol(
handler,
engines,
configurable_decl.name.clone(),
Declaration::ConfigurableDeclaration(*decl_id),
)?;
if let Some(value) = &configurable_decl.value {
TyExpression::collect(handler, engines, ctx, value)?;
}
Ok(())
}

pub fn type_check(
handler: &Handler,
mut ctx: TypeCheckContext,
Expand Down
23 changes: 22 additions & 1 deletion sway-core/src/semantic_analysis/ast_node/declaration/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,39 @@ use sway_error::{
warning::{CompileWarning, Warning},
};
use sway_types::{style::is_screaming_snake_case, Spanned};
use symbol_collection_context::SymbolCollectionContext;

use crate::{
decl_engine::parsed_id::ParsedDeclId,
language::{
parsed::{self, *},
ty::{self, TyConstantDecl},
ty::{self, TyConstantDecl, TyExpression},
CallPath,
},
semantic_analysis::{type_check_context::EnforceTypeArguments, *},
Engines, SubstTypes, SubstTypesContext, TypeInfo,
};

impl ty::TyConstantDecl {
pub(crate) fn collect(
handler: &Handler,
engines: &Engines,
ctx: &mut SymbolCollectionContext,
decl_id: &ParsedDeclId<ConstantDeclaration>,
) -> Result<(), ErrorEmitted> {
let constant_decl = engines.pe().get_constant(decl_id);
ctx.insert_parsed_symbol(
handler,
engines,
constant_decl.name.clone(),
Declaration::ConstantDeclaration(*decl_id),
)?;
if let Some(value) = &constant_decl.value {
TyExpression::collect(handler, engines, ctx, value)?;
}
Ok(())
}

pub fn type_check(
handler: &Handler,
mut ctx: TypeCheckContext,
Expand Down
Loading

0 comments on commit d178613

Please sign in to comment.