Skip to content

Commit 44a16af

Browse files
Introduce a type check Context. Replaces TypeCheckArguments. (#2004)
* Introduce a type check `Context`. Replaces `TypeCheckArguments`. * Add missing unknown type annotation. Clean up some formatting. Also adds some resetting of the help text and type annotation (to unknown) in many cases to better match the original behaviour. It's difficult to tell which locations these values were originally used as placeholders, and which locations they're a necessity for correctness. This at least appears to fix an issue with expression return type inference. * Rename semantic_analysis::Context to TypeCheckContext * Improve field doc comments for help_text, self_type * Add doc comment to mode field in TypeCheckContext * Construct TypeCheckContext at Program level, not module level. This should help to clarify how we can pass other type check context (like the declaration and type engines once they're added) through to the submodules. Previously, this was a little unclear as the `TypeCheckContext` was only constructed at the module level. * Add missing namespace field doc comment to TypeCheckContext * Fix TypeCheckContext constructor in IR test
1 parent 755ff6a commit 44a16af

File tree

25 files changed

+903
-1188
lines changed

25 files changed

+903
-1188
lines changed

sway-core/src/ir_generation/compile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
error::CompileError,
33
parse_tree::{Purity, Visibility},
4-
semantic_analysis::{ast_node::*, *},
4+
semantic_analysis::{ast_node::*, namespace},
55
};
66

77
use super::{

sway-core/src/ir_generation/function.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
use super::{compile::compile_function, convert::*, lexical_map::LexicalMap, types::*};
1111

1212
use fuel_crypto::Hasher;
13-
use sway_ir::*;
13+
use sway_ir::{Context, *};
1414
use sway_types::{
1515
ident::Ident,
1616
span::{Span, Spanned},

sway-core/src/parse_tree/declaration/type_parameter.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ impl fmt::Display for TypeParameter {
6868

6969
impl TypeParameter {
7070
pub(crate) fn type_check(
71+
ctx: TypeCheckContext,
7172
type_parameter: TypeParameter,
72-
namespace: &mut Namespace,
73-
) -> CompileResult<TypeParameter> {
73+
) -> CompileResult<Self> {
7474
let mut warnings = vec![];
7575
let mut errors = vec![];
7676
if !type_parameter.trait_constraints.is_empty() {
@@ -87,7 +87,7 @@ impl TypeParameter {
8787
name: type_parameter.name_ident.clone(),
8888
type_id,
8989
};
90-
namespace
90+
ctx.namespace
9191
.insert_symbol(type_parameter.name_ident.clone(), type_parameter_decl)
9292
.ok(&mut warnings, &mut errors);
9393
let type_parameter = TypeParameter {

sway-core/src/semantic_analysis.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ mod module;
44
pub mod namespace;
55
mod node_dependencies;
66
mod program;
7-
pub(crate) mod type_check_arguments;
7+
mod type_check_context;
88
pub(crate) use ast_node::*;
99
pub use ast_node::{TypedConstantDeclaration, TypedDeclaration, TypedFunctionDeclaration};
1010
pub use module::{TypedModule, TypedSubmodule};
1111
pub use namespace::Namespace;
1212
pub use program::{TypedProgram, TypedProgramKind};
13-
pub use type_check_arguments::*;
13+
pub(crate) use type_check_context::TypeCheckContext;
Lines changed: 14 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use super::*;
2-
use crate::semantic_analysis::{ast_node::Mode, TypeCheckArguments};
32
use crate::CodeBlock;
43

54
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -23,41 +22,24 @@ impl DeterministicallyAborts for TypedCodeBlock {
2322

2423
impl TypedCodeBlock {
2524
pub(crate) fn type_check(
26-
arguments: TypeCheckArguments<'_, CodeBlock>,
25+
mut ctx: TypeCheckContext,
26+
code_block: CodeBlock,
2727
) -> CompileResult<(Self, TypeId)> {
2828
let mut warnings = Vec::new();
2929
let mut errors = Vec::new();
3030

31-
let TypeCheckArguments {
32-
checkee: other,
33-
namespace,
34-
return_type_annotation: type_annotation,
35-
help_text,
36-
self_type,
37-
opts,
38-
..
39-
} = arguments;
40-
4131
// Create a temp namespace for checking within the code block scope.
42-
let mut code_block_namespace = namespace.clone();
43-
let evaluated_contents = other
32+
let mut code_block_namespace = ctx.namespace.clone();
33+
let evaluated_contents = code_block
4434
.contents
4535
.iter()
4636
.filter_map(|node| {
47-
TypedAstNode::type_check(TypeCheckArguments {
48-
checkee: node.clone(),
49-
namespace: &mut code_block_namespace,
50-
return_type_annotation: type_annotation,
51-
help_text,
52-
self_type,
53-
mode: Mode::NonAbi,
54-
opts,
55-
})
56-
.ok(&mut warnings, &mut errors)
37+
let ctx = ctx.by_ref().scoped(&mut code_block_namespace);
38+
TypedAstNode::type_check(ctx, node.clone()).ok(&mut warnings, &mut errors)
5739
})
5840
.collect::<Vec<TypedAstNode>>();
5941

60-
let implicit_return_span = other
42+
let implicit_return_span = code_block
6143
.contents
6244
.iter()
6345
.find_map(|x| match &x.content {
@@ -81,27 +63,17 @@ impl TypedCodeBlock {
8163
});
8264

8365
if let Some(return_type) = return_type {
84-
let (mut new_warnings, new_errors) = unify_with_self(
85-
return_type,
86-
type_annotation,
87-
self_type,
88-
&implicit_return_span.unwrap_or_else(|| other.whole_block_span.clone()),
89-
help_text,
90-
);
66+
let span = implicit_return_span.unwrap_or_else(|| code_block.whole_block_span.clone());
67+
let (mut new_warnings, new_errors) = ctx.unify_with_self(return_type, &span);
9168
warnings.append(&mut new_warnings);
9269
errors.append(&mut new_errors.into_iter().map(|x| x.into()).collect());
9370
// The annotation will result in a cast, so set the return type accordingly.
9471
}
9572

96-
ok(
97-
(
98-
TypedCodeBlock {
99-
contents: evaluated_contents,
100-
},
101-
return_type.unwrap_or_else(|| insert_type(TypeInfo::Tuple(Vec::new()))),
102-
),
103-
warnings,
104-
errors,
105-
)
73+
let typed_code_block = TypedCodeBlock {
74+
contents: evaluated_contents,
75+
};
76+
let type_id = return_type.unwrap_or_else(|| insert_type(TypeInfo::Tuple(Vec::new())));
77+
ok((typed_code_block, type_id), warnings, errors)
10678
}
10779
}

sway-core/src/semantic_analysis/ast_node/declaration/abi.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ use sway_types::{Ident, Span};
33

44
use crate::{
55
error::{err, ok},
6-
semantic_analysis::ast_node::{type_check_interface_surface, type_check_trait_methods},
6+
semantic_analysis::{
7+
ast_node::{type_check_interface_surface, type_check_trait_methods},
8+
TypeCheckContext,
9+
},
710
type_engine::{insert_type, AbiName, TypeId},
8-
AbiDeclaration, CompileResult, FunctionDeclaration, Namespace, TypeInfo,
11+
AbiDeclaration, CompileResult, FunctionDeclaration, TypeInfo,
912
};
1013

1114
use super::{CreateTypeId, TypedTraitFn};
@@ -40,10 +43,9 @@ impl CreateTypeId for TypedAbiDeclaration {
4043

4144
impl TypedAbiDeclaration {
4245
pub(crate) fn type_check(
46+
ctx: TypeCheckContext,
4347
abi_decl: AbiDeclaration,
44-
namespace: &mut Namespace,
45-
self_type: TypeId,
46-
) -> CompileResult<TypedAbiDeclaration> {
48+
) -> CompileResult<Self> {
4749
let mut warnings = vec![];
4850
let mut errors = vec![];
4951

@@ -60,15 +62,15 @@ impl TypedAbiDeclaration {
6062
// so we don't support the case of calling a contract's own interface
6163
// from itself. This is by design.
6264
let interface_surface = check!(
63-
type_check_interface_surface(interface_surface, namespace),
65+
type_check_interface_surface(interface_surface, ctx.namespace),
6466
return err(warnings, errors),
6567
warnings,
6668
errors
6769
);
6870
// type check these for errors but don't actually use them yet -- the real
6971
// ones will be type checked with proper symbols when the ABI is implemented
7072
let _methods = check!(
71-
type_check_trait_methods(methods.clone(), namespace, self_type,),
73+
type_check_trait_methods(ctx, methods.clone()),
7274
vec![],
7375
warnings,
7476
errors

sway-core/src/semantic_analysis/ast_node/declaration/enum.rs

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,7 @@ impl MonomorphizeHelper for TypedEnumDeclaration {
7878
}
7979

8080
impl TypedEnumDeclaration {
81-
pub fn type_check(
82-
decl: EnumDeclaration,
83-
namespace: &mut Namespace,
84-
self_type: TypeId,
85-
) -> CompileResult<TypedEnumDeclaration> {
81+
pub fn type_check(ctx: TypeCheckContext, decl: EnumDeclaration) -> CompileResult<Self> {
8682
let mut errors = vec![];
8783
let mut warnings = vec![];
8884

@@ -95,14 +91,15 @@ impl TypedEnumDeclaration {
9591
} = decl;
9692

9793
// create a namespace for the decl, used to create a scope for generics
98-
let mut namespace = namespace.clone();
94+
let mut decl_namespace = ctx.namespace.clone();
95+
let mut ctx = ctx.scoped(&mut decl_namespace);
9996

10097
// type check the type parameters
10198
// insert them into the namespace
10299
let mut new_type_parameters = vec![];
103100
for type_parameter in type_parameters.into_iter() {
104101
new_type_parameters.push(check!(
105-
TypeParameter::type_check(type_parameter, &mut namespace),
102+
TypeParameter::type_check(ctx.by_ref(), type_parameter),
106103
return err(warnings, errors),
107104
warnings,
108105
errors
@@ -113,12 +110,7 @@ impl TypedEnumDeclaration {
113110
let mut variants_buf = vec![];
114111
for variant in variants {
115112
variants_buf.push(check!(
116-
TypedEnumVariant::type_check(
117-
variant.clone(),
118-
&mut namespace,
119-
self_type,
120-
variant.span,
121-
),
113+
TypedEnumVariant::type_check(ctx.by_ref(), variant.clone()),
122114
continue,
123115
warnings,
124116
errors
@@ -216,18 +208,15 @@ impl ReplaceSelfType for TypedEnumVariant {
216208

217209
impl TypedEnumVariant {
218210
pub(crate) fn type_check(
211+
mut ctx: TypeCheckContext,
219212
variant: EnumVariant,
220-
namespace: &mut Namespace,
221-
self_type: TypeId,
222-
span: Span,
223-
) -> CompileResult<TypedEnumVariant> {
213+
) -> CompileResult<Self> {
224214
let mut warnings = vec![];
225215
let mut errors = vec![];
226216
let enum_variant_type = check!(
227-
namespace.resolve_type_with_self(
217+
ctx.resolve_type_with_self(
228218
insert_type(variant.type_info),
229-
self_type,
230-
&span,
219+
&variant.span,
231220
EnforceTypeArguments::Yes
232221
),
233222
insert_type(TypeInfo::ErrorRecovery),

sway-core/src/semantic_analysis/ast_node/declaration/function.rs

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -121,19 +121,10 @@ impl ToJsonAbi for TypedFunctionDeclaration {
121121
}
122122

123123
impl TypedFunctionDeclaration {
124-
pub fn type_check(
125-
arguments: TypeCheckArguments<'_, FunctionDeclaration>,
126-
) -> CompileResult<TypedFunctionDeclaration> {
124+
pub fn type_check(ctx: TypeCheckContext, fn_decl: FunctionDeclaration) -> CompileResult<Self> {
127125
let mut warnings = Vec::new();
128126
let mut errors = Vec::new();
129-
let TypeCheckArguments {
130-
checkee: fn_decl,
131-
namespace,
132-
self_type,
133-
mode,
134-
mut opts,
135-
..
136-
} = arguments;
127+
137128
let FunctionDeclaration {
138129
name,
139130
body,
@@ -147,17 +138,18 @@ impl TypedFunctionDeclaration {
147138
..
148139
} = fn_decl;
149140
is_snake_case(&name).ok(&mut warnings, &mut errors);
150-
opts.purity = purity;
151141

152142
// create a namespace for the function
153-
let mut namespace = namespace.clone();
143+
let mut fn_namespace = ctx.namespace.clone();
144+
145+
let mut ctx = ctx.scoped(&mut fn_namespace).with_purity(purity);
154146

155147
// type check the type parameters
156148
// insert them into the namespace
157149
let mut new_type_parameters = vec![];
158150
for type_parameter in type_parameters.into_iter() {
159151
new_type_parameters.push(check!(
160-
TypeParameter::type_check(type_parameter, &mut namespace),
152+
TypeParameter::type_check(ctx.by_ref(), type_parameter),
161153
return err(warnings, errors),
162154
warnings,
163155
errors
@@ -169,7 +161,7 @@ impl TypedFunctionDeclaration {
169161
let mut new_parameters = vec![];
170162
for parameter in parameters.into_iter() {
171163
new_parameters.push(check!(
172-
TypedFunctionParameter::type_check(parameter, &mut namespace, self_type),
164+
TypedFunctionParameter::type_check(ctx.by_ref(), parameter),
173165
continue,
174166
warnings,
175167
errors
@@ -178,9 +170,8 @@ impl TypedFunctionDeclaration {
178170

179171
// type check the return type
180172
let return_type = check!(
181-
namespace.resolve_type_with_self(
173+
ctx.resolve_type_with_self(
182174
insert_type(return_type),
183-
self_type,
184175
&return_type_span,
185176
EnforceTypeArguments::Yes
186177
),
@@ -193,24 +184,21 @@ impl TypedFunctionDeclaration {
193184
//
194185
// If there are no implicit block returns, then we do not want to type check them, so we
195186
// stifle the errors. If there _are_ implicit block returns, we want to type_check them.
196-
let (body, _implicit_block_return) = check!(
197-
TypedCodeBlock::type_check(TypeCheckArguments {
198-
checkee: body,
199-
namespace: &mut namespace,
200-
return_type_annotation: return_type,
201-
help_text:
202-
"Function body's return type does not match up with its return type annotation.",
203-
self_type,
204-
mode: Mode::NonAbi,
205-
opts,
206-
}),
207-
(
208-
TypedCodeBlock { contents: vec![] },
209-
insert_type(TypeInfo::ErrorRecovery)
210-
),
211-
warnings,
212-
errors
213-
);
187+
let (body, _implicit_block_return) = {
188+
let ctx = ctx
189+
.by_ref()
190+
.with_help_text("Function body's return type does not match up with its return type annotation.")
191+
.with_type_annotation(return_type);
192+
check!(
193+
TypedCodeBlock::type_check(ctx, body),
194+
(
195+
TypedCodeBlock { contents: vec![] },
196+
insert_type(TypeInfo::ErrorRecovery)
197+
),
198+
warnings,
199+
errors
200+
)
201+
};
214202

215203
// gather the return statements
216204
let return_statements: Vec<&TypedExpression> = body
@@ -222,13 +210,11 @@ impl TypedFunctionDeclaration {
222210

223211
// unify the types of the return statements with the function return type
224212
for stmt in return_statements {
225-
let (mut new_warnings, new_errors) = unify_with_self(
226-
stmt.return_type,
227-
return_type,
228-
self_type,
229-
&stmt.span,
230-
"Return statement must return the declared function return type.",
231-
);
213+
let (mut new_warnings, new_errors) = ctx
214+
.by_ref()
215+
.with_type_annotation(return_type)
216+
.with_help_text("Return statement must return the declared function return type.")
217+
.unify_with_self(stmt.return_type, &stmt.span);
232218
warnings.append(&mut new_warnings);
233219
errors.append(&mut new_errors.into_iter().map(|x| x.into()).collect());
234220
}
@@ -243,7 +229,7 @@ impl TypedFunctionDeclaration {
243229
return_type_span,
244230
visibility,
245231
// if this is for a contract, then it is a contract call
246-
is_contract_call: mode == Mode::ImplAbiFn,
232+
is_contract_call: ctx.mode() == Mode::ImplAbiFn,
247233
purity,
248234
};
249235

0 commit comments

Comments
 (0)