Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions bbq/vm/test/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9512,6 +9512,43 @@ func TestGetAuthAccount(t *testing.T) {
})
}

func TestBoolToString(t *testing.T) {

t.Parallel()

t.Run("true", func(t *testing.T) {
t.Parallel()

result, err := CompileAndInvoke(t,
`
fun test(): String {
let x: Bool = true
return x.toString()
}
`,
"test",
)
require.NoError(t, err)
require.Equal(t, interpreter.NewUnmeteredStringValue("true"), result)
})

t.Run("false", func(t *testing.T) {
t.Parallel()

result, err := CompileAndInvoke(t,
`
fun test(): String {
let x: Bool = false
return x.toString()
}
`,
"test",
)
require.NoError(t, err)
require.Equal(t, interpreter.NewUnmeteredStringValue("false"), result)
})
}

func TestStringTemplate(t *testing.T) {

t.Parallel()
Expand Down Expand Up @@ -9550,6 +9587,23 @@ func TestStringTemplate(t *testing.T) {
require.NoError(t, err)
require.Equal(t, interpreter.NewUnmeteredStringValue("A + B = 4"), result)
})

t.Run("bool", func(t *testing.T) {
t.Parallel()

result, err := CompileAndInvoke(t,
`
fun test(): String {
let x = true
let y = false
return "\(x) and \(y)"
}
`,
"test",
)
require.NoError(t, err)
require.Equal(t, interpreter.NewUnmeteredStringValue("true and false"), result)
})
}

type assumeValidPublicKeyValidator struct{}
Expand Down
41 changes: 41 additions & 0 deletions bbq/vm/value_bool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Cadence - The resource-oriented smart contract programming language
*
* Copyright Flow Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package vm

import (
"github.com/onflow/cadence/bbq/commons"
"github.com/onflow/cadence/interpreter"
"github.com/onflow/cadence/sema"
)

// members

