@@ -2,34 +2,37 @@ use crate::{
2
2
migrations:: MutProgramInfo ,
3
3
modifying:: * ,
4
4
visiting:: {
5
- InvalidateTypedElement , LexedFnCallInfoMut , ProgramVisitorMut , TreesVisitorMut ,
6
- TyFnCallInfo , VisitingContext ,
5
+ InvalidateTypedElement , LexedFnCallInfoMut , LexedMethodCallInfoMut , ProgramVisitorMut ,
6
+ TreesVisitorMut , TyFnCallInfo , TyMethodCallInfo , VisitingContext ,
7
7
} ,
8
8
} ;
9
9
use anyhow:: { bail, Ok , Result } ;
10
10
use sway_ast:: Expr ;
11
- use sway_core:: language:: { ty:: TyExpression , CallPath } ;
11
+ use sway_core:: {
12
+ language:: { ty:: TyExpression , CallPath } ,
13
+ TypeInfo ,
14
+ } ;
12
15
use sway_types:: { Span , Spanned } ;
13
16
14
17
use super :: { ContinueMigrationProcess , DryRun , MigrationStep , MigrationStepKind } ;
15
18
16
19
// NOTE: We do not fully support cases when `b256::from` is nested within another `b256::from`.
17
20
// E.g.: `b256::from(Bytes::from(b256::from(nested_bytes)))`.
18
21
// In such cases, only the outermost `b256::from` will be migrated.
22
+ // The same is with `Bytes::into`.
19
23
// In practice, this does not happen.
20
24
21
- #[ allow( dead_code) ]
22
- pub ( super ) const REPLACE_B256_FROM_BYTES_TO_TRY_FROM_BYTES_STEP : MigrationStep = MigrationStep {
23
- title : "Replace calls to `b256::from(<bytes>)` with `b256::try_from(<bytes>).unwrap()`" ,
25
+ pub ( super ) const REPLACE_B256_FROM_BYTES_WITH_TRY_FROM_BYTES_STEP : MigrationStep = MigrationStep {
26
+ title : "Replace `b256::from(<bytes>)` calls with `b256::try_from(<bytes>).unwrap()`" ,
24
27
duration : 0 ,
25
28
kind : MigrationStepKind :: CodeModification (
26
- replace_b256_from_bytes_to_try_from_bytes_step ,
29
+ replace_b256_from_bytes_with_try_from_bytes_step ,
27
30
& [ ] ,
28
31
ContinueMigrationProcess :: IfNoManualMigrationActionsNeeded ,
29
32
) ,
30
33
help : & [
31
- "Migration will replace all the calls to `b256::from(<bytes>)` with " ,
32
- "`b256::try_from(<bytes>).unwrap()`." ,
34
+ "Migration will replace all the `b256::from(<bytes>)` calls " ,
35
+ "with `b256::try_from(<bytes>).unwrap()`." ,
33
36
" " ,
34
37
"E.g.:" ,
35
38
" let result = b256::from(some_bytes);" ,
@@ -38,7 +41,26 @@ pub(super) const REPLACE_B256_FROM_BYTES_TO_TRY_FROM_BYTES_STEP: MigrationStep =
38
41
] ,
39
42
} ;
40
43
41
- fn replace_b256_from_bytes_to_try_from_bytes_step (
44
+ pub ( super ) const REPLACE_BYTES_INTO_B256_WITH_TRY_INTO_B256_STEP : MigrationStep = MigrationStep {
45
+ title : "Replace `<bytes>.into()` calls with `<bytes>.try_into().unwrap()`" ,
46
+ duration : 0 ,
47
+ kind : MigrationStepKind :: CodeModification (
48
+ replace_bytes_into_b256_with_try_into_b256_step,
49
+ & [ ] ,
50
+ ContinueMigrationProcess :: IfNoManualMigrationActionsNeeded ,
51
+ ) ,
52
+ help : & [
53
+ "Migration will replace all the `<bytes>.into()` calls resulting in \" b256\" " ,
54
+ "with `<bytes>.try_into().unwrap()`." ,
55
+ " " ,
56
+ "E.g.:" ,
57
+ " let result: b256 = some_bytes.into();" ,
58
+ "will become:" ,
59
+ " let result: b256 = some_bytes.try_into().unwrap();" ,
60
+ ] ,
61
+ } ;
62
+
63
+ fn replace_b256_from_bytes_with_try_from_bytes_step (
42
64
program_info : & mut MutProgramInfo ,
43
65
dry_run : DryRun ,
44
66
) -> Result < Vec < Span > > {
@@ -113,3 +135,78 @@ fn replace_b256_from_bytes_to_try_from_bytes_step(
113
135
114
136
ProgramVisitorMut :: visit_program ( program_info, dry_run, & mut Visitor { } )
115
137
}
138
+
139
+ fn replace_bytes_into_b256_with_try_into_b256_step (
140
+ program_info : & mut MutProgramInfo ,
141
+ dry_run : DryRun ,
142
+ ) -> Result < Vec < Span > > {
143
+ struct Visitor ;
144
+ impl TreesVisitorMut < Span > for Visitor {
145
+ fn visit_method_call (
146
+ & mut self ,
147
+ ctx : & VisitingContext ,
148
+ lexed_method_call : & mut Expr ,
149
+ ty_method_call : Option < & TyExpression > ,
150
+ output : & mut Vec < Span > ,
151
+ ) -> Result < InvalidateTypedElement > {
152
+ let lexed_method_call_info = LexedMethodCallInfoMut :: new ( lexed_method_call) ?;
153
+ let ty_method_call_info = ty_method_call
154
+ . map ( |ty_method_call| TyMethodCallInfo :: new ( ctx. engines . de ( ) , ty_method_call) )
155
+ . transpose ( ) ?;
156
+
157
+ // We need the typed info in order to ensure that the `into` function
158
+ // is really the `Bytes::into(self) -> b256` function.
159
+ let Some ( ty_method_call_info) = ty_method_call_info else {
160
+ return Ok ( InvalidateTypedElement :: No ) ;
161
+ } ;
162
+
163
+ let method_return_type = ctx
164
+ . engines
165
+ . te ( )
166
+ . get ( ty_method_call_info. fn_decl . return_type . type_id ) ;
167
+ let method_target_is_bytes_struct = match ctx
168
+ . engines
169
+ . te ( )
170
+ . get ( ty_method_call_info. parent_type_id )
171
+ . as_ref ( )
172
+ {
173
+ TypeInfo :: Struct ( decl_id) => {
174
+ let struct_decl = ctx. engines . de ( ) . get_struct ( decl_id) ;
175
+ struct_decl. call_path == CallPath :: fullpath ( & [ "std" , "bytes" , "Bytes" ] )
176
+ }
177
+ _ => false ,
178
+ } ;
179
+
180
+ if !( ty_method_call_info. fn_decl . name . as_str ( ) == "into"
181
+ && matches ! ( method_return_type. as_ref( ) , TypeInfo :: B256 )
182
+ && method_target_is_bytes_struct)
183
+ {
184
+ return Ok ( InvalidateTypedElement :: No ) ;
185
+ }
186
+
187
+ // We have found a `Bytes::into(self) -> b256` call.
188
+ output. push ( lexed_method_call_info. path_seg . span ( ) ) ;
189
+
190
+ if ctx. dry_run == DryRun :: Yes {
191
+ return Ok ( InvalidateTypedElement :: No ) ;
192
+ }
193
+
194
+ let lexed_into_path = match lexed_method_call {
195
+ Expr :: MethodCall { path_seg, .. } => path_seg,
196
+ _ => bail ! ( "`lexed_method_call` must be of the variant `Expr::MethodCall`." ) ,
197
+ } ;
198
+
199
+ // Rename the call to `into` to `try_into`.
200
+ modify ( lexed_into_path) . set_name ( "try_into" ) ;
201
+
202
+ // The call to `try_into` becomes the target of the `unwrap` method call.
203
+ let target = lexed_method_call. clone ( ) ;
204
+ let insert_span = Span :: empty_at_end ( & target. span ( ) ) ;
205
+ * lexed_method_call = New :: method_call ( insert_span, target, "unwrap" ) ;
206
+
207
+ Ok ( InvalidateTypedElement :: Yes )
208
+ }
209
+ }
210
+
211
+ ProgramVisitorMut :: visit_program ( program_info, dry_run, & mut Visitor { } )
212
+ }
0 commit comments