tact
tact copied to clipboard
`self` in traits and contracts
Problem statement
Take a look at the following snippet.
import "@stdlib/deploy";
trait Trait {
id: Int;
get fun contractData(): Trait { // typechecker thinks it's ok here
return self;
}
}
contract Contract with Deployable, Trait {
id: Int as uint32 = 0;
}
Its compilation fail with the following error message:
💼 Compiling project test-trait ...
Tact compilation failed
Error: test-trait.tact:5:9: Type mismatch: "Contract" is not assignable to "Trait"
Line 5, col 9:
4 | get fun contractData(): Trait {
> 5 | return self;
^~~~~~~~~~~~
6 | }
Inside the Trait
trait the self
variable has type Trait
, but then contractData
gets re-typechecked as a contract getter inside the Contract
contract where self
has type Contract
.
Possible solutions
First of all, let me note that disallowing re-typechecking is not a solution, since during code generation we need the full type information.
Forbid using self
as a standalone variable
In other words, passing self
around, returning it from functions, including getters (see also a related issue: #579) would be prohibited. Only expressions of the form self.Var
would be allowed in this case.
This restriction's scope could be limited to traits only, so a whole-contract state getter featured in #579 is still possible.
Introduce Self
type variable
So self: Self
in any context (including mutating methods).
This would allow to generalize the type of the problematic getter as follows:
trait Trait {
id: Int;
get fun contractData(): Self { // `Self` means `Trait` here
return self;
}
}
But when the getter gets inserted in the contract scope, the contractData
's result type will be Contract
.
This solution would support to implement a trait that allows easier debugging by providing the whole contract state:
trait ContractStateGetter {
get fun contractState(): Self { return self }
}
which could be included automatically when the debug
config option is set to true.