func init() {

typeName := commons.TypeQualifier(sema.BoolType)

registerBuiltinTypeBoundFunction(
typeName,
NewNativeFunctionValue(
sema.ToStringFunctionName,
sema.ToStringFunctionType,
interpreter.NativeBoolValueToStringFunction,
),
)
}
8 changes: 1 addition & 7 deletions bbq/vm/value_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,7 @@ import (

func init() {

for _, pathType := range []sema.Type{
sema.PathType,
sema.StoragePathType,
sema.CapabilityPathType,
sema.PublicPathType,
sema.PrivatePathType,
} {
for _, pathType := range sema.AllPathTypes {
typeName := commons.TypeQualifier(pathType)

registerBuiltinTypeBoundFunction(
Expand Down
34 changes: 34 additions & 0 deletions interpreter/builtinfunctions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,40 @@ func TestInterpretToString(t *testing.T) {
)
})

t.Run("Bool, true", func(t *testing.T) {

t.Parallel()

inter := parseCheckAndPrepare(t, `
let x: Bool = true
let y = x.toString()
`)

AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredStringValue("true"),
inter.GetGlobal("y"),
)
})

t.Run("Bool, false", func(t *testing.T) {

t.Parallel()

inter := parseCheckAndPrepare(t, `
let x: Bool = false
let y = x.toString()
`)

AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredStringValue("false"),
inter.GetGlobal("y"),
)
})

for _, ty := range sema.AllFixedPointTypes {

t.Run(ty.String(), func(t *testing.T) {
Expand Down
53 changes: 53 additions & 0 deletions interpreter/value_bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type BoolValue values.BoolValue
var _ Value = BoolValue(false)
var _ EquatableValue = BoolValue(false)
var _ HashableValue = BoolValue(false)
var _ MemberAccessibleValue = BoolValue(false)

const TrueValue = BoolValue(true)
const FalseValue = BoolValue(false)
Expand Down Expand Up @@ -191,3 +192,55 @@ func (v BoolValue) Clone(_ ValueCloneContext) Value {
func (BoolValue) DeepRemove(_ ValueRemoveContext, _ bool) {
// NO-OP
}

func (v BoolValue) GetMember(context MemberAccessibleContext, name string, memberKind common.DeclarationKind) Value {
return GetMember(
context,
v,
name,
memberKind,
nil,
)
}

func (v BoolValue) GetMethod(context MemberAccessibleContext, name string) FunctionValue {
switch name {
case sema.ToStringFunctionName:
return NewBoundHostFunctionValue(
context,
v,
sema.ToStringFunctionType,
NativeBoolValueToStringFunction,
)
}

return nil
}

var TrueStringValue = NewUnmeteredStringValue("true")
var FalseStringValue = NewUnmeteredStringValue("false")

var NativeBoolValueToStringFunction = NativeFunction(
func(
context NativeFunctionContext,
_ TypeArgumentsIterator,
_ ArgumentTypesIterator,
receiver Value,
_ []Value,
) Value {
if AssertValueOfType[BoolValue](receiver) {
return TrueStringValue
}
return FalseStringValue
},
)

func (BoolValue) RemoveMember(_ ValueTransferContext, _ string) Value {
// Bool has no removable members (fields / functions)
panic(errors.NewUnreachableError())
}

func (BoolValue) SetMember(_ ValueTransferContext, _ string, _ Value) bool {
// Bool has no settable members (fields / functions)
panic(errors.NewUnreachableError())
}
3 changes: 3 additions & 0 deletions sema/builtinfunctions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ func TestCheckToString(t *testing.T) {

for _, numberOrAddressType := range common.Concat(
sema.AllNumberTypes,
sema.AllPathTypes,
[]sema.Type{
sema.TheAddressType,
sema.BoolType,
sema.CharacterType,
},
) {

Expand Down
6 changes: 4 additions & 2 deletions sema/check_string_template_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ func (checker *Checker) VisitStringTemplateExpression(stringTemplateExpression *
for _, element := range stringTemplateExpression.Expressions {
valueType := checker.VisitExpression(element, stringTemplateExpression, elementType)

if !isValidStringTemplateValue(valueType) {
if !valueType.IsInvalidType() &&
!isValidStringTemplateValue(valueType) {

checker.report(
&TypeMismatchWithDescriptionError{
ActualType: valueType,
ExpectedTypeDescription: "a type with built-in toString() or bool",
ExpectedTypeDescription: "a built-in type with toString()",
Range: ast.NewRangeFromPositioned(checker.memoryGauge, element),
},
)
Expand Down
15 changes: 13 additions & 2 deletions sema/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,18 @@ func TestCheckStringTemplate(t *testing.T) {
require.NoError(t, err)
})

t.Run("valid, bool", func(t *testing.T) {

t.Parallel()

_, err := ParseAndCheck(t, `
let a = true
let x: String = "The value of a is: \(a)"
`)

require.NoError(t, err)
})

t.Run("invalid, struct", func(t *testing.T) {

t.Parallel()
Expand Down Expand Up @@ -785,10 +797,9 @@ func TestCheckStringTemplate(t *testing.T) {
let x: String = "\(a)"
`)

errs := RequireCheckerErrors(t, err, 2)
errs := RequireCheckerErrors(t, err, 1)

assert.IsType(t, &sema.NotDeclaredError{}, errs[0])
assert.IsType(t, &sema.TypeMismatchWithDescriptionError{}, errs[1])
})

t.Run("invalid, resource", func(t *testing.T) {
Expand Down
11 changes: 10 additions & 1 deletion sema/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,8 @@ func withBuiltinMembers(ty Type, members map[string]MemberResolver) map[string]M

func HasToStringFunction(ty Type) bool {
switch ty {
case CharacterType:
case BoolType,
CharacterType:
return true
default:
return IsSubType(ty, NumberType) ||
Expand Down Expand Up @@ -4712,6 +4713,14 @@ var AllNumberTypes = common.Concat(
},
)

var AllPathTypes = []Type{
PathType,
StoragePathType,
CapabilityPathType,
PublicPathType,
PrivatePathType,
}

var BuiltinEntitlements = map[string]*EntitlementType{}

var BuiltinEntitlementMappings = map[string]*EntitlementMapType{
Expand Down
Loading