diff --git a/encoding/ccf/ccf_test.go b/encoding/ccf/ccf_test.go index 788d88d085..ab29a3a975 100644 --- a/encoding/ccf/ccf_test.go +++ b/encoding/ccf/ccf_test.go @@ -6661,7 +6661,6 @@ func TestEncodeValueOfIntersectionType(t *testing.T) { ) countSumIntersectionType := cadence.NewIntersectionType( - nil, []cadence.Type{ hasCountInterfaceType, hasSumInterfaceType, @@ -6688,7 +6687,6 @@ func TestEncodeValueOfIntersectionType(t *testing.T) { ) expectedCountSumIntersectionType := cadence.NewIntersectionType( - nil, []cadence.Type{ hasSumInterfaceType, hasCountInterfaceType, @@ -6807,11 +6805,6 @@ func TestEncodeValueOfIntersectionType(t *testing.T) { 0xd8, ccf.CBORTagIntersectionType, // array, 2 items follow 0x82, - // type - // null - 0xf6, - // array, 2 items follow - 0x82, // tag 0xd8, ccf.CBORTagTypeRef, // bytes, 1 byte follows @@ -6882,7 +6875,6 @@ func TestEncodeValueOfIntersectionType(t *testing.T) { ) countSumIntersectionType := cadence.NewIntersectionType( - statsType, []cadence.Type{ hasCountInterfaceType, hasSumInterfaceType, @@ -6909,7 +6901,6 @@ func TestEncodeValueOfIntersectionType(t *testing.T) { ) expectedCountSumIntersectionType := cadence.NewIntersectionType( - expectedStatsType, []cadence.Type{ hasSumInterfaceType, hasCountInterfaceType, @@ -7028,13 +7019,6 @@ func TestEncodeValueOfIntersectionType(t *testing.T) { 0xd8, ccf.CBORTagIntersectionType, // array, 2 items follow 0x82, - // type - // tag - 0xd8, ccf.CBORTagTypeRef, - // bytes, 0 byte follows - 0x40, - // array, 2 items follow - 0x82, // tag 0xd8, ccf.CBORTagTypeRef, // bytes, 1 byte follows @@ -9465,13 +9449,7 @@ func TestEncodeType(t *testing.T) { t.Run("with static nil intersection type", func(t *testing.T) { t.Parallel() - testEncodeAndDecode( - t, - cadence.TypeValue{ - StaticType: &cadence.IntersectionType{ - Types: []cadence.Type{}, - }, - }, + encodedData := []byte{ // language=json, format=json-cdc // {"value":{"staticType":{"kind":"Intersection","type":"","types":[]}},"type":"Type"} @@ -9490,62 +9468,44 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, - // array, 2 elements follow - 0x82, - // null - 0xf6, // array, 0 element follows 0x80, - }, - ) + } + + _, err := ccf.Decode(nil, encodedData) + require.Error(t, err) + assert.Equal(t, "ccf: failed to decode: unexpected empty intersection type", err.Error()) + }) t.Run("with static no intersection type", func(t *testing.T) { t.Parallel() - testEncodeAndDecodeEx( - t, - cadence.TypeValue{ - StaticType: &cadence.IntersectionType{ - Types: []cadence.Type{}, - Type: cadence.IntType{}, - }, - }, - []byte{ - // language=json, format=json-cdc - // {"value":{"staticType":{"kind":"Intersection","typeID":"Int{String}","type":{"kind":"Int"},"types":[]}},"type":"Type"} - // - // language=edn, format=ccf - // 130([137(41), 191([185(4), []])]) - // - // language=cbor, format=ccf - // tag - 0xd8, ccf.CBORTagTypeAndValue, - // array, 2 elements follow - 0x82, - // tag - 0xd8, ccf.CBORTagSimpleType, - // Meta type ID (41) - 0x18, 0x29, - // tag - 0xd8, ccf.CBORTagIntersectionTypeValue, - // array, 2 elements follow - 0x82, - // tag - 0xd8, ccf.CBORTagSimpleTypeValue, - // Int type ID (4) - 0x04, - // array, 0 element follows - 0x80, - }, - // Expected decoded IntersectionType doesn't have type ID. - cadence.TypeValue{ - StaticType: &cadence.IntersectionType{ - Types: []cadence.Type{}, - Type: cadence.IntType{}, - }, - }, - ) + encodedData := []byte{ + // language=json, format=json-cdc + // {"value":{"staticType":{"kind":"Intersection","typeID":"Int{String}","type":{"kind":"Int"},"types":[]}},"type":"Type"} + // + // language=edn, format=ccf + // 130([137(41), 191([185(4), []])]) + // + // language=cbor, format=ccf + // tag + 0xd8, ccf.CBORTagTypeAndValue, + // array, 2 elements follow + 0x82, + // tag + 0xd8, ccf.CBORTagSimpleType, + // Meta type ID (41) + 0x18, 0x29, + // tag + 0xd8, ccf.CBORTagIntersectionTypeValue, + // array, 0 element follows + 0x80, + } + + _, err := ccf.Decode(nil, encodedData) + require.Error(t, err) + assert.Equal(t, "ccf: failed to decode: unexpected empty intersection type", err.Error()) }) t.Run("with static intersection type", func(t *testing.T) { @@ -9558,7 +9518,6 @@ func TestEncodeType(t *testing.T) { Types: []cadence.Type{ cadence.StringType{}, }, - Type: cadence.IntType{}, }, }, []byte{ @@ -9579,12 +9538,6 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, - // array, 2 elements follow - 0x82, - // tag - 0xd8, ccf.CBORTagSimpleTypeValue, - // Int type ID (4) - 0x04, // array, 1 element follows 0x81, // tag @@ -9598,7 +9551,6 @@ func TestEncodeType(t *testing.T) { Types: []cadence.Type{ cadence.StringType{}, }, - Type: cadence.IntType{}, }, }, ) @@ -9616,7 +9568,6 @@ func TestEncodeType(t *testing.T) { cadence.NewAnyStructType(), cadence.StringType{}, }, - Type: cadence.IntType{}, }, }, []byte{ @@ -9637,12 +9588,6 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, - // array, 2 elements follow - 0x82, - // tag - 0xd8, ccf.CBORTagSimpleTypeValue, - // Int type ID (4) - 0x04, // array, 2 element follows 0x82, // tag @@ -9661,7 +9606,6 @@ func TestEncodeType(t *testing.T) { cadence.StringType{}, cadence.NewAnyStructType(), }, - Type: cadence.IntType{}, }, }, ) @@ -9675,7 +9619,6 @@ func TestEncodeType(t *testing.T) { t, cadence.TypeValue{ StaticType: &cadence.IntersectionType{ - Type: cadence.TheAnyStructType, Types: []cadence.Type{ cadence.NewStructInterfaceType( common.NewAddressLocation(nil, common.Address{0x01}, "TypeA"), @@ -9716,12 +9659,6 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, - // array, 2 elements follow - 0x82, - // tag - 0xd8, ccf.CBORTagSimpleTypeValue, - // AnyStruct type ID (39) - 0x18, 0x27, // 3 sorted types // array, 3 element follows 0x83, @@ -9790,7 +9727,6 @@ func TestEncodeType(t *testing.T) { // Expected decoded IntersectionType has sorted types and no type ID. cadence.TypeValue{ StaticType: &cadence.IntersectionType{ - Type: cadence.TheAnyStructType, Types: []cadence.Type{ cadence.NewStructInterfaceType( common.IdentifierLocation("LocationC"), @@ -14439,7 +14375,7 @@ func TestEncodeValueOfIntersectedInterface(t *testing.T) { } struct MiddleStruct { - var field: AnyStruct{Interface} + var field: {Interface} } struct interface Interface {} @@ -14468,7 +14404,7 @@ func TestEncodeValueOfIntersectedInterface(t *testing.T) { []cadence.Field{ { Type: cadence.NewIntersectionType( - cadence.TheAnyStructType, []cadence.Type{interfaceType}), + []cadence.Type{interfaceType}), Identifier: "field", }, }, @@ -14599,12 +14535,6 @@ func TestEncodeValueOfIntersectedInterface(t *testing.T) { 0x66, 0x69, 0x65, 0x6c, 0x64, // tag 0xd8, ccf.CBORTagIntersectionType, - // array, 2 item follows - 0x82, - // tag - 0xd8, ccf.CBORTagSimpleType, - // AnyStruct type ID (39) - 0x18, 0x27, // array, 1 item follows 0x81, // tag @@ -14781,7 +14711,6 @@ func TestSortOptions(t *testing.T) { ) countSumIntersectionType := cadence.NewIntersectionType( - nil, []cadence.Type{ hasCountInterfaceType, hasSumInterfaceType, @@ -14809,7 +14738,6 @@ func TestSortOptions(t *testing.T) { ) expectedCountSumIntersectionType := cadence.NewIntersectionType( - nil, []cadence.Type{ hasCountInterfaceType, hasSumInterfaceType, @@ -14925,11 +14853,6 @@ func TestSortOptions(t *testing.T) { 0xd8, ccf.CBORTagIntersectionType, // array, 2 items follow 0x82, - // type - // null - 0xf6, - // array, 2 items follow - 0x82, // tag 0xd8, ccf.CBORTagTypeRef, // bytes, 1 byte follows @@ -15004,7 +14927,6 @@ func TestSortOptions(t *testing.T) { ) expectedCountSumIntersectionType := cadence.NewIntersectionType( - nil, []cadence.Type{ hasCountInterfaceType, hasSumInterfaceType, @@ -15120,11 +15042,6 @@ func TestSortOptions(t *testing.T) { 0xd8, ccf.CBORTagIntersectionType, // array, 2 items follow 0x82, - // type - // null - 0xf6, - // array, 2 items follow - 0x82, // tag 0xd8, ccf.CBORTagTypeRef, // bytes, 1 byte follows @@ -15199,7 +15116,6 @@ func TestSortOptions(t *testing.T) { ) expectedCountSumIntersectionType := cadence.NewIntersectionType( - nil, []cadence.Type{ hasSumInterfaceType, hasCountInterfaceType, @@ -15315,11 +15231,6 @@ func TestSortOptions(t *testing.T) { 0xd8, ccf.CBORTagIntersectionType, // array, 2 items follow 0x82, - // type - // null - 0xf6, - // array, 2 items follow - 0x82, // tag 0xd8, ccf.CBORTagTypeRef, // bytes, 1 byte follows @@ -15394,7 +15305,6 @@ func TestSortOptions(t *testing.T) { ) expectedCountSumIntersectionType := cadence.NewIntersectionType( - nil, []cadence.Type{ hasSumInterfaceType, hasCountInterfaceType, @@ -15510,11 +15420,6 @@ func TestSortOptions(t *testing.T) { 0xd8, ccf.CBORTagIntersectionType, // array, 2 items follow 0x82, - // type - // null - 0xf6, - // array, 2 items follow - 0x82, // tag 0xd8, ccf.CBORTagTypeRef, // bytes, 1 byte follows diff --git a/encoding/ccf/decode_type.go b/encoding/ccf/decode_type.go index 3008a17ab7..ff35c43578 100644 --- a/encoding/ccf/decode_type.go +++ b/encoding/ccf/decode_type.go @@ -553,23 +553,14 @@ func (d *Decoder) decodeIntersectionType( decodeTypeFn decodeTypeFn, decodeIntersectionTypeFn decodeTypeFn, ) (cadence.Type, error) { - // Decode array of length 2. - err := decodeCBORArrayWithKnownSize(d.dec, 2) - if err != nil { - return nil, err - } - - // element 0: type - typ, err := decodeTypeFn(types) - if err != nil { - return nil, err - } - - // element 1: types + // types typeCount, err := d.dec.DecodeArrayHead() if err != nil { return nil, err } + if typeCount == 0 { + return nil, errors.New("unexpected empty intersection type") + } intersectionTypeIDs := make(map[string]struct{}, typeCount) var previousIntersectionTypeID string @@ -611,9 +602,12 @@ func (d *Decoder) decodeIntersectionType( intersectionTypes[i] = intersectedType } + if len(intersectionTypes) == 0 { + return nil, errors.New("unexpected empty intersection type") + } + return cadence.NewMeteredIntersectionType( d.gauge, - typ, intersectionTypes, ), nil } diff --git a/encoding/ccf/encode_type.go b/encoding/ccf/encode_type.go index ce45b739e0..70f8bc0966 100644 --- a/encoding/ccf/encode_type.go +++ b/encoding/ccf/encode_type.go @@ -390,19 +390,7 @@ func (e *Encoder) encodeIntersectionTypeWithRawTag( return err } - // Encode array head of length 2. - err = e.enc.EncodeArrayHead(2) - if err != nil { - return err - } - - // element 0: type with given encodeTypeFn - err = encodeTypeFn(typ.Type, tids) - if err != nil { - return err - } - - // element 1: types as array. + // types as array. // Encode array head with number of types. intersectionTypes := typ.Types diff --git a/encoding/ccf/traverse_value.go b/encoding/ccf/traverse_value.go index e283594fac..bb6192cc00 100644 --- a/encoding/ccf/traverse_value.go +++ b/encoding/ccf/traverse_value.go @@ -145,7 +145,7 @@ func (ct *compositeTypes) traverseType(typ cadence.Type) (checkRuntimeType bool) return ct.traverseType(typ.Type) case *cadence.IntersectionType: - check := ct.traverseType(typ.Type) + check := false for _, typ := range typ.Types { checkTyp := ct.traverseType(typ) check = check || checkTyp diff --git a/encoding/json/decode.go b/encoding/json/decode.go index 18c2810e15..2a948492a6 100644 --- a/encoding/json/decode.go +++ b/encoding/json/decode.go @@ -1154,12 +1154,9 @@ func (d *Decoder) decodeNominalType( } func (d *Decoder) decodeIntersectionType( - typeValue any, intersectionValue []any, results typeDecodingResults, ) cadence.Type { - typ := d.decodeType(typeValue, results) - types := make([]cadence.Type, 0, len(intersectionValue)) for _, typ := range intersectionValue { types = append(types, d.decodeType(typ, results)) @@ -1167,7 +1164,6 @@ func (d *Decoder) decodeIntersectionType( return cadence.NewMeteredIntersectionType( d.gauge, - typ, types, ) } @@ -1206,9 +1202,7 @@ func (d *Decoder) decodeType(valueJSON any, results typeDecodingResults) cadence return d.decodeFunctionType(typeParametersValue, parametersValue, returnValue, purity, results) case "Intersection": intersectionValue := obj.Get(intersectionTypesKey) - typeValue := obj.Get(typeKey) return d.decodeIntersectionType( - typeValue, toSlice(intersectionValue), results, ) diff --git a/encoding/json/encode.go b/encoding/json/encode.go index ccce53eba7..2841838845 100644 --- a/encoding/json/encode.go +++ b/encoding/json/encode.go @@ -184,7 +184,6 @@ type jsonReferenceType struct { type jsonIntersectionType struct { Kind string `json:"kind"` TypeID string `json:"typeID"` - Type jsonValue `json:"type"` Types []jsonValue `json:"types"` } @@ -962,7 +961,6 @@ func prepareType(typ cadence.Type, results typePreparationResults) jsonValue { } return jsonIntersectionType{ Kind: "Intersection", - Type: prepareType(typ.Type, results), Types: types, TypeID: typ.ID(), } diff --git a/encoding/json/encoding_test.go b/encoding/json/encoding_test.go index c200cde1be..4e68542f6e 100644 --- a/encoding/json/encoding_test.go +++ b/encoding/json/encoding_test.go @@ -2766,7 +2766,6 @@ func TestEncodeType(t *testing.T) { Types: []cadence.Type{ cadence.StringType{}, }, - Type: cadence.IntType{}, }, }, // language=json @@ -2776,10 +2775,7 @@ func TestEncodeType(t *testing.T) { "value": { "staticType": { "kind": "Intersection", - "typeID": "Int{String}", - "type": { - "kind": "Int" - }, + "typeID": "{String}", "types": [ { "kind": "String" diff --git a/runtime/ast/type.go b/runtime/ast/type.go index 6c03e60005..d24767d75b 100644 --- a/runtime/ast/type.go +++ b/runtime/ast/type.go @@ -624,7 +624,6 @@ func (t *ReferenceType) CheckEqual(other Type, checker TypeEqualityChecker) erro // IntersectionType type IntersectionType struct { - Type Type `json:"IntersectionType"` Types []*NominalType Range } @@ -633,13 +632,11 @@ var _ Type = &IntersectionType{} func NewIntersectionType( memoryGauge common.MemoryGauge, - typ Type, types []*NominalType, astRange Range, ) *IntersectionType { common.UseMemory(memoryGauge, common.IntersectionTypeMemoryUsage) return &IntersectionType{ - Type: typ, Types: types, Range: astRange, } @@ -675,9 +672,6 @@ func (t *IntersectionType) Doc() prettier.Doc { } var doc prettier.Concat - if t.Type != nil { - doc = append(doc, t.Type.Doc()) - } return append(doc, prettier.Group{ diff --git a/runtime/ast/type_test.go b/runtime/ast/type_test.go index ffa11a9b1e..c3b81d5e97 100644 --- a/runtime/ast/type_test.go +++ b/runtime/ast/type_test.go @@ -1252,11 +1252,6 @@ func TestIntersectionType_Doc(t *testing.T) { t.Parallel() ty := &IntersectionType{ - Type: &NominalType{ - Identifier: Identifier{ - Identifier: "AB", - }, - }, Types: []*NominalType{ { Identifier: Identifier{ @@ -1273,7 +1268,6 @@ func TestIntersectionType_Doc(t *testing.T) { assert.Equal(t, prettier.Concat{ - prettier.Text("AB"), prettier.Group{ Doc: prettier.Concat{ prettier.Text("{"), @@ -1300,11 +1294,6 @@ func TestIntersectionType_String(t *testing.T) { t.Parallel() ty := &IntersectionType{ - Type: &NominalType{ - Identifier: Identifier{ - Identifier: "AB", - }, - }, Types: []*NominalType{ { Identifier: Identifier{ @@ -1320,7 +1309,7 @@ func TestIntersectionType_String(t *testing.T) { } assert.Equal(t, - "AB{CD, EF}", + "{CD, EF}", ty.String(), ) } @@ -1330,12 +1319,6 @@ func TestIntersectionType_MarshalJSON(t *testing.T) { t.Parallel() ty := &IntersectionType{ - Type: &NominalType{ - Identifier: Identifier{ - Identifier: "AB", - Pos: Position{Offset: 1, Line: 2, Column: 3}, - }, - }, Types: []*NominalType{ { Identifier: Identifier{ @@ -1364,16 +1347,6 @@ func TestIntersectionType_MarshalJSON(t *testing.T) { ` { "Type": "IntersectionType", - "IntersectionType": { - "Type": "NominalType", - "Identifier": { - "Identifier": "AB", - "StartPos": {"Offset": 1, "Line": 2, "Column": 3}, - "EndPos": {"Offset": 2, "Line": 2, "Column": 4} - }, - "StartPos": {"Offset": 1, "Line": 2, "Column": 3}, - "EndPos": {"Offset": 2, "Line": 2, "Column": 4} - }, "Types": [ { "Type": "NominalType", diff --git a/runtime/capabilitycontrollers_test.go b/runtime/capabilitycontrollers_test.go index 7e8ba64427..38072be912 100644 --- a/runtime/capabilitycontrollers_test.go +++ b/runtime/capabilitycontrollers_test.go @@ -554,8 +554,8 @@ func TestRuntimeCapabilityControllers(t *testing.T) { let expectedCapID: UInt64 = 1 // Arrange - let issuedCap: Capability<&AuthAccount{}> = - signer.capabilities.account.issue<&AuthAccount{}>() + let issuedCap: Capability<&AuthAccount> = + signer.capabilities.account.issue<&AuthAccount>() signer.capabilities.publish(issuedCap, at: publicPath) // Act @@ -1643,9 +1643,9 @@ func TestRuntimeCapabilityControllers(t *testing.T) { signer.capabilities.storage.issue<&Test.R>(storagePath1) let issuedCap2: Capability<&Test.R> = signer.capabilities.storage.issue<&Test.R>(storagePath1) - let issuedCap3: Capability<&Test.R{}> = - signer.capabilities.storage.issue<&Test.R{}>(storagePath1) - let issuedCap4: Capability<&Test.R{}> = + let issuedCap3: Capability<&Test.R> = + signer.capabilities.storage.issue<&Test.R>(storagePath1) + let issuedCap4: Capability<&Test.R> = signer.capabilities.storage.issue<&Test.R>(storagePath2) // Assert @@ -1730,8 +1730,8 @@ func TestRuntimeCapabilityControllers(t *testing.T) { signer.capabilities.storage.issue<&Test.R>(storagePath1) let issuedCap2: Capability<&Test.R> = signer.capabilities.storage.issue<&Test.R>(storagePath1) - let issuedCap3: Capability<&Test.R{}> = - signer.capabilities.storage.issue<&Test.R{}>(storagePath1) + let issuedCap3: Capability<&Test.R> = + signer.capabilities.storage.issue<&Test.R>(storagePath1) let issuedCap4: Capability<&Test.R> = signer.capabilities.storage.issue<&Test.R>(storagePath2) @@ -1755,7 +1755,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) { assert(controller2!.target() == storagePath1) assert(controller3!.capabilityID == 3) - assert(controller3!.borrowType == Type<&Test.R{}>()) + assert(controller3!.borrowType == Type<&Test.R>()) assert(controller3!.target() == storagePath1) assert(controller4!.capabilityID == 4) @@ -1787,8 +1787,8 @@ func TestRuntimeCapabilityControllers(t *testing.T) { signer.capabilities.storage.issue<&Test.R>(storagePath1) let issuedCap2: Capability<&Test.R> = signer.capabilities.storage.issue<&Test.R>(storagePath1) - let issuedCap3: Capability<&Test.R{}> = - signer.capabilities.storage.issue<&Test.R{}>(storagePath1) + let issuedCap3: Capability<&Test.R> = + signer.capabilities.storage.issue<&Test.R>(storagePath1) let issuedCap4: Capability<&Test.R> = signer.capabilities.storage.issue<&Test.R>(storagePath2) @@ -1872,8 +1872,8 @@ func TestRuntimeCapabilityControllers(t *testing.T) { signer.capabilities.storage.issue<&Test.R>(storagePath1) let issuedCap2: Capability<&Test.R> = signer.capabilities.storage.issue<&Test.R>(storagePath1) - let issuedCap3: Capability<&Test.R{}> = - signer.capabilities.storage.issue<&Test.R{}>(storagePath1) + let issuedCap3: Capability<&Test.R> = + signer.capabilities.storage.issue<&Test.R>(storagePath1) let issuedCap4: Capability<&Test.R> = signer.capabilities.storage.issue<&Test.R>(storagePath2) @@ -2117,8 +2117,8 @@ func TestRuntimeCapabilityControllers(t *testing.T) { signer.capabilities.account.issue<&AuthAccount>() let issuedCap2: Capability<&AuthAccount> = signer.capabilities.account.issue<&AuthAccount>() - let issuedCap3: Capability<&AuthAccount{}> = - signer.capabilities.account.issue<&AuthAccount{}>() + let issuedCap3: Capability<&AuthAccount> = + signer.capabilities.account.issue<&AuthAccount>() // Assert assert(issuedCap1.id == 1) @@ -2196,8 +2196,8 @@ func TestRuntimeCapabilityControllers(t *testing.T) { signer.capabilities.account.issue<&AuthAccount>() let issuedCap2: Capability<&AuthAccount> = signer.capabilities.account.issue<&AuthAccount>() - let issuedCap3: Capability<&AuthAccount{}> = - signer.capabilities.account.issue<&AuthAccount{}>() + let issuedCap3: Capability<&AuthAccount> = + signer.capabilities.account.issue<&AuthAccount>() // Act let controller1: &AccountCapabilityController? = @@ -2215,7 +2215,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) { assert(controller2!.borrowType == Type<&AuthAccount>()) assert(controller3!.capabilityID == 3) - assert(controller3!.borrowType == Type<&AuthAccount{}>()) + assert(controller3!.borrowType == Type<&AuthAccount>()) } } `, @@ -2240,8 +2240,8 @@ func TestRuntimeCapabilityControllers(t *testing.T) { signer.capabilities.account.issue<&AuthAccount>() let issuedCap2: Capability<&AuthAccount> = signer.capabilities.account.issue<&AuthAccount>() - let issuedCap3: Capability<&AuthAccount{}> = - signer.capabilities.account.issue<&AuthAccount{}>() + let issuedCap3: Capability<&AuthAccount> = + signer.capabilities.account.issue<&AuthAccount>() // Act let controllers: [&AccountCapabilityController] = @@ -2313,8 +2313,8 @@ func TestRuntimeCapabilityControllers(t *testing.T) { signer.capabilities.account.issue<&AuthAccount>() let issuedCap2: Capability<&AuthAccount> = signer.capabilities.account.issue<&AuthAccount>() - let issuedCap3: Capability<&AuthAccount{}> = - signer.capabilities.account.issue<&AuthAccount{}>() + let issuedCap3: Capability<&AuthAccount> = + signer.capabilities.account.issue<&AuthAccount>() // Act let controllers: [&AccountCapabilityController] = [] @@ -2572,8 +2572,8 @@ func TestRuntimeCapabilityControllers(t *testing.T) { let controller2: &StorageCapabilityController? = signer.capabilities.storage.getController(byCapabilityID: issuedCap2.id) - let issuedCap3: Capability<&Test.R{}> = - signer.capabilities.storage.issue<&Test.R{}>(storagePath1) + let issuedCap3: Capability<&Test.R> = + signer.capabilities.storage.issue<&Test.R>(storagePath1) let controller3: &StorageCapabilityController? = signer.capabilities.storage.getController(byCapabilityID: issuedCap3.id) diff --git a/runtime/contract_update_validation_test.go b/runtime/contract_update_validation_test.go index 9a3b1de7bf..dbf43a79b6 100644 --- a/runtime/contract_update_validation_test.go +++ b/runtime/contract_update_validation_test.go @@ -835,7 +835,7 @@ func TestRuntimeContractUpdateValidation(t *testing.T) { const oldCode = ` access(all) contract Test { - access(all) var x: AnyStruct{TestStruct}? + access(all) var x: {TestStruct}? init() { self.x = nil @@ -851,7 +851,7 @@ func TestRuntimeContractUpdateValidation(t *testing.T) { const newCode = ` access(all) contract Test { - access(all) var x: AnyStruct{TestStruct}? + access(all) var x: {TestStruct}? init() { self.x = nil @@ -1396,8 +1396,8 @@ func TestRuntimeContractUpdateValidation(t *testing.T) { // intersection type access(all) var a: {TestInterface} access(all) var b: {TestInterface} - access(all) var c: AnyStruct{TestInterface} - access(all) var d: AnyStruct{TestInterface} + access(all) var c: {TestInterface} + access(all) var d: {TestInterface} init() { var count: Int = 567 @@ -1423,9 +1423,9 @@ func TestRuntimeContractUpdateValidation(t *testing.T) { const newCode = ` access(all) contract Test { access(all) var a: {TestInterface} - access(all) var b: AnyStruct{TestInterface} + access(all) var b: {TestInterface} access(all) var c: {TestInterface} - access(all) var d: AnyStruct{TestInterface} + access(all) var d: {TestInterface} init() { var count: Int = 567 @@ -1460,7 +1460,7 @@ func TestRuntimeContractUpdateValidation(t *testing.T) { access(all) contract Test { // intersection type - access(all) var a: TestStruct{TestInterface} + access(all) var a: TestStruct access(all) var b: {TestInterface} init() { @@ -1469,7 +1469,7 @@ func TestRuntimeContractUpdateValidation(t *testing.T) { self.b = TestStruct() } - access(all) struct TestStruct:TestInterface { + access(all) struct TestStruct: TestInterface { access(all) let a: Int init() { self.a = 123 @@ -1485,7 +1485,7 @@ func TestRuntimeContractUpdateValidation(t *testing.T) { const newCode = ` access(all) contract Test { access(all) var a: {TestInterface} - access(all) var b: TestStruct{TestInterface} + access(all) var b: TestStruct init() { var count: Int = 567 @@ -1493,7 +1493,7 @@ func TestRuntimeContractUpdateValidation(t *testing.T) { self.b = TestStruct() } - access(all) struct TestStruct:TestInterface { + access(all) struct TestStruct: TestInterface { access(all) let a: Int init() { self.a = 123 @@ -1511,11 +1511,11 @@ func TestRuntimeContractUpdateValidation(t *testing.T) { assert.Contains(t, err.Error(), "access(all) var a: {TestInterface}"+ "\n | ^^^^^^^^^^^^^^^ "+ - "incompatible type annotations. expected `TestStruct{TestInterface}`, found `{TestInterface}`") + "incompatible type annotations. expected `TestStruct`") - assert.Contains(t, err.Error(), "access(all) var b: TestStruct{TestInterface}"+ - "\n | ^^^^^^^^^^^^^^^^^^^^^^^^^ "+ - "incompatible type annotations. expected `{TestInterface}`, found `TestStruct{TestInterface}`") + assert.Contains(t, err.Error(), "access(all) var b: TestStruct"+ + "\n | ^^^^^^^^^^ "+ + "incompatible type annotations. expected `{TestInterface}`, found `TestStruct`") }) t.Run("enum valid", func(t *testing.T) { diff --git a/runtime/convertTypes.go b/runtime/convertTypes.go index 8db9386e14..4914fac5a9 100644 --- a/runtime/convertTypes.go +++ b/runtime/convertTypes.go @@ -517,8 +517,6 @@ func exportIntersectionType( results map[sema.TypeID]cadence.Type, ) *cadence.IntersectionType { - convertedType := ExportMeteredType(gauge, t.Type, results) - intersectionTypes := make([]cadence.Type, len(t.Types)) for i, typ := range t.Types { @@ -527,7 +525,6 @@ func exportIntersectionType( return cadence.NewMeteredIntersectionType( gauge, - convertedType, intersectionTypes, ) } @@ -699,7 +696,6 @@ func ImportType(memoryGauge common.MemoryGauge, t cadence.Type) interpreter.Stat } return interpreter.NewIntersectionStaticType( memoryGauge, - ImportType(memoryGauge, t.Type), types, ) case cadence.BlockType: diff --git a/runtime/convertValues_test.go b/runtime/convertValues_test.go index 73dd5a0aeb..4db6b7e620 100644 --- a/runtime/convertValues_test.go +++ b/runtime/convertValues_test.go @@ -1373,10 +1373,6 @@ func TestImportRuntimeType(t *testing.T) { { label: "IntersectionType", actual: &cadence.IntersectionType{ - Type: &cadence.StructType{ - Location: TestLocation, - QualifiedIdentifier: "S", - }, Types: []cadence.Type{ &cadence.StructInterfaceType{ Location: TestLocation, @@ -1384,10 +1380,6 @@ func TestImportRuntimeType(t *testing.T) { }}, }, expected: &interpreter.IntersectionStaticType{ - Type: interpreter.CompositeStaticType{ - Location: TestLocation, - QualifiedIdentifier: "S", - }, Types: []interpreter.InterfaceStaticType{ { Location: TestLocation, @@ -2127,7 +2119,6 @@ func TestExportTypeValue(t *testing.T) { ty := interpreter.TypeValue{ Type: &interpreter.IntersectionStaticType{ - Type: interpreter.NewCompositeStaticTypeComputeTypeID(inter, TestLocation, "S"), Types: []interpreter.InterfaceStaticType{ { Location: TestLocation, @@ -2143,11 +2134,6 @@ func TestExportTypeValue(t *testing.T) { assert.Equal(t, cadence.TypeValue{ StaticType: &cadence.IntersectionType{ - Type: &cadence.StructType{ - QualifiedIdentifier: "S", - Location: TestLocation, - Fields: []cadence.Field{}, - }, Types: []cadence.Type{ &cadence.StructInterfaceType{ QualifiedIdentifier: "SI", diff --git a/runtime/ft_test.go b/runtime/ft_test.go index 0118029de3..af7e375cab 100644 --- a/runtime/ft_test.go +++ b/runtime/ft_test.go @@ -371,7 +371,7 @@ access(all) contract FlowToken: FungibleToken { // Create a public capability to the stored Vault that only exposes // the 'deposit' method through the 'Receiver' interface // - adminAccount.link<&FlowToken.Vault{FungibleToken.Receiver}>( + adminAccount.link<&FlowToken.Vault>( /public/flowTokenReceiver, target: /storage/flowTokenVault ) @@ -379,7 +379,7 @@ access(all) contract FlowToken: FungibleToken { // Create a public capability to the stored Vault that only exposes // the 'balance' field through the 'Balance' interface // - adminAccount.link<&FlowToken.Vault{FungibleToken.Balance}>( + adminAccount.link<&FlowToken.Vault>( /public/flowTokenBalance, target: /storage/flowTokenVault ) @@ -407,14 +407,14 @@ transaction { // Create a public capability to the Vault that only exposes // the deposit function through the Receiver interface - signer.link<&FlowToken.Vault{FungibleToken.Receiver}>( + signer.link<&FlowToken.Vault>( /public/flowTokenReceiver, target: /storage/flowTokenVault ) // Create a public capability to the Vault that only exposes // the balance field through the Balance interface - signer.link<&FlowToken.Vault{FungibleToken.Balance}>( + signer.link<&FlowToken.Vault>( /public/flowTokenBalance, target: /storage/flowTokenVault ) @@ -494,7 +494,7 @@ access(all) fun main(account: Address): UFix64 { let vaultRef = getAccount(account) .getCapability(/public/flowTokenBalance) - .borrow<&FlowToken.Vault{FungibleToken.Balance}>() + .borrow<&FlowToken.Vault>() ?? panic("Could not borrow Balance reference to the Vault") return vaultRef.balance diff --git a/runtime/interpreter/decode.go b/runtime/interpreter/decode.go index 91f6d072e5..5c8647ec58 100644 --- a/runtime/interpreter/decode.go +++ b/runtime/interpreter/decode.go @@ -1856,13 +1856,27 @@ func (d TypeDecoder) decodeIntersectionStaticType() (StaticType, error) { ) } - // Decode intersection type at array index encodedIntersectionStaticTypeTypeFieldKey - intersectionType, err := d.DecodeStaticType() + var legacyRestrictedType StaticType + + t, err := d.decoder.NextType() if err != nil { - return nil, errors.NewUnexpectedError( - "invalid intersection static type key type encoding: %w", - err, - ) + return nil, err + } + + if t == cbor.NilType { + err = d.decoder.DecodeNil() + if err != nil { + return nil, err + } + } else { + // Decode intersection type at array index encodedIntersectionStaticTypeLegacyTypeFieldKey + legacyRestrictedType, err = d.DecodeStaticType() + if err != nil { + return nil, errors.NewUnexpectedError( + "invalid intersection static type key type encoding: %w", + err, + ) + } } // Decode intersected types at array index encodedIntersectionStaticTypeTypesFieldKey @@ -1916,11 +1930,13 @@ func (d TypeDecoder) decodeIntersectionStaticType() (StaticType, error) { } } - return NewIntersectionStaticType( + staticType := NewIntersectionStaticType( d.memoryGauge, - intersectionType, intersections, - ), nil + ) + staticType.LegacyType = legacyRestrictedType + + return staticType, nil } func (d TypeDecoder) decodeCapabilityStaticType() (StaticType, error) { diff --git a/runtime/interpreter/encode.go b/runtime/interpreter/encode.go index e068b62cc9..7c2ce5d8aa 100644 --- a/runtime/interpreter/encode.go +++ b/runtime/interpreter/encode.go @@ -1561,8 +1561,8 @@ func (t DictionaryStaticType) Encode(e *cbor.StreamEncoder) error { // NOTE: NEVER change, only add/increment; ensure uint64 const ( - // encodedIntersectionStaticTypeTypeFieldKey uint64 = 0 - // encodedIntersectionStaticTypeTypesFieldKey uint64 = 1 + // encodedIntersectionStaticTypeLegacyTypeFieldKey uint64 = 0 + // encodedIntersectionStaticTypeTypesFieldKey uint64 = 1 // !!! *WARNING* !!! // @@ -1576,8 +1576,8 @@ const ( // cbor.Tag{ // Number: CBORTagIntersectionStaticType, // Content: cborArray{ -// encodedIntersectionStaticTypeTypeFieldKey: StaticType(v.Type), -// encodedIntersectionStaticTypeTypesFieldKey: []any(v.Types), +// encodedIntersectionStaticTypeLegacyTypeFieldKey: StaticType(v.LegacyRestrictedType), +// encodedIntersectionStaticTypeTypesFieldKey: []any(v.Types), // }, // } func (t *IntersectionStaticType) Encode(e *cbor.StreamEncoder) error { @@ -1591,16 +1591,26 @@ func (t *IntersectionStaticType) Encode(e *cbor.StreamEncoder) error { if err != nil { return err } - // Encode type at array index encodedIntersectionStaticTypeTypeFieldKey - err = t.Type.Encode(e) - if err != nil { - return err + + if t.LegacyType != nil { + // Encode type at array index encodedIntersectionStaticTypeTypeFieldKey + err = t.LegacyType.Encode(e) + if err != nil { + return err + } + } else { + err = e.EncodeNil() + if err != nil { + return err + } } + // Encode types (as array) at array index encodedIntersectionStaticTypeTypesFieldKey err = e.EncodeArrayHead(uint64(len(t.Types))) if err != nil { return err } + for _, typ := range t.Types { // Encode typ as array types element err = typ.Encode(e) diff --git a/runtime/interpreter/encoding_test.go b/runtime/interpreter/encoding_test.go index f42f18221c..3d57ba229e 100644 --- a/runtime/interpreter/encoding_test.go +++ b/runtime/interpreter/encoding_test.go @@ -4146,11 +4146,6 @@ func TestEncodeDecodePathLinkValue(t *testing.T) { value := PathLinkValue{ TargetPath: publicPathValue, Type: &IntersectionStaticType{ - Type: NewCompositeStaticTypeComputeTypeID( - nil, - utils.TestLocation, - "S", - ), Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -4167,10 +4162,28 @@ func TestEncodeDecodePathLinkValue(t *testing.T) { encoded := assemble( // tag 0xd8, CBORTagIntersectionStaticType, + // array, length 2 + 0x82, + // nil + 0xf6, + // array, length 2 + 0x82, + // tag + 0xd8, CBORTagInterfaceStaticType, // array, 2 items follow 0x82, // tag - 0xd8, CBORTagCompositeStaticType, + 0xd8, CBORTagStringLocation, + // UTF-8 string, length 4 + 0x64, + // t, e, s, t + 0x74, 0x65, 0x73, 0x74, + // UTF-8 string, length 2 + 0x62, + // I1 + 0x49, 0x31, + // tag + 0xd8, CBORTagInterfaceStaticType, // array, 2 items follow 0x82, // tag @@ -4179,10 +4192,48 @@ func TestEncodeDecodePathLinkValue(t *testing.T) { 0x64, // t, e, s, t 0x74, 0x65, 0x73, 0x74, - // UTF-8 string, length 1 - 0x61, - // S - 0x53, + // UTF-8 string, length 2 + 0x62, + // I2 + 0x49, 0x32, + ) + + testEncodeDecode(t, + encodeDecodeTest{ + value: value, + encoded: encoded, + }, + ) + }) + + t.Run("legacy intersection", func(t *testing.T) { + + t.Parallel() + + value := PathLinkValue{ + TargetPath: publicPathValue, + Type: &IntersectionStaticType{ + LegacyType: interpreter.PrimitiveStaticTypeInt, + Types: []InterfaceStaticType{ + { + Location: utils.TestLocation, + QualifiedIdentifier: "I1", + }, + { + Location: utils.TestLocation, + QualifiedIdentifier: "I2", + }, + }, + }, + } + + encoded := assemble( + // tag + 0xd8, CBORTagIntersectionStaticType, + // array, length 2 + 0x82, + // int type + 0xd8, 0xd4, 0x18, 0x24, // array, length 2 0x82, // tag @@ -4854,11 +4905,6 @@ func TestEncodeDecodeStorageCapabilityControllerValue(t *testing.T) { TargetPath: publicPathValue, BorrowType: ReferenceStaticType{ ReferencedType: &IntersectionStaticType{ - Type: NewCompositeStaticTypeComputeTypeID( - nil, - utils.TestLocation, - "S", - ), Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -4887,22 +4933,10 @@ func TestEncodeDecodeStorageCapabilityControllerValue(t *testing.T) { 0xf6, // tag 0xd8, CBORTagIntersectionStaticType, - // array, 2 items follow - 0x82, - // tag - 0xd8, CBORTagCompositeStaticType, - // array, 2 items follow + // array, length 2 0x82, - // tag - 0xd8, CBORTagStringLocation, - // UTF-8 string, length 4 - 0x64, - // t, e, s, t - 0x74, 0x65, 0x73, 0x74, - // UTF-8 string, length 1 - 0x61, - // S - 0x53, + // nil + 0xf6, // array, length 2 0x82, // tag @@ -5055,14 +5089,19 @@ func TestEncodeDecodeAccountCapabilityControllerValue(t *testing.T) { ) }) - t.Run("unauthorized reference, intersection AuthAccount", func(t *testing.T) { + t.Run("unauthorized reference, intersection I1", func(t *testing.T) { t.Parallel() value := &AccountCapabilityControllerValue{ BorrowType: ReferenceStaticType{ ReferencedType: &IntersectionStaticType{ - Type: PrimitiveStaticTypeAuthAccount, + Types: []interpreter.InterfaceStaticType{ + { + Location: utils.TestLocation, + QualifiedIdentifier: "SimpleInterface", + }, + }, }, Authorization: UnauthorizedAccess, }, @@ -5081,14 +5120,26 @@ func TestEncodeDecodeAccountCapabilityControllerValue(t *testing.T) { 0xf6, // tag 0xd8, CBORTagIntersectionStaticType, + // array, length 2 + 0x82, + // nil + 0xf6, + // array, 1 item follows + 0x81, + // tag + 0xd8, CBORTagInterfaceStaticType, // array, 2 items follow 0x82, // tag - 0xd8, CBORTagPrimitiveStaticType, - // unsigned 90 - 0x18, 0x5a, - // array, length 0 - 0x80, + 0xd8, CBORTagStringLocation, + // UTF-8 string, length 4 + 0x64, + // t, e, s, t + 0x74, 0x65, 0x73, 0x74, + // UTF-8 string, length 22 + 0x6F, + // SimpleInterface + 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, ) testEncodeDecode(t, diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index ae393e3c18..d4ad8733d0 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -3609,7 +3609,7 @@ func functionTypeFunction(invocation Invocation) Value { } func intersectionTypeFunction(invocation Invocation) Value { - intersectionIDs, ok := invocation.Arguments[1].(*ArrayValue) + intersectionIDs, ok := invocation.Arguments[0].(*ArrayValue) if !ok { panic(errors.NewUnreachableError()) } @@ -3652,26 +3652,9 @@ func intersectionTypeFunction(invocation Invocation) Value { } } - var semaType sema.Type - var err error - - switch typeID := invocation.Arguments[0].(type) { - case NilValue: - semaType = nil - case *SomeValue: - innerValue := typeID.InnerValue(invocation.Interpreter, invocation.LocationRange) - semaType, err = lookupComposite(invocation.Interpreter, innerValue.(*StringValue).Str) - if err != nil { - return Nil - } - default: - panic(errors.NewUnreachableError()) - } - var invalidIntersectionType bool - ty := sema.CheckIntersectionType( + sema.CheckIntersectionType( invocation.Interpreter, - semaType, semaIntersections, func(_ func(*ast.IntersectionType) error) { invalidIntersectionType = true @@ -3690,7 +3673,6 @@ func intersectionTypeFunction(invocation Invocation) Value { invocation.Interpreter, NewIntersectionStaticType( invocation.Interpreter, - ConvertSemaToStaticType(invocation.Interpreter, ty), staticIntersections, ), ), diff --git a/runtime/interpreter/statictype.go b/runtime/interpreter/statictype.go index 729a9127df..f133f156ac 100644 --- a/runtime/interpreter/statictype.go +++ b/runtime/interpreter/statictype.go @@ -395,21 +395,19 @@ var NilStaticType = OptionalStaticType{ // IntersectionStaticType type IntersectionStaticType struct { - Type StaticType - Types []InterfaceStaticType + Types []InterfaceStaticType + LegacyType StaticType } var _ StaticType = &IntersectionStaticType{} func NewIntersectionStaticType( memoryGauge common.MemoryGauge, - staticType StaticType, types []InterfaceStaticType, ) *IntersectionStaticType { common.UseMemory(memoryGauge, common.IntersectionStaticTypeMemoryUsage) return &IntersectionStaticType{ - Type: staticType, Types: types, } } @@ -436,7 +434,7 @@ func (t *IntersectionStaticType) String() string { } } - return fmt.Sprintf("%s{%s}", t.Type, strings.Join(types, ", ")) + return fmt.Sprintf("{%s}", strings.Join(types, ", ")) } func (t *IntersectionStaticType) MeteredString(memoryGauge common.MemoryGauge) string { @@ -453,9 +451,7 @@ func (t *IntersectionStaticType) MeteredString(memoryGauge common.MemoryGauge) s l := len(types)*2 + 2 common.UseMemory(memoryGauge, common.NewRawStringMemoryUsage(l)) - typeStr := t.Type.MeteredString(memoryGauge) - - return fmt.Sprintf("%s{%s}", typeStr, strings.Join(types, ", ")) + return fmt.Sprintf("{%s}", strings.Join(types, ", ")) } func (t *IntersectionStaticType) Equal(other StaticType) bool { @@ -475,7 +471,7 @@ outer: return false } - return t.Type.Equal(otherIntersectionType.Type) + return true } // Authorization @@ -765,7 +761,6 @@ func ConvertSemaToStaticType(memoryGauge common.MemoryGauge, t sema.Type) Static return NewIntersectionStaticType( memoryGauge, - ConvertSemaToStaticType(memoryGauge, t.Type), intersectedTypess, ) @@ -1004,21 +999,8 @@ func ConvertStaticToSemaType( } } - ty, err := ConvertStaticToSemaType( - memoryGauge, - t.Type, - getInterface, - getComposite, - getEntitlement, - getEntitlementMapType, - ) - if err != nil { - return nil, err - } - return sema.NewIntersectionType( memoryGauge, - ty, intersectedTypes, ), nil diff --git a/runtime/interpreter/statictype_test.go b/runtime/interpreter/statictype_test.go index 50052eccd1..ac534d747f 100644 --- a/runtime/interpreter/statictype_test.go +++ b/runtime/interpreter/statictype_test.go @@ -757,7 +757,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.True(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -770,7 +769,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { }, }).Equal( &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -792,59 +790,21 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.True(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{}, }).Equal( &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{}, }, ), ) }) - t.Run("different intersection type", func(t *testing.T) { - - t.Parallel() - - require.False(t, - (&IntersectionStaticType{ - Type: PrimitiveStaticTypeString, - Types: []InterfaceStaticType{ - { - Location: utils.TestLocation, - QualifiedIdentifier: "X", - }, - { - Location: utils.TestLocation, - QualifiedIdentifier: "Y", - }, - }, - }).Equal( - &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, - Types: []InterfaceStaticType{ - { - Location: utils.TestLocation, - QualifiedIdentifier: "Y", - }, - { - Location: utils.TestLocation, - QualifiedIdentifier: "X", - }, - }, - }, - ), - ) - }) - t.Run("fewer intersections", func(t *testing.T) { t.Parallel() require.False(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -857,7 +817,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { }, }).Equal( &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -875,7 +834,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.False(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -884,7 +842,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { }, }).Equal( &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -906,7 +863,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.False(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -919,7 +875,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { }, }).Equal( &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -941,7 +896,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.False(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -1378,13 +1332,11 @@ func TestStaticTypeConversion(t *testing.T) { { name: "Intersection", semaType: &sema.IntersectionType{ - Type: sema.IntType, Types: []*sema.InterfaceType{ testInterfaceSemaType, }, }, staticType: &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ testInterfaceStaticType, }, diff --git a/runtime/missingmember_test.go b/runtime/missingmember_test.go index a1b0882ce9..b6dc90b730 100644 --- a/runtime/missingmember_test.go +++ b/runtime/missingmember_test.go @@ -232,7 +232,7 @@ access(all) contract FlowToken: FungibleToken { // Create a public capability to the stored Vault that only exposes // the deposit method through the Receiver interface // - adminAccount.link<&FlowToken.Vault{FungibleToken.Receiver}>( + adminAccount.link<&FlowToken.Vault>( /public/flowTokenReceiver, target: /storage/flowTokenVault ) @@ -240,7 +240,7 @@ access(all) contract FlowToken: FungibleToken { // Create a public capability to the stored Vault that only exposes // the balance field through the Balance interface // - adminAccount.link<&FlowToken.Vault{FungibleToken.Balance}>( + adminAccount.link<&FlowToken.Vault>( /public/flowTokenBalance, target: /storage/flowTokenVault ) @@ -447,7 +447,7 @@ access(all) contract FBRC: FungibleToken { // Create a public capability to the stored Vault that only exposes // the deposit method through the Receiver interface // - self.account.link<&FBRC.Vault{FungibleToken.Receiver}>( + self.account.link<&FBRC.Vault>( self.CollectionReceiverPath, target: self.CollectionStoragePath ) @@ -455,7 +455,7 @@ access(all) contract FBRC: FungibleToken { // Create a public capability to the stored Vault that only exposes // the balance field through the Balance interface // - self.account.link<&FBRC.Vault{FungibleToken.Balance}>( + self.account.link<&FBRC.Vault>( self.CollectionBalancePath, target: self.CollectionStoragePath ) @@ -599,9 +599,9 @@ access(all) contract GarmentNFT: NonFungibleToken { access(all) let garment: Garment // Royalty capability which NFT will use - access(all) let royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}> + access(all) let royaltyVault: Capability<&FBRC.Vault> - init(serialNumber: UInt32, garmentDataID: UInt32, royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}>) { + init(serialNumber: UInt32, garmentDataID: UInt32, royaltyVault: Capability<&FBRC.Vault>) { GarmentNFT.totalSupply = GarmentNFT.totalSupply + 1 as UInt64 self.id = GarmentNFT.totalSupply @@ -659,7 +659,7 @@ access(all) contract GarmentNFT: NonFungibleToken { } // Mint the new Garment - access(all) fun mintNFT(garmentDataID: UInt32, royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}>): @NFT { + access(all) fun mintNFT(garmentDataID: UInt32, royaltyVault: Capability<&FBRC.Vault>): @NFT { pre { royaltyVault.check(): "Royalty capability is invalid!" @@ -681,7 +681,7 @@ access(all) contract GarmentNFT: NonFungibleToken { return <-newGarment } - access(all) fun batchMintNFT(garmentDataID: UInt32, royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}>, quantity: UInt64): @Collection { + access(all) fun batchMintNFT(garmentDataID: UInt32, royaltyVault: Capability<&FBRC.Vault>, quantity: UInt64): @Collection { let newCollection <- create Collection() var i: UInt64 = 0 @@ -1063,9 +1063,9 @@ access(all) contract MaterialNFT: NonFungibleToken { access(all) let material: Material // Royalty capability which NFT will use - access(all) let royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}> + access(all) let royaltyVault: Capability<&FBRC.Vault> - init(serialNumber: UInt32, materialDataID: UInt32, royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}>) { + init(serialNumber: UInt32, materialDataID: UInt32, royaltyVault: Capability<&FBRC.Vault>) { MaterialNFT.totalSupply = MaterialNFT.totalSupply + 1 as UInt64 self.id = MaterialNFT.totalSupply @@ -1121,7 +1121,7 @@ access(all) contract MaterialNFT: NonFungibleToken { } // Mint the new Material - access(all) fun mintNFT(materialDataID: UInt32, royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}>): @NFT { + access(all) fun mintNFT(materialDataID: UInt32, royaltyVault: Capability<&FBRC.Vault>): @NFT { pre { royaltyVault.check(): "Royalty capability is invalid!" @@ -1143,7 +1143,7 @@ access(all) contract MaterialNFT: NonFungibleToken { return <-newMaterial } - access(all) fun batchMintNFT(materialDataID: UInt32, royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}>, quantity: UInt64): @Collection { + access(all) fun batchMintNFT(materialDataID: UInt32, royaltyVault: Capability<&FBRC.Vault>, quantity: UInt64): @Collection { let newCollection <- create Collection() var i: UInt64 = 0 @@ -1550,7 +1550,7 @@ access(all) contract ItemNFT: NonFungibleToken { access(all) var name: String // Royalty capability which NFT will use - access(all) let royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}> + access(all) let royaltyVault: Capability<&FBRC.Vault> // after you remove the garment and material from the item, the ItemNFT will be considered "dead". // accounts will be unable to deposit, withdraw or call functions of the nft. @@ -1563,7 +1563,7 @@ access(all) contract ItemNFT: NonFungibleToken { access(self) var material: @MaterialNFT.NFT? - init(serialNumber: UInt32, name: String, itemDataID: UInt32, royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}>, garment: @GarmentNFT.NFT, material: @MaterialNFT.NFT) { + init(serialNumber: UInt32, name: String, itemDataID: UInt32, royaltyVault: Capability<&FBRC.Vault>, garment: @GarmentNFT.NFT, material: @MaterialNFT.NFT) { ItemNFT.totalSupply = ItemNFT.totalSupply + 1 as UInt64 @@ -1652,7 +1652,7 @@ access(all) contract ItemNFT: NonFungibleToken { // mint the NFT, combining a garment and boot. // The itemData that is used to mint the Item is based on the garment and material' garmentDataID and materialDataID - access(all) fun mintNFT(name: String, royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}>, garment: @GarmentNFT.NFT, material: @MaterialNFT.NFT): @NFT { + access(all) fun mintNFT(name: String, royaltyVault: Capability<&FBRC.Vault>, garment: @GarmentNFT.NFT, material: @MaterialNFT.NFT): @NFT { pre { royaltyVault.check(): "Royalty capability is invalid!" @@ -2127,20 +2127,20 @@ import FungibleToken from 0x9a0766d93b6608b7 access(all) fun hasFBRC(_ address: Address): Bool { let receiver = getAccount(address) - .getCapability<&FBRC.Vault{FungibleToken.Receiver}>(FBRC.CollectionReceiverPath) + .getCapability<&FBRC.Vault>(FBRC.CollectionReceiverPath) .check() let balance = getAccount(address) - .getCapability<&FBRC.Vault{FungibleToken.Balance}>(FBRC.CollectionBalancePath) + .getCapability<&FBRC.Vault>(FBRC.CollectionBalancePath) .check() return receiver && balance } access(all) fun hasFlowToken(_ address: Address): Bool { let receiver = getAccount(address) - .getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + .getCapability<&FlowToken.Vault>(/public/flowTokenReceiver) .check() let balance = getAccount(address) - .getCapability<&FlowToken.Vault{FungibleToken.Balance}>(/public/flowTokenBalance) + .getCapability<&FlowToken.Vault>(/public/flowTokenBalance) .check() return receiver && balance } @@ -2172,8 +2172,8 @@ transaction { } acct.unlink(FBRC.CollectionReceiverPath) acct.unlink(FBRC.CollectionBalancePath) - acct.link<&FBRC.Vault{FungibleToken.Receiver}>(FBRC.CollectionReceiverPath, target: FBRC.CollectionStoragePath) - acct.link<&FBRC.Vault{FungibleToken.Balance}>(FBRC.CollectionBalancePath, target: FBRC.CollectionStoragePath) + acct.link<&FBRC.Vault>(FBRC.CollectionReceiverPath, target: FBRC.CollectionStoragePath) + acct.link<&FBRC.Vault>(FBRC.CollectionBalancePath, target: FBRC.CollectionStoragePath) } if !hasFlowToken(acct.address) { @@ -2182,8 +2182,8 @@ transaction { } acct.unlink(/public/flowTokenReceiver) acct.unlink(/public/flowTokenBalance) - acct.link<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver, target: /storage/flowTokenVault) - acct.link<&FlowToken.Vault{FungibleToken.Balance}>(/public/flowTokenBalance, target: /storage/flowTokenVault) + acct.link<&FlowToken.Vault>(/public/flowTokenReceiver, target: /storage/flowTokenVault) + acct.link<&FlowToken.Vault>(/public/flowTokenBalance, target: /storage/flowTokenVault) } if !hasGarmentNFT(acct.address) { @@ -2405,14 +2405,14 @@ transaction(recipientAddr: Address, garmentDataID: UInt32, royaltyVaultAddr: Add let adminRef: &GarmentNFT.Admin - let royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}> + let royaltyVault: Capability<&FBRC.Vault> prepare(acct: AuthAccount) { self.adminRef = acct.borrow<&GarmentNFT.Admin>(from: GarmentNFT.AdminStoragePath) ?? panic("No admin resource in storage") - self.royaltyVault = getAccount(royaltyVaultAddr).getCapability<&FBRC.Vault{FungibleToken.Receiver}>(FBRC.CollectionReceiverPath) + self.royaltyVault = getAccount(royaltyVaultAddr).getCapability<&FBRC.Vault>(FBRC.CollectionReceiverPath) } execute { @@ -2463,14 +2463,14 @@ transaction(recipientAddr: Address, materialDataID: UInt32, royaltyVaultAddr: Ad let adminRef: &MaterialNFT.Admin - let royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}> + let royaltyVault: Capability<&FBRC.Vault> prepare(acct: AuthAccount) { self.adminRef = acct.borrow<&MaterialNFT.Admin>(from: MaterialNFT.AdminStoragePath) ?? panic("No admin resource in storage") - self.royaltyVault = getAccount(royaltyVaultAddr).getCapability<&FBRC.Vault{FungibleToken.Receiver}>(FBRC.CollectionReceiverPath) + self.royaltyVault = getAccount(royaltyVaultAddr).getCapability<&FBRC.Vault>(FBRC.CollectionReceiverPath) } execute { @@ -2524,7 +2524,7 @@ transaction(recipientAddr: Address, name: String, garmentWithdrawID: UInt64, mat let garment: @NonFungibleToken.NFT let material: @NonFungibleToken.NFT - let royaltyVault: Capability<&FBRC.Vault{FungibleToken.Receiver}> + let royaltyVault: Capability<&FBRC.Vault> prepare(garmentAndMaterialAcct: AuthAccount) { @@ -2540,7 +2540,7 @@ transaction(recipientAddr: Address, name: String, garmentWithdrawID: UInt64, mat self.material <- materialCollectionRef.withdraw(withdrawID: materialWithdrawID) - self.royaltyVault = getAccount(royaltyVaultAddr).getCapability<&FBRC.Vault{FungibleToken.Receiver}>(FBRC.CollectionReceiverPath) + self.royaltyVault = getAccount(royaltyVaultAddr).getCapability<&FBRC.Vault>(FBRC.CollectionReceiverPath) } @@ -2969,7 +2969,7 @@ access(all) contract FlowToken: FungibleToken { // Create a public capability to the stored Vault that only exposes // the deposit method through the Receiver interface // - adminAccount.link<&FlowToken.Vault{FungibleToken.Receiver}>( + adminAccount.link<&FlowToken.Vault>( /public/flowTokenReceiver, target: /storage/flowTokenVault ) @@ -2977,7 +2977,7 @@ access(all) contract FlowToken: FungibleToken { // Create a public capability to the stored Vault that only exposes // the balance field through the Balance interface // - adminAccount.link<&FlowToken.Vault{FungibleToken.Balance}>( + adminAccount.link<&FlowToken.Vault>( /public/flowTokenBalance, target: /storage/flowTokenVault ) @@ -3623,7 +3623,7 @@ access(all) contract AuctionDutch { //the currentPrice is still higher then your bid, this is find we just add your bid to the correct tick bucket if price > vault.balance { let bidId =auction.addBid(vault: <- vault, nftCap:nftCap, vaultCap: vaultCap, time: time) - return <- create Bid(capability: AuctionDutch.account.getCapability<&Collection{Public}>(AuctionDutch.CollectionPublicPath), auctionId: id, bidId: bidId) + return <- create Bid(capability: AuctionDutch.account.getCapability<&Collection>(AuctionDutch.CollectionPublicPath), auctionId: id, bidId: bidId) } let tooMuchCash=vault.balance - price @@ -3633,7 +3633,7 @@ access(all) contract AuctionDutch { } let bidId=auction.addBid(vault: <- vault, nftCap:nftCap, vaultCap: vaultCap, time: time) - return <- create Bid(capability: AuctionDutch.account.getCapability<&Collection{Public}>(AuctionDutch.CollectionPublicPath), auctionId: id, bidId: bidId) + return <- create Bid(capability: AuctionDutch.account.getCapability<&Collection>(AuctionDutch.CollectionPublicPath), auctionId: id, bidId: bidId) } access(all) fun tickOrFulfill(_ id:UInt64) { @@ -3683,7 +3683,7 @@ access(all) contract AuctionDutch { access(all) fun getBids(_ id: UInt64) : Bids { let account = AuctionDutch.account - let cap=account.getCapability<&Collection{Public}>(self.CollectionPublicPath) + let cap=account.getCapability<&Collection>(self.CollectionPublicPath) if let collection = cap.borrow() { return collection.getBids(id) } @@ -3692,7 +3692,7 @@ access(all) contract AuctionDutch { access(all) fun getAuctionDutch(_ id: UInt64) : AuctionDutchStatus? { let account = AuctionDutch.account - let cap=account.getCapability<&Collection{Public}>(self.CollectionPublicPath) + let cap=account.getCapability<&Collection>(self.CollectionPublicPath) if let collection = cap.borrow() { return collection.getStatus(id) } @@ -3701,11 +3701,11 @@ access(all) contract AuctionDutch { access(all) resource Bid { - access(all) let capability:Capability<&Collection{Public}> + access(all) let capability:Capability<&Collection> access(all) let auctionId: UInt64 access(all) let bidId: UInt64 - init(capability:Capability<&Collection{Public}>, auctionId: UInt64, bidId:UInt64) { + init(capability:Capability<&Collection>, auctionId: UInt64, bidId:UInt64) { self.capability=capability self.auctionId=auctionId self.bidId=bidId @@ -3770,7 +3770,7 @@ access(all) contract AuctionDutch { access(all) fun bid(marketplace: Address, id: UInt64, vault: @FungibleToken.Vault, vaultCap: Capability<&{FungibleToken.Receiver}>, nftCap: Capability<&{NonFungibleToken.Receiver}>) { - let dutchAuctionCap=getAccount(marketplace).getCapability<&AuctionDutch.Collection{AuctionDutch.Public}>(AuctionDutch.CollectionPublicPath) + let dutchAuctionCap=getAccount(marketplace).getCapability<&AuctionDutch.Collection>(AuctionDutch.CollectionPublicPath) let bid <- dutchAuctionCap.borrow()!.bid(id: id, vault: <- vault, vaultCap: vaultCap, nftCap: nftCap) self.bids[bid.uuid] <-! bid } @@ -3821,7 +3821,7 @@ access(all) contract AuctionDutch { let account=self.account let collection <- create Collection() account.save(<-collection, to: AuctionDutch.CollectionStoragePath) - account.link<&Collection{Public}>(AuctionDutch.CollectionPublicPath, target: AuctionDutch.CollectionStoragePath) + account.link<&Collection>(AuctionDutch.CollectionPublicPath, target: AuctionDutch.CollectionStoragePath) } } @@ -3943,14 +3943,14 @@ transaction { // Create a public capability to the Vault that only exposes // the deposit function through the Receiver interface - signer.link<&FlowToken.Vault{FungibleToken.Receiver}>( + signer.link<&FlowToken.Vault>( /public/flowTokenReceiver, target: /storage/flowTokenVault ) // Create a public capability to the Vault that only exposes // the balance field through the Balance interface - signer.link<&FlowToken.Vault{FungibleToken.Balance}>( + signer.link<&FlowToken.Vault>( /public/flowTokenBalance, target: /storage/flowTokenVault ) @@ -4096,7 +4096,7 @@ transaction(recipient: Address, amount: UFix64) { let nftCap = signer.getCapability<&{NonFungibleToken.Receiver}>(/public/doesNotExist) let bid <- getAccount(0x99ca04281098b33d) - .getCapability<&AuctionDutch.Collection{AuctionDutch.Public}>(AuctionDutch.CollectionPublicPath) + .getCapability<&AuctionDutch.Collection>(AuctionDutch.CollectionPublicPath) .borrow()! .bid( id: 0, @@ -4314,7 +4314,7 @@ access(all) contract ExampleToken { // Function that mints new tokens and deposits into an account's vault // using their Receiver reference. - access(all) fun mintTokens(amount: UFix64, recipient: Capability<&AnyResource{Receiver}>) { + access(all) fun mintTokens(amount: UFix64, recipient: Capability<&{Receiver}>) { let recipientRef = recipient.borrow() ?? panic("Could not borrow a receiver reference to the vault") @@ -4536,7 +4536,7 @@ access(all) contract ExampleMarketplace { // that only exposes the methods that are supposed to be public // access(all) resource interface SalePublic { - access(all) fun purchase(tokenID: UInt64, recipient: Capability<&AnyResource{ExampleNFT.NFTReceiver}>, buyTokens: @ExampleToken.Vault) + access(all) fun purchase(tokenID: UInt64, recipient: Capability<&{ExampleNFT.NFTReceiver}>, buyTokens: @ExampleToken.Vault) access(all) fun idPrice(tokenID: UInt64): UFix64? access(all) fun getIDs(): [UInt64] } @@ -4557,10 +4557,10 @@ access(all) contract ExampleMarketplace { // The fungible token vault of the owner of this sale. // When someone buys a token, this resource can deposit // tokens into their account. - access(account) let ownerVault: Capability<&AnyResource{ExampleToken.Receiver}> + access(account) let ownerVault: Capability<&{ExampleToken.Receiver}> init (ownerCollection: Capability<&ExampleNFT.Collection>, - ownerVault: Capability<&AnyResource{ExampleToken.Receiver}>) { + ownerVault: Capability<&{ExampleToken.Receiver}>) { pre { // Check that the owner's collection capability is correct @@ -4605,7 +4605,7 @@ access(all) contract ExampleMarketplace { } // purchase lets a user send tokens to purchase an NFT that is for sale - access(all) fun purchase(tokenID: UInt64, recipient: Capability<&AnyResource{ExampleNFT.NFTReceiver}>, buyTokens: @ExampleToken.Vault) { + access(all) fun purchase(tokenID: UInt64, recipient: Capability<&{ExampleNFT.NFTReceiver}>, buyTokens: @ExampleToken.Vault) { pre { self.prices[tokenID] != nil: "No token matching this ID for sale!" @@ -4653,7 +4653,7 @@ access(all) contract ExampleMarketplace { // createCollection returns a new collection resource to the caller access(all) fun createSaleCollection(ownerCollection: Capability<&ExampleNFT.Collection>, - ownerVault: Capability<&AnyResource{ExampleToken.Receiver}>): @SaleCollection { + ownerVault: Capability<&{ExampleToken.Receiver}>): @SaleCollection { return <- create SaleCollection(ownerCollection: ownerCollection, ownerVault: ownerVault) } } @@ -4740,7 +4740,7 @@ import ExampleNFT from 0x02 transaction { prepare(acct: AuthAccount) { // Create a public Receiver capability to the Vault - acct.link<&ExampleToken.Vault{ExampleToken.Receiver, ExampleToken.Balance}> + acct.link<&ExampleToken.Vault> (/public/CadenceFungibleTokenTutorialReceiver, target: /storage/CadenceFungibleTokenTutorialVault) log("Created Vault references") @@ -4778,7 +4778,7 @@ transaction { acct.save<@ExampleToken.Vault>(<-vaultA, to: /storage/CadenceFungibleTokenTutorialVault) // Create a public Receiver capability to the Vault - let ReceiverRef = acct.link<&ExampleToken.Vault{ExampleToken.Receiver, ExampleToken.Balance}>(/public/CadenceFungibleTokenTutorialReceiver, target: /storage/CadenceFungibleTokenTutorialVault) + let ReceiverRef = acct.link<&ExampleToken.Vault>(/public/CadenceFungibleTokenTutorialReceiver, target: /storage/CadenceFungibleTokenTutorialVault) log("Created a Vault and published a reference") @@ -4815,8 +4815,8 @@ import ExampleNFT from 0x02 transaction { // Public Vault Receiver References for both accounts - let acct1Capability: Capability<&AnyResource{ExampleToken.Receiver}> - let acct2Capability: Capability<&AnyResource{ExampleToken.Receiver}> + let acct1Capability: Capability<&{ExampleToken.Receiver}> + let acct2Capability: Capability<&{ExampleToken.Receiver}> // Private minter references for this account to mint tokens let minterRef: &ExampleToken.VaultMinter @@ -4826,9 +4826,9 @@ transaction { let account2 = getAccount(0x02) // Retrieve public Vault Receiver references for both accounts - self.acct1Capability = acct.getCapability<&AnyResource{ExampleToken.Receiver}>(/public/CadenceFungibleTokenTutorialReceiver) + self.acct1Capability = acct.getCapability<&{ExampleToken.Receiver}>(/public/CadenceFungibleTokenTutorialReceiver) - self.acct2Capability = account2.getCapability<&AnyResource{ExampleToken.Receiver}>(/public/CadenceFungibleTokenTutorialReceiver) + self.acct2Capability = account2.getCapability<&{ExampleToken.Receiver}>(/public/CadenceFungibleTokenTutorialReceiver) // Get the stored Minter reference for account 0x01 self.minterRef = acct.borrow<&ExampleToken.VaultMinter>(from: /storage/CadenceFungibleTokenTutorialMinter) @@ -4877,7 +4877,7 @@ transaction { acct.save(<-sale, to: /storage/NFTSale) // Create a public capability to the sale so that others can call its methods - acct.link<&ExampleMarketplace.SaleCollection{ExampleMarketplace.SalePublic}>(/public/NFTSale, target: /storage/NFTSale) + acct.link<&ExampleMarketplace.SaleCollection>(/public/NFTSale, target: /storage/NFTSale) log("Sale Created for account 1. Selling NFT 1 for 10 tokens") } @@ -4898,7 +4898,7 @@ transaction { // Capability to the buyer's NFT collection where they // will store the bought NFT - let collectionCapability: Capability<&AnyResource{ExampleNFT.NFTReceiver}> + let collectionCapability: Capability<&{ExampleNFT.NFTReceiver}> // Vault that will hold the tokens that will be used to // but the NFT @@ -4907,7 +4907,7 @@ transaction { prepare(acct: AuthAccount) { // get the references to the buyer's fungible token Vault and NFT Collection Receiver - self.collectionCapability = acct.getCapability<&AnyResource{ExampleNFT.NFTReceiver}>(ExampleNFT.CollectionPublicPath) + self.collectionCapability = acct.getCapability<&{ExampleNFT.NFTReceiver}>(ExampleNFT.CollectionPublicPath) let vaultRef = acct.borrow<&ExampleToken.Vault>(from: /storage/CadenceFungibleTokenTutorialVault) ?? panic("Could not borrow owner's vault reference") @@ -4922,7 +4922,7 @@ transaction { // get the reference to the seller's sale let saleRef = seller.getCapability(/public/NFTSale) - .borrow<&AnyResource{ExampleMarketplace.SalePublic}>() + .borrow<&{ExampleMarketplace.SalePublic}>() ?? panic("Could not borrow seller's sale reference") // purchase the NFT the the seller is selling, giving them the capability diff --git a/runtime/parser/parser_test.go b/runtime/parser/parser_test.go index 7e0799e3e1..61dac6589b 100644 --- a/runtime/parser/parser_test.go +++ b/runtime/parser/parser_test.go @@ -559,10 +559,10 @@ func TestParseBuffering(t *testing.T) { let S = 1 if false { let Type_X_Y__qp_identifier = - Type().identifier; // parses fine + Type<{Y}>().identifier; // parses fine return f(a:S().identifier) // should also parse fine + return f(a:S().identifier) // should also parse fine } }` diff --git a/runtime/parser/type.go b/runtime/parser/type.go index 1ae6511345..67b3fb2dff 100644 --- a/runtime/parser/type.go +++ b/runtime/parser/type.go @@ -80,17 +80,6 @@ func setTypeLeftDenotation(tokenType lexer.TokenType, leftDenotation typeLeftDen typeLeftDenotations[tokenType] = leftDenotation } -func setTypeMetaLeftDenotation(tokenType lexer.TokenType, metaLeftDenotation typeMetaLeftDenotationFunc) { - current := typeMetaLeftDenotations[tokenType] - if current != nil { - panic(errors.NewUnexpectedError( - "type meta left denotation for token %s already exists", - tokenType, - )) - } - typeMetaLeftDenotations[tokenType] = metaLeftDenotation -} - type prefixTypeFunc func(parser *parser, right ast.Type, tokenRange ast.Range) ast.Type type postfixTypeFunc func(parser *parser, left ast.Type, tokenRange ast.Range) ast.Type @@ -358,7 +347,6 @@ func defineIntersectionOrDictionaryType() { } intersectionType = ast.NewIntersectionType( p.memoryGauge, - nil, []*ast.NominalType{ firstNominalType, }, @@ -462,7 +450,6 @@ func defineIntersectionOrDictionaryType() { intersectionType = ast.NewIntersectionType( p.memoryGauge, nil, - nil, ast.NewRange( p.memoryGauge, startToken.StartPos, @@ -480,69 +467,6 @@ func defineIntersectionOrDictionaryType() { } }, ) - - // For the left denotation we need a meta left denotation: - // We need to look ahead and check if the brace is followed by whitespace or not. - // In case there is a space, the type is *not* considered a intersection type. - // This handles the ambiguous case where a function return type's open brace - // may either be a intersection type (if there is no whitespace) - // or the start of the function body (if there is whitespace). - - setTypeMetaLeftDenotation( - lexer.TokenBraceOpen, - func(p *parser, rightBindingPower int, left ast.Type) (result ast.Type, err error, done bool) { - - // Perform a lookahead - - current := p.current - cursor := p.tokens.Cursor() - - // Skip the `{` token. - p.next() - - // In case there is a space, the type is *not* considered a intersection type. - // The buffered tokens are replayed to allow them to be re-parsed. - - if p.current.Is(lexer.TokenSpace) { - p.current = current - p.tokens.Revert(cursor) - - return left, nil, true - } - - // It was determined that a intersection type is parsed. - // Still, it should have maybe not been parsed if the right binding power - // was higher. In that case, replay the buffered tokens and stop. - - if rightBindingPower >= typeLeftBindingPowerIntersection { - p.current = current - p.tokens.Revert(cursor) - return left, nil, true - } - - nominalTypes, endPos, err := parseNominalTypes(p, lexer.TokenBraceClose, lexer.TokenComma) - - if err != nil { - return nil, err, true - } - - // Skip the closing brace - p.next() - - result = ast.NewIntersectionType( - p.memoryGauge, - left, - nominalTypes, - ast.NewRange( - p.memoryGauge, - left.StartPosition(), - endPos, - ), - ) - - return result, err, false - }, - ) } func parseNominalType( diff --git a/runtime/parser/type_test.go b/runtime/parser/type_test.go index df4c51aa3c..8834c360ce 100644 --- a/runtime/parser/type_test.go +++ b/runtime/parser/type_test.go @@ -507,102 +507,56 @@ func TestParseIntersectionType(t *testing.T) { t.Parallel() - t.Run("with intersection type, no types", func(t *testing.T) { + t.Run("with old prefix and no types", func(t *testing.T) { t.Parallel() - result, errs := testParseType("T{}") - require.Empty(t, errs) + _, errs := testParseType("T{}") utils.AssertEqualWithDiff(t, - &ast.IntersectionType{ - Type: &ast.NominalType{ - Identifier: ast.Identifier{ - Identifier: "T", - Pos: ast.Position{Line: 1, Column: 0, Offset: 0}, - }, - }, - Types: nil, - Range: ast.Range{ - StartPos: ast.Position{Line: 1, Column: 0, Offset: 0}, - EndPos: ast.Position{Line: 1, Column: 2, Offset: 2}, + []error{ + &SyntaxError{ + Message: "unexpected token: '{'", + Pos: ast.Position{Offset: 1, Line: 1, Column: 1}, }, }, - result, + errs, ) }) - t.Run("with intersection type, one type", func(t *testing.T) { + t.Run("with old prefix and one type", func(t *testing.T) { t.Parallel() - result, errs := testParseType("T{U}") - require.Empty(t, errs) - + _, errs := testParseType("T{U}") utils.AssertEqualWithDiff(t, - &ast.IntersectionType{ - Type: &ast.NominalType{ - Identifier: ast.Identifier{ - Identifier: "T", - Pos: ast.Position{Line: 1, Column: 0, Offset: 0}, - }, - }, - Types: []*ast.NominalType{ - { - Identifier: ast.Identifier{ - Identifier: "U", - Pos: ast.Position{Line: 1, Column: 2, Offset: 2}, - }, - }, - }, - Range: ast.Range{ - StartPos: ast.Position{Line: 1, Column: 0, Offset: 0}, - EndPos: ast.Position{Line: 1, Column: 3, Offset: 3}, + []error{ + &SyntaxError{ + Message: "unexpected token: '{'", + Pos: ast.Position{Offset: 1, Line: 1, Column: 1}, }, }, - result, + errs, ) }) - t.Run("with intersection type, two types", func(t *testing.T) { + t.Run("with old prefix and two types", func(t *testing.T) { t.Parallel() - result, errs := testParseType("T{U , V }") - require.Empty(t, errs) - + _, errs := testParseType("T{U , V }") utils.AssertEqualWithDiff(t, - &ast.IntersectionType{ - Type: &ast.NominalType{ - Identifier: ast.Identifier{ - Identifier: "T", - Pos: ast.Position{Line: 1, Column: 0, Offset: 0}, - }, - }, - Types: []*ast.NominalType{ - { - Identifier: ast.Identifier{ - Identifier: "U", - Pos: ast.Position{Line: 1, Column: 2, Offset: 2}, - }, - }, - { - Identifier: ast.Identifier{ - Identifier: "V", - Pos: ast.Position{Line: 1, Column: 6, Offset: 6}, - }, - }, - }, - Range: ast.Range{ - StartPos: ast.Position{Line: 1, Column: 0, Offset: 0}, - EndPos: ast.Position{Line: 1, Column: 8, Offset: 8}, + []error{ + &SyntaxError{ + Message: "unexpected token: '{'", + Pos: ast.Position{Offset: 1, Line: 1, Column: 1}, }, }, - result, + errs, ) }) - t.Run("without intersection type, no types", func(t *testing.T) { + t.Run("no types", func(t *testing.T) { t.Parallel() @@ -620,7 +574,7 @@ func TestParseIntersectionType(t *testing.T) { ) }) - t.Run("without intersection type, one type", func(t *testing.T) { + t.Run("one type", func(t *testing.T) { t.Parallel() @@ -646,7 +600,7 @@ func TestParseIntersectionType(t *testing.T) { ) }) - t.Run("invalid: without intersection type, missing type after comma", func(t *testing.T) { + t.Run("invalid: missing type after comma", func(t *testing.T) { t.Parallel() @@ -680,7 +634,7 @@ func TestParseIntersectionType(t *testing.T) { ) }) - t.Run("invalid: without intersection type, type without comma", func(t *testing.T) { + t.Run("invalid: type without comma", func(t *testing.T) { t.Parallel() @@ -699,7 +653,7 @@ func TestParseIntersectionType(t *testing.T) { assert.Nil(t, result) }) - t.Run("invalid: without intersection type, colon", func(t *testing.T) { + t.Run("invalid: colon", func(t *testing.T) { t.Parallel() @@ -718,16 +672,16 @@ func TestParseIntersectionType(t *testing.T) { assert.Nil(t, result) }) - t.Run("invalid: with intersection type, colon", func(t *testing.T) { + t.Run("invalid: colon", func(t *testing.T) { t.Parallel() - result, errs := testParseType("T{U , V : W }") + result, errs := testParseType("{U , V : W }") utils.AssertEqualWithDiff(t, []error{ &SyntaxError{ - Message: `unexpected token: got ':', expected ',' or '}'`, - Pos: ast.Position{Offset: 8, Line: 1, Column: 8}, + Message: `unexpected colon in intersection type`, + Pos: ast.Position{Offset: 7, Line: 1, Column: 7}, }, }, errs, @@ -737,7 +691,7 @@ func TestParseIntersectionType(t *testing.T) { assert.Nil(t, result) }) - t.Run("invalid: without intersection type, first is non-nominal", func(t *testing.T) { + t.Run("invalid: first is non-nominal", func(t *testing.T) { t.Parallel() @@ -756,26 +710,7 @@ func TestParseIntersectionType(t *testing.T) { assert.Nil(t, result) }) - t.Run("invalid: with intersection type, first is non-nominal", func(t *testing.T) { - - t.Parallel() - - result, errs := testParseType("T{[U]}") - utils.AssertEqualWithDiff(t, - []error{ - &SyntaxError{ - Message: "unexpected non-nominal type: [U]", - Pos: ast.Position{Offset: 5, Line: 1, Column: 5}, - }, - }, - errs, - ) - - // TODO: return type - assert.Nil(t, result) - }) - - t.Run("invalid: without intersection type, second is non-nominal", func(t *testing.T) { + t.Run("invalid: second is non-nominal", func(t *testing.T) { t.Parallel() @@ -794,26 +729,7 @@ func TestParseIntersectionType(t *testing.T) { assert.Nil(t, result) }) - t.Run("invalid: with intersection type, second is non-nominal", func(t *testing.T) { - - t.Parallel() - - result, errs := testParseType("T{U, [V]}") - utils.AssertEqualWithDiff(t, - []error{ - &SyntaxError{ - Message: "unexpected non-nominal type: [V]", - Pos: ast.Position{Offset: 8, Line: 1, Column: 8}, - }, - }, - errs, - ) - - // TODO: return type - assert.Nil(t, result) - }) - - t.Run("invalid: without intersection type, missing end", func(t *testing.T) { + t.Run("invalid: missing end", func(t *testing.T) { t.Parallel() @@ -831,25 +747,7 @@ func TestParseIntersectionType(t *testing.T) { assert.Nil(t, result) }) - t.Run("invalid: with intersection type, missing end", func(t *testing.T) { - - t.Parallel() - - result, errs := testParseType("T{") - utils.AssertEqualWithDiff(t, - []error{ - &SyntaxError{ - Message: "invalid end of input, expected type", - Pos: ast.Position{Offset: 2, Line: 1, Column: 2}, - }, - }, - errs, - ) - - assert.Nil(t, result) - }) - - t.Run("invalid: without intersection type, missing end after type", func(t *testing.T) { + t.Run("invalid: missing end after type", func(t *testing.T) { t.Parallel() @@ -867,25 +765,7 @@ func TestParseIntersectionType(t *testing.T) { assert.Nil(t, result) }) - t.Run("invalid: with intersection type, missing end after type", func(t *testing.T) { - - t.Parallel() - - result, errs := testParseType("T{U") - utils.AssertEqualWithDiff(t, - []error{ - &SyntaxError{ - Message: "invalid end of input, expected '}'", - Pos: ast.Position{Offset: 3, Line: 1, Column: 3}, - }, - }, - errs, - ) - - assert.Nil(t, result) - }) - - t.Run("invalid: without intersection type, missing end after comma", func(t *testing.T) { + t.Run("invalid: missing end after comma", func(t *testing.T) { t.Parallel() @@ -903,25 +783,7 @@ func TestParseIntersectionType(t *testing.T) { assert.Nil(t, result) }) - t.Run("invalid: with intersection type, missing end after comma", func(t *testing.T) { - - t.Parallel() - - result, errs := testParseType("T{U,") - utils.AssertEqualWithDiff(t, - []error{ - &SyntaxError{ - Message: "invalid end of input, expected type", - Pos: ast.Position{Offset: 4, Line: 1, Column: 4}, - }, - }, - errs, - ) - - assert.Nil(t, result) - }) - - t.Run("invalid: without intersection type, just comma", func(t *testing.T) { + t.Run("invalid: just comma", func(t *testing.T) { t.Parallel() @@ -938,24 +800,6 @@ func TestParseIntersectionType(t *testing.T) { assert.Nil(t, result) }) - - t.Run("invalid: with intersection type, just comma", func(t *testing.T) { - - t.Parallel() - - result, errs := testParseType("T{,}") - utils.AssertEqualWithDiff(t, - []error{ - &SyntaxError{ - Message: "unexpected separator", - Pos: ast.Position{Offset: 2, Line: 1, Column: 2}, - }, - }, - errs, - ) - - assert.Nil(t, result) - }) } func TestParseDictionaryType(t *testing.T) { @@ -2875,73 +2719,7 @@ func TestParseOptionalReference(t *testing.T) { ) } -func TestParseIntersectionReferenceTypeWithBaseType(t *testing.T) { - - t.Parallel() - - const code = ` - let x: &R{I} = 1 - ` - result, errs := testParseProgram(code) - require.Empty(t, errs) - - utils.AssertEqualWithDiff(t, - []ast.Declaration{ - &ast.VariableDeclaration{ - Access: ast.AccessNotSpecified, - IsConstant: true, - Identifier: ast.Identifier{ - Identifier: "x", - Pos: ast.Position{Offset: 12, Line: 2, Column: 11}, - }, - TypeAnnotation: &ast.TypeAnnotation{ - IsResource: false, - Type: &ast.ReferenceType{ - Type: &ast.IntersectionType{ - Type: &ast.NominalType{ - Identifier: ast.Identifier{ - Identifier: "R", - Pos: ast.Position{Offset: 16, Line: 2, Column: 15}, - }, - }, - Types: []*ast.NominalType{ - { - Identifier: ast.Identifier{ - Identifier: "I", - Pos: ast.Position{Offset: 18, Line: 2, Column: 17}, - }, - }, - }, - Range: ast.Range{ - StartPos: ast.Position{Offset: 16, Line: 2, Column: 15}, - EndPos: ast.Position{Offset: 19, Line: 2, Column: 18}, - }, - }, - StartPos: ast.Position{Offset: 15, Line: 2, Column: 14}, - }, - StartPos: ast.Position{Offset: 15, Line: 2, Column: 14}, - }, - Value: &ast.IntegerExpression{ - PositiveLiteral: []byte("1"), - Value: big.NewInt(1), - Base: 10, - Range: ast.Range{ - StartPos: ast.Position{Offset: 23, Line: 2, Column: 22}, - EndPos: ast.Position{Offset: 23, Line: 2, Column: 22}, - }, - }, - Transfer: &ast.Transfer{ - Operation: ast.TransferOperationCopy, - Pos: ast.Position{Offset: 21, Line: 2, Column: 20}, - }, - StartPos: ast.Position{Offset: 8, Line: 2, Column: 7}, - }, - }, - result.Declarations(), - ) -} - -func TestParseIntersectionReferenceTypeWithoutBaseType(t *testing.T) { +func TestParseIntersectionReferenceType(t *testing.T) { t.Parallel() @@ -3005,72 +2783,6 @@ func TestParseOptionalIntersectionType(t *testing.T) { t.Parallel() - const code = ` - let x: @R{I}? = 1 - ` - result, errs := testParseProgram(code) - require.Empty(t, errs) - - utils.AssertEqualWithDiff(t, - []ast.Declaration{ - &ast.VariableDeclaration{ - Access: ast.AccessNotSpecified, - IsConstant: true, - Identifier: ast.Identifier{ - Identifier: "x", - Pos: ast.Position{Offset: 12, Line: 2, Column: 11}, - }, - TypeAnnotation: &ast.TypeAnnotation{ - IsResource: true, - Type: &ast.OptionalType{ - Type: &ast.IntersectionType{ - Type: &ast.NominalType{ - Identifier: ast.Identifier{ - Identifier: "R", - Pos: ast.Position{Offset: 16, Line: 2, Column: 15}, - }, - }, - Types: []*ast.NominalType{ - { - Identifier: ast.Identifier{ - Identifier: "I", - Pos: ast.Position{Offset: 18, Line: 2, Column: 17}, - }, - }, - }, - Range: ast.Range{ - StartPos: ast.Position{Offset: 16, Line: 2, Column: 15}, - EndPos: ast.Position{Offset: 19, Line: 2, Column: 18}, - }, - }, - EndPos: ast.Position{Offset: 20, Line: 2, Column: 19}, - }, - StartPos: ast.Position{Offset: 15, Line: 2, Column: 14}, - }, - Value: &ast.IntegerExpression{ - PositiveLiteral: []byte("1"), - Value: big.NewInt(1), - Base: 10, - Range: ast.Range{ - StartPos: ast.Position{Offset: 24, Line: 2, Column: 23}, - EndPos: ast.Position{Offset: 24, Line: 2, Column: 23}, - }, - }, - Transfer: &ast.Transfer{ - Operation: ast.TransferOperationCopy, - Pos: ast.Position{Offset: 22, Line: 2, Column: 21}, - }, - StartPos: ast.Position{Offset: 8, Line: 2, Column: 7}, - }, - }, - result.Declarations(), - ) -} - -func TestParseOptionalIntersectionTypeOnlyTypes(t *testing.T) { - - t.Parallel() - const code = ` let x: @{I}? = 1 ` diff --git a/runtime/runtime_test.go b/runtime/runtime_test.go index cfed4e3b87..514aa8514b 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -2581,7 +2581,7 @@ func TestRuntimeResourceContractWithInterface(t *testing.T) { transaction { prepare(signer: AuthAccount) { signer.save(<-createR(), to: /storage/r) - signer.link<&AnyResource{RI}>(/public/r, target: /storage/r) + signer.link<&{RI}>(/public/r, target: /storage/r) } } `) @@ -2598,7 +2598,7 @@ func TestRuntimeResourceContractWithInterface(t *testing.T) { prepare(signer: AuthAccount) { let ref = signer .getCapability(/public/r) - .borrow<&AnyResource{RI}>()! + .borrow<&{RI}>()! ref.x() } } @@ -4165,7 +4165,7 @@ access(all) contract FungibleToken { } } - access(all) fun deposit(from: @AnyResource{Receiver}) { + access(all) fun deposit(from: @{Receiver}) { pre { from.balance > 0: "Deposit balance needs to be positive!" @@ -4191,7 +4191,7 @@ access(all) contract FungibleToken { } // transfer combines withdraw and deposit into one function call - access(all) fun transfer(to: &AnyResource{Receiver}, amount: Int) { + access(all) fun transfer(to: &{Receiver}, amount: Int) { pre { amount <= self.balance: "Insufficient funds" @@ -4203,7 +4203,7 @@ access(all) contract FungibleToken { to.deposit(from: <-self.withdraw(amount: amount)) } - access(all) fun deposit(from: @AnyResource{Receiver}) { + access(all) fun deposit(from: @{Receiver}) { self.balance = self.balance + from.balance destroy from } @@ -4218,7 +4218,7 @@ access(all) contract FungibleToken { } access(all) resource VaultMinter { - access(all) fun mintTokens(amount: Int, recipient: &AnyResource{Receiver}) { + access(all) fun mintTokens(amount: Int, recipient: &{Receiver}) { recipient.deposit(from: <-create Vault(balance: amount)) } } @@ -4253,7 +4253,7 @@ func TestRuntimeFungibleTokenUpdateAccountCode(t *testing.T) { prepare(acct: AuthAccount) { - acct.link<&AnyResource{FungibleToken.Receiver}>( + acct.link<&{FungibleToken.Receiver}>( /public/receiver, target: /storage/vault ) @@ -4277,7 +4277,7 @@ func TestRuntimeFungibleTokenUpdateAccountCode(t *testing.T) { acct.save(<-vault, to: /storage/vault) - acct.link<&AnyResource{FungibleToken.Receiver}>( + acct.link<&{FungibleToken.Receiver}>( /public/receiver, target: /storage/vault ) @@ -4387,7 +4387,7 @@ func TestRuntimeFungibleTokenCreateAccount(t *testing.T) { transaction { prepare(acct: AuthAccount) { - acct.link<&AnyResource{FungibleToken.Receiver}>( + acct.link<&{FungibleToken.Receiver}>( /public/receiver, target: /storage/vault ) @@ -4411,7 +4411,7 @@ func TestRuntimeFungibleTokenCreateAccount(t *testing.T) { acct.save(<-vault, to: /storage/vault) - acct.link<&AnyResource{FungibleToken.Receiver}>( + acct.link<&{FungibleToken.Receiver}>( /public/receiver, target: /storage/vault ) @@ -4567,7 +4567,7 @@ func TestRuntimeInvokeStoredInterfaceFunction(t *testing.T) { transaction { prepare(signer: AuthAccount) { - signer.borrow<&AnyResource{TestContractInterface.RInterface}>(from: /storage/r)?.check(a: %d, b: %d) + signer.borrow<&{TestContractInterface.RInterface}>(from: /storage/r)?.check(a: %d, b: %d) } } `, diff --git a/runtime/sema/authaccount.cdc b/runtime/sema/authaccount.cdc index e987a4094b..f6a7f8566d 100644 --- a/runtime/sema/authaccount.cdc +++ b/runtime/sema/authaccount.cdc @@ -411,6 +411,6 @@ access(all) struct AuthAccount { access(all) fun forEachController(_ function: fun(&AccountCapabilityController): Bool) /// Issue/create a new account capability. - access(all) fun issue(): Capability + access(all) fun issue(): Capability } } diff --git a/runtime/sema/authaccount.gen.go b/runtime/sema/authaccount.gen.go index b6b46c24c3..32cde643e0 100644 --- a/runtime/sema/authaccount.gen.go +++ b/runtime/sema/authaccount.gen.go @@ -1723,9 +1723,7 @@ const AuthAccountAccountCapabilitiesTypeIssueFunctionName = "issue" var AuthAccountAccountCapabilitiesTypeIssueFunctionTypeParameterT = &TypeParameter{ Name: "T", TypeBound: &ReferenceType{ - Type: &IntersectionType{ - Type: AuthAccountType, - }, + Type: AuthAccountType, Authorization: UnauthorizedAccess, }, } diff --git a/runtime/sema/check_casting_expression.go b/runtime/sema/check_casting_expression.go index a850598c82..1ec4cf2a4c 100644 --- a/runtime/sema/check_casting_expression.go +++ b/runtime/sema/check_casting_expression.go @@ -204,177 +204,39 @@ func FailableCastCanSucceed(subType, superType Type) bool { switch typedSubType := subType.(type) { case *IntersectionType: - - intersectionSuperType := typedSuperType.Type - switch intersectionSuperType { - - case AnyResourceType: - // A intersection type `T{Us}` - // is a subtype of a intersection type `AnyResource{Vs}`: - // - // When `T == AnyResource || T == Any`: - // if the run-time type conforms to `Vs` - // - // When `T != AnyResource && T != Any`: - // if `T` conforms to `Vs`. - // `Us` and `Vs` do *not* have to be subsets. - - switch typedSubType.Type { - case AnyResourceType, AnyType: - return true - default: - if typedInnerSubType, ok := typedSubType.Type.(*CompositeType); ok { - - return IsSubType(typedInnerSubType, intersectionSuperType) && - typedSuperType.EffectiveIntersectionSet(). - IsSubsetOf(typedInnerSubType.EffectiveInterfaceConformanceSet()) - } - } - - case AnyStructType: - // A intersection type `T{Us}` - // is a subtype of a intersection type `AnyStruct{Vs}`: - // - // When `T == AnyStruct || T == Any`: if the run-time type conforms to `Vs` - // - // When `T != AnyStruct && T != Any`: if `T` conforms to `Vs`. - // `Us` and `Vs` do *not* have to be subsets. - - switch typedSubType.Type { - case AnyStructType, AnyType: - return true - default: - if typedInnerSubType, ok := typedSubType.Type.(*CompositeType); ok { - - return IsSubType(typedInnerSubType, intersectionSuperType) && - typedSuperType.EffectiveIntersectionSet(). - IsSubsetOf(typedInnerSubType.EffectiveInterfaceConformanceSet()) - } - } - - case AnyType: - // A intersection type `T{Us}` - // is a subtype of a intersection type `Any{Vs}`: - // - // When `T == AnyResource || T == AnyStruct || T == Any`: - // if the run-time type conforms to `Vs` - // - // When `T != AnyResource && T != AnyStruct && T != Any`: - // if `T` conforms to `Vs`. - // `Us` and `Vs` do *not* have to be subsets. - - switch typedSubType.Type { - case AnyResourceType, AnyStructType, AnyType: - return true - default: - if typedInnerSubType, ok := typedSubType.Type.(*CompositeType); ok { - - return IsSubType(typedInnerSubType, intersectionSuperType) && - typedSuperType.EffectiveIntersectionSet(). - IsSubsetOf(typedInnerSubType.EffectiveInterfaceConformanceSet()) - } - } - - default: - - // A intersection type `T{Us}` - // is a subtype of a intersection type `V{Ws}`: - // - // When `T == AnyResource || T == AnyStruct || T == Any`: - // if the run-time type is `V`. - // - // When `T != AnyResource && T != AnyStruct && T != Any`: - // if `T == V`. - // `Us` and `Ws` do *not* have to be subsets: - // The owner may freely restrict and unrestrict. - - switch typedSubType.Type { - case AnyResourceType, AnyStructType, AnyType: - return true - default: - return typedSubType.Type.Equal(typedSuperType.Type) - } - } + // A intersection type `{Us}` + // is a subtype of a intersection type `{Vs}`: + // if the run-time type conforms to `Vs` + // `Us` and `Vs` do *not* have to be subsets. + return true case *CompositeType: - switch typedSuperType.Type { - case AnyResourceType, AnyStructType, AnyType: - - // A type `T` - // is a subtype of a intersection type `AnyResource{Us}` / `AnyStruct{Us}` / `Any{Us}`: - // - // When `T != AnyResource && T != AnyStruct && T != Any`: - // if `T` is a subtype of the intersection supertype, - // and `T` conforms to `Us`. - - return IsSubType(typedSubType, typedSuperType.Type) && - typedSuperType.EffectiveIntersectionSet(). - IsSubsetOf(typedSubType.EffectiveInterfaceConformanceSet()) - - default: - - // A type `T` - // is a subtype of a intersection type `U{Vs}`: - // - // When `T != AnyResource && T != AnyStruct && T != Any`: - // if `T == U`. + // A type `T` is a subtype of a intersection type `{Us}`: + // + // When `T != AnyResource && T != AnyStruct && T != Any`: + // if `T` conforms to `Us`. - return typedSubType.Equal(typedSuperType.Type) - } + return typedSuperType.EffectiveIntersectionSet(). + IsSubsetOf(typedSubType.EffectiveInterfaceConformanceSet()) } switch subType { case AnyResourceType, AnyStructType, AnyType: + // A type `T` is a subtype of a intersection type `{Us}`: + // if the run-time type conforms to `Vs` - switch typedSuperType.Type { - case AnyResourceType, AnyStructType, AnyType: - - // A type `T` - // is a subtype of a intersection type `AnyResource{Us}` / `AnyStruct{Us}` / `Any{Us}`: - // - // When `T == AnyResource || T == AnyStruct` || T == Any`: - // if the run-time type conforms to `Vs` - - return true - - default: - - // A type `T` - // is a subtype of a intersection type `U{Vs}`: - // - // When `T == AnyResource || T == AnyStruct || T == Any`: - // if the run-time type is U. - - // NOTE: inverse! - - return IsSubType(typedSuperType.Type, subType) - } + return true } case *CompositeType: - - switch typedSubType := subType.(type) { + switch subType.(type) { case *IntersectionType: - // A intersection type `T{Us}` - // is a subtype of a type `V`: - // - // When `T == AnyResource || T == AnyStruct || T == Any`: + // A intersection type `{Us}` is a subtype of a type `V`: // if the run-time type is V. - // - // When `T != AnyResource && T != AnyStruct && T != Any`: - // if `T == V`. - // The owner may freely unrestrict. - - switch typedSubType.Type { - case AnyResourceType, AnyStructType, AnyType: - return true - - default: - return typedSubType.Type.Equal(typedSuperType) - } + return true } } @@ -382,14 +244,13 @@ func FailableCastCanSucceed(subType, superType Type) bool { switch superType { case AnyResourceType, AnyStructType: - // A intersection type `T{Us}` - // or a type `T` - // is a subtype of the type `AnyResource` / `AnyStruct`: - // if `T` is `AnyType`, or `T` is a subtype of `AnyResource` / `AnyStruct`. + // A intersection type `{Us}` or a type `T` s a subtype of the type `AnyResource` / `AnyStruct`: + // if `T` is `AnyType`, or `T` is a subtype of `AnyResource` / `AnyStruct`, or if `Us` are subtypes of `AnyResource` / `AnyStruct` innerSubtype := subType if intersectionSubType, ok := subType.(*IntersectionType); ok { - innerSubtype = intersectionSubType.Type + // because the intersection's types are guaranteed to be the same kind, we only need to check the first one + innerSubtype = intersectionSubType.Types[0] } return innerSubtype == AnyType || diff --git a/runtime/sema/check_composite_declaration.go b/runtime/sema/check_composite_declaration.go index b9d320bea4..a04ed01c72 100644 --- a/runtime/sema/check_composite_declaration.go +++ b/runtime/sema/check_composite_declaration.go @@ -2443,13 +2443,9 @@ func (checker *Checker) declareSelfValue(selfType Type, selfDocString string) { func (checker *Checker) declareBaseValue(baseType Type, attachmentType *CompositeType, superDocString string) { if typedBaseType, ok := baseType.(*InterfaceType); ok { - intersectionType := AnyStructType - if baseType.IsResourceType() { - intersectionType = AnyResourceType - } // we can't actually have a value of an interface type I, so instead we create a value of {I} // to be referenced by `base` - baseType = NewIntersectionType(checker.memoryGauge, intersectionType, []*InterfaceType{typedBaseType}) + baseType = NewIntersectionType(checker.memoryGauge, []*InterfaceType{typedBaseType}) } // the `base` value in an attachment function has the set of entitlements defined by the required entitlements specified in the attachment's declaration // ------------------------------- diff --git a/runtime/sema/checker.go b/runtime/sema/checker.go index 5976d39bdf..36fc78956a 100644 --- a/runtime/sema/checker.go +++ b/runtime/sema/checker.go @@ -899,7 +899,6 @@ func (checker *Checker) ConvertType(t ast.Type) Type { func CheckIntersectionType( memoryGauge common.MemoryGauge, - intersectionType Type, types []*InterfaceType, report func(func(*ast.IntersectionType) error), ) Type { @@ -978,75 +977,28 @@ func CheckIntersectionType( }) } - var hadExplicitType = intersectionType != nil + // If no intersection type is given, infer `AnyResource`/`AnyStruct` + // based on the composite kind of the intersections. - if !hadExplicitType { - // If no intersection type is given, infer `AnyResource`/`AnyStruct` - // based on the composite kind of the intersections. + switch intersectionsCompositeKind { + case common.CompositeKindUnknown: + // If no intersection type is given, and also no intersections, + // the type is ambiguous. - switch intersectionsCompositeKind { - case common.CompositeKindUnknown: - // If no intersection type is given, and also no intersections, - // the type is ambiguous. - - intersectionType = InvalidType - - report(func(t *ast.IntersectionType) error { - return &AmbiguousIntersectionTypeError{Range: ast.NewRangeFromPositioned(memoryGauge, t)} - }) - - case common.CompositeKindResource: - intersectionType = AnyResourceType - - case common.CompositeKindStructure: - intersectionType = AnyStructType - - default: - panic(errors.NewUnreachableError()) - } - } - - // The intersection type must be a composite type - // or `AnyResource`/`AnyStruct` - - reportInvalidIntersectionType := func() { report(func(t *ast.IntersectionType) error { - return &InvalidIntersectionTypeError{ - Type: intersectionType, - Range: ast.NewRangeFromPositioned(memoryGauge, t.Type), - } + return &AmbiguousIntersectionTypeError{Range: ast.NewRangeFromPositioned(memoryGauge, t)} }) - } - - var compositeType *CompositeType - - if !intersectionType.IsInvalidType() { - - if typeResult, ok := intersectionType.(*CompositeType); ok { - switch typeResult.Kind { - - case common.CompositeKindResource, - common.CompositeKindStructure: - - compositeType = typeResult - - default: - reportInvalidIntersectionType() - } - } else { + return InvalidType - switch intersectionType { - case AnyResourceType, AnyStructType, AnyType: - break + case common.CompositeKindResource, common.CompositeKindStructure: + break - default: - if hadExplicitType { - reportInvalidIntersectionType() - } - } - } + default: + panic(errors.NewUnreachableError()) } + var compositeType *CompositeType + // If the intersection type is a composite type, // check that the intersections are conformances @@ -1070,18 +1022,11 @@ func CheckIntersectionType( } } } - return intersectionType + + return &IntersectionType{Types: types} } func (checker *Checker) convertIntersectionType(t *ast.IntersectionType) Type { - var intersectionType Type - - // Convert the intersection type, if any - - if t.Type != nil { - intersectionType = checker.ConvertType(t.Type) - } - // Convert the intersected types var intersectedTypes []*InterfaceType @@ -1114,19 +1059,15 @@ func (checker *Checker) convertIntersectionType(t *ast.IntersectionType) Type { intersectedTypes = append(intersectedTypes, intersectedInterfaceType) } - intersectionType = CheckIntersectionType( + intersectionType := CheckIntersectionType( checker.memoryGauge, - intersectionType, intersectedTypes, func(getError func(*ast.IntersectionType) error) { checker.report(getError(t)) }, ) - return &IntersectionType{ - Type: intersectionType, - Types: intersectedTypes, - } + return intersectionType } func (checker *Checker) convertReferenceType(t *ast.ReferenceType) Type { diff --git a/runtime/sema/errors.go b/runtime/sema/errors.go index 78f75be3a5..034c2842d6 100644 --- a/runtime/sema/errors.go +++ b/runtime/sema/errors.go @@ -3424,27 +3424,6 @@ func (e *ConstantSizedArrayLiteralSizeError) SecondaryError() string { ) } -// InvalidIntersectionTypeError - -type InvalidIntersectionTypeError struct { - Type Type - ast.Range -} - -var _ SemanticError = &InvalidIntersectionTypeError{} -var _ errors.UserError = &InvalidIntersectionTypeError{} - -func (*InvalidIntersectionTypeError) isSemanticError() {} - -func (*InvalidIntersectionTypeError) IsUserError() {} - -func (e *InvalidIntersectionTypeError) Error() string { - return fmt.Sprintf( - "cannot restrict type: `%s`", - e.Type.QualifiedString(), - ) -} - // InvalidIntersectedTypeError type InvalidIntersectedTypeError struct { @@ -3531,24 +3510,6 @@ func (e *InvalidNonConformanceIntersectionError) Error() string { ) } -// InvalidIntersectionTypeMemberAccessError - -type InvalidIntersectionTypeMemberAccessError struct { - Name string - ast.Range -} - -var _ SemanticError = &InvalidIntersectionTypeMemberAccessError{} -var _ errors.UserError = &InvalidIntersectionTypeMemberAccessError{} - -func (*InvalidIntersectionTypeMemberAccessError) isSemanticError() {} - -func (*InvalidIntersectionTypeMemberAccessError) IsUserError() {} - -func (e *InvalidIntersectionTypeMemberAccessError) Error() string { - return fmt.Sprintf("member of intersection type is not accessible: %s", e.Name) -} - // IntersectionMemberClashError type IntersectionMemberClashError struct { diff --git a/runtime/sema/gen/main.go b/runtime/sema/gen/main.go index 44aca89784..5a3666cd1c 100644 --- a/runtime/sema/gen/main.go +++ b/runtime/sema/gen/main.go @@ -725,12 +725,6 @@ func typeExpr(t ast.Type, typeParams map[string]string) dst.Expr { case *ast.IntersectionType: var elements []dst.Expr - if t.Type != nil { - intersectionType := typeExpr(t.Type, typeParams) - elements = append(elements, - goKeyValue("Type", intersectionType), - ) - } if len(t.Types) > 0 { intersectedTypes := make([]dst.Expr, 0, len(t.Types)) diff --git a/runtime/sema/gen/testdata/fields.cdc b/runtime/sema/gen/testdata/fields.cdc index af62563a57..667f50b712 100644 --- a/runtime/sema/gen/testdata/fields.cdc +++ b/runtime/sema/gen/testdata/fields.cdc @@ -31,10 +31,4 @@ access(all) struct Test { /// This is a test intersection type (without type) field. access(all) let testIntersectionWithoutType: {Bar, Baz} - - /// This is a test intersection type (with type) field. - access(all) let testIntersectionWithType: Foo{Bar, Baz} - - /// This is a test intersection type (without types) field. - access(all) let testIntersectionWithoutTypes: Foo{} } diff --git a/runtime/sema/gen/testdata/fields.golden.go b/runtime/sema/gen/testdata/fields.golden.go index 4e1be367a1..a361770494 100644 --- a/runtime/sema/gen/testdata/fields.golden.go +++ b/runtime/sema/gen/testdata/fields.golden.go @@ -127,27 +127,6 @@ const TestTypeTestIntersectionWithoutTypeFieldDocString = ` This is a test intersection type (without type) field. ` -const TestTypeTestIntersectionWithTypeFieldName = "testIntersectionWithType" - -var TestTypeTestIntersectionWithTypeFieldType = &IntersectionType{ - Type: FooType, - Types: []*InterfaceType{BarType, BazType}, -} - -const TestTypeTestIntersectionWithTypeFieldDocString = ` -This is a test intersection type (with type) field. -` - -const TestTypeTestIntersectionWithoutTypesFieldName = "testIntersectionWithoutTypes" - -var TestTypeTestIntersectionWithoutTypesFieldType = &IntersectionType{ - Type: FooType, -} - -const TestTypeTestIntersectionWithoutTypesFieldDocString = ` -This is a test intersection type (without types) field. -` - const TestTypeName = "Test" var TestType = &SimpleType{ @@ -254,22 +233,6 @@ func init() { TestTypeTestIntersectionWithoutTypeFieldType, TestTypeTestIntersectionWithoutTypeFieldDocString, ), - NewUnmeteredFieldMember( - t, - ast.AccessAll, - ast.VariableKindConstant, - TestTypeTestIntersectionWithTypeFieldName, - TestTypeTestIntersectionWithTypeFieldType, - TestTypeTestIntersectionWithTypeFieldDocString, - ), - NewUnmeteredFieldMember( - t, - ast.AccessAll, - ast.VariableKindConstant, - TestTypeTestIntersectionWithoutTypesFieldName, - TestTypeTestIntersectionWithoutTypesFieldType, - TestTypeTestIntersectionWithoutTypesFieldDocString, - ), }) } } diff --git a/runtime/sema/runtime_type_constructors.go b/runtime/sema/runtime_type_constructors.go index 1b53de279e..7b48a27a94 100644 --- a/runtime/sema/runtime_type_constructors.go +++ b/runtime/sema/runtime_type_constructors.go @@ -134,14 +134,6 @@ var FunctionTypeFunctionType = NewSimpleFunctionType( var IntersectionTypeFunctionType = NewSimpleFunctionType( FunctionPurityView, []Parameter{ - { - Identifier: "identifier", - TypeAnnotation: NewTypeAnnotation( - &OptionalType{ - Type: StringType, - }, - ), - }, { Identifier: "types", TypeAnnotation: NewTypeAnnotation( diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 4da2c3069d..caddea0a40 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -4964,21 +4964,15 @@ func (*InterfaceType) TypeAnnotationState() TypeAnnotationState { func (t *InterfaceType) RewriteWithIntersectionTypes() (Type, bool) { switch t.CompositeKind { - case common.CompositeKindResource: + case common.CompositeKindResource, common.CompositeKindStructure: return &IntersectionType{ - Type: AnyResourceType, - Types: []*InterfaceType{t}, - }, true - - case common.CompositeKindStructure: - return &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{t}, }, true default: return t, false } + } func (*InterfaceType) Unify(_ Type, _ *TypeParameterTypeOrderedMap, _ func(err error), _ ast.Range) bool { @@ -6181,120 +6175,21 @@ func checkSubTypeWithoutEquality(subType Type, superType Type) bool { return true case *IntersectionType: + switch typedSubType := subType.(type) { + case *IntersectionType: - intersectionSuperType := typedSuperType.Type - switch intersectionSuperType { - case AnyResourceType, AnyStructType, AnyType: - - switch subType { - case AnyResourceType: - // `AnyResource` is a subtype of a intersection type - // - `AnyResource{Us}`: not statically; - // - `AnyStruct{Us}`: never. - // - `Any{Us}`: not statically; - - return false - - case AnyStructType: - // `AnyStruct` is a subtype of a intersection type - // - `AnyStruct{Us}`: not statically. - // - `AnyResource{Us}`: never; - // - `Any{Us}`: not statically. - - return false - - case AnyType: - // `Any` is a subtype of a intersection type - // - `Any{Us}: not statically.` - // - `AnyStruct{Us}`: never; - // - `AnyResource{Us}`: never; - - return false - } - - switch typedSubType := subType.(type) { - case *IntersectionType: - - // A intersection type `T{Us}` - // is a subtype of a intersection type `AnyResource{Vs}` / `AnyStruct{Vs}` / `Any{Vs}`: - - intersectionSubtype := typedSubType.Type - switch intersectionSubtype { - case AnyResourceType, AnyStructType, AnyType: - // When `T == AnyResource || T == AnyStruct || T == Any`: - // if the intersection type of the subtype - // is a subtype of the intersection supertype, - // and `Vs` is a subset of `Us`. - - return IsSubType(intersectionSubtype, intersectionSuperType) && - typedSuperType.EffectiveIntersectionSet(). - IsSubsetOf(typedSubType.EffectiveIntersectionSet()) - } - - if intersectionSubtype, ok := intersectionSubtype.(*CompositeType); ok { - // When `T != AnyResource && T != AnyStruct && T != Any`: - // if the intersection type of the subtype - // is a subtype of the intersection supertype, - // and `T` conforms to `Vs`. - // `Us` and `Vs` do *not* have to be subsets. - - return IsSubType(intersectionSubtype, intersectionSuperType) && - typedSuperType.EffectiveIntersectionSet(). - IsSubsetOf(intersectionSubtype.EffectiveInterfaceConformanceSet()) - } - - case *CompositeType: - // A type `T` - // is a subtype of a intersection type `AnyResource{Us}` / `AnyStruct{Us}` / `Any{Us}`: - // if `T` is a subtype of the intersection supertype, - // and `T` conforms to `Us`. - - return IsSubType(typedSubType, typedSuperType.Type) && - typedSuperType.EffectiveIntersectionSet(). - IsSubsetOf(typedSubType.EffectiveInterfaceConformanceSet()) - } - - default: - - switch typedSubType := subType.(type) { - case *IntersectionType: - - // A intersection type `T{Us}` - // is a subtype of a intersection type `V{Ws}`: - - switch typedSubType.Type { - case AnyResourceType, AnyStructType, AnyType: - // When `T == AnyResource || T == AnyStruct || T == Any`: - // not statically. - return false - } - - if intersectionSubType, ok := typedSubType.Type.(*CompositeType); ok { - // When `T != AnyResource && T != AnyStructType && T != Any`: if `T == V`. - // - // `Us` and `Ws` do *not* have to be subsets: - // The owner may freely restrict and unrestrict. - - return intersectionSubType == typedSuperType.Type - } - - case *CompositeType: - // A type `T` - // is a subtype of a intersection type `U{Vs}`: if `T <: U`. - // - // The owner may freely restrict. + // A intersection type `{Us}` is a subtype of a intersection type `{Vs}` / `{Vs}` / `{Vs}`: + // when `Vs` is a subset of `Us`. - return IsSubType(typedSubType, typedSuperType.Type) - } + return typedSuperType.EffectiveIntersectionSet(). + IsSubsetOf(typedSubType.EffectiveIntersectionSet()) - switch subType { - case AnyResourceType, AnyStructType, AnyType: - // A type `T` - // is a subtype of a intersection type `AnyResource{Vs}` / `AnyStruct{Vs}` / `Any{Vs}`: - // not statically. + case *CompositeType: + // A type `T` is a subtype of a intersection type `{Us}` / `{Us}` / `{Us}`: + // when `T` conforms to `Us`. - return false - } + return typedSuperType.EffectiveIntersectionSet(). + IsSubsetOf(typedSubType.EffectiveInterfaceConformanceSet()) } case *CompositeType: @@ -6305,22 +6200,8 @@ func checkSubTypeWithoutEquality(subType Type, superType Type) bool { switch typedSubType := subType.(type) { case *IntersectionType: - // A intersection type `T{Us}` - // is a subtype of a type `V`: - - switch typedSubType.Type { - case AnyResourceType, AnyStructType, AnyType: - // When `T == AnyResource || T == AnyStruct || T == Any`: not statically. - return false - } - - if intersectionSubType, ok := typedSubType.Type.(*CompositeType); ok { - // When `T != AnyResource && T != AnyStruct`: if `T == V`. - // - // The owner may freely unrestrict. - - return intersectionSubType == typedSuperType - } + // A intersection type `{Us}` is never a subtype of a type `V`: + return false case *CompositeType: // The supertype composite type might be a type requirement. @@ -6594,7 +6475,6 @@ func (t *TransactionType) Resolve(_ *TypeParameterTypeOrderedMap) Type { // IntersectionType type IntersectionType struct { - Type Type // an internal set of field `Types` effectiveIntersectionSet *InterfaceSet Types []*InterfaceType @@ -6606,7 +6486,11 @@ type IntersectionType struct { var _ Type = &IntersectionType{} -func NewIntersectionType(memoryGauge common.MemoryGauge, typ Type, types []*InterfaceType) *IntersectionType { +func NewIntersectionType(memoryGauge common.MemoryGauge, types []*InterfaceType) *IntersectionType { + if len(types) == 0 { + panic(errors.NewUnreachableError()) + } + common.UseMemory(memoryGauge, common.IntersectionSemaTypeMemoryUsage) // Also meter the cost for the `effectiveIntersectionSet` here, since ordered maps are not separately metered. @@ -6616,7 +6500,6 @@ func NewIntersectionType(memoryGauge common.MemoryGauge, typ Type, types []*Inte common.UseMemory(memoryGauge, entriesUsage) return &IntersectionType{ - Type: typ, Types: types, } } @@ -6646,9 +6529,8 @@ func (t *IntersectionType) Tag() TypeTag { return IntersectionTypeTag } -func formatIntersectionType(separator string, typeString string, intersectionStrings []string) string { +func formatIntersectionType(separator string, intersectionStrings []string) string { var result strings.Builder - result.WriteString(typeString) result.WriteByte('{') for i, intersectionString := range intersectionStrings { if i > 0 { @@ -6661,8 +6543,8 @@ func formatIntersectionType(separator string, typeString string, intersectionStr return result.String() } -func FormatIntersectionTypeID(typeString string, intersectionStrings []string) string { - return formatIntersectionType("", typeString, intersectionStrings) +func FormatIntersectionTypeID(intersectionStrings []string) string { + return formatIntersectionType("", intersectionStrings) } func (t *IntersectionType) string(separator string, typeFormatter func(Type) string) string { @@ -6674,7 +6556,7 @@ func (t *IntersectionType) string(separator string, typeFormatter func(Type) str intersectionStrings = append(intersectionStrings, typeFormatter(typ)) } } - return formatIntersectionType(separator, typeFormatter(t.Type), intersectionStrings) + return formatIntersectionType(separator, intersectionStrings) } func (t *IntersectionType) String() string { @@ -6703,10 +6585,6 @@ func (t *IntersectionType) Equal(other Type) bool { return false } - if !otherIntersectionType.Type.Equal(t.Type) { - return false - } - // Check that the set of types are equal; order does not matter intersectionSet := t.EffectiveIntersectionSet() @@ -6720,17 +6598,11 @@ func (t *IntersectionType) Equal(other Type) bool { } func (t *IntersectionType) IsResourceType() bool { - if t.Type == nil { - return false - } - return t.Type.IsResourceType() + // intersections are guaranteed to have all their interfaces be the same kind + return t.Types[0].IsResourceType() } func (t *IntersectionType) IsInvalidType() bool { - if t.Type != nil && t.Type.IsInvalidType() { - return true - } - for _, typ := range t.Types { if typ.IsInvalidType() { return true @@ -6741,10 +6613,6 @@ func (t *IntersectionType) IsInvalidType() bool { } func (t *IntersectionType) IsStorable(results map[*Member]bool) bool { - if t.Type != nil && !t.Type.IsStorable(results) { - return false - } - for _, typ := range t.Types { if !typ.IsStorable(results) { return false @@ -6755,10 +6623,6 @@ func (t *IntersectionType) IsStorable(results map[*Member]bool) bool { } func (t *IntersectionType) IsExportable(results map[*Member]bool) bool { - if t.Type != nil && !t.Type.IsExportable(results) { - return false - } - for _, typ := range t.Types { if !typ.IsExportable(results) { return false @@ -6769,10 +6633,6 @@ func (t *IntersectionType) IsExportable(results map[*Member]bool) bool { } func (t *IntersectionType) IsImportable(results map[*Member]bool) bool { - if t.Type != nil && !t.Type.IsImportable(results) { - return false - } - for _, typ := range t.Types { if !typ.IsImportable(results) { return false @@ -6815,11 +6675,8 @@ func (t *IntersectionType) Map(gauge common.MemoryGauge, typeParamMap map[*TypeP } } - mappedType := t.Type.Map(gauge, typeParamMap, f) - return f(NewIntersectionType( gauge, - mappedType, intersectionTypes, )) } @@ -6846,43 +6703,6 @@ func (t *IntersectionType) initializeMemberResolvers() { } } - // Also include members of the intersection type for convenience, - // to help check the rest of the program and improve the developer experience, - // *but* also report an error that this access is invalid when the entry is resolved. - // - // The intersection type may be `AnyResource`, in which case there are no members. - - for name, loopResolver := range t.Type.GetMembers() { //nolint:maprange - - if _, ok := memberResolvers[name]; ok { - continue - } - - // NOTE: don't capture loop variable - resolver := loopResolver - - memberResolvers[name] = MemberResolver{ - Kind: resolver.Kind, - Resolve: func( - memoryGauge common.MemoryGauge, - identifier string, - targetRange ast.Range, - report func(error), - ) *Member { - member := resolver.Resolve(memoryGauge, identifier, targetRange, report) - - report( - &InvalidIntersectionTypeMemberAccessError{ - Name: identifier, - Range: targetRange, - }, - ) - - return member - }, - } - } - t.memberResolvers = memberResolvers }) } @@ -6897,9 +6717,6 @@ func (t *IntersectionType) SupportedEntitlements() (set *EntitlementOrderedSet) t.EffectiveIntersectionSet().ForEach(func(it *InterfaceType) { set.SetAll(it.SupportedEntitlements()) }) - if supportingType, ok := t.Type.(EntitlementSupportingType); ok { - set.SetAll(supportingType.SupportedEntitlements()) - } t.supportedEntitlements = set return set diff --git a/runtime/sema/type_tags.go b/runtime/sema/type_tags.go index 2a1fbb5417..bef99a388e 100644 --- a/runtime/sema/type_tags.go +++ b/runtime/sema/type_tags.go @@ -927,21 +927,15 @@ func commonSuperTypeOfComposites(types []Type) Type { } } - var superType Type - if hasResources { - superType = AnyResourceType - } else { - superType = AnyStructType - } - if hasCommonInterface { return &IntersectionType{ - Type: superType, Types: commonInterfacesList, } + } else if hasResources { + return AnyResourceType + } else { + return AnyStructType } - - return superType } func unwrapOptionals(types []Type) ([]Type, int) { diff --git a/runtime/sema/type_test.go b/runtime/sema/type_test.go index 72deee16f9..2552d49fca 100644 --- a/runtime/sema/type_test.go +++ b/runtime/sema/type_test.go @@ -200,7 +200,7 @@ func TestIntersectionType_StringAndID(t *testing.T) { t.Parallel() - t.Run("base type and intersected types", func(t *testing.T) { + t.Run("intersected types", func(t *testing.T) { t.Parallel() @@ -211,26 +211,21 @@ func TestIntersectionType_StringAndID(t *testing.T) { } ty := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R", - Location: common.StringLocation("a"), - }, Types: []*InterfaceType{interfaceType}, } assert.Equal(t, - "R{I}", + "{I}", ty.String(), ) assert.Equal(t, - TypeID("S.a.R{S.b.I}"), + TypeID("{S.b.I}"), ty.ID(), ) }) - t.Run("base type and intersected types", func(t *testing.T) { + t.Run("intersected types", func(t *testing.T) { t.Parallel() @@ -247,44 +242,16 @@ func TestIntersectionType_StringAndID(t *testing.T) { } ty := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R", - Location: common.StringLocation("a"), - }, Types: []*InterfaceType{i1, i2}, } assert.Equal(t, ty.String(), - "R{I1, I2}", - ) - - assert.Equal(t, - TypeID("S.a.R{S.b.I1,S.c.I2}"), - ty.ID(), - ) - }) - - t.Run("no intersected types", func(t *testing.T) { - - t.Parallel() - - ty := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R", - Location: common.StringLocation("a"), - }, - } - - assert.Equal(t, - "R{}", - ty.String(), + "{I1, I2}", ) assert.Equal(t, - TypeID("S.a.R{}"), + TypeID("{S.b.I1,S.c.I2}"), ty.ID(), ) }) @@ -294,7 +261,7 @@ func TestIntersectionType_Equals(t *testing.T) { t.Parallel() - t.Run("same base type and more intersected types", func(t *testing.T) { + t.Run("more intersected types", func(t *testing.T) { t.Parallel() @@ -311,27 +278,17 @@ func TestIntersectionType_Equals(t *testing.T) { } a := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R", - Location: common.StringLocation("a"), - }, Types: []*InterfaceType{i1}, } b := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R", - Location: common.StringLocation("a"), - }, Types: []*InterfaceType{i1, i2}, } assert.False(t, a.Equal(b)) }) - t.Run("same base type and fewer intersected types", func(t *testing.T) { + t.Run("fewer intersected types", func(t *testing.T) { t.Parallel() @@ -348,27 +305,17 @@ func TestIntersectionType_Equals(t *testing.T) { } a := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R", - Location: common.StringLocation("a"), - }, Types: []*InterfaceType{i1, i2}, } b := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R", - Location: common.StringLocation("a"), - }, Types: []*InterfaceType{i1}, } assert.False(t, a.Equal(b)) }) - t.Run("same base type and same intersected types", func(t *testing.T) { + t.Run("same intersected types", func(t *testing.T) { t.Parallel() @@ -385,110 +332,21 @@ func TestIntersectionType_Equals(t *testing.T) { } a := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R", - Location: common.StringLocation("a"), - }, Types: []*InterfaceType{i1, i2}, } b := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R", - Location: common.StringLocation("a"), - }, Types: []*InterfaceType{i1, i2}, } assert.True(t, a.Equal(b)) }) - - t.Run("different base type and same intersected types", func(t *testing.T) { - - t.Parallel() - - i1 := &InterfaceType{ - CompositeKind: common.CompositeKindResource, - Identifier: "I1", - Location: common.StringLocation("b"), - } - - i2 := &InterfaceType{ - CompositeKind: common.CompositeKindResource, - Identifier: "I2", - Location: common.StringLocation("b"), - } - - a := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R1", - Location: common.StringLocation("a"), - }, - Types: []*InterfaceType{i1, i2}, - } - - b := &IntersectionType{ - Type: &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R2", - Location: common.StringLocation("a"), - }, - Types: []*InterfaceType{i1, i2}, - } - - assert.False(t, a.Equal(b)) - }) } func TestIntersectionType_GetMember(t *testing.T) { t.Parallel() - t.Run("forbid undeclared members", func(t *testing.T) { - - t.Parallel() - - resourceType := &CompositeType{ - Kind: common.CompositeKindResource, - Identifier: "R", - Location: common.StringLocation("a"), - Fields: []string{}, - Members: &StringMemberOrderedMap{}, - } - ty := &IntersectionType{ - Type: resourceType, - Types: []*InterfaceType{}, - } - - fieldName := "s" - resourceType.Members.Set(fieldName, NewUnmeteredPublicConstantFieldMember( - ty.Type, - fieldName, - IntType, - "", - )) - - actualMembers := ty.GetMembers() - - require.Contains(t, actualMembers, fieldName) - - var reportedError error - actualMember := actualMembers[fieldName].Resolve( - nil, - fieldName, - ast.Range{}, - func(err error) { - reportedError = err - }, - ) - - assert.IsType(t, &InvalidIntersectionTypeMemberAccessError{}, reportedError) - assert.NotNil(t, actualMember) - }) - t.Run("allow declared members", func(t *testing.T) { t.Parallel() @@ -507,7 +365,6 @@ func TestIntersectionType_GetMember(t *testing.T) { Members: &StringMemberOrderedMap{}, } intersectionType := &IntersectionType{ - Type: resourceType, Types: []*InterfaceType{ interfaceType, }, @@ -515,15 +372,8 @@ func TestIntersectionType_GetMember(t *testing.T) { fieldName := "s" - resourceType.Members.Set(fieldName, NewUnmeteredPublicConstantFieldMember( - intersectionType.Type, - fieldName, - IntType, - "", - )) - interfaceMember := NewUnmeteredPublicConstantFieldMember( - intersectionType.Type, + resourceType, fieldName, IntType, "", @@ -1076,7 +926,6 @@ func TestCommonSuperType(t *testing.T) { }, expectedSuperType: func() Type { typ := &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{interfaceType2}, } // just initialize for equality @@ -1092,7 +941,6 @@ func TestCommonSuperType(t *testing.T) { }, expectedSuperType: func() Type { typ := &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{interfaceType1, interfaceType2}, } // just initialize for equality @@ -1117,7 +965,6 @@ func TestCommonSuperType(t *testing.T) { }, expectedSuperType: func() Type { typ := &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{superInterfaceType}, } @@ -1512,14 +1359,19 @@ func TestCommonSuperType(t *testing.T) { Members: &StringMemberOrderedMap{}, } + interfaceType2 := &InterfaceType{ + Location: testLocation, + Identifier: "I2", + CompositeKind: common.CompositeKindStructure, + Members: &StringMemberOrderedMap{}, + } + intersectionType1 := &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{interfaceType1}, } intersectionType2 := &IntersectionType{ - Type: AnyResourceType, - Types: []*InterfaceType{interfaceType1}, + Types: []*InterfaceType{interfaceType2}, } tests := []testCase{ @@ -1537,7 +1389,7 @@ func TestCommonSuperType(t *testing.T) { intersectionType1, intersectionType2, }, - expectedSuperType: InvalidType, + expectedSuperType: AnyStructType, }, } @@ -1556,32 +1408,41 @@ func TestCommonSuperType(t *testing.T) { Members: &StringMemberOrderedMap{}, } - intersectionType1 := &IntersectionType{ - Type: AnyStructType, - Types: []*InterfaceType{interfaceType1}, + interfaceType2 := &InterfaceType{ + Location: testLocation, + Identifier: "I1", + CompositeKind: common.CompositeKindStructure, + Members: &StringMemberOrderedMap{}, } - intersectionType2 := &IntersectionType{ - Type: AnyResourceType, - Types: []*InterfaceType{interfaceType1}, + capType1 := &CapabilityType{ + BorrowType: &IntersectionType{ + Types: []*InterfaceType{interfaceType1}, + }, + } + + capType2 := &CapabilityType{ + BorrowType: &IntersectionType{ + Types: []*InterfaceType{interfaceType2}, + }, } tests := []testCase{ { name: "homogenous", types: []Type{ - intersectionType1, - intersectionType1, + capType1, + capType1, }, - expectedSuperType: intersectionType1, + expectedSuperType: capType1, }, { name: "heterogeneous", types: []Type{ - intersectionType1, - intersectionType2, + capType1, + capType2, }, - expectedSuperType: InvalidType, + expectedSuperType: AnyStructType, }, } @@ -1691,7 +1552,6 @@ func TestCommonSuperType(t *testing.T) { BorrowType: AnyStructType, }, &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{ { Location: common.StringLocation("test"), @@ -2019,7 +1879,7 @@ func TestMapType(t *testing.T) { for _, i := range typ.Types { interfaces = append(interfaces, &InterfaceType{Identifier: i.Identifier + "f"}) } - return NewIntersectionType(nil, typ.Type, interfaces) + return NewIntersectionType(nil, interfaces) } return ty } @@ -2078,7 +1938,6 @@ func TestMapType(t *testing.T) { original := NewIntersectionType( nil, - StringType, []*InterfaceType{ {Identifier: "foo"}, {Identifier: "bar"}, @@ -2086,7 +1945,6 @@ func TestMapType(t *testing.T) { ) mapped := NewIntersectionType( nil, - BoolType, []*InterfaceType{ {Identifier: "foof"}, {Identifier: "barf"}, diff --git a/runtime/stdlib/contracts/test.cdc b/runtime/stdlib/contracts/test.cdc index 25392726b3..a01bf742bf 100644 --- a/runtime/stdlib/contracts/test.cdc +++ b/runtime/stdlib/contracts/test.cdc @@ -6,9 +6,9 @@ access(all) contract Test { /// access(all) struct Blockchain { - access(all) let backend: AnyStruct{BlockchainBackend} + access(all) let backend: {BlockchainBackend} - init(backend: AnyStruct{BlockchainBackend}) { + init(backend: {BlockchainBackend}) { self.backend = backend } diff --git a/runtime/stdlib/type-comparator.go b/runtime/stdlib/type-comparator.go index e117cef31f..642e118f36 100644 --- a/runtime/stdlib/type-comparator.go +++ b/runtime/stdlib/type-comparator.go @@ -20,7 +20,6 @@ package stdlib import ( "github.com/onflow/cadence/runtime/ast" - "github.com/onflow/cadence/runtime/sema" ) var _ ast.TypeEqualityChecker = &TypeComparator{} @@ -98,24 +97,6 @@ func (c *TypeComparator) CheckIntersectionTypeEquality(expected *ast.Intersectio return newTypeMismatchError(expected, found) } - if expected.Type == nil { - if !isAnyStructOrAnyResourceType(foundIntersectionType.Type) { - return newTypeMismatchError(expected, found) - } - // else go on to check intersected types - } else if foundIntersectionType.Type == nil { - if !isAnyStructOrAnyResourceType(expected.Type) { - return newTypeMismatchError(expected, found) - } - // else go on to check intersected types - } else { - // both are not nil - err := expected.Type.CheckEqual(foundIntersectionType.Type, c) - if err != nil { - return newTypeMismatchError(expected, found) - } - } - if len(expected.Types) != len(foundIntersectionType.Types) { return newTypeMismatchError(expected, found) } @@ -240,25 +221,6 @@ func identifiersEqual(expected []ast.Identifier, found []ast.Identifier) bool { return true } -func isAnyStructOrAnyResourceType(astType ast.Type) bool { - // If the intersection type is not stated, then it is either AnyStruct or AnyResource - if astType == nil { - return true - } - - nominalType, ok := astType.(*ast.NominalType) - if !ok { - return false - } - - switch nominalType.Identifier.Identifier { - case sema.AnyStructType.Name, sema.AnyResourceType.Name: - return true - default: - return false - } -} - func newTypeMismatchError(expectedType ast.Type, foundType ast.Type) *TypeMismatchError { return &TypeMismatchError{ ExpectedType: expectedType, diff --git a/runtime/storage_test.go b/runtime/storage_test.go index 95944c64a4..098393515e 100644 --- a/runtime/storage_test.go +++ b/runtime/storage_test.go @@ -466,7 +466,7 @@ func TestRuntimePublicCapabilityBorrowTypeConfusion(t *testing.T) { // Create a public capability to the stored Vault that only exposes // the balance field through the Balance interface - self.account.link<&DapperUtilityCoin.Vault{FungibleToken.Balance}>( + self.account.link<&DapperUtilityCoin.Vault>( /public/dapperUtilityCoinBalance, target: /storage/dapperUtilityCoinVault ) @@ -1538,12 +1538,12 @@ func TestRuntimeStorageReferenceCast(t *testing.T) { prepare(signer: AuthAccount) { signer.save(<-Test.createR(), to: /storage/r) - signer.link<&Test.R{Test.RI}>( + signer.link<&Test.R>( /public/r, target: /storage/r ) - let ref = signer.getCapability<&Test.R{Test.RI}>(/public/r).borrow()! + let ref = signer.getCapability<&Test.R>(/public/r).borrow()! let casted = (ref as AnyStruct) as! &Test.R } @@ -1637,12 +1637,12 @@ func TestRuntimeStorageReferenceDowncast(t *testing.T) { prepare(signer: AuthAccount) { signer.save(<-Test.createR(), to: /storage/r) - signer.link<&Test.R{Test.RI}>( + signer.link<&Test.R>( /public/r, target: /storage/r ) - let ref = signer.getCapability<&Test.R{Test.RI}>(/public/r).borrow()! + let ref = signer.getCapability<&Test.R>(/public/r).borrow()! let casted = (ref as AnyStruct) as! auth(Test.E) &Test.R } @@ -2245,7 +2245,7 @@ access(all) contract Test { return <- create Holder() } - access(all) fun attach(asRole: Role, receiver: &AnyResource{Receiver}) { + access(all) fun attach(asRole: Role, receiver: &{Receiver}) { // TODO: Now verify that the owner is valid. let capability = self.capabilities[asRole]! @@ -2271,7 +2271,7 @@ transaction { prepare(acct: AuthAccount) {} execute { let holder <- Test.createHolder() - Test.attach(asRole: Test.Role.aaa, receiver: &holder as &AnyResource{Test.Receiver}) + Test.attach(asRole: Test.Role.aaa, receiver: &holder as &{Test.Receiver}) destroy holder } } diff --git a/runtime/tests/checker/access_test.go b/runtime/tests/checker/access_test.go index ab4ed38ef8..1891eb6909 100644 --- a/runtime/tests/checker/access_test.go +++ b/runtime/tests/checker/access_test.go @@ -1482,7 +1482,7 @@ func TestCheckAccessInterfaceFieldVariableDeclarationWithSecondValue(t *testing. } access(all) fun test() { - let b: @AnyResource{B} <- create BImpl() + let b: @{B} <- create BImpl() let oldA <- b.a <- create A() destroy oldA destroy b @@ -1996,7 +1996,7 @@ func TestCheckAccessSameContractInnerStructInterfaceField(t *testing.T) { } fun useB() { - let b: AnyStruct{B} = A.BImpl() + let b: {B} = A.BImpl() b.field } } @@ -2104,7 +2104,7 @@ func TestCheckAccessOtherContractInnerStructInterfaceField(t *testing.T) { contract C { fun useB() { - let b: AnyStruct{A.B} = A.BImpl() + let b: {A.B} = A.BImpl() b.field } } diff --git a/runtime/tests/checker/attachments_test.go b/runtime/tests/checker/attachments_test.go index f3aa00024a..c50a66eb5a 100644 --- a/runtime/tests/checker/attachments_test.go +++ b/runtime/tests/checker/attachments_test.go @@ -1442,7 +1442,7 @@ func TestCheckBaseTyping(t *testing.T) { struct interface I {} attachment Test for I { fun foo() { - let x = base as! &R{I} + let x = base as! &{I} } }`, ) @@ -1460,7 +1460,7 @@ func TestCheckBaseTyping(t *testing.T) { resource interface I {} attachment Test for I { fun foo() { - let x = base as! &R{I} + let x = base as! &{I} } }`, ) @@ -2399,7 +2399,7 @@ func TestCheckAttach(t *testing.T) { struct S: I {} attachment A for AnyStruct {} access(all) fun foo() { - let s: S{I} = S() + let s: {I} = S() attach A() to s } `, @@ -2413,25 +2413,6 @@ func TestCheckAttachToIntersectionType(t *testing.T) { t.Parallel() - t.Run("struct intersection", func(t *testing.T) { - - t.Parallel() - - _, err := ParseAndCheck(t, - ` - struct interface I {} - struct S: I {} - attachment A for AnyStruct {} - access(all) fun foo() { - let s: S{I} = S() - attach A() to s - } - `, - ) - - require.NoError(t, err) - }) - t.Run("any struct intersection", func(t *testing.T) { t.Parallel() @@ -2455,25 +2436,6 @@ func TestCheckAttachToIntersectionType(t *testing.T) { t.Parallel() - _, err := ParseAndCheck(t, - ` - resource interface I {} - resource R: I {} - attachment A for AnyResource {} - access(all) fun foo() { - let r: @R{I} <- create R() - destroy attach A() to <-r - } - `, - ) - - require.NoError(t, err) - }) - - t.Run("anyresource intersection", func(t *testing.T) { - - t.Parallel() - _, err := ParseAndCheck(t, ` resource interface I {} @@ -2489,48 +2451,7 @@ func TestCheckAttachToIntersectionType(t *testing.T) { require.NoError(t, err) }) - t.Run("attach struct interface to struct interface", func(t *testing.T) { - - t.Parallel() - - _, err := ParseAndCheck(t, - ` - struct interface I {} - struct S: I {} - attachment A for I {} - access(all) fun foo() { - let s: S{I} = S() - attach A() to s - } - `, - ) - - require.NoError(t, err) - }) - - t.Run("attach struct interface to struct", func(t *testing.T) { - - t.Parallel() - - _, err := ParseAndCheck(t, - ` - struct interface I {} - struct S: I {} - attachment A for S {} - access(all) fun foo() { - let s: S{I} = S() - attach A() to s - } - `, - ) - - // there is no reason to error here; the owner of this - // intersection type is always able to unrestrict - - require.NoError(t, err) - }) - - t.Run("attach anystruct interface to struct", func(t *testing.T) { + t.Run("attach interface to struct", func(t *testing.T) { t.Parallel() @@ -2561,38 +2482,16 @@ func TestCheckAttachToIntersectionType(t *testing.T) { resource R: I {} attachment A for I {} access(all) fun foo() { - let r: @R{I} <- create R() - destroy attach A() to <-r - } - `, - ) - - require.NoError(t, err) - }) - - t.Run("attach resource interface to resource", func(t *testing.T) { - - t.Parallel() - - _, err := ParseAndCheck(t, - ` - resource interface I {} - resource R: I {} - attachment A for R {} - access(all) fun foo() { - let r: @R{I} <- create R() + let r: @{I} <- create R() destroy attach A() to <-r } `, ) - // owner can unrestrict `r` as they wish, so there is no reason to - // limit attach here - require.NoError(t, err) }) - t.Run("attach anyresource interface to resource", func(t *testing.T) { + t.Run("attach interface to resource", func(t *testing.T) { t.Parallel() @@ -3447,13 +3346,14 @@ func TestCheckRemoveFromIntersection(t *testing.T) { struct S: I {} struct interface I {} attachment A for S {} - access(all) fun foo(s: S{I}) { + access(all) fun foo(s: {I}) { remove A from s } `, ) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + assert.IsType(t, &sema.InvalidAttachmentRemoveError{}, errs[0]) }) t.Run("basic struct interface", func(t *testing.T) { @@ -3465,7 +3365,7 @@ func TestCheckRemoveFromIntersection(t *testing.T) { struct S: I {} struct interface I {} attachment A for I {} - access(all) fun foo(s: S{I}) { + access(all) fun foo(s: {I}) { remove A from s } `, @@ -3483,16 +3383,15 @@ func TestCheckRemoveFromIntersection(t *testing.T) { resource S: I {} resource interface I {} attachment A for S {} - access(all) fun foo(s: @S{I}) { + access(all) fun foo(s: @{I}) { remove A from s destroy s } `, ) - // owner can always unrestrict `s`, so no need to prevent removal of A - - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + assert.IsType(t, &sema.InvalidAttachmentRemoveError{}, errs[0]) }) t.Run("basic resource interface", func(t *testing.T) { @@ -3504,7 +3403,7 @@ func TestCheckRemoveFromIntersection(t *testing.T) { resource S: I {} resource interface I {} attachment A for I {} - access(all) fun foo(s: @S{I}) { + access(all) fun foo(s: @{I}) { remove A from s destroy s } @@ -3592,25 +3491,6 @@ func TestCheckRemoveFromIntersection(t *testing.T) { t.Parallel() - _, err := ParseAndCheck(t, - ` - struct S: I, J {} - struct interface I {} - struct interface J {} - attachment A for I {} - access(all) fun foo(s: S{I, J}) { - remove A from s - } - `, - ) - - require.NoError(t, err) - }) - - t.Run("anystruct multiple intersection", func(t *testing.T) { - - t.Parallel() - _, err := ParseAndCheck(t, ` struct interface I {} @@ -3962,7 +3842,7 @@ func TestCheckAccessAttachmentIntersection(t *testing.T) { struct R: I {} struct interface I {} attachment A for I {} - access(all) fun foo(r: R{I}) { + access(all) fun foo(r: {I}) { r[A] } `, @@ -3987,22 +3867,6 @@ func TestCheckAccessAttachmentIntersection(t *testing.T) { assert.IsType(t, &sema.InvalidTypeIndexingError{}, errs[0]) }) - t.Run("intersection concrete base reference", func(t *testing.T) { - t.Parallel() - - _, err := ParseAndCheck(t, - ` - struct R: I {} - struct interface I {} - attachment A for R {} - access(all) fun foo(r: &R{I}) { - r[A] - } - `, - ) - require.NoError(t, err) - }) - t.Run("intersection concrete base reference to interface", func(t *testing.T) { t.Parallel() @@ -4077,7 +3941,7 @@ func TestCheckAccessAttachmentIntersection(t *testing.T) { struct interface I {} struct interface J {} attachment A for I {} - access(all) fun foo(r: R{J}) { + access(all) fun foo(r: {J}) { r[A] } `, @@ -4096,7 +3960,7 @@ func TestCheckAccessAttachmentIntersection(t *testing.T) { struct interface I {} struct interface J {} attachment A for I {} - access(all) fun foo(r: &R{J}) { + access(all) fun foo(r: &{J}) { r[A] } `, diff --git a/runtime/tests/checker/casting_test.go b/runtime/tests/checker/casting_test.go index 4c8ab4e1d3..7f904ac873 100644 --- a/runtime/tests/checker/casting_test.go +++ b/runtime/tests/checker/casting_test.go @@ -148,8 +148,8 @@ func TestCheckCastResourceType(t *testing.T) { checker, err := ParseAndCheck(t, types+` - let r: @R{I1, I2} <- create R() - let r2 <- r as @R{I2} + let r: @{I1, I2} <- create R() + let r2 <- r as @{I2} `, ) @@ -167,9 +167,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @R{I2}? { - let r: @R{I1, I2} <- create R() - if let r2 <- r as? @R{I2} { + fun test(): @{I2}? { + let r: @{I1, I2} <- create R() + if let r2 <- r as? @{I2} { return <-r2 } else { destroy r @@ -195,30 +195,25 @@ func TestCheckCastResourceType(t *testing.T) { t.Run("static", func(t *testing.T) { - checker, err := ParseAndCheck(t, + _, err := ParseAndCheck(t, types+` - let r: @R{I1} <- create R() - let r2 <- r as @R{I1, I2} + let r: @{I1} <- create R() + let r2 <- r as @{I1, I2} `, ) - require.NoError(t, err) - - r2Type := RequireGlobalValue(t, checker.Elaboration, "r2") + errs := RequireCheckerErrors(t, err, 1) - require.IsType(t, - &sema.IntersectionType{}, - r2Type, - ) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @R{I1, I2}? { - let r: @R{I1} <- create R() - if let r2 <- r as? @R{I1, I2} { + fun test(): @{I1, I2}? { + let r: @{I1} <- create R() + if let r2 <- r as? @{I1, I2} { return <-r2 } else { destroy r @@ -246,23 +241,21 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @R1{I} <- create R1() - let r2 <- r as @R2{I} + let r: @{I} <- create R1() + let r2 <- r as @{I} `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @R2{I}? { - let r: @R1{I} <- create R1() - if let r2 <- r as? @R2{I} { + fun test(): @{I}? { + let r: @{I} <- create R1() + if let r2 <- r as? @{I} { return <-r2 } else { destroy r @@ -272,9 +265,7 @@ func TestCheckCastResourceType(t *testing.T) { `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) @@ -291,7 +282,7 @@ func TestCheckCastResourceType(t *testing.T) { checker, err := ParseAndCheck(t, types+` let r: @R <- create R() - let r2 <- r as @R{I} + let r2 <- r as @{I} `, ) @@ -309,9 +300,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @R{I}? { + fun test(): @{I}? { let r: @R <- create R() - if let r2 <- r as? @R{I} { + if let r2 <- r as? @{I} { return <-r2 } else { destroy r @@ -340,22 +331,20 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` let r: @R1 <- create R1() - let r2 <- r as @R2{I} + let r2 <- r as @{I} `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @R2{I}? { + fun test(): @{I}? { let r: @R1 <- create R1() - if let r2 <- r as? @R2{I} { + if let r2 <- r as? @{I} { return <-r2 } else { destroy r @@ -364,10 +353,7 @@ func TestCheckCastResourceType(t *testing.T) { } `, ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) @@ -384,7 +370,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` let r: @AnyResource <- create R() - let r2 <- r as @R{RI} + let r2 <- r as @{RI} `, ) @@ -399,9 +385,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @R{RI}? { + fun test(): @{RI}? { let r: @AnyResource <- create R() - if let r2 <- r as? @R{RI} { + if let r2 <- r as? @{RI} { return <-r2 } else { destroy r @@ -415,7 +401,7 @@ func TestCheckCastResourceType(t *testing.T) { }) }) - t.Run("intersection AnyResource -> conforming intersection type", func(t *testing.T) { + t.Run("intersection -> conforming intersection type", func(t *testing.T) { const types = ` resource interface RI {} @@ -427,25 +413,21 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @AnyResource{RI} <- create R() - let r2 <- r as @R{RI} + let r: @{RI} <- create R() + let r2 <- r as @{RI} `, ) - // NOTE: static cast not allowed, only dynamic - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @R{RI}? { - let r: @AnyResource{RI} <- create R() - if let r2 <- r as? @R{RI} { + fun test(): @{RI}? { + let r: @{RI} <- create R() + if let r2 <- r as? @{RI} { return <-r2 } else { destroy r @@ -459,7 +441,7 @@ func TestCheckCastResourceType(t *testing.T) { }) }) - t.Run("intersection AnyResource -> non-conforming intersection type", func(t *testing.T) { + t.Run("intersection -> non-conforming intersection type", func(t *testing.T) { const types = ` resource interface RI {} @@ -471,25 +453,23 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @AnyResource{RI} <- create R() - let r2 <- r as @R{RI} + let r: @{RI} <- create R() + let r2 <- r as @{RI} `, ) - errs := RequireCheckerErrors(t, err, 3) + errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[2]) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @R{RI}? { - let r: @AnyResource{RI} <- create R() - if let r2 <- r as? @R{RI} { + fun test(): @{RI}? { + let r: @{RI} <- create R() + if let r2 <- r as? @{RI} { return <-r2 } else { destroy r @@ -499,11 +479,9 @@ func TestCheckCastResourceType(t *testing.T) { `, ) - errs := RequireCheckerErrors(t, err, 3) + errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[0]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[2]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) }) @@ -520,21 +498,16 @@ func TestCheckCastResourceType(t *testing.T) { t.Run("static", func(t *testing.T) { - checker, err := ParseAndCheck(t, + _, err := ParseAndCheck(t, types+` - let r: @R{I} <- create R() + let r: @{I} <- create R() let r2 <- r as @R `, ) - require.NoError(t, err) - - r2Type := RequireGlobalValue(t, checker.Elaboration, "r2") + errs := RequireCheckerErrors(t, err, 1) - require.IsType(t, - &sema.CompositeType{}, - r2Type, - ) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) t.Run("dynamic", func(t *testing.T) { @@ -542,7 +515,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @R? { - let r: @R{I} <- create R() + let r: @{I} <- create R() if let r2 <- r as? @R { return <-r2 } else { @@ -571,7 +544,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @R{I} <- create R() + let r: @{I} <- create R() let t <- r as @T `, ) @@ -586,7 +559,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @T? { - let r: @R{I} <- create R() + let r: @{I} <- create R() if let t <- r as? @T { return <-t } else { @@ -597,9 +570,7 @@ func TestCheckCastResourceType(t *testing.T) { `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) @@ -615,7 +586,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @AnyResource{RI} <- create R() + let r: @{RI} <- create R() let r2 <- r as @R `, ) @@ -632,7 +603,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @R? { - let r: @AnyResource{RI} <- create R() + let r: @{RI} <- create R() if let r2 <- r as? @R { return <-r2 } else { @@ -659,7 +630,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @AnyResource{RI} <- create R() + let r: @{RI} <- create R() let r2 <- r as @R `, ) @@ -675,7 +646,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @R? { - let r: @AnyResource{RI} <- create R() + let r: @{RI} <- create R() if let r2 <- r as? @R { return <-r2 } else { @@ -750,7 +721,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` let r: @R <- create R() - let r2 <- r as @AnyResource{RI} + let r2 <- r as @{RI} `, ) @@ -763,9 +734,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{RI}? { + fun test(): @{RI}? { let r: @R <- create R() - if let r2 <- r as? @AnyResource{RI} { + if let r2 <- r as? @{RI} { return <-r2 } else { destroy r @@ -795,7 +766,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` let r: @R <- create R() - let r2 <- r as @AnyResource{RI} + let r2 <- r as @{RI} `, ) @@ -806,9 +777,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{RI}? { + fun test(): @{RI}? { let r: @R <- create R() - if let r2 <- r as? @AnyResource{RI} { + if let r2 <- r as? @{RI} { return <-r2 } else { destroy r @@ -832,39 +803,23 @@ func TestCheckCastResourceType(t *testing.T) { t.Run("static", func(t *testing.T) { - checker, err := ParseAndCheck(t, + _, err := ParseAndCheck(t, types+` - let r: @R{I} <- create R() - let r2 <- r as @AnyResource{I} + let r: @{I} <- create R() + let r2 <- r as @{I} `, ) require.NoError(t, err) - - iType := RequireGlobalType(t, checker.Elaboration, "I") - - require.IsType(t, &sema.InterfaceType{}, iType) - - r2Type := RequireGlobalValue(t, checker.Elaboration, "r2") - - require.IsType(t, - &sema.IntersectionType{ - Type: sema.AnyResourceType, - Types: []*sema.InterfaceType{ - iType.(*sema.InterfaceType), - }, - }, - r2Type, - ) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{I}? { - let r: @R{I} <- create R() - if let r2 <- r as? @AnyResource{I} { + fun test(): @{I}? { + let r: @{I} <- create R() + if let r2 <- r as? @{I} { return <-r2 } else { destroy r @@ -878,7 +833,7 @@ func TestCheckCastResourceType(t *testing.T) { }) }) - t.Run("intersection type -> intersection AnyResource with conformance not in type", func(t *testing.T) { + t.Run("intersection type -> intersection with conformance not in type", func(t *testing.T) { const types = ` resource interface I1 {} @@ -890,39 +845,25 @@ func TestCheckCastResourceType(t *testing.T) { t.Run("static", func(t *testing.T) { - checker, err := ParseAndCheck(t, + _, err := ParseAndCheck(t, types+` - let r: @R{I1} <- create R() - let r2 <- r as @AnyResource{I2} + let r: @{I1} <- create R() + let r2 <- r as @{I2} `, ) - require.NoError(t, err) - - i2Type := RequireGlobalType(t, checker.Elaboration, "I2") - - require.IsType(t, &sema.InterfaceType{}, i2Type) - - r2Type := RequireGlobalValue(t, checker.Elaboration, "r2") + errs := RequireCheckerErrors(t, err, 1) - require.IsType(t, - &sema.IntersectionType{ - Type: sema.AnyResourceType, - Types: []*sema.InterfaceType{ - i2Type.(*sema.InterfaceType), - }, - }, - r2Type, - ) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{I2}? { - let r: @R{I1} <- create R() - if let r2 <- r as? @AnyResource{I2} { + fun test(): @{I2}? { + let r: @{I1} <- create R() + if let r2 <- r as? @{I2} { return <-r2 } else { destroy r @@ -950,8 +891,8 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @R{I1} <- create R() - let r2 <- r as @AnyResource{I2} + let r: @{I1} <- create R() + let r2 <- r as @{I2} `, ) @@ -964,9 +905,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{I2}? { - let r: @R{I1} <- create R() - if let r2 <- r as? @AnyResource{I2} { + fun test(): @{I2}? { + let r: @{I1} <- create R() + if let r2 <- r as? @{I2} { return <-r2 } else { destroy r @@ -976,9 +917,7 @@ func TestCheckCastResourceType(t *testing.T) { `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) @@ -996,8 +935,8 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @AnyResource{I1, I2} <- create R() - let r2 <- r as @AnyResource{I2} + let r: @{I1, I2} <- create R() + let r2 <- r as @{I2} `, ) @@ -1008,9 +947,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{I2}? { - let r: @AnyResource{I1, I2} <- create R() - if let r2 <- r as? @AnyResource{I2} { + fun test(): @{I2}? { + let r: @{I1, I2} <- create R() + if let r2 <- r as? @{I2} { return <-r2 } else { destroy r @@ -1038,8 +977,8 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @AnyResource{I1} <- create R() - let r2 <- r as @AnyResource{I1, I2} + let r: @{I1} <- create R() + let r2 <- r as @{I1, I2} `, ) @@ -1052,9 +991,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{I1, I2}? { - let r: @AnyResource{I1} <- create R() - if let r2 <- r as? @AnyResource{I1, I2} { + fun test(): @{I1, I2}? { + let r: @{I1} <- create R() + if let r2 <- r as? @{I1, I2} { return <-r2 } else { destroy r @@ -1082,8 +1021,8 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @AnyResource{I1} <- create R() - let r2 <- r as @AnyResource{I1, I2} + let r: @{I1} <- create R() + let r2 <- r as @{I1, I2} `, ) @@ -1096,9 +1035,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{I1, I2}? { - let r: @AnyResource{I1} <- create R() - if let r2 <- r as? @AnyResource{I1, I2} { + fun test(): @{I1, I2}? { + let r: @{I1} <- create R() + if let r2 <- r as? @{I1, I2} { return <-r2 } else { destroy r @@ -1125,7 +1064,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` let r: @AnyResource <- create R() - let r2 <- r as @AnyResource{I} + let r2 <- r as @{I} `, ) @@ -1138,9 +1077,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{I}? { + fun test(): @{I}? { let r: @AnyResource <- create R() - if let r2 <- r as? @AnyResource{I} { + if let r2 <- r as? @{I} { return <-r2 } else { destroy r @@ -1170,7 +1109,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @R{I1} <- create R() + let r: @{I1} <- create R() let r2 <- r as @AnyResource `, ) @@ -1183,7 +1122,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @AnyResource? { - let r: @R{I1} <- create R() + let r: @{I1} <- create R() if let r2 <- r as? @AnyResource { return <-r2 } else { @@ -1212,7 +1151,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let r: @AnyResource{I1} <- create R() + let r: @{I1} <- create R() let r2 <- r as @AnyResource `, ) @@ -1225,7 +1164,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @AnyResource? { - let r: @AnyResource{I1} <- create R() + let r: @{I1} <- create R() if let r2 <- r as? @AnyResource { return <-r2 } else { @@ -1298,8 +1237,8 @@ func TestCheckCastStructType(t *testing.T) { checker, err := ParseAndCheck(t, types+` - let s: S{I1, I2} = S() - let s2 = s as S{I2} + let s: {I1, I2} = S() + let s2 = s as {I2} `, ) @@ -1317,8 +1256,8 @@ func TestCheckCastStructType(t *testing.T) { checker, err := ParseAndCheck(t, types+` - let s: S{I1, I2} = S() - let s2 = s as? S{I2} + let s: {I1, I2} = S() + let s2 = s as? {I2} `, ) @@ -1345,54 +1284,12 @@ func TestCheckCastStructType(t *testing.T) { struct S: I1, I2 {} ` - t.Run("static", func(t *testing.T) { - - checker, err := ParseAndCheck(t, - types+` - let s: S{I1} = S() - let s2 = s as S{I1, I2} - `, - ) - - require.NoError(t, err) - - s2Type := RequireGlobalValue(t, checker.Elaboration, "s2") - - require.IsType(t, - &sema.IntersectionType{}, - s2Type, - ) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: S{I1} = S() - let s2 = s as? S{I1, I2} - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run("intersection type -> intersection type: different struct", func(t *testing.T) { - - const types = ` - struct interface I {} - - struct S1: I {} - - struct S2: I {} - ` - t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: S1{I} = S1() - let s2 = s as S2{I} + let s: {I1} = S() + let s2 = s as {I1, I2} `, ) @@ -1405,18 +1302,16 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: S1{I} = S1() - let s2 = s as? S2{I} + let s: {I1} = S() + let s2 = s as? {I1, I2} `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) - t.Run("type -> intersection type: same struct", func(t *testing.T) { + t.Run("type -> intersection type", func(t *testing.T) { const types = ` struct interface I {} @@ -1429,7 +1324,7 @@ func TestCheckCastStructType(t *testing.T) { checker, err := ParseAndCheck(t, types+` let s: S = S() - let s2 = s as S{I} + let s2 = s as {I} `, ) @@ -1448,7 +1343,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: S = S() - let s2 = s as? S{I} + let s2 = s as? {I} `, ) @@ -1456,25 +1351,25 @@ func TestCheckCastStructType(t *testing.T) { }) }) - t.Run("type -> intersection type: different struct", func(t *testing.T) { + t.Run("AnyStruct -> conforming intersection type", func(t *testing.T) { const types = ` - struct interface I {} - - struct S1: I {} + struct interface SI {} - struct S2: I {} + struct S: SI {} ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: S1 = S1() - let s2 = s as S2{I} + let s: AnyStruct = S() + let s2 = s as {SI} `, ) + // NOTE: static cast not allowed, only dynamic + errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) @@ -1484,18 +1379,16 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: S1 = S1() - let s2 = s as? S2{I} + let s: AnyStruct = S() + let s2 = s as? {SI} `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) - t.Run("AnyStruct -> conforming intersection type", func(t *testing.T) { + t.Run("intersection -> conforming intersection type", func(t *testing.T) { const types = ` struct interface SI {} @@ -1507,24 +1400,20 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct = S() - let s2 = s as S{SI} + let s: {SI} = S() + let s2 = s as {SI} `, ) - // NOTE: static cast not allowed, only dynamic - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct = S() - let s2 = s as? S{SI} + let s: {SI} = S() + let s2 = s as? {SI} `, ) @@ -1532,20 +1421,22 @@ func TestCheckCastStructType(t *testing.T) { }) }) - t.Run("intersection AnyStruct -> conforming intersection type", func(t *testing.T) { + // Supertype: Struct + + t.Run("intersection -> conforming struct", func(t *testing.T) { const types = ` - struct interface SI {} + struct interface SI {} - struct S: SI {} + struct S: SI {} ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() - let s2 = s as S{SI} + let s: {SI} = S() + let s2 = s as S `, ) @@ -1560,8 +1451,8 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() - let s2 = s as? S{SI} + let s: {SI} = S() + let s2 = s as? S `, ) @@ -1569,80 +1460,71 @@ func TestCheckCastStructType(t *testing.T) { }) }) - t.Run("intersection AnyStruct -> non-conforming intersection type", func(t *testing.T) { + t.Run("intersection AnyStruct -> non-conforming struct", func(t *testing.T) { const types = ` - struct interface SI {} + struct interface SI {} - struct S {} + struct S {} ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() - let s2 = s as S{SI} + let s: {SI} = S() + let s2 = s as S `, ) - errs := RequireCheckerErrors(t, err, 3) + errs := RequireCheckerErrors(t, err, 2) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[2]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() - let s2 = s as? S{SI} + let s: {SI} = S() + let s2 = s as? S `, ) - errs := RequireCheckerErrors(t, err, 2) + errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) }) }) - // Supertype: Struct - - t.Run("intersection type -> type: same struct", func(t *testing.T) { + t.Run("AnyStruct -> type", func(t *testing.T) { const types = ` - struct interface I {} + struct interface SI {} - struct S: I {} + struct S: SI {} ` t.Run("static", func(t *testing.T) { - checker, err := ParseAndCheck(t, + _, err := ParseAndCheck(t, types+` - let s: S{I} = S() + let s: AnyStruct = S() let s2 = s as S `, ) - require.NoError(t, err) - - s2Type := RequireGlobalValue(t, checker.Elaboration, "s2") + errs := RequireCheckerErrors(t, err, 1) - require.IsType(t, - &sema.CompositeType{}, - s2Type, - ) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: S{I} = S() + let s: AnyStruct = S() let s2 = s as? S `, ) @@ -1651,22 +1533,23 @@ func TestCheckCastStructType(t *testing.T) { }) }) - t.Run("intersection type -> type: different struct", func(t *testing.T) { + // Supertype: intersection AnyStruct - const types = ` - struct interface I {} + t.Run("struct -> intersection AnyStruct with non-conformance type", func(t *testing.T) { - struct S: I {} + const types = ` + struct interface SI {} - struct T: I {} + // NOTE: S does not conform to SI + struct S {} ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: T{I} = S() - let t = s as T + let s: S = S() + let s2 = s as {SI} `, ) @@ -1679,8 +1562,8 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: T{I} = S() - let t = s as? T + let s: S = S() + let s2 = s as? {SI} `, ) @@ -1688,38 +1571,35 @@ func TestCheckCastStructType(t *testing.T) { assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) + }) - t.Run("intersection AnyStruct -> conforming struct", func(t *testing.T) { + t.Run("struct -> intersection AnyStruct with conformance type", func(t *testing.T) { const types = ` - struct interface SI {} + struct interface SI {} - struct S: SI {} + struct S: SI {} ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() - let s2 = s as S + let s: S = S() + let s2 = s as {SI} `, ) - // NOTE: static cast not allowed, only dynamic - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() - let s2 = s as? S + let s: S = S() + let s2 = s as? {SI} `, ) @@ -1727,72 +1607,71 @@ func TestCheckCastStructType(t *testing.T) { }) }) - t.Run("intersection AnyStruct -> non-conforming struct", func(t *testing.T) { + t.Run("intersection type -> intersection with non-conformance type", func(t *testing.T) { const types = ` - struct interface SI {} + struct interface I1 {} - struct S {} + struct interface I2 {} + + struct S: I1 {} ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() - let s2 = s as S + let s: {I1} = S() + let s2 = s as {I2} `, ) - errs := RequireCheckerErrors(t, err, 2) + errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() - let s2 = s as? S + let s: {I1} = S() + let s2 = s as? {I2} `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) - t.Run("AnyStruct -> type", func(t *testing.T) { + t.Run("intersection -> intersection: fewer types", func(t *testing.T) { const types = ` - struct interface SI {} + struct interface I1 {} - struct S: SI {} + struct interface I2 {} + + struct S: I1, I2 {} ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct = S() - let s2 = s as S + let s: {I1, I2} = S() + let s2 = s as {I2} `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct = S() - let s2 = s as? S + let s: {I1, I2} = S() + let s2 = s as? {I2} `, ) @@ -1800,255 +1679,7 @@ func TestCheckCastStructType(t *testing.T) { }) }) - // Supertype: intersection AnyStruct - - t.Run("struct -> intersection AnyStruct with non-conformance type", func(t *testing.T) { - - const types = ` - struct interface SI {} - - // NOTE: S does not conform to SI - struct S {} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: S = S() - let s2 = s as AnyStruct{SI} - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: S = S() - let s2 = s as? AnyStruct{SI} - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - }) - - t.Run("struct -> intersection AnyStruct with conformance type", func(t *testing.T) { - - const types = ` - struct interface SI {} - - struct S: SI {} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: S = S() - let s2 = s as AnyStruct{SI} - `, - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: S = S() - let s2 = s as? AnyStruct{SI} - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run("intersection type -> intersection AnyStruct with conformance in type", func(t *testing.T) { - - const types = ` - struct interface I {} - - struct S: I {} - ` - - t.Run("static", func(t *testing.T) { - - checker, err := ParseAndCheck(t, - types+` - let s: S{I} = S() - let s2 = s as AnyStruct{I} - `, - ) - - require.NoError(t, err) - - iType := RequireGlobalType(t, checker.Elaboration, "I") - - require.IsType(t, &sema.InterfaceType{}, iType) - - s2Type := RequireGlobalValue(t, checker.Elaboration, "s2") - - require.IsType(t, - &sema.IntersectionType{ - Type: sema.AnyStructType, - Types: []*sema.InterfaceType{ - iType.(*sema.InterfaceType), - }, - }, - s2Type, - ) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: S{I} = S() - let s2 = s as? AnyStruct{I} - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run("intersection type -> intersection AnyStruct with conformance not in type", func(t *testing.T) { - - const types = ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - ` - - t.Run("static", func(t *testing.T) { - - checker, err := ParseAndCheck(t, - types+` - let s: S{I1} = S() - let s2 = s as AnyStruct{I2} - `, - ) - - require.NoError(t, err) - - i2Type := RequireGlobalType(t, checker.Elaboration, "I2") - - require.IsType(t, &sema.InterfaceType{}, i2Type) - - s2Type := RequireGlobalValue(t, checker.Elaboration, "s2") - - require.IsType(t, - &sema.IntersectionType{ - Type: sema.AnyStructType, - Types: []*sema.InterfaceType{ - i2Type.(*sema.InterfaceType), - }, - }, - s2Type, - ) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: S{I1} = S() - let s2 = s as? AnyStruct{I2} - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run("intersection type -> intersection AnyStruct with non-conformance type", func(t *testing.T) { - - const types = ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1 {} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: S{I1} = S() - let s2 = s as AnyStruct{I2} - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: S{I1} = S() - let s2 = s as? AnyStruct{I2} - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - }) - - t.Run("intersection AnyStruct -> intersection AnyStruct: fewer types", func(t *testing.T) { - - const types = ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: AnyStruct{I1, I2} = S() - let s2 = s as AnyStruct{I2} - `, - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: AnyStruct{I1, I2} = S() - let s2 = s as? AnyStruct{I2} - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run("intersection AnyStruct -> intersection AnyStruct: more types", func(t *testing.T) { + t.Run("intersection AnyStruct -> intersection AnyStruct: more types", func(t *testing.T) { const types = ` struct interface I1 {} @@ -2062,8 +1693,8 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{I1} = S() - let s2 = s as AnyStruct{I1, I2} + let s: {I1} = S() + let s2 = s as {I1, I2} `, ) @@ -2076,8 +1707,8 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{I1} = S() - let s2 = s as? AnyStruct{I1, I2} + let s: {I1} = S() + let s2 = s as? {I1, I2} `, ) @@ -2099,8 +1730,8 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{I1} = S() - let s2 = s as AnyStruct{I1, I2} + let s: {I1} = S() + let s2 = s as {I1, I2} `, ) @@ -2113,8 +1744,8 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{I1} = S() - let s2 = s as? AnyStruct{I1, I2} + let s: {I1} = S() + let s2 = s as? {I1, I2} `, ) @@ -2135,7 +1766,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: AnyStruct = S() - let s2 = s as AnyStruct{I} + let s2 = s as {I} `, ) @@ -2149,7 +1780,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: AnyStruct = S() - let s2 = s as? AnyStruct{I} + let s2 = s as? {I} `, ) @@ -2173,7 +1804,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: S{I1} = S() + let s: {I1} = S() let s2 = s as AnyStruct `, ) @@ -2185,7 +1816,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: S{I1} = S() + let s: {I1} = S() let s2 = s as? AnyStruct `, ) @@ -2208,7 +1839,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{I1} = S() + let s: {I1} = S() let s2 = s as AnyStruct `, ) @@ -2220,7 +1851,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{I1} = S() + let s: {I1} = S() let s2 = s as? AnyStruct `, ) @@ -2317,11 +1948,9 @@ func TestCheckReferenceTypeSubTyping(t *testing.T) { for _, ty := range []string{ "R", - "R{I}", "AnyResource", - "AnyResource{I}", + "{I}", "Any", - "Any{I}", } { test(ty) } @@ -2381,11 +2010,9 @@ func TestCheckReferenceTypeSubTyping(t *testing.T) { for _, ty := range []string{ "S", - "S{I}", "AnyStruct", - "AnyStruct{I}", + "{I}", "Any", - "Any{I}", } { test(ty) } @@ -2462,14 +2089,14 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { entitlement X let x <- create R() - let r = &x as auth(X) &R{I1, I2} + let r = &x as auth(X) &{I1, I2} ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, setup+` - let r2 = r as &R{I2} + let r2 = r as &{I2} `, ) @@ -2480,7 +2107,7 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { _, err := ParseAndCheck(t, setup+` - let r2 = r as? &R{I2} + let r2 = r as? &{I2} `, ) @@ -2499,25 +2126,27 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { entitlement X let x <- create R() - let r = &x as auth(X) &R{I1} + let r = &x as auth(X) &{I1} ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, setup+` - let r2 = r as &R{I1, I2} + let r2 = r as &{I1, I2} `, ) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, setup+` - let r2 = r as? &R{I1, I2} + let r2 = r as? &{I1, I2} `, ) @@ -2525,48 +2154,44 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { }) }) - t.Run("intersection type -> intersection type: different resource", func(t *testing.T) { + t.Run("type -> intersection type: same resource", func(t *testing.T) { const setup = ` resource interface I {} - resource R1: I {} - - resource R2: I {} + resource R: I {} entitlement X - let x <- create R1() - let r = &x as auth(X) &R1{I} + let x <- create R() + let r = &x as auth(X) &R ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, setup+` - let r2 = r as &R2{I} + let r2 = r as &{I} `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, setup+` - let r2 = r as? &R2{I} + let r2 = r as? &{I} `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) - t.Run("type -> intersection type: same resource", func(t *testing.T) { + // Supertype: Resource + + t.Run("intersection type -> type", func(t *testing.T) { const setup = ` resource interface I {} @@ -2575,25 +2200,27 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { entitlement X let x <- create R() - let r = &x as auth(X) &R + let r = &x as auth(X) &{I} ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheck(t, setup+` - let r2 = r as &R{I} + let r2 = r as &R `, ) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheck(t, setup+` - let r2 = r as? &R{I} + let r2 = r as? &R `, ) @@ -2601,28 +2228,29 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { }) }) - t.Run("type -> intersection type: different resource", func(t *testing.T) { - - const setup = ` - resource interface I {} + t.Run("intersection -> conforming resource", func(t *testing.T) { - resource R1: I {} + setup := + ` + resource interface RI {} - resource R2: I {} - entitlement X + resource R: RI {} + entitlement X - let x <- create R1() - let r = &x as auth(X) &R1 - ` + let x <- create R() + let r = &x as auth(X) &{RI} + ` t.Run("static", func(t *testing.T) { - _, err := ParseAndCheck(t, + _, err := ParseAndCheckWithAny(t, setup+` - let r2 = r as &R2{I} - `, + let r2 = r as &R + `, ) + // NOTE: static cast not allowed, only dynamic + errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) @@ -2630,168 +2258,155 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { t.Run("dynamic", func(t *testing.T) { - _, err := ParseAndCheck(t, + _, err := ParseAndCheckWithAny(t, setup+` - let r2 = r as? &R2{I} - `, + let r2 = r as? &R + `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) - for _, ty := range []sema.Type{ - sema.AnyResourceType, - sema.AnyType, - } { + t.Run("intersection -> non-conforming resource", func(t *testing.T) { - t.Run(fmt.Sprintf("intersection %s -> conforming intersection type", ty), func(t *testing.T) { + setup := + ` + resource interface RI {} - setup := fmt.Sprintf(` - resource interface RI {} + resource R {} + entitlement X - resource R: RI {} - entitlement X + let x <- create R() + let r = &x as auth(X) &{RI} + ` - let x <- create R() - let r = &x as auth(X) &%s{RI} - `, - ty, + t.Run("static", func(t *testing.T) { + + _, err := ParseAndCheckWithAny(t, + setup+` + let r2 = r as &R + `, ) - t.Run("static", func(t *testing.T) { + errs := RequireCheckerErrors(t, err, 2) - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as &R{RI} - `, - ) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) + }) - // NOTE: static cast not allowed, only dynamic + t.Run("dynamic", func(t *testing.T) { - errs := RequireCheckerErrors(t, err, 1) + _, err := ParseAndCheckWithAny(t, + setup+` + let r2 = r as? &R + `, + ) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + errs := RequireCheckerErrors(t, err, 1) - t.Run("dynamic", func(t *testing.T) { + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) + }) - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as? &R{RI} - `, - ) + t.Run("resource -> intersection with non-conformance type", func(t *testing.T) { - require.NoError(t, err) - }) - }) + const setup = ` + resource interface RI {} - t.Run(fmt.Sprintf("%s -> conforming intersection type", ty), func(t *testing.T) { + // NOTE: R does not conform to RI + resource R {} + entitlement X - setup := fmt.Sprintf(` - resource interface RI {} + let x <- create R() + let r = &x as auth(X) &R + ` - resource R: RI {} - entitlement X + t.Run("static", func(t *testing.T) { - let x <- create R() - let r = &x as auth(X) &%s - `, - ty, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as &{RI} + `, ) - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as &R{RI} - `, - ) + errs := RequireCheckerErrors(t, err, 1) - errs := RequireCheckerErrors(t, err, 1) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + t.Run("dynamic", func(t *testing.T) { - t.Run("dynamic", func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as? &{RI} + `, + ) - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as? &R{RI} - `, - ) + errs := RequireCheckerErrors(t, err, 1) - require.NoError(t, err) - }) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) + }) - t.Run(fmt.Sprintf("intersection %s -> non-conforming intersection type", ty), func(t *testing.T) { - - setup := fmt.Sprintf(` - resource interface RI {} - - resource R {} - entitlement X + t.Run("resource -> intersection with conformance type", func(t *testing.T) { - let x <- create R() - let r = &x as auth(X) &%s{RI} - `, - ty, - ) + const setup = ` + resource interface RI {} - t.Run("static", func(t *testing.T) { + resource R: RI {} + entitlement X - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as &R{RI} - `, - ) + let x <- create R() + let r = &x as auth(X) &R + ` - errs := RequireCheckerErrors(t, err, 3) + t.Run("static", func(t *testing.T) { - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[2]) - }) + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as &{RI} + `, + ) - t.Run("dynamic", func(t *testing.T) { + require.NoError(t, err) + }) - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as? &R{RI} - `, - ) + t.Run("dynamic", func(t *testing.T) { - errs := RequireCheckerErrors(t, err, 2) + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as? &{RI} + `, + ) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) - }) + require.NoError(t, err) }) - } - - // Supertype: Resource + }) - t.Run("intersection type -> type: same resource", func(t *testing.T) { + t.Run("intersection type -> intersection with conformance in type", func(t *testing.T) { const setup = ` - resource interface I {} + resource interface I {} - resource R: I {} + resource R: I {} entitlement X - let x <- create R() - let r = &x as auth(X) &R{I} - ` + let x <- create R() + let r = &x as auth(X) &{I} + ` t.Run("static", func(t *testing.T) { - _, err := ParseAndCheck(t, - setup+` - let r2 = r as &R - `, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as &{I} + `, ) require.NoError(t, err) @@ -2799,36 +2414,38 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { t.Run("dynamic", func(t *testing.T) { - _, err := ParseAndCheck(t, - setup+` - let r2 = r as? &R - `, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as? &{I} + `, ) require.NoError(t, err) }) }) - t.Run("intersection type -> type: different resource", func(t *testing.T) { + t.Run("intersection type -> intersection with conformance not in type", func(t *testing.T) { const setup = ` - resource interface I {} + resource interface I1 {} - resource R: I {} - entitlement X + resource interface I2 {} - resource T: I {} + resource R: I1, I2 {} + entitlement X - let x <- create R() - let r = &x as auth(X) &R{I} - ` + let x <- create R() + let r = &x as auth(X) &{I1} + ` t.Run("static", func(t *testing.T) { - _, err := ParseAndCheck(t, - setup+` - let t = r as &T - `, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as &{I2} + `, ) errs := RequireCheckerErrors(t, err, 1) @@ -2838,107 +2455,62 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { t.Run("dynamic", func(t *testing.T) { - _, err := ParseAndCheck(t, - setup+` - let t = r as? &T - `, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as? &{I2} + `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) - for _, ty := range []sema.Type{ - sema.AnyResourceType, - sema.AnyType, - } { - - t.Run(fmt.Sprintf("intersection %s -> conforming resource", ty), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - resource interface RI {} - - resource R: RI {} - entitlement X - - let x <- create R() - let r = &x as auth(X) &%s{RI} - `, - ty, - ) + t.Run("intersection type -> intersection with non-conformance type", func(t *testing.T) { - t.Run("static", func(t *testing.T) { + const setup = ` + resource interface I1 {} - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as &R - `, - ) + resource interface I2 {} - // NOTE: static cast not allowed, only dynamic + resource R: I1 {} + entitlement X - errs := RequireCheckerErrors(t, err, 1) + let x <- create R() + let r = &x as auth(X) &{I1} + ` - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + t.Run("static", func(t *testing.T) { - t.Run("dynamic", func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as &{I2} + `, + ) - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as? &R - `, - ) + errs := RequireCheckerErrors(t, err, 1) - require.NoError(t, err) - }) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) - t.Run(fmt.Sprintf("intersection %s -> non-conforming resource", ty), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - resource interface RI {} - - resource R {} - entitlement X + t.Run("dynamic", func(t *testing.T) { - let x <- create R() - let r = &x as auth(X) &%s{RI} - `, - ty, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as? &{I2} + `, ) - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as &R - `, - ) - - errs := RequireCheckerErrors(t, err, 2) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as? &R - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + require.NoError(t, err) }) + }) + + for _, ty := range []sema.Type{ + sema.AnyResourceType, + sema.AnyType, + } { t.Run(fmt.Sprintf("%s -> type", ty), func(t *testing.T) { @@ -2980,19 +2552,18 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { }) }) - // Supertype: intersection AnyResource / Any - - t.Run(fmt.Sprintf("resource -> intersection %s with non-conformance type", ty), func(t *testing.T) { + t.Run(fmt.Sprintf("intersection type -> %s", ty), func(t *testing.T) { const setup = ` - resource interface RI {} + resource interface I1 {} + + resource interface I2 {} - // NOTE: R does not conform to RI - resource R {} + resource R: I1, I2 {} entitlement X let x <- create R() - let r = &x as auth(X) &R + let r = &x as auth(X) &{I1} ` t.Run("static", func(t *testing.T) { @@ -3000,15 +2571,13 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { _, err := ParseAndCheckWithAny(t, setup+fmt.Sprintf( ` - let r2 = r as &%s{RI} + let r2 = r as &%s `, ty, ), ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) t.Run("dynamic", func(t *testing.T) { @@ -3016,24 +2585,24 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { _, err := ParseAndCheckWithAny(t, setup+fmt.Sprintf( ` - let r2 = r as? &%s{RI} + let r2 = r as? &%s `, ty, ), ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) - t.Run(fmt.Sprintf("resource -> intersection %s with conformance type", ty), func(t *testing.T) { + t.Run(fmt.Sprintf("type -> %s", ty), func(t *testing.T) { const setup = ` - resource interface RI {} + resource interface I1 {} + + resource interface I2 {} - resource R: RI {} + resource R: I1, I2 {} entitlement X let x <- create R() @@ -3045,7 +2614,7 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { _, err := ParseAndCheckWithAny(t, setup+fmt.Sprintf( ` - let r2 = r as &%s{RI} + let r2 = r as &%s `, ty, ), @@ -3059,7 +2628,7 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { _, err := ParseAndCheckWithAny(t, setup+fmt.Sprintf( ` - let r2 = r as? &%s{RI} + let r2 = r as? &%s `, ty, ), @@ -3068,518 +2637,469 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { require.NoError(t, err) }) }) + } +} - t.Run(fmt.Sprintf("intersection type -> intersection %s with conformance in type", ty), func(t *testing.T) { +func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { - const setup = ` - resource interface I {} + t.Parallel() - resource R: I {} - entitlement X + // Supertype: Intersection type - let x <- create R() - let r = &x as auth(X) &R{I} - ` + t.Run("intersection type -> intersection type: fewer types", func(t *testing.T) { - t.Run("static", func(t *testing.T) { + const setup = ` + struct interface I1 {} - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I} - `, - ty, - ), - ) + struct interface I2 {} - require.NoError(t, err) - }) + struct S: I1, I2 {} + entitlement X - t.Run("dynamic", func(t *testing.T) { + let x = S() + let s = &x as auth(X) &{I1, I2} + ` - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I} - `, - ty, - ), - ) + t.Run("static", func(t *testing.T) { - require.NoError(t, err) - }) + _, err := ParseAndCheck(t, + setup+` + let s2 = s as &{I2} + `, + ) + + require.NoError(t, err) }) - t.Run(fmt.Sprintf("intersection type -> intersection %s with conformance not in type", ty), func(t *testing.T) { + t.Run("dynamic", func(t *testing.T) { - const setup = ` - resource interface I1 {} + _, err := ParseAndCheck(t, + setup+` + let s2 = s as? &{I2} + `, + ) - resource interface I2 {} + require.NoError(t, err) + }) + }) - resource R: I1, I2 {} - entitlement X + t.Run("intersection type -> intersection type: more types", func(t *testing.T) { - let x <- create R() - let r = &x as auth(X) &R{I1} - ` + const setup = ` + struct interface I1 {} - t.Run("static", func(t *testing.T) { + struct interface I2 {} - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I2} - `, - ty, - ), - ) + struct S: I1, I2 {} + entitlement X - require.NoError(t, err) - }) + let x = S() + let s = &x as auth(X) &{I1} + ` - t.Run("dynamic", func(t *testing.T) { + t.Run("static", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I2} - `, - ty, - ), - ) + _, err := ParseAndCheck(t, + setup+` + let s2 = s as &{I1, I2} + `, + ) - require.NoError(t, err) - }) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) - t.Run(fmt.Sprintf("intersection type -> intersection %s with non-conformance type", ty), func(t *testing.T) { + t.Run("dynamic", func(t *testing.T) { - const setup = ` - resource interface I1 {} + _, err := ParseAndCheck(t, + setup+` + let s2 = s as? &{I1, I2} + `, + ) - resource interface I2 {} + require.NoError(t, err) + }) + }) - resource R: I1 {} - entitlement X + t.Run("intersection type -> intersection type: different struct", func(t *testing.T) { - let x <- create R() - let r = &x as auth(X) &R{I1} - ` + const setup = ` + struct interface I {} - t.Run("static", func(t *testing.T) { + struct S1: I {} - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I2} - `, - ty, - ), - ) + struct S2: I {} + entitlement X - errs := RequireCheckerErrors(t, err, 1) + let x = S1() + let s = &x as auth(X) &{I} + ` - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + t.Run("static", func(t *testing.T) { - t.Run("dynamic", func(t *testing.T) { + _, err := ParseAndCheck(t, + setup+` + let s2 = s as &{I} + `, + ) - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I2} - `, - ty, - ), - ) + require.NoError(t, err) + }) - errs := RequireCheckerErrors(t, err, 1) + t.Run("dynamic", func(t *testing.T) { - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + _, err := ParseAndCheck(t, + setup+` + let s2 = s as? &{I} + `, + ) + + require.NoError(t, err) }) + }) - for _, otherType := range []sema.Type{ - sema.AnyResourceType, - sema.AnyType, - } { + t.Run("type -> intersection type: same struct", func(t *testing.T) { - t.Run(fmt.Sprintf("intersection %s -> intersection %s: fewer types", ty, otherType), func(t *testing.T) { + const setup = ` + struct interface I {} - setup := fmt.Sprintf( - ` - resource interface I1 {} + struct S: I {} + entitlement X - resource interface I2 {} + let x = S() + let s = &x as auth(X) &S - resource R: I1, I2 {} - entitlement X + ` - let x <- create R() - let r = &x as auth(X) &%s{I1, I2} - `, - ty, - ) + t.Run("static", func(t *testing.T) { - t.Run("static", func(t *testing.T) { + _, err := ParseAndCheck(t, + setup+` + let s2 = s as &{I} + `, + ) - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I2} - `, - otherType, - ), - ) + require.NoError(t, err) + }) - if ty == sema.AnyType && otherType == sema.AnyResourceType { + t.Run("dynamic", func(t *testing.T) { - errs := RequireCheckerErrors(t, err, 1) + _, err := ParseAndCheck(t, + setup+` + let s2 = s as? &{I} + `, + ) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) + }) + }) - return - } + for _, ty := range []sema.Type{ + sema.AnyStructType, + sema.AnyType, + } { - require.NoError(t, err) - }) + t.Run(fmt.Sprintf("%s -> conforming intersection type", ty), func(t *testing.T) { - t.Run("dynamic", func(t *testing.T) { + setup := fmt.Sprintf( + ` + struct interface SI {} - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I2} - `, - otherType, - ), - ) + struct S: SI {} + entitlement X - require.NoError(t, err) - }) - }) + let x = S() + let s = &x as auth(X) &%s + `, + ty, + ) - t.Run(fmt.Sprintf("intersection %s -> intersection %s: more types", ty, otherType), func(t *testing.T) { + t.Run("static", func(t *testing.T) { - setup := fmt.Sprintf( - ` - resource interface I1 {} + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as &{SI} + `, + ) + + errs := RequireCheckerErrors(t, err, 1) - resource interface I2 {} + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - resource R: I1, I2 {} - entitlement X + t.Run("dynamic", func(t *testing.T) { - let x <- create R() - let r = &x as auth(X) &%s{I1} + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as? &{SI} `, - ty, ) - t.Run("static", func(t *testing.T) { + require.NoError(t, err) + }) + }) - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I1, I2} - `, - otherType, - ), - ) + } - errs := RequireCheckerErrors(t, err, 1) + // Supertype: Struct - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + t.Run("intersection type -> type: same struct", func(t *testing.T) { - t.Run("dynamic", func(t *testing.T) { + const setup = ` + struct interface I {} - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I1, I2} - `, - otherType, - ), - ) + struct S: I {} + entitlement X - require.NoError(t, err) - }) - }) + let x = S() + let s = &x as auth(X) &{I} + ` - t.Run(fmt.Sprintf("intersection %s -> intersection %s with non-conformance type", ty, otherType), func(t *testing.T) { + t.Run("static", func(t *testing.T) { - setup := fmt.Sprintf( - ` - resource interface I1 {} + _, err := ParseAndCheck(t, + setup+` + let s2 = s as &S + `, + ) - resource interface I2 {} + errs := RequireCheckerErrors(t, err, 1) - resource R: I1 {} - entitlement X + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - let x <- create R() - let r = &x as auth(X) &%s{I1} - `, - ty, - ) + t.Run("dynamic", func(t *testing.T) { - t.Run("static", func(t *testing.T) { + _, err := ParseAndCheck(t, + setup+` + let s2 = s as? &S + `, + ) - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I1, I2} - `, - otherType, - ), - ) + require.NoError(t, err) + }) + }) - errs := RequireCheckerErrors(t, err, 1) + t.Run("intersection type -> type: different struct", func(t *testing.T) { - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + const setup = ` + struct interface I {} - t.Run("dynamic", func(t *testing.T) { + struct S: I {} - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I1, I2} - `, - otherType, - ), - ) + struct T: I {} + entitlement X - require.NoError(t, err) - }) - }) + let x = S() + let s = &x as auth(X) &{I} + ` - t.Run(fmt.Sprintf("%s -> intersection %s", ty, otherType), func(t *testing.T) { + t.Run("static", func(t *testing.T) { - setup := fmt.Sprintf( - ` - resource interface I {} + _, err := ParseAndCheck(t, + setup+` + let t = s as &T + `, + ) - resource R: I {} - entitlement X + errs := RequireCheckerErrors(t, err, 1) - let x <- create R() - let r = &x as auth(X) &%s - `, - ty, - ) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - t.Run("static", func(t *testing.T) { + t.Run("dynamic", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I} - `, - otherType, - ), - ) + _, err := ParseAndCheck(t, + setup+` + let t = s as? &T + `, + ) - errs := RequireCheckerErrors(t, err, 1) + require.NoError(t, err) + }) + }) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + t.Run("intersection -> conforming struct", func(t *testing.T) { - t.Run("dynamic", func(t *testing.T) { + setup := + ` + struct interface RI {} - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I} - `, - otherType, - ), - ) + struct S: RI {} + entitlement X - require.NoError(t, err) - }) - }) - } + let x = S() + let s = &x as auth(X) &{RI} + ` - // Supertype: AnyResource / Any + t.Run("static", func(t *testing.T) { - t.Run(fmt.Sprintf("intersection type -> %s", ty), func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as &S + `, + ) - const setup = ` - resource interface I1 {} + // NOTE: static cast not allowed, only dynamic - resource interface I2 {} + errs := RequireCheckerErrors(t, err, 1) - resource R: I1, I2 {} - entitlement X + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - let x <- create R() - let r = &x as auth(X) &R{I1} - ` + t.Run("dynamic", func(t *testing.T) { - t.Run("static", func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as? &S + `, + ) - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s - `, - ty, - ), - ) + require.NoError(t, err) + }) + }) - require.NoError(t, err) - }) + t.Run("intersection -> non-conforming struct", func(t *testing.T) { - t.Run("dynamic", func(t *testing.T) { + setup := + ` + struct interface RI {} - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s - `, - ty, - ), - ) + struct S {} + entitlement X - require.NoError(t, err) - }) - }) + let x = S() + let s = &x as auth(X) &{RI} + ` - for _, otherType := range []sema.Type{ - sema.AnyResourceType, - sema.AnyType, - } { - t.Run(fmt.Sprintf("intersection %s -> %s", ty, otherType), func(t *testing.T) { + t.Run("static", func(t *testing.T) { - setup := fmt.Sprintf( - ` - resource interface I1 {} + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as &S + `, + ) - resource interface I2 {} + errs := RequireCheckerErrors(t, err, 2) - resource R: I1, I2 {} - entitlement X + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) + }) - let x <- create R() - let r = &x as auth(X) &%s{I1} - `, - ty, - ) + t.Run("dynamic", func(t *testing.T) { - t.Run("static", func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as? &S + `, + ) - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s - `, - otherType, - ), - ) + errs := RequireCheckerErrors(t, err, 1) - if ty == sema.AnyType && otherType == sema.AnyResourceType { + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) + }) - errs := RequireCheckerErrors(t, err, 1) + t.Run("struct -> intersection with non-conformance type", func(t *testing.T) { - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + const setup = ` + struct interface SI {} - return - } + // NOTE: S does not conform to SI + struct S {} + entitlement X - require.NoError(t, err) - }) + let x = S() + let s = &x as auth(X) &S + ` - t.Run("dynamic", func(t *testing.T) { + t.Run("static", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s - `, - otherType, - ), - ) + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as &{SI} + `, + ) - require.NoError(t, err) - }) - }) + errs := RequireCheckerErrors(t, err, 1) - } + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - t.Run(fmt.Sprintf("type -> %s", ty), func(t *testing.T) { + t.Run("dynamic", func(t *testing.T) { - const setup = ` - resource interface I1 {} + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as? &{SI} + `, + ) - resource interface I2 {} + errs := RequireCheckerErrors(t, err, 1) - resource R: I1, I2 {} - entitlement X + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) + }) - let x <- create R() - let r = &x as auth(X) &R - ` + t.Run("struct -> intersection with conformance type", func(t *testing.T) { - t.Run("static", func(t *testing.T) { + const setup = ` + struct interface SI {} - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s - `, - ty, - ), - ) + struct S: SI {} + entitlement X - require.NoError(t, err) - }) + let x = S() + let s = &x as auth(X) &S + ` - t.Run("dynamic", func(t *testing.T) { + t.Run("static", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s - `, - ty, - ), - ) + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as &{SI} + `, + ) - require.NoError(t, err) - }) + require.NoError(t, err) }) - } -} -func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { + t.Run("dynamic", func(t *testing.T) { - t.Parallel() + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as? &{SI} + `, + ) - // Supertype: Intersection type + require.NoError(t, err) + }) + }) - t.Run("intersection type -> intersection type: fewer types", func(t *testing.T) { + t.Run("intersection type -> intersection with conformance in type", func(t *testing.T) { const setup = ` - struct interface I1 {} + struct interface I {} - struct interface I2 {} + struct S: I {} - struct S: I1, I2 {} entitlement X - let x = S() - let s = &x as auth(X) &S{I1, I2} - ` + let x = S() + let s = &x as auth(X) &{I} + ` t.Run("static", func(t *testing.T) { - _, err := ParseAndCheck(t, - setup+` - let s2 = s as &S{I2} - `, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as &{I} + `, ) require.NoError(t, err) @@ -3587,150 +3107,81 @@ func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { t.Run("dynamic", func(t *testing.T) { - _, err := ParseAndCheck(t, - setup+` - let s2 = s as? &S{I2} - `, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as? &{I} + `, ) require.NoError(t, err) }) }) - t.Run("intersection type -> intersection type: more types", func(t *testing.T) { + t.Run("intersection type -> intersection with conformance not in type", func(t *testing.T) { const setup = ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - entitlement X - - let x = S() - let s = &x as auth(X) &S{I1} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheck(t, - setup+` - let s2 = s as &S{I1, I2} - `, - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - setup+` - let s2 = s as? &S{I1, I2} - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run("intersection type -> intersection type: different struct", func(t *testing.T) { + struct interface I1 {} - const setup = ` - struct interface I {} + struct interface I2 {} - struct S1: I {} + struct S: I1, I2 {} - struct S2: I {} entitlement X - let x = S1() - let s = &x as auth(X) &S1{I} - ` + let x = S() + let s = &x as auth(X) &{I1} + ` t.Run("static", func(t *testing.T) { - _, err := ParseAndCheck(t, - setup+` - let s2 = s as &S2{I} - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - setup+` - let s2 = s as? &S2{I} - `, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as &{I2} + `, ) errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) - }) - - t.Run("type -> intersection type: same struct", func(t *testing.T) { - - const setup = ` - struct interface I {} - - struct S: I {} - entitlement X - - let x = S() - let s = &x as auth(X) &S - - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheck(t, - setup+` - let s2 = s as &S{I} - `, - ) - - require.NoError(t, err) - }) t.Run("dynamic", func(t *testing.T) { - _, err := ParseAndCheck(t, - setup+` - let s2 = s as? &S{I} - `, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as? &{I2} + `, ) require.NoError(t, err) }) }) - t.Run("type -> intersection type: different struct", func(t *testing.T) { + t.Run("intersection type -> intersection with non-conformance type", func(t *testing.T) { const setup = ` - struct interface I {} + struct interface I1 {} - struct S1: I {} + struct interface I2 {} + + struct S: I1 {} - struct S2: I {} entitlement X - let x = S1() - let s = &x as auth(X) &S1 - ` + let x = S() + let s = &x as auth(X) &{I1} + ` t.Run("static", func(t *testing.T) { - _, err := ParseAndCheck(t, - setup+` - let s2 = s as &S2{I} - `, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as &{I2} + `, ) errs := RequireCheckerErrors(t, err, 1) @@ -3740,15 +3191,14 @@ func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { t.Run("dynamic", func(t *testing.T) { - _, err := ParseAndCheck(t, - setup+` - let s2 = s as? &S2{I} - `, + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as? &{I2} + `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) @@ -3756,7 +3206,8 @@ func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { sema.AnyStructType, sema.AnyType, } { - t.Run(fmt.Sprintf("intersection %s -> conforming intersection type", ty), func(t *testing.T) { + + t.Run(fmt.Sprintf("%s -> type", ty), func(t *testing.T) { setup := fmt.Sprintf( ` @@ -3766,7 +3217,7 @@ func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { entitlement X let x = S() - let s = &x as auth(X) &%s{SI} + let s = &x as auth(X) &%s `, ty, ) @@ -3775,12 +3226,10 @@ func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { _, err := ParseAndCheckWithAny(t, setup+` - let s2 = s as &S{SI} + let s2 = s as &S `, ) - // NOTE: static cast not allowed, only dynamic - errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) @@ -3790,7 +3239,7 @@ func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { _, err := ParseAndCheckWithAny(t, setup+` - let s2 = s as? &S{SI} + let s2 = s as? &S `, ) @@ -3798,1694 +3247,273 @@ func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { }) }) - t.Run(fmt.Sprintf("%s -> conforming intersection type", ty), func(t *testing.T) { + } +} - setup := fmt.Sprintf( - ` - struct interface SI {} +func TestCheckCastUnauthorizedResourceReferenceType(t *testing.T) { - struct S: SI {} - entitlement X + t.Parallel() - let x = S() - let s = &x as auth(X) &%s - `, - ty, - ) + for name, op := range map[string]string{ + "static": "as", + "dynamic": "as?", + } { - t.Run("static", func(t *testing.T) { + t.Run(name, func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as &S{SI} - `, - ) + // Supertype: Intersection type - errs := RequireCheckerErrors(t, err, 1) + t.Run("intersection type -> intersection type: fewer types", func(t *testing.T) { - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + _, err := ParseAndCheck(t, + fmt.Sprintf( + ` + resource interface I1 {} - t.Run("dynamic", func(t *testing.T) { + resource interface I2 {} - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as? &S{SI} - `, + resource R: I1, I2 {} + + let x <- create R() + let r = &x as &{I1, I2} + let r2 = r %s &{I2} + `, + op, + ), ) require.NoError(t, err) }) - }) - t.Run(fmt.Sprintf("intersection %s -> non-conforming intersection type", ty), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - struct interface SI {} + t.Run("intersection type -> intersection type: more types", func(t *testing.T) { - struct S {} - entitlement X + _, err := ParseAndCheck(t, + fmt.Sprintf( + ` + resource interface I1 {} - let x = S() - let s = &x as auth(X) &%s{SI} - `, - ty, - ) + resource interface I2 {} - t.Run("static", func(t *testing.T) { + resource R: I1, I2 {} - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as &S{SI} - `, + let x <- create R() + let r = &x as &{I1} + let r2 = r %s &{I1, I2} + `, + op, + ), ) - errs := RequireCheckerErrors(t, err, 3) + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[2]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { + require.NoError(t, err) + } }) - t.Run("dynamic", func(t *testing.T) { + t.Run("type -> intersection type: same resource", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as? &S{SI} - `, - ) + _, err := ParseAndCheck(t, + fmt.Sprintf( + ` + resource interface I {} - errs := RequireCheckerErrors(t, err, 2) + resource R: I {} - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) - }) - }) - } + let x <- create R() + let r = &x as &R + let r2 = r %s &{I} + `, + op, + ), + ) - // Supertype: Struct + require.NoError(t, err) + }) - t.Run("intersection type -> type: same struct", func(t *testing.T) { + t.Run("intersection -> conforming intersection type", func(t *testing.T) { - const setup = ` - struct interface I {} + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + resource interface RI {} - struct S: I {} - entitlement X + resource R: RI {} - let x = S() - let s = &x as auth(X) &S{I} - ` + let x <- create R() + let r = &x as &{RI} + let r2 = r %s &{RI} + `, + op, + ), + ) - t.Run("static", func(t *testing.T) { + require.NoError(t, err) + }) - _, err := ParseAndCheck(t, - setup+` - let s2 = s as &S - `, - ) + for _, ty := range []sema.Type{ + sema.AnyResourceType, + sema.AnyType, + } { - require.NoError(t, err) - }) + t.Run(fmt.Sprintf("%s -> conforming intersection type", ty), func(t *testing.T) { - t.Run("dynamic", func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + resource interface RI {} - _, err := ParseAndCheck(t, - setup+` - let s2 = s as? &S - `, - ) + resource R: RI {} - require.NoError(t, err) - }) - }) - - t.Run("intersection type -> type: different struct", func(t *testing.T) { - - const setup = ` - struct interface I {} - - struct S: I {} - - struct T: I {} - entitlement X - - let x = S() - let s = &x as auth(X) &S{I} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheck(t, - setup+` - let t = s as &T - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - setup+` - let t = s as? &T - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - }) - - for _, ty := range []sema.Type{ - sema.AnyStructType, - sema.AnyType, - } { - - t.Run(fmt.Sprintf("intersection %s -> conforming struct", ty), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - struct interface RI {} - - struct S: RI {} - entitlement X - - let x = S() - let s = &x as auth(X) &%s{RI} - `, - ty, - ) - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as &S - `, - ) - - // NOTE: static cast not allowed, only dynamic - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as? &S - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run(fmt.Sprintf("intersection %s -> non-conforming struct", ty), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - struct interface RI {} - - struct S {} - entitlement X - - let x = S() - let s = &x as auth(X) &%s{RI} - `, - ty, - ) - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as &S - `, - ) - - errs := RequireCheckerErrors(t, err, 2) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as? &S - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - }) - - t.Run(fmt.Sprintf("%s -> type", ty), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - struct interface SI {} - - struct S: SI {} - entitlement X - - let x = S() - let s = &x as auth(X) &%s - `, - ty, - ) - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as &S - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as? &S - `, - ) - - require.NoError(t, err) - }) - }) - - // Supertype: intersection AnyStruct / Any - - t.Run(fmt.Sprintf("struct -> intersection %s with non-conformance type", ty), func(t *testing.T) { - - const setup = ` - struct interface SI {} - - // NOTE: S does not conform to SI - struct S {} - entitlement X - - let x = S() - let s = &x as auth(X) &S - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s{SI} - `, - ty, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s{SI} - `, - ty, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - }) - - t.Run(fmt.Sprintf("struct -> intersection %s with conformance type", ty), func(t *testing.T) { - - const setup = ` - struct interface SI {} - - struct S: SI {} - entitlement X - - let x = S() - let s = &x as auth(X) &S - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s{SI} - `, - ty, - ), - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s{SI} - `, - ty, - ), - ) - - require.NoError(t, err) - }) - }) - - t.Run(fmt.Sprintf("intersection type -> intersection %s with conformance in type", ty), func(t *testing.T) { - - const setup = ` - struct interface I {} - - struct S: I {} - - entitlement X - - let x = S() - let s = &x as auth(X) &S{I} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s{I} - `, - ty, - ), - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s{I} - `, - ty, - ), - ) - - require.NoError(t, err) - }) - }) - - t.Run(fmt.Sprintf("intersection type -> intersection %s with conformance not in type", ty), func(t *testing.T) { - - const setup = ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - - entitlement X - - let x = S() - let s = &x as auth(X) &S{I1} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s{I2} - `, - ty, - ), - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s{I2} - `, - ty, - ), - ) - - require.NoError(t, err) - }) - }) - - t.Run(fmt.Sprintf("intersection type -> intersection %s with non-conformance type", ty), func(t *testing.T) { - - const setup = ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1 {} - - entitlement X - - let x = S() - let s = &x as auth(X) &S{I1} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s{I2} - `, - ty, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s{I2} - `, - ty, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - }) - - for _, otherType := range []sema.Type{ - sema.AnyStructType, - sema.AnyType, - } { - - t.Run(fmt.Sprintf("intersection %s -> intersection %s: fewer types", ty, otherType), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - - entitlement X - - let x = S() - let s = &x as auth(X) &%s{I1, I2} - `, - ty, - ) - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s{I2} - `, - otherType, - ), - ) - - if ty == sema.AnyType && otherType == sema.AnyStructType { - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - - return - } - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s{I2} - `, - otherType, - ), - ) - - require.NoError(t, err) - }) - }) - - t.Run(fmt.Sprintf("intersection %s -> intersection %s: more types", ty, otherType), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - - entitlement X - - let x = S() - let s = &x as auth(X) &%s{I1} - `, - ty, - ) - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s{I1, I2} - `, - otherType, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s{I1, I2} - `, - otherType, - ), - ) - - require.NoError(t, err) - }) - }) - - t.Run(fmt.Sprintf("intersection %s -> intersection %s with non-conformance type", ty, otherType), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1 {} - - entitlement X - - let x = S() - let s = &x as auth(X) &%s{I1} - `, - ty, - ) - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s{I1, I2} - `, - otherType, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s{I1, I2} - `, - otherType, - ), - ) - - require.NoError(t, err) - }) - }) - - t.Run(fmt.Sprintf("%s -> intersection %s", ty, otherType), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - struct interface I {} - - struct S: I {} - - entitlement X - - let x = S() - let s = &x as auth(X) &%s - `, - ty, - ) - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s{I} - `, - otherType, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s{I} - `, - otherType, - ), - ) - - require.NoError(t, err) - }) - }) - - // Supertype: AnyStruct / Any - - t.Run(fmt.Sprintf("intersection %s -> %s", ty, otherType), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - - entitlement X - - let x = S() - let s = &x as auth(X) &%s{I1} - `, - ty, - ) - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s - `, - otherType, - ), - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s - `, - otherType, - ), - ) - - require.NoError(t, err) - }) - }) - } - - t.Run(fmt.Sprintf("intersection type -> %s", ty), func(t *testing.T) { - - const setup = ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - - entitlement X - - let x = S() - let s = &x as auth(X) &S{I1} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s - `, - ty, - ), - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s - `, - ty, - ), - ) - - require.NoError(t, err) - }) - }) - - t.Run(fmt.Sprintf("type -> %s", ty), func(t *testing.T) { - - const setup = ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - - entitlement X - - let x = S() - let s = &x as auth(X) &S - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as &%s - `, - ty, - ), - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let s2 = s as? &%s - `, - ty, - ), - ) - - require.NoError(t, err) - }) - }) - } -} - -func TestCheckCastUnauthorizedResourceReferenceType(t *testing.T) { - - t.Parallel() - - for name, op := range map[string]string{ - "static": "as", - "dynamic": "as?", - } { - - t.Run(name, func(t *testing.T) { - - // Supertype: Intersection type - - t.Run("intersection type -> intersection type: fewer types", func(t *testing.T) { - - _, err := ParseAndCheck(t, - fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1, I2 {} - - let x <- create R() - let r = &x as &R{I1, I2} - let r2 = r %s &R{I2} - `, - op, - ), - ) - - require.NoError(t, err) - }) - - t.Run("intersection type -> intersection type: more types", func(t *testing.T) { - - _, err := ParseAndCheck(t, - fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1, I2 {} - - let x <- create R() - let r = &x as &R{I1} - let r2 = r %s &R{I1, I2} - `, - op, - ), - ) - - require.NoError(t, err) - }) - - t.Run("intersection type -> intersection type: different resource", func(t *testing.T) { - - _, err := ParseAndCheck(t, - fmt.Sprintf( - ` - resource interface I {} - - resource R1: I {} - - resource R2: I {} - - let x <- create R1() - let r = &x as &R1{I} - let r2 = r %s &R2{I} - `, - op, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run("type -> intersection type: same resource", func(t *testing.T) { - - _, err := ParseAndCheck(t, - fmt.Sprintf( - ` - resource interface I {} - - resource R: I {} - - let x <- create R() - let r = &x as &R - let r2 = r %s &R{I} - `, - op, - ), - ) - - require.NoError(t, err) - }) - - t.Run("type -> intersection type: different resource", func(t *testing.T) { - - _, err := ParseAndCheck(t, - fmt.Sprintf( - ` - resource interface I {} - - resource R1: I {} - - resource R2: I {} - - let x <- create R1() - let r = &x as &R1 - let r2 = r %s &R2{I} - `, - op, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - for _, ty := range []sema.Type{ - sema.AnyResourceType, - sema.AnyType, - } { - - t.Run(fmt.Sprintf("intersection %s -> conforming intersection type", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface RI {} - - resource R: RI {} - - let x <- create R() - let r = &x as &%s{RI} - let r2 = r %s &R{RI} - `, - ty, - op, - ), - ) - - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) - - t.Run(fmt.Sprintf("%s -> conforming intersection type", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface RI {} - - resource R: RI {} - - let x <- create R() - let r = &x as &%s - let r2 = r %s &R{RI} - `, - ty, - op, - ), - ) - - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) - - t.Run(fmt.Sprintf("intersection %s -> non-conforming intersection type", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface RI {} - - resource R {} - - let x <- create R() - let r = &x as &%s{RI} - let r2 = r %s &R{RI} - `, - ty, - op, - ), - ) - - if name == "static" { - errs := RequireCheckerErrors(t, err, 3) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[2]) - } else { - errs := RequireCheckerErrors(t, err, 2) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) - } - }) - } - - // Supertype: Resource - - t.Run("intersection type -> type", func(t *testing.T) { - - _, err := ParseAndCheck(t, - fmt.Sprintf( - ` - resource interface I {} - - resource R: I {} - - let x <- create R() - let r = &x as &R{I} - let r2 = r %s &R - `, - op, - ), - ) - - require.NoError(t, err) - }) - - t.Run("intersection type -> type: different resource", func(t *testing.T) { - - _, err := ParseAndCheck(t, - fmt.Sprintf( - ` - resource interface I {} - - resource R: I {} - - resource T: I {} - - let x <- create R() - let r = &x as &R{I} - let t = r %s &T - `, - op, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - for _, ty := range []sema.Type{ - sema.AnyResourceType, - sema.AnyType, - } { - - t.Run(fmt.Sprintf("intersection %s -> conforming resource", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface RI {} - - resource R: RI {} - - let x <- create R() - let r = &x as &%s{RI} - let r2 = r %s &R - `, - ty, - op, - ), - ) - - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) - - t.Run(fmt.Sprintf("intersection %s -> non-conforming resource", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface RI {} - - resource R {} - - let x <- create R() - let r = &x as &%s{RI} - let r2 = r %s &R - `, - ty, - op, - ), - ) - - if name == "static" { - errs := RequireCheckerErrors(t, err, 2) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) - } else { - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } - }) - - t.Run(fmt.Sprintf("%s -> type", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface RI {} - - resource R: RI {} - - let x <- create R() - let r = &x as &%s - let r2 = r %s &R - `, - ty, - op, - ), - ) + let x <- create R() + let r = &x as &%s + let r2 = r %s &{RI} + `, + ty, + op, + ), + ) if name == "static" { errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) } else { - require.NoError(t, err) - } - }) - - // Supertype: intersection AnyResource / Any - - t.Run(fmt.Sprintf("resource -> intersection %s with non-conformance type", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface RI {} - - // NOTE: R does not conform to RI - resource R {} - - let x <- create R() - let r = &x as &R - let r2 = r %s &%s{RI} - `, - op, - ty, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - - t.Run(fmt.Sprintf("resource -> intersection %s with conformance type", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface RI {} - - resource R: RI {} - - let x <- create R() - let r = &x as &R - let r2 = r %s &%s{RI} - `, - op, - ty, - ), - ) - - require.NoError(t, err) - }) - - t.Run(fmt.Sprintf("intersection type -> intersection %s with conformance in type", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I {} - - resource R: I {} - - let x <- create R() - let r = &x as &R{I} - let r2 = r %s &%s{I} - `, - op, - ty, - ), - ) - - require.NoError(t, err) - }) - - t.Run(fmt.Sprintf("intersection type -> intersection %s with conformance not in type", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1, I2 {} - - let x <- create R() - let r = &x as &R{I1} - let r2 = r %s &%s{I2} - `, - op, - ty, - ), - ) - - require.NoError(t, err) - }) - - t.Run(fmt.Sprintf("intersection type -> intersection %s with non-conformance type", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1 {} - - let x <- create R() - let r = &x as &R{I1} - let r2 = r %s &%s{I2} - `, - op, - ty, - ), - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - - }) - - for _, otherType := range []sema.Type{ - sema.AnyResourceType, - sema.AnyType, - } { - - t.Run(fmt.Sprintf("intersection %s -> intersection %s: fewer types", ty, otherType), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1, I2 {} - - let x <- create R() - let r = &x as &%s{I1, I2} - let r2 = r %s &%s{I2} - `, - ty, - op, - otherType, - ), - ) - - if ty == sema.AnyType && otherType == sema.AnyResourceType { - - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - - return - } - - require.NoError(t, err) - }) - - t.Run(fmt.Sprintf("intersection %s -> intersection %s: more types", ty, otherType), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1, I2 {} - - let x <- create R() - let r = &x as &%s{I1} - let r2 = r %s &%s{I1, I2} - `, - ty, - op, - otherType, - ), - ) - - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) - - t.Run(fmt.Sprintf("intersection %s -> intersection %s with non-conformance type", ty, otherType), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1 {} - - let x <- create R() - let r = &x as &%s{I1} - let r2 = r %s &%s{I1, I2} - `, - ty, - op, - otherType, - ), - ) - - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) - - t.Run(fmt.Sprintf("%s -> intersection %s", ty, otherType), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I {} - - resource R: I {} - - let x <- create R() - let r = &x as &%s - let r2 = r %s &%s{I} - `, - ty, - op, - otherType, - ), - ) - - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) - - // Supertype: AnyResource / Any - - t.Run(fmt.Sprintf("intersection %s -> %s", ty, otherType), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1, I2 {} - - let x <- create R() - let r = &x as &%s{I1} - let r2 = r %s &%s - `, - ty, - op, - otherType, - ), - ) - - if ty == sema.AnyType && otherType == sema.AnyResourceType && name == "static" { - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) - - } - - t.Run(fmt.Sprintf("intersection type -> %s", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1, I2 {} - - let x <- create R() - let r = &x as &R{I1} - let r2 = r %s &%s - `, - op, - ty, - ), - ) - - require.NoError(t, err) - }) - - t.Run(fmt.Sprintf("type -> %s", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1, I2 {} - - let x <- create R() - let r = &x as &R - let r2 = r %s &%s - `, - op, - ty, - ), - ) - - require.NoError(t, err) - }) - } - }) - } -} - -func TestCheckCastUnauthorizedStructReferenceType(t *testing.T) { - - t.Parallel() - - for name, op := range map[string]string{ - "static": "as", - "dynamic": "as?", - } { - - t.Run(name, func(t *testing.T) { - - // Supertype: Intersection type - - t.Run("intersection type -> intersection type: fewer types", func(t *testing.T) { - - _, err := ParseAndCheck(t, - fmt.Sprintf( - ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - - let x = S() - let s = &x as &S{I1, I2} - let s2 = s %s &S{I2} - `, - op, - ), - ) + require.NoError(t, err) + } + }) + } - require.NoError(t, err) - }) + // Supertype: Resource - t.Run("intersection type -> intersection type: more types", func(t *testing.T) { + t.Run("intersection type -> type", func(t *testing.T) { _, err := ParseAndCheck(t, fmt.Sprintf( ` - struct interface I1 {} - - struct interface I2 {} + resource interface I {} - struct S: I1, I2 {} + resource R: I {} - let x = S() - let s = &x as &S{I1} - let s2 = s %s &S{I1, I2} + let x <- create R() + let r = &x as &{I} + let r2 = r %s &R `, op, ), ) - require.NoError(t, err) + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { + require.NoError(t, err) + } }) - t.Run("intersection type -> intersection type: different resource", func(t *testing.T) { + t.Run("intersection type -> type: different resource", func(t *testing.T) { _, err := ParseAndCheck(t, fmt.Sprintf( ` - struct interface I {} + resource interface I {} - struct S1: I {} + resource R: I {} - struct S2: I {} + resource T: I {} - let x = S1() - let s = &x as &S1{I} - let s2 = s %s &S2{I} + let x <- create R() + let r = &x as &{I} + let t = r %s &T `, op, ), ) - errs := RequireCheckerErrors(t, err, 1) + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { + require.NoError(t, err) + } }) - t.Run("type -> intersection type: same resource", func(t *testing.T) { + t.Run("intersection -> conforming resource", func(t *testing.T) { - _, err := ParseAndCheck(t, + _, err := ParseAndCheckWithAny(t, fmt.Sprintf( ` - struct interface I {} + resource interface RI {} - struct S: I {} + resource R: RI {} - let x = S() - let s = &x as &S - let s2 = s %s &S{I} - `, + let x <- create R() + let r = &x as &{RI} + let r2 = r %s &R + `, op, ), ) - require.NoError(t, err) + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { + require.NoError(t, err) + } }) - t.Run("type -> intersection type: different resource", func(t *testing.T) { + t.Run("intersection -> non-conforming resource", func(t *testing.T) { - _, err := ParseAndCheck(t, + _, err := ParseAndCheckWithAny(t, fmt.Sprintf( ` - struct interface I {} + resource interface RI {} - struct S1: I {} + resource R {} - struct S2: I {} - - let x = S1() - let s = &x as &S1 - let s2 = s %s &S2{I} - `, + let x <- create R() + let r = &x as &{RI} + let r2 = r %s &R + `, op, ), ) - errs := RequireCheckerErrors(t, err, 1) + if name == "static" { + errs := RequireCheckerErrors(t, err, 2) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) + } else { + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } }) for _, ty := range []sema.Type{ - sema.AnyStructType, + sema.AnyResourceType, sema.AnyType, } { - t.Run(fmt.Sprintf("intersection %s -> conforming intersection type", ty), func(t *testing.T) { + t.Run(fmt.Sprintf("%s -> type", ty), func(t *testing.T) { _, err := ParseAndCheckWithAny(t, fmt.Sprintf( ` - struct interface RI {} + resource interface RI {} - struct S: RI {} + resource R: RI {} - let x = S() - let s = &x as &%s{RI} - let s2 = s %s &S{RI} + let x <- create R() + let r = &x as &%s + let r2 = r %s &R `, ty, op, @@ -5501,20 +3529,21 @@ func TestCheckCastUnauthorizedStructReferenceType(t *testing.T) { } }) - t.Run(fmt.Sprintf("%s -> conforming intersection type", ty), func(t *testing.T) { + t.Run("intersection type -> intersection with conformance not in type", func(t *testing.T) { _, err := ParseAndCheckWithAny(t, fmt.Sprintf( ` - struct interface RI {} + resource interface I1 {} - struct S: RI {} + resource interface I2 {} - let x = S() - let s = &x as &%s - let s2 = s %s &S{RI} + resource R: I1, I2 {} + + let x <- create R() + let r = &x as &{I1} + let r2 = r %s &{I2} `, - ty, op, ), ) @@ -5528,54 +3557,161 @@ func TestCheckCastUnauthorizedStructReferenceType(t *testing.T) { } }) - t.Run(fmt.Sprintf("intersection %s -> non-conforming intersection type", ty), func(t *testing.T) { + t.Run("intersection -> intersection with non-conformance type", func(t *testing.T) { _, err := ParseAndCheckWithAny(t, fmt.Sprintf( ` - struct interface RI {} + resource interface I1 {} - struct S {} + resource interface I2 {} - let x = S() - let s = &x as &%s{RI} - let s2 = s %s &S{RI} - `, - ty, + resource R: I1 {} + + let x <- create R() + let r = &x as &{I1} + let r2 = r %s &{I1, I2} + `, op, ), ) if name == "static" { - errs := RequireCheckerErrors(t, err, 3) + errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[2]) } else { + require.NoError(t, err) + } + }) + + t.Run(fmt.Sprintf("%s -> intersection", ty), func(t *testing.T) { - errs := RequireCheckerErrors(t, err, 2) + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + resource interface I {} + + resource R: I {} + + let x <- create R() + let r = &x as &%s + let r2 = r %s &{I} + `, + ty, + op, + ), + ) + + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[1]) + } else { + require.NoError(t, err) } }) + + t.Run(fmt.Sprintf("intersection -> %s", ty), func(t *testing.T) { + + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + resource interface I1 {} + + resource interface I2 {} + + resource R: I1, I2 {} + + let x <- create R() + let r = &x as &{I1} + let r2 = r %s &%s + `, + op, + ty, + ), + ) + + require.NoError(t, err) + }) + + t.Run(fmt.Sprintf("intersection type -> %s", ty), func(t *testing.T) { + + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + resource interface I1 {} + + resource interface I2 {} + + resource R: I1, I2 {} + + let x <- create R() + let r = &x as &{I1} + let r2 = r %s &%s + `, + op, + ty, + ), + ) + + require.NoError(t, err) + }) + + t.Run(fmt.Sprintf("type -> %s", ty), func(t *testing.T) { + + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + resource interface I1 {} + + resource interface I2 {} + + resource R: I1, I2 {} + + let x <- create R() + let r = &x as &R + let r2 = r %s &%s + `, + op, + ty, + ), + ) + + require.NoError(t, err) + }) } + }) + } +} - // Supertype: Resource +func TestCheckCastUnauthorizedStructReferenceType(t *testing.T) { - t.Run("intersection type -> type", func(t *testing.T) { + t.Parallel() + + for name, op := range map[string]string{ + "static": "as", + "dynamic": "as?", + } { + + t.Run(name, func(t *testing.T) { + + // Supertype: Intersection type + + t.Run("intersection type -> intersection type: fewer types", func(t *testing.T) { _, err := ParseAndCheck(t, fmt.Sprintf( ` - struct interface I {} + struct interface I1 {} - struct S: I {} + struct interface I2 {} + + struct S: I1, I2 {} let x = S() - let s = &x as &S{I} - let s2 = s %s &S + let s = &x as &{I1, I2} + let s2 = s %s &{I2} `, op, ), @@ -5584,93 +3720,60 @@ func TestCheckCastUnauthorizedStructReferenceType(t *testing.T) { require.NoError(t, err) }) - t.Run("intersection type -> type: different resource", func(t *testing.T) { + t.Run("intersection type -> intersection type: more types", func(t *testing.T) { _, err := ParseAndCheck(t, fmt.Sprintf( ` - struct interface I {} + struct interface I1 {} - struct S: I {} + struct interface I2 {} - struct T: I {} + struct S: I1, I2 {} let x = S() - let s = &x as &S{I} - let t = s %s &T + let s = &x as &{I1} + let s2 = s %s &{I1, I2} `, op, ), ) - errs := RequireCheckerErrors(t, err, 1) + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { + require.NoError(t, err) + } }) - for _, ty := range []sema.Type{ - sema.AnyStructType, - sema.AnyType, - } { - - t.Run(fmt.Sprintf("intersection %s -> conforming resource", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface RI {} - - struct S: RI {} - - let x = S() - let s = &x as &%s{RI} - let s2 = s %s &S - `, - ty, - op, - ), - ) - - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) - - t.Run(fmt.Sprintf("intersection %s -> non-conforming resource", ty), func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface RI {} - - struct S {} - - let x = S() - let s = &x as &%s{RI} - let s2 = s %s &S - `, - ty, - op, - ), - ) + t.Run("type -> intersection type: same resource", func(t *testing.T) { - if name == "static" { - errs := RequireCheckerErrors(t, err, 2) + _, err := ParseAndCheck(t, + fmt.Sprintf( + ` + struct interface I {} - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) - } else { - errs := RequireCheckerErrors(t, err, 1) + struct S: I {} - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } - }) + let x = S() + let s = &x as &S + let s2 = s %s &{I} + `, + op, + ), + ) - t.Run(fmt.Sprintf("%s -> type", ty), func(t *testing.T) { + require.NoError(t, err) + }) + + for _, ty := range []sema.Type{ + sema.AnyStructType, + sema.AnyType, + } { + + t.Run(fmt.Sprintf("%s -> conforming intersection type", ty), func(t *testing.T) { _, err := ParseAndCheckWithAny(t, fmt.Sprintf( @@ -5681,7 +3784,7 @@ func TestCheckCastUnauthorizedStructReferenceType(t *testing.T) { let x = S() let s = &x as &%s - let s2 = s %s &S + let s2 = s %s &{RI} `, ty, op, @@ -5695,297 +3798,319 @@ func TestCheckCastUnauthorizedStructReferenceType(t *testing.T) { } else { require.NoError(t, err) } - }) + } - // Supertype: intersection AnyStruct / Any + // Supertype: Resource - t.Run(fmt.Sprintf("resource -> intersection %s with non-conformance type", ty), func(t *testing.T) { + t.Run("intersection type -> type", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface RI {} + _, err := ParseAndCheck(t, + fmt.Sprintf( + ` + struct interface I {} - // NOTE: R does not conform to RI - struct S {} + struct S: I {} - let x = S() - let s = &x as &S - let s2 = s %s &%s{RI} - `, - op, - ty, - ), - ) + let x = S() + let s = &x as &{I} + let s2 = s %s &S + `, + op, + ), + ) + if name == "static" { errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + } else { + require.NoError(t, err) + } + }) - t.Run(fmt.Sprintf("resource -> intersection %s with conformance type", ty), func(t *testing.T) { + t.Run("intersection type -> type: different resource", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface RI {} + _, err := ParseAndCheck(t, + fmt.Sprintf( + ` + struct interface I {} - struct S: RI {} + struct S: I {} - let x = S() - let s = &x as &S - let s2 = s %s &%s{RI} - `, - op, - ty, - ), - ) + struct T: I {} + let x = S() + let s = &x as &{I} + let t = s %s &T + `, + op, + ), + ) + + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { require.NoError(t, err) - }) + } + }) - t.Run(fmt.Sprintf("intersection type -> intersection %s with conformance in type", ty), func(t *testing.T) { + t.Run("intersection -> conforming resource", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface I {} + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + struct interface RI {} - struct S: I {} + struct S: RI {} - let x = S() - let s = &x as &S{I} - let s2 = s %s &%s{I} - `, - op, - ty, - ), - ) + let x = S() + let s = &x as &{RI} + let s2 = s %s &S + `, + op, + ), + ) + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { require.NoError(t, err) - }) + } + }) - t.Run(fmt.Sprintf("intersection type -> intersection %s with conformance not in type", ty), func(t *testing.T) { + t.Run("intersection -> non-conforming resource", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface I1 {} + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + struct interface RI {} - struct interface I2 {} + struct S {} - struct S: I1, I2 {} + let x = S() + let s = &x as &{RI} + let s2 = s %s &S + `, + op, + ), + ) - let x = S() - let s = &x as &S{I1} - let s2 = s %s &%s{I2} - `, - op, - ty, - ), - ) + if name == "static" { + errs := RequireCheckerErrors(t, err, 2) - require.NoError(t, err) - }) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) + } else { + errs := RequireCheckerErrors(t, err, 1) - t.Run(fmt.Sprintf("intersection type -> intersection %s with non-conformance type", ty), func(t *testing.T) { + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } + }) - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface I1 {} + // Supertype: intersection AnyStruct / Any - struct interface I2 {} + t.Run("resource -> intersection with non-conformance type", func(t *testing.T) { - struct S: I1 {} + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + struct interface RI {} + + // NOTE: R does not conform to RI + struct S {} let x = S() - let s = &x as &S{I1} - let s2 = s %s &%s{I2} + let s = &x as &S + let s2 = s %s &{RI} `, - op, - ty, - ), - ) + op, + ), + ) - errs := RequireCheckerErrors(t, err, 1) + errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - for _, otherType := range []sema.Type{ - sema.AnyStructType, - sema.AnyType, - } { + t.Run("resource -> intersection with conformance type", func(t *testing.T) { - t.Run(fmt.Sprintf("intersection %s -> intersection %s: fewer types", ty, otherType), func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + struct interface RI {} - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface I1 {} + struct S: RI {} - struct interface I2 {} + let x = S() + let s = &x as &S + let s2 = s %s &{RI} + `, + op, + ), + ) - struct S: I1, I2 {} + require.NoError(t, err) + }) - let x = S() - let s = &x as &%s{I1, I2} - let s2 = s %s &%s{I2} - `, - ty, - op, - otherType, - ), - ) + t.Run("intersection -> intersection: fewer types", func(t *testing.T) { - if ty == sema.AnyType && otherType == sema.AnyStructType { + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + struct interface I1 {} - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) + struct interface I2 {} - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } + struct S: I1, I2 {} - return - } + let x = S() + let s = &x as &{I1, I2} + let s2 = s %s &{I2} + `, + op, + ), + ) - require.NoError(t, err) - }) + require.NoError(t, err) + }) - t.Run(fmt.Sprintf("intersection %s -> intersection %s: more types", ty, otherType), func(t *testing.T) { + t.Run("intersection -> intersection: more types", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface I1 {} + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + struct interface I1 {} - struct interface I2 {} + struct interface I2 {} - struct S: I1, I2 {} + struct S: I1, I2 {} - let x = S() - let s = &x as &%s{I1} - let s2 = s %s &%s{I1, I2} - `, - ty, - op, - otherType, - ), - ) + let x = S() + let s = &x as &{I1} + let s2 = s %s &{I1, I2} + `, + op, + ), + ) - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { + require.NoError(t, err) + } + }) - t.Run(fmt.Sprintf("intersection %s -> intersection %s with non-conformance type", ty, otherType), func(t *testing.T) { + t.Run("intersection -> intersection %s with non-conformance type", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface I1 {} + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + struct interface I1 {} - struct interface I2 {} + struct interface I2 {} - struct S: I1 {} + struct S: I1 {} - let x = S() - let s = &x as &%s{I1} - let s2 = s %s &%s{I1, I2} - `, - ty, - op, - otherType, - ), - ) + let x = S() + let s = &x as &{I1} + let s2 = s %s &{I1, I2} + `, + op, + ), + ) - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { + require.NoError(t, err) + } + }) - t.Run(fmt.Sprintf("%s -> intersection %s", ty, otherType), func(t *testing.T) { + for _, ty := range []sema.Type{ + sema.AnyStructType, + sema.AnyType, + } { - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface I {} + t.Run(fmt.Sprintf("%s -> type", ty), func(t *testing.T) { - struct S: I {} + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + struct interface RI {} - let x = S() - let s = &x as &%s - let s2 = s %s &%s{I} - `, - ty, - op, - otherType, - ), - ) + struct S: RI {} - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) + let x = S() + let s = &x as &%s + let s2 = s %s &S + `, + ty, + op, + ), + ) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) - // Supertype: AnyStruct / Any + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { + require.NoError(t, err) + } + }) - t.Run(fmt.Sprintf("intersection %s -> %s", ty, otherType), func(t *testing.T) { + t.Run(fmt.Sprintf("%s -> intersection", ty), func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - struct interface I1 {} + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + struct interface I {} - struct interface I2 {} + struct S: I {} - struct S: I1, I2 {} + let x = S() + let s = &x as &%s + let s2 = s %s &{I} + `, + ty, + op, + ), + ) - let x = S() - let s = &x as &%s{I1} - let s2 = s %s &%s - `, - ty, - op, - otherType, - ), - ) + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { require.NoError(t, err) - }) - } + } + }) - t.Run(fmt.Sprintf("intersection type -> %s", ty), func(t *testing.T) { + // Supertype: AnyStruct / Any + + t.Run(fmt.Sprintf("intersection -> %s", ty), func(t *testing.T) { _, err := ParseAndCheckWithAny(t, fmt.Sprintf( ` - struct interface I1 {} + struct interface I1 {} - struct interface I2 {} + struct interface I2 {} - struct S: I1, I2 {} + struct S: I1, I2 {} - let x = S() - let s = &x as &S{I1} - let s2 = s %s &%s - `, + let x = S() + let s = &x as &{I1} + let s2 = s %s &%s + `, op, ty, ), diff --git a/runtime/tests/checker/composite_test.go b/runtime/tests/checker/composite_test.go index 166026925a..962b5da695 100644 --- a/runtime/tests/checker/composite_test.go +++ b/runtime/tests/checker/composite_test.go @@ -847,7 +847,7 @@ func TestCheckInvalidResourceFieldWithMissingResourceAnnotation(t *testing.T) { annotationType := "Test" if isInterface { - annotationType = "AnyResource{Test}" + annotationType = "{Test}" } _, err := ParseAndCheck(t, diff --git a/runtime/tests/checker/contract_test.go b/runtime/tests/checker/contract_test.go index 5348f14d5a..955dfd7359 100644 --- a/runtime/tests/checker/contract_test.go +++ b/runtime/tests/checker/contract_test.go @@ -360,7 +360,7 @@ func TestCheckContractNestedDeclarationOrderOutsideInside(t *testing.T) { annotationType := "R" if isInterface { - annotationType = "AnyResource{R}" + annotationType = "{R}" } t.Run(interfaceKeyword, func(t *testing.T) { @@ -525,21 +525,21 @@ func TestCheckContractNestedDeclarationsComplex(t *testing.T) { switch firstKind { case common.CompositeKindResource: firstQualifiedTypeAnnotation = fmt.Sprintf( - "AnyResource{%s}", + "{%s}", firstQualifiedTypeAnnotation, ) firstLocalTypeAnnotation = fmt.Sprintf( - "AnyResource{%s}", + "{%s}", firstLocalTypeAnnotation, ) case common.CompositeKindStructure: firstQualifiedTypeAnnotation = fmt.Sprintf( - "AnyStruct{%s}", + "{%s}", firstQualifiedTypeAnnotation, ) firstLocalTypeAnnotation = fmt.Sprintf( - "AnyStruct{%s}", + "{%s}", firstLocalTypeAnnotation, ) @@ -552,21 +552,21 @@ func TestCheckContractNestedDeclarationsComplex(t *testing.T) { switch secondKind { case common.CompositeKindResource: secondQualifiedTypeAnnotation = fmt.Sprintf( - "AnyResource{%s}", + "{%s}", secondQualifiedTypeAnnotation, ) secondLocalTypeAnnotation = fmt.Sprintf( - "AnyResource{%s}", + "{%s}", secondLocalTypeAnnotation, ) case common.CompositeKindStructure: secondQualifiedTypeAnnotation = fmt.Sprintf( - "AnyStruct{%s}", + "{%s}", secondQualifiedTypeAnnotation, ) secondLocalTypeAnnotation = fmt.Sprintf( - "AnyStruct{%s}", + "{%s}", secondLocalTypeAnnotation, ) } diff --git a/runtime/tests/checker/dynamic_casting_test.go b/runtime/tests/checker/dynamic_casting_test.go index 96015125c9..1d15204a9f 100644 --- a/runtime/tests/checker/dynamic_casting_test.go +++ b/runtime/tests/checker/dynamic_casting_test.go @@ -731,7 +731,7 @@ func TestCheckDynamicCastingStructInterface(t *testing.T) { types := []string{ "AnyStruct", "S", - "AnyStruct{I}", + "{I}", } for _, operation := range dynamicCastingOperations { @@ -797,7 +797,7 @@ func TestCheckDynamicCastingStructInterface(t *testing.T) { struct interface I2 {} let i: %[1]s = S() - let s: AnyStruct{I2}? = i %[2]s AnyStruct{I2} + let s: {I2}? = i %[2]s {I2} `, fromType, operation.Symbol(), @@ -824,7 +824,7 @@ func TestCheckDynamicCastingResourceInterface(t *testing.T) { types := []string{ "AnyResource", "R", - "AnyResource{I}", + "{I}", } for _, fromType := range types { @@ -952,9 +952,9 @@ func TestCheckDynamicCastingResourceInterface(t *testing.T) { resource interface I2 {} - fun test(): @AnyResource{I2}? { + fun test(): @{I2}? { let i: @%s <- create R() - if let r <- i as? @AnyResource{I2} { + if let r <- i as? @{I2} { return <-r } else { destroy i @@ -986,9 +986,9 @@ func TestCheckDynamicCastingResourceInterface(t *testing.T) { resource interface I2 {} - fun test(): @AnyResource{I2}? { + fun test(): @{I2}? { let i: @%s <- create R() - let r <- i as! @AnyResource{I2} + let r <- i as! @{I2} return <-r } `, diff --git a/runtime/tests/checker/entitlements_test.go b/runtime/tests/checker/entitlements_test.go index ecbad4e702..1791e6d6a0 100644 --- a/runtime/tests/checker/entitlements_test.go +++ b/runtime/tests/checker/entitlements_test.go @@ -2895,14 +2895,14 @@ func TestCheckEntitlementTypeAnnotation(t *testing.T) { _, err := ParseAndCheckAccount(t, ` entitlement E resource interface I { - let e: E{E} + let e: {E} } `) errs := RequireCheckerErrors(t, err, 2) require.IsType(t, &sema.InvalidIntersectedTypeError{}, errs[0]) - require.IsType(t, &sema.InvalidIntersectionTypeError{}, errs[1]) + require.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[1]) }) t.Run("reference", func(t *testing.T) { @@ -3106,14 +3106,14 @@ func TestCheckEntitlementMappingTypeAnnotation(t *testing.T) { _, err := ParseAndCheckAccount(t, ` entitlement mapping E {} resource interface I { - let e: E{E} + let e: {E} } `) errs := RequireCheckerErrors(t, err, 2) require.IsType(t, &sema.InvalidIntersectedTypeError{}, errs[0]) - require.IsType(t, &sema.InvalidIntersectionTypeError{}, errs[1]) + require.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[1]) }) t.Run("reference", func(t *testing.T) { diff --git a/runtime/tests/checker/interface_test.go b/runtime/tests/checker/interface_test.go index 7edfe544a8..30e078f5c7 100644 --- a/runtime/tests/checker/interface_test.go +++ b/runtime/tests/checker/interface_test.go @@ -430,22 +430,9 @@ func TestCheckInvalidInterfaceConformanceIncompatibleCompositeKinds(t *testing.T checker, err := ParseAndCheck(t, code) - // NOTE: type mismatch is only tested when both kinds are not contracts - // (which can not be passed by value) - - if firstKind != common.CompositeKindContract && - secondKind != common.CompositeKindContract { - - errs := RequireCheckerErrors(t, err, 2) - - assert.IsType(t, &sema.CompositeKindMismatchError{}, errs[0]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) - - } else { - errs := RequireCheckerErrors(t, err, 1) + errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.CompositeKindMismatchError{}, errs[0]) - } + assert.IsType(t, &sema.CompositeKindMismatchError{}, errs[0]) require.NotNil(t, checker) @@ -1969,7 +1956,6 @@ func TestCheckInvalidInterfaceUseAsTypeSuggestion(t *testing.T) { { TypeAnnotation: sema.NewTypeAnnotation( &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ iType, }, @@ -1981,7 +1967,6 @@ func TestCheckInvalidInterfaceUseAsTypeSuggestion(t *testing.T) { &sema.DictionaryType{ KeyType: sema.IntType, ValueType: &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ iType, }, @@ -4175,28 +4160,7 @@ func TestCheckInheritedInterfacesSubtyping(t *testing.T) { t.Parallel() - t.Run("intersection composite type subtyping", func(t *testing.T) { - - t.Parallel() - - _, err := ParseAndCheck(t, ` - struct interface A {} - - struct interface B: A {} - - struct S: B {} - - - fun foo(): {A} { - var s: S{B} = S() - return s - } - `) - - require.NoError(t, err) - }) - - t.Run("intersection anystruct type subtyping", func(t *testing.T) { + t.Run("intersection type subtyping", func(t *testing.T) { t.Parallel() @@ -4357,13 +4321,13 @@ func TestCheckInheritedInterfacesSubtyping(t *testing.T) { // Case I: &{B, C} is a subtype of &{B} fun foo(): &{B} { - var s: S{B, C} = S() + var s: {B, C} = S() return &s as &{B, C} } // Case II: &{B} is a subtype of &{A} fun bar(): &{A} { - var s: S{B} = S() + var s: {B} = S() return &s as &{B} } `) @@ -4385,15 +4349,15 @@ func TestCheckInheritedInterfacesSubtyping(t *testing.T) { struct S: B, C {} // Case I: &S{B, C} is a subtype of &S{B} - fun foo(): &S{B} { - var s: S{B, C} = S() - return &s as &S{B, C} + fun foo(): &{B} { + var s: {B, C} = S() + return &s as &{B, C} } - // Case II: &S{B} is a subtype of &S{A} - fun bar(): &S{A} { - var s: S{B} = S() - return &s as &S{B} + // Case II: &{B} is a subtype of &S{A} + fun bar(): &{A} { + var s: {B} = S() + return &s as &{B} } `) @@ -4413,16 +4377,16 @@ func TestCheckInheritedInterfacesSubtyping(t *testing.T) { struct S: B, C {} - // Case I: &S{B, C} is a subtype of &S{B} - fun foo(): &S{B} { - var s: S{B, C} = S() - return &s as &S{B, C} + // Case I: &{B, C} is a subtype of &{B} + fun foo(): &{B} { + var s: {B, C} = S() + return &s as &{B, C} } - // Case II: &S{B, C} is also a subtype of &S{A} - fun bar(): &S{A} { - var s: S{B, C} = S() - return &s as &S{B, C} + // Case II: &{B, C} is also a subtype of &{A} + fun bar(): &{A} { + var s: {B, C} = S() + return &s as &{B, C} } `) diff --git a/runtime/tests/checker/intersection_test.go b/runtime/tests/checker/intersection_test.go index 0d397633fc..5ace34afdc 100644 --- a/runtime/tests/checker/intersection_test.go +++ b/runtime/tests/checker/intersection_test.go @@ -36,10 +36,12 @@ func TestCheckIntersectionType(t *testing.T) { _, err := ParseAndCheck(t, ` resource R {} - let r: @R{} <- create R() + let r: @{} <- create R() `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) t.Run("struct: no types", func(t *testing.T) { @@ -49,10 +51,12 @@ func TestCheckIntersectionType(t *testing.T) { _, err := ParseAndCheck(t, ` struct S {} - let r: S{} = S() + let r: {} = S() `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) t.Run("resource: one type", func(t *testing.T) { @@ -66,7 +70,7 @@ func TestCheckIntersectionType(t *testing.T) { resource R: I1, I2 {} - let r: @R{I1} <- create R() + let r: @{I1} <- create R() `) require.NoError(t, err) @@ -83,7 +87,7 @@ func TestCheckIntersectionType(t *testing.T) { struct S: I1, I2 {} - let r: S{I1} = S() + let r: {I1} = S() `) require.NoError(t, err) @@ -97,10 +101,12 @@ func TestCheckIntersectionType(t *testing.T) { resource R {} let r <- create R() - let ref: &R{} = &r as &R + let ref: &{} = &r as &R `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) t.Run("reference to struct type", func(t *testing.T) { @@ -111,10 +117,12 @@ func TestCheckIntersectionType(t *testing.T) { struct S {} let s = S() - let ref: &S{} = &s as &S + let ref: &{} = &s as &S `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) t.Run("resource: non-conformance type", func(t *testing.T) { @@ -127,12 +135,12 @@ func TestCheckIntersectionType(t *testing.T) { // NOTE: R does not conform to I resource R {} - let r: @R{I} <- create R() + let r: @{I} <- create R() `) errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[0]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) t.Run("struct: non-conformance type", func(t *testing.T) { @@ -145,12 +153,12 @@ func TestCheckIntersectionType(t *testing.T) { // NOTE: S does not conform to I struct S {} - let s: S{I} = S() + let s: {I} = S() `) errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[0]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) t.Run("resource: duplicate type", func(t *testing.T) { @@ -163,7 +171,7 @@ func TestCheckIntersectionType(t *testing.T) { resource R: I {} // NOTE: I is duplicated - let r: @R{I, I} <- create R() + let r: @{I, I} <- create R() `) errs := RequireCheckerErrors(t, err, 1) @@ -181,7 +189,7 @@ func TestCheckIntersectionType(t *testing.T) { struct S: I {} // NOTE: I is duplicated - let s: S{I, I} = S() + let s: {I, I} = S() `) errs := RequireCheckerErrors(t, err, 1) @@ -189,7 +197,7 @@ func TestCheckIntersectionType(t *testing.T) { assert.IsType(t, &sema.InvalidIntersectionTypeDuplicateError{}, errs[0]) }) - t.Run("restricted resource, with structure interface type", func(t *testing.T) { + t.Run("intersection resource, with structure interface type", func(t *testing.T) { t.Parallel() @@ -198,7 +206,7 @@ func TestCheckIntersectionType(t *testing.T) { resource R: I {} - let r: @R{I} <- create R() + let r: {I} = create R() `) errs := RequireCheckerErrors(t, err, 1) @@ -206,7 +214,7 @@ func TestCheckIntersectionType(t *testing.T) { assert.IsType(t, &sema.CompositeKindMismatchError{}, errs[0]) }) - t.Run("restricted struct, with resource interface type", func(t *testing.T) { + t.Run("intersection struct, with resource interface type", func(t *testing.T) { t.Parallel() @@ -215,7 +223,7 @@ func TestCheckIntersectionType(t *testing.T) { struct S: I {} - let s: S{I} = S() + let s: @{I} <- S() `) errs := RequireCheckerErrors(t, err, 1) @@ -223,7 +231,7 @@ func TestCheckIntersectionType(t *testing.T) { assert.IsType(t, &sema.CompositeKindMismatchError{}, errs[0]) }) - t.Run("resource: non-concrete restricted type", func(t *testing.T) { + t.Run("intersection resource interface ", func(t *testing.T) { t.Parallel() @@ -232,51 +240,15 @@ func TestCheckIntersectionType(t *testing.T) { resource R: I {} - let r: @[R]{I} <- [<-create R()] - `) - - errs := RequireCheckerErrors(t, err, 2) - - assert.IsType(t, &sema.InvalidIntersectionTypeError{}, errs[0]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) - }) - - t.Run("struct: non-concrete restricted type", func(t *testing.T) { - - t.Parallel() - - _, err := ParseAndCheck(t, ` - struct interface I {} - - struct S: I {} - - let s: [S]{I} = [S()] - `) - - errs := RequireCheckerErrors(t, err, 2) - - assert.IsType(t, &sema.InvalidIntersectionTypeError{}, errs[0]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) - }) - - t.Run("restricted resource interface ", func(t *testing.T) { - - t.Parallel() - - _, err := ParseAndCheck(t, ` - resource interface I {} - - resource R: I {} - - let r: @I{} <- create R() + let r: @{} <- create R() `) errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.InvalidIntersectionTypeError{}, errs[0]) + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) - t.Run("restricted struct interface", func(t *testing.T) { + t.Run("intersection struct interface", func(t *testing.T) { t.Parallel() @@ -285,15 +257,15 @@ func TestCheckIntersectionType(t *testing.T) { struct S: I {} - let s: I{} = S() + let s: {} = S() `) errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.InvalidIntersectionTypeError{}, errs[0]) + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) - t.Run("restricted type requirement", func(t *testing.T) { + t.Run("intersection type requirement", func(t *testing.T) { t.Parallel() @@ -316,7 +288,7 @@ func TestCheckIntersectionType(t *testing.T) { fun test() { let r <- C.createR() - let r2: @CI.R{CI.RI} <- r + let r2: @{CI.RI} <- r destroy r2 } `) @@ -324,55 +296,10 @@ func TestCheckIntersectionType(t *testing.T) { }) } -func TestCheckRestrictedTypeMemberAccess(t *testing.T) { +func TestCheckIntersectionTypeMemberAccess(t *testing.T) { t.Parallel() - t.Run("no types: resource", func(t *testing.T) { - - _, err := ParseAndCheck(t, ` - resource R { - let n: Int - - init(n: Int) { - self.n = n - } - } - - fun test() { - let r: @R{} <- create R(n: 1) - r.n - destroy r - } - `) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.InvalidIntersectionTypeMemberAccessError{}, errs[0]) - }) - - t.Run("no types: struct", func(t *testing.T) { - - _, err := ParseAndCheck(t, ` - struct S { - let n: Int - - init(n: Int) { - self.n = n - } - } - - fun test() { - let s: S{} = S(n: 1) - s.n - } - `) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.InvalidIntersectionTypeMemberAccessError{}, errs[0]) - }) - t.Run("type with member: resource", func(t *testing.T) { _, err := ParseAndCheck(t, ` @@ -390,7 +317,7 @@ func TestCheckRestrictedTypeMemberAccess(t *testing.T) { } fun test() { - let r: @R{I} <- create R(n: 1) + let r: @{I} <- create R(n: 1) r.n destroy r } @@ -416,7 +343,7 @@ func TestCheckRestrictedTypeMemberAccess(t *testing.T) { } fun test() { - let s: S{I} = S(n: 1) + let s: {I} = S(n: 1) s.n } `) @@ -441,7 +368,7 @@ func TestCheckRestrictedTypeMemberAccess(t *testing.T) { } fun test() { - let r: @R{I} <- create R(n: 1) + let r: @{I} <- create R(n: 1) r.n destroy r } @@ -449,7 +376,7 @@ func TestCheckRestrictedTypeMemberAccess(t *testing.T) { errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.InvalidIntersectionTypeMemberAccessError{}, errs[0]) + assert.IsType(t, &sema.NotDeclaredMemberError{}, errs[0]) }) t.Run("type without member: struct", func(t *testing.T) { @@ -469,14 +396,14 @@ func TestCheckRestrictedTypeMemberAccess(t *testing.T) { } fun test() { - let s: S{I} = S(n: 1) + let s: {I} = S(n: 1) s.n } `) errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.InvalidIntersectionTypeMemberAccessError{}, errs[0]) + assert.IsType(t, &sema.NotDeclaredMemberError{}, errs[0]) }) t.Run("types with clashing members: resource", func(t *testing.T) { @@ -500,7 +427,7 @@ func TestCheckRestrictedTypeMemberAccess(t *testing.T) { } fun test() { - let r: @R{I1, I2} <- create R(n: 1) + let r: @{I1, I2} <- create R(n: 1) r.n destroy r } @@ -533,7 +460,7 @@ func TestCheckRestrictedTypeMemberAccess(t *testing.T) { } fun test() { - let s: S{I1, I2} = S(n: 1) + let s: {I1, I2} = S(n: 1) s.n } `) @@ -545,38 +472,42 @@ func TestCheckRestrictedTypeMemberAccess(t *testing.T) { }) } -func TestCheckRestrictedTypeSubtyping(t *testing.T) { +func TestCheckIntersectionTypeSubtyping(t *testing.T) { t.Parallel() - t.Run("resource type to restricted type with same type, no type", func(t *testing.T) { + t.Run("resource type to intersection type with same type, no type", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` resource R {} fun test() { - let r: @R{} <- create R() + let r: @{} <- create R() destroy r } `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) - t.Run("struct type to restricted type with same type, no type", func(t *testing.T) { + t.Run("struct type to intersection type with same type, no type", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` struct S {} - let s: S{} = S() + let s: {} = S() `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) - t.Run("resource type to restricted type with same type, one type", func(t *testing.T) { + t.Run("resource type to intersection type with same type, one type", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -587,7 +518,7 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { resource R: I1, I2 {} fun test() { - let r: @R{I1} <- create R() + let r: @{I1} <- create R() destroy r } `) @@ -595,7 +526,7 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { require.NoError(t, err) }) - t.Run("struct type to restricted type with same type, one type", func(t *testing.T) { + t.Run("struct type to intersection type with same type, one type", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -605,13 +536,13 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { struct S: I1, I2 {} - let s: S{I1} = S() + let s: {I1} = S() `) require.NoError(t, err) }) - t.Run("resource type to restricted type with different restricted type", func(t *testing.T) { + t.Run("resource type to intersection type with different intersection type", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -620,17 +551,17 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { resource S {} fun test() { - let s: @S{} <- create R() + let s: @{} <- create R() destroy s } `) errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) - t.Run("struct type to restricted type with different restricted type", func(t *testing.T) { + t.Run("struct type to intersection type with different intersection type", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -638,46 +569,52 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { struct S {} - let s: S{} = R() + let s: {} = R() `) errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) - t.Run("restricted resource type to restricted type with same type, no types", func(t *testing.T) { + t.Run("intersection resource type to intersection type with same type, no types", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` resource R {} fun test() { - let r: @R{} <- create R() - let r2: @R{} <- r + let r: @{} <- create R() + let r2: @{} <- r destroy r2 } `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 2) + + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[1]) }) - t.Run("restricted struct type to restricted type with same type, no types", func(t *testing.T) { + t.Run("intersection struct type to intersection type with same type, no types", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` struct S {} fun test() { - let s: S{} = S() - let s2: S{} = s + let s: {} = S() + let s2: {} = s } `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 2) + + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[1]) }) - t.Run("restricted resource type to restricted type with same type, 0 to 1 type", func(t *testing.T) { + t.Run("intersection resource type to intersection type with same type, 0 to 1 type", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -688,16 +625,18 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { resource R: I1, I2 {} fun test() { - let r: @R{} <- create R() - let r2: @R{I1} <- r + let r: @{} <- create R() + let r2: @{I1} <- r destroy r2 } `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) - t.Run("restricted struct type to restricted type with same type, 0 to 1 type", func(t *testing.T) { + t.Run("intersection struct type to intersection type with same type, 0 to 1 type", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -707,14 +646,16 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { struct S: I1, I2 {} - let s: S{} = S() - let s2: S{I1} = s + let s: {} = S() + let s2: {I1} = s `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) }) - t.Run("restricted resource type to restricted type with same type, 1 to 2 types", func(t *testing.T) { + t.Run("intersection resource type to intersection type with same type, 1 to 2 types", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -725,16 +666,18 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { resource R: I1, I2 {} fun test() { - let r: @R{I2} <- create R() - let r2: @R{I1, I2} <- r + let r: @{I2} <- create R() + let r2: @{I1, I2} <- r destroy r2 } `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) - t.Run("restricted struct type to restricted type with same type, 1 to 2 types", func(t *testing.T) { + t.Run("intersection struct type to intersection type with same type, 1 to 2 types", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -745,14 +688,16 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { struct S: I1, I2 {} - let s: S{I2} = S() - let s2: S{I1, I2} = s + let s: {I2} = S() + let s2: {I1, I2} = s `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) - t.Run("restricted resource type to restricted type with same type, reordered types", func(t *testing.T) { + t.Run("intersection resource type to intersection type with same type, reordered types", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -763,8 +708,8 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { resource R: I1, I2 {} fun test() { - let r: @R{I2, I1} <- create R() - let r2: @R{I1, I2} <- r + let r: @{I2, I1} <- create R() + let r2: @{I1, I2} <- r destroy r2 } `) @@ -772,7 +717,7 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { require.NoError(t, err) }) - t.Run("restricted struct type to restricted type with same type, reordered types", func(t *testing.T) { + t.Run("intersection struct type to intersection type with same type, reordered types", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -782,14 +727,14 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { struct S: I1, I2 {} - let s: S{I2, I1} = S() - let s2: S{I1, I2} = s + let s: {I2, I1} = S() + let s2: {I1, I2} = s `) require.NoError(t, err) }) - t.Run("restricted resource type to restricted type with same type, fewer types", func(t *testing.T) { + t.Run("intersection resource type to intersection type with same type, fewer types", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -800,8 +745,8 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { resource R: I1, I2 {} fun test() { - let r: @R{I1, I2} <- create R() - let r2: @R{I2} <- r + let r: @{I1, I2} <- create R() + let r2: @{I2} <- r destroy r2 } `) @@ -809,7 +754,7 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { require.NoError(t, err) }) - t.Run("restricted struct type to restricted type with same type, fewer types", func(t *testing.T) { + t.Run("intersection struct type to intersection type with same type, fewer types", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -819,14 +764,14 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { struct S: I1, I2 {} - let s: S{I1, I2} = S() - let s2: S{I2} = s + let s: {I1, I2} = S() + let s2: {I2} = s `) require.NoError(t, err) }) - t.Run("restricted resource type to resource type", func(t *testing.T) { + t.Run("intersection resource type to resource type", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -837,16 +782,18 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { resource R: I1, I2 {} fun test() { - let r: @R{I1} <- create R() + let r: @{I1} <- create R() let r2: @R <- r destroy r2 } `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) - t.Run("restricted struct type to struct type", func(t *testing.T) { + t.Run("intersection struct type to struct type", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -856,15 +803,17 @@ func TestCheckRestrictedTypeSubtyping(t *testing.T) { struct S: I1, I2 {} - let s: S{I1} = S() + let s: {I1} = S() let s2: S = s `) - require.NoError(t, err) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) } -func TestCheckRestrictedTypeNoType(t *testing.T) { +func TestCheckIntersectionTypeNoType(t *testing.T) { t.Parallel() @@ -924,8 +873,6 @@ func TestCheckRestrictedTypeNoType(t *testing.T) { ty := rType.(*sema.IntersectionType) - assert.IsType(t, sema.AnyResourceType, ty.Type) - require.Len(t, ty.Types, 1) assert.Same(t, RequireGlobalType(t, checker.Elaboration, "I1"), @@ -949,8 +896,6 @@ func TestCheckRestrictedTypeNoType(t *testing.T) { ty := rType.(*sema.IntersectionType) - assert.IsType(t, sema.AnyStructType, ty.Type) - require.Len(t, ty.Types, 1) assert.Same(t, RequireGlobalType(t, checker.Elaboration, "I1"), @@ -974,8 +919,6 @@ func TestCheckRestrictedTypeNoType(t *testing.T) { ty := rType.(*sema.IntersectionType) - assert.IsType(t, sema.AnyResourceType, ty.Type) - require.Len(t, ty.Types, 2) assert.Same(t, RequireGlobalType(t, checker.Elaboration, "I1"), @@ -1003,8 +946,6 @@ func TestCheckRestrictedTypeNoType(t *testing.T) { ty := rType.(*sema.IntersectionType) - assert.IsType(t, sema.AnyStructType, ty.Type) - require.Len(t, ty.Types, 2) assert.Same(t, RequireGlobalType(t, checker.Elaboration, "I1"), @@ -1049,8 +990,6 @@ func TestCheckRestrictedTypeNoType(t *testing.T) { ty := rType.(*sema.IntersectionType) - assert.IsType(t, sema.AnyResourceType, ty.Type) - require.Len(t, ty.Types, 1) assert.Same(t, RequireGlobalType(t, checker.Elaboration, "I1"), @@ -1077,8 +1016,6 @@ func TestCheckRestrictedTypeNoType(t *testing.T) { ty := rType.(*sema.IntersectionType) - assert.IsType(t, sema.AnyStructType, ty.Type) - require.Len(t, ty.Types, 1) assert.Same(t, RequireGlobalType(t, checker.Elaboration, "I1"), @@ -1105,8 +1042,6 @@ func TestCheckRestrictedTypeNoType(t *testing.T) { ty := rType.(*sema.IntersectionType) - assert.IsType(t, sema.AnyResourceType, ty.Type) - require.Len(t, ty.Types, 2) assert.Same(t, RequireGlobalType(t, checker.Elaboration, "I1"), @@ -1137,8 +1072,6 @@ func TestCheckRestrictedTypeNoType(t *testing.T) { ty := rType.(*sema.IntersectionType) - assert.IsType(t, sema.AnyStructType, ty.Type) - require.Len(t, ty.Types, 2) assert.Same(t, RequireGlobalType(t, checker.Elaboration, "I1"), @@ -1151,7 +1084,7 @@ func TestCheckRestrictedTypeNoType(t *testing.T) { }) } -func TestCheckRestrictedTypeConformanceOrder(t *testing.T) { +func TestCheckIntersectionTypeConformanceOrder(t *testing.T) { t.Parallel() @@ -1166,34 +1099,17 @@ func TestCheckRestrictedTypeConformanceOrder(t *testing.T) { contract C { resource interface RI {} resource R: RI {} - fun foo(): &R{RI} { panic("") } + fun foo(): &{RI} { panic("") } } `) require.NoError(t, err) }) - t.Run("invalid", func(t *testing.T) { - - t.Parallel() - - _, err := ParseAndCheckWithPanic(t, ` - contract C { - resource interface RI {} - resource R {} - fun foo(): &R{RI} { panic("") } - } - `) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.InvalidNonConformanceIntersectionError{}, errs[0]) - }) - } // https://github.com/onflow/cadence/issues/326 -func TestCheckRestrictedConformance(t *testing.T) { +func TestCheckIntersectionConformance(t *testing.T) { t.Parallel() @@ -1202,13 +1118,13 @@ func TestCheckRestrictedConformance(t *testing.T) { contract C { resource interface RI { - fun get(): &R{RI} + fun get(): &{RI} } resource R: RI { - fun get(): &R{RI} { - return &self as &R{RI} + fun get(): &{RI} { + return &self as &{RI} } } } diff --git a/runtime/tests/checker/nesting_test.go b/runtime/tests/checker/nesting_test.go index 9fc3a7813e..4f235ee487 100644 --- a/runtime/tests/checker/nesting_test.go +++ b/runtime/tests/checker/nesting_test.go @@ -164,9 +164,9 @@ func TestCheckCompositeDeclarationNestedStructInterfaceUse(t *testing.T) { struct X: XI {} - var xi: AnyStruct{XI} + var xi: {XI} - init(xi: AnyStruct{XI}) { + init(xi: {XI}) { self.xi = xi } diff --git a/runtime/tests/checker/reference_test.go b/runtime/tests/checker/reference_test.go index bb222587e4..34a8121334 100644 --- a/runtime/tests/checker/reference_test.go +++ b/runtime/tests/checker/reference_test.go @@ -463,7 +463,7 @@ func TestCheckReferenceExpressionWithIntersectionAnyResultType(t *testing.T) { resource R: I {} let r <- create R() - let ref = &r as &AnyResource{I} + let ref = &r as &{I} `) require.NoError(t, err) @@ -478,7 +478,7 @@ func TestCheckReferenceExpressionWithIntersectionAnyResultType(t *testing.T) { struct S: I {} let s = S() - let ref = &s as &AnyStruct{I} + let ref = &s as &{I} `) require.NoError(t, err) @@ -944,7 +944,7 @@ func TestCheckResourceInterfaceReferenceFunctionCall(t *testing.T) { fun test() { let r <- create R() - let ref = &r as &AnyResource{I} + let ref = &r as &{I} ref.foo() destroy r } @@ -969,7 +969,7 @@ func TestCheckResourceInterfaceReferenceFunctionCall(t *testing.T) { fun test() { let s = S() - let ref = &s as &AnyStruct{I} + let ref = &s as &{I} ref.foo() } `) @@ -996,7 +996,7 @@ func TestCheckInvalidResourceInterfaceReferenceFunctionCall(t *testing.T) { fun test() { let r <- create R() - let ref = &r as &AnyResource{I} + let ref = &r as &{I} ref.foo() destroy r } @@ -1021,7 +1021,7 @@ func TestCheckInvalidResourceInterfaceReferenceFunctionCall(t *testing.T) { fun test() { let s = S() - let ref = &s as &AnyStruct{I} + let ref = &s as &{I} ref.foo() } `) @@ -1257,33 +1257,17 @@ func TestCheckInvalidReferenceExpressionNonReferenceAmbiguous(t *testing.T) { assert.IsType(t, &sema.NotDeclaredError{}, errs[1]) } -func TestCheckInvalidReferenceExpressionNonReferenceAnyResource(t *testing.T) { - - t.Parallel() - - _, err := ParseAndCheck(t, ` - let y = &x as AnyResource{} - `) - - errs := RequireCheckerErrors(t, err, 4) - - assert.IsType(t, &sema.MissingResourceAnnotationError{}, errs[0]) - assert.IsType(t, &sema.NonReferenceTypeReferenceError{}, errs[1]) - assert.IsType(t, &sema.NotDeclaredError{}, errs[2]) - assert.IsType(t, &sema.IncorrectTransferOperationError{}, errs[3]) -} - func TestCheckInvalidReferenceExpressionNonReferenceAnyStruct(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` - let y = &x as AnyStruct{} + let y = &x as {} `) errs := RequireCheckerErrors(t, err, 2) - assert.IsType(t, &sema.NonReferenceTypeReferenceError{}, errs[0]) + assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0]) assert.IsType(t, &sema.NotDeclaredError{}, errs[1]) } diff --git a/runtime/tests/checker/resources_test.go b/runtime/tests/checker/resources_test.go index 6d4f3d400d..896fdac034 100644 --- a/runtime/tests/checker/resources_test.go +++ b/runtime/tests/checker/resources_test.go @@ -5239,7 +5239,7 @@ func TestCheckIntersectionAnyResourceType(t *testing.T) { resource R: RI {} - let ri: @AnyResource{RI} <- create R() + let ri: @{RI} <- create R() `) require.NoError(t, err) @@ -5251,7 +5251,7 @@ func TestCheckIntersectionAnyResourceType(t *testing.T) { resource R: RI {} - let ri: @[AnyResource{RI}] <- [<-create R()] + let ri: @[{RI}] <- [<-create R()] `) require.NoError(t, err) diff --git a/runtime/tests/checker/runtimetype_test.go b/runtime/tests/checker/runtimetype_test.go index c605bafbab..d2f0e2cc3f 100644 --- a/runtime/tests/checker/runtimetype_test.go +++ b/runtime/tests/checker/runtimetype_test.go @@ -690,17 +690,17 @@ func TestCheckIntersectionTypeConstructor(t *testing.T) { expectedError error }{ { - name: "S{I1, I2}", + name: "{I1, I2}", code: ` - let result = IntersectionType(identifier: "S", types: ["I1", "I2"]) + let result = IntersectionType(types: ["I1", "I2"]) `, expectedError: nil, }, { - name: "S{}", + name: "{}", code: ` struct S {} - let result = IntersectionType(identifier: "S", types: []) + let result = IntersectionType(types: []) `, expectedError: nil, }, @@ -708,37 +708,23 @@ func TestCheckIntersectionTypeConstructor(t *testing.T) { name: "{S}", code: ` struct S {} - let result = IntersectionType(identifier: nil, types: ["S"]) + let result = IntersectionType(types: ["S"]) `, expectedError: nil, }, - { - name: "type mismatch first arg", - code: ` - let result = IntersectionType(identifier: 3, types: ["I"]) - `, - expectedError: &sema.TypeMismatchError{}, - }, - { - name: "type mismatch second arg", - code: ` - let result = IntersectionType(identifier: "A", types: [3]) - `, - expectedError: &sema.TypeMismatchError{}, - }, { name: "too many args", code: ` - let result = IntersectionType(identifier: "A", types: ["I1"], ["I2"]) + let result = IntersectionType(types: ["I1"], identifier: "A", ) `, expectedError: &sema.ArgumentCountError{}, }, { - name: "one arg", + name: "wrong typed arg", code: ` - let result = IntersectionType(identifier: "A") + let result = IntersectionType(types: "A") `, - expectedError: &sema.ArgumentCountError{}, + expectedError: &sema.TypeMismatchError{}, }, { name: "no args", @@ -748,16 +734,9 @@ func TestCheckIntersectionTypeConstructor(t *testing.T) { expectedError: &sema.ArgumentCountError{}, }, { - name: "missing first label", - code: ` - let result = IntersectionType("S", types: ["I1", "I2"]) - `, - expectedError: &sema.MissingArgumentLabelError{}, - }, - { - name: "missing second label", + name: "missing label", code: ` - let result = IntersectionType(identifier: "S", ["I1", "I2"]) + let result = IntersectionType(["I1", "I2"]) `, expectedError: &sema.MissingArgumentLabelError{}, }, diff --git a/runtime/tests/checker/type_inference_test.go b/runtime/tests/checker/type_inference_test.go index 5e9ebc13b6..dee22a8101 100644 --- a/runtime/tests/checker/type_inference_test.go +++ b/runtime/tests/checker/type_inference_test.go @@ -829,7 +829,6 @@ func TestCheckArraySupertypeInference(t *testing.T) { access(all) struct Baz: I1, I2, I3 {} `, expectedElementType: &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ { Location: common.StringLocation("test"), @@ -852,7 +851,6 @@ func TestCheckArraySupertypeInference(t *testing.T) { `, expectedElementType: &sema.VariableSizedType{ Type: &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ { Location: common.StringLocation("test"), @@ -877,7 +875,6 @@ func TestCheckArraySupertypeInference(t *testing.T) { `, expectedElementType: &sema.VariableSizedType{ Type: &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ { Location: common.StringLocation("test"), @@ -1030,7 +1027,6 @@ func TestCheckDictionarySupertypeInference(t *testing.T) { `, expectedKeyType: sema.IntType, expectedValueType: &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ { Location: common.StringLocation("test"), @@ -1055,7 +1051,6 @@ func TestCheckDictionarySupertypeInference(t *testing.T) { expectedValueType: &sema.DictionaryType{ KeyType: sema.IntType, ValueType: &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ { Location: common.StringLocation("test"), @@ -1082,7 +1077,6 @@ func TestCheckDictionarySupertypeInference(t *testing.T) { expectedValueType: &sema.DictionaryType{ KeyType: sema.IntType, ValueType: &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ { Location: common.StringLocation("test"), @@ -1191,7 +1185,7 @@ func TestCheckTypeInferenceForTypesWithDifferentTypeMaskRanges(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` - let x: @AnyResource{Foo} <- create Bar() + let x: @{Foo} <- create Bar() let y = [<-x, 6] resource interface Foo {} @@ -1207,7 +1201,7 @@ func TestCheckTypeInferenceForTypesWithDifferentTypeMaskRanges(t *testing.T) { t.Parallel() checker, err := ParseAndCheck(t, ` - let x: AnyStruct{Foo} = Bar() + let x: {Foo} = Bar() let y = true ? x : nil struct interface Foo {} @@ -1244,7 +1238,6 @@ func TestCheckCompositeSupertypeInference(t *testing.T) { ` expectedType := &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ { Location: common.StringLocation("test"), diff --git a/runtime/tests/interpreter/attachments_test.go b/runtime/tests/interpreter/attachments_test.go index 4fe6299ce9..bc9cde98d1 100644 --- a/runtime/tests/interpreter/attachments_test.go +++ b/runtime/tests/interpreter/attachments_test.go @@ -1346,8 +1346,8 @@ func TestInterpretAttachmentStorage(t *testing.T) { let r <- create R() let r2 <- attach A() to <-r authAccount.save(<-r2, to: /storage/foo) - authAccount.link<&R{I}>(/public/foo, target: /storage/foo) - let cap = pubAccount.getCapability<&R{I}>(/public/foo)! + authAccount.link<&{I}>(/public/foo, target: /storage/foo) + let cap = pubAccount.getCapability<&{I}>(/public/foo)! let i = cap.borrow()![A]?.foo()! return i } diff --git a/runtime/tests/interpreter/dynamic_casting_test.go b/runtime/tests/interpreter/dynamic_casting_test.go index bd9538030a..765bc28e9c 100644 --- a/runtime/tests/interpreter/dynamic_casting_test.go +++ b/runtime/tests/interpreter/dynamic_casting_test.go @@ -963,7 +963,7 @@ func TestInterpretDynamicCastingStructInterface(t *testing.T) { types := []string{ "AnyStruct", "S", - "AnyStruct{I}", + "{I}", } for operation := range dynamicCastingOperations { @@ -1015,7 +1015,7 @@ func TestInterpretDynamicCastingResourceInterface(t *testing.T) { types := []string{ "AnyResource", "R", - "AnyResource{I}", + "{I}", } for operation := range dynamicCastingOperations { @@ -1487,8 +1487,8 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "R{I1, I2}", - "R{I2}", + "{I1, I2}", + "{I2}", operation, ) }) @@ -1503,53 +1503,8 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "R{I1}", - "R{I1, I2}", - operation, - ) - }) - - t.Run("type -> intersection type: same resource", func(t *testing.T) { - - testResourceCastValid(t, - ` - resource interface I {} - - resource R: I {} - `, - "R", - "R{I}", - operation, - ) - }) - - t.Run("intersection AnyResource -> conforming intersection type", func(t *testing.T) { - - testResourceCastValid(t, - ` - resource interface RI {} - - resource R: RI {} - `, - "AnyResource{RI}", - "R{RI}", - operation, - ) - }) - - // TODO: should statically fail? - t.Run("intersection AnyResource -> non-conforming intersection type", func(t *testing.T) { - - testResourceCastInvalid(t, - ` - resource interface RI {} - - resource R: RI {} - - resource T {} - `, - "AnyResource{RI}", - "T{}", + "{I1}", + "{I1, I2}", operation, ) }) @@ -1563,7 +1518,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: RI {} `, "AnyResource", - "R{RI}", + "{RI}", operation, ) }) @@ -1579,7 +1534,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource T: TI {} `, "AnyResource", - "T{TI}", + "{TI}", operation, ) }) @@ -1594,13 +1549,13 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I {} `, - "R{I}", + "{I}", "R", operation, ) }) - t.Run("intersection AnyResource -> conforming resource", func(t *testing.T) { + t.Run("intersection -> conforming resource", func(t *testing.T) { testResourceCastValid(t, ` @@ -1608,13 +1563,13 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: RI {} `, - "AnyResource{RI}", + "{RI}", "R", operation, ) }) - t.Run("intersection AnyResource -> non-conforming resource", func(t *testing.T) { + t.Run("intersection -> non-conforming resource", func(t *testing.T) { testResourceCastInvalid(t, ` @@ -1624,7 +1579,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource T: RI {} `, - "AnyResource{RI}", + "{RI}", "T", operation, ) @@ -1673,26 +1628,12 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: RI {} `, "R", - "AnyResource{RI}", + "{RI}", operation, ) }) - t.Run("intersection type -> intersection AnyResource with conformance in type", func(t *testing.T) { - - testResourceCastValid(t, - ` - resource interface I {} - - resource R: I {} - `, - "R{I}", - "AnyResource{I}", - operation, - ) - }) - - t.Run("intersection type -> intersection AnyResource with conformance not in type", func(t *testing.T) { + t.Run("intersection type -> intersection with conformance not in type", func(t *testing.T) { testResourceCastValid(t, ` @@ -1702,13 +1643,13 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "R{I1}", - "AnyResource{I2}", + "{I1}", + "{I2}", operation, ) }) - t.Run("intersection AnyResource -> intersection AnyResource: fewer types", func(t *testing.T) { + t.Run("intersection -> intersection: fewer types", func(t *testing.T) { testResourceCastValid(t, ` @@ -1718,13 +1659,13 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "AnyResource{I1, I2}", - "AnyResource{I2}", + "{I1, I2}", + "{I2}", operation, ) }) - t.Run("intersection AnyResource -> intersection AnyResource: more types", func(t *testing.T) { + t.Run("intersection -> intersection: more types", func(t *testing.T) { testResourceCastValid(t, ` @@ -1734,13 +1675,13 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "AnyResource{I1}", - "AnyResource{I1, I2}", + "{I1}", + "{I1, I2}", operation, ) }) - t.Run("intersection AnyResource -> intersection AnyResource: different types, conforming", func(t *testing.T) { + t.Run("intersection -> intersection: different types, conforming", func(t *testing.T) { testResourceCastValid(t, ` @@ -1750,13 +1691,13 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "AnyResource{I1}", - "AnyResource{I2}", + "{I1}", + "{I2}", operation, ) }) - t.Run("intersection AnyResource -> intersection AnyResource: different types, non-conforming", func(t *testing.T) { + t.Run("intersection -> intersection: different types, non-conforming", func(t *testing.T) { testResourceCastInvalid(t, ` @@ -1767,13 +1708,13 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1 {} `, - "AnyResource{I1}", - "AnyResource{I2}", + "{I1}", + "{I2}", operation, ) }) - t.Run("intersection AnyResource -> intersection AnyResource with non-conformance type", func(t *testing.T) { + t.Run("intersection -> intersection with non-conformance type", func(t *testing.T) { testResourceCastInvalid(t, ` @@ -1783,13 +1724,13 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1 {} `, - "AnyResource{I1}", - "AnyResource{I1, I2}", + "{I1}", + "{I1, I2}", operation, ) }) - t.Run("AnyResource -> intersection AnyResource", func(t *testing.T) { + t.Run("AnyResource -> intersection", func(t *testing.T) { testResourceCastValid(t, ` @@ -1798,30 +1739,14 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I {} `, "AnyResource", - "AnyResource{I}", + "{I}", operation, ) }) // Supertype: AnyResource - t.Run("intersection type -> AnyResource", func(t *testing.T) { - - testResourceCastValid(t, - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1, I2 {} - `, - "R{I1}", - "AnyResource", - operation, - ) - }) - - t.Run("intersection AnyResource -> AnyResource", func(t *testing.T) { + t.Run("intersection -> AnyResource", func(t *testing.T) { testResourceCastValid(t, ` @@ -1831,7 +1756,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "AnyResource{I1}", + "{I1}", "AnyResource", operation, ) @@ -1876,8 +1801,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "S{I1, I2}", - "S{I2}", + "{I1, I2}", + "{I2}", operation, ) }) @@ -1892,8 +1817,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "S{I1}", - "S{I1, I2}", + "{I1}", + "{I1, I2}", operation, ) }) @@ -1907,38 +1832,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I {} `, "S", - "S{I}", - operation, - ) - }) - - t.Run("intersection AnyStruct -> conforming intersection type", func(t *testing.T) { - - testStructCastValid(t, - ` - struct interface SI {} - - struct S: SI {} - `, - "AnyStruct{SI}", - "S{SI}", - operation, - ) - }) - - // TODO: should statically fail? - t.Run("intersection AnyStruct -> non-conforming intersection type", func(t *testing.T) { - - testStructCastInvalid(t, - ` - struct interface SI {} - - struct S: SI {} - - struct T {} - `, - "AnyStruct{SI}", - "T{}", + "{I}", operation, ) }) @@ -1952,7 +1846,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: SI {} `, "AnyStruct", - "S{SI}", + "{SI}", operation, ) }) @@ -1968,7 +1862,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct T: TI {} `, "AnyStruct", - "T{TI}", + "{TI}", operation, ) }) @@ -1983,7 +1877,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I {} `, - "S{I}", + "{I}", "S", operation, ) @@ -1997,7 +1891,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: SI {} `, - "AnyStruct{SI}", + "{SI}", "S", operation, ) @@ -2013,7 +1907,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct T: SI {} `, - "AnyStruct{SI}", + "{SI}", "T", operation, ) @@ -2051,9 +1945,9 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { ) }) - // Supertype: intersection AnyStruct + // Supertype: intersection - t.Run("struct -> intersection AnyStruct with conformance type", func(t *testing.T) { + t.Run("struct -> intersection with conformance type", func(t *testing.T) { testStructCastValid(t, ` @@ -2062,26 +1956,12 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: SI {} `, "S", - "AnyStruct{SI}", + "{SI}", operation, ) }) - t.Run("intersection type -> intersection AnyStruct with conformance in type", func(t *testing.T) { - - testStructCastValid(t, - ` - struct interface I {} - - struct S: I {} - `, - "S{I}", - "AnyStruct{I}", - operation, - ) - }) - - t.Run("intersection type -> intersection AnyStruct with conformance not in type", func(t *testing.T) { + t.Run("intersection type -> intersection with conformance not in type", func(t *testing.T) { testStructCastValid(t, ` @@ -2091,13 +1971,13 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "S{I1}", - "AnyStruct{I2}", + "{I1}", + "{I2}", operation, ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct: fewer types", func(t *testing.T) { + t.Run("intersection -> intersection: fewer types", func(t *testing.T) { testStructCastValid(t, ` @@ -2107,13 +1987,13 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "AnyStruct{I1, I2}", - "AnyStruct{I2}", + "{I1, I2}", + "{I2}", operation, ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct: more types", func(t *testing.T) { + t.Run("intersection -> intersection: more types", func(t *testing.T) { testStructCastValid(t, ` @@ -2123,13 +2003,13 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "AnyStruct{I1}", - "AnyStruct{I1, I2}", + "{I1}", + "{I1, I2}", operation, ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct: different types, conforming", func(t *testing.T) { + t.Run("intersection -> intersection: different types, conforming", func(t *testing.T) { testStructCastValid(t, ` @@ -2139,13 +2019,13 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "AnyStruct{I1}", - "AnyStruct{I2}", + "{I1}", + "{I2}", operation, ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct: different types, non-conforming", func(t *testing.T) { + t.Run("intersection -> intersection: different types, non-conforming", func(t *testing.T) { testStructCastInvalid(t, ` @@ -2156,8 +2036,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1 {} `, - "AnyStruct{I1}", - "AnyStruct{I2}", + "{I1}", + "{I2}", operation, ) }) @@ -2172,8 +2052,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1 {} `, - "AnyStruct{I1}", - "AnyStruct{I1, I2}", + "{I1}", + "{I1, I2}", operation, ) }) @@ -2187,7 +2067,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I {} `, "AnyStruct", - "AnyStruct{I}", + "{I}", operation, ) }) @@ -2204,13 +2084,13 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "S{I1}", + "{I1}", "AnyStruct", operation, ) }) - t.Run("intersection AnyStruct -> AnyStruct", func(t *testing.T) { + t.Run("intersection -> AnyStruct", func(t *testing.T) { testStructCastValid(t, ` @@ -2220,7 +2100,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "AnyStruct{I1}", + "{I1}", "AnyStruct", operation, ) @@ -2426,8 +2306,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &R{I1, I2}", - "&R{I2}", + "auth(E) &{I1, I2}", + "&{I2}", operation, true, ) @@ -2445,8 +2325,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &R{I1}", - "&R{I1, I2}", + "auth(E) &{I1}", + "&{I1, I2}", operation, true, ) @@ -2463,7 +2343,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &R", - "&R{I}", + "&{I}", operation, true, ) @@ -2479,28 +2359,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{RI}", - "&R{RI}", - operation, - true, - ) - }) - - // TODO: should statically fail? - t.Run("intersection AnyResource -> non-conforming intersection type", func(t *testing.T) { - - testReferenceCastInvalid(t, - ` - resource interface RI {} - - resource R: RI {} - - resource T {} - - entitlement E - `, - "auth(E) &AnyResource{RI}", - "&T{}", + "auth(E) &{RI}", + "&{RI}", operation, true, ) @@ -2517,7 +2377,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyResource", - "&R{RI}", + "&{RI}", operation, true, ) @@ -2536,7 +2396,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyResource", - "&T{TI}", + "&{TI}", operation, true, ) @@ -2554,7 +2414,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &R{I}", + "auth(E) &{I}", "&R", operation, true, @@ -2571,7 +2431,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{RI}", + "auth(E) &{RI}", "&R", operation, true, @@ -2590,7 +2450,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{RI}", + "auth(E) &{RI}", "&T", operation, true, @@ -2645,7 +2505,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &R", - "&AnyResource{RI}", + "&{RI}", operation, true, ) @@ -2661,8 +2521,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &R{I}", - "&AnyResource{I}", + "auth(E) &{I}", + "&{I}", operation, true, ) @@ -2680,8 +2540,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &R{I1}", - "&AnyResource{I2}", + "auth(E) &{I1}", + "&{I2}", operation, true, ) @@ -2699,8 +2559,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{I1, I2}", - "&AnyResource{I2}", + "auth(E) &{I1, I2}", + "&{I2}", operation, true, ) @@ -2718,8 +2578,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{I1}", - "&AnyResource{I1, I2}", + "auth(E) &{I1}", + "&{I1, I2}", operation, true, ) @@ -2737,8 +2597,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{I1}", - "&AnyResource{I2}", + "auth(E) &{I1}", + "&{I2}", operation, true, ) @@ -2756,8 +2616,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{I1}", - "&AnyResource{I2}", + "auth(E) &{I1}", + "&{I2}", operation, true, ) @@ -2774,8 +2634,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { resource R: I1 {} entitlement E `, - "auth(E) &AnyResource{I1}", - "&AnyResource{I1, I2}", + "auth(E) &{I1}", + "&{I1, I2}", operation, true, ) @@ -2791,7 +2651,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyResource", - "&AnyResource{I}", + "&{I}", operation, true, ) @@ -2810,14 +2670,14 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { resource R: I1, I2 {} entitlement E `, - "auth(E) &R{I1}", + "auth(E) &{I1}", "&AnyResource", operation, true, ) }) - t.Run("intersection AnyResource -> AnyResource", func(t *testing.T) { + t.Run("intersection -> AnyResource", func(t *testing.T) { testReferenceCastValid(t, ` @@ -2828,7 +2688,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { resource R: I1, I2 {} entitlement E `, - "auth(E) &AnyResource{I1}", + "auth(E) &{I1}", "&AnyResource", operation, true, @@ -2877,8 +2737,8 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} entitlement E `, - "auth(E) &S{I1, I2}", - "&S{I2}", + "auth(E) &{I1, I2}", + "&{I2}", operation, false, ) @@ -2895,8 +2755,8 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} entitlement E `, - "auth(E) &S{I1}", - "&S{I1, I2}", + "auth(E) &{I1}", + "&{I1, I2}", operation, false, ) @@ -2912,13 +2772,13 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &S", - "&S{I}", + "&{I}", operation, false, ) }) - t.Run("intersection AnyStruct -> conforming intersection type", func(t *testing.T) { + t.Run("intersection -> conforming intersection type", func(t *testing.T) { testReferenceCastValid(t, ` @@ -2927,27 +2787,8 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: SI {} entitlement E `, - "auth(E) &AnyStruct{SI}", - "&S{SI}", - operation, - false, - ) - }) - - // TODO: should statically fail? - t.Run("intersection AnyStruct -> non-conforming intersection type", func(t *testing.T) { - - testReferenceCastInvalid(t, - ` - struct interface SI {} - - struct S: SI {} - - struct T {} - entitlement E -`, - "auth(E) &AnyStruct{SI}", - "&T{}", + "auth(E) &{SI}", + "&{SI}", operation, false, ) @@ -2963,7 +2804,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyStruct", - "&S{SI}", + "&{SI}", operation, false, ) @@ -2981,31 +2822,13 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyStruct", - "&T{TI}", - operation, - false, - ) - }) - - // Supertype: Struct - - t.Run("intersection type -> type: same struct", func(t *testing.T) { - - testReferenceCastValid(t, - ` - struct interface I {} - - struct S: I {} - entitlement E -`, - "auth(E) &S{I}", - "&S", + "&{TI}", operation, false, ) }) - t.Run("intersection AnyStruct -> conforming struct", func(t *testing.T) { + t.Run("intersection -> conforming struct", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3014,7 +2837,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: SI {} entitlement E `, - "auth(E) &AnyStruct{SI}", + "auth(E) &{SI}", "&S", operation, false, @@ -3032,7 +2855,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct T: SI {} entitlement E `, - "auth(E) &AnyStruct{SI}", + "auth(E) &{SI}", "&T", operation, false, @@ -3073,9 +2896,9 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { ) }) - // Supertype: intersection AnyStruct + // Supertype: intersection - t.Run("struct -> intersection AnyStruct with conformance type", func(t *testing.T) { + t.Run("struct -> intersection with conformance type", func(t *testing.T) { testReferenceCastValid(t, ` struct interface SI {} @@ -3084,28 +2907,11 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &S", - "&AnyStruct{SI}", + "&{SI}", operation, false, ) }) - - t.Run("intersection type -> intersection AnyStruct with conformance in type", func(t *testing.T) { - - testReferenceCastValid(t, - ` - struct interface I {} - - struct S: I {} - entitlement E -`, - "auth(E) &S{I}", - "&AnyStruct{I}", - operation, - false, - ) - }) - t.Run("intersection type -> intersection AnyStruct with conformance not in type", func(t *testing.T) { testReferenceCastValid(t, @@ -3117,14 +2923,14 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} entitlement E `, - "auth(E) &S{I1}", - "&AnyStruct{I2}", + "auth(E) &{I1}", + "&{I2}", operation, false, ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct: fewer types", func(t *testing.T) { + t.Run("intersection -> intersection: fewer types", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3135,14 +2941,14 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} entitlement E `, - "auth(E) &AnyStruct{I1, I2}", - "&AnyStruct{I2}", + "auth(E) &{I1, I2}", + "&{I2}", operation, false, ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct: more types", func(t *testing.T) { + t.Run("intersection -> intersection: more types", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3153,14 +2959,14 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} entitlement E `, - "auth(E) &AnyStruct{I1}", - "&AnyStruct{I1, I2}", + "auth(E) &{I1}", + "&{I1, I2}", operation, false, ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct: different types, conforming", func(t *testing.T) { + t.Run("intersection -> intersection: different types, conforming", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3171,14 +2977,14 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} entitlement E `, - "auth(E) &AnyStruct{I1}", - "&AnyStruct{I2}", + "auth(E) &{I1}", + "&{I2}", operation, false, ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct: different types, non-conforming", func(t *testing.T) { + t.Run("intersection -> intersection: different types, non-conforming", func(t *testing.T) { testReferenceCastInvalid(t, ` @@ -3189,14 +2995,14 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1 {} entitlement E `, - "auth(E) &AnyStruct{I1}", - "&AnyStruct{I2}", + "auth(E) &{I1}", + "&{I2}", operation, false, ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct with non-conformance type", func(t *testing.T) { + t.Run("intersection -> intersection with non-conformance type", func(t *testing.T) { testReferenceCastInvalid(t, ` @@ -3207,14 +3013,14 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1 {} entitlement E `, - "auth(E) &AnyStruct{I1}", - "&AnyStruct{I1, I2}", + "auth(E) &{I1}", + "&{I1, I2}", operation, false, ) }) - t.Run("AnyStruct -> intersection AnyStruct", func(t *testing.T) { + t.Run("AnyStruct -> intersection", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3224,7 +3030,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyStruct", - "&AnyStruct{I}", + "&{I}", operation, false, ) @@ -3243,25 +3049,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} entitlement E `, - "auth(E) &S{I1}", - "&AnyStruct", - operation, - false, - ) - }) - - t.Run("intersection AnyStruct -> AnyStruct", func(t *testing.T) { - - testReferenceCastValid(t, - ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - entitlement E -`, - "auth(E) &AnyStruct{I1}", + "auth(E) &{I1}", "&AnyStruct", operation, false, @@ -3308,8 +3096,8 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I1, I2 {} `, - "&R{I1, I2}", - "&R{I2}", + "&{I1, I2}", + "&{I2}", operation, true, ) @@ -3324,7 +3112,7 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I {} `, "&R", - "&R{I}", + "&{I}", operation, true, ) @@ -3332,7 +3120,7 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) // Supertype: intersection AnyResource - t.Run("resource -> intersection AnyResource with conformance type", func(t *testing.T) { + t.Run("resource -> intersection with conformance type", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3341,13 +3129,13 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: RI {} `, "&R", - "&AnyResource{RI}", + "&{RI}", operation, true, ) }) - t.Run("intersection type -> intersection AnyResource with conformance in type", func(t *testing.T) { + t.Run("intersection type -> intersection with conformance in type", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3355,14 +3143,14 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I {} `, - "&R{I}", - "&AnyResource{I}", + "&{I}", + "&{I}", operation, true, ) }) - t.Run("intersection AnyResource -> intersection AnyResource: fewer types", func(t *testing.T) { + t.Run("intersection -> intersection: fewer types", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3372,8 +3160,8 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I1, I2 {} `, - "&AnyResource{I1, I2}", - "&AnyResource{I2}", + "&{I1, I2}", + "&{I2}", operation, true, ) @@ -3391,24 +3179,7 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I1, I2 {} `, - "&R{I1}", - "&AnyResource", - operation, - true, - ) - }) - - t.Run("intersection AnyResource -> AnyResource", func(t *testing.T) { - - testReferenceCastValid(t, - ` - resource interface I1 {} - - resource interface I2 {} - - resource R: I1, I2 {} - `, - "&AnyResource{I1}", + "&{I1}", "&AnyResource", operation, true, @@ -3454,8 +3225,8 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} `, - "&S{I1, I2}", - "&S{I2}", + "&{I1, I2}", + "&{I2}", operation, false, ) @@ -3470,7 +3241,7 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: I {} `, "&S", - "&S{I}", + "&{I}", operation, false, ) @@ -3478,7 +3249,7 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { // Supertype: intersection AnyStruct - t.Run("struct -> intersection AnyStruct with conformance type", func(t *testing.T) { + t.Run("struct -> intersection with conformance type", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3487,28 +3258,13 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: RI {} `, "&S", - "&AnyStruct{RI}", + "&{RI}", operation, false, ) }) - t.Run("intersection type -> intersection AnyStruct with conformance in type", func(t *testing.T) { - - testReferenceCastValid(t, - ` - struct interface I {} - - struct S: I {} - `, - "&S{I}", - "&AnyStruct{I}", - operation, - false, - ) - }) - - t.Run("intersection AnyStruct -> intersection AnyStruct: fewer types", func(t *testing.T) { + t.Run("intersection -> intersection: fewer types", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3518,8 +3274,8 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} `, - "&AnyStruct{I1, I2}", - "&AnyStruct{I2}", + "&{I1, I2}", + "&{I2}", operation, false, ) @@ -3537,24 +3293,7 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} `, - "&S{I1}", - "&AnyStruct", - operation, - false, - ) - }) - - t.Run("intersection AnyStruct -> AnyStruct", func(t *testing.T) { - - testReferenceCastValid(t, - ` - struct interface I1 {} - - struct interface I2 {} - - struct S: I1, I2 {} - `, - "&AnyStruct{I1}", + "&{I1}", "&AnyStruct", operation, false, @@ -3929,7 +3668,7 @@ func TestInterpretReferenceCasting(t *testing.T) { fun test() { let x = bar() let y = [&x as &AnyStruct] - let z = y as! [&bar{foo}] + let z = y as! [&{foo}] } struct interface foo {} @@ -3952,7 +3691,7 @@ func TestInterpretReferenceCasting(t *testing.T) { fun test() { let x = bar() let y = {"a": &x as &AnyStruct} - let z = y as! {String: &bar{foo}} + let z = y as! {String: &{foo}} } struct interface foo {} diff --git a/runtime/tests/interpreter/entitlements_test.go b/runtime/tests/interpreter/entitlements_test.go index cde9e52300..d885ab8b7d 100644 --- a/runtime/tests/interpreter/entitlements_test.go +++ b/runtime/tests/interpreter/entitlements_test.go @@ -532,8 +532,8 @@ func TestInterpretEntitledReferenceCasting(t *testing.T) { fun test(): Bool { let x <- create R() - let r = &x as auth(E) &AnyResource{RI} - let r2 = r as! &R{RI} + let r = &x as auth(E) &{RI} + let r2 = r as! &{RI} let isSuccess = r2 != nil destroy x return isSuccess diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 9d0c88b143..0832354940 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -4930,7 +4930,7 @@ func TestInterpretReferenceFailableDowncasting(t *testing.T) { fun testValidUnauthorized(): Bool { let r <- create R() - let ref: AnyStruct = &r as &R{RI} + let ref: AnyStruct = &r as &{RI} let ref2 = ref as? &R let isNil = ref2 == nil destroy r @@ -4939,7 +4939,7 @@ func TestInterpretReferenceFailableDowncasting(t *testing.T) { fun testValidAuthorized(): Bool { let r <- create R() - let ref: AnyStruct = &r as auth(E) &R{RI} + let ref: AnyStruct = &r as auth(E) &{RI} let ref2 = ref as? &R let isNil = ref2 == nil destroy r @@ -4948,8 +4948,8 @@ func TestInterpretReferenceFailableDowncasting(t *testing.T) { fun testValidIntersection(): Bool { let r <- create R() - let ref: AnyStruct = &r as &R{RI} - let ref2 = ref as? &R{RI} + let ref: AnyStruct = &r as &{RI} + let ref2 = ref as? &{RI} let isNil = ref2 == nil destroy r return isNil @@ -4997,8 +4997,8 @@ func TestInterpretReferenceFailableDowncasting(t *testing.T) { // Inject a function that returns a storage reference value, // which is borrowed as: - // - `&R{RI}` (unauthorized, if argument for parameter `authorized` == false) - // - `auth(E) &R{RI}` (authorized, if argument for parameter `authorized` == true) + // - `&{RI}` (unauthorized, if argument for parameter `authorized` == false) + // - `auth(E) &{RI}` (authorized, if argument for parameter `authorized` == true) storageAddress := common.MustBytesToAddress([]byte{0x42}) storagePath := interpreter.PathValue{ @@ -5036,14 +5036,12 @@ func TestInterpretReferenceFailableDowncasting(t *testing.T) { } riType := getType("RI").(*sema.InterfaceType) - rType := getType("R") return &interpreter.StorageReferenceValue{ Authorization: auth, TargetStorageAddress: storageAddress, TargetPath: storagePath, BorrowedType: &sema.IntersectionType{ - Type: rType, Types: []*sema.InterfaceType{ riType, }, @@ -5083,9 +5081,9 @@ func TestInterpretReferenceFailableDowncasting(t *testing.T) { return ref as? &R } - fun testValidIntersection(): &R{RI}? { + fun testValidIntersection(): &{RI}? { let ref: AnyStruct = getStorageReference(authorized: false) - return ref as? &R{RI} + return ref as? &{RI} } `, ParseCheckAndInterpretOptions{ diff --git a/runtime/tests/interpreter/member_test.go b/runtime/tests/interpreter/member_test.go index 4d1dde3206..15af95ae85 100644 --- a/runtime/tests/interpreter/member_test.go +++ b/runtime/tests/interpreter/member_test.go @@ -216,11 +216,11 @@ func TestInterpretMemberAccessType(t *testing.T) { } } - fun get(si: AnyStruct{SI}) { + fun get(si: {SI}) { si.foo } - fun set(si: AnyStruct{SI}) { + fun set(si: {SI}) { si.foo = 2 } `) @@ -263,11 +263,11 @@ func TestInterpretMemberAccessType(t *testing.T) { } } - fun get(si: AnyStruct{SI}) { + fun get(si: {SI}) { si.foo } - fun set(si: AnyStruct{SI}) { + fun set(si: {SI}) { si.foo = 3 } `) @@ -309,7 +309,7 @@ func TestInterpretMemberAccessType(t *testing.T) { } } - fun get(si: AnyStruct{SI}?) { + fun get(si: {SI}?) { si?.foo } `) @@ -352,7 +352,7 @@ func TestInterpretMemberAccessType(t *testing.T) { } } - fun get(si: AnyStruct{SI}?) { + fun get(si: {SI}?) { si?.foo } `) diff --git a/runtime/tests/interpreter/memory_metering_test.go b/runtime/tests/interpreter/memory_metering_test.go index 56a0a91251..11cee2c9c9 100644 --- a/runtime/tests/interpreter/memory_metering_test.go +++ b/runtime/tests/interpreter/memory_metering_test.go @@ -8041,10 +8041,9 @@ func TestInterpretInterfaceStaticType(t *testing.T) { struct interface I {} access(all) fun main() { - let type = Type() + let type = Type<{I}>() IntersectionType( - identifier: type.identifier, types: [type.identifier] ) } @@ -8483,7 +8482,7 @@ func TestInterpretASTMetering(t *testing.T) { } var g = &a as &Int // reference type - var h: AnyStruct{foo} = bar() // intersection type + var h: {foo} = bar() // intersection type var i: Capability<&bar>? = nil // instantiation type } @@ -8502,7 +8501,7 @@ func TestInterpretASTMetering(t *testing.T) { assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindDictionaryType)) assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindFunctionType)) assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindInstantiationType)) - assert.Equal(t, uint64(16), meter.getMemory(common.MemoryKindNominalType)) + assert.Equal(t, uint64(15), meter.getMemory(common.MemoryKindNominalType)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindOptionalType)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindReferenceType)) assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindIntersectionType)) @@ -8671,7 +8670,7 @@ func TestInterpretStaticTypeConversionMetering(t *testing.T) { script := ` access(all) fun main() { - let a: {Int: AnyStruct{Foo}} = {} // dictionary + intersection + let a: {Int: {Foo}} = {} // dictionary + intersection let b: [&Int] = [] // variable-sized + reference let c: [Int?; 2] = [1, 2] // constant-sized + optional let d: [Capability<&Bar>] = [] // capability + variable-sized + reference @@ -9263,7 +9262,7 @@ func TestInterpretStaticTypeStringConversion(t *testing.T) { script := ` access(all) fun main() { - log(Type()) + log(Type<{Foo}>()) } struct interface Foo {} diff --git a/runtime/tests/interpreter/runtimetype_test.go b/runtime/tests/interpreter/runtimetype_test.go index 068c693340..18a9c4862e 100644 --- a/runtime/tests/interpreter/runtimetype_test.go +++ b/runtime/tests/interpreter/runtimetype_test.go @@ -575,31 +575,23 @@ func TestInterpretIntersectionType(t *testing.T) { access(all) let foo : Int } - let a = IntersectionType(identifier: "S.test.A", types: ["S.test.R"])! - let b = IntersectionType(identifier: "S.test.B", types: ["S.test.S"])! + let a = IntersectionType(types: ["S.test.R"])! + let b = IntersectionType(types: ["S.test.S"])! - let c = IntersectionType(identifier: "S.test.B", types: ["S.test.R"]) - let d = IntersectionType(identifier: "S.test.A", types: ["S.test.S"]) - let e = IntersectionType(identifier: "S.test.B", types: ["S.test.S2"]) + let c = IntersectionType(types: []) - let f = IntersectionType(identifier: "S.test.B", types: ["X"]) - let g = IntersectionType(identifier: "S.test.N", types: ["S.test.S2"]) + let f = IntersectionType(types: ["X"]) - let h = Type<@A{R}>() - let i = Type() + let h = Type<@{R}>() + let i = Type<{S}>() - let j = IntersectionType(identifier: nil, types: ["S.test.R"])! - let k = IntersectionType(identifier: nil, types: ["S.test.S"])! + let j = IntersectionType(types: ["S.test.R", "S.test.S" ]) + let k = IntersectionType(types: ["S.test.S", "S.test.S2"])! `) assert.Equal(t, interpreter.TypeValue{ Type: &interpreter.IntersectionStaticType{ - Type: interpreter.CompositeStaticType{ - QualifiedIdentifier: "A", - Location: utils.TestLocation, - TypeID: "S.test.A", - }, Types: []interpreter.InterfaceStaticType{ { QualifiedIdentifier: "R", @@ -611,14 +603,14 @@ func TestInterpretIntersectionType(t *testing.T) { inter.Globals.Get("a").GetValue(), ) + assert.Equal(t, + interpreter.Nil, + inter.Globals.Get("c").GetValue(), + ) + assert.Equal(t, interpreter.TypeValue{ Type: &interpreter.IntersectionStaticType{ - Type: interpreter.CompositeStaticType{ - QualifiedIdentifier: "B", - Location: utils.TestLocation, - TypeID: "S.test.B", - }, Types: []interpreter.InterfaceStaticType{ { QualifiedIdentifier: "S", @@ -631,60 +623,33 @@ func TestInterpretIntersectionType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ - Type: &interpreter.IntersectionStaticType{ - Type: interpreter.PrimitiveStaticTypeAnyResource, - Types: []interpreter.InterfaceStaticType{ - { - QualifiedIdentifier: "R", - Location: utils.TestLocation, - }, - }, - }, - }, + interpreter.Nil, inter.Globals.Get("j").GetValue(), ) assert.Equal(t, interpreter.TypeValue{ Type: &interpreter.IntersectionStaticType{ - Type: interpreter.PrimitiveStaticTypeAnyStruct, Types: []interpreter.InterfaceStaticType{ { QualifiedIdentifier: "S", Location: utils.TestLocation, }, + { + QualifiedIdentifier: "S2", + Location: utils.TestLocation, + }, }, }, }, inter.Globals.Get("k").GetValue(), ) - assert.Equal(t, - interpreter.Nil, - inter.Globals.Get("c").GetValue(), - ) - - assert.Equal(t, - interpreter.Nil, - inter.Globals.Get("d").GetValue(), - ) - - assert.Equal(t, - interpreter.Nil, - inter.Globals.Get("e").GetValue(), - ) - assert.Equal(t, interpreter.Nil, inter.Globals.Get("f").GetValue(), ) - assert.Equal(t, - interpreter.Nil, - inter.Globals.Get("g").GetValue(), - ) - assert.Equal(t, inter.Globals.Get("a").GetValue(), inter.Globals.Get("h").GetValue(), diff --git a/runtime/tests/interpreter/transfer_test.go b/runtime/tests/interpreter/transfer_test.go index d7eedc0429..36702a8394 100644 --- a/runtime/tests/interpreter/transfer_test.go +++ b/runtime/tests/interpreter/transfer_test.go @@ -117,7 +117,7 @@ func TestInterpretTransferCheck(t *testing.T) { fun test() { let r <- C.createR() let r2: @CI.R <- r as @CI.R - let r3: @CI.R{CI.RI} <- r2 + let r3: @{CI.RI} <- r2 destroy r3 } `, @@ -158,7 +158,7 @@ func TestInterpretTransferCheck(t *testing.T) { fun test() { let r <- C.createR() let ref: &CI.R = &r as &CI.R - let intersectionRef: &CI.R{CI.RI} = ref + let intersectionRef: &{CI.RI} = ref destroy r } `, diff --git a/types.go b/types.go index 9a025f1aa9..0e19e69bc4 100644 --- a/types.go +++ b/types.go @@ -2273,29 +2273,25 @@ type IntersectionSet = map[Type]struct{} type IntersectionType struct { typeID string - Type Type Types []Type intersectionSet IntersectionSet intersectionSetOnce sync.Once } func NewIntersectionType( - typ Type, types []Type, ) *IntersectionType { return &IntersectionType{ - Type: typ, Types: types, } } func NewMeteredIntersectionType( gauge common.MemoryGauge, - typ Type, types []Type, ) *IntersectionType { common.UseMemory(gauge, common.CadenceIntersectionTypeMemoryUsage) - return NewIntersectionType(typ, types) + return NewIntersectionType(types) } func (*IntersectionType) isType() {} @@ -2310,11 +2306,7 @@ func (t *IntersectionType) ID() string { typeStrings = append(typeStrings, typ.ID()) } } - var typeString string - if t.Type != nil { - typeString = t.Type.ID() - } - t.typeID = sema.FormatIntersectionTypeID(typeString, typeStrings) + t.typeID = sema.FormatIntersectionTypeID(typeStrings) } return t.typeID } @@ -2325,16 +2317,6 @@ func (t *IntersectionType) Equal(other Type) bool { return false } - if t.Type == nil && otherType.Type != nil { - return false - } - if t.Type != nil && otherType.Type == nil { - return false - } - if t.Type != nil && !t.Type.Equal(otherType.Type) { - return false - } - intersectionSet := t.IntersectionSet() otherIntersectionSet := otherType.IntersectionSet() diff --git a/types_test.go b/types_test.go index 05ccd6ff89..e913c34006 100644 --- a/types_test.go +++ b/types_test.go @@ -173,10 +173,6 @@ func TestType_ID(t *testing.T) { }, { &IntersectionType{ - Type: &ResourceType{ - Location: utils.TestLocation, - QualifiedIdentifier: "Foo", - }, Types: []Type{ &ResourceInterfaceType{ Location: utils.TestLocation, @@ -184,7 +180,7 @@ func TestType_ID(t *testing.T) { }, }, }, - "S.test.Foo{S.test.FooI}", + "{S.test.FooI}", }, { &FunctionType{ @@ -1703,14 +1699,12 @@ func TestTypeEquality(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, IntType{}, }, } target := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, IntType{}, @@ -1723,14 +1717,12 @@ func TestTypeEquality(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, IntType{}, }, } target := &IntersectionType{ - Type: IntType{}, Types: []Type{ IntType{}, AnyType{}, @@ -1743,7 +1735,6 @@ func TestTypeEquality(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ IntType{}, AnyType{}, @@ -1751,7 +1742,6 @@ func TestTypeEquality(t *testing.T) { }, } target := &IntersectionType{ - Type: IntType{}, Types: []Type{ IntType{}, AnyType{}, @@ -1760,38 +1750,16 @@ func TestTypeEquality(t *testing.T) { assert.True(t, source.Equal(target)) }) - t.Run("different inner type", func(t *testing.T) { - t.Parallel() - - source := &IntersectionType{ - Type: IntType{}, - Types: []Type{ - AnyType{}, - IntType{}, - }, - } - target := &IntersectionType{ - Type: StringType{}, - Types: []Type{ - AnyType{}, - IntType{}, - }, - } - assert.False(t, source.Equal(target)) - }) - t.Run("different intersections", func(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, IntType{}, }, } target := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, StringType{}, @@ -1804,13 +1772,11 @@ func TestTypeEquality(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, }, } target := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, StringType{}, @@ -1823,7 +1789,6 @@ func TestTypeEquality(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, },