From ce94b540c49f1b6c602da94630bf7d8984dd4ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 2 Jul 2024 10:07:12 -0700 Subject: [PATCH 1/2] fix toConstantSized: always return optional --- runtime/interpreter/value.go | 41 ++++++++++++------- runtime/tests/interpreter/interpreter_test.go | 37 +++++++++++++++++ 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 84e39ca244..ac4e647a92 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -3484,6 +3484,7 @@ func (v *ArrayValue) ToVariableSized( locationRange LocationRange, ) Value { var returnArrayStaticType ArrayStaticType + switch v.Type.(type) { case *ConstantSizedStaticType: returnArrayStaticType = NewVariableSizedStaticType( @@ -3536,33 +3537,41 @@ func (v *ArrayValue) ToConstantSized( interpreter *Interpreter, locationRange LocationRange, expectedConstantSizedArraySize int64, -) Value { - if int64(v.Count()) != expectedConstantSizedArraySize { +) OptionalValue { + + // Ensure the array has the expected size. + + count := v.Count() + + if int64(count) != expectedConstantSizedArraySize { return NilOptionalValue } - var returnArrayStaticType ArrayStaticType - switch v.Type.(type) { - case *VariableSizedStaticType: - returnArrayStaticType = NewConstantSizedStaticType( - interpreter, - v.Type.ElementType(), - expectedConstantSizedArraySize, - ) - default: + // Convert the variable-size array type to a constant-sized array type. + + variableSizedType, ok := v.Type.(*VariableSizedStaticType) + if !ok { panic(errors.NewUnreachableError()) } + constantSizedType := NewConstantSizedStaticType( + interpreter, + variableSizedType.Type, + expectedConstantSizedArraySize, + ) + + // Convert the array to a constant-sized array. + iterator, err := v.array.Iterator() if err != nil { panic(errors.NewExternalError(err)) } - return NewArrayValueWithIterator( + constantSizedArray := NewArrayValueWithIterator( interpreter, - returnArrayStaticType, + constantSizedType, common.ZeroAddress, - uint64(v.Count()), + uint64(count), func() Value { // Meter computation for iterating the array. @@ -3589,6 +3598,10 @@ func (v *ArrayValue) ToConstantSized( ) }, ) + + // Return the constant-sized array as an optional value. + + return NewSomeValueNonCopying(interpreter, constantSizedArray) } func (v *ArrayValue) SetType(staticType ArrayStaticType) { diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 70d72612f5..51630906ce 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -11518,6 +11518,43 @@ func TestInterpretArrayToConstantSized(t *testing.T) { ), ) }) + + t.Run("ensure result is optional", func(t *testing.T) { + t.Parallel() + + baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation) + baseValueActivation.DeclareValue(stdlib.PanicFunction) + + baseActivation := activations.NewActivation(nil, interpreter.BaseActivation) + interpreter.Declare(baseActivation, stdlib.PanicFunction) + + inter, err := parseCheckAndInterpretWithOptions(t, + ` + fun test(): [UInt8; 20] { + return "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + .decodeHex() + .toConstantSized<[UInt8; 20]>() + ?? panic("toConstantSized failed") + } + `, + ParseCheckAndInterpretOptions{ + CheckerConfig: &sema.Config{ + BaseValueActivationHandler: func(_ common.Location) *sema.VariableActivation { + return baseValueActivation + }, + }, + Config: &interpreter.Config{ + BaseActivationHandler: func(_ common.Location) *interpreter.VariableActivation { + return baseActivation + }, + }, + }, + ) + require.NoError(t, err) + + _, err = inter.Invoke("test") + require.NoError(t, err) + }) } func TestInterpretCastingBoxing(t *testing.T) { From bb69a7c324ce2f5e11311474395f827e7ff9e599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 2 Jul 2024 10:11:24 -0700 Subject: [PATCH 2/2] improve toVariableSized --- runtime/interpreter/value.go | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index ac4e647a92..33740d0b27 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -3483,18 +3483,21 @@ func (v *ArrayValue) ToVariableSized( interpreter *Interpreter, locationRange LocationRange, ) Value { - var returnArrayStaticType ArrayStaticType - switch v.Type.(type) { - case *ConstantSizedStaticType: - returnArrayStaticType = NewVariableSizedStaticType( - interpreter, - v.Type.ElementType(), - ) - default: + // Convert the constant-sized array type to a variable-sized array type. + + constantSizedType, ok := v.Type.(*ConstantSizedStaticType) + if !ok { panic(errors.NewUnreachableError()) } + variableSizedType := NewVariableSizedStaticType( + interpreter, + constantSizedType.Type, + ) + + // Convert the array to a variable-sized array. + iterator, err := v.array.Iterator() if err != nil { panic(errors.NewExternalError(err)) @@ -3502,7 +3505,7 @@ func (v *ArrayValue) ToVariableSized( return NewArrayValueWithIterator( interpreter, - returnArrayStaticType, + variableSizedType, common.ZeroAddress, uint64(v.Count()), func() Value { @@ -3547,7 +3550,7 @@ func (v *ArrayValue) ToConstantSized( return NilOptionalValue } - // Convert the variable-size array type to a constant-sized array type. + // Convert the variable-sized array type to a constant-sized array type. variableSizedType, ok := v.Type.(*VariableSizedStaticType) if !ok {