Skip to content
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

Add support for language level errors (LangError) #1450

Merged
merged 111 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
c62ea25
Add example cross-chain contract
HCastano Oct 22, 2022
5e8cd1e
Update `CallBuilder`'s return type to a `Result`
HCastano Oct 24, 2022
728c45c
Write to output buffer on dispatch error
HCastano Oct 25, 2022
810ea54
Whoops, reduce value of `u8`
HCastano Oct 25, 2022
980f6a7
Add some `cargo-contract` automation helpers
HCastano Oct 25, 2022
6181d9c
Set default if no input is given
HCastano Oct 25, 2022
63fc94c
Return type expected by call builder after succesful dispatch
HCastano Oct 25, 2022
4280d37
Fix typo
HCastano Oct 25, 2022
474133a
Return an actual `DispatchError` back to the caller
HCastano Oct 26, 2022
e3f67ea
Temporarily stop generating contract ref code
HCastano Oct 31, 2022
6a04bd1
Manually change message return type to Result
HCastano Oct 31, 2022
5c9d250
Transform message return type in the IR
HCastano Oct 31, 2022
a989be6
Change message return type when generating contract reference
HCastano Oct 31, 2022
a9cae76
Return message output directly in the codegen
HCastano Nov 1, 2022
b3e0141
Add error type for handling language errors
HCastano Nov 1, 2022
cf332b7
Clean up some things
HCastano Nov 1, 2022
845b009
Merge branch 'master' into hc-add-ink-level-errors
HCastano Nov 1, 2022
dc1b7a3
Remove some unused code
HCastano Nov 1, 2022
2ad4633
Add DispatchError type metadata
ascjones Nov 2, 2022
5421a0c
Merge branch 'master' into hc-add-ink-level-errors
ascjones Nov 2, 2022
14b5875
Use language error over dispatch error
HCastano Nov 2, 2022
a38a395
Change message body's visibility based on message signature
HCastano Nov 2, 2022
a4d653b
Fix unreachable code warning
HCastano Nov 2, 2022
fc42d66
Appease Clippy
HCastano Nov 2, 2022
9705ff3
Rustfmt cross-contract example
HCastano Nov 2, 2022
fc7f374
align for runtime metadata compatibility
xermicus Nov 4, 2022
7869558
Merge branch 'master' into hc-add-ink-level-errors
xermicus Nov 4, 2022
a668018
Fix formatting
HCastano Nov 7, 2022
89d2cf5
Write `lang_error` into metadata using spec builder
HCastano Nov 7, 2022
68417b7
Use `parse_quote` macro over the `syn::parse` function
HCastano Nov 7, 2022
f2ef955
Use correct span in call builder
HCastano Nov 7, 2022
183dc11
Always return `Type` instead of `Option` from `wrapped_output`
HCastano Nov 7, 2022
26e1170
Merge branch 'master' into hc-add-ink-level-errors
HCastano Nov 7, 2022
ae11633
Temporarily appease Clippy
HCastano Nov 7, 2022
1630b3d
Another temporary Clippy fix
HCastano Nov 7, 2022
2e7b5bc
Generate checked and unchecked versions of contract messages
HCastano Nov 7, 2022
87ca721
Use non-checked message as checked message implementation
HCastano Nov 7, 2022
66dd9d1
Remove error handling from test
HCastano Nov 7, 2022
517d408
Add method for generating checked message idents
HCastano Nov 8, 2022
1b6cacc
Merge branch 'master' into hc-add-ink-level-errors
HCastano Nov 8, 2022
150e4d3
Fix UI tests related to `no_implicit_prelude`
HCastano Nov 9, 2022
e59f53e
Merge branch 'master' into hc-add-ink-level-errors
HCastano Nov 9, 2022
d68777e
Remove unneccessary import
HCastano Nov 9, 2022
4f2caad
Add `Default` implementation for `cross_chain_test`
HCastano Nov 9, 2022
f617a0c
Bless some UI tests
HCastano Nov 9, 2022
105fe23
Update `Output` type for doc test
HCastano Nov 9, 2022
90cf477
Update `cross_chain_test` to appease Clippy
HCastano Nov 9, 2022
3774d29
Generate `*_checked` functions for `ContractRef` calls
HCastano Nov 10, 2022
13d7a42
Implement `Debug` for Multisig Wasm builds
HCastano Nov 10, 2022
8929234
Add another `Debug` impl
HCastano Nov 10, 2022
bb6c445
Add `lang_error` to metadata tests
HCastano Nov 10, 2022
10c9e7d
Add example which uses ContractRefs
HCastano Nov 10, 2022
57ddec7
Handle dispatch error in example
HCastano Nov 10, 2022
077d15b
Add UI test for checking that messages now return `Result`s
HCastano Nov 10, 2022
816f312
Add test for message hygiene (or lack thereof)
HCastano Nov 10, 2022
636e7c9
Add test to check that `*_checked` messages are generated
HCastano Nov 10, 2022
e2d8194
Remove debug logging from macro code
HCastano Nov 10, 2022
94449dd
Appease Clippy
HCastano Nov 10, 2022
f1137a7
Remove `--skip-linting` from scripts
HCastano Nov 11, 2022
2afef50
Fix fallible constructor revert, make `Ok` explicit
ascjones Nov 11, 2022
ed1aeec
Hack together E2E test example for `LangError`
HCastano Nov 11, 2022
ed60df8
Add a couple of type aliases to E2E test
HCastano Nov 13, 2022
8cea958
Add E2E test which demonstrates write-on-err bug
HCastano Nov 13, 2022
2488761
Split out E2E tests into seperate functions
HCastano Nov 13, 2022
3670755
Merge branch 'aj/add-ink-level-errors' into hc-add-ink-level-errors
HCastano Nov 13, 2022
412c9ac
Tweak E2E tests to make them pass given Andrew's fixes
HCastano Nov 13, 2022
59bde0e
Remove outdated UI test
HCastano Nov 13, 2022
6eea67e
Fix a couple more tests
HCastano Nov 13, 2022
a78b042
Unify output type and arrow in codegen
HCastano Nov 14, 2022
96c9c42
Allow `result_unit_err` Clippy lint
HCastano Nov 14, 2022
f113dc2
Move `Flipper` functionality into integration example
HCastano Nov 14, 2022
f6b4c10
Rename `cross_chain_test` to indicate that its an integration test
HCastano Nov 15, 2022
8b8eec8
Remove test helper scripts
HCastano Nov 15, 2022
6c24543
Remove `ContractRef` example/compile test
HCastano Nov 15, 2022
ce67e87
Appease Clippy
HCastano Nov 15, 2022
f5b5ae4
Add `MessageResult` type alias
HCastano Nov 15, 2022
0fbbae1
Remove `Ref` re-export from Flipper
HCastano Nov 15, 2022
894e898
Remove TODOs related to E2E issues
HCastano Nov 15, 2022
fa9d57b
Work around `additional_contracts` bug by moving tests
HCastano Nov 15, 2022
51dec24
Clean up `lang_err_integration_tests` a bit
HCastano Nov 15, 2022
cee90d7
Fix spellcheck lint
HCastano Nov 15, 2022
b1cfc9f
Merge branch 'master' into hc-add-ink-level-errors
HCastano Nov 15, 2022
1870988
Place E2E tests behind feature flag
HCastano Nov 15, 2022
476ed65
Apply suggestions from code review
HCastano Nov 15, 2022
2ce3677
Unwrap message result in delegator E2E tests
HCastano Nov 15, 2022
3410224
Revert "Remove `ContractRef` example/compile test"
HCastano Nov 15, 2022
98aa04f
Move `LangError` integration tests into single workspace
HCastano Nov 15, 2022
0164c01
Move flip related E2E tests to `integration_flipper`
HCastano Nov 15, 2022
3ed6521
Move `integration_flipper` into its own folder
HCastano Nov 15, 2022
a82346e
Update `call_builder` test to use `integration_flipper`
HCastano Nov 15, 2022
50c5f4e
Get `contract_ref` E2E test working again
HCastano Nov 15, 2022
d63cae1
Fill out author and version metadata
HCastano Nov 15, 2022
55c4f3c
Add integration tests to CI
HCastano Nov 15, 2022
671377e
Remove leftover .gitignore
HCastano Nov 15, 2022
c7b8b07
Skip default checks if it's a lang error integration test
HCastano Nov 15, 2022
ed6a6d6
Fix UI test
HCastano Nov 15, 2022
1a74375
Skip a few CI stages
HCastano Nov 15, 2022
dff5ada
Add back Clippy stage
HCastano Nov 15, 2022
26e2e37
Revert "Skip a few CI stages"
HCastano Nov 15, 2022
49d2ee4
Run `LangError` E2E tests in CI
HCastano Nov 15, 2022
5785eb0
Rename tests using kabob-case instead of snake_case
HCastano Nov 15, 2022
7d57f8c
Try running with `staging` image
HCastano Nov 16, 2022
2b05e59
Change image back to `production`
HCastano Nov 16, 2022
80a27a7
Try cleaning some things
HCastano Nov 16, 2022
0212c90
Guess there was no lockfile
HCastano Nov 16, 2022
12bc824
Clean up the cleanup
HCastano Nov 16, 2022
55b4e4f
Clean em up again
HCastano Nov 16, 2022
1644343
Use `MessageResult` typedef in one more place
HCastano Nov 16, 2022
f1211ba
Poke CI
HCastano Nov 16, 2022
9a1e41f
Move comment location
HCastano Nov 16, 2022
4057790
Update contract name
HCastano Nov 16, 2022
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
28 changes: 28 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ variables:
ALL_CRATES: "${PURELY_STD_CRATES} ${ALSO_WASM_CRATES}"
DELEGATOR_SUBCONTRACTS: "accumulator adder subber"
UPGRADEABLE_CONTRACTS: "forward-calls set-code-hash"
LANG_ERR_INTEGRATION_CONTRACTS: "integration-flipper call-builder contract-ref"
# TODO `cargo clippy --verbose --all-targets --all-features` for this crate
# currently fails on `stable`, but succeeds on `nightly`. This is due to
# this fix not yet in stable: https://github.com/rust-lang/rust-clippy/issues/8895.
Expand Down Expand Up @@ -122,6 +123,7 @@ examples-fmt:
# Note that we disable the license header check for the examples, since they are unlicensed.
- for example in examples/*/; do
if [ "$example" = "examples/upgradeable-contracts/" ]; then continue; fi;
if [ "$example" = "examples/lang-err-integration-tests/" ]; then continue; fi;
cargo +nightly fmt --verbose --manifest-path ${example}/Cargo.toml -- --check;
done
- for contract in ${DELEGATOR_SUBCONTRACTS}; do
Expand All @@ -130,6 +132,9 @@ examples-fmt:
- for contract in ${UPGRADEABLE_CONTRACTS}; do
cargo +nightly fmt --verbose --manifest-path ./examples/upgradeable-contracts/${contract}/Cargo.toml -- --check;
done
- for contract in ${LANG_ERR_INTEGRATION_CONTRACTS}; do
cargo +nightly fmt --verbose --manifest-path ./examples/lang-err-integration-tests/${contract}/Cargo.toml -- --check;
done
- cargo +nightly fmt --verbose --manifest-path ./examples/upgradeable-contracts/set-code-hash/updated-incrementer/Cargo.toml -- --check
# This file is not a part of the cargo project, so it wouldn't be formatted the usual way
- rustfmt +nightly --verbose --check ./examples/psp22-extension/runtime/psp22-extension-example.rs
Expand Down Expand Up @@ -161,6 +166,7 @@ examples-clippy-std:
script:
- for example in examples/*/; do
if [ "$example" = "examples/upgradeable-contracts/" ]; then continue; fi;
if [ "$example" = "examples/lang-err-integration-tests/" ]; then continue; fi;
cargo clippy --verbose --all-targets --manifest-path ${example}/Cargo.toml -- -D warnings -A $CLIPPY_ALLOWED;
done
- for contract in ${DELEGATOR_SUBCONTRACTS}; do
Expand All @@ -169,6 +175,9 @@ examples-clippy-std:
- for contract in ${UPGRADEABLE_CONTRACTS}; do
cargo clippy --verbose --all-targets --manifest-path ./examples/upgradeable-contracts/${contract}/Cargo.toml -- -D warnings -A $CLIPPY_ALLOWED;
done
- for contract in ${LANG_ERR_INTEGRATION_CONTRACTS}; do
cargo clippy --verbose --all-targets --manifest-path ./examples/lang-err-integration-tests/${contract}/Cargo.toml -- -D warnings -A $CLIPPY_ALLOWED;
done
- cargo clippy --verbose --all-targets --manifest-path ./examples/upgradeable-contracts/set-code-hash/updated-incrementer/Cargo.toml -- -D warnings -A $CLIPPY_ALLOWED;
allow_failure: true

