Skip to content

Commit

Permalink
Merge branch 'master' into braqzen-4656
Browse files Browse the repository at this point in the history
  • Loading branch information
Braqzen authored Jul 13, 2023
2 parents ae201b9 + 13ed81b commit 24b08cb
Show file tree
Hide file tree
Showing 21 changed files with 776 additions and 148 deletions.
1 change: 1 addition & 0 deletions docs/reference/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
- [Comments](./documentation/language/style-guide/comments.md)
- [Getter Functions](./documentation/language/style-guide/getters.md)
- [Unused Variables](./documentation/language/style-guide/unused-variables.md)
- [Intermediate Variables](./documentation/language/style-guide/intermediate-variables.md)

## Common Operations

Expand Down
8 changes: 8 additions & 0 deletions docs/reference/src/code/Forc.lock
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ name = 'interface'
source = 'member'
dependencies = ['std path+from-root-0F28276288D2432C']

[[package]]
name = 'intermediate_variables'
source = 'member'
dependencies = [
'core',
'std',
]

[[package]]
name = 'letter_casing'
source = 'member'
Expand Down
1 change: 1 addition & 0 deletions docs/reference/src/code/Forc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ members = [
"language/style-guide/pattern_matching",
"language/style-guide/struct_shorthand",
"language/style-guide/unused_variables",
"language/style-guide/intermediate_variables",
"language/traits/associated-consts",
"language/variables",
"misc/advanced-concepts/enum_advanced",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
out
target
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "lib.sw"
license = "Apache-2.0"
name = "intermediate_variables"

[dependencies]
core = { path = "../../../../../../../sway-lib-core" }
std = { path = "../../../../../../../sway-lib-std" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
library;

#[allow(dead_code)]
fn update_state() -> u64 {
// Used for context in the following function
42
}

#[allow(dead_code)]
// ANCHOR: contextual_assignment
fn contextual_assignment() {
let remaining_amount = update_state();
// code that uses `remaining_amount` instead of directly calling `update_state()`
}
// ANCHOR_END: contextual_assignment

#[allow(dead_code)]
fn update_state_of_vault_v3_storage_contract() -> u64 {
// Used for context in the following function
42
}

#[allow(dead_code)]
// ANCHOR: shortened_name
fn shortened_name() {
let remaining_amount = update_state_of_vault_v3_storage_contract();
// code that uses `remaining_amount` instead of directly calling `update_state_of_vault_v3_storage_contract()`
}
// ANCHOR_END: shortened_name
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Intermediate Variables

An intermediate variable, or a temporary variable, is a variable that is typically used once. In most cases we avoid creating intermediate variables; however, there are cases where they may enrich the code.

## Contextual Assignment

It may be beneficial to use an intermediate variable to provide context to the reader about the value.

```sway
{{#include ../../../code/language/style-guide/intermediate_variables/src/lib.sw:contextual_assignment}}
```

## Shortened Name

In the cases of multiple levels of indentation or overly verbose names it may be beneficial to create an intermediate variable with a shorter name.

```sway
{{#include ../../../code/language/style-guide/intermediate_variables/src/lib.sw:shortened_name}}
```
17 changes: 17 additions & 0 deletions sway-core/src/semantic_analysis/ast_node/declaration/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
language::{
parsed::*,
ty::{self, TyImplItem, TyTraitItem},
CallPath,
},
semantic_analysis::{declaration::insert_supertraits_into_namespace, Mode, TypeCheckContext},
CompileResult, ReplaceSelfType, TypeId, TypeInfo,
Expand Down Expand Up @@ -215,5 +216,21 @@ impl ty::TyAbiDecl {
}
}
}
// Insert the methods of the ABI into the namespace.
// Specifically do not check for conflicting definitions because
// this is just a temporary namespace for type checking and
// these are not actual impl blocks.
// We check that a contract method cannot call a contract method
// from the same ABI later, during method application typechecking.
ctx.namespace.insert_trait_implementation(
CallPath::from(self.name.clone()),
vec![],
type_id,
&all_items,
&self.span,
Some(self.span()),
false,
ctx.engines,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -284,23 +284,27 @@ pub(crate) fn type_check_method_application(
.clone()
.map(|x| type_engine.get(x.return_type))
{
Some(TypeInfo::ContractCaller { address, .. }) => address,
Some(TypeInfo::ContractCaller { address, .. }) => match address {
Some(address) => address,
None => {
errors.push(CompileError::ContractAddressMustBeKnown {
span: call_path.span(),
});
return err(warnings, errors);
}
},
None => {
errors.push(CompileError::ContractCallsItsOwnMethod { span });
return err(warnings, errors);
}
_ => {
errors.push(CompileError::Internal(
"Attempted to find contract address of non-contract-call.",
span.clone(),
span,
));
None
return err(warnings, errors);
}
};
let contract_address = if let Some(addr) = contract_address {
addr
} else {
errors.push(CompileError::ContractAddressMustBeKnown {
span: call_path.span(),
});
return err(warnings, errors);
};
let func_selector = check!(
method.to_fn_selector_value(engines),
[0; 4],
Expand Down
3 changes: 3 additions & 0 deletions sway-error/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,8 @@ pub enum CompileError {
method_name: String,
as_traits: Vec<String>,
},
#[error("A contract method cannot call methods belonging to the same ABI")]
ContractCallsItsOwnMethod { span: Span },
}

impl std::convert::From<TypeError> for CompileError {
Expand Down Expand Up @@ -824,6 +826,7 @@ impl Spanned for CompileError {
NameDefinedMultipleTimes { span, .. } => span.clone(),
MultipleApplicableItemsInScope { span, .. } => span.clone(),
CannotBeEvaluatedToConst { span } => span.clone(),
ContractCallsItsOwnMethod { span } => span.clone(),
}
}
}
Expand Down
86 changes: 86 additions & 0 deletions sway-ir/src/optimize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,89 @@ pub mod simplify_cfg;
pub use simplify_cfg::*;

mod target_fuel;

#[cfg(test)]
pub mod tests {
use crate::{PassGroup, PassManager};
use sway_types::SourceEngine;

/// This function parses the IR text representation and run the specified optimizers passes.
/// Then, depending on the `expected` parameter it checks if the IR was optimized or not.
///
/// This comparison is done by capturing all instructions with metadata "!0".
///
/// For example:
///
/// ```rust, ignore
/// assert_optimization(
/// &["constcombine"],
/// "entry fn main() -> u64 {
/// entry():
/// l = const u64 1
/// r = const u64 2
/// result = add l, r, !0
/// ret u64 result
/// }",
/// ["const u64 3"],
/// );
/// ```
pub(crate) fn assert_optimization<'a>(
passes: &[&'static str],
body: &str,
expected: Option<impl IntoIterator<Item = &'a str>>,
) {
let source_engine = SourceEngine::default();
let mut context = crate::parse(
&format!(
"script {{
{body}
}}
!0 = \"a.sw\""
),
&source_engine,
)
.unwrap();

let mut pass_manager = PassManager::default();
crate::register_known_passes(&mut pass_manager);

let mut group = PassGroup::default();
for pass in passes {
group.append_pass(pass);
}

let modified = pass_manager.run(&mut context, &group).unwrap();
assert_eq!(expected.is_some(), modified);

let Some(expected) = expected else {
return;
};

let actual = context
.to_string()
.lines()
.filter_map(|x| {
if x.contains(", !0") {
Some(format!("{}\n", x.trim()))
} else {
None
}
})
.collect::<Vec<String>>();

assert!(!actual.is_empty());

let mut expected_matches = actual.len();

for (actual, expected) in actual.iter().zip(expected) {
if !actual.contains(expected) {
panic!("error: {actual:?} {expected:?}");
} else {
expected_matches -= 1;
}
}

assert_eq!(expected_matches, 0);
}
}
Loading

0 comments on commit 24b08cb

Please sign in to comment.