Skip to content

Commit

Permalink
Eliminate need for ~ in ~Foo::bar() (FuelLabs#3218)
Browse files Browse the repository at this point in the history
Fixes FuelLabs#1436.

This PR first removes the need for `~` in `~Foo::bar` by first delaying
the interpretation of `Foo::Bar` (associated call, free function call,
or enum variant construction?) until type checking. This is achieved
with `ExprKind::AmbiguousPathExpression`. During type checking, we ask
whether `Foo` (and any prefixes) is a module, or an enum. If it's
neither, we attempt type checking as an associated function call.
Otherwise, we continue as if we had a `ExpressionKind::DelineatedPath`.

Once `~` is made redundant, it's then also removed from the language and
so also from tests, examples, and the standard library.

Co-authored-by: Alex Hansen <[email protected]>
  • Loading branch information
Centril and sezna authored Oct 31, 2022
1 parent 3095027 commit cd10014
Show file tree
Hide file tree
Showing 92 changed files with 1,014 additions and 985 deletions.
18 changes: 9 additions & 9 deletions examples/hashing/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ struct Stats {
}

fn main() {
let zero = ~b256::min();
let zero = b256::min();
// Use the generic sha256 to hash some integers
let sha_hashed_u8 = sha256(~u8::max());
let sha_hashed_u16 = sha256(~u16::max());
let sha_hashed_u32 = sha256(~u32::max());
let sha_hashed_u64 = sha256(~u64::max());
let sha_hashed_u8 = sha256(u8::max());
let sha_hashed_u16 = sha256(u16::max());
let sha_hashed_u32 = sha256(u32::max());
let sha_hashed_u64 = sha256(u64::max());

// Or hash a b256
let sha_hashed_b256 = sha256(VALUE_A);
Expand Down Expand Up @@ -80,10 +80,10 @@ fn main() {
log(sha_hashed_struct);

// Use the generic keccak256 to hash some integers
let keccak_hashed_u8 = keccak256(~u8::max());
let keccak_hashed_u16 = keccak256(~u16::max());
let keccak_hashed_u32 = keccak256(~u32::max());
let keccak_hashed_u64 = keccak256(~u64::max());
let keccak_hashed_u8 = keccak256(u8::max());
let keccak_hashed_u16 = keccak256(u16::max());
let keccak_hashed_u32 = keccak256(u32::max());
let keccak_hashed_u64 = keccak256(u64::max());

// Or hash a b256
let keccak_hashed_b256 = keccak256(VALUE_A);
Expand Down
4 changes: 2 additions & 2 deletions examples/identity/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ use std::{
};

storage {
owner: Identity = Identity::ContractId(~ContractId::from(ZERO_B256)),
owner: Identity = Identity::ContractId(ContractId::from(ZERO_B256)),
}

impl IdentityExample for Contract {
fn cast_to_identity() {
// ANCHOR: cast_to_identity
let raw_address: b256 = 0xddec0e7e6a9a4a4e3e57d08d080d71a299c628a46bc609aab4627695679421ca;
let my_identity: Identity = Identity::Address(~Address::from(raw_address));
let my_identity: Identity = Identity::Address(Address::from(raw_address));
// ANCHOR_END: cast_to_identity
}

Expand Down
2 changes: 1 addition & 1 deletion examples/liquidity_pool/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ abi LiquidityPool {
fn withdraw(recipient: Address);
}

const BASE_TOKEN = ~ContractId::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c);
const BASE_TOKEN = ContractId::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c);

impl LiquidityPool for Contract {
fn deposit(recipient: Address) {
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 @@ -6,7 +6,7 @@ abi MyOwnedContract {
fn receive(field_1: u64) -> bool;
}

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

impl MyOwnedContract for Contract {
fn receive(field_1: u64) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion examples/signatures/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const MSG_HASH = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4
fn main() {
let hi = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
let lo = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
let signature: B512 = ~B512::from(hi, lo);
let signature: B512 = B512::from(hi, lo);

// A recovered public key pair.
let public_key = ec_recover(signature, MSG_HASH);
Expand Down
9 changes: 4 additions & 5 deletions examples/storage_map/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,18 @@ impl StorageMapExample for Contract {
// ANCHOR: storage_map_insert
#[storage(write)]
fn insert_into_storage_map() {
let addr1 = ~Address::from(0x0101010101010101010101010101010101010101010101010101010101010101);
let addr2 = ~Address::from(0x0202020202020202020202020202020202020202020202020202020202020202);
let addr1 = Address::from(0x0101010101010101010101010101010101010101010101010101010101010101);
let addr2 = Address::from(0x0202020202020202020202020202020202020202020202020202020202020202);

storage.map.insert(addr1, 42);
storage.map.insert(addr2, 77);
}
// ANCHOR_END: storage_map_insert

// ANCHOR: storage_map_get
#[storage(read, write)]
fn get_from_storage_map() {
let addr1 = ~Address::from(0x0101010101010101010101010101010101010101010101010101010101010101);
let addr2 = ~Address::from(0x0202020202020202020202020202020202020202020202020202020202020202);
let addr1 = Address::from(0x0101010101010101010101010101010101010101010101010101010101010101);
let addr2 = Address::from(0x0202020202020202020202020202020202020202020202020202020202020202);

storage.map.insert(addr1, 42);
storage.map.insert(addr2, 77);
Expand Down
4 changes: 2 additions & 2 deletions examples/subcurrency/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{chain::auth::{AuthError, msg_sender}, hash::sha256, logging::log};
////////////////////////////////////////
// Event declarations
////////////////////////////////////////
//
//
// Events allow clients to react to changes in the contract.
// Unlike Solidity, events are simply structs.
//
Expand Down Expand Up @@ -37,7 +37,7 @@ abi Token {
// Constants
////////////////////////////////////////
/// Address of contract creator.
const MINTER = ~Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b);
const MINTER = Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b);

////////////////////////////////////////
// Contract storage
Expand Down
6 changes: 3 additions & 3 deletions examples/vec/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use std::logging::log;

fn main() {
// ANCHOR: vec_new
let v: Vec<u64> = ~Vec::new();
let v: Vec<u64> = Vec::new();
// ANCHOR_END: vec_new
// ANCHOR: vec_push
let mut v = ~Vec::new();
let mut v = Vec::new();

v.push(5);
v.push(6);
Expand Down Expand Up @@ -39,7 +39,7 @@ fn main() {
Boolean: bool,
}

let mut row = ~Vec::new();
let mut row = Vec::new();
row.push(TableCell::Int(3));
row.push(TableCell::B256(0x0101010101010101010101010101010101010101010101010101010101010101));
row.push(TableCell::Boolean(true));
Expand Down
2 changes: 1 addition & 1 deletion examples/wallet_contract_caller_script/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ fn main() {
let contract_address = 0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b;
let caller = abi(Wallet, contract_address);
let amount_to_send = 200;
let recipient_address = ~Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b);
let recipient_address = Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b);
caller.send_funds {
gas: 10000,
coins: 0,
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 @@ -17,7 +17,7 @@ use std::{
// ANCHOR: abi_import
use wallet_abi::Wallet;
// ANCHOR_END: abi_import
const OWNER_ADDRESS = ~Address::from(0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861);
const OWNER_ADDRESS = Address::from(0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861);

storage {
balance: u64 = 0,
Expand Down
1 change: 0 additions & 1 deletion sway-ast/src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ define_token!(
);
define_token!(OpenAngleBracketToken, "`<`", [LessThan], []);
define_token!(CloseAngleBracketToken, "`>`", [GreaterThan], []);
define_token!(TildeToken, "`~`", [Tilde], []);
define_token!(EqToken, "`=`", [Equals], [GreaterThan, Equals]);
define_token!(AddEqToken, "`+=`", [Add, Equals], []);
define_token!(SubEqToken, "`-=`", [Sub, Equals], []);
Expand Down
36 changes: 11 additions & 25 deletions sway-ast/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub struct PathExpr {

#[derive(Clone, Debug)]
pub struct PathExprSegment {
pub fully_qualified: Option<TildeToken>,
pub name: Ident,
pub generics_opt: Option<(DoubleColonToken, GenericArgs)>,
}
Expand All @@ -33,11 +32,7 @@ impl Spanned for PathExpr {

impl PathExpr {
pub fn try_into_ident(self) -> Result<Ident, PathExpr> {
if self.root_opt.is_none()
&& self.suffix.is_empty()
&& self.prefix.fully_qualified.is_none()
&& self.prefix.generics_opt.is_none()
{
if self.root_opt.is_none() && self.suffix.is_empty() && self.prefix.generics_opt.is_none() {
return Ok(self.prefix.name);
}
Err(self)
Expand All @@ -46,15 +41,11 @@ impl PathExpr {

impl Spanned for PathExprSegment {
fn span(&self) -> Span {
let start = match &self.fully_qualified {
Some(tilde_token) => tilde_token.span(),
None => self.name.span(),
};
let end = match &self.generics_opt {
Some((_, generic_args)) => generic_args.span(),
None => self.name.span(),
};
Span::join(start, end)
let start = self.name.span();
match &self.generics_opt {
Some((_, generic_args)) => Span::join(start, generic_args.span()),
None => start,
}
}
}

Expand Down Expand Up @@ -84,22 +75,17 @@ impl Spanned for PathType {

#[derive(Clone, Debug)]
pub struct PathTypeSegment {
pub fully_qualified: Option<TildeToken>,
pub name: Ident,
pub generics_opt: Option<(Option<DoubleColonToken>, GenericArgs)>,
}

impl Spanned for PathTypeSegment {
fn span(&self) -> Span {
let start = match &self.fully_qualified {
Some(tilde_token) => tilde_token.span(),
None => self.name.span(),
};
let end = match &self.generics_opt {
Some((_, generic_args)) => generic_args.span(),
None => self.name.span(),
};
Span::join(start, end)
let start = self.name.span();
match &self.generics_opt {
Some((_, generic_args)) => Span::join(start, generic_args.span()),
None => start,
}
}
}

Expand Down
3 changes: 0 additions & 3 deletions sway-ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ pub enum PunctKind {
Ampersand,
Caret,
Pipe,
Tilde,
Underscore,
Sharp,
}
Expand Down Expand Up @@ -61,7 +60,6 @@ impl PunctKind {
PunctKind::Ampersand => '&',
PunctKind::Caret => '^',
PunctKind::Pipe => '|',
PunctKind::Tilde => '~',
PunctKind::Underscore => '_',
PunctKind::Sharp => '#',
}
Expand Down Expand Up @@ -280,7 +278,6 @@ impl CharExt for char {
'&' => Some(PunctKind::Ampersand),
'^' => Some(PunctKind::Caret),
'|' => Some(PunctKind::Pipe),
'~' => Some(PunctKind::Tilde),
'_' => Some(PunctKind::Underscore),
'#' => Some(PunctKind::Sharp),
_ => None,
Expand Down
4 changes: 2 additions & 2 deletions sway-core/src/language/call_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ impl<T: Spanned> Spanned for CallPath<T> {
}

impl CallPath {
/// shifts the last prefix into the suffix and removes the old suffix
/// noop if prefixes are empty
/// Shifts the last prefix into the suffix, and removes the old suffix.
/// Does nothing if prefixes are empty.
pub fn rshift(&self) -> CallPath {
if self.prefixes.is_empty() {
self.clone()
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/language/parsed/expression/method_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{Ident, TypeInfo};
#[derive(Debug, Clone)]
pub enum MethodName {
/// Represents a method lookup with a type somewhere in the path
/// like a::b::~C::d()
/// like `a::b::C::d()` with `C` being the type.
FromType {
call_path_binding: TypeBinding<CallPath<(TypeInfo, Span)>>,
method_name: Ident,
Expand Down
29 changes: 29 additions & 0 deletions sway-core/src/language/parsed/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,32 @@ pub struct SubfieldExpression {
pub field_to_access: Ident,
}

#[derive(Debug, Clone)]
pub struct AmbiguousSuffix {
/// The ambiguous part of the suffix.
///
/// For example, if we have `Foo::bar()`,
/// we don't know whether `Foo` is a module or a type,
/// so `before` would be `Foo` here with any type arguments.
pub before: TypeBinding<Ident>,
/// The final suffix, i.e., the function name.
///
/// In the example above, this would be `bar`.
pub suffix: Ident,
}

impl Spanned for AmbiguousSuffix {
fn span(&self) -> Span {
Span::join(self.before.span(), self.suffix.span())
}
}

#[derive(Debug, Clone)]
pub struct AmbiguousPathExpression {
pub call_path_binding: TypeBinding<CallPath<AmbiguousSuffix>>,
pub args: Vec<Expression>,
}

#[derive(Debug, Clone)]
pub struct DelineatedPathExpression {
pub call_path_binding: TypeBinding<CallPath>,
Expand Down Expand Up @@ -123,6 +149,9 @@ pub enum ExpressionKind {
/// when joined, the same as that stored in `expr.span`.
Error(Box<[Span]>),
Literal(Literal),
/// An ambiguous path where we don't know until type checking whether this
/// is a free function call or a UFCS (Rust term) style associated function call.
AmbiguousPathExpression(Box<AmbiguousPathExpression>),
FunctionApplication(Box<FunctionApplicationExpression>),
LazyOperator(LazyOperatorExpression),
Variable(Ident),
Expand Down
Loading

0 comments on commit cd10014

Please sign in to comment.