Skip to content

Commit 6e99f12

Browse files
const initialization: a few fixes (#2158)
* const initialization: a few fixes * cargo fmt * Address review comments * Add IR test Co-authored-by: Mohammad Fawaz <[email protected]>
1 parent 1dad396 commit 6e99f12

File tree

10 files changed

+118
-45
lines changed

10 files changed

+118
-45
lines changed

sway-core/src/ir_generation/function.rs

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
asm_generation::from_ir::ir_type_size_in_bytes,
1010
constants,
1111
error::CompileError,
12+
ir_generation::const_eval::compile_constant_expression,
1213
parse_tree::{AsmOp, AsmRegister, LazyOp, Literal, Purity, Visibility},
1314
semantic_analysis::*,
1415
type_engine::{insert_type, resolve_type, TypeId, TypeInfo},
@@ -997,29 +998,33 @@ impl FnCompiler {
997998
// This is local to the function, so we add it to the locals, rather than the module
998999
// globals like other const decls.
9991000
let TypedConstantDeclaration { name, value, .. } = ast_const_decl;
1001+
let const_expr_val = compile_constant_expression(context, self.module, &value)?;
1002+
let local_name = self.lexical_map.insert(name.as_str().to_owned());
1003+
let return_type = convert_resolved_typeid(context, &value.return_type, &value.span)?;
10001004

1001-
if let TypedExpressionVariant::Literal(literal) = &value.expression {
1002-
let initialiser = convert_literal_to_constant(literal);
1003-
let return_type = convert_resolved_typeid(context, &value.return_type, &value.span)?;
1004-
let name = name.as_str().to_owned();
1005-
self.function
1006-
.new_local_ptr(context, name.clone(), return_type, false, Some(initialiser))
1007-
.map_err(|ir_error| {
1008-
CompileError::InternalOwned(ir_error.to_string(), Span::dummy())
1009-
})?;
1010-
1011-
// We still insert this into the symbol table, as itself... can they be shadowed?
1012-
// (Hrmm, name resolution in the variable expression code could be smarter about var
1013-
// decls vs const decls, for now they're essentially the same...)
1014-
self.lexical_map.insert(name);
1005+
// We compile consts the same as vars are compiled. This is because ASM generation
1006+
// cannot handle
1007+
// 1. initializing aggregates
1008+
// 2. get_ptr()
1009+
// into the data section.
1010+
let ptr = self
1011+
.function
1012+
.new_local_ptr(context, local_name, return_type, false, None)
1013+
.map_err(|ir_error| CompileError::InternalOwned(ir_error.to_string(), Span::dummy()))?;
10151014

1016-
Ok(Constant::get_unit(context, span_md_idx))
1017-
} else {
1018-
Err(CompileError::Internal(
1019-
"Unsupported constant declaration type, expecting a literal.",
1020-
name.span(),
1021-
))
1015+
// We can have empty aggregates, especially arrays, which shouldn't be initialised, but
1016+
// otherwise use a store.
1017+
let ptr_ty = *ptr.get_type(context);
1018+
if ir_type_size_in_bytes(context, &ptr_ty) > 0 {
1019+
let ptr_val = self
1020+
.current_block
1021+
.ins(context)
1022+
.get_ptr(ptr, ptr_ty, 0, span_md_idx);
1023+
self.current_block
1024+
.ins(context)
1025+
.store(ptr_val, const_expr_val, span_md_idx);
10221026
}
1027+
Ok(const_expr_val)
10231028
}
10241029

10251030
fn compile_reassignment(

sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,21 @@ pub(crate) fn type_check_method_application(
193193
warnings,
194194
errors
195195
);
196-
let variable_decl = check!(
197-
unknown_decl.expect_variable().cloned(),
198-
return err(warnings, errors),
199-
warnings,
200-
errors
201-
);
202196

203-
if !variable_decl.is_mutable.is_mutable() && *is_mutable {
197+
let is_decl_mutable = match unknown_decl {
198+
TypedDeclaration::ConstantDeclaration(_) => false,
199+
_ => {
200+
let variable_decl = check!(
201+
unknown_decl.expect_variable().cloned(),
202+
return err(warnings, errors),
203+
warnings,
204+
errors
205+
);
206+
variable_decl.is_mutable.is_mutable()
207+
}
208+
};
209+
210+
if !is_decl_mutable && *is_mutable {
204211
errors.push(CompileError::MethodRequiresMutableSelf {
205212
method_name: method_name.easy_name(),
206213
variable_name: name.clone(),

sway-core/src/semantic_analysis/ast_node/mod.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -303,25 +303,16 @@ impl TypedAstNode {
303303
value,
304304
visibility,
305305
}) => {
306-
let result = type_check_ascribed_expr(
307-
ctx.by_ref(),
308-
type_ascription.clone(),
309-
value,
310-
);
306+
let result =
307+
type_check_ascribed_expr(ctx.by_ref(), type_ascription, value);
311308
is_screaming_snake_case(&name).ok(&mut warnings, &mut errors);
312309
let value =
313310
check!(result, error_recovery_expr(name.span()), warnings, errors);
314311
let typed_const_decl =
315-
TypedDeclaration::VariableDeclaration(TypedVariableDeclaration {
312+
TypedDeclaration::ConstantDeclaration(TypedConstantDeclaration {
316313
name: name.clone(),
317-
body: value,
318-
is_mutable: if visibility.is_public() {
319-
VariableMutability::ExportedConst
320-
} else {
321-
VariableMutability::Immutable
322-
},
323-
const_decl_origin: true,
324-
type_ascription: insert_type(type_ascription),
314+
value,
315+
visibility,
325316
});
326317
ctx.namespace.insert_symbol(name, typed_const_decl.clone());
327318
typed_const_decl
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
script {
2+
fn main() -> u64, !1 {
3+
local ptr { u64 } X
4+
5+
entry:
6+
v0 = get_ptr ptr { u64 } X, ptr { u64 }, 0, !2
7+
v1 = const { u64 } { u64 1 }, !3
8+
store v1, ptr v0, !2
9+
v2 = get_ptr ptr { u64 } X, ptr { u64 }, 0, !4
10+
v3 = extract_value v2, { u64 }, 0, !5
11+
ret u64 v3
12+
}
13+
}
14+
15+
!0 = filepath "/path/to/local_const_init.sw"
16+
!1 = span !0 70 114
17+
!2 = span !0 91 106
18+
!3 = span !0 33 68
19+
!4 = span !0 109 110
20+
!5 = span !0 22 29
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
script;
2+
3+
struct S {
4+
s : u64
5+
}
6+
7+
fn s(x : u64) -> S {
8+
S { s: x }
9+
}
10+
11+
fn main() -> u64 {
12+
const X = s(1);
13+
X.s
14+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[[package]]
2+
name = 'const_nonconst_init'
3+
source = 'root'
4+
dependencies = ['core']
5+
6+
[[package]]
7+
name = 'core'
8+
source = 'path+from-root-E57A3612ABF8CF11'
9+
dependencies = []
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[project]
2+
authors = ["Fuel Labs <[email protected]>"]
3+
entry = "main.sw"
4+
license = "Apache-2.0"
5+
name = "const_nonconst_init"
6+
7+
[dependencies]
8+
core = { path = "../../../../../../sway-lib-core" }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
script;
2+
3+
fn bla(x: u64) -> u64 {
4+
x + 1
5+
}
6+
7+
fn main() -> u64 {
8+
const X = bla(0);
9+
X
10+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
category = "fail"
2+
3+
# check: $()const X = bla(0);
4+
# nextln: $()Could not evaluate initializer to a const declaration.

test/src/e2e_vm_tests/test_programs/should_pass/language/const_inits/src/main.sw

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,22 @@ const EN1c = En1::NoVal;
3636
const ETH_ID0_VALUE = ETH_ID0.value;
3737
const TUP1_idx2 = TUP1.2;
3838

39+
const INT1 = 1;
40+
3941
fn main() -> u64 {
42+
const int1 = 1;
43+
assert(int1 == INT1);
44+
4045
// initialization through function applications.
41-
let eth_id0 = ~ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000000);
42-
let eth_id1 = ~ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000001);
46+
const eth_id0 = ~ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000000);
47+
const eth_id1 = ~ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000001);
4348
assert(eth_id0 == ETH_ID0 && eth_id1 == ETH_ID1);
4449

4550
// tuples and arrays.
46-
let t1 = (2, 1, 21);
51+
const t1 = (2, 1, 21);
4752
assert(t1.0 == TUP1.0 && t1.1 == TUP1.1 && t1.2 == TUP1.2);
4853
assert(t1.0 == TUP2.0 && t1.1 == TUP2.1 && t1.2 == TUP2.2);
49-
let a1 = [1, 2, 3];
54+
const a1 = [1, 2, 3];
5055
assert(a1[0] == ARR1[0] && a1[1] == ARR1[1] && a1[2] == ARR1[2]);
5156
assert(a1[0] == ARR2[0] && a1[1] == ARR2[1] && a1[2] == ARR2[2]);
5257

0 commit comments

Comments
 (0)