Expand All @@ -179,6 +188,7 @@ examples-clippy-wasm:
script:
- for example in examples/*/; do
if [ "$example" = "examples/upgradeable-contracts/" ]; then continue; fi;
if [ "$example" = "examples/lang-err-integration-tests/" ]; then continue; fi;
cargo clippy --verbose --manifest-path ${example}/Cargo.toml --no-default-features --target wasm32-unknown-unknown -- -D warnings -A $CLIPPY_ALLOWED;
done
- for contract in ${DELEGATOR_SUBCONTRACTS}; do
Expand All @@ -187,6 +197,9 @@ examples-clippy-wasm:
- for contract in ${UPGRADEABLE_CONTRACTS}; do
cargo clippy --verbose --manifest-path ./examples/upgradeable-contracts/${contract}/Cargo.toml --no-default-features --target wasm32-unknown-unknown -- -D warnings -A $CLIPPY_ALLOWED;
done
- for contract in ${LANG_ERR_INTEGRATION_CONTRACTS}; do
cargo clippy --verbose --manifest-path ./examples/lang-err-integration-tests/${contract}/Cargo.toml --no-default-features --target wasm32-unknown-unknown -- -D warnings -A $CLIPPY_ALLOWED;
done
- cargo clippy --verbose --manifest-path ./examples/upgradeable-contracts/set-code-hash/updated-incrementer/Cargo.toml --no-default-features --target wasm32-unknown-unknown -- -D warnings -A $CLIPPY_ALLOWED;
allow_failure: true

Expand Down Expand Up @@ -363,6 +376,7 @@ examples-test:
- *start-substrate-contracts-node
- for example in examples/*/; do
if [ "$example" = "examples/upgradeable-contracts/" ]; then continue; fi;
if [ "$example" = "examples/lang-err-integration-tests/" ]; then continue; fi;
if grep -q "e2e-tests = \[\]" "${example}/Cargo.toml"; then
cargo test --verbose --manifest-path ${example}/Cargo.toml --features e2e-tests;
else
Expand All @@ -375,6 +389,12 @@ examples-test:
- for contract in ${UPGRADEABLE_CONTRACTS}; do
cargo test --verbose --manifest-path ./examples/upgradeable-contracts/${contract}/Cargo.toml;
done
# TODO (#1502): We need to clean before running, otherwise the CI fails with a
# linking error.
- for contract in ${LANG_ERR_INTEGRATION_CONTRACTS}; do
cargo clean --verbose --manifest-path ./examples/lang-err-integration-tests/${contract}/Cargo.toml;
cargo test --verbose --manifest-path ./examples/lang-err-integration-tests/${contract}/Cargo.toml --features e2e-tests;
done
- cargo test --verbose --manifest-path ./examples/upgradeable-contracts/set-code-hash/updated-incrementer/Cargo.toml;

