diff --git a/CHANGELOG.md b/CHANGELOG.md index c7500d41e..f9c237f96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Optional types for `self` argument in `extends mutates` functions are now allowed: PR [#854](https://github.com/tact-lang/tact/pull/854) + ### Fixed - Collisions in getter method ids are now handled and reported properly: PR [#875](https://github.com/tact-lang/tact/pull/875) diff --git a/src/generator/writers/writeExpression.ts b/src/generator/writers/writeExpression.ts index 2ee49d62d..df1e33845 100644 --- a/src/generator/writers/writeExpression.ts +++ b/src/generator/writers/writeExpression.ts @@ -558,13 +558,6 @@ export function writeExpression(f: AstExpression, wCtx: WriterContext): string { // Reference type if (selfTyRef.kind === "ref") { - if (selfTyRef.optional) { - throwCompilationError( - `Cannot call function of non - direct type: "${printTypeRef(selfTyRef)}"`, - f.loc, - ); - } - // Render function call const selfTy = getType(wCtx.ctx, selfTyRef.name); diff --git a/src/generator/writers/writeFunction.ts b/src/generator/writers/writeFunction.ts index 15216d0c4..79cccaa43 100644 --- a/src/generator/writers/writeFunction.ts +++ b/src/generator/writers/writeFunction.ts @@ -503,7 +503,7 @@ function writeCondition( export function writeFunction(f: FunctionDescription, ctx: WriterContext) { // Resolve self - const self = f.self ? getType(ctx.ctx, f.self) : null; + const self = f.self?.kind === "ref" ? getType(ctx.ctx, f.self.name) : null; // Write function header let returns: string = resolveFuncType(f.returns, ctx); @@ -683,7 +683,7 @@ function writeNonMutatingFunction( export function writeGetter(f: FunctionDescription, ctx: WriterContext) { // Render tensors - const self = f.self !== null ? getType(ctx.ctx, f.self) : null; + const self = f.self?.kind === "ref" ? getType(ctx.ctx, f.self.name) : null; if (!self) { throw new Error(`No self type for getter ${idTextErr(f.name)}`); // Impossible } diff --git a/src/storage/__snapshots__/resolveAllocation.spec.ts.snap b/src/storage/__snapshots__/resolveAllocation.spec.ts.snap index 8fef304b6..274c24bff 100644 --- a/src/storage/__snapshots__/resolveAllocation.spec.ts.snap +++ b/src/storage/__snapshots__/resolveAllocation.spec.ts.snap @@ -2293,7 +2293,11 @@ exports[`resolveAllocation should write program 1`] = ` "returns": { "kind": "void", }, - "self": "Sample", + "self": { + "kind": "ref", + "name": "Sample", + "optional": false, + }, }, }, "header": null, diff --git a/src/test/e2e-emulated/contracts/mutating-method-chaining.tact b/src/test/e2e-emulated/contracts/mutating-methods.tact similarity index 73% rename from src/test/e2e-emulated/contracts/mutating-method-chaining.tact rename to src/test/e2e-emulated/contracts/mutating-methods.tact index d7e8b2627..aac3bf439 100644 --- a/src/test/e2e-emulated/contracts/mutating-method-chaining.tact +++ b/src/test/e2e-emulated/contracts/mutating-methods.tact @@ -1,8 +1,17 @@ +asm(value key self keySize) extends mutates fun nativeUdictStoreUint(self: Cell?, keySize: Int, key: Int, value: Slice) { DICTUSET } + extends mutates fun multiply(self: Int, x: Int): Int { self *= x; return self; } +extends fun multiplyExtends(self: Int?, x: Int): Int? { + if (self == null) { + return null; + } + return self!! * x; +} + struct Foo { s: Slice; } @@ -64,4 +73,15 @@ contract Tester { self.s.loadUint(1); return self.s.loadUint(3); } + + get fun test10(dict: Cell?): Cell? { + dict.nativeUdictStoreUint(8, 123, rawSlice("456")); + return dict; + } + + get fun test11(x: Int?): Int? { + x.multiplyExtends(2); + x.multiplyExtends(2).multiplyExtends(3); + return x.multiplyExtends(2).multiplyExtends(3); + } } \ No newline at end of file diff --git a/src/test/e2e-emulated/contracts/semantics.tact b/src/test/e2e-emulated/contracts/semantics.tact index e30c9e5ec..0ba57c58d 100644 --- a/src/test/e2e-emulated/contracts/semantics.tact +++ b/src/test/e2e-emulated/contracts/semantics.tact @@ -13,7 +13,8 @@ struct SC { c1: Int; } -// Wrapper struct in order to pass maps to mutating functions. See issue #815 +// Wrapper struct in order to pass maps to mutating functions. See issue #815. +// Also, it is useful for nesting maps inside maps. struct MapWrapper { m: map } @@ -47,6 +48,29 @@ extends mutates fun changeSomeFields(self: SA) { self.a2.b2.c1 += 1; } +extends fun copyStruct(self: SA): SA { + // Since structs are passed by value, "self" will be a copy of the struct given as parameter + return self; +} + +// Identity function, just to test chaining of mutating functions. +extends mutates fun reflectStruct(self: SA): SA { + return self; +} + +extends mutates fun incrementIntFields(self: SA): SA { + self.a1 += 1; + self.a2.b2.c1 += 1; + self.a2.b3 += 1; + return self; +} + +extends mutates fun flipBooleanFields(self: SA): SA { + self.a2.b1 = !self.a2.b1; + return self; +} + + /**** Auxiliary functions for maps **********/ fun getNewMap(m: map): map { @@ -137,6 +161,27 @@ extends mutates fun changeSomeEntries(self: MapWrapper) { self.m.del(3); } +extends fun unwrapAndCopyMap(self: MapWrapper): map { + // Since structs are passed by value, "self" will be a copy of the wrapped map given as parameter + // Hence, the unwrapped map is a copy of the map. + return self.m; +} + +extends mutates fun unwrapMap(self: MapWrapper): map { + // Even though "self" is a copy, the mutates function will assign the copy back into "self" once the function finishes. + // Observe that the function will return a copy of the wrapped map as well. + // This means that there are actually TWO assignments when one does something like this: + // m = wm.unwrapMap(); + // After "unwrapMap" finishes execution, wm will be reassigned with the copy of self (which in this case is identical + // to the input to "unwrapMap"), and m will be assigned with "self.m" (computed using the copy of "self"). + return self.m; +} + +// Identity function, just to test chaining of mutating functions. +extends mutates fun reflectMap(self: MapWrapper): MapWrapper { + return self; +} + /**** Auxiliary functions for contracts **********/ fun copyAndModifyContract(c: SemanticsTester): SemanticsTester { @@ -161,6 +206,45 @@ extends mutates fun changeSomeContractFields(self: SemanticsTester) { self.sA.a2.b2.c1 += 30; } +// Identity function, but as a simple extends function. +extends fun copyContract(self: SemanticsTester): SemanticsTester { + return self; +} + +// Identity function, just to test chaining of mutating functions. +extends mutates fun reflectContract(self: SemanticsTester): SemanticsTester { + return self; +} + +extends mutates fun incrementIntFieldsInUB(self: SemanticsTester): SemanticsTester { + self.uB.b2.c1 += 1; + self.uB.b3 += 1; + return self; +} + +extends mutates fun flipBooleanFieldsInUB(self: SemanticsTester): SemanticsTester { + self.uB.b1 = !self.uB.b1; + return self; +} + + +/**** Auxiliary functions for integers **********/ + +extends mutates fun multiplyBy2(self: Int): Int { + self *= 2; + return self; +} + +extends mutates fun increment(self: Int): Int { + self += 1; + return self; +} + +extends mutates fun doNothing(self: Int): Int { + return self; +} + + contract SemanticsTester { // Currently, declaring fields like this: @@ -189,6 +273,8 @@ contract SemanticsTester { mA: map; mB: map; + mC: map; // Simulate nested maps by wrapping them in a struct, + // "Morally", mC has type map>. // Flag storing the result of calling method mutateContractState. @@ -219,7 +305,7 @@ contract SemanticsTester { // Initialize the mA map self.mA.set(1, self.sA); // The compiler does not complain that self.mA is not initialized, because // map fields in contracts are implicitly initialized as empty. - // Function checkMapInit will later check this + // Function checkMapInit will later check this. // Make a copy of sA to assign a different key value pair in the map let s = self.sA; @@ -235,6 +321,10 @@ contract SemanticsTester { self.mA.set(3, s); + // Initialize the mC map. The nested map will contain a copy of self.sA. + let nestedMap = MapWrapper {m: emptyMap()}; + nestedMap.m.set(10, self.sA); + self.mC.set(100, nestedMap); /****** Contracts *****/ @@ -311,6 +401,20 @@ contract SemanticsTester { result &&= (k == 1 || k == 2 || k == 3); } + // The map self.mC has a single entry 100 -> MapWrapper {m: 10 -> self.sA}. + foreach (k1, v1 in self.mC) { + foreach (k2, v2 in v1.m) { + result &&= + k1 == 100 && + k2 == 10 && + + v2.a1 == 20 && + v2.a2.b1 == true && + v2.a2.b2.c1 == 5 && + v2.a2.b3 == 10; + } + } + return result; } @@ -418,6 +522,249 @@ contract SemanticsTester { s.a2.b3 == 10; } + get fun testReturnedStructs(): Bool { + // The call to the non-mutating extends function "copyStruct" always makes a copy + // of the parameter struct. Therefore, passing the result to the mutating function + // "changeSomeFields" will modify the copy, not the original struct. + + self.sA.copyStruct().changeSomeFields(); + + let result = + self.checkAllContractFieldsAreUnchanged(); + + // For the following test, make a copy of self.sA. + let s = self.sA; + + // What is the effect of executing the following line? + + s.reflectStruct().changeSomeFields(); + + // First, reflectStruct makes a copy of s. When reflectStruct finalizes, it assigns the copy back into + // s. Additionally, reflectStruct returns the copy of s, call it s'. + // s' is then passed to changeSomeFields, which makes again a copy of s', call it s''. + // changeSomeFields changes some fields of s'' and reassigns s' with this changed s''. + // Additionally changeSomeFields returns the changed s''. + // Note that the only place where s is reassigned is after reflectStruct executes. + // This means that the above expression does NOT change s. + + result &&= + self.checkAllContractFieldsAreUnchanged() && + s.a1 == 20 && + s.a2.b1 == true && + s.a2.b2.c1 == 5 && + s.a2.b3 == 10; + + // Therefore, if we actually want to change s using changeSomeFields, we + // should split the chain steps: + + s.reflectStruct(); // Each step changes s + s.changeSomeFields(); + + // Note that doing the trick of assigning back s + // + // s = s.reflectStruct().changeSomeFields(); + // + // is not possible because changeSomeFields has void return type. + + // s is now changed by changeSomeFields, and the rest remains the same + result &&= + self.checkAllContractFieldsAreUnchanged() && + s.a1 == 120 && + s.a2.b1 == true && + s.a2.b2.c1 == 6 && + s.a2.b3 == 10; + + // For further examples of chaining of mutating functions, see the tests mutatesChainStruct + + return result; + } + + /* + The following functions exemplify how to properly chain mutating functions. + Each function in the chain returns a copy to the next function in the chain. + Hence, to change the original variable, we need to reassign the value returned + from the last mutating function. + */ + + get fun mutatesChainStruct1(): Bool { + let s = self.sA; + s.reflectStruct().incrementIntFields().flipBooleanFields(); // s changed only by the first function + + let t = self.sA; + t = t.reflectStruct().incrementIntFields().flipBooleanFields(); // Assign back to t the struct returned by the last function + + // The less confusing solution is to simply break the chain. + // This solution even works when the last function in the chain has void return type. + // Each step changes z + let z = self.sA; + z.reflectStruct(); + z.incrementIntFields(); + z.flipBooleanFields(); + + return self.checkAllContractFieldsAreUnchanged() && + s.a1 == 20 && + s.a2.b1 == true && + s.a2.b2.c1 == 5 && + s.a2.b3 == 10 && + + t.a1 == 21 && + t.a2.b1 == false && + t.a2.b2.c1 == 6 && + t.a2.b3 == 11 && + + z.a1 == 21 && + z.a2.b1 == false && + z.a2.b2.c1 == 6 && + z.a2.b3 == 11; + + } + + get fun mutatesChainStruct2(): Bool { + let s = self.sA; + s.reflectStruct().flipBooleanFields().incrementIntFields(); + + let t = self.sA; + t = t.reflectStruct().flipBooleanFields().incrementIntFields(); + + let z = self.sA; + z.reflectStruct(); + z.flipBooleanFields(); + z.incrementIntFields(); + + return self.checkAllContractFieldsAreUnchanged() && + s.a1 == 20 && + s.a2.b1 == true && + s.a2.b2.c1 == 5 && + s.a2.b3 == 10 && + + t.a1 == 21 && + t.a2.b1 == false && + t.a2.b2.c1 == 6 && + t.a2.b3 == 11 && + + z.a1 == 21 && + z.a2.b1 == false && + z.a2.b2.c1 == 6 && + z.a2.b3 == 11; + } + + get fun mutatesChainStruct3(): Bool { + let s = self.sA; + s.incrementIntFields().reflectStruct().flipBooleanFields(); + + let t = self.sA; + t = t.incrementIntFields().reflectStruct().flipBooleanFields(); + + let z = self.sA; + z.incrementIntFields(); + z.reflectStruct(); + z.flipBooleanFields(); + + return self.checkAllContractFieldsAreUnchanged() && + s.a1 == 21 && + s.a2.b1 == true && + s.a2.b2.c1 == 6 && + s.a2.b3 == 11 && + + t.a1 == 21 && + t.a2.b1 == false && + t.a2.b2.c1 == 6 && + t.a2.b3 == 11 && + + z.a1 == 21 && + z.a2.b1 == false && + z.a2.b2.c1 == 6 && + z.a2.b3 == 11; + } + + get fun mutatesChainStruct4(): Bool { + let s = self.sA; + s.incrementIntFields().flipBooleanFields().reflectStruct(); + + let t = self.sA; + t = t.incrementIntFields().flipBooleanFields().reflectStruct(); + + let z = self.sA; + z.incrementIntFields(); + z.flipBooleanFields(); + z.reflectStruct(); + + return self.checkAllContractFieldsAreUnchanged() && + s.a1 == 21 && + s.a2.b1 == true && + s.a2.b2.c1 == 6 && + s.a2.b3 == 11 && + + t.a1 == 21 && + t.a2.b1 == false && + t.a2.b2.c1 == 6 && + t.a2.b3 == 11 && + + z.a1 == 21 && + z.a2.b1 == false && + z.a2.b2.c1 == 6 && + z.a2.b3 == 11; + } + + get fun mutatesChainStruct5(): Bool { + let s = self.sA; + s.flipBooleanFields().incrementIntFields().reflectStruct(); + + let t = self.sA; + t = t.flipBooleanFields().incrementIntFields().reflectStruct(); + + let z = self.sA; + z.flipBooleanFields(); + z.incrementIntFields(); + z.reflectStruct(); + + return self.checkAllContractFieldsAreUnchanged() && + s.a1 == 20 && + s.a2.b1 == false && + s.a2.b2.c1 == 5 && + s.a2.b3 == 10 && + + t.a1 == 21 && + t.a2.b1 == false && + t.a2.b2.c1 == 6 && + t.a2.b3 == 11 && + + z.a1 == 21 && + z.a2.b1 == false && + z.a2.b2.c1 == 6 && + z.a2.b3 == 11; + } + + get fun mutatesChainStruct6(): Bool { + let s = self.sA; + s.flipBooleanFields().reflectStruct().incrementIntFields(); + + let t = self.sA; + t = t.flipBooleanFields().reflectStruct().incrementIntFields(); + + let z = self.sA; + z.flipBooleanFields(); + z.reflectStruct(); + z.incrementIntFields(); + + return self.checkAllContractFieldsAreUnchanged() && + s.a1 == 20 && + s.a2.b1 == false && + s.a2.b2.c1 == 5 && + s.a2.b3 == 10 && + + t.a1 == 21 && + t.a2.b1 == false && + t.a2.b2.c1 == 6 && + t.a2.b3 == 11 && + + z.a1 == 21 && + z.a2.b1 == false && + z.a2.b2.c1 == 6 && + z.a2.b3 == 11; + } + + /*************** Maps ********************/ // Assigning a map to a variable preserves contents @@ -595,6 +942,262 @@ contract SemanticsTester { return result; } + get fun testReturnedMaps1(): Bool { + // The "get" function for maps always creates a copy of the input map + // because "get" is a non-mutating function. This means that + // the following expression will not change the struct in entry 2 of self.mA, + // even if "changeSomeFields" is a mutating function for structs. + // The mutating function "changeSomeFields" is changing the copy + // returned by "get". + + self.mA.get(2)!!.changeSomeFields(); + + // Everything remains the same + + return self.checkAllContractFieldsAreUnchanged(); + } + + /* + The following test cannot be carried out because FunC reports errors. See issue #866. + But the comments inside the test are good hypotheses of what I expect it will happen + when the issue is resolved, because this is what happens in the case of structs (see + function testReturnedStructs). + + get fun testReturnedMaps2(): Bool { + // The call to the non-mutating extends function "unwrapAndCopyMap" always makes a copy + // of the parameter. Therefore, passing the result to the mutating function + // "del" will modify the copy, not the original. + + let wm = MapWrapper {m: self.mA}; + + wm.unwrapAndCopyMap().del(1); // FunC error: issue #866 + + // The contract fields remain the same and also wm + let result = + self.checkAllContractFieldsAreUnchanged() && + wm.m.get(1)!!.a1 == 20 && + wm.m.get(1)!!.a2.b1 == true && + wm.m.get(1)!!.a2.b2.c1 == 5 && + wm.m.get(1)!!.a2.b3 == 10 && + + wm.m.get(2)!!.a1 == 20 && + wm.m.get(2)!!.a2.b1 == true && + wm.m.get(2)!!.a2.b2.c1 == 100 && + wm.m.get(2)!!.a2.b3 == 0 && + + wm.m.get(3)!!.a1 == 5 && + wm.m.get(3)!!.a2.b1 == false && + wm.m.get(3)!!.a2.b2.c1 == 150 && + wm.m.get(3)!!.a2.b3 == 0; + + foreach (k, _ in wm.m) { + result &&= (k == 1 || k == 2 || k == 3); + } + + // Instead, passing "wm" to the mutating function "unwrapMap", + // will return a copy of "wm.m", which is then given as input to "del". + // This means that the following expression does not delete entry 1 + // from wm.m, but deleted from the copy of wm.m: + + wm.unwrapMap().del(1); // FunC error: issue #866 + + // The contract fields remain the same and also wm + result &&= + self.checkAllContractFieldsAreUnchanged() && + wm.m.get(1)!!.a1 == 20 && + wm.m.get(1)!!.a2.b1 == true && + wm.m.get(1)!!.a2.b2.c1 == 5 && + wm.m.get(1)!!.a2.b3 == 10 && + + wm.m.get(2)!!.a1 == 20 && + wm.m.get(2)!!.a2.b1 == true && + wm.m.get(2)!!.a2.b2.c1 == 100 && + wm.m.get(2)!!.a2.b3 == 0 && + + wm.m.get(3)!!.a1 == 5 && + wm.m.get(3)!!.a2.b1 == false && + wm.m.get(3)!!.a2.b2.c1 == 150 && + wm.m.get(3)!!.a2.b3 == 0; + + foreach (k, _ in wm.m) { + result &&= (k == 1 || k == 2 || k == 3); + } + + // Since unwrapMap always returns a copy of wm.m, it is not possible + // to delete entries indirectly through the use of unwrapMap. + // Therefore, the only way is to directly unwrap the map: + + wm.m.del(1); + + // The contract fields remain the same and wm only lost entry 1 + result &&= + self.checkAllContractFieldsAreUnchanged() && + + wm.m.get(2)!!.a1 == 20 && + wm.m.get(2)!!.a2.b1 == true && + wm.m.get(2)!!.a2.b2.c1 == 100 && + wm.m.get(2)!!.a2.b3 == 0 && + + wm.m.get(3)!!.a1 == 5 && + wm.m.get(3)!!.a2.b1 == false && + wm.m.get(3)!!.a2.b2.c1 == 150 && + wm.m.get(3)!!.a2.b3 == 0; + + foreach (k, _ in wm.m) { + result &&= (k == 2 || k == 3); + } + + // Hence, chaining mutating functions to attempt to delete another entry, + // will not change wm, because those functions always return copies: + + wm.reflectMap().unwrapMap().del(2); // FunC error: issue #866 + + // The contract fields remain the same and wm remains as in the previous step + result &&= + self.checkAllContractFieldsAreUnchanged() && + + wm.m.get(2)!!.a1 == 20 && + wm.m.get(2)!!.a2.b1 == true && + wm.m.get(2)!!.a2.b2.c1 == 100 && + wm.m.get(2)!!.a2.b3 == 0 && + + wm.m.get(3)!!.a1 == 5 && + wm.m.get(3)!!.a2.b1 == false && + wm.m.get(3)!!.a2.b2.c1 == 150 && + wm.m.get(3)!!.a2.b3 == 0; + + foreach (k, _ in wm.m) { + result &&= (k == 2 || k == 3); + } + + return result; + } + + FINISHES Test that cannot be carried out. + */ + + get fun mutateNestedMap1(): Bool { + // Make a local copy of self.mC for the tests. + let m = self.mC; + + // The map m has the single entry 100 -> MapWrap {m: 10 -> copy of self.sA} + + // Modify the internal struct in m + // This should not change self.mC. + + // Note that it is not possible to change the internal struct directly using: + + // m.get(100)!!.m.get(10)!!.a2.b2.c1 = XXX; + + // because the left side of an assignment must be a path expression. + // Hence, we need to assign the struct first into a variable: + + let s = m.get(100)!!.m.get(10)!!; + + // But recall that s is a COPY of the struct inside the nested map (since assignments are always by value). + // Indeed, if we change s, the nested map in m does not change. + + s.a2.b2.c1 = 1000; + + // Check that s does change + + let result = s.a1 == 20 && + s.a2.b1 == true && + s.a2.b2.c1 == 1000 && + s.a2.b3 == 10; + + // But m does not change + foreach (k1, v1 in m) { + foreach (k2, v2 in v1.m) { + result &&= + k1 == 100 && + k2 == 10 && + + v2.a1 == 20 && + v2.a2.b1 == true && + v2.a2.b2.c1 == 5 && + v2.a2.b3 == 10; + } + } + + // Hence, we need to assign s back into m + + // However, the following expression will not work, + // because the "get" function always makes a copy of "m" (see test "testReturnedMaps1" above). + // m.get(100)!!.m.set(10, s); + + // This means we are forced to update the entire entry for key 100. + + // The fact that "get" always returns copies of nested structures has one big consequence: + // it is not possible to update a deeply nested map without rebuilding the map of the root + // key that leads to the updated nested map, i.e., + // if the map is: + // key1 -> [ + // key1.1 -> [key1.1.1 -> val1], + // key1.2 -> [key1.2.1 -> val2] + // ] + // Then, updating the entry key1.1.1 with value val3 would require + // updating key1 with + // [ + // key1.1 -> [key1.1.1 -> val3], + // key1.2 -> [key1.2.1 -> val2] + // ] + + // First build the map containing the updated s and wrap it + let nestedMap1: map = emptyMap(); + nestedMap1.set(10, s); + let wrappedNested1 = MapWrapper {m: nestedMap1}; + + // As a side note: we can also achieve the same result by doing this: + let wrappedNested2 = MapWrapper {m: emptyMap()}; + wrappedNested2.m.set(10, s); + + // Indeed, wrappedNested1 and wrappedNested2 are equal + + foreach (k2, v2 in wrappedNested1.m) { + result &&= + k2 == 10 && + + v2.a1 == 20 && + v2.a2.b1 == true && + v2.a2.b2.c1 == 1000 && + v2.a2.b3 == 10; + } + + foreach (k2, v2 in wrappedNested2.m) { + result &&= + k2 == 10 && + + v2.a1 == 20 && + v2.a2.b1 == true && + v2.a2.b2.c1 == 1000 && + v2.a2.b3 == 10; + } + + // Finally, assign the wrapped map to the key 100 + m.set(100, wrappedNested1); + + // Check that m changed + + foreach (k1, v1 in m) { + foreach (k2, v2 in v1.m) { + result &&= + k1 == 100 && + k2 == 10 && + + v2.a1 == 20 && + v2.a2.b1 == true && + v2.a2.b2.c1 == 1000 && + v2.a2.b3 == 10; + } + } + + // The rest of the fields in the contract did not change (including self.mC). + result &&= self.checkAllContractFieldsAreUnchanged(); + + return result; + } + /*************** Contracts ********************/ get fun contractAssign1(): Bool { @@ -835,6 +1438,20 @@ contract SemanticsTester { result &&= (k == 1 || k == 2 || k == 3); } + // The map self.mC has a single entry 100 -> MapWrapper {m: 10 -> original self.sA}. + foreach (k1, v1 in self.mC) { + foreach (k2, v2 in v1.m) { + result &&= + k1 == 100 && + k2 == 10 && + + v2.a1 == 20 && + v2.a2.b1 == true && + v2.a2.b2.c1 == 5 && + v2.a2.b3 == 10; + } + } + return result; } @@ -864,6 +1481,63 @@ contract SemanticsTester { return result; } + get fun testReturnedContracts(): Bool { + // The call to the non-mutating extends function "copyContract" always makes a copy + // of the parameter contract. Therefore, passing the result to the mutating function + // "changeSomeContractFields" will modify the copy, not the original contract. + + self.copyContract().changeSomeContractFields(); + + let result = + self.checkAllContractFieldsAreUnchanged(); + + // For the following test, make a copy of self. + let c = self; + + // Now consider this expression: + + c.reflectContract().changeSomeContractFields(); + + // Again, passing "c" to the mutating function "reflectContract", + // will reassign back to c a copy of c, but it will also pass the copy of c to + // changeSomeContractFields. + // This means that the above expression will not modify c. + // Note that since the return type of changeSomeContractFields is void, + // we cannot use the trick: + // + // c = c.reflectContract().changeSomeContractFields(); + // + // to actually update c. Hence, the only ways are to directly call + // changeSomeContractFields or divide the expression into steps: + // + // c.changeSomeContractFields(); + // + // or: + // + // c.reflectContract(); + // c.changeSomeContractFields(); + + // Nothing changed + result &&= + self.checkAllContractFieldsAreUnchanged() && + c.checkAllContractFieldsAreUnchanged(); + + // When chaining mutating functions, one needs to reassign c in order to mutate it, + // because the chain passes copies to the next mutating function, + // and the copy returned by the last mutating function will be lost + // if not reassigned back into c: + + c = c.reflectContract().incrementIntFieldsInUB().flipBooleanFieldsInUB(); + + // c is now changed, the rest remains the same. + result &&= + self.checkAllContractFieldsAreUnchanged() && + c.checkFieldsEqualTo(SB {b1: true, b2: SC {c1: 1}, b3: 15}, 5); + + return result; + + } + get fun mutateContractStateFlag(): Bool { return self.mutateContractStateResult; } @@ -871,4 +1545,111 @@ contract SemanticsTester { get fun changesPersisted(): Bool { return self.checkFieldsEqualTo(SB {b1: true, b2: SC {c1: 77}, b3: 88}, 35); } -} \ No newline at end of file + + + /*************** Integers ********************/ + + /* + The following functions exemplify how to properly chain mutating functions. + Each function in the chain returns a copy to the next function in the chain. + Hence, to change the original variable, we need to reassign the value returned + from the last mutating function. + + Another way that is actually less confusing, is to simply break the chain + into single steps. + + */ + get fun mutatesChainInt1(): Bool { + let s = 2; + s.multiplyBy2().increment().doNothing(); // s is changed only by the first mutating function. + + let t = 2; + t = t.multiplyBy2().increment().doNothing(); // t reassigned with the value returned by the last function. + + // The less confusing solution is to simply break the chain. + // This solution even works when the last function in the chain has void return type. + // Each step changes z + + let z = 2; + z.multiplyBy2(); + z.increment(); + z.doNothing(); + + return s == 4 && t == 5 && z == 5; + } + + get fun mutatesChainInt2(): Bool { + let s = 2; + s.multiplyBy2().doNothing().increment(); + + let t = 2; + t = t.multiplyBy2().doNothing().increment(); + + let z = 2; + z.multiplyBy2(); + z.doNothing(); + z.increment(); + + return s == 4 && t == 5 && z == 5; + } + + get fun mutatesChainInt3(): Bool { + let s = 2; + s.doNothing().multiplyBy2().increment(); + + let t = 2; + t = t.doNothing().multiplyBy2().increment(); + + let z = 2; + z.doNothing(); + z.multiplyBy2(); + z.increment(); + + return s == 2 && t == 5 && z == 5; + } + + get fun mutatesChainInt4(): Bool { + let s = 2; + s.doNothing().increment().multiplyBy2(); + + let t = 2; + t = t.doNothing().increment().multiplyBy2(); + + let z = 2; + z.doNothing(); + z.increment(); + z.multiplyBy2(); + + return s == 2 && t == 6 && z == 6; + } + + get fun mutatesChainInt5(): Bool { + let s = 2; + s.increment().doNothing().multiplyBy2(); + + let t = 2; + t = t.increment().doNothing().multiplyBy2(); + + let z = 2; + z.increment(); + z.doNothing(); + z.multiplyBy2(); + + return s == 3 && t == 6 && z == 6; + } + + get fun mutatesChainInt6(): Bool { + let s = 2; + s.increment().multiplyBy2().doNothing(); + + let t = 2; + t = t.increment().multiplyBy2().doNothing(); + + let z = 2; + z.increment(); + z.multiplyBy2(); + z.doNothing(); + + return s == 3 && t == 6 && z == 6; + } +} diff --git a/src/test/e2e-emulated/mutating-method-chaining.spec.ts b/src/test/e2e-emulated/mutating-methods.spec.ts similarity index 54% rename from src/test/e2e-emulated/mutating-method-chaining.spec.ts rename to src/test/e2e-emulated/mutating-methods.spec.ts index 9485a6588..b1e929510 100644 --- a/src/test/e2e-emulated/mutating-method-chaining.spec.ts +++ b/src/test/e2e-emulated/mutating-methods.spec.ts @@ -1,6 +1,6 @@ -import { toNano } from "@ton/core"; +import { beginCell, BitString, Dictionary, toNano } from "@ton/core"; import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox"; -import { Tester } from "./contracts/output/mutating-method-chaining_Tester"; +import { Tester } from "./contracts/output/mutating-methods_Tester"; import "@ton/test-utils"; describe("bugs", () => { @@ -52,5 +52,41 @@ describe("bugs", () => { expect(await contract.getTest7()).toBe(42n); expect(await contract.getTest8()).toBe(5n); expect(await contract.getTest9()).toBe(5n); + + // Test `extends mutates` function with optional self param + { + // Non-empty dictionary + const d = Dictionary.empty( + Dictionary.Keys.Uint(8), + Dictionary.Values.BitString(12), + ); + d.set(1, new BitString(Buffer.from("1234", "hex"), 0, 12)); + const c = beginCell().storeDictDirect(d).endCell(); + const c2 = await contract.getTest10(c); + const d2 = c2 + ?.beginParse() + .loadDictDirect( + Dictionary.Keys.Uint(8), + Dictionary.Values.BitString(12), + ); + expect(d2?.size).toBe(2); + expect(d2?.get(1)?.toString()).toBe("123"); + expect(d2?.get(123)?.toString()).toBe("456"); + } + { + // Empty dictionary + const c = await contract.getTest10(null); + const d = c + ?.beginParse() + .loadDictDirect( + Dictionary.Keys.Uint(8), + Dictionary.Values.BitString(12), + ); + expect(d?.size).toBe(1); + expect(d?.get(123)?.toString()).toBe("456"); + } + + expect(await contract.getTest11(1n)).toBe(6n); + expect(await contract.getTest11(2n)).toBe(12n); }); }); diff --git a/src/test/e2e-emulated/semantics.spec.ts b/src/test/e2e-emulated/semantics.spec.ts index 15a94ac16..4d7c768ec 100644 --- a/src/test/e2e-emulated/semantics.spec.ts +++ b/src/test/e2e-emulated/semantics.spec.ts @@ -42,6 +42,13 @@ describe("semantics", () => { expect(await contract.getParamStruct2()).toEqual(true); expect(await contract.getMutateParamStruct1()).toEqual(true); expect(await contract.getMutateParamStruct2()).toEqual(true); + expect(await contract.getTestReturnedStructs()).toEqual(true); + expect(await contract.getMutatesChainStruct1()).toEqual(true); + expect(await contract.getMutatesChainStruct2()).toEqual(true); + expect(await contract.getMutatesChainStruct3()).toEqual(true); + expect(await contract.getMutatesChainStruct4()).toEqual(true); + expect(await contract.getMutatesChainStruct5()).toEqual(true); + expect(await contract.getMutatesChainStruct6()).toEqual(true); // Maps @@ -51,6 +58,18 @@ describe("semantics", () => { expect(await contract.getParamMap2()).toEqual(true); expect(await contract.getMutateParamMap1()).toEqual(true); expect(await contract.getMutateParamMap2()).toEqual(true); + expect(await contract.getTestReturnedMaps1()).toEqual(true); + // expect(await contract.getTestReturnedMaps2()).toEqual(true); + expect(await contract.getMutateNestedMap1()).toEqual(true); + + // Integers + + expect(await contract.getMutatesChainInt1()).toEqual(true); + expect(await contract.getMutatesChainInt2()).toEqual(true); + expect(await contract.getMutatesChainInt3()).toEqual(true); + expect(await contract.getMutatesChainInt4()).toEqual(true); + expect(await contract.getMutatesChainInt5()).toEqual(true); + expect(await contract.getMutatesChainInt6()).toEqual(true); // Contracts @@ -58,6 +77,7 @@ describe("semantics", () => { expect(await contract.getContractAssign2()).toEqual(true); expect(await contract.getParamContract()).toEqual(true); expect(await contract.getMutateParamContract()).toEqual(true); + expect(await contract.getTestReturnedContracts()).toEqual(true); // Obtain the address before the contract gets modified const address1 = await contract.getAddress(); diff --git a/src/types/__snapshots__/resolveDescriptors.spec.ts.snap b/src/types/__snapshots__/resolveDescriptors.spec.ts.snap index 30b43c1b0..dd0d9ca5d 100644 --- a/src/types/__snapshots__/resolveDescriptors.spec.ts.snap +++ b/src/types/__snapshots__/resolveDescriptors.spec.ts.snap @@ -769,7 +769,11 @@ exports[`resolveDescriptors should resolve descriptors for asm-extends-fun 1`] = "name": "Cell", "optional": false, }, - "self": "Slice", + "self": { + "kind": "ref", + "name": "Slice", + "optional": false, + }, }, }, "header": null, @@ -4505,7 +4509,11 @@ exports[`resolveDescriptors should resolve descriptors for contract-getter-overr "name": "Int", "optional": false, }, - "self": "T", + "self": { + "kind": "ref", + "name": "T", + "optional": false, + }, }, }, "header": null, @@ -4682,7 +4690,11 @@ exports[`resolveDescriptors should resolve descriptors for contract-getter-overr "name": "Int", "optional": false, }, - "self": "TestContract", + "self": { + "kind": "ref", + "name": "TestContract", + "optional": false, + }, }, }, "header": null, @@ -4832,7 +4844,11 @@ exports[`resolveDescriptors should resolve descriptors for contract-getter-overr "name": "Int", "optional": false, }, - "self": "T", + "self": { + "kind": "ref", + "name": "T", + "optional": false, + }, }, }, "header": null, @@ -5073,7 +5089,11 @@ exports[`resolveDescriptors should resolve descriptors for contract-getter-overr "name": "Int", "optional": false, }, - "self": "T", + "self": { + "kind": "ref", + "name": "T", + "optional": false, + }, }, }, "header": null, @@ -5250,7 +5270,11 @@ exports[`resolveDescriptors should resolve descriptors for contract-getter-overr "name": "Int", "optional": false, }, - "self": "TestContract", + "self": { + "kind": "ref", + "name": "TestContract", + "optional": false, + }, }, }, "header": null, @@ -5428,7 +5452,11 @@ exports[`resolveDescriptors should resolve descriptors for contract-getter-overr "name": "Int", "optional": false, }, - "self": "T", + "self": { + "kind": "ref", + "name": "T", + "optional": false, + }, }, }, "header": null, @@ -5485,7 +5513,7 @@ exports[`resolveDescriptors should resolve descriptors for contract-getter-overr exports[`resolveDescriptors should resolve descriptors for contract-getter-override-virtual 2`] = `[]`; -exports[`resolveDescriptors should resolve descriptors for init-vars-analysis-uninit-storage-vars 1`] = ` +exports[`resolveDescriptors should resolve descriptors for fun-extends-opt-self 1`] = ` [ { "ast": { @@ -5502,168 +5530,924 @@ exports[`resolveDescriptors should resolve descriptors for init-vars-analysis-un "constants": [], "dependsOn": [], "fields": [], - "functions": Map {}, - "header": null, - "init": null, - "interfaces": [], - "kind": "primitive_type_decl", - "name": "Int", - "origin": "user", - "partialFieldCount": 0, - "receivers": [], - "signature": null, - "tlb": null, - "traits": [], - "uid": 38154, - }, - { - "ast": { - "id": 4, - "kind": "primitive_type_decl", - "loc": primitive Bool;, - "name": { - "id": 3, - "kind": "type_id", - "loc": Bool, - "text": "Bool", - }, - }, - "constants": [], - "dependsOn": [], - "fields": [], - "functions": Map {}, - "header": null, - "init": null, - "interfaces": [], - "kind": "primitive_type_decl", - "name": "Bool", - "origin": "user", - "partialFieldCount": 0, - "receivers": [], - "signature": null, - "tlb": null, - "traits": [], - "uid": 33424, - }, - { - "ast": { - "attributes": [], - "declarations": [], - "id": 6, - "kind": "trait", - "loc": trait BaseTrait { - + "functions": Map { + "test_extends" => { + "ast": { + "attributes": [ + { + "loc": extends, + "type": "extends", + }, + ], + "id": 26, + "kind": "function_def", + "loc": extends fun test_extends(self: Int, y: Int?): Int { + return 123; }, - "name": { - "id": 5, - "kind": "id", - "loc": BaseTrait, - "text": "BaseTrait", - }, - "traits": [], - }, - "constants": [], - "dependsOn": [], - "fields": [], - "functions": Map {}, - "header": null, - "init": null, - "interfaces": [], - "kind": "trait", - "name": "BaseTrait", - "origin": "user", - "partialFieldCount": 0, - "receivers": [], - "signature": null, - "tlb": null, - "traits": [], - "uid": 1020, - }, - { - "ast": { - "attributes": [], - "declarations": [ - { - "as": null, - "id": 10, - "initializer": null, - "kind": "field_decl", - "loc": a: Int, "name": { - "id": 8, + "id": 15, "kind": "id", - "loc": a, - "text": "a", + "loc": test_extends, + "text": "test_extends", }, - "type": { - "id": 9, + "params": [ + { + "id": 19, + "kind": "typed_parameter", + "loc": self: Int, + "name": { + "id": 17, + "kind": "id", + "loc": self, + "text": "self", + }, + "type": { + "id": 18, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + { + "id": 23, + "kind": "typed_parameter", + "loc": y: Int?, + "name": { + "id": 20, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "id": 22, + "kind": "optional_type", + "loc": Int?, + "typeArg": { + "id": 21, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + }, + ], + "return": { + "id": 16, "kind": "type_id", "loc": Int, "text": "Int", }, + "statements": [ + { + "expression": { + "base": 10, + "id": 24, + "kind": "number", + "loc": 123, + "value": 123n, + }, + "id": 25, + "kind": "statement_return", + "loc": return 123;, + }, + ], }, - { - "as": null, - "id": 13, - "initializer": null, - "kind": "field_decl", - "loc": b: Bool, - "name": { - "id": 11, - "kind": "id", - "loc": b, - "text": "b", - }, - "type": { - "id": 12, - "kind": "type_id", - "loc": Bool, - "text": "Bool", + "isAbstract": false, + "isGetter": false, + "isInline": false, + "isMutating": false, + "isOverride": false, + "isVirtual": false, + "name": "test_extends", + "origin": "user", + "params": [ + { + "loc": y: Int?, + "name": { + "id": 20, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "kind": "ref", + "name": "Int", + "optional": true, + }, }, + ], + "returns": { + "kind": "ref", + "name": "Int", + "optional": false, }, - { - "id": 14, - "kind": "contract_init", - "loc": init() { - - }, - "params": [], - "statements": [], - }, - { - "attributes": [], - "id": 16, - "kind": "function_def", - "loc": fun hello() { - - }, - "name": { - "id": 15, - "kind": "id", - "loc": hello, - "text": "hello", - }, - "params": [], - "return": null, - "statements": [], + "self": { + "kind": "ref", + "name": "Int", + "optional": false, }, - { - "attributes": [], - "id": 18, + }, + "test_extends_self" => { + "ast": { + "attributes": [ + { + "loc": extends, + "type": "extends", + }, + ], + "id": 38, "kind": "function_def", - "loc": fun hello2() { - - }, + "loc": extends fun test_extends_self(self: Int?, y: Int): Int { + return 123; +}, "name": { - "id": 17, + "id": 27, "kind": "id", - "loc": hello2, - "text": "hello2", + "loc": test_extends_self, + "text": "test_extends_self", }, - "params": [], - "return": null, - "statements": [], - }, + "params": [ + { + "id": 32, + "kind": "typed_parameter", + "loc": self: Int?, + "name": { + "id": 29, + "kind": "id", + "loc": self, + "text": "self", + }, + "type": { + "id": 31, + "kind": "optional_type", + "loc": Int?, + "typeArg": { + "id": 30, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + }, + { + "id": 35, + "kind": "typed_parameter", + "loc": y: Int, + "name": { + "id": 33, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "id": 34, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + ], + "return": { + "id": 28, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + "statements": [ + { + "expression": { + "base": 10, + "id": 36, + "kind": "number", + "loc": 123, + "value": 123n, + }, + "id": 37, + "kind": "statement_return", + "loc": return 123;, + }, + ], + }, + "isAbstract": false, + "isGetter": false, + "isInline": false, + "isMutating": false, + "isOverride": false, + "isVirtual": false, + "name": "test_extends_self", + "origin": "user", + "params": [ + { + "loc": y: Int, + "name": { + "id": 33, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "kind": "ref", + "name": "Int", + "optional": false, + }, + }, + ], + "returns": { + "kind": "ref", + "name": "Int", + "optional": false, + }, + "self": { + "kind": "ref", + "name": "Int", + "optional": true, + }, + }, + "test_mutates" => { + "ast": { + "attributes": [ + { + "loc": extends, + "type": "extends", + }, + { + "loc": mutates, + "type": "mutates", + }, + ], + "id": 50, + "kind": "function_def", + "loc": extends mutates fun test_mutates(self: Int, y: Int?): Int { + return 123; +}, + "name": { + "id": 39, + "kind": "id", + "loc": test_mutates, + "text": "test_mutates", + }, + "params": [ + { + "id": 43, + "kind": "typed_parameter", + "loc": self: Int, + "name": { + "id": 41, + "kind": "id", + "loc": self, + "text": "self", + }, + "type": { + "id": 42, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + { + "id": 47, + "kind": "typed_parameter", + "loc": y: Int?, + "name": { + "id": 44, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "id": 46, + "kind": "optional_type", + "loc": Int?, + "typeArg": { + "id": 45, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + }, + ], + "return": { + "id": 40, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + "statements": [ + { + "expression": { + "base": 10, + "id": 48, + "kind": "number", + "loc": 123, + "value": 123n, + }, + "id": 49, + "kind": "statement_return", + "loc": return 123;, + }, + ], + }, + "isAbstract": false, + "isGetter": false, + "isInline": false, + "isMutating": true, + "isOverride": false, + "isVirtual": false, + "name": "test_mutates", + "origin": "user", + "params": [ + { + "loc": y: Int?, + "name": { + "id": 44, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "kind": "ref", + "name": "Int", + "optional": true, + }, + }, + ], + "returns": { + "kind": "ref", + "name": "Int", + "optional": false, + }, + "self": { + "kind": "ref", + "name": "Int", + "optional": false, + }, + }, + "test_mutates_self" => { + "ast": { + "attributes": [ + { + "loc": extends, + "type": "extends", + }, + { + "loc": mutates, + "type": "mutates", + }, + ], + "id": 62, + "kind": "function_def", + "loc": extends mutates fun test_mutates_self(self: Int?, y: Int): Int { + return 123; +}, + "name": { + "id": 51, + "kind": "id", + "loc": test_mutates_self, + "text": "test_mutates_self", + }, + "params": [ + { + "id": 56, + "kind": "typed_parameter", + "loc": self: Int?, + "name": { + "id": 53, + "kind": "id", + "loc": self, + "text": "self", + }, + "type": { + "id": 55, + "kind": "optional_type", + "loc": Int?, + "typeArg": { + "id": 54, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + }, + { + "id": 59, + "kind": "typed_parameter", + "loc": y: Int, + "name": { + "id": 57, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "id": 58, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + ], + "return": { + "id": 52, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + "statements": [ + { + "expression": { + "base": 10, + "id": 60, + "kind": "number", + "loc": 123, + "value": 123n, + }, + "id": 61, + "kind": "statement_return", + "loc": return 123;, + }, + ], + }, + "isAbstract": false, + "isGetter": false, + "isInline": false, + "isMutating": true, + "isOverride": false, + "isVirtual": false, + "name": "test_mutates_self", + "origin": "user", + "params": [ + { + "loc": y: Int, + "name": { + "id": 57, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "kind": "ref", + "name": "Int", + "optional": false, + }, + }, + ], + "returns": { + "kind": "ref", + "name": "Int", + "optional": false, + }, + "self": { + "kind": "ref", + "name": "Int", + "optional": true, + }, + }, + "test_mutates_self_opt" => { + "ast": { + "attributes": [ + { + "loc": extends, + "type": "extends", + }, + { + "loc": mutates, + "type": "mutates", + }, + ], + "id": 75, + "kind": "function_def", + "loc": extends mutates fun test_mutates_self_opt(self: Int?, y: Int): Int? { + return null; +}, + "name": { + "id": 63, + "kind": "id", + "loc": test_mutates_self_opt, + "text": "test_mutates_self_opt", + }, + "params": [ + { + "id": 69, + "kind": "typed_parameter", + "loc": self: Int?, + "name": { + "id": 66, + "kind": "id", + "loc": self, + "text": "self", + }, + "type": { + "id": 68, + "kind": "optional_type", + "loc": Int?, + "typeArg": { + "id": 67, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + }, + { + "id": 72, + "kind": "typed_parameter", + "loc": y: Int, + "name": { + "id": 70, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "id": 71, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + ], + "return": { + "id": 65, + "kind": "optional_type", + "loc": Int?, + "typeArg": { + "id": 64, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + "statements": [ + { + "expression": { + "id": 73, + "kind": "null", + "loc": null, + }, + "id": 74, + "kind": "statement_return", + "loc": return null;, + }, + ], + }, + "isAbstract": false, + "isGetter": false, + "isInline": false, + "isMutating": true, + "isOverride": false, + "isVirtual": false, + "name": "test_mutates_self_opt", + "origin": "user", + "params": [ + { + "loc": y: Int, + "name": { + "id": 70, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "kind": "ref", + "name": "Int", + "optional": false, + }, + }, + ], + "returns": { + "kind": "ref", + "name": "Int", + "optional": true, + }, + "self": { + "kind": "ref", + "name": "Int", + "optional": true, + }, + }, + }, + "header": null, + "init": null, + "interfaces": [], + "kind": "primitive_type_decl", + "name": "Int", + "origin": "user", + "partialFieldCount": 0, + "receivers": [], + "signature": null, + "tlb": null, + "traits": [], + "uid": 38154, + }, +] +`; + +exports[`resolveDescriptors should resolve descriptors for fun-extends-opt-self 2`] = ` +[ + { + "ast": { + "attributes": [], + "id": 14, + "kind": "function_def", + "loc": fun test(x: Int, y: Int?): Int { + return 123; +}, + "name": { + "id": 3, + "kind": "id", + "loc": test, + "text": "test", + }, + "params": [ + { + "id": 7, + "kind": "typed_parameter", + "loc": x: Int, + "name": { + "id": 5, + "kind": "id", + "loc": x, + "text": "x", + }, + "type": { + "id": 6, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + { + "id": 11, + "kind": "typed_parameter", + "loc": y: Int?, + "name": { + "id": 8, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "id": 10, + "kind": "optional_type", + "loc": Int?, + "typeArg": { + "id": 9, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + }, + ], + "return": { + "id": 4, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + "statements": [ + { + "expression": { + "base": 10, + "id": 12, + "kind": "number", + "loc": 123, + "value": 123n, + }, + "id": 13, + "kind": "statement_return", + "loc": return 123;, + }, + ], + }, + "isAbstract": false, + "isGetter": false, + "isInline": false, + "isMutating": false, + "isOverride": false, + "isVirtual": false, + "name": "test", + "origin": "user", + "params": [ + { + "loc": x: Int, + "name": { + "id": 5, + "kind": "id", + "loc": x, + "text": "x", + }, + "type": { + "kind": "ref", + "name": "Int", + "optional": false, + }, + }, + { + "loc": y: Int?, + "name": { + "id": 8, + "kind": "id", + "loc": y, + "text": "y", + }, + "type": { + "kind": "ref", + "name": "Int", + "optional": true, + }, + }, + ], + "returns": { + "kind": "ref", + "name": "Int", + "optional": false, + }, + "self": null, + }, +] +`; + +exports[`resolveDescriptors should resolve descriptors for init-vars-analysis-uninit-storage-vars 1`] = ` +[ + { + "ast": { + "id": 2, + "kind": "primitive_type_decl", + "loc": primitive Int;, + "name": { + "id": 1, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + "constants": [], + "dependsOn": [], + "fields": [], + "functions": Map {}, + "header": null, + "init": null, + "interfaces": [], + "kind": "primitive_type_decl", + "name": "Int", + "origin": "user", + "partialFieldCount": 0, + "receivers": [], + "signature": null, + "tlb": null, + "traits": [], + "uid": 38154, + }, + { + "ast": { + "id": 4, + "kind": "primitive_type_decl", + "loc": primitive Bool;, + "name": { + "id": 3, + "kind": "type_id", + "loc": Bool, + "text": "Bool", + }, + }, + "constants": [], + "dependsOn": [], + "fields": [], + "functions": Map {}, + "header": null, + "init": null, + "interfaces": [], + "kind": "primitive_type_decl", + "name": "Bool", + "origin": "user", + "partialFieldCount": 0, + "receivers": [], + "signature": null, + "tlb": null, + "traits": [], + "uid": 33424, + }, + { + "ast": { + "attributes": [], + "declarations": [], + "id": 6, + "kind": "trait", + "loc": trait BaseTrait { + +}, + "name": { + "id": 5, + "kind": "id", + "loc": BaseTrait, + "text": "BaseTrait", + }, + "traits": [], + }, + "constants": [], + "dependsOn": [], + "fields": [], + "functions": Map {}, + "header": null, + "init": null, + "interfaces": [], + "kind": "trait", + "name": "BaseTrait", + "origin": "user", + "partialFieldCount": 0, + "receivers": [], + "signature": null, + "tlb": null, + "traits": [], + "uid": 1020, + }, + { + "ast": { + "attributes": [], + "declarations": [ + { + "as": null, + "id": 10, + "initializer": null, + "kind": "field_decl", + "loc": a: Int, + "name": { + "id": 8, + "kind": "id", + "loc": a, + "text": "a", + }, + "type": { + "id": 9, + "kind": "type_id", + "loc": Int, + "text": "Int", + }, + }, + { + "as": null, + "id": 13, + "initializer": null, + "kind": "field_decl", + "loc": b: Bool, + "name": { + "id": 11, + "kind": "id", + "loc": b, + "text": "b", + }, + "type": { + "id": 12, + "kind": "type_id", + "loc": Bool, + "text": "Bool", + }, + }, + { + "id": 14, + "kind": "contract_init", + "loc": init() { + + }, + "params": [], + "statements": [], + }, + { + "attributes": [], + "id": 16, + "kind": "function_def", + "loc": fun hello() { + + }, + "name": { + "id": 15, + "kind": "id", + "loc": hello, + "text": "hello", + }, + "params": [], + "return": null, + "statements": [], + }, + { + "attributes": [], + "id": 18, + "kind": "function_def", + "loc": fun hello2() { + + }, + "name": { + "id": 17, + "kind": "id", + "loc": hello2, + "text": "hello2", + }, + "params": [], + "return": null, + "statements": [], + }, ], "id": 19, "kind": "contract", @@ -5805,7 +6589,11 @@ exports[`resolveDescriptors should resolve descriptors for init-vars-analysis-un "returns": { "kind": "void", }, - "self": "HelloWorld", + "self": { + "kind": "ref", + "name": "HelloWorld", + "optional": false, + }, }, "hello2" => { "ast": { @@ -5837,7 +6625,11 @@ exports[`resolveDescriptors should resolve descriptors for init-vars-analysis-un "returns": { "kind": "void", }, - "self": "HelloWorld", + "self": { + "kind": "ref", + "name": "HelloWorld", + "optional": false, + }, }, }, "header": null, @@ -6682,7 +7474,11 @@ exports[`resolveDescriptors should resolve descriptors for item-funs-with-errors "name": "Int", "optional": false, }, - "self": "Main", + "self": { + "kind": "ref", + "name": "Main", + "optional": false, + }, }, "hello2" => { "ast": { @@ -6739,7 +7535,11 @@ exports[`resolveDescriptors should resolve descriptors for item-funs-with-errors "name": "Point", "optional": false, }, - "self": "Main", + "self": { + "kind": "ref", + "name": "Main", + "optional": false, + }, }, }, "header": null, @@ -6972,7 +7772,11 @@ exports[`resolveDescriptors should resolve descriptors for item-method 1`] = ` "name": "Int", "optional": false, }, - "self": "Int", + "self": { + "kind": "ref", + "name": "Int", + "optional": false, + }, }, }, "header": null, @@ -7320,7 +8124,11 @@ mutates extends native inc(self: Int): Int;, "name": "Int", "optional": false, }, - "self": "Int", + "self": { + "kind": "ref", + "name": "Int", + "optional": false, + }, }, }, "header": null, @@ -8090,7 +8898,11 @@ exports[`resolveDescriptors should resolve descriptors for map-value-as-coins 1` "name": "Int", "optional": false, }, - "self": "Main", + "self": { + "kind": "ref", + "name": "Main", + "optional": false, + }, }, }, "header": null, diff --git a/src/types/__snapshots__/resolveStatements.spec.ts.snap b/src/types/__snapshots__/resolveStatements.spec.ts.snap index 6d4ca594c..6e92c641e 100644 --- a/src/types/__snapshots__/resolveStatements.spec.ts.snap +++ b/src/types/__snapshots__/resolveStatements.spec.ts.snap @@ -2268,6 +2268,223 @@ exports[`resolveStatements should resolve statements for expr-struct-constructio ] `; +exports[`resolveStatements should resolve statements for fun-extends-optional 1`] = ` +[ + [ + "y", + "Int?", + ], + [ + "null", + "", + ], + [ + "y == null", + "Bool", + ], + [ + "x", + "Int", + ], + [ + "x", + "Int", + ], + [ + "y", + "Int?", + ], + [ + "y!!", + "Int", + ], + [ + "x + y!!", + "Int", + ], + [ + "y", + "Int?", + ], + [ + "null", + "", + ], + [ + "y == null", + "Bool", + ], + [ + "self", + "Int", + ], + [ + "self", + "Int", + ], + [ + "y", + "Int?", + ], + [ + "y!!", + "Int", + ], + [ + "self + y!!", + "Int", + ], + [ + "self", + "Int?", + ], + [ + "null", + "", + ], + [ + "self == null", + "Bool", + ], + [ + "y", + "Int", + ], + [ + "self", + "Int?", + ], + [ + "self!!", + "Int", + ], + [ + "y", + "Int", + ], + [ + "self!! + y", + "Int", + ], + [ + "y", + "Int?", + ], + [ + "null", + "", + ], + [ + "y == null", + "Bool", + ], + [ + "self", + "Int", + ], + [ + "self", + "Int", + ], + [ + "y", + "Int?", + ], + [ + "y!!", + "Int", + ], + [ + "self", + "Int", + ], + [ + "self", + "Int?", + ], + [ + "null", + "", + ], + [ + "self == null", + "Bool", + ], + [ + "y", + "Int", + ], + [ + "self", + "Int?", + ], + [ + "self", + "Int?", + ], + [ + "self!!", + "Int", + ], + [ + "y", + "Int", + ], + [ + "self!! + y", + "Int", + ], + [ + "self", + "Int?", + ], + [ + "self!!", + "Int", + ], + [ + "self", + "Int?", + ], + [ + "null", + "", + ], + [ + "self == null", + "Bool", + ], + [ + "null", + "", + ], + [ + "self", + "Int?", + ], + [ + "self", + "Int?", + ], + [ + "self!!", + "Int", + ], + [ + "y", + "Int", + ], + [ + "self!! + y", + "Int", + ], + [ + "self", + "Int?", + ], +] +`; + exports[`resolveStatements should resolve statements for init-vars-analysis-with-if 1`] = ` [ [ diff --git a/src/types/resolveDescriptors.ts b/src/types/resolveDescriptors.ts index 8940dfa04..1247ba6be 100644 --- a/src/types/resolveDescriptors.ts +++ b/src/types/resolveDescriptors.ts @@ -626,7 +626,7 @@ export function resolveDescriptors(ctx: CompilerContext) { // function resolveFunctionDescriptor( - optSelf: string | null, + optSelf: TypeRef | null, a: | AstFunctionDef | AstNativeFunctionDecl @@ -746,7 +746,13 @@ export function resolveDescriptors(ctx: CompilerContext) { // Check virtual if (isVirtual) { - const t = types.get(self!)!; + if (self?.kind !== "ref") { + throwInternalCompilerError( + "Virtual functions must have a self parameter", + isVirtual.loc, + ); + } + const t = types.get(self.name!)!; if (t.kind !== "trait") { throwCompilationError( "Virtual functions must be defined within a trait", @@ -757,7 +763,13 @@ export function resolveDescriptors(ctx: CompilerContext) { // Check abstract if (isAbstract) { - const t = types.get(self!)!; + if (self?.kind !== "ref") { + throwInternalCompilerError( + "Abstract functions must have a self parameter", + isAbstract.loc, + ); + } + const t = types.get(self.name!)!; if (t.kind !== "trait") { throwCompilationError( "Abstract functions must be defined within a trait", @@ -767,7 +779,13 @@ export function resolveDescriptors(ctx: CompilerContext) { } if (isOverride) { - const t = types.get(self!)!; + if (self?.kind !== "ref") { + throwInternalCompilerError( + "Override functions must have a self parameter", + isOverride.loc, + ); + } + const t = types.get(self.name!)!; if (!["contract", "trait"].includes(t.kind)) { throwCompilationError( "Overridden functions must be defined within a contract or a trait", @@ -818,12 +836,6 @@ export function resolveDescriptors(ctx: CompilerContext) { firstParam.loc, ); } - if (firstParam.type.optional) { - throwCompilationError( - "Extend functions must have a non-optional type as the first parameter", - firstParam.loc, - ); - } if (!types.has(firstParam.type.name)) { throwCompilationError( "Type " + firstParam.type.name + " not found", @@ -832,7 +844,7 @@ export function resolveDescriptors(ctx: CompilerContext) { } // Update self and remove first parameter - self = firstParam.type.name; + self = firstParam.type; params = params.slice(1); } @@ -1031,8 +1043,16 @@ export function resolveDescriptors(ctx: CompilerContext) { d.kind === "function_decl" || d.kind === "asm_function_def" ) { - const f = resolveFunctionDescriptor(s.name, d, s.origin); - if (f.self !== s.name) { + const f = resolveFunctionDescriptor( + { + kind: "ref", + name: s.name, + optional: false, + }, + d, + s.origin, + ); + if (f.self?.kind !== "ref" || f.self.name !== s.name) { throwInternalCompilerError( `Function self must be ${s.name}`, ); // Impossible @@ -1614,7 +1634,11 @@ export function resolveDescriptors(ctx: CompilerContext) { // Register function contractOrTrait.functions.set(traitFunction.name, { ...traitFunction, - self: contractOrTrait.name, + self: { + kind: "ref", + name: contractOrTrait.name, + optional: false, + }, ast: cloneNode(traitFunction.ast), }); } @@ -1870,13 +1894,19 @@ export function resolveDescriptors(ctx: CompilerContext) { for (const a of ast.functions) { const r = resolveFunctionDescriptor(null, a, a.loc.origin); if (r.self) { - if (types.get(r.self)!.functions.has(r.name)) { + if (r.self.kind !== "ref") { + throwCompilationError( + `Wrong self type "${r.name}" for static function`, + r.ast.loc, + ); + } + if (types.get(r.self.name)!.functions.has(r.name)) { throwCompilationError( - `Function "${r.name}" already exists in type "${r.self}"`, + `Function "${r.name}" already exists in type "${r.self.name}"`, r.ast.loc, ); } - types.get(r.self)!.functions.set(r.name, r); + types.get(r.self.name)!.functions.set(r.name, r); } else { if (staticFunctions.has(r.name) || GlobalFunctions.has(r.name)) { throwCompilationError( diff --git a/src/types/resolveExpression.ts b/src/types/resolveExpression.ts index 95190249c..702523f0f 100644 --- a/src/types/resolveExpression.ts +++ b/src/types/resolveExpression.ts @@ -562,13 +562,6 @@ function resolveCall( // Handle ref if (src.kind === "ref") { - if (src.optional) { - throwCompilationError( - `Invalid type "${printTypeRef(src)}" for function call`, - exp.loc, - ); - } - // Register return type const srcT = getType(ctx, src.name); diff --git a/src/types/resolveStatements.ts b/src/types/resolveStatements.ts index 5093b2463..91ff414dd 100644 --- a/src/types/resolveStatements.ts +++ b/src/types/resolveStatements.ts @@ -864,12 +864,12 @@ export function resolveStatements(ctx: CompilerContext) { ) { // Build statement context let sctx = emptyContext(f.ast.loc, f.name, f.returns); - sctx = addVariable( - selfId, - { kind: "ref", name: t.name, optional: false }, - ctx, - sctx, - ); + if (f.self === null) { + throwInternalCompilerError( + "Self is null where it should not be", + ); + } + sctx = addVariable(selfId, f.self, ctx, sctx); for (const a of f.params) { sctx = addVariable(a.name, a.type, ctx, sctx); } diff --git a/src/types/stmts/fun-extends-optional.tact b/src/types/stmts/fun-extends-optional.tact new file mode 100644 index 000000000..4a13d2e05 --- /dev/null +++ b/src/types/stmts/fun-extends-optional.tact @@ -0,0 +1,46 @@ +primitive Int; + +fun test(x: Int, y: Int?): Int { + if (y == null) { + return x; + } + return x + y!!; +} + +extends fun test_extends(self: Int, y: Int?): Int { + if (y == null) { + return self; + } + return self + y!!; +} + +extends fun test_extends_self(self: Int?, y: Int): Int { + if (self == null) { + return y; + } + return self!! + y; +} + +extends mutates fun test_mutates(self: Int, y: Int?): Int { + if (y == null) { + return self; + } + self += y!!; + return self; +} + +extends mutates fun test_mutates_self(self: Int?, y: Int): Int { + if (self == null) { + return y; + } + self = self!! + y; + return self!!; +} + +extends mutates fun test_mutates_self_opt(self: Int?, y: Int): Int? { + if (self == null) { + return null; + } + self = self!! + y; + return self; +} \ No newline at end of file diff --git a/src/types/test/fun-extends-opt-self.tact b/src/types/test/fun-extends-opt-self.tact new file mode 100644 index 000000000..57cd29b75 --- /dev/null +++ b/src/types/test/fun-extends-opt-self.tact @@ -0,0 +1,25 @@ +primitive Int; + +fun test(x: Int, y: Int?): Int { + return 123; +} + +extends fun test_extends(self: Int, y: Int?): Int { + return 123; +} + +extends fun test_extends_self(self: Int?, y: Int): Int { + return 123; +} + +extends mutates fun test_mutates(self: Int, y: Int?): Int { + return 123; +} + +extends mutates fun test_mutates_self(self: Int?, y: Int): Int { + return 123; +} + +extends mutates fun test_mutates_self_opt(self: Int?, y: Int): Int? { + return null; +} \ No newline at end of file diff --git a/src/types/types.ts b/src/types/types.ts index e7f6860e4..f82fbc70e 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -149,7 +149,7 @@ export type FunctionDescription = { isVirtual: boolean; isAbstract: boolean; isInline: boolean; - self: string | null; + self: TypeRef | null; returns: TypeRef; params: FunctionParameter[]; ast: diff --git a/tact.config.json b/tact.config.json index fd858093e..946c32d2f 100644 --- a/tact.config.json +++ b/tact.config.json @@ -95,8 +95,8 @@ "output": "./src/test/e2e-emulated/contracts/output" }, { - "name": "mutating-method-chaining", - "path": "./src/test/e2e-emulated/contracts/mutating-method-chaining.tact", + "name": "mutating-methods", + "path": "./src/test/e2e-emulated/contracts/mutating-methods.tact", "output": "./src/test/e2e-emulated/contracts/output" }, { diff --git a/yarn.lock b/yarn.lock index 3f354ba1d..961af5687 100644 --- a/yarn.lock +++ b/yarn.lock @@ -308,34 +308,35 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@cspell/cspell-bundled-dicts@8.14.2": - version "8.14.2" - resolved "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.14.2.tgz#746706485228e055ff342a66191cb6b9e58e748a" - integrity sha512-Kv2Utj/RTSxfufGXkkoTZ/3ErCsYWpCijtDFr/FwSsM7mC0PzLpdlcD9xjtgrJO5Kwp7T47iTG21U4Mwddyi8Q== +"@cspell/cspell-bundled-dicts@8.14.4": + version "8.14.4" + resolved "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.14.4.tgz#61e116fb3c505d4ebf2f842f24ea1e39bc47d469" + integrity sha512-JHZOpCJzN6fPBapBOvoeMxZbr0ZA11ZAkwcqM4w0lKoacbi6TwK8GIYf66hHvwLmMeav75TNXWE6aPTvBLMMqA== dependencies: "@cspell/dict-ada" "^4.0.2" - "@cspell/dict-aws" "^4.0.3" - "@cspell/dict-bash" "^4.1.3" + "@cspell/dict-aws" "^4.0.4" + "@cspell/dict-bash" "^4.1.4" "@cspell/dict-companies" "^3.1.4" - "@cspell/dict-cpp" "^5.1.12" + "@cspell/dict-cpp" "^5.1.16" "@cspell/dict-cryptocurrencies" "^5.0.0" "@cspell/dict-csharp" "^4.0.2" "@cspell/dict-css" "^4.0.13" - "@cspell/dict-dart" "^2.0.3" + "@cspell/dict-dart" "^2.2.1" "@cspell/dict-django" "^4.1.0" "@cspell/dict-docker" "^1.1.7" - "@cspell/dict-dotnet" "^5.0.2" + "@cspell/dict-dotnet" "^5.0.5" "@cspell/dict-elixir" "^4.0.3" "@cspell/dict-en-common-misspellings" "^2.0.4" "@cspell/dict-en-gb" "1.1.33" "@cspell/dict-en_us" "^4.3.23" "@cspell/dict-filetypes" "^3.0.4" + "@cspell/dict-flutter" "^1.0.0" "@cspell/dict-fonts" "^4.0.0" "@cspell/dict-fsharp" "^1.0.1" "@cspell/dict-fullstack" "^3.2.0" "@cspell/dict-gaming-terms" "^1.0.5" "@cspell/dict-git" "^3.0.0" - "@cspell/dict-golang" "^6.0.9" + "@cspell/dict-golang" "^6.0.12" "@cspell/dict-google" "^1.0.1" "@cspell/dict-haskell" "^4.0.1" "@cspell/dict-html" "^4.0.5" @@ -349,73 +350,73 @@ "@cspell/dict-makefile" "^1.0.0" "@cspell/dict-monkeyc" "^1.0.6" "@cspell/dict-node" "^5.0.1" - "@cspell/dict-npm" "^5.0.18" - "@cspell/dict-php" "^4.0.8" - "@cspell/dict-powershell" "^5.0.5" - "@cspell/dict-public-licenses" "^2.0.7" - "@cspell/dict-python" "^4.2.4" + "@cspell/dict-npm" "^5.1.4" + "@cspell/dict-php" "^4.0.10" + "@cspell/dict-powershell" "^5.0.8" + "@cspell/dict-public-licenses" "^2.0.8" + "@cspell/dict-python" "^4.2.6" "@cspell/dict-r" "^2.0.1" - "@cspell/dict-ruby" "^5.0.2" + "@cspell/dict-ruby" "^5.0.3" "@cspell/dict-rust" "^4.0.5" "@cspell/dict-scala" "^5.0.3" - "@cspell/dict-software-terms" "^4.0.6" + "@cspell/dict-software-terms" "^4.1.3" "@cspell/dict-sql" "^2.1.5" "@cspell/dict-svelte" "^1.0.2" "@cspell/dict-swift" "^2.0.1" - "@cspell/dict-terraform" "^1.0.0" + "@cspell/dict-terraform" "^1.0.1" "@cspell/dict-typescript" "^3.1.6" "@cspell/dict-vue" "^3.0.0" -"@cspell/cspell-json-reporter@8.14.2": - version "8.14.2" - resolved "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.14.2.tgz#c05e6e0d6e63072e3f416c9b3088aa8329de19a1" - integrity sha512-TZavcnNIZKX1xC/GNj80RgFVKHCT4pHT0qm9jCsQFH2QJfyCrUlkEvotKGSQ04lAyCwWg6Enq95qhouF8YbKUQ== +"@cspell/cspell-json-reporter@8.14.4": + version "8.14.4" + resolved "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.14.4.tgz#4646c1963b9b02fea3faae3c5ee04fb6dda8548e" + integrity sha512-gJ6tQbGCNLyHS2iIimMg77as5MMAFv3sxU7W6tjLlZp8htiNZS7fS976g24WbT/hscsTT9Dd0sNHkpo8K3nvVw== dependencies: - "@cspell/cspell-types" "8.14.2" + "@cspell/cspell-types" "8.14.4" -"@cspell/cspell-pipe@8.14.2": - version "8.14.2" - resolved "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.14.2.tgz#8f9df27fff5c6c55e29fa6967768a38b5494a665" - integrity sha512-aWMoXZAXEre0/M9AYWOW33YyOJZ06i4vvsEpWBDWpHpWQEmsR/7cMMgld8Pp3wlEjIUclUAKTYmrZ61PFWU/og== +"@cspell/cspell-pipe@8.14.4": + version "8.14.4" + resolved "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.14.4.tgz#5e81509d7c2763ac0e8c09b7989fe95e36fe0a05" + integrity sha512-CLLdouqfrQ4rqdQdPu0Oo+HHCU/oLYoEsK1nNPb28cZTFxnn0cuSPKB6AMPBJmMwdfJ6fMD0BCKNbEe1UNLHcw== -"@cspell/cspell-resolver@8.14.2": - version "8.14.2" - resolved "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.14.2.tgz#0cfaa0d0f613feab76ddb30a1d0a60d428726a0c" - integrity sha512-pSyBsAvslaN0dx0pHdvECJEuFDDBJGAD6G8U4BVbIyj2OPk0Ox0HrZIj6csYxxoJERAgNO/q7yCPwa4j9NNFXg== +"@cspell/cspell-resolver@8.14.4": + version "8.14.4" + resolved "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.14.4.tgz#839258970996c8262b290f6e8fbbac27d43fb0b8" + integrity sha512-s3uZyymJ04yn8+zlTp7Pt1WRSlAel6XVo+iZRxls3LSvIP819KK64DoyjCD2Uon0Vg9P/K7aAPt8GcxDcnJtgA== dependencies: global-directory "^4.0.1" -"@cspell/cspell-service-bus@8.14.2": - version "8.14.2" - resolved "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.14.2.tgz#f0d317fd4de99700b2b7f10b05d88dc2ea55d7f8" - integrity sha512-WUF7xf3YgXYIqjmBwLcVugYIrYL4WfXchgSo9rmbbnOcAArzsK+HKfzb4AniZAJ1unxcIQ0JnVlRmnCAKPjjLg== +"@cspell/cspell-service-bus@8.14.4": + version "8.14.4" + resolved "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.14.4.tgz#3c081578c7a369e4a737311e8ee31e709a48abb8" + integrity sha512-i3UG+ep63akNsDXZrtGgICNF3MLBHtvKe/VOIH6+L+NYaAaVHqqQvOY9MdUwt1HXh8ElzfwfoRp36wc5aAvt6g== -"@cspell/cspell-types@8.14.2": - version "8.14.2" - resolved "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.14.2.tgz#e1bae42766b43ff6d943b57bb7830bc873f25c94" - integrity sha512-MRY8MjBNOKGMDSkxAKueYAgVL43miO+lDcLCBBP+7cNXqHiUFMIZteONcGp3kJT0dWS04dN6lKAXvaNF0aWcng== +"@cspell/cspell-types@8.14.4": + version "8.14.4" + resolved "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.14.4.tgz#93ceff0bcefe75c259ae3475961f580f3de36e79" + integrity sha512-VXwikqdHgjOVperVVCn2DOe8W3rPIswwZtMHfRYnagpzZo/TOntIjkXPJSfTtl/cFyx5DnCBsDH8ytKGlMeHkw== "@cspell/dict-ada@^4.0.2": version "4.0.2" resolved "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.0.2.tgz" integrity sha512-0kENOWQeHjUlfyId/aCM/mKXtkEgV0Zu2RhUXCBr4hHo9F9vph+Uu8Ww2b0i5a4ZixoIkudGA+eJvyxrG1jUpA== -"@cspell/dict-aws@^4.0.3": +"@cspell/dict-aws@^4.0.4": version "4.0.4" resolved "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.4.tgz#638a38df18c93d5cb74607b24ab4e1498825d565" integrity sha512-6AWI/Kkf+RcX/J81VX8+GKLeTgHWEr/OMhGk3dHQzWK66RaqDJCGDqi7494ghZKcBB7dGa3U5jcKw2FZHL/u3w== -"@cspell/dict-bash@^4.1.3": - version "4.1.3" - resolved "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.1.3.tgz" - integrity sha512-tOdI3QVJDbQSwPjUkOiQFhYcu2eedmX/PtEpVWg0aFps/r6AyjUQINtTgpqMYnYuq8O1QUIQqnpx21aovcgZCw== +"@cspell/dict-bash@^4.1.4": + version "4.1.4" + resolved "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.1.4.tgz#a7942df189d3cc5ebced5b877d64ddbb24301137" + integrity sha512-W/AHoQcJYn3Vn/tUiXX2+6D/bhfzdDshwcbQWv9TdiNlXP9P6UJjDKWbxyA5ogJCsR2D0X9Kx11oV8E58siGKQ== "@cspell/dict-companies@^3.1.4": version "3.1.4" resolved "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.1.4.tgz#2e7094416432b8547ec335683f5aac9a49dce47e" integrity sha512-y9e0amzEK36EiiKx3VAA+SHQJPpf2Qv5cCt5eTUSggpTkiFkCh6gRKQ97rVlrKh5GJrqinDwYIJtTsxuh2vy2Q== -"@cspell/dict-cpp@^5.1.12": +"@cspell/dict-cpp@^5.1.16": version "5.1.16" resolved "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-5.1.16.tgz#e6557d5b916ebff02045b60f7016749e085921b0" integrity sha512-32fU5RkuOM55IRcxjByiSoKbjr+C4danDfYjHaQNRWdvjzJzci3fLDGA2wTXiclkgDODxGiV8LCTUwCz+3TNWA== @@ -435,10 +436,10 @@ resolved "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.13.tgz#b95310ba67694d25bcb055786dde65e091621d14" integrity sha512-WfOQkqlAJTo8eIQeztaH0N0P+iF5hsJVKFuhy4jmARPISy8Efcv8QXk2/IVbmjJH0/ZV7dKRdnY5JFVXuVz37g== -"@cspell/dict-dart@^2.0.3": - version "2.0.3" - resolved "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.0.3.tgz" - integrity sha512-cLkwo1KT5CJY5N5RJVHks2genFkNCl/WLfj+0fFjqNR+tk3tBI1LY7ldr9piCtSFSm4x9pO1x6IV3kRUY1lLiw== +"@cspell/dict-dart@^2.2.1": + version "2.2.1" + resolved "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.2.1.tgz#d5ef7632240cb19c8892e66ba5ed1089ab8e46a3" + integrity sha512-yriKm7QkoPx3JPSSOcw6iX9gOb2N50bOo/wqWviqPYbhpMRh9Xiv6dkUy3+ot+21GuShZazO8X6U5+Vw67XEwg== "@cspell/dict-data-science@^2.0.1": version "2.0.1" @@ -455,10 +456,10 @@ resolved "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.7.tgz" integrity sha512-XlXHAr822euV36GGsl2J1CkBIVg3fZ6879ZOg5dxTIssuhUOCiV2BuzKZmt6aIFmcdPmR14+9i9Xq+3zuxeX0A== -"@cspell/dict-dotnet@^5.0.2": - version "5.0.2" - resolved "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.2.tgz" - integrity sha512-UD/pO2A2zia/YZJ8Kck/F6YyDSpCMq0YvItpd4YbtDVzPREfTZ48FjZsbYi4Jhzwfvc6o8R56JusAE58P+4sNQ== +"@cspell/dict-dotnet@^5.0.5": + version "5.0.5" + resolved "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.5.tgz#0f614ef6fa052e7598a6fe20770a1e5bb19f0de1" + integrity sha512-gjg0L97ee146wX47dnA698cHm85e7EOpf9mVrJD8DmEaqoo/k1oPy2g7c7LgKxK9XnqwoXxhLNnngPrwXOoEtQ== "@cspell/dict-elixir@^4.0.3": version "4.0.3" @@ -485,6 +486,11 @@ resolved "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.4.tgz" integrity sha512-IBi8eIVdykoGgIv5wQhOURi5lmCNJq0we6DvqKoPQJHthXbgsuO1qrHSiUVydMiQl/XvcnUWTMeAlVUlUClnVg== +"@cspell/dict-flutter@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@cspell/dict-flutter/-/dict-flutter-1.0.0.tgz#9179aeb5e7544c061ffa3e5080a4c015f88efee3" + integrity sha512-W7k1VIc4KeV8BjEBxpA3cqpzbDWjfb7oXkEb0LecBCBp5Z7kcfnjT1YVotTx/U9PGyAOBhDaEdgZACVGNQhayw== + "@cspell/dict-fonts@^4.0.0": version "4.0.0" resolved "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-4.0.0.tgz" @@ -510,10 +516,10 @@ resolved "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-3.0.0.tgz" integrity sha512-simGS/lIiXbEaqJu9E2VPoYW1OTC2xrwPPXNXFMa2uo/50av56qOuaxDrZ5eH1LidFXwoc8HROCHYeKoNrDLSw== -"@cspell/dict-golang@^6.0.9": - version "6.0.9" - resolved "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.9.tgz" - integrity sha512-etDt2WQauyEQDA+qPS5QtkYTb2I9l5IfQftAllVoB1aOrT6bxxpHvMEpJ0Hsn/vezxrCqa/BmtUbRxllIxIuSg== +"@cspell/dict-golang@^6.0.12": + version "6.0.12" + resolved "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.12.tgz#a9d4c53edfec34d06a226a9af6af0df899bd720f" + integrity sha512-LEPeoqd+4O+vceHF73S7D7+LYfrAjOvp4Dqzh4MT30ruzlQ77yHRSuYOJtrFN1GK5ntAt/ILSVOKg9sgsz1Llg== "@cspell/dict-google@^1.0.1": version "1.0.1" @@ -580,27 +586,27 @@ resolved "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-5.0.1.tgz" integrity sha512-lax/jGz9h3Dv83v8LHa5G0bf6wm8YVRMzbjJPG/9rp7cAGPtdrga+XANFq+B7bY5+jiSA3zvj10LUFCFjnnCCg== -"@cspell/dict-npm@^5.0.18": - version "5.1.4" - resolved "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.1.4.tgz#2359f2c0256080aea0a01440c6f3e78ea75df64d" - integrity sha512-yzqVTY4P5neom4z9orV2IFOqDZ7fDotmisP7nwQkEmftoELgn5CUtNdnJhWDoDQQn6yrxOxA8jEqmyETIWzN4Q== +"@cspell/dict-npm@^5.1.4": + version "5.1.5" + resolved "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.1.5.tgz#f3a7317988052494f776a6b60e3bffb3f063a006" + integrity sha512-oAOGWuJYU3DlO+cAsStKMWN8YEkBue25cRC9EwdiL5Z84nchU20UIoYrLfIQejMlZca+1GyrNeyxRAgn4KiivA== -"@cspell/dict-php@^4.0.8": +"@cspell/dict-php@^4.0.10": version "4.0.10" resolved "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.0.10.tgz#e2ad4d3e30ec009824d9663a795f6281ae39caaf" integrity sha512-NfTZdp6kcZDF1PvgQ6cY0zE4FUO5rSwNmBH/iwCBuaLfJAFQ97rgjxo+D2bic4CFwNjyHutnHPtjJBRANO5XQw== -"@cspell/dict-powershell@^5.0.5": - version "5.0.8" - resolved "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.8.tgz#185c454c633e72ebd708328f2cf6dbbc5028ae0a" - integrity sha512-Eg64BccQp5oEJ+V/O2G27KaLWmuOL2AWMOs2470adUihOleRfW8j9XwAEGCS+JKSnDb2mksWA72Z6kDqH138IQ== +"@cspell/dict-powershell@^5.0.8": + version "5.0.9" + resolved "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.9.tgz#124212c8ae616356a9119e8010723fb5ac85e317" + integrity sha512-Vi0h0rlxS39tgTyUtxI6L3BPHH7MLPkLWCYkNfb/buQuNJYNFdHiF4bqoqVdJ/7ZrfIfNg4i6rzocnwGRn2ruw== -"@cspell/dict-public-licenses@^2.0.7": +"@cspell/dict-public-licenses@^2.0.8": version "2.0.8" resolved "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.8.tgz#ed8c3b5b22f28129cf3517821740599f05733b68" integrity sha512-Sup+tFS7cDV0fgpoKtUqEZ6+fA/H+XUgBiqQ/Fbs6vUE3WCjJHOIVsP+udHuyMH7iBfJ4UFYOYeORcY4EaKdMg== -"@cspell/dict-python@^4.2.4": +"@cspell/dict-python@^4.2.6": version "4.2.6" resolved "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.6.tgz#fce9950d59c6707442af04701d4ed7c7be333901" integrity sha512-Hkz399qDGEbfXi9GYa2hDl7GahglI86JmS2F1KP8sfjLXofUgtnknyC5NWc86nzHcP38pZiPqPbTigyDYw5y8A== @@ -612,10 +618,10 @@ resolved "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.0.1.tgz" integrity sha512-KCmKaeYMLm2Ip79mlYPc8p+B2uzwBp4KMkzeLd5E6jUlCL93Y5Nvq68wV5fRLDRTf7N1LvofkVFWfDcednFOgA== -"@cspell/dict-ruby@^5.0.2": - version "5.0.2" - resolved "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.0.2.tgz" - integrity sha512-cIh8KTjpldzFzKGgrqUX4bFyav5lC52hXDKo4LbRuMVncs3zg4hcSf4HtURY+f2AfEZzN6ZKzXafQpThq3dl2g== +"@cspell/dict-ruby@^5.0.3": + version "5.0.3" + resolved "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.0.3.tgz#614e9a3d4dcd720e750c037b9dfb6001da8b25e0" + integrity sha512-V1xzv9hN6u8r6SM4CkYdsxs4ov8gjXXo0Twfx5kWhLXbEVxTXDMt7ohLTqpy2XlF5mutixZdbHMeFiAww8v+Ug== "@cspell/dict-rust@^4.0.5": version "4.0.5" @@ -627,10 +633,10 @@ resolved "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.3.tgz#85a469b2d139766b6307befc89243928e3d82b39" integrity sha512-4yGb4AInT99rqprxVNT9TYb1YSpq58Owzq7zi3ZS5T0u899Y4VsxsBiOgHnQ/4W+ygi+sp+oqef8w8nABR2lkg== -"@cspell/dict-software-terms@^4.0.6": - version "4.1.3" - resolved "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-4.1.3.tgz#364ff43034900dc508af376f06042de75ed53297" - integrity sha512-5Wn5JG4IzCboX5pjISdkipsPKGaz1//iuBZdHl4US5x7mO4jOGXLpjzx6ZoPM4PXUlMEFz9NJRCDepAu8fXVtA== +"@cspell/dict-software-terms@^4.1.3": + version "4.1.4" + resolved "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-4.1.4.tgz#9b0da3e0674230d757e82ef67171db0764e17a16" + integrity sha512-AHS25sYEzWze/aFglp9ODKSu+phjkuGx+OLwIcmOnvyn8axtSq5GCn9UqS4XG1/Qn0UG2Lgb4i5PJbZ0QNPNXQ== "@cspell/dict-sql@^2.1.5": version "2.1.5" @@ -647,10 +653,10 @@ resolved "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.1.tgz" integrity sha512-gxrCMUOndOk7xZFmXNtkCEeroZRnS2VbeaIPiymGRHj5H+qfTAzAKxtv7jJbVA3YYvEzWcVE2oKDP4wcbhIERw== -"@cspell/dict-terraform@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.0.0.tgz" - integrity sha512-Ak+vy4HP/bOgzf06BAMC30+ZvL9mzv21xLM2XtfnBLTDJGdxlk/nK0U6QT8VfFLqJ0ZZSpyOxGsUebWDCTr/zQ== +"@cspell/dict-terraform@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.0.1.tgz#81648af2e7f19e8b3188be5e7b1a2d2b6627f58b" + integrity sha512-29lmUUnZgPh+ieZ5hunick8hzNIpNRtiJh9vAusNskPCrig3RTW6u7F+GG1a8uyslbzSw+Irjf40PTOan1OJJA== "@cspell/dict-typescript@^3.1.6": version "3.1.6" @@ -662,27 +668,27 @@ resolved "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.0.tgz" integrity sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A== -"@cspell/dynamic-import@8.14.2": - version "8.14.2" - resolved "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.14.2.tgz#4968d1b6b20806f9bb78b92c628300cad288072f" - integrity sha512-5MbqtIligU7yPwHWU/5yFCgMvur4i1bRAF1Cy8y2dDtHsa204S/w/SaXs+51EFLp2eNbCiBisCBrwJFT7R1RxA== +"@cspell/dynamic-import@8.14.4": + version "8.14.4" + resolved "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.14.4.tgz#c3a8a9f5a8c6d6f8ccd2612a367bcc870dd07244" + integrity sha512-GjKsBJvPXp4dYRqsMn7n1zpnKbnpfJnlKLOVeoFBh8fi4n06G50xYr+G25CWX1WT3WFaALAavvVICEUPrVsuqg== dependencies: import-meta-resolve "^4.1.0" -"@cspell/filetypes@8.14.2": - version "8.14.2" - resolved "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-8.14.2.tgz#e05d48a504efa72d9cebd9fb45b666e116673335" - integrity sha512-ZevArA0mWeVTTqHicxCPZIAeCibpY3NwWK/x6d1Lgu7RPk/daoGAM546Q2SLChFu+r10tIH7pRG212A6Q9ihPA== +"@cspell/filetypes@8.14.4": + version "8.14.4" + resolved "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-8.14.4.tgz#2f8b705d5b7df68817702899f9a94282ac4eef40" + integrity sha512-qd68dD7xTA4Mnf/wjIKYz2SkiTBshIM+yszOUtLa06YJm0aocoNQ25FHXyYEQYm9NQXCYnRWWA02sFMGs8Sv/w== -"@cspell/strong-weak-map@8.14.2": - version "8.14.2" - resolved "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.14.2.tgz#4fd8fd616690125775c0f7a596a1295b03e9a43d" - integrity sha512-7sRzJc392CQYNNrtdPEfOHJdRqsqf6nASCtbS5A9hL2UrdWQ4uN7r/D+Y1HpuizwY9eOkZvarcFfsYt5wE0Pug== +"@cspell/strong-weak-map@8.14.4": + version "8.14.4" + resolved "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.14.4.tgz#31a34bc7963d2c18d6cda391b2ddda58b9cb3061" + integrity sha512-Uyfck64TfVU24wAP3BLGQ5EsAfzIZiLfN90NhttpEM7GlOBmbGrEJd4hNOwfpYsE/TT80eGWQVPRTLr5SDbXFA== -"@cspell/url@8.14.2": - version "8.14.2" - resolved "https://registry.npmjs.org/@cspell/url/-/url-8.14.2.tgz#8a6d30011596ccefb48a6135225554011c46dc03" - integrity sha512-YmWW+B/2XQcCynLpiAQF77Bitm5Cynw3/BICZkbdveKjJkUzEmXB+U2qWuwXOyU8xUYuwkP63YM8McnI567rUA== +"@cspell/url@8.14.4": + version "8.14.4" + resolved "https://registry.npmjs.org/@cspell/url/-/url-8.14.4.tgz#46c17d7da0f04fe032ece932ed8137852062341c" + integrity sha512-htHhNF8WrM/NfaLSWuTYw0NqVgFRVHYSyHlRT3i/Yv5xvErld8Gw7C6ldm+0TLjoGlUe6X1VV72JSir7+yLp/Q== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" @@ -2274,80 +2280,80 @@ crypto-random-string@^4.0.0: dependencies: type-fest "^1.0.1" -cspell-config-lib@8.14.2: - version "8.14.2" - resolved "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.14.2.tgz#cc401080c14dab7b355bda4e90a22b7dfb05ffd6" - integrity sha512-yHP1BdcH5dbjb8qiZr6+bxEnJ+rxTULQ00wBz3eBPWCghJywEAYYvMWoYuxVtPpndlkKYC1wJAHsyNkweQyepA== +cspell-config-lib@8.14.4: + version "8.14.4" + resolved "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.14.4.tgz#4642d22c4db22dd1b8923005ff369a24ff541f62" + integrity sha512-cnUeJfniTiebqCaQmIUnbSrPrTH7xzKRQjJDHAEV0WYnOG2MhRXI13OzytdFdhkVBdStmgTzTCJKE7x+kmU2NA== dependencies: - "@cspell/cspell-types" "8.14.2" + "@cspell/cspell-types" "8.14.4" comment-json "^4.2.5" - yaml "^2.5.0" + yaml "^2.5.1" -cspell-dictionary@8.14.2: - version "8.14.2" - resolved "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.14.2.tgz#0268d437eed78bfcf6eadc3674a3e3104e010d7a" - integrity sha512-gWuAvf6queGGUvGbfAxxUq55cZ0OevWPbjnCrSB0PpJ4tqdFd8dLcvVrIKzoE2sBXKPw2NDkmoEngs6iGavC0w== +cspell-dictionary@8.14.4: + version "8.14.4" + resolved "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.14.4.tgz#d6bfaa972785b184499d7f81791c913440229de4" + integrity sha512-pZvQHxpAW5fZAnt3ZKKy3s7M+3CX2t8tCS3uJrpEHIynlCawpG0fPF78rVE5o+g0dON36Lguc/BUuSN4IWKLmQ== dependencies: - "@cspell/cspell-pipe" "8.14.2" - "@cspell/cspell-types" "8.14.2" - cspell-trie-lib "8.14.2" + "@cspell/cspell-pipe" "8.14.4" + "@cspell/cspell-types" "8.14.4" + cspell-trie-lib "8.14.4" fast-equals "^5.0.1" -cspell-gitignore@8.14.2: - version "8.14.2" - resolved "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.14.2.tgz#239995ac11652a9978126ec35b12d663010a90f3" - integrity sha512-lrO/49NaKBpkR7vFxv4OOY+oHmsG5+gNQejrBBWD9Nv9vvjJtz/G36X/rcN6M6tFcQQMWwa01kf04nxz8Ejuhg== +cspell-gitignore@8.14.4: + version "8.14.4" + resolved "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.14.4.tgz#bb53748ed93af980ed7c5772577ccdedada85293" + integrity sha512-RwfQEW5hD7CpYwS7m3b0ONG0nTLKP6bL2tvMdl7qtaYkL7ztGdsBTtLD1pmwqUsCbiN5RuaOxhYOYeRcpFRIkQ== dependencies: - "@cspell/url" "8.14.2" - cspell-glob "8.14.2" - cspell-io "8.14.2" + "@cspell/url" "8.14.4" + cspell-glob "8.14.4" + cspell-io "8.14.4" find-up-simple "^1.0.0" -cspell-glob@8.14.2: - version "8.14.2" - resolved "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.14.2.tgz#09f53191e58db113837a088a7a9ea7a181f2deb7" - integrity sha512-9Q1Kgoo1ev3fKTpp9y5n8M4RLxd8B0f5o4y5FQe4dBU0j/bt+/YDrLZNWDm77JViV606XQ6fimG1FTTq6pT9/g== - dependencies: - "@cspell/url" "8.14.2" - micromatch "^4.0.7" - -cspell-grammar@8.14.2: - version "8.14.2" - resolved "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.14.2.tgz#a37e4f6ce6aae8eba2ba57822a4cfe0cd7fd8909" - integrity sha512-eYwceVP80FGYVJenE42ALnvEKOXaXjq4yVbb1Ni1umO/9qamLWNCQ1RP6rRACy5e/cXviAbhrQ5Mtw6n+pyPEQ== - dependencies: - "@cspell/cspell-pipe" "8.14.2" - "@cspell/cspell-types" "8.14.2" - -cspell-io@8.14.2: - version "8.14.2" - resolved "https://registry.npmjs.org/cspell-io/-/cspell-io-8.14.2.tgz#501b26c630f6d8e9fc89fce1ad806c10b440723a" - integrity sha512-uaKpHiY3DAgfdzgKMQml6U8F8o9udMuYxGqYa5FVfN7D5Ap7B2edQzSLTUYwxrFEn4skSfp6XY73+nzJvxzH4Q== - dependencies: - "@cspell/cspell-service-bus" "8.14.2" - "@cspell/url" "8.14.2" - -cspell-lib@8.14.2: - version "8.14.2" - resolved "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.14.2.tgz#ca404ad026c7150c96426a11faa5c9f761015bbb" - integrity sha512-d2oiIXHXnADmnhIuFLOdNE63L7OUfzgpLbYaqAWbkImCUDkevfGrOgnX8TJ03fUgZID4nvQ+3kgu/n2j4eLZjQ== - dependencies: - "@cspell/cspell-bundled-dicts" "8.14.2" - "@cspell/cspell-pipe" "8.14.2" - "@cspell/cspell-resolver" "8.14.2" - "@cspell/cspell-types" "8.14.2" - "@cspell/dynamic-import" "8.14.2" - "@cspell/filetypes" "8.14.2" - "@cspell/strong-weak-map" "8.14.2" - "@cspell/url" "8.14.2" +cspell-glob@8.14.4: + version "8.14.4" + resolved "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.14.4.tgz#b5abbaa291f3d17d5e52a33d26193a29761e30c8" + integrity sha512-C/xTS5nujMRMuguibq92qMVP767mtxrur7DcVolCvpzcivm1RB5NtIN0OctQxTyMbnmKeQv1t4epRKQ9A8vWRg== + dependencies: + "@cspell/url" "8.14.4" + micromatch "^4.0.8" + +cspell-grammar@8.14.4: + version "8.14.4" + resolved "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.14.4.tgz#a047c9d365127f9e7688eebb649b14a8a7b0ce9e" + integrity sha512-yaSKAAJDiamsw3FChbw4HXb2RvTQrDsLelh1+T4MavarOIcAxXrqAJ8ysqm++g+S/ooJz2YO8YWIyzJKxcMf8g== + dependencies: + "@cspell/cspell-pipe" "8.14.4" + "@cspell/cspell-types" "8.14.4" + +cspell-io@8.14.4: + version "8.14.4" + resolved "https://registry.npmjs.org/cspell-io/-/cspell-io-8.14.4.tgz#fa80333f473fd04973b850c25116b6392f6c88a3" + integrity sha512-o6OTWRyx/Az+PFhr1B0wMAwqG070hFC9g73Fkxd8+rHX0rfRS69QZH7LgSmZytqbZIMxCTDGdsLl33MFGWCbZQ== + dependencies: + "@cspell/cspell-service-bus" "8.14.4" + "@cspell/url" "8.14.4" + +cspell-lib@8.14.4: + version "8.14.4" + resolved "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.14.4.tgz#f59f3141c3b9b44b46defc927365e484a1f7d1cc" + integrity sha512-qdkUkKtm+nmgpA4jQbmQTuepDfjHBDWvs3zDuEwVIVFq/h8gnXrRr75gJ3RYdTy+vOOqHPoLLqgxyqkUUrUGXA== + dependencies: + "@cspell/cspell-bundled-dicts" "8.14.4" + "@cspell/cspell-pipe" "8.14.4" + "@cspell/cspell-resolver" "8.14.4" + "@cspell/cspell-types" "8.14.4" + "@cspell/dynamic-import" "8.14.4" + "@cspell/filetypes" "8.14.4" + "@cspell/strong-weak-map" "8.14.4" + "@cspell/url" "8.14.4" clear-module "^4.1.2" comment-json "^4.2.5" - cspell-config-lib "8.14.2" - cspell-dictionary "8.14.2" - cspell-glob "8.14.2" - cspell-grammar "8.14.2" - cspell-io "8.14.2" - cspell-trie-lib "8.14.2" + cspell-config-lib "8.14.4" + cspell-dictionary "8.14.4" + cspell-glob "8.14.4" + cspell-grammar "8.14.4" + cspell-io "8.14.4" + cspell-trie-lib "8.14.4" env-paths "^3.0.0" fast-equals "^5.0.1" gensequence "^7.0.0" @@ -2357,36 +2363,36 @@ cspell-lib@8.14.2: vscode-uri "^3.0.8" xdg-basedir "^5.1.0" -cspell-trie-lib@8.14.2: - version "8.14.2" - resolved "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.14.2.tgz#3748544d4f6ca85c3d72a1f2eb72b930c898865b" - integrity sha512-rZMbaEBGoyy4/zxKECaMyVyGLbuUxYmZ5jlEgiA3xPtEdWwJ4iWRTo5G6dWbQsXoxPYdAXXZ0/q0GQ2y6Jt0kw== +cspell-trie-lib@8.14.4: + version "8.14.4" + resolved "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.14.4.tgz#1cc1d1110edc0d208a027b1bdc3cbec1a15ea7f8" + integrity sha512-zu8EJ33CH+FA5lwTRGqS//Q6phO0qtgEmODMR1KPlD7WlrfTFMb3bWFsLo/tiv5hjpsn7CM6dYDAAgBOSkoyhQ== dependencies: - "@cspell/cspell-pipe" "8.14.2" - "@cspell/cspell-types" "8.14.2" + "@cspell/cspell-pipe" "8.14.4" + "@cspell/cspell-types" "8.14.4" gensequence "^7.0.0" cspell@^8.8.3: - version "8.14.2" - resolved "https://registry.npmjs.org/cspell/-/cspell-8.14.2.tgz#d1434bc66831113121a91427c39dc22802dc4c31" - integrity sha512-ii/W7fwO4chNQVYl1C/8k7RW8EXzLb69rvg08p8mSJx8B2UasVJ9tuJpTH2Spo1jX6N3H0dKPWUbd1fAmdAhPg== - dependencies: - "@cspell/cspell-json-reporter" "8.14.2" - "@cspell/cspell-pipe" "8.14.2" - "@cspell/cspell-types" "8.14.2" - "@cspell/dynamic-import" "8.14.2" - "@cspell/url" "8.14.2" + version "8.14.4" + resolved "https://registry.npmjs.org/cspell/-/cspell-8.14.4.tgz#a160fefcaf7158b8fa435245936b4f0426dc8736" + integrity sha512-R5Awb3i/RKaVVcZzFt8dkN3M6VnifIEDYBcbzbmYjZ/Eq+ASF+QTmI0E9WPhMEcFM1nd7YOyXnETo560yRdoKw== + dependencies: + "@cspell/cspell-json-reporter" "8.14.4" + "@cspell/cspell-pipe" "8.14.4" + "@cspell/cspell-types" "8.14.4" + "@cspell/dynamic-import" "8.14.4" + "@cspell/url" "8.14.4" chalk "^5.3.0" chalk-template "^1.1.0" commander "^12.1.0" - cspell-dictionary "8.14.2" - cspell-gitignore "8.14.2" - cspell-glob "8.14.2" - cspell-io "8.14.2" - cspell-lib "8.14.2" + cspell-dictionary "8.14.4" + cspell-gitignore "8.14.4" + cspell-glob "8.14.4" + cspell-io "8.14.4" + cspell-lib "8.14.4" fast-glob "^3.3.2" fast-json-stable-stringify "^2.1.0" - file-entry-cache "^9.0.0" + file-entry-cache "^9.1.0" get-stdin "^9.0.0" semver "^7.6.3" strip-ansi "^7.1.0" @@ -2862,7 +2868,7 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -file-entry-cache@^9.0.0: +file-entry-cache@^9.1.0: version "9.1.0" resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz#2e66ad98ce93f49aed1b178c57b0b5741591e075" integrity sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg== @@ -4115,9 +4121,9 @@ kleur@^3.0.3: integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== knip@^5.24.1: - version "5.30.5" - resolved "https://registry.npmjs.org/knip/-/knip-5.30.5.tgz#0455d7969bfb02c11bcd0c3062d79529c87cfda1" - integrity sha512-opta1VVKAfIzhvj1iyOr/3SgSDC6jYPoUaYkvjftNqMTeURppYY5VqrAa5DOcJnIsdcAdyoIKHUFg9NRiFaM5w== + version "5.30.6" + resolved "https://registry.npmjs.org/knip/-/knip-5.30.6.tgz#798dd6a7fe338025166b8b138bb183d6b8714b75" + integrity sha512-YkcnRVl0N99xZ7eaXE7KlH/4cPTCn6BGuk9KxINEdCMFN3yita2vGBizApy97ZOHgghy8tb589gQ3xvLMFIO4w== dependencies: "@nodelib/fs.walk" "1.2.8" "@snyk/github-codeowners" "1.1.0" @@ -4316,7 +4322,7 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.4, micromatch@^4.0.7: +micromatch@^4.0.4, micromatch@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -5822,10 +5828,10 @@ yallist@^3.0.2: resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yaml@^2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d" - integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw== +yaml@^2.5.1: + version "2.5.1" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130" + integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q== yargs-parser@21.1.1, yargs-parser@^21.1.1: version "21.1.1"