Skip to content

Enforce type annotations for constants #7054

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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion docs/book/src/basics/constants.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

<!-- This section should explain what constants are in Sway -->
<!-- constants:example:start -->

Constants are similar to variables; however, there are a few differences:

- Constants are always evaluated at compile-time.
- Constants can be declared both inside of a [function](../index.md) and at global / `impl` scope.
- The `mut` keyword cannot be used with constants.
- Constants must contain a [type annotation](./variables.md#type-annotations).
<!-- constants:example:end -->

```sway
Expand All @@ -31,19 +33,21 @@ fn arr_wrapper(a: u64, b: u64, c: u64) -> [u64; 3] {
[a, b, c]
}

const ARR2 = arr_wrapper(bool_to_num(1) + 42, 2, 3);
const ARR2: [u64; 3] = arr_wrapper(bool_to_num(1) + 42, 2, 3);
```

## Associated Constants

<!-- This section should explain what associated constants are -->
<!-- assoc_constants:example:start -->

Associated constants are constants associated with a type and can be declared in an `impl` block or in a `trait` definition.

Associated constants declared inside a `trait` definition may omit their initializers to indicate that each implementation of the trait must specify those initializers.

The identifier is the name of the constant used in the path. The type is the type that the
definition has to implement.

<!-- assoc_constants:example:end -->

You can _define_ an associated `const` directly in the interface surface of a trait:
Expand Down Expand Up @@ -102,7 +106,9 @@ fn main() -> u64 {

<!-- This section should explain what configurable constants are in Sway -->
<!-- config_constants:example:start -->

Configurable constants are special constants that behave like regular constants in the sense that they cannot change during program execution, but they can be configured _after_ the Sway program has been built. The Rust and TS SDKs allow updating the values of these constants by injecting new values for them directly in the bytecode without having to build the program again. These are useful for contract factories and behave somewhat similarly to `immutable` variables from languages like Solidity.

<!-- config_constants:example:end -->

Configurable constants are declared inside a `configurable` block and require a type ascription and an initializer as follows:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ abi ContractB {
fn make_call();
}

const contract_id = 0x79fa8779bed2f36c3581d01c79df8da45eee09fac1fd76a5a656e16326317ef0;
const contract_id: b256 = 0x79fa8779bed2f36c3581d01c79df8da45eee09fac1fd76a5a656e16326317ef0;

impl ContractB for Contract {
fn make_call() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ storage {
balance: u64 = 0,
}

const OWNER = Address::from(0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861);
const OWNER: Address = Address::from(0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861);

impl Wallet for Contract {
#[storage(read, write)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ library;
struct S {}

impl S {
const ID = 0;
const ID: u64 = 0;
}

// ANCHOR: id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ library;
fn foo() {}

// Can import everything below because they are using the `pub` keyword
pub const ONE = __to_str_array("1");
pub const ONE: str[1] = __to_str_array("1");

pub struct MyStruct {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
library;
// ANCHOR_END: module
// ANCHOR: const
const MAXIMUM_DEPOSIT = 10;
const MAXIMUM_DEPOSIT: u64 = 10;
// ANCHOR_END: const
// ANCHOR: structures
struct MultiSignatureWallet {
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/src/code/language/variables/src/lib.sw
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ fn shadowing() {

fn constants() {
// ANCHOR: constants
const FOO = 5;
const FOO: u64 = 5;
// ANCHOR_END: constants
}
2 changes: 1 addition & 1 deletion docs/reference/src/code/operations/call_data/src/lib.sw
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::context::msg_amount;
// ANCHOR_END: import_amount

// ANCHOR: access_control
const OWNER = Identity::Address(Address::from(0x0000000000000000000000000000000000000000000000000000000000000000));
const OWNER: Identity = Identity::Address(Address::from(0x0000000000000000000000000000000000000000000000000000000000000000));

fn update() {
require(msg_sender().unwrap() == OWNER, "Owner Only");
Expand Down
2 changes: 1 addition & 1 deletion examples/hashing/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl Hash for Person {
}
}

const VALUE_A = 0x9280359a3b96819889d30614068715d634ad0cf9bba70c0f430a8c201138f79f;
const VALUE_A: b256 = 0x9280359a3b96819889d30614068715d634ad0cf9bba70c0f430a8c201138f79f;

enum Location {
Earth: (),
Expand Down
2 changes: 1 addition & 1 deletion examples/msg_sender/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ abi MyOwnedContract {
fn receive(field_1: u64) -> bool;
}

const OWNER = Address::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c);
const OWNER: Address = Address::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c);

impl MyOwnedContract for Contract {
fn receive(field_1: u64) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion examples/wallet_smart_contract/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{asset::transfer, call_frames::msg_asset_id, context::msg_amount};
// ANCHOR: abi_import
use wallet_abi::Wallet;
// ANCHOR_END: abi_import
const OWNER_ADDRESS = Address::from(0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861);
const OWNER_ADDRESS: Address = Address::from(0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861);

storage {
balance: u64 = 0,
Expand Down
4 changes: 2 additions & 2 deletions sway-core/src/ir_generation/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1871,13 +1871,13 @@ mod tests {
// Code blocks that can be converted to constants
assert_is_constant(true, "", "{ 1 }");
assert_is_constant(true, "", "{ let a = 1; a }");
assert_is_constant(true, "", "{ const a = 1; a }");
assert_is_constant(true, "", "{ const a: u64 = 1; a }");
assert_is_constant(true, "", "{ struct A {} 1 }");
assert_is_constant(true, "fn id(x: u64) -> u64 { { let x = 2; }; x }", "id(1)");

// Code blocks that cannot be converted to constants
assert_is_constant(false, "", "{ let a = 1; }");
assert_is_constant(false, "", "{ const a = 1; }");
assert_is_constant(false, "", "{ const a: u64 = 1; }");
assert_is_constant(false, "", "{ struct A {} }");
assert_is_constant(false, "", "{ return 1; 1 }");
assert_is_constant(false, "", "{ }");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ use sway_ast::{
PathTypeSegment, Pattern, PatternStructField, PubToken, Punctuated, QualifiedPathRoot,
Statement, StatementLet, Submodule, TraitType, Traits, Ty, TypeField, UseTree, WhereClause,
};
use sway_error::handler::{ErrorEmitted, Handler};
use sway_error::{convert_parse_tree_error::ConvertParseTreeError, error::CompileError};
use sway_error::{
handler::{ErrorEmitted, Handler},
warning::{CompileWarning, Warning},
};
use sway_features::ExperimentalFeatures;
use sway_types::{integer_bits::IntegerBits, BaseIdent};
use sway_types::{Ident, Span, Spanned};
Expand Down Expand Up @@ -1033,6 +1036,10 @@ pub(crate) fn item_const_to_constant_declaration(
let type_ascription = match item_const.ty_opt {
Some((_colon_token, ty)) => ty_to_type_argument(context, handler, engines, ty)?,
None => {
handler.emit_warn(CompileWarning {
span: span.clone(),
warning_content: Warning::ExpectedTypeAnnotationForConstants,
});
if expr.is_none() {
let err =
ConvertParseTreeError::ConstantRequiresTypeAscription { span: span.clone() };
Expand Down
5 changes: 5 additions & 0 deletions sway-error/src/warning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pub enum Warning {
last_occurrence: Span,
previous_occurrences: Vec<Span>,
},
ExpectedTypeAnnotationForConstants,
}

/// Elements that can be deprecated.
Expand Down Expand Up @@ -319,6 +320,10 @@ impl fmt::Display for Warning {
format!(" {} times", num_to_str(previous_occurrences.len()))
}
),
ExpectedTypeAnnotationForConstants => write!(
f,
"This constant lacks a type annotation."
),
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions sway-lib-std/src/constants.sw
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use ::primitives::*;
/// }
/// ```
#[deprecated(note = "Please use `b256::zero()`.")]
pub const ZERO_B256 = 0x0000000000000000000000000000000000000000000000000000000000000000;
pub const ZERO_B256: b256 = 0x0000000000000000000000000000000000000000000000000000000000000000;

/// A u256 of zero value.
///
Expand All @@ -37,7 +37,7 @@ pub const ZERO_B256 = 0x00000000000000000000000000000000000000000000000000000000
/// }
/// ```
#[deprecated(note = "Please use `u256::zero()`.")]
pub const ZERO_U256 = 0x00u256;
pub const ZERO_U256: u256 = 0x00u256;

/// The default Sub Id for assets.
///
Expand All @@ -51,4 +51,4 @@ pub const ZERO_U256 = 0x00u256;
/// assert(AssetId::new(contract_id(), DEFAULT_SUB_ID) == msg_asset_id());
/// }
/// ```
pub const DEFAULT_SUB_ID = b256::zero();
pub const DEFAULT_SUB_ID: b256 = b256::zero();
12 changes: 6 additions & 6 deletions sway-lib-std/src/error_signals.sw
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,39 @@ library;
/// # Additional Information
///
/// The value is: 18446744073709486080
pub const FAILED_REQUIRE_SIGNAL = 0xffff_ffff_ffff_0000;
pub const FAILED_REQUIRE_SIGNAL: u64 = 0xffff_ffff_ffff_0000;

/// A revert with this value signals that it was caused by a failing call to `std::asset::transfer_to_address`.
///
/// # Additional Information
///
/// The value is: 18446744073709486081
pub const FAILED_TRANSFER_TO_ADDRESS_SIGNAL = 0xffff_ffff_ffff_0001;
pub const FAILED_TRANSFER_TO_ADDRESS_SIGNAL: u64 = 0xffff_ffff_ffff_0001;

/// A revert with this value signals that it was caused by a failing call to `std::assert::assert_eq`.
///
/// # Additional Information
///
/// The value is: 18446744073709486083
pub const FAILED_ASSERT_EQ_SIGNAL = 0xffff_ffff_ffff_0003;
pub const FAILED_ASSERT_EQ_SIGNAL: u64 = 0xffff_ffff_ffff_0003;

/// A revert with this value signals that it was caused by a failing call to `std::assert::assert`.
///
/// # Additional Information
///
/// The value is: 18446744073709486084
pub const FAILED_ASSERT_SIGNAL = 0xffff_ffff_ffff_0004;
pub const FAILED_ASSERT_SIGNAL: u64 = 0xffff_ffff_ffff_0004;

/// A revert with this value signals that it was caused by a failing call to `std::assert::assert_ne`.
///
/// # Additional Information
///
/// The value is: 18446744073709486085
pub const FAILED_ASSERT_NE_SIGNAL = 0xffff_ffff_ffff_0005;
pub const FAILED_ASSERT_NE_SIGNAL: u64 = 0xffff_ffff_ffff_0005;

/// A revert with this value signals that it was caused by a call to `std::revert::revert_with_log`.
///
/// # Additional Information
///
/// The value is: 18446744073709486086
pub const REVERT_WITH_LOG_SIGNAL = 0xffff_ffff_ffff_0006;
pub const REVERT_WITH_LOG_SIGNAL: u64 = 0xffff_ffff_ffff_0006;
50 changes: 25 additions & 25 deletions sway-lib-std/src/inputs.sw
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,31 @@ use ::codec::*;
use ::raw_slice::*;

// GTF Opcode const selectors
pub const GTF_INPUT_TYPE = 0x200;
// pub const GTF_INPUT_COIN_TX_ID = 0x201;
// pub const GTF_INPUT_COIN_OUTPUT_INDEX = 0x202;
pub const GTF_INPUT_COIN_OWNER = 0x203;
pub const GTF_INPUT_COIN_AMOUNT = 0x204;
pub const GTF_INPUT_COIN_ASSET_ID = 0x205;
pub const GTF_INPUT_COIN_WITNESS_INDEX = 0x207;
pub const GTF_INPUT_COIN_PREDICATE_LENGTH = 0x209;
pub const GTF_INPUT_COIN_PREDICATE_DATA_LENGTH = 0x20A;
pub const GTF_INPUT_COIN_PREDICATE = 0x20B;
pub const GTF_INPUT_COIN_PREDICATE_DATA = 0x20C;
// pub const GTF_INPUT_COIN_PREDICATE_GAS_USED = 0x20D;
// pub const GTF_INPUT_CONTRACT_CONTRACT_ID = 0x225;
pub const GTF_INPUT_MESSAGE_SENDER = 0x240;
pub const GTF_INPUT_MESSAGE_RECIPIENT = 0x241;
pub const GTF_INPUT_MESSAGE_AMOUNT = 0x242;
pub const GTF_INPUT_MESSAGE_NONCE = 0x243;
pub const GTF_INPUT_MESSAGE_WITNESS_INDEX = 0x244;
pub const GTF_INPUT_MESSAGE_DATA_LENGTH = 0x245;
pub const GTF_INPUT_MESSAGE_PREDICATE_LENGTH = 0x246;
pub const GTF_INPUT_MESSAGE_PREDICATE_DATA_LENGTH = 0x247;
pub const GTF_INPUT_MESSAGE_DATA = 0x248;
pub const GTF_INPUT_MESSAGE_PREDICATE = 0x249;
pub const GTF_INPUT_MESSAGE_PREDICATE_DATA = 0x24A;
// pub const GTF_INPUT_MESSAGE_PREDICATE_GAS_USED = 0x24B;
pub const GTF_INPUT_TYPE: u64 = 0x200;
// pub const GTF_INPUT_COIN_TX_ID: u64 = 0x201;
// pub const GTF_INPUT_COIN_OUTPUT_INDEX: u64 = 0x202;
pub const GTF_INPUT_COIN_OWNER: u64 = 0x203;
pub const GTF_INPUT_COIN_AMOUNT: u64 = 0x204;
pub const GTF_INPUT_COIN_ASSET_ID: u64 = 0x205;
pub const GTF_INPUT_COIN_WITNESS_INDEX: u64 = 0x207;
pub const GTF_INPUT_COIN_PREDICATE_LENGTH: u64 = 0x209;
pub const GTF_INPUT_COIN_PREDICATE_DATA_LENGTH: u64 = 0x20A;
pub const GTF_INPUT_COIN_PREDICATE: u64 = 0x20B;
pub const GTF_INPUT_COIN_PREDICATE_DATA: u64 = 0x20C;
// pub const GTF_INPUT_COIN_PREDICATE_GAS_USED: u64 = 0x20D;
// pub const GTF_INPUT_CONTRACT_CONTRACT_ID: u64 = 0x225;
pub const GTF_INPUT_MESSAGE_SENDER: u64 = 0x240;
pub const GTF_INPUT_MESSAGE_RECIPIENT: u64 = 0x241;
pub const GTF_INPUT_MESSAGE_AMOUNT: u64 = 0x242;
pub const GTF_INPUT_MESSAGE_NONCE: u64 = 0x243;
pub const GTF_INPUT_MESSAGE_WITNESS_INDEX: u64 = 0x244;
pub const GTF_INPUT_MESSAGE_DATA_LENGTH: u64 = 0x245;
pub const GTF_INPUT_MESSAGE_PREDICATE_LENGTH: u64 = 0x246;
pub const GTF_INPUT_MESSAGE_PREDICATE_DATA_LENGTH: u64 = 0x247;
pub const GTF_INPUT_MESSAGE_DATA: u64 = 0x248;
pub const GTF_INPUT_MESSAGE_PREDICATE: u64 = 0x249;
pub const GTF_INPUT_MESSAGE_PREDICATE_DATA: u64 = 0x24A;
// pub const GTF_INPUT_MESSAGE_PREDICATE_GAS_USED: u64 = 0x24B;

/// The input type for a transaction.
pub enum Input {
Expand Down
22 changes: 11 additions & 11 deletions sway-lib-std/src/outputs.sw
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ use ::codec::*;

// GTF Opcode const selectors
//
pub const GTF_OUTPUT_TYPE = 0x300;
pub const GTF_OUTPUT_COIN_TO = 0x301;
pub const GTF_OUTPUT_COIN_AMOUNT = 0x302;
pub const GTF_OUTPUT_COIN_ASSET_ID = 0x303;
// pub const GTF_OUTPUT_CONTRACT_INPUT_INDEX = 0x304;
// pub const GTF_OUTPUT_CONTRACT_BALANCE_ROOT = 0x305;
// pub const GTF_OUTPUT_CONTRACT_STATE_ROOT = 0x306;
// pub const GTF_OUTPUT_CONTRACT_CREATED_CONTRACT_ID = 0x307;
// pub const GTF_OUTPUT_CONTRACT_CREATED_STATE_ROOT = 0x308;
pub const GTF_OUTPUT_TYPE: u64 = 0x300;
pub const GTF_OUTPUT_COIN_TO: u64 = 0x301;
pub const GTF_OUTPUT_COIN_AMOUNT: u64 = 0x302;
pub const GTF_OUTPUT_COIN_ASSET_ID: u64 = 0x303;
// pub const GTF_OUTPUT_CONTRACT_INPUT_INDEX: u64 = 0x304;
// pub const GTF_OUTPUT_CONTRACT_BALANCE_ROOT: u64 = 0x305;
// pub const GTF_OUTPUT_CONTRACT_STATE_ROOT: u64 = 0x306;
// pub const GTF_OUTPUT_CONTRACT_CREATED_CONTRACT_ID: u64 = 0x307;
// pub const GTF_OUTPUT_CONTRACT_CREATED_STATE_ROOT: u64 = 0x308;

const OUTPUT_VARIABLE_ASSET_ID_OFFSET = 48;
const OUTPUT_VARIABLE_TO_OFFSET = 8;
const OUTPUT_VARIABLE_ASSET_ID_OFFSET: u64 = 48;
const OUTPUT_VARIABLE_TO_OFFSET: u64 = 8;

/// The output type for a transaction.
pub enum Output {
Expand Down
Loading
Loading