examples-contract-build:
Expand All @@ -386,6 +406,7 @@ examples-contract-build:
- cargo contract -V
- for example in examples/*/; do
if [ "$example" = "examples/upgradeable-contracts/" ]; then continue; fi;
if [ "$example" = "examples/lang-err-integration-tests/" ]; then continue; fi;
pushd $example &&
cargo +stable contract build &&
popd;
Expand All @@ -394,6 +415,9 @@ examples-contract-build:
- for contract in ${UPGRADEABLE_CONTRACTS}; do
cargo +stable contract build --manifest-path ./examples/upgradeable-contracts/${contract}/Cargo.toml;
done
- for contract in ${LANG_ERR_INTEGRATION_CONTRACTS}; do
cargo +stable contract build --manifest-path ./examples/lang-err-integration-tests/${contract}/Cargo.toml;
done
- cargo +stable contract build --manifest-path ./examples/upgradeable-contracts/set-code-hash/updated-incrementer/Cargo.toml

examples-docs:
Expand All @@ -409,6 +433,7 @@ examples-docs:
# of this flag.
- for example in examples/*/; do
if [ "$example" = "examples/upgradeable-contracts/" ]; then continue; fi;
if [ "$example" = "examples/lang-err-integration-tests/" ]; then continue; fi;
cargo doc --manifest-path ${example}/Cargo.toml --document-private-items --verbose --no-deps;
done
- for contract in ${DELEGATOR_SUBCONTRACTS}; do
Expand All @@ -417,6 +442,9 @@ examples-docs:
- for contract in ${UPGRADEABLE_CONTRACTS}; do
cargo doc --manifest-path ./examples/upgradeable-contracts/${contract}/Cargo.toml --document-private-items --verbose --no-deps;
done
- for contract in ${LANG_ERR_INTEGRATION_CONTRACTS}; do
cargo doc --manifest-path ./examples/lang-err-integration-tests/${contract}/Cargo.toml --document-private-items --verbose --no-deps;
done
- cargo doc --manifest-path ./examples/upgradeable-contracts/set-code-hash/updated-incrementer/Cargo.toml --document-private-items --verbose --no-deps


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,10 +369,8 @@ impl CallBuilder<'_> {
let input_types = generator::input_types(message.inputs());
let arg_list = generator::generate_argument_list(input_types.iter().cloned());
let mut_tok = callable.receiver().is_ref_mut().then(|| quote! { mut });
let output = message.output();
let return_type =
output.map_or_else(|| quote! { () }, |output| quote! { #output });
let output_span = output.span();
let return_type = message.wrapped_output();
let output_span = return_type.span();
let output_type = quote_spanned!(output_span=>
::ink::env::call::CallBuilder<
Environment,
Expand Down
17 changes: 17 additions & 0 deletions crates/ink/codegen/src/generator/as_dependency/contract_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ impl ContractRef<'_> {
.filter_attr(message.attrs().to_vec());
let storage_ident = self.contract.module().storage().ident();
let message_ident = message.ident();
let checked_message_ident = message.checked_ident();
let call_operator = match message.receiver() {
ir::Receiver::Ref => quote! { call },
ir::Receiver::RefMut => quote! { call_mut },
Expand All @@ -344,13 +345,29 @@ impl ContractRef<'_> {
let input_bindings = message.inputs().map(|input| &input.pat).collect::<Vec<_>>();
let input_types = message.inputs().map(|input| &input.ty).collect::<Vec<_>>();
let output_type = message.output().map(|ty| quote! { -> #ty });
let wrapped_output_type = message.wrapped_output();
quote_spanned!(span=>
#( #attrs )*
#[inline]
pub fn #message_ident(
& #mut_token self
#( , #input_bindings : #input_types )*
) #output_type {
self.#checked_message_ident( #( #input_bindings, )* )
.unwrap_or_else(|error| ::core::panic!(
"encountered error while calling {}::{}: {:?}",
::core::stringify!(#storage_ident),
::core::stringify!(#message_ident),
error,
))
}

#( #attrs )*
#[inline]
pub fn #checked_message_ident(
& #mut_token self
#( , #input_bindings : #input_types )*
) -> #wrapped_output_type {
ascjones marked this conversation as resolved.
Show resolved Hide resolved
<Self as ::ink::codegen::TraitCallBuilder>::#call_operator(self)
.#message_ident( #( #input_bindings ),* )
.fire()
Expand Down
57 changes: 37 additions & 20 deletions crates/ink/codegen/src/generator/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,16 +435,34 @@ impl Dispatch<'_> {
.unwrap_or_else(|error| ::core::panic!("{}", error))
}

::ink::env::decode_input::<
<#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type>()
.map_err(|_| ::ink::reflect::DispatchError::CouldNotReadInput)
.and_then(|decoder| {
<<#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type
as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(decoder)
})
.unwrap_or_else(|error| {
::core::panic!("dispatching ink! message failed: {}", error)
})
let dispatchable = match ::ink::env::decode_input::<
<#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type,
>() {
::core::result::Result::Ok(decoded_dispatchable) => {
decoded_dispatchable
}
::core::result::Result::Err(_decoding_error) => {
use ::core::default::Default;
let error = ::core::result::Result::Err(::ink::LangError::CouldNotReadInput);

// At this point we're unable to set the `Ok` variant to be the any "real"
// message output since we were unable to figure out what the caller wanted
// to dispatch in the first place, so we set it to `()`.
//
// This is okay since we're going to only be encoding the `Err` variant
// into the output buffer anyways.
::ink::env::return_value::<::ink::MessageResult<()>>(
::ink::env::ReturnFlags::default().set_reverted(true),
&error,
);
}
};

<<#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type
as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable)
ascjones marked this conversation as resolved.
Show resolved Hide resolved
.unwrap_or_else(|error| {
::core::panic!("dispatching ink! message failed: {}", error)
})
}
)
}
Expand Down Expand Up @@ -761,23 +779,24 @@ impl Dispatch<'_> {
let failure = ::ink::is_result_type!(#message_output)
&& ::ink::is_result_err!(result);

// Currently no `LangError`s are raised at this level of the dispatch logic
// so `Ok` is always returned to the caller.
let return_value = ::core::result::Result::Ok(result);

if failure {
// We return early here since there is no need to push back the
// intermediate results of the contract - the transaction is going to be
// reverted anyways.
::ink::env::return_value::<#message_output>(
::ink::env::ReturnFlags::default().set_reverted(true), &result
::ink::env::return_value::<::ink::MessageResult::<#message_output>>(
::ink::env::ReturnFlags::default().set_reverted(true), &return_value
)
}

push_contract(contract, #mutates_storage);

if ::core::any::TypeId::of::<#message_output>() != ::core::any::TypeId::of::<()>() {
// In case the return type is `()` we do not return a value.
::ink::env::return_value::<#message_output>(
::ink::env::ReturnFlags::default(), &result
)
}
::ink::env::return_value::<::ink::MessageResult::<#message_output>>(
::ink::env::ReturnFlags::default(), &return_value
)
}
)
});
Expand Down Expand Up @@ -848,8 +867,6 @@ impl Dispatch<'_> {
match self {
#( #message_execute ),*
};

