Releases: onflow/cadence
v1.10.3
What's Changed
This update mainly focuses on improving safety and consistency in Cadence. As part of this effort, several changes have been introduced to prevent accidental foot-guns by users.
Changed function signature for filter and map array-functions
A breaking change was introduced for filter and map to make them consistent with for-in loops and indexed array access.
If filter or map is used on an array reference whose element type is itself a container type (e.g. struct, resource, array, or dictionary), then the callback parameter must now also be a reference type.
For example, assume S is a struct type and arrayRef is a reference to an array of S structs as shown below.
access(all) struct S {}
var array: [S] = [S()]
var arrayRef: &[S] = &arrayThen, previously, using the filter function on this array-reference required a callback of type fun(S): Bool:
var filteredArray = arrayRef.filter(
// Note the parameter type used to be `S`
view fun(element: S): Bool {
return true
},
)From this release onwards, the filter method was changed to require a callback of type fun(&S): Bool:
var filteredArray = arrayRef.filter(
// Note the parameter type is now a reference type `&S`
view fun(element: &S): Bool {
return true
},
)Similarly, for map method, the callback that needs to be passed-in must have a reference type (&S) parameter.
var mappedArray = arrayRef.map(
// Note the parameter type is now a reference type `&S`
view fun(element: &S): Int {
return 1
},
)Erase entitlements when assigned to AnyStruct
Previously, authorized references retained their entitlements when upcast to AnyStruct.
var authRef: auth(E) &T = ...
// Assign to `AnyStruct`
var any: AnyStruct = authRef
// Can get the auth-ref back by down-casting
var downCastedAuthRef = any as! auth(E) &THowever, this behaviour was inconsistent with normal reference upcasting, where entitlements are stripped to match the target type.
This inconsistency could lead developers to incorrectly assume that upcasting to AnyStruct also strips entitlements.
From this release onward, upcasting to AnyStruct behaves the same as other reference upcasts and strips entitlements during the cast.
var authRef: auth(E) &T = ...
// Assign to `AnyStruct`
var any: AnyStruct = authRef
// This would panic at runtime, since the entitlements were stripped during the up-cast in the previous step.
var downCastedAuthRef = any as! auth(E) &TRun conditions of inherited default functions
Previously, when an interface default function also defines conditions, and the concrete type overrides the default function as shown below, then the conditions also get overridden.
resource interface Receiver {
// Default function also defines a condition.
fun log(_ message: String) {
pre{ message != "" }
log(message.append("from Receiver"))
}
}
resource Vault: Receiver {}
// `log` function is overridden.
// This also overrides the condition (i.e: ignores conditions from `Receiver` interface).
fun log(_ message: String) {
log(message)
}
}This has been a foot-gun because the author of the interface might not be aware that the conditions are getting ignored/overridden too.
Therefore, to avoid that, the behaviour was changed such that the conditions are always run, regardless of whether the concrete type implements/override the default implementation or not.
resource Vault: Receiver {}
// `log` function is overridden.
// However, the conditions won't get overridden.
// The condition defined on the interface would still be applicable.
fun log(_ message: String) {
log(message)
}
}Intersect authorizations for nested references
When a nested authorized reference is accessed via an unauthorized reference (e.g: an array reference of type &[auth(E) &T] and then accessing the element refs[0]), the inner authorized reference auth(E) &T was returned as is. However, this behaviour was not well defined in the member-access semantics proposal FLIP 89, and was not very intuitive, leaving potential of accidental foot-guns.
var arrayRef: &[auth(E) &T] = ...
// The resulting type used to be the entitled-type `auth(E) &T`
var element: auth(E) &T = arrayRef[0]Therefore, this was changed such that the result's authorization would now be the intersection of the outer (container) reference's authorization and the inner (element) reference's authorization.
var arrayRef: &[auth(E) &T] = ...
// The resulting type now is the un-entitled type `&T`
var element: &T = arrayRef[0]The intersection is computed as follows:
-
Index Access (arrays, dictionaries)
Container Type Old Result New Result auth(E) &[&T]&T&T(no change — inner is already unauthorized)&[auth(E) &T]auth(E) &T&T(outer unauthorized strips inner)auth(E) &[auth(E) &T]auth(E) &Tauth(E) &T(no change — intersection preserves matching auth)auth(E,F) &[auth(F,G) &T]auth(F,G) &Tauth(F) &T(only F is in both)auth(E) &[auth(F) &T]auth(F) &T&T(E and F are disjoint, empty intersection)For dictionaries, the same rules apply, e.g.,
auth(E) &{String: auth(E) &T}gives(auth(E) &T)?. Unauthorized outer strips inner auth, same as arrays. -
Member Access (composites)
The outer authorization for intersection is the raw outer reference's authorization (not mapped, since
access(mapping M)fields cannot have reference types).Container Type Old Result New Result &Swith fieldlet x: auth(E) &Tauth(E) &T&T(outer unauthorized strips inner)auth(E) &Swith fieldlet x: auth(E) &Tauth(E) &Tauth(E) &T(matching auth preserved)auth(E,F) &Swith fieldlet x: auth(F,G) &Tauth(F,G) &Tauth(F) &T(partial intersection)auth(E) &Swith fieldlet x: auth(F) &Tauth(F) &T&T(disjoint, empty intersection)
Complete List of Changes:
⭐ Features
- Add tool which allows changing contract in CSV by @turbolent in #4486
🛠 Improvements
- Improve decode-slab tool by @turbolent in #4458
- Make coverage report thread-safe by @turbolent in #4476
- Parallelize execution of compat suites by @turbolent in #4479
- Improve version bump by @turbolent in #4490
🐞 Bug Fixes
- Fix AST walking by @turbolent in #4471
🧪 Testing
- Test crypto algorithm enum case values by @turbolent in #4472
📖 Documentation
- docs: add TL;DR, FAQ, and GEO enhancements for discoverability by @Aliserag in #4480
- docs: followup SEO/GEO audit fixes by @Aliserag in #4481
Other Changes
- Merge
release/v1.10.2tomasterby @github-actions[bot] in #4467 - Return user-facing error from Test.readFile on file-not-found by @holyfuchs in #4469
- docs: add AGENTS.md by @Aliserag in #4482
- Port v1.10.3-rc.3 by @turbolent in #4488
- Fix version in NPM package by @turbolent in #4489
New Contributors
Full Changelog: v1.10.2...v1.10.3
v1.10.2
What's Changed
⭐ Features
- Add comparison functions by @turbolent in #4430
- Add a new
StringBuildertype which allows constructing strings efficiently by @turbolent in #4453 - Add
guardstatement by @turbolent in #4432 - Add
freezeTimeandunfreezeTimetoTeststdlib Blockchain interface by @holyfuchs in #4466
🛠 Improvements
- Improve defensive check for invalid type error reporting by @turbolent in #4456
- Update update tool by @turbolent in #4459
- Add ComputationUsed to TransactionResult in test framework by @holyfuchs in #4455
- Prevent invalid changes to enums by @turbolent in #4463
📖 Documentation
Other Changes
- Merge
release/v1.10.1tomasterby @github-actions[bot] in #4462 - Update to atree v0.16.0 by @turbolent in #4464
New Contributors
- @holyfuchs made their first contribution in #4455
Full Changelog: v1.10.1...v1.10.2
v1.10.1
What's Changed
🐞 Bug Fixes
- Port v1.10.1-rc.1 by @turbolent in #4460
Other Changes
- Merge
release/v1.10.0tomasterby @github-actions[bot] in #4454 - Bump to atree v0.15 and fxamacker/cbor v2.9.1 stream-mode branch by @fxamacker in #4457
- Fix NPM package version by @turbolent in #4461
Full Changelog: v1.10.0...v1.10.1
v1.10.0
What's Changed
⭐ Features
- Add ReadOnlyLoaded iterator for the DomainStorageMap by @janezpodhostnik in #4442
🛠 Improvements
- Improve AST walking by @turbolent in #4434
- Improve Source Compatibility Suite by @turbolent in #4428
- Improve assertions for instructions by introducing "pretty" instructions by @turbolent in #4423
- Optimize Cadence ArrayValue and Go []byte conversions (up to 13.7x faster and 8x less memory) by @fxamacker in #4443
- Assert pretty instructions by @turbolent in #4451
- Optimize transferring array, dict, and composite (e.g., 2x faster for byte arrays) by @fxamacker in #4448
- Replace mapLoadedValueIterator wrapper by using Atree implementation by @fxamacker in #4449
- Add support for for-in looping/iterating over the keys of dictionaries by @turbolent in #4436
🐞 Bug Fixes
- Port v1.9.9-rc.2 by @turbolent in #4440
- Fix syntax error test by @turbolent in #4438
Other Changes
- Update changelog by @turbolent in #4435
- Merge
release/v1.9.9tov1.9by @github-actions[bot] in #4441 - Port v1.9.10-rc.1 by @turbolent in #4445
Full Changelog: v1.9.9...v1.10.0
v1.9.10
What's Changed
🛠 Improvements
- [v1.9] Port v1.9.10-rc.1 by @turbolent in #4444
Other Changes
- Merge
release/v1.9.9tov1.9by @github-actions[bot] in #4441
Full Changelog: v1.9.9...v1.9.10
v1.9.9
What's Changed
🐞 Bug Fixes
- [v1.9] Port v1.9.9-rc.2 by @turbolent in #4439
Other Changes
- Merge
release/v1.9.8tomasterby @github-actions[bot] in #4433
Full Changelog: v1.9.8...v1.9.9
v1.9.8
What's Changed
🐞 Bug Fixes
- Port v1.9.8-rc.2 by @turbolent in #4431
Other Changes
- Merge
release/v1.9.7tomasterby @github-actions[bot] in #4426
Full Changelog: v1.9.7...v1.9.8
v1.9.7
What's Changed
🐞 Bug Fixes
- Port v1.9.7-rc.1 by @turbolent in #4424
Other Changes
- Merge
release/v1.9.6tomasterby @github-actions[bot] in #4422 - Update to atree v0.12.1 by @turbolent in #4425
Full Changelog: v1.9.6...v1.9.7
v1.9.6
What's Changed
🐞 Bug Fixes
- Remove special handling of empty identifier in member access by @turbolent in #4419
- Fix string template expression parsing with quoted quotes by @turbolent in #4420
- Fix ComputationProfile holding on to environment reference by @janezpodhostnik in #4418
- [Compiler] Enable compiler for remaining account tests by @turbolent in #4421
Other Changes
- Merge
release/v1.9.5tomasterby @github-actions[bot] in #4416
Full Changelog: v1.9.5...v1.9.6
v1.9.5
What's Changed
⭐ Features
- [Compiler] Validate static argument types in contract initializer by @turbolent in #4411
🛠 Improvements
- Avoid unnecessary repeated type conversions by @turbolent in #4409
- Improve comments in generated Go code by @turbolent in #4414
- Add the variable declaration value's actual type to the elaboration by @turbolent in #4415
- Add support for decoding into cadence.Address and *big.Int by @turbolent in #4412
🐞 Bug Fixes
- [Compiler] Remove additional transfers of indexing values in swap statements by @turbolent in #4413
Other Changes
- Merge
release/v1.9.4tomasterby @github-actions[bot] in #4410
Full Changelog: v1.9.4...v1.9.5