Skip to content

Commit 2c89314

Browse files
authored
Merge pull request #4520 from onflow/supun/fix-inherited-code-from-same-contract
[Compiler] Fix compiling inherited code from same contract
2 parents 0fb572e + a1bb600 commit 2c89314

2 files changed

Lines changed: 29 additions & 4 deletions

File tree

bbq/compiler/compiler.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4723,10 +4723,10 @@ func (c *Compiler[_, _]) emitConvert(valueType, targetType sema.Type) {
47234723

47244724
func (c *Compiler[_, _]) getOrAddType(ty sema.Type) uint16 {
47254725
// When compiling an inherited code, if we come across a concrete contract type,
4726-
// then use a reference-type to it.
4727-
// An inherited code can never refer to the currently compiling contract (i.e: circular imports),
4728-
// so it's always safe to treat an inherited contract-variable type as a reference type.
4729-
if c.isInheritedCode {
4726+
// then use a reference-type to it if the contract is imported.
4727+
// Non-imported contracts (i.e: the enclosing contract of the current program) should be
4728+
// used as the concrete type, not as a reference.
4729+
if c.isInheritedCode && c.isImportedContract(ty) {
47304730
ty = sema.ImportedType(c.Config.MemoryGauge, ty)
47314731
}
47324732

@@ -4745,6 +4745,16 @@ func (c *Compiler[_, _]) getOrAddType(ty sema.Type) uint16 {
47454745
return index
47464746
}
47474747

4748+
func (c *Compiler[_, _]) isImportedContract(ty sema.Type) bool {
4749+
compositeType, isCompositeType := ty.(*sema.CompositeType)
4750+
if !isCompositeType || compositeType.Kind != common.CompositeKindContract {
4751+
return false
4752+
}
4753+
4754+
_, isImported := c.addedImports[compositeType.Location]
4755+
return isImported
4756+
}
4757+
47484758
func (c *Compiler[_, T]) addCompiledType(ty sema.Type, data T) uint16 {
47494759
count := len(c.compiledTypes)
47504760
if count >= math.MaxUint16 {

runtime/runtime_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14037,6 +14037,12 @@ func TestRuntimeContractAccessInInheritedCode(t *testing.T) {
1403714037
}
1403814038
}
1403914039
14040+
access(all) struct S: I {
14041+
// 'foo' function has an inherited pre-condition.
14042+
// It refers to the **same** contract inside the inherited code.
14043+
access(all) fun test() {}
14044+
}
14045+
1404014046
access(all) view fun someFunction(): Bool {
1404114047
return true
1404214048
}
@@ -14094,12 +14100,21 @@ func TestRuntimeContractAccessInInheritedCode(t *testing.T) {
1409414100
import Foo from %s
1409514101
1409614102
access(all) struct S: Foo.I {
14103+
// 'foo' function has an inherited pre-condition.
14104+
// It refers to an **imported** contract inside the inherited code.
1409714105
access(all) fun test() {}
1409814106
}
1409914107
1410014108
access(all) fun main() {
14109+
// 'S' struct is inheriting from a type (Foo.I) defined in an imported contract.
14110+
// So the pre-condition 'Foo.someFunction()' should refer to 'Foo' via a reference.
1410114111
let s = S()
1410214112
s.test()
14113+
14114+
// 'Foo.S' struct is inheriting from a type (Foo.I) defined in the same contract.
14115+
// So the pre-condition 'Foo.someFunction()' should refer to 'Foo' as the concrete type.
14116+
let fooS = Foo.S()
14117+
fooS.test()
1410314118
}`,
1410414119
addressValue.ShortHexWithPrefix(),
1410514120
)

0 commit comments

Comments
 (0)