::core::result::Result::Ok(())
}
}

Expand Down
10 changes: 9 additions & 1 deletion crates/ink/codegen/src/generator/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ impl Metadata<'_> {
.attrs()
.iter()
.filter_map(|attr| attr.extract_docs());
let error_ty = syn::parse_quote! {
::ink::LangError
};
let error = Self::generate_type_spec(&error_ty);
quote! {
::ink::metadata::ContractSpec::new()
.constructors([
Expand All @@ -107,6 +111,9 @@ impl Metadata<'_> {
.docs([
#( #docs ),*
])
.lang_error(
#error
)
.done()
}
}
Expand Down Expand Up @@ -172,6 +179,7 @@ impl Metadata<'_> {
fn without_display_name(ty: &syn::Type) -> TokenStream2 {
quote! { ::ink::metadata::TypeSpec::of_type::<#ty>() }
}

if let syn::Type::Path(type_path) = ty {
if type_path.qself.is_some() {
return without_display_name(ty)
Expand Down Expand Up @@ -256,7 +264,7 @@ impl Metadata<'_> {
let mutates = message.receiver().is_ref_mut();
let ident = message.ident();
let args = message.inputs().map(Self::generate_dispatch_argument);
let ret_ty = Self::generate_return_type(message.output());
let ret_ty = Self::generate_return_type(Some(&message.wrapped_output()));
xermicus marked this conversation as resolved.
Show resolved Hide resolved
quote_spanned!(span =>
::ink::metadata::MessageSpec::from_label(::core::stringify!(#ident))
.selector([
Expand Down
20 changes: 20 additions & 0 deletions crates/ink/ir/src/ir/item_impl/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,21 @@ impl Message {
}
}

/// Returns the return type of the message, but wrapped within a `Result`.
///
/// This is used to to allow callers to handle certain types of errors which are not exposed
/// by messages.
pub fn wrapped_output(&self) -> syn::Type {
let return_type = self
.output()
.map(quote::ToTokens::to_token_stream)
.unwrap_or_else(|| quote::quote! { () });

syn::parse_quote! {
::ink::MessageResult<#return_type>
}
}

/// Returns a local ID unique to the ink! message with respect to its implementation block.
///
/// # Note
Expand All @@ -301,6 +316,11 @@ impl Message {
pub fn local_id(&self) -> u32 {
utils::local_message_id(self.ident())
}

/// Returns the identifier of the message with an additional `_checked` suffix attached.
pub fn checked_ident(&self) -> Ident {
quote::format_ident!("{}_checked", self.ident())
}
}

#[cfg(test)]
Expand Down
4 changes: 4 additions & 0 deletions crates/ink/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,7 @@ pub use ink_macro::{
test,
trait_definition,
};
pub use ink_primitives::{
LangError,
MessageResult,
};
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ error[E0277]: the trait bound `contract::Error: TypeInfo` is not satisfied
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
and 64 others
and $N others
= note: required for `Result<(), contract::Error>` to implement `ConstructorReturnSpec`
= note: this error originates in the attribute macro `ink::contract` (in Nightly builds, run with -Z macro-backtrace for more info)
20 changes: 20 additions & 0 deletions crates/ink/tests/ui/contract/fail/message-hygiene-checked.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#[ink::contract]
mod contract {
#[ink(storage)]
pub struct Contract {}

impl Contract {
#[ink(constructor)]
pub fn constructor() -> Self {
Self {}
}

#[ink(message)]
pub fn message(&self) {}

#[ink(message)]
pub fn message_checked(&self) {}
}
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error[E0201]: duplicate definitions with name `message_checked`:
--> tests/ui/contract/fail/message-hygiene-checked.rs:16:9
|
1 | #[ink::contract]
| ---------------- previous definition of `message_checked` here
...
16 | pub fn message_checked(&self) {}
| ^^^ duplicate definition
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ note: required by a bound in `ExecutionInput::<ArgumentList<ArgumentListEnd, Arg
| T: scale::Encode,
| ^^^^^^^^^^^^^ required by this bound in `ExecutionInput::<ArgumentList<ArgumentListEnd, ArgumentListEnd>>::push_arg`

error[E0599]: the method `fire` exists for struct `ink::ink_env::call::CallBuilder<DefaultEnvironment, Set<Call<DefaultEnvironment>>, Set<ExecutionInput<ArgumentList<ink::ink_env::call::utils::Argument<NonCodecType>, ArgumentList<ArgumentListEnd, ArgumentListEnd>>>>, Set<ReturnType<()>>>`, but its trait bounds were not satisfied
error[E0599]: the method `fire` exists for struct `ink::ink_env::call::CallBuilder<DefaultEnvironment, Set<Call<DefaultEnvironment>>, Set<ExecutionInput<ArgumentList<ink::ink_env::call::utils::Argument<NonCodecType>, ArgumentList<ArgumentListEnd, ArgumentListEnd>>>>, Set<ReturnType<Result<(), LangError>>>>`, but its trait bounds were not satisfied
--> tests/ui/contract/fail/message-input-non-codec.rs:16:9
|
16 | pub fn message(&self, _input: NonCodecType) {}
| ^^^ method cannot be called on `ink::ink_env::call::CallBuilder<DefaultEnvironment, Set<Call<DefaultEnvironment>>, Set<ExecutionInput<ArgumentList<ink::ink_env::call::utils::Argument<NonCodecType>, ArgumentList<ArgumentListEnd, ArgumentListEnd>>>>, Set<ReturnType<()>>>` due to unsatisfied trait bounds
| ^^^ method cannot be called on `ink::ink_env::call::CallBuilder<DefaultEnvironment, Set<Call<DefaultEnvironment>>, Set<ExecutionInput<ArgumentList<ink::ink_env::call::utils::Argument<NonCodecType>, ArgumentList<ArgumentListEnd, ArgumentListEnd>>>>, Set<ReturnType<Result<(), LangError>>>>` due to unsatisfied trait bounds
|
::: $WORKSPACE/crates/env/src/call/execution_input.rs
|
Expand Down
Loading