diff --git a/CHANGELOG.md b/CHANGELOG.md index 115764e52..78f1e532e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Name clashes with FunC keywords in struct constructor function parameters: PR [#467](https://github.com/tact-lang/tact/issues/467) - Error messages for traversing non-path-expressions in `foreach`-loops : PR [#479](https://github.com/tact-lang/tact/pull/479) +- Shadowing of trait constants by contract storage variables: PR [#480](https://github.com/tact-lang/tact/pull/480) ## [1.4.0] - 2024-06-21 diff --git a/src/types/__snapshots__/resolveDescriptors.spec.ts.snap b/src/types/__snapshots__/resolveDescriptors.spec.ts.snap index b94d78dc6..a93ab1856 100644 --- a/src/types/__snapshots__/resolveDescriptors.spec.ts.snap +++ b/src/types/__snapshots__/resolveDescriptors.spec.ts.snap @@ -245,6 +245,16 @@ Line 9, col 24: " `; +exports[`resolveDescriptors should fail descriptors for scope-storage-var-shadows-trait-const 1`] = ` +":8:3: Contract Foo inherits constant "storageReserve" from its traits and hence cannot have a storage variable with the same name +Line 8, col 3: + 7 | // is a virtual constant defined in BaseTrait +> 8 | storageReserve: Int; + ^~~~~~~~~~~~~~~~~~~ + 9 | +" +`; + exports[`resolveDescriptors should fail descriptors for scope-struct-shadows-contract 1`] = ` ":12:1: Type "Main" already exists Line 12, col 1: diff --git a/src/types/resolveDescriptors.ts b/src/types/resolveDescriptors.ts index 8b71e801a..61f3c7289 100644 --- a/src/types/resolveDescriptors.ts +++ b/src/types/resolveDescriptors.ts @@ -1402,6 +1402,14 @@ export function resolveDescriptors(ctx: CompilerContext) { t.ast.ref, ); } + const contractField = t.fields.find((v) => v.name === f.name); + if (contractField) { + // a trait constant has the same name as a contract field + throwCompilationError( + `Contract ${t.name} inherits constant "${f.name}" from its traits and hence cannot have a storage variable with the same name`, + contractField.ref, + ); + } // Register constant t.constants.push({ diff --git a/src/types/test-failed/scope-storage-var-shadows-trait-const.tact b/src/types/test-failed/scope-storage-var-shadows-trait-const.tact new file mode 100644 index 000000000..fbfcf5510 --- /dev/null +++ b/src/types/test-failed/scope-storage-var-shadows-trait-const.tact @@ -0,0 +1,13 @@ +primitive Int; + +trait BaseTrait { virtual const storageReserve: Int = 0; } + +contract Foo { + // this should be a var-scope error because storageReserve + // is a virtual constant defined in BaseTrait + storageReserve: Int; + + init() { + self.storageReserve = ton("0.05"); + } +}