From 6eb1eb62f6fdf6af45a6e2a40a51859e89c25bf4 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Fri, 16 Jun 2023 14:12:14 -0400 Subject: [PATCH 01/16] remove ast restricted type --- encoding/ccf/ccf_test.go | 4 +- runtime/ast/type.go | 6 - runtime/ast/type_test.go | 29 +- runtime/contract_update_validation_test.go | 12 +- runtime/convertTypes.go | 5 +- runtime/convertValues_test.go | 9 - runtime/interpreter/interpreter.go | 23 +- runtime/interpreter/statictype.go | 5 +- runtime/interpreter/statictype_test.go | 1 - runtime/missingmember_test.go | 26 +- runtime/parser/parser_test.go | 4 +- runtime/parser/type.go | 65 ---- runtime/parser/type_test.go | 362 ++---------------- runtime/runtime_test.go | 22 +- runtime/sema/authaccount.cdc | 2 +- runtime/sema/authaccount.gen.go | 4 +- runtime/sema/check_casting_expression.go | 181 +-------- runtime/sema/check_composite_declaration.go | 6 +- runtime/sema/checker.go | 90 +---- runtime/sema/errors.go | 18 - runtime/sema/gen/main.go | 6 - runtime/sema/type.go | 246 ++---------- runtime/sema/type_tags.go | 1 - runtime/sema/type_test.go | 182 +-------- runtime/stdlib/contracts/test.cdc | 4 +- runtime/stdlib/type-comparator.go | 18 - runtime/storage_test.go | 4 +- runtime/tests/checker/access_test.go | 6 +- runtime/tests/checker/casting_test.go | 162 ++++---- runtime/tests/checker/composite_test.go | 2 +- runtime/tests/checker/contract_test.go | 18 +- runtime/tests/checker/dynamic_casting_test.go | 14 +- runtime/tests/checker/interface_test.go | 2 - runtime/tests/checker/intersection_test.go | 73 +--- runtime/tests/checker/nesting_test.go | 4 +- runtime/tests/checker/reference_test.go | 30 +- runtime/tests/checker/resources_test.go | 4 +- runtime/tests/checker/type_inference_test.go | 11 +- .../tests/interpreter/dynamic_casting_test.go | 176 ++++----- .../tests/interpreter/entitlements_test.go | 2 +- runtime/tests/interpreter/interpreter_test.go | 10 +- runtime/tests/interpreter/member_test.go | 12 +- .../tests/interpreter/memory_metering_test.go | 8 +- types.go | 22 +- types_test.go | 37 +- 45 files changed, 386 insertions(+), 1542 deletions(-) diff --git a/encoding/ccf/ccf_test.go b/encoding/ccf/ccf_test.go index 7c4c2287da..94ee79e9d0 100644 --- a/encoding/ccf/ccf_test.go +++ b/encoding/ccf/ccf_test.go @@ -6530,7 +6530,6 @@ func TestEncodeValueOfIntersectionType(t *testing.T) { ) countSumIntersectionType := cadence.NewIntersectionType( - nil, []cadence.Type{ hasCountInterfaceType, hasSumInterfaceType, @@ -6557,7 +6556,6 @@ func TestEncodeValueOfIntersectionType(t *testing.T) { ) expectedCountSumIntersectionType := cadence.NewIntersectionType( - nil, []cadence.Type{ hasSumInterfaceType, hasCountInterfaceType, @@ -14145,7 +14143,7 @@ func TestEncodeValueOfIntersectedInterface(t *testing.T) { } struct MiddleStruct { - var field: AnyStruct{Interface} + var field: {Interface} } struct interface Interface {} 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/contract_update_validation_test.go b/runtime/contract_update_validation_test.go index 9a3b1de7bf..2a5d25d00f 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 diff --git a/runtime/convertTypes.go b/runtime/convertTypes.go index f79935ade7..67f8498131 100644 --- a/runtime/convertTypes.go +++ b/runtime/convertTypes.go @@ -515,8 +515,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 { @@ -525,7 +523,6 @@ func exportIntersectionType( return cadence.NewMeteredIntersectionType( gauge, - convertedType, intersectionTypes, ) } @@ -695,7 +692,7 @@ func ImportType(memoryGauge common.MemoryGauge, t cadence.Type) interpreter.Stat } return interpreter.NewIntersectionStaticType( memoryGauge, - ImportType(memoryGauge, t.Type), + nil, types, ) case cadence.BlockType: diff --git a/runtime/convertValues_test.go b/runtime/convertValues_test.go index 96602ca612..3bd563463b 100644 --- a/runtime/convertValues_test.go +++ b/runtime/convertValues_test.go @@ -1358,10 +1358,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, @@ -2110,11 +2106,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/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index 23f3bdf5bd..92e5e759bf 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -3507,7 +3507,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()) } @@ -3550,26 +3550,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 @@ -3588,7 +3571,7 @@ func intersectionTypeFunction(invocation Invocation) Value { invocation.Interpreter, NewIntersectionStaticType( invocation.Interpreter, - ConvertSemaToStaticType(invocation.Interpreter, ty), + nil, staticIntersections, ), ), diff --git a/runtime/interpreter/statictype.go b/runtime/interpreter/statictype.go index 729a9127df..08e2640a4c 100644 --- a/runtime/interpreter/statictype.go +++ b/runtime/interpreter/statictype.go @@ -765,7 +765,7 @@ func ConvertSemaToStaticType(memoryGauge common.MemoryGauge, t sema.Type) Static return NewIntersectionStaticType( memoryGauge, - ConvertSemaToStaticType(memoryGauge, t.Type), + nil, intersectedTypess, ) @@ -1004,7 +1004,7 @@ func ConvertStaticToSemaType( } } - ty, err := ConvertStaticToSemaType( + _, err := ConvertStaticToSemaType( memoryGauge, t.Type, getInterface, @@ -1018,7 +1018,6 @@ func ConvertStaticToSemaType( return sema.NewIntersectionType( memoryGauge, - ty, intersectedTypes, ), nil diff --git a/runtime/interpreter/statictype_test.go b/runtime/interpreter/statictype_test.go index 3904235d5d..ec39e47df0 100644 --- a/runtime/interpreter/statictype_test.go +++ b/runtime/interpreter/statictype_test.go @@ -1373,7 +1373,6 @@ func TestStaticTypeConversion(t *testing.T) { { name: "Intersection", semaType: &sema.IntersectionType{ - Type: sema.IntType, Types: []*sema.InterfaceType{ testInterfaceSemaType, }, diff --git a/runtime/missingmember_test.go b/runtime/missingmember_test.go index a1b0882ce9..16fbab3842 100644 --- a/runtime/missingmember_test.go +++ b/runtime/missingmember_test.go @@ -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) } } @@ -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) @@ -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..aa857a0f51 100644 --- a/runtime/parser/type.go +++ b/runtime/parser/type.go @@ -358,7 +358,6 @@ func defineIntersectionOrDictionaryType() { } intersectionType = ast.NewIntersectionType( p.memoryGauge, - nil, []*ast.NominalType{ firstNominalType, }, @@ -462,7 +461,6 @@ func defineIntersectionOrDictionaryType() { intersectionType = ast.NewIntersectionType( p.memoryGauge, nil, - nil, ast.NewRange( p.memoryGauge, startToken.StartPos, @@ -480,69 +478,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 ee6431a1c6..5065bd9cdb 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -2575,7 +2575,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) } } `) @@ -2592,7 +2592,7 @@ func TestRuntimeResourceContractWithInterface(t *testing.T) { prepare(signer: AuthAccount) { let ref = signer .getCapability(/public/r) - .borrow<&AnyResource{RI}>()! + .borrow<&{RI}>()! ref.x() } } @@ -4153,7 +4153,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!" @@ -4179,7 +4179,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" @@ -4191,7 +4191,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 } @@ -4206,7 +4206,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)) } } @@ -4241,7 +4241,7 @@ func TestRuntimeFungibleTokenUpdateAccountCode(t *testing.T) { prepare(acct: AuthAccount) { - acct.link<&AnyResource{FungibleToken.Receiver}>( + acct.link<&{FungibleToken.Receiver}>( /public/receiver, target: /storage/vault ) @@ -4265,7 +4265,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 ) @@ -4375,7 +4375,7 @@ func TestRuntimeFungibleTokenCreateAccount(t *testing.T) { transaction { prepare(acct: AuthAccount) { - acct.link<&AnyResource{FungibleToken.Receiver}>( + acct.link<&{FungibleToken.Receiver}>( /public/receiver, target: /storage/vault ) @@ -4399,7 +4399,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 ) @@ -4555,7 +4555,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 b9ba65ae29..d635433c81 100644 --- a/runtime/sema/authaccount.cdc +++ b/runtime/sema/authaccount.cdc @@ -403,6 +403,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 691c87e977..a624fe5a0e 100644 --- a/runtime/sema/authaccount.gen.go +++ b/runtime/sema/authaccount.gen.go @@ -1692,9 +1692,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 45deee6830..8694572aa2 100644 --- a/runtime/sema/check_composite_declaration.go +++ b/runtime/sema/check_composite_declaration.go @@ -2433,13 +2433,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 fae67eecd7..ca8c4ffdec 100644 --- a/runtime/sema/checker.go +++ b/runtime/sema/checker.go @@ -897,10 +897,9 @@ func (checker *Checker) ConvertType(t ast.Type) Type { func CheckIntersectionType( memoryGauge common.MemoryGauge, - intersectionType Type, types []*InterfaceType, report func(func(*ast.IntersectionType) error), -) Type { +) { intersectionRanges := make(map[*InterfaceType]func(*ast.IntersectionType) ast.Range, len(types)) intersectionsCompositeKind := common.CompositeKindUnknown memberSet := map[string]*InterfaceType{} @@ -976,75 +975,27 @@ func CheckIntersectionType( }) } - var hadExplicitType = intersectionType != nil - - 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. - - 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()) - } - } + // If no intersection type is given, infer `AnyResource`/`AnyStruct` + // based on the composite kind of the intersections. - // The intersection type must be a composite type - // or `AnyResource`/`AnyStruct` + switch intersectionsCompositeKind { + case common.CompositeKindUnknown: + // If no intersection type is given, and also no intersections, + // the type is ambiguous. - 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() { + case common.CompositeKindResource, common.CompositeKindStructure: + break - if typeResult, ok := intersectionType.(*CompositeType); ok { - switch typeResult.Kind { - - case common.CompositeKindResource, - common.CompositeKindStructure: - - compositeType = typeResult - - default: - reportInvalidIntersectionType() - } - } else { - - switch intersectionType { - case AnyResourceType, AnyStructType, AnyType: - 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 @@ -1068,18 +1019,9 @@ func CheckIntersectionType( } } } - return intersectionType } 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 @@ -1112,9 +1054,8 @@ func (checker *Checker) convertIntersectionType(t *ast.IntersectionType) Type { intersectedTypes = append(intersectedTypes, intersectedInterfaceType) } - intersectionType = CheckIntersectionType( + CheckIntersectionType( checker.memoryGauge, - intersectionType, intersectedTypes, func(getError func(*ast.IntersectionType) error) { checker.report(getError(t)) @@ -1122,7 +1063,6 @@ func (checker *Checker) convertIntersectionType(t *ast.IntersectionType) Type { ) return &IntersectionType{ - Type: intersectionType, Types: intersectedTypes, } } diff --git a/runtime/sema/errors.go b/runtime/sema/errors.go index 509b853676..89e484032f 100644 --- a/runtime/sema/errors.go +++ b/runtime/sema/errors.go @@ -3514,24 +3514,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/type.go b/runtime/sema/type.go index 6ff47a7751..0e85ea2a38 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -4911,22 +4911,9 @@ func (*InterfaceType) TypeAnnotationState() TypeAnnotationState { } func (t *InterfaceType) RewriteWithIntersectionTypes() (Type, bool) { - switch t.CompositeKind { - case common.CompositeKindResource: - return &IntersectionType{ - Type: AnyResourceType, - Types: []*InterfaceType{t}, - }, true - - case common.CompositeKindStructure: - return &IntersectionType{ - Type: AnyStructType, - Types: []*InterfaceType{t}, - }, true - - default: - return t, false - } + return &IntersectionType{ + Types: []*InterfaceType{t}, + }, true } func (*InterfaceType) Unify(_ Type, _ *TypeParameterTypeOrderedMap, _ func(err error), _ ast.Range) bool { @@ -6129,120 +6116,27 @@ func checkSubTypeWithoutEquality(subType Type, superType Type) bool { return true case *IntersectionType: - - intersectionSuperType := typedSuperType.Type - switch intersectionSuperType { + // `Any` is never a subtype of a intersection type + switch subType { case AnyResourceType, AnyStructType, AnyType: + return false + } - 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 - } + switch typedSubType := subType.(type) { + case *IntersectionType: - 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: @@ -6253,22 +6147,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. @@ -6542,7 +6422,6 @@ func (t *TransactionType) Resolve(_ *TypeParameterTypeOrderedMap) Type { // IntersectionType type IntersectionType struct { - Type Type // an internal set of field `Types` effectiveIntersectionSet *InterfaceSet Types []*InterfaceType @@ -6554,7 +6433,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. @@ -6564,7 +6447,6 @@ func NewIntersectionType(memoryGauge common.MemoryGauge, typ Type, types []*Inte common.UseMemory(memoryGauge, entriesUsage) return &IntersectionType{ - Type: typ, Types: types, } } @@ -6594,9 +6476,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 { @@ -6609,8 +6490,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 { @@ -6622,7 +6503,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 { @@ -6651,10 +6532,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() @@ -6668,17 +6545,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 @@ -6689,10 +6560,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 @@ -6703,10 +6570,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 @@ -6717,10 +6580,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 @@ -6763,11 +6622,8 @@ func (t *IntersectionType) Map(gauge common.MemoryGauge, typeParamMap map[*TypeP } } - mappedType := t.Type.Map(gauge, typeParamMap, f) - return f(NewIntersectionType( gauge, - mappedType, intersectionTypes, )) } @@ -6794,43 +6650,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 }) } @@ -6845,9 +6664,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 8f12115ff4..f98f4f9ac8 100644 --- a/runtime/sema/type_tags.go +++ b/runtime/sema/type_tags.go @@ -931,7 +931,6 @@ func commonSuperTypeOfComposites(types []Type) Type { if hasCommonInterface { return &IntersectionType{ - Type: superType, Types: commonInterfacesList, } } diff --git a/runtime/sema/type_test.go b/runtime/sema/type_test.go index ec98db41dc..a7d415a717 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, "", @@ -1056,7 +906,6 @@ func TestCommonSuperType(t *testing.T) { }, expectedSuperType: func() Type { typ := &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{interfaceType2}, } // just initialize for equality @@ -1072,7 +921,6 @@ func TestCommonSuperType(t *testing.T) { }, expectedSuperType: func() Type { typ := &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{interfaceType1, interfaceType2}, } // just initialize for equality @@ -1097,7 +945,6 @@ func TestCommonSuperType(t *testing.T) { }, expectedSuperType: func() Type { typ := &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{superInterfaceType}, } @@ -1493,12 +1340,10 @@ func TestCommonSuperType(t *testing.T) { } intersectionType1 := &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{interfaceType1}, } intersectionType2 := &IntersectionType{ - Type: AnyResourceType, Types: []*InterfaceType{interfaceType1}, } @@ -1537,12 +1382,10 @@ func TestCommonSuperType(t *testing.T) { } intersectionType1 := &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{interfaceType1}, } intersectionType2 := &IntersectionType{ - Type: AnyResourceType, Types: []*InterfaceType{interfaceType1}, } @@ -1671,7 +1514,6 @@ func TestCommonSuperType(t *testing.T) { BorrowType: AnyStructType, }, &IntersectionType{ - Type: AnyStructType, Types: []*InterfaceType{ { Location: common.StringLocation("test"), @@ -1999,7 +1841,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 } @@ -2058,7 +1900,6 @@ func TestMapType(t *testing.T) { original := NewIntersectionType( nil, - StringType, []*InterfaceType{ {Identifier: "foo"}, {Identifier: "bar"}, @@ -2066,7 +1907,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 fcc98cf095..41e6729f78 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..8d8c25a045 100644 --- a/runtime/stdlib/type-comparator.go +++ b/runtime/stdlib/type-comparator.go @@ -98,24 +98,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) } diff --git a/runtime/storage_test.go b/runtime/storage_test.go index 95944c64a4..22f8af8052 100644 --- a/runtime/storage_test.go +++ b/runtime/storage_test.go @@ -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/casting_test.go b/runtime/tests/checker/casting_test.go index 4c8ab4e1d3..acb5ea7b49 100644 --- a/runtime/tests/checker/casting_test.go +++ b/runtime/tests/checker/casting_test.go @@ -427,7 +427,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{RI} `, ) @@ -444,7 +444,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @R{RI}? { - let r: @AnyResource{RI} <- create R() + let r: @{RI} <- create R() if let r2 <- r as? @R{RI} { return <-r2 } else { @@ -471,7 +471,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{RI} `, ) @@ -488,7 +488,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @R{RI}? { - let r: @AnyResource{RI} <- create R() + let r: @{RI} <- create R() if let r2 <- r as? @R{RI} { return <-r2 } else { @@ -615,7 +615,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 +632,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 +659,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 +675,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 +750,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 +763,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 +795,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 +806,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 @@ -835,7 +835,7 @@ func TestCheckCastResourceType(t *testing.T) { checker, err := ParseAndCheck(t, types+` let r: @R{I} <- create R() - let r2 <- r as @AnyResource{I} + let r2 <- r as @{I} `, ) @@ -849,7 +849,6 @@ func TestCheckCastResourceType(t *testing.T) { require.IsType(t, &sema.IntersectionType{ - Type: sema.AnyResourceType, Types: []*sema.InterfaceType{ iType.(*sema.InterfaceType), }, @@ -862,9 +861,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{I}? { + fun test(): @{I}? { let r: @R{I} <- create R() - if let r2 <- r as? @AnyResource{I} { + if let r2 <- r as? @{I} { return <-r2 } else { destroy r @@ -893,7 +892,7 @@ func TestCheckCastResourceType(t *testing.T) { checker, err := ParseAndCheck(t, types+` let r: @R{I1} <- create R() - let r2 <- r as @AnyResource{I2} + let r2 <- r as @{I2} `, ) @@ -907,7 +906,6 @@ func TestCheckCastResourceType(t *testing.T) { require.IsType(t, &sema.IntersectionType{ - Type: sema.AnyResourceType, Types: []*sema.InterfaceType{ i2Type.(*sema.InterfaceType), }, @@ -920,9 +918,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{I2}? { + fun test(): @{I2}? { let r: @R{I1} <- create R() - if let r2 <- r as? @AnyResource{I2} { + if let r2 <- r as? @{I2} { return <-r2 } else { destroy r @@ -951,7 +949,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` let r: @R{I1} <- create R() - let r2 <- r as @AnyResource{I2} + let r2 <- r as @{I2} `, ) @@ -964,9 +962,9 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` - fun test(): @AnyResource{I2}? { + fun test(): @{I2}? { let r: @R{I1} <- create R() - if let r2 <- r as? @AnyResource{I2} { + if let r2 <- r as? @{I2} { return <-r2 } else { destroy r @@ -996,8 +994,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 +1006,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 +1036,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 +1050,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 +1080,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 +1094,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 +1123,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 +1136,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 @@ -1212,7 +1210,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 +1223,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 { @@ -1544,7 +1542,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() + let s: {SI} = S() let s2 = s as S{SI} `, ) @@ -1560,7 +1558,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() + let s: {SI} = S() let s2 = s as? S{SI} `, ) @@ -1581,7 +1579,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() + let s: {SI} = S() let s2 = s as S{SI} `, ) @@ -1597,7 +1595,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() + let s: {SI} = S() let s2 = s as? S{SI} `, ) @@ -1702,7 +1700,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() + let s: {SI} = S() let s2 = s as S `, ) @@ -1718,7 +1716,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() + let s: {SI} = S() let s2 = s as? S `, ) @@ -1739,7 +1737,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() + let s: {SI} = S() let s2 = s as S `, ) @@ -1754,7 +1752,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{SI} = S() + let s: {SI} = S() let s2 = s as? S `, ) @@ -1816,7 +1814,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: S = S() - let s2 = s as AnyStruct{SI} + let s2 = s as {SI} `, ) @@ -1830,7 +1828,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: S = S() - let s2 = s as? AnyStruct{SI} + let s2 = s as? {SI} `, ) @@ -1854,7 +1852,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: S = S() - let s2 = s as AnyStruct{SI} + let s2 = s as {SI} `, ) @@ -1866,7 +1864,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: S = S() - let s2 = s as? AnyStruct{SI} + let s2 = s as? {SI} `, ) @@ -1887,7 +1885,7 @@ func TestCheckCastStructType(t *testing.T) { checker, err := ParseAndCheck(t, types+` let s: S{I} = S() - let s2 = s as AnyStruct{I} + let s2 = s as {I} `, ) @@ -1901,7 +1899,6 @@ func TestCheckCastStructType(t *testing.T) { require.IsType(t, &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ iType.(*sema.InterfaceType), }, @@ -1915,7 +1912,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: S{I} = S() - let s2 = s as? AnyStruct{I} + let s2 = s as? {I} `, ) @@ -1938,7 +1935,7 @@ func TestCheckCastStructType(t *testing.T) { checker, err := ParseAndCheck(t, types+` let s: S{I1} = S() - let s2 = s as AnyStruct{I2} + let s2 = s as {I2} `, ) @@ -1952,7 +1949,6 @@ func TestCheckCastStructType(t *testing.T) { require.IsType(t, &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ i2Type.(*sema.InterfaceType), }, @@ -1966,7 +1962,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: S{I1} = S() - let s2 = s as? AnyStruct{I2} + let s2 = s as? {I2} `, ) @@ -1989,7 +1985,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: S{I1} = S() - let s2 = s as AnyStruct{I2} + let s2 = s as {I2} `, ) @@ -2003,7 +1999,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: S{I1} = S() - let s2 = s as? AnyStruct{I2} + let s2 = s as? {I2} `, ) @@ -2027,8 +2023,8 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{I1, I2} = S() - let s2 = s as AnyStruct{I2} + let s: {I1, I2} = S() + let s2 = s as {I2} `, ) @@ -2039,8 +2035,8 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{I1, I2} = S() - let s2 = s as? AnyStruct{I2} + let s: {I1, I2} = S() + let s2 = s as? {I2} `, ) @@ -2062,8 +2058,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 +2072,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 +2095,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 +2109,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 +2131,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 +2145,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} `, ) @@ -2208,7 +2204,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 +2216,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: AnyStruct{I1} = S() + let s: {I1} = S() let s2 = s as? AnyStruct `, ) @@ -2319,7 +2315,7 @@ func TestCheckReferenceTypeSubTyping(t *testing.T) { "R", "R{I}", "AnyResource", - "AnyResource{I}", + "{I}", "Any", "Any{I}", } { @@ -2383,7 +2379,7 @@ func TestCheckReferenceTypeSubTyping(t *testing.T) { "S", "S{I}", "AnyStruct", - "AnyStruct{I}", + "{I}", "Any", "Any{I}", } { 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/interface_test.go b/runtime/tests/checker/interface_test.go index 8d151bc1e3..8725821f04 100644 --- a/runtime/tests/checker/interface_test.go +++ b/runtime/tests/checker/interface_test.go @@ -1969,7 +1969,6 @@ func TestCheckInvalidInterfaceUseAsTypeSuggestion(t *testing.T) { { TypeAnnotation: sema.NewTypeAnnotation( &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ iType, }, @@ -1981,7 +1980,6 @@ func TestCheckInvalidInterfaceUseAsTypeSuggestion(t *testing.T) { &sema.DictionaryType{ KeyType: sema.IntType, ValueType: &sema.IntersectionType{ - Type: sema.AnyStructType, Types: []*sema.InterfaceType{ iType, }, diff --git a/runtime/tests/checker/intersection_test.go b/runtime/tests/checker/intersection_test.go index 0d397633fc..2b01a642b6 100644 --- a/runtime/tests/checker/intersection_test.go +++ b/runtime/tests/checker/intersection_test.go @@ -324,55 +324,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 +345,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 } @@ -441,7 +396,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 +404,7 @@ func TestCheckRestrictedTypeMemberAccess(t *testing.T) { errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.InvalidIntersectionTypeMemberAccessError{}, errs[0]) + assert.IsType(t, &sema.InvalidAccessError{}, errs[0]) }) t.Run("type without member: struct", func(t *testing.T) { @@ -469,14 +424,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.InvalidAccessError{}, errs[0]) }) t.Run("types with clashing members: resource", func(t *testing.T) { @@ -924,8 +879,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 +902,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 +925,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 +952,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 +996,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 +1022,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 +1048,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 +1078,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"), 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 a875424251..34266fc958 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,28 +1257,12 @@ 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) 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/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/dynamic_casting_test.go b/runtime/tests/interpreter/dynamic_casting_test.go index f124cacded..23086fb001 100644 --- a/runtime/tests/interpreter/dynamic_casting_test.go +++ b/runtime/tests/interpreter/dynamic_casting_test.go @@ -962,7 +962,7 @@ func TestInterpretDynamicCastingStructInterface(t *testing.T) { types := []string{ "AnyStruct", "S", - "AnyStruct{I}", + "{I}", } for operation := range dynamicCastingOperations { @@ -1014,7 +1014,7 @@ func TestInterpretDynamicCastingResourceInterface(t *testing.T) { types := []string{ "AnyResource", "R", - "AnyResource{I}", + "{I}", } for operation := range dynamicCastingOperations { @@ -1530,7 +1530,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: RI {} `, - "AnyResource{RI}", + "{RI}", "R{RI}", operation, ) @@ -1547,7 +1547,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource T {} `, - "AnyResource{RI}", + "{RI}", "T{}", operation, ) @@ -1607,7 +1607,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: RI {} `, - "AnyResource{RI}", + "{RI}", "R", operation, ) @@ -1623,7 +1623,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource T: RI {} `, - "AnyResource{RI}", + "{RI}", "T", operation, ) @@ -1672,7 +1672,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: RI {} `, "R", - "AnyResource{RI}", + "{RI}", operation, ) }) @@ -1686,7 +1686,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I {} `, "R{I}", - "AnyResource{I}", + "{I}", operation, ) }) @@ -1702,7 +1702,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, "R{I1}", - "AnyResource{I2}", + "{I2}", operation, ) }) @@ -1717,8 +1717,8 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "AnyResource{I1, I2}", - "AnyResource{I2}", + "{I1, I2}", + "{I2}", operation, ) }) @@ -1733,8 +1733,8 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "AnyResource{I1}", - "AnyResource{I1, I2}", + "{I1}", + "{I1, I2}", operation, ) }) @@ -1749,8 +1749,8 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "AnyResource{I1}", - "AnyResource{I2}", + "{I1}", + "{I2}", operation, ) }) @@ -1766,8 +1766,8 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1 {} `, - "AnyResource{I1}", - "AnyResource{I2}", + "{I1}", + "{I2}", operation, ) }) @@ -1782,8 +1782,8 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1 {} `, - "AnyResource{I1}", - "AnyResource{I1, I2}", + "{I1}", + "{I1, I2}", operation, ) }) @@ -1797,7 +1797,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I {} `, "AnyResource", - "AnyResource{I}", + "{I}", operation, ) }) @@ -1830,7 +1830,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "AnyResource{I1}", + "{I1}", "AnyResource", operation, ) @@ -1919,7 +1919,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: SI {} `, - "AnyStruct{SI}", + "{SI}", "S{SI}", operation, ) @@ -1936,7 +1936,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct T {} `, - "AnyStruct{SI}", + "{SI}", "T{}", operation, ) @@ -1996,7 +1996,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: SI {} `, - "AnyStruct{SI}", + "{SI}", "S", operation, ) @@ -2012,7 +2012,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct T: SI {} `, - "AnyStruct{SI}", + "{SI}", "T", operation, ) @@ -2061,7 +2061,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: SI {} `, "S", - "AnyStruct{SI}", + "{SI}", operation, ) }) @@ -2075,7 +2075,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I {} `, "S{I}", - "AnyStruct{I}", + "{I}", operation, ) }) @@ -2091,7 +2091,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, "S{I1}", - "AnyStruct{I2}", + "{I2}", operation, ) }) @@ -2106,8 +2106,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "AnyStruct{I1, I2}", - "AnyStruct{I2}", + "{I1, I2}", + "{I2}", operation, ) }) @@ -2122,8 +2122,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "AnyStruct{I1}", - "AnyStruct{I1, I2}", + "{I1}", + "{I1, I2}", operation, ) }) @@ -2138,8 +2138,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "AnyStruct{I1}", - "AnyStruct{I2}", + "{I1}", + "{I2}", operation, ) }) @@ -2155,8 +2155,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1 {} `, - "AnyStruct{I1}", - "AnyStruct{I2}", + "{I1}", + "{I2}", operation, ) }) @@ -2171,8 +2171,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1 {} `, - "AnyStruct{I1}", - "AnyStruct{I1, I2}", + "{I1}", + "{I1, I2}", operation, ) }) @@ -2186,7 +2186,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I {} `, "AnyStruct", - "AnyStruct{I}", + "{I}", operation, ) }) @@ -2219,7 +2219,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "AnyStruct{I1}", + "{I1}", "AnyStruct", operation, ) @@ -2478,7 +2478,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{RI}", + "auth(E) &{RI}", "&R{RI}", operation, true, @@ -2498,7 +2498,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{RI}", + "auth(E) &{RI}", "&T{}", operation, true, @@ -2570,7 +2570,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{RI}", + "auth(E) &{RI}", "&R", operation, true, @@ -2589,7 +2589,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{RI}", + "auth(E) &{RI}", "&T", operation, true, @@ -2644,7 +2644,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &R", - "&AnyResource{RI}", + "&{RI}", operation, true, ) @@ -2661,7 +2661,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &R{I}", - "&AnyResource{I}", + "&{I}", operation, true, ) @@ -2680,7 +2680,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &R{I1}", - "&AnyResource{I2}", + "&{I2}", operation, true, ) @@ -2698,8 +2698,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{I1, I2}", - "&AnyResource{I2}", + "auth(E) &{I1, I2}", + "&{I2}", operation, true, ) @@ -2717,8 +2717,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{I1}", - "&AnyResource{I1, I2}", + "auth(E) &{I1}", + "&{I1, I2}", operation, true, ) @@ -2736,8 +2736,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{I1}", - "&AnyResource{I2}", + "auth(E) &{I1}", + "&{I2}", operation, true, ) @@ -2755,8 +2755,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &AnyResource{I1}", - "&AnyResource{I2}", + "auth(E) &{I1}", + "&{I2}", operation, true, ) @@ -2773,8 +2773,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, ) @@ -2790,7 +2790,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyResource", - "&AnyResource{I}", + "&{I}", operation, true, ) @@ -2827,7 +2827,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { resource R: I1, I2 {} entitlement E `, - "auth(E) &AnyResource{I1}", + "auth(E) &{I1}", "&AnyResource", operation, true, @@ -2926,7 +2926,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: SI {} entitlement E `, - "auth(E) &AnyStruct{SI}", + "auth(E) &{SI}", "&S{SI}", operation, false, @@ -2945,7 +2945,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct T {} entitlement E `, - "auth(E) &AnyStruct{SI}", + "auth(E) &{SI}", "&T{}", operation, false, @@ -3013,7 +3013,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: SI {} entitlement E `, - "auth(E) &AnyStruct{SI}", + "auth(E) &{SI}", "&S", operation, false, @@ -3031,7 +3031,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct T: SI {} entitlement E `, - "auth(E) &AnyStruct{SI}", + "auth(E) &{SI}", "&T", operation, false, @@ -3083,7 +3083,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &S", - "&AnyStruct{SI}", + "&{SI}", operation, false, ) @@ -3099,7 +3099,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &S{I}", - "&AnyStruct{I}", + "&{I}", operation, false, ) @@ -3117,7 +3117,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &S{I1}", - "&AnyStruct{I2}", + "&{I2}", operation, false, ) @@ -3134,8 +3134,8 @@ 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, ) @@ -3152,8 +3152,8 @@ 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, ) @@ -3170,8 +3170,8 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} entitlement E `, - "auth(E) &AnyStruct{I1}", - "&AnyStruct{I2}", + "auth(E) &{I1}", + "&{I2}", operation, false, ) @@ -3188,8 +3188,8 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1 {} entitlement E `, - "auth(E) &AnyStruct{I1}", - "&AnyStruct{I2}", + "auth(E) &{I1}", + "&{I2}", operation, false, ) @@ -3206,8 +3206,8 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1 {} entitlement E `, - "auth(E) &AnyStruct{I1}", - "&AnyStruct{I1, I2}", + "auth(E) &{I1}", + "&{I1, I2}", operation, false, ) @@ -3223,7 +3223,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyStruct", - "&AnyStruct{I}", + "&{I}", operation, false, ) @@ -3260,7 +3260,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} entitlement E `, - "auth(E) &AnyStruct{I1}", + "auth(E) &{I1}", "&AnyStruct", operation, false, @@ -3340,7 +3340,7 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: RI {} `, "&R", - "&AnyResource{RI}", + "&{RI}", operation, true, ) @@ -3355,7 +3355,7 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I {} `, "&R{I}", - "&AnyResource{I}", + "&{I}", operation, true, ) @@ -3371,8 +3371,8 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I1, I2 {} `, - "&AnyResource{I1, I2}", - "&AnyResource{I2}", + "&{I1, I2}", + "&{I2}", operation, true, ) @@ -3407,7 +3407,7 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I1, I2 {} `, - "&AnyResource{I1}", + "&{I1}", "&AnyResource", operation, true, @@ -3486,7 +3486,7 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: RI {} `, "&S", - "&AnyStruct{RI}", + "&{RI}", operation, false, ) @@ -3501,7 +3501,7 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: I {} `, "&S{I}", - "&AnyStruct{I}", + "&{I}", operation, false, ) @@ -3517,8 +3517,8 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} `, - "&AnyStruct{I1, I2}", - "&AnyStruct{I2}", + "&{I1, I2}", + "&{I2}", operation, false, ) @@ -3553,7 +3553,7 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} `, - "&AnyStruct{I1}", + "&{I1}", "&AnyStruct", operation, false, diff --git a/runtime/tests/interpreter/entitlements_test.go b/runtime/tests/interpreter/entitlements_test.go index eb3e1e4863..51465ccf4c 100644 --- a/runtime/tests/interpreter/entitlements_test.go +++ b/runtime/tests/interpreter/entitlements_test.go @@ -532,7 +532,7 @@ func TestInterpretEntitledReferenceCasting(t *testing.T) { fun test(): Bool { let x <- create R() - let r = &x as auth(E) &AnyResource{RI} + let r = &x as auth(E) &{RI} let r2 = r as! &R{RI} let isSuccess = r2 != nil destroy x diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 9aec8999d8..f7b71a3b32 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -4889,7 +4889,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 @@ -4898,7 +4898,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 @@ -4907,8 +4907,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 @@ -4995,14 +4995,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, }, 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..54f262e26e 100644 --- a/runtime/tests/interpreter/memory_metering_test.go +++ b/runtime/tests/interpreter/memory_metering_test.go @@ -8041,7 +8041,7 @@ func TestInterpretInterfaceStaticType(t *testing.T) { struct interface I {} access(all) fun main() { - let type = Type() + let type = Type<{I}>() IntersectionType( identifier: type.identifier, @@ -8483,7 +8483,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 } @@ -8671,7 +8671,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 +9263,7 @@ func TestInterpretStaticTypeStringConversion(t *testing.T) { script := ` access(all) fun main() { - log(Type()) + log(Type<{Foo}>()) } struct interface Foo {} diff --git a/types.go b/types.go index ebcc519c9c..012ec42fd1 100644 --- a/types.go +++ b/types.go @@ -2027,29 +2027,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() {} @@ -2064,11 +2060,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 } @@ -2079,16 +2071,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 f71acdbf1c..e2cebaccbc 100644 --- a/types_test.go +++ b/types_test.go @@ -171,10 +171,6 @@ func TestType_ID(t *testing.T) { }, { &IntersectionType{ - Type: &ResourceType{ - Location: utils.TestLocation, - QualifiedIdentifier: "Foo", - }, Types: []Type{ &ResourceInterfaceType{ Location: utils.TestLocation, @@ -182,7 +178,7 @@ func TestType_ID(t *testing.T) { }, }, }, - "S.test.Foo{S.test.FooI}", + "{S.test.FooI}", }, { &FunctionType{ @@ -1700,14 +1696,12 @@ func TestTypeEquality(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, IntType{}, }, } target := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, IntType{}, @@ -1720,14 +1714,12 @@ func TestTypeEquality(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, IntType{}, }, } target := &IntersectionType{ - Type: IntType{}, Types: []Type{ IntType{}, AnyType{}, @@ -1740,7 +1732,6 @@ func TestTypeEquality(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ IntType{}, AnyType{}, @@ -1748,7 +1739,6 @@ func TestTypeEquality(t *testing.T) { }, } target := &IntersectionType{ - Type: IntType{}, Types: []Type{ IntType{}, AnyType{}, @@ -1757,38 +1747,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{}, @@ -1801,13 +1769,11 @@ func TestTypeEquality(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, }, } target := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, StringType{}, @@ -1820,7 +1786,6 @@ func TestTypeEquality(t *testing.T) { t.Parallel() source := &IntersectionType{ - Type: IntType{}, Types: []Type{ AnyType{}, }, From 0cb90c24c211855d756ded33d0f70122dcbc237f Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Fri, 16 Jun 2023 17:21:19 -0400 Subject: [PATCH 02/16] partial fix of checker tests --- runtime/sema/checker.go | 11 +- runtime/sema/type_tags.go | 4 + runtime/tests/checker/casting_test.go | 4597 ++++++-------------- runtime/tests/checker/intersection_test.go | 281 +- runtime/tests/checker/reference_test.go | 2 +- 5 files changed, 1503 insertions(+), 3392 deletions(-) diff --git a/runtime/sema/checker.go b/runtime/sema/checker.go index ca8c4ffdec..f1ab6bc97f 100644 --- a/runtime/sema/checker.go +++ b/runtime/sema/checker.go @@ -899,7 +899,7 @@ func CheckIntersectionType( memoryGauge common.MemoryGauge, types []*InterfaceType, report func(func(*ast.IntersectionType) error), -) { +) Type { intersectionRanges := make(map[*InterfaceType]func(*ast.IntersectionType) ast.Range, len(types)) intersectionsCompositeKind := common.CompositeKindUnknown memberSet := map[string]*InterfaceType{} @@ -986,6 +986,7 @@ func CheckIntersectionType( report(func(t *ast.IntersectionType) error { return &AmbiguousIntersectionTypeError{Range: ast.NewRangeFromPositioned(memoryGauge, t)} }) + return InvalidType case common.CompositeKindResource, common.CompositeKindStructure: break @@ -1019,6 +1020,8 @@ func CheckIntersectionType( } } } + + return &IntersectionType{Types: types} } func (checker *Checker) convertIntersectionType(t *ast.IntersectionType) Type { @@ -1054,7 +1057,7 @@ func (checker *Checker) convertIntersectionType(t *ast.IntersectionType) Type { intersectedTypes = append(intersectedTypes, intersectedInterfaceType) } - CheckIntersectionType( + intersectionType := CheckIntersectionType( checker.memoryGauge, intersectedTypes, func(getError func(*ast.IntersectionType) error) { @@ -1062,9 +1065,7 @@ func (checker *Checker) convertIntersectionType(t *ast.IntersectionType) Type { }, ) - return &IntersectionType{ - Types: intersectedTypes, - } + return intersectionType } func (checker *Checker) convertReferenceType(t *ast.ReferenceType) Type { diff --git a/runtime/sema/type_tags.go b/runtime/sema/type_tags.go index f98f4f9ac8..27eca56979 100644 --- a/runtime/sema/type_tags.go +++ b/runtime/sema/type_tags.go @@ -930,6 +930,10 @@ func commonSuperTypeOfComposites(types []Type) Type { } if hasCommonInterface { + if len(commonInterfacesList) == 0 { + panic(errors.NewUnreachableError()) + } + return &IntersectionType{ Types: commonInterfacesList, } diff --git a/runtime/tests/checker/casting_test.go b/runtime/tests/checker/casting_test.go index acb5ea7b49..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 {} @@ -428,24 +414,20 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` let r: @{RI} <- create R() - let r2 <- r as @R{RI} + 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}? { + fun test(): @{RI}? { let r: @{RI} <- create R() - if let r2 <- r as? @R{RI} { + 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 {} @@ -472,24 +454,22 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` let r: @{RI} <- create R() - let r2 <- r as @R{RI} + 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}? { + fun test(): @{RI}? { let r: @{RI} <- create R() - if let r2 <- r as? @R{RI} { + 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) }) }) @@ -832,29 +803,14 @@ 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 @{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{ - Types: []*sema.InterfaceType{ - iType.(*sema.InterfaceType), - }, - }, - r2Type, - ) }) t.Run("dynamic", func(t *testing.T) { @@ -862,7 +818,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @{I}? { - let r: @R{I} <- create R() + let r: @{I} <- create R() if let r2 <- r as? @{I} { return <-r2 } else { @@ -877,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 {} @@ -889,29 +845,16 @@ 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 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{ - Types: []*sema.InterfaceType{ - i2Type.(*sema.InterfaceType), - }, - }, - r2Type, - ) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) t.Run("dynamic", func(t *testing.T) { @@ -919,7 +862,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @{I2}? { - let r: @R{I1} <- create R() + let r: @{I1} <- create R() if let r2 <- r as? @{I2} { return <-r2 } else { @@ -948,7 +891,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 @{I2} `, ) @@ -963,7 +906,7 @@ func TestCheckCastResourceType(t *testing.T) { _, err := ParseAndCheck(t, types+` fun test(): @{I2}? { - let r: @R{I1} <- create R() + let r: @{I1} <- create R() if let r2 <- r as? @{I2} { return <-r2 } else { @@ -974,9 +917,7 @@ func TestCheckCastResourceType(t *testing.T) { `, ) - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + require.NoError(t, err) }) }) @@ -1168,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 `, ) @@ -1181,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 { @@ -1296,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} `, ) @@ -1315,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} `, ) @@ -1343,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} `, ) @@ -1403,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 {} @@ -1427,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} `, ) @@ -1446,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} `, ) @@ -1454,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]) @@ -1482,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 {} @@ -1505,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} `, ) @@ -1530,12 +1421,14 @@ 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) { @@ -1543,7 +1436,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: {SI} = S() - let s2 = s as S{SI} + let s2 = s as S `, ) @@ -1559,7 +1452,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: {SI} = S() - let s2 = s as? S{SI} + let s2 = s as? S `, ) @@ -1567,12 +1460,12 @@ 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) { @@ -1580,15 +1473,14 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: {SI} = S() - let s2 = s as S{SI} + 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) { @@ -1596,51 +1488,43 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` let s: {SI} = S() - let s2 = s as? S{SI} + 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 `, ) @@ -1649,172 +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 - `, - ) - - 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: T{I} = S() - let t = s as? T - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - }) - - t.Run("intersection AnyStruct -> conforming struct", 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: {SI} = S() - 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 := ParseAndCheck(t, - types+` - let s: {SI} = S() - let s2 = s as? S - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run("intersection AnyStruct -> non-conforming struct", func(t *testing.T) { - - const types = ` - struct interface SI {} - - struct S {} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheck(t, - types+` - let s: {SI} = S() - 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 := ParseAndCheck(t, - types+` - let s: {SI} = S() - let s2 = s as? S - `, - ) - - errs := RequireCheckerErrors(t, err, 1) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) - }) - - t.Run("AnyStruct -> 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: AnyStruct = S() - 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 := ParseAndCheck(t, - types+` - let s: AnyStruct = S() - let s2 = s as? S - `, - ) - - require.NoError(t, err) - }) - }) - - // 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 {SI} + let s: S = S() + let s2 = s as {SI} `, ) @@ -1872,105 +1607,7 @@ func TestCheckCastStructType(t *testing.T) { }) }) - 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 {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{ - 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? {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 {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{ - 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? {I2} - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run("intersection type -> intersection AnyStruct with non-conformance type", func(t *testing.T) { + t.Run("intersection type -> intersection with non-conformance type", func(t *testing.T) { const types = ` struct interface I1 {} @@ -1984,7 +1621,7 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: S{I1} = S() + let s: {I1} = S() let s2 = s as {I2} `, ) @@ -1998,18 +1635,16 @@ func TestCheckCastStructType(t *testing.T) { _, err := ParseAndCheck(t, types+` - let s: S{I1} = 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("intersection AnyStruct -> intersection AnyStruct: fewer types", func(t *testing.T) { + t.Run("intersection -> intersection: fewer types", func(t *testing.T) { const types = ` struct interface I1 {} @@ -2169,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 `, ) @@ -2181,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 `, ) @@ -2313,11 +1948,9 @@ func TestCheckReferenceTypeSubTyping(t *testing.T) { for _, ty := range []string{ "R", - "R{I}", "AnyResource", "{I}", "Any", - "Any{I}", } { test(ty) } @@ -2377,11 +2010,9 @@ func TestCheckReferenceTypeSubTyping(t *testing.T) { for _, ty := range []string{ "S", - "S{I}", "AnyStruct", "{I}", "Any", - "Any{I}", } { test(ty) } @@ -2458,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} `, ) @@ -2476,7 +2107,7 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { _, err := ParseAndCheck(t, setup+` - let r2 = r as? &R{I2} + let r2 = r as? &{I2} `, ) @@ -2495,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} `, ) @@ -2521,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 {} @@ -2571,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 `, ) @@ -2597,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]) @@ -2626,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) @@ -2795,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) @@ -2834,16 +2455,56 @@ 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} + `, + ) + + require.NoError(t, err) + }) + }) + + t.Run("intersection type -> intersection with non-conformance type", func(t *testing.T) { + + const setup = ` + resource interface I1 {} + + resource interface I2 {} + + resource R: I1 {} + entitlement X + + let x <- create R() + let r = &x as auth(X) &{I1} + ` + + t.Run("static", func(t *testing.T) { + + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as &{I2} + `, ) errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) + + t.Run("dynamic", func(t *testing.T) { + + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let r2 = r as? &{I2} + `, + ) + + require.NoError(t, err) + }) }) for _, ty := range []sema.Type{ @@ -2851,7 +2512,7 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { sema.AnyType, } { - t.Run(fmt.Sprintf("intersection %s -> conforming resource", ty), func(t *testing.T) { + t.Run(fmt.Sprintf("%s -> type", ty), func(t *testing.T) { setup := fmt.Sprintf( ` @@ -2861,7 +2522,7 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { entitlement X let x <- create R() - let r = &x as auth(X) &%s{RI} + let r = &x as auth(X) &%s `, ty, ) @@ -2874,8 +2535,6 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { `, ) - // NOTE: static cast not allowed, only dynamic - errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) @@ -2893,98 +2552,57 @@ func TestCheckCastAuthorizedResourceReferenceType(t *testing.T) { }) }) - t.Run(fmt.Sprintf("intersection %s -> non-conforming resource", ty), func(t *testing.T) { + t.Run(fmt.Sprintf("intersection type -> %s", ty), func(t *testing.T) { - setup := fmt.Sprintf( - ` - resource interface RI {} + const setup = ` + resource interface I1 {} - resource R {} - entitlement X + resource interface I2 {} - let x <- create R() - let r = &x as auth(X) &%s{RI} - `, - ty, - ) + resource R: I1, I2 {} + entitlement X + + let x <- create R() + let r = &x as auth(X) &{I1} + ` t.Run("static", func(t *testing.T) { _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as &R - `, + setup+fmt.Sprintf( + ` + let r2 = r as &%s + `, + ty, + ), ) - errs := RequireCheckerErrors(t, err, 2) - - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) + require.NoError(t, err) }) t.Run("dynamic", func(t *testing.T) { _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as? &R - `, + setup+fmt.Sprintf( + ` + 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("%s -> type", 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 - `, - ty, - ) - - t.Run("static", 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]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let r2 = r as? &R - `, - ) - - require.NoError(t, err) - }) - }) - - // Supertype: intersection AnyResource / Any - - t.Run(fmt.Sprintf("resource -> intersection %s with non-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 {} - // NOTE: R does not conform to RI - resource R {} + resource R: I1, I2 {} entitlement X let x <- create R() @@ -2996,15 +2614,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) { @@ -3012,2335 +2628,629 @@ 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) { +func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { - const setup = ` - resource interface RI {} + t.Parallel() - resource R: RI {} - entitlement X + // Supertype: Intersection type - let x <- create R() - let r = &x as auth(X) &R - ` + 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{RI} - `, - 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{RI} - `, - 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 in type", ty), func(t *testing.T) { + t.Run("dynamic", func(t *testing.T) { - const setup = ` - resource interface I {} + _, err := ParseAndCheck(t, + setup+` + let s2 = s as? &{I2} + `, + ) - resource R: I {} - entitlement X + require.NoError(t, err) + }) + }) - let x <- create R() - let r = &x as auth(X) &R{I} - ` + t.Run("intersection type -> intersection type: more 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} + ` - _, 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 &{I1, I2} + `, + ) - t.Run(fmt.Sprintf("intersection type -> intersection %s with conformance not in type", ty), func(t *testing.T) { + errs := RequireCheckerErrors(t, err, 1) - const setup = ` - resource interface I1 {} + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - resource interface I2 {} + t.Run("dynamic", func(t *testing.T) { - resource R: I1, I2 {} - entitlement X + _, err := ParseAndCheck(t, + setup+` + let s2 = s as? &{I1, I2} + `, + ) - let x <- create R() - let r = &x as auth(X) &R{I1} - ` + require.NoError(t, err) + }) + }) - t.Run("static", func(t *testing.T) { + t.Run("intersection type -> intersection type: different struct", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I2} - `, - ty, - ), - ) + const setup = ` + struct interface I {} - require.NoError(t, err) - }) + struct S1: I {} - t.Run("dynamic", func(t *testing.T) { + struct S2: I {} + entitlement X - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I2} - `, - ty, - ), - ) + let x = S1() + let s = &x as auth(X) &{I} + ` - require.NoError(t, err) - }) - }) + t.Run("static", func(t *testing.T) { - t.Run(fmt.Sprintf("intersection type -> intersection %s with non-conformance type", ty), func(t *testing.T) { + _, err := ParseAndCheck(t, + setup+` + let s2 = s as &{I} + `, + ) - const setup = ` - resource interface I1 {} + require.NoError(t, err) + }) - resource interface I2 {} + t.Run("dynamic", func(t *testing.T) { - resource R: I1 {} - entitlement X + _, err := ParseAndCheck(t, + setup+` + let s2 = s as? &{I} + `, + ) - let x <- create R() - let r = &x as auth(X) &R{I1} - ` + require.NoError(t, err) + }) + }) - t.Run("static", func(t *testing.T) { + t.Run("type -> intersection type: same struct", func(t *testing.T) { - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I2} - `, - ty, - ), - ) + const setup = ` + struct interface I {} - errs := RequireCheckerErrors(t, err, 1) + struct S: I {} + entitlement X - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + let x = S() + let s = &x as auth(X) &S - t.Run("dynamic", func(t *testing.T) { + ` - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I2} - `, - ty, - ), - ) + t.Run("static", 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) }) - 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) { + t.Run("dynamic", func(t *testing.T) { - setup := fmt.Sprintf( - ` - resource interface I1 {} + _, err := ParseAndCheck(t, + setup+` + let s2 = s as? &{I} + `, + ) - resource interface I2 {} + require.NoError(t, err) + }) + }) - 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) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I2} - `, - otherType, - ), - ) + for _, ty := range []sema.Type{ + sema.AnyStructType, + sema.AnyType, + } { - if ty == sema.AnyType && otherType == sema.AnyResourceType { + t.Run(fmt.Sprintf("%s -> conforming intersection type", ty), func(t *testing.T) { - errs := RequireCheckerErrors(t, err, 1) + setup := fmt.Sprintf( + ` + struct interface SI {} - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + struct S: SI {} + entitlement X - return - } + let x = S() + let s = &x as auth(X) &%s + `, + ty, + ) - require.NoError(t, err) - }) + t.Run("static", func(t *testing.T) { - t.Run("dynamic", func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as &{SI} + `, + ) - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I2} - `, - otherType, - ), - ) + errs := RequireCheckerErrors(t, err, 1) - require.NoError(t, err) - }) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) - t.Run(fmt.Sprintf("intersection %s -> intersection %s: more types", ty, otherType), func(t *testing.T) { - - setup := fmt.Sprintf( - ` - resource interface I1 {} - - resource interface I2 {} - - 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) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r 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 r2 = r as? &%s{I1, I2} - `, - otherType, - ), - ) - - require.NoError(t, err) - }) + 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( - ` - resource interface I1 {} + // Supertype: Struct - resource interface I2 {} + t.Run("intersection type -> type: same struct", func(t *testing.T) { - resource R: I1 {} - entitlement X + const setup = ` + struct interface I {} - let x <- create R() - let r = &x as auth(X) &%s{I1} - `, - ty, - ) + struct S: I {} + entitlement X - t.Run("static", func(t *testing.T) { + let x = S() + let s = &x as auth(X) &{I} + ` - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I1, I2} - `, - otherType, - ), - ) + t.Run("static", func(t *testing.T) { - errs := RequireCheckerErrors(t, err, 1) + _, err := ParseAndCheck(t, + setup+` + let s2 = s as &S + `, + ) - 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+fmt.Sprintf( - ` - let r2 = r as? &%s{I1, I2} - `, - otherType, - ), - ) + t.Run("dynamic", func(t *testing.T) { - require.NoError(t, err) - }) - }) + _, err := ParseAndCheck(t, + setup+` + let s2 = s as? &S + `, + ) - t.Run(fmt.Sprintf("%s -> intersection %s", ty, otherType), func(t *testing.T) { + require.NoError(t, err) + }) + }) - setup := fmt.Sprintf( - ` - resource interface I {} + t.Run("intersection type -> type: different struct", func(t *testing.T) { - resource R: I {} - entitlement X + const setup = ` + struct interface I {} - let x <- create R() - let r = &x as auth(X) &%s - `, - ty, - ) + struct S: I {} - t.Run("static", func(t *testing.T) { + struct T: I {} + entitlement X - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s{I} - `, - otherType, - ), - ) + let x = S() + let s = &x as auth(X) &{I} + ` - errs := RequireCheckerErrors(t, err, 1) + t.Run("static", func(t *testing.T) { - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - }) + _, err := ParseAndCheck(t, + setup+` + let t = s as &T + `, + ) - t.Run("dynamic", func(t *testing.T) { + errs := RequireCheckerErrors(t, err, 1) - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s{I} - `, - otherType, - ), - ) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - require.NoError(t, err) - }) - }) - } + t.Run("dynamic", func(t *testing.T) { - // Supertype: AnyResource / Any + _, err := ParseAndCheck(t, + setup+` + let t = s as? &T + `, + ) - t.Run(fmt.Sprintf("intersection type -> %s", ty), func(t *testing.T) { + require.NoError(t, err) + }) + }) - const setup = ` - resource interface I1 {} + t.Run("intersection -> conforming struct", func(t *testing.T) { - resource interface I2 {} + setup := + ` + struct interface RI {} - resource R: I1, I2 {} + struct S: RI {} entitlement X - let x <- create R() - let r = &x as auth(X) &R{I1} - ` - - t.Run("static", func(t *testing.T) { + let x = S() + let s = &x as auth(X) &{RI} + ` - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s - `, - ty, - ), - ) + t.Run("static", func(t *testing.T) { - require.NoError(t, err) - }) + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as &S + `, + ) - t.Run("dynamic", func(t *testing.T) { + // NOTE: static cast not allowed, only dynamic - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s - `, - ty, - ), - ) + errs := RequireCheckerErrors(t, err, 1) - require.NoError(t, err) - }) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) }) - for _, otherType := range []sema.Type{ - sema.AnyResourceType, - sema.AnyType, - } { - t.Run(fmt.Sprintf("intersection %s -> %s", ty, otherType), func(t *testing.T) { + t.Run("dynamic", func(t *testing.T) { - setup := fmt.Sprintf( - ` - resource interface I1 {} + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as? &S + `, + ) - resource interface I2 {} + require.NoError(t, err) + }) + }) - resource R: I1, I2 {} - entitlement X + t.Run("intersection -> non-conforming struct", func(t *testing.T) { - let x <- create R() - let r = &x as auth(X) &%s{I1} - `, - ty, - ) + setup := + ` + struct interface RI {} - t.Run("static", func(t *testing.T) { + struct S {} + entitlement X - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s - `, - otherType, - ), - ) + let x = S() + let s = &x as auth(X) &{RI} + ` - if ty == sema.AnyType && otherType == sema.AnyResourceType { + t.Run("static", func(t *testing.T) { - errs := RequireCheckerErrors(t, err, 1) + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as &S + `, + ) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + errs := RequireCheckerErrors(t, err, 2) - return - } + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + assert.IsType(t, &sema.TypeMismatchError{}, errs[1]) + }) - require.NoError(t, err) - }) + t.Run("dynamic", func(t *testing.T) { - t.Run("dynamic", 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) - require.NoError(t, err) - }) - }) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) + }) - } + t.Run("struct -> intersection with non-conformance type", func(t *testing.T) { - t.Run(fmt.Sprintf("type -> %s", ty), func(t *testing.T) { + const setup = ` + struct interface SI {} - const setup = ` - resource interface I1 {} + // NOTE: S does not conform to SI + struct S {} + entitlement X - resource interface I2 {} + let x = S() + let s = &x as auth(X) &S + ` - resource R: I1, I2 {} - entitlement X + t.Run("static", func(t *testing.T) { - let x <- create R() - let r = &x as auth(X) &R - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as &%s - `, - ty, - ), - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+fmt.Sprintf( - ` - let r2 = r as? &%s - `, - ty, - ), - ) - - require.NoError(t, err) - }) - }) - } -} - -func TestCheckCastAuthorizedStructReferenceType(t *testing.T) { - - t.Parallel() - - // Supertype: Intersection type - - t.Run("intersection type -> intersection type: fewer types", 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, I2} - ` - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheck(t, - setup+` - let s2 = s as &S{I2} - `, - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - setup+` - let s2 = s as? &S{I2} - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run("intersection type -> intersection type: more types", 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) { - - const setup = ` - struct interface I {} - - struct S1: I {} - - struct S2: I {} - entitlement X - - let x = S1() - let s = &x as auth(X) &S1{I} - ` - - 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} - `, - ) - - 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} - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run("type -> intersection type: different struct", func(t *testing.T) { - - const setup = ` - struct interface I {} - - struct S1: I {} - - struct S2: I {} - entitlement X - - let x = S1() - let s = &x as auth(X) &S1 - ` - - 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 &{SI} + `, ) 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 intersection 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{SI} - `, - ty, - ) - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as &S{SI} - `, - ) - - // 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{SI} - `, - ) - - require.NoError(t, err) - }) - }) - - t.Run(fmt.Sprintf("%s -> conforming intersection 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{SI} - `, - ) - - 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{SI} - `, - ) - - 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 {} - - struct S {} - entitlement X - - let x = S() - let s = &x as auth(X) &%s{SI} - `, - ty, - ) - - t.Run("static", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as &S{SI} - `, - ) - - 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]) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheckWithAny(t, - setup+` - let s2 = s as? &S{SI} - `, - ) - - errs := RequireCheckerErrors(t, err, 2) - - 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) { - - 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 := ParseAndCheck(t, - setup+` - let s2 = s as &S - `, - ) - - require.NoError(t, err) - }) - - t.Run("dynamic", func(t *testing.T) { - - _, err := ParseAndCheck(t, - setup+` - let s2 = s as? &S - `, - ) - - 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, - ), - ) - - 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, - ), - ) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - require.NoError(t, err) - }) + t.Run("dynamic", func(t *testing.T) { - t.Run(fmt.Sprintf("intersection type -> intersection %s with non-conformance type", ty), func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as? &{SI} + `, + ) - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} + errs := RequireCheckerErrors(t, err, 1) - resource interface I2 {} + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) + }) - resource R: I1 {} + t.Run("struct -> intersection with conformance type", func(t *testing.T) { - let x <- create R() - let r = &x as &R{I1} - let r2 = r %s &%s{I2} - `, - op, - ty, - ), - ) + const setup = ` + struct interface SI {} - errs := RequireCheckerErrors(t, err, 1) + struct S: SI {} + entitlement X - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + let x = S() + let s = &x as auth(X) &S + ` - }) + t.Run("static", func(t *testing.T) { - for _, otherType := range []sema.Type{ - sema.AnyResourceType, - sema.AnyType, - } { + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as &{SI} + `, + ) - t.Run(fmt.Sprintf("intersection %s -> intersection %s: fewer types", ty, otherType), func(t *testing.T) { + require.NoError(t, err) + }) - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} + t.Run("dynamic", func(t *testing.T) { - resource interface I2 {} + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as? &{SI} + `, + ) - resource R: I1, I2 {} + require.NoError(t, err) + }) + }) - let x <- create R() - let r = &x as &%s{I1, I2} - let r2 = r %s &%s{I2} - `, - ty, - op, - otherType, - ), - ) + t.Run("intersection type -> intersection with conformance in type", func(t *testing.T) { - if ty == sema.AnyType && otherType == sema.AnyResourceType { + const setup = ` + struct interface I {} - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) + struct S: I {} - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } + entitlement X - return - } + let x = S() + let s = &x as auth(X) &{I} + ` - require.NoError(t, err) - }) + t.Run("static", func(t *testing.T) { - t.Run(fmt.Sprintf("intersection %s -> intersection %s: more types", ty, otherType), func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as &{I} + `, + ) - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} + require.NoError(t, err) + }) - resource interface I2 {} + t.Run("dynamic", func(t *testing.T) { - resource R: I1, I2 {} + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as? &{I} + `, + ) - let x <- create R() - let r = &x as &%s{I1} - let r2 = r %s &%s{I1, I2} - `, - ty, - op, - otherType, - ), - ) + require.NoError(t, err) + }) + }) - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) + t.Run("intersection type -> intersection with conformance not in type", func(t *testing.T) { - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) + const setup = ` + struct interface I1 {} - t.Run(fmt.Sprintf("intersection %s -> intersection %s with non-conformance type", ty, otherType), func(t *testing.T) { + struct interface I2 {} - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} + struct S: I1, I2 {} - resource interface I2 {} + entitlement X - resource R: I1 {} + let x = S() + let s = &x as auth(X) &{I1} + ` - let x <- create R() - let r = &x as &%s{I1} - let r2 = r %s &%s{I1, I2} - `, - ty, - op, - otherType, - ), - ) + t.Run("static", func(t *testing.T) { - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as &{I2} + `, + ) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) + errs := RequireCheckerErrors(t, err, 1) - t.Run(fmt.Sprintf("%s -> intersection %s", ty, otherType), func(t *testing.T) { + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I {} + t.Run("dynamic", func(t *testing.T) { - resource R: I {} + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as? &{I2} + `, + ) - let x <- create R() - let r = &x as &%s - let r2 = r %s &%s{I} - `, - ty, - op, - otherType, - ), - ) + require.NoError(t, err) + }) + }) - if name == "static" { - errs := RequireCheckerErrors(t, err, 1) + t.Run("intersection type -> intersection with non-conformance type", func(t *testing.T) { - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) + const setup = ` + struct interface I1 {} - // Supertype: AnyResource / Any + struct interface I2 {} - t.Run(fmt.Sprintf("intersection %s -> %s", ty, otherType), func(t *testing.T) { + struct S: I1 {} - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} + entitlement X - resource interface I2 {} + let x = S() + let s = &x as auth(X) &{I1} + ` - resource R: I1, I2 {} + t.Run("static", func(t *testing.T) { - let x <- create R() - let r = &x as &%s{I1} - let r2 = r %s &%s - `, - ty, - op, - otherType, - ), - ) + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as &{I2} + `, + ) - if ty == sema.AnyType && otherType == sema.AnyResourceType && name == "static" { - errs := RequireCheckerErrors(t, err, 1) + errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) - } else { - require.NoError(t, err) - } - }) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - } + t.Run("dynamic", func(t *testing.T) { - t.Run(fmt.Sprintf("intersection type -> %s", ty), func(t *testing.T) { + _, err := ParseAndCheckWithAny(t, + setup+ + ` + let s2 = s as? &{I2} + `, + ) - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} + require.NoError(t, err) + }) + }) - resource interface I2 {} + for _, ty := range []sema.Type{ + sema.AnyStructType, + sema.AnyType, + } { - resource R: I1, I2 {} + t.Run(fmt.Sprintf("%s -> type", ty), func(t *testing.T) { - let x <- create R() - let r = &x as &R{I1} - let r2 = r %s &%s - `, - op, - ty, - ), - ) + setup := fmt.Sprintf( + ` + struct interface SI {} - require.NoError(t, err) - }) + struct S: SI {} + entitlement X - t.Run(fmt.Sprintf("type -> %s", ty), func(t *testing.T) { + let x = S() + let s = &x as auth(X) &%s + `, + ty, + ) - _, err := ParseAndCheckWithAny(t, - fmt.Sprintf( - ` - resource interface I1 {} + t.Run("static", func(t *testing.T) { - resource interface I2 {} + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as &S + `, + ) - resource R: I1, I2 {} + errs := RequireCheckerErrors(t, err, 1) - let x <- create R() - let r = &x as &R - let r2 = r %s &%s - `, - op, - ty, - ), - ) + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + }) - require.NoError(t, err) - }) - } + t.Run("dynamic", func(t *testing.T) { + + _, err := ParseAndCheckWithAny(t, + setup+` + let s2 = s as? &S + `, + ) + + require.NoError(t, err) + }) }) + } } -func TestCheckCastUnauthorizedStructReferenceType(t *testing.T) { +func TestCheckCastUnauthorizedResourceReferenceType(t *testing.T) { t.Parallel() @@ -5358,130 +3268,252 @@ func TestCheckCastUnauthorizedStructReferenceType(t *testing.T) { _, err := ParseAndCheck(t, fmt.Sprintf( ` - struct interface I1 {} + resource interface I1 {} - struct interface I2 {} + resource interface I2 {} - struct S: I1, I2 {} + resource R: I1, I2 {} - let x = S() - let s = &x as &S{I1, I2} - let s2 = s %s &S{I2} + let x <- create R() + let r = &x as &{I1, I2} + let r2 = r %s &{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 &{I1} + let r2 = r %s &{I1, I2} + `, + op, + ), + ) + + 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: 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 &{I} `, op, ), ) - require.NoError(t, err) - }) + require.NoError(t, err) + }) + + t.Run("intersection -> conforming intersection type", func(t *testing.T) { + + _, err := ParseAndCheckWithAny(t, + fmt.Sprintf( + ` + resource interface RI {} + + resource R: RI {} + + let x <- create R() + let r = &x as &{RI} + let r2 = r %s &{RI} + `, + op, + ), + ) + + require.NoError(t, err) + }) + + for _, ty := range []sema.Type{ + sema.AnyResourceType, + sema.AnyType, + } { + + 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 &{RI} + `, + ty, + op, + ), + ) + + if name == "static" { + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) + } else { + 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, @@ -5497,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, ), ) @@ -5524,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, ), @@ -5580,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( @@ -5677,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, @@ -5691,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/intersection_test.go b/runtime/tests/checker/intersection_test.go index 2b01a642b6..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 } `) @@ -371,7 +343,7 @@ func TestCheckIntersectionTypeMemberAccess(t *testing.T) { } fun test() { - let s: S{I} = S(n: 1) + let s: {I} = S(n: 1) s.n } `) @@ -404,7 +376,7 @@ func TestCheckIntersectionTypeMemberAccess(t *testing.T) { errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.InvalidAccessError{}, errs[0]) + assert.IsType(t, &sema.NotDeclaredMemberError{}, errs[0]) }) t.Run("type without member: struct", func(t *testing.T) { @@ -431,7 +403,7 @@ func TestCheckIntersectionTypeMemberAccess(t *testing.T) { errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.InvalidAccessError{}, errs[0]) + assert.IsType(t, &sema.NotDeclaredMemberError{}, errs[0]) }) t.Run("types with clashing members: resource", func(t *testing.T) { @@ -455,7 +427,7 @@ func TestCheckIntersectionTypeMemberAccess(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 } @@ -488,7 +460,7 @@ func TestCheckIntersectionTypeMemberAccess(t *testing.T) { } fun test() { - let s: S{I1, I2} = S(n: 1) + let s: {I1, I2} = S(n: 1) s.n } `) @@ -500,38 +472,42 @@ func TestCheckIntersectionTypeMemberAccess(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, ` @@ -542,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 } `) @@ -550,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, ` @@ -560,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, ` @@ -575,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, ` @@ -593,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, ` @@ -643,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, ` @@ -662,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, ` @@ -680,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, ` @@ -700,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, ` @@ -718,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 } `) @@ -727,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, ` @@ -737,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, ` @@ -755,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 } `) @@ -764,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, ` @@ -774,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, ` @@ -792,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, ` @@ -811,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() @@ -1090,7 +1084,7 @@ func TestCheckRestrictedTypeNoType(t *testing.T) { }) } -func TestCheckRestrictedTypeConformanceOrder(t *testing.T) { +func TestCheckIntersectionTypeConformanceOrder(t *testing.T) { t.Parallel() @@ -1105,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() @@ -1141,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/reference_test.go b/runtime/tests/checker/reference_test.go index 34266fc958..eef99c1de8 100644 --- a/runtime/tests/checker/reference_test.go +++ b/runtime/tests/checker/reference_test.go @@ -1267,7 +1267,7 @@ func TestCheckInvalidReferenceExpressionNonReferenceAnyStruct(t *testing.T) { 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]) } From 78504f8f39a2576e74676371dc94d5780e6b4665 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 20 Jun 2023 14:17:44 -0400 Subject: [PATCH 03/16] fix contract interface conversion --- runtime/sema/type.go | 13 +++++++++--- runtime/tests/checker/attachments_test.go | 24 ++++------------------- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 0e85ea2a38..8ad291d70a 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -4911,9 +4911,16 @@ func (*InterfaceType) TypeAnnotationState() TypeAnnotationState { } func (t *InterfaceType) RewriteWithIntersectionTypes() (Type, bool) { - return &IntersectionType{ - Types: []*InterfaceType{t}, - }, true + switch t.CompositeKind { + case common.CompositeKindResource, common.CompositeKindStructure: + return &IntersectionType{ + Types: []*InterfaceType{t}, + }, true + + default: + return t, false + } + } func (*InterfaceType) Unify(_ Type, _ *TypeParameterTypeOrderedMap, _ func(err error), _ ast.Range) bool { diff --git a/runtime/tests/checker/attachments_test.go b/runtime/tests/checker/attachments_test.go index f3aa00024a..4b24452510 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} } }`, ) @@ -3962,7 +3962,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 +3987,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() @@ -4096,7 +4080,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] } `, From d82bf22989f66ceada8cf9528250af4045eccabf Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 21 Jun 2023 12:23:25 -0400 Subject: [PATCH 04/16] update more types --- runtime/tests/checker/attachments_test.go | 146 ++-------------------- runtime/tests/checker/interface_test.go | 57 +++------ 2 files changed, 31 insertions(+), 172 deletions(-) diff --git a/runtime/tests/checker/attachments_test.go b/runtime/tests/checker/attachments_test.go index 4b24452510..c50a66eb5a 100644 --- a/runtime/tests/checker/attachments_test.go +++ b/runtime/tests/checker/attachments_test.go @@ -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 {} @@ -4061,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] } `, diff --git a/runtime/tests/checker/interface_test.go b/runtime/tests/checker/interface_test.go index 8725821f04..162961825d 100644 --- a/runtime/tests/checker/interface_test.go +++ b/runtime/tests/checker/interface_test.go @@ -4173,28 +4173,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() @@ -4355,13 +4334,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} } `) @@ -4383,15 +4362,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} } `) @@ -4411,16 +4390,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} } `) From 7ddc35b441fcb8e73a7ab04fded2be04417436c1 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 21 Jun 2023 13:17:25 -0400 Subject: [PATCH 05/16] fix remaining checker tests --- runtime/sema/errors.go | 21 --------------------- runtime/tests/checker/entitlements_test.go | 8 ++++---- runtime/tests/checker/interface_test.go | 17 ++--------------- 3 files changed, 6 insertions(+), 40 deletions(-) diff --git a/runtime/sema/errors.go b/runtime/sema/errors.go index 89e484032f..6a881b0a6a 100644 --- a/runtime/sema/errors.go +++ b/runtime/sema/errors.go @@ -3407,27 +3407,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 { diff --git a/runtime/tests/checker/entitlements_test.go b/runtime/tests/checker/entitlements_test.go index db557e0eae..e6903b32d0 100644 --- a/runtime/tests/checker/entitlements_test.go +++ b/runtime/tests/checker/entitlements_test.go @@ -2779,14 +2779,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) { @@ -2990,14 +2990,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 162961825d..435b807a17 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) From e351e3c64057ffd18bd501532cc9b54c8921a735 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 21 Jun 2023 13:38:34 -0400 Subject: [PATCH 06/16] remove outer type from intersectionstatictype --- encoding/json/decode.go | 6 -- encoding/json/encode.go | 2 - encoding/json/encoding_test.go | 4 -- runtime/convertTypes.go | 1 - runtime/convertValues_test.go | 5 -- runtime/interpreter/decode.go | 33 ---------- runtime/interpreter/encode.go | 20 ------ runtime/interpreter/encoding_test.go | 35 +++++----- runtime/interpreter/interpreter.go | 1 - runtime/interpreter/statictype.go | 24 +------ runtime/interpreter/statictype_test.go | 14 ---- runtime/sema/runtime_type_constructors.go | 8 --- runtime/tests/checker/runtimetype_test.go | 43 ++++-------- runtime/tests/interpreter/attachments_test.go | 4 +- runtime/tests/interpreter/runtimetype_test.go | 66 ++++--------------- 15 files changed, 46 insertions(+), 220 deletions(-) diff --git a/encoding/json/decode.go b/encoding/json/decode.go index 40eae04970..84a84bc992 100644 --- a/encoding/json/decode.go +++ b/encoding/json/decode.go @@ -1114,12 +1114,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)) @@ -1127,7 +1124,6 @@ func (d *Decoder) decodeIntersectionType( return cadence.NewMeteredIntersectionType( d.gauge, - typ, types, ) } @@ -1166,9 +1162,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 61f078f11e..5eedff1169 100644 --- a/encoding/json/encode.go +++ b/encoding/json/encode.go @@ -183,7 +183,6 @@ type jsonReferenceType struct { type jsonIntersectionType struct { Kind string `json:"kind"` - Type jsonValue `json:"type"` Types []jsonValue `json:"types"` } @@ -930,7 +929,6 @@ func prepareType(typ cadence.Type, results typePreparationResults) jsonValue { } return jsonIntersectionType{ Kind: "Intersection", - Type: prepareType(typ.Type, results), Types: types, } case *cadence.CapabilityType: diff --git a/encoding/json/encoding_test.go b/encoding/json/encoding_test.go index f22f61c316..8c781c7732 100644 --- a/encoding/json/encoding_test.go +++ b/encoding/json/encoding_test.go @@ -2704,7 +2704,6 @@ func TestEncodeType(t *testing.T) { Types: []cadence.Type{ cadence.StringType{}, }, - Type: cadence.IntType{}, }, }, // language=json @@ -2714,9 +2713,6 @@ func TestEncodeType(t *testing.T) { "value": { "staticType": { "kind": "Intersection", - "type": { - "kind": "Int" - }, "types": [ { "kind": "String" diff --git a/runtime/convertTypes.go b/runtime/convertTypes.go index 67f8498131..2f79e018a2 100644 --- a/runtime/convertTypes.go +++ b/runtime/convertTypes.go @@ -692,7 +692,6 @@ func ImportType(memoryGauge common.MemoryGauge, t cadence.Type) interpreter.Stat } return interpreter.NewIntersectionStaticType( memoryGauge, - nil, types, ) case cadence.BlockType: diff --git a/runtime/convertValues_test.go b/runtime/convertValues_test.go index 3bd563463b..39732e4d0f 100644 --- a/runtime/convertValues_test.go +++ b/runtime/convertValues_test.go @@ -1365,10 +1365,6 @@ func TestImportRuntimeType(t *testing.T) { }}, }, expected: &interpreter.IntersectionStaticType{ - Type: interpreter.CompositeStaticType{ - Location: TestLocation, - QualifiedIdentifier: "S", - }, Types: []interpreter.InterfaceStaticType{ { Location: TestLocation, @@ -2090,7 +2086,6 @@ func TestExportTypeValue(t *testing.T) { ty := interpreter.TypeValue{ Type: &interpreter.IntersectionStaticType{ - Type: interpreter.NewCompositeStaticTypeComputeTypeID(inter, TestLocation, "S"), Types: []interpreter.InterfaceStaticType{ { Location: TestLocation, diff --git a/runtime/interpreter/decode.go b/runtime/interpreter/decode.go index 54afe092d5..daf90bd25c 100644 --- a/runtime/interpreter/decode.go +++ b/runtime/interpreter/decode.go @@ -1808,38 +1808,6 @@ func (d TypeDecoder) decodeDictionaryStaticType() (StaticType, error) { } func (d TypeDecoder) decodeIntersectionStaticType() (StaticType, error) { - const expectedLength = encodedIntersectionStaticTypeLength - - arraySize, err := d.decoder.DecodeArrayHead() - - if err != nil { - if e, ok := err.(*cbor.WrongTypeError); ok { - return nil, errors.NewUnexpectedError( - "invalid intersection static type encoding: expected [%d]any, got %s", - expectedLength, - e.ActualType.String(), - ) - } - return nil, err - } - - if arraySize != expectedLength { - return nil, errors.NewUnexpectedError( - "invalid intersection static type encoding: expected [%d]any, got [%d]any", - expectedLength, - arraySize, - ) - } - - // Decode intersection type at array index encodedIntersectionStaticTypeTypeFieldKey - intersectionType, 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 intersectionSize, err := d.decoder.DecodeArrayHead() if err != nil { @@ -1893,7 +1861,6 @@ func (d TypeDecoder) decodeIntersectionStaticType() (StaticType, error) { return NewIntersectionStaticType( d.memoryGauge, - intersectionType, intersections, ), nil } diff --git a/runtime/interpreter/encode.go b/runtime/interpreter/encode.go index 10a7efebf0..24c888341c 100644 --- a/runtime/interpreter/encode.go +++ b/runtime/interpreter/encode.go @@ -1542,24 +1542,11 @@ func (t DictionaryStaticType) Encode(e *cbor.StreamEncoder) error { return t.ValueType.Encode(e) } -// NOTE: NEVER change, only add/increment; ensure uint64 -const ( - // encodedIntersectionStaticTypeTypeFieldKey uint64 = 0 - // encodedIntersectionStaticTypeTypesFieldKey uint64 = 1 - - // !!! *WARNING* !!! - // - // encodedIntersectionStaticTypeLength MUST be updated when new element is added. - // It is used to verify encoded intersection static type length during decoding. - encodedIntersectionStaticTypeLength = 2 -) - // Encode encodes IntersectionStaticType as // // cbor.Tag{ // Number: CBORTagIntersectionStaticType, // Content: cborArray{ -// encodedIntersectionStaticTypeTypeFieldKey: StaticType(v.Type), // encodedIntersectionStaticTypeTypesFieldKey: []any(v.Types), // }, // } @@ -1568,17 +1555,10 @@ func (t *IntersectionStaticType) Encode(e *cbor.StreamEncoder) error { err := e.EncodeRawBytes([]byte{ // tag number 0xd8, CBORTagIntersectionStaticType, - // array, 2 items follow - 0x82, }) if err != nil { return err } - // Encode type at array index encodedIntersectionStaticTypeTypeFieldKey - err = t.Type.Encode(e) - if err != nil { - return err - } // Encode types (as array) at array index encodedIntersectionStaticTypeTypesFieldKey err = e.EncodeArrayHead(uint64(len(t.Types))) if err != nil { diff --git a/runtime/interpreter/encoding_test.go b/runtime/interpreter/encoding_test.go index 590b6a83c6..f23958c050 100644 --- a/runtime/interpreter/encoding_test.go +++ b/runtime/interpreter/encoding_test.go @@ -4018,11 +4018,6 @@ func TestEncodeDecodePathLinkValue(t *testing.T) { value := PathLinkValue{ TargetPath: publicPathValue, Type: &IntersectionStaticType{ - Type: NewCompositeStaticTypeComputeTypeID( - nil, - utils.TestLocation, - "S", - ), Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -4726,11 +4721,6 @@ func TestEncodeDecodeStorageCapabilityControllerValue(t *testing.T) { TargetPath: publicPathValue, BorrowType: ReferenceStaticType{ ReferencedType: &IntersectionStaticType{ - Type: NewCompositeStaticTypeComputeTypeID( - nil, - utils.TestLocation, - "S", - ), Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -4927,14 +4917,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, }, @@ -4953,14 +4948,20 @@ func TestEncodeDecodeAccountCapabilityControllerValue(t *testing.T) { 0xf6, // tag 0xd8, CBORTagIntersectionStaticType, + // 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 92e5e759bf..e6f67b779d 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -3571,7 +3571,6 @@ func intersectionTypeFunction(invocation Invocation) Value { invocation.Interpreter, NewIntersectionStaticType( invocation.Interpreter, - nil, staticIntersections, ), ), diff --git a/runtime/interpreter/statictype.go b/runtime/interpreter/statictype.go index 08e2640a4c..6544b5475e 100644 --- a/runtime/interpreter/statictype.go +++ b/runtime/interpreter/statictype.go @@ -395,7 +395,6 @@ var NilStaticType = OptionalStaticType{ // IntersectionStaticType type IntersectionStaticType struct { - Type StaticType Types []InterfaceStaticType } @@ -403,13 +402,11 @@ 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 +433,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 +450,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 +470,7 @@ outer: return false } - return t.Type.Equal(otherIntersectionType.Type) + return true } // Authorization @@ -765,7 +760,6 @@ func ConvertSemaToStaticType(memoryGauge common.MemoryGauge, t sema.Type) Static return NewIntersectionStaticType( memoryGauge, - nil, intersectedTypess, ) @@ -1004,18 +998,6 @@ func ConvertStaticToSemaType( } } - _, err := ConvertStaticToSemaType( - memoryGauge, - t.Type, - getInterface, - getComposite, - getEntitlement, - getEntitlementMapType, - ) - if err != nil { - return nil, err - } - return sema.NewIntersectionType( memoryGauge, intersectedTypes, diff --git a/runtime/interpreter/statictype_test.go b/runtime/interpreter/statictype_test.go index ec39e47df0..1d32a50e5f 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,11 +790,9 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.True(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{}, }).Equal( &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{}, }, ), @@ -809,7 +805,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.False(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeString, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -822,7 +817,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { }, }).Equal( &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -844,7 +838,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.False(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -857,7 +850,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { }, }).Equal( &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -875,7 +867,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.False(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -884,7 +875,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { }, }).Equal( &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -906,7 +896,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.False(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -919,7 +908,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { }, }).Equal( &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -941,7 +929,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { require.False(t, (&IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ { Location: utils.TestLocation, @@ -1378,7 +1365,6 @@ func TestStaticTypeConversion(t *testing.T) { }, }, staticType: &IntersectionStaticType{ - Type: PrimitiveStaticTypeInt, Types: []InterfaceStaticType{ testInterfaceStaticType, }, 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/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/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/runtimetype_test.go b/runtime/tests/interpreter/runtimetype_test.go index 068c693340..16f8774d39 100644 --- a/runtime/tests/interpreter/runtimetype_test.go +++ b/runtime/tests/interpreter/runtimetype_test.go @@ -575,31 +575,21 @@ 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 f = IntersectionType(types: ["X"]) - let f = IntersectionType(identifier: "S.test.B", types: ["X"]) - let g = IntersectionType(identifier: "S.test.N", types: ["S.test.S2"]) + let h = Type<@{R}>() + let i = Type<{S}>() - let h = Type<@A{R}>() - let i = Type() - - 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", @@ -614,11 +604,6 @@ func TestInterpretIntersectionType(t *testing.T) { 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 +616,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(), From 7184964f1f37bfffd4dfd24c4a8ed628abca32c4 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 21 Jun 2023 13:55:38 -0400 Subject: [PATCH 07/16] fix interpreter tests --- .../tests/interpreter/dynamic_casting_test.go | 425 ++++-------------- .../tests/interpreter/entitlements_test.go | 2 +- runtime/tests/interpreter/interpreter_test.go | 4 +- .../tests/interpreter/memory_metering_test.go | 3 +- runtime/tests/interpreter/runtimetype_test.go | 7 + runtime/tests/interpreter/transfer_test.go | 4 +- 6 files changed, 95 insertions(+), 350 deletions(-) diff --git a/runtime/tests/interpreter/dynamic_casting_test.go b/runtime/tests/interpreter/dynamic_casting_test.go index 23086fb001..f974568805 100644 --- a/runtime/tests/interpreter/dynamic_casting_test.go +++ b/runtime/tests/interpreter/dynamic_casting_test.go @@ -1486,8 +1486,8 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "R{I1, I2}", - "R{I2}", + "{I1, I2}", + "{I2}", operation, ) }) @@ -1502,53 +1502,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 {} - `, - "{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 {} - `, - "{RI}", - "T{}", + "{I1}", + "{I1, I2}", operation, ) }) @@ -1562,7 +1517,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: RI {} `, "AnyResource", - "R{RI}", + "{RI}", operation, ) }) @@ -1578,7 +1533,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource T: TI {} `, "AnyResource", - "T{TI}", + "{TI}", operation, ) }) @@ -1593,13 +1548,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, ` @@ -1613,7 +1568,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { ) }) - t.Run("intersection AnyResource -> non-conforming resource", func(t *testing.T) { + t.Run("intersection -> non-conforming resource", func(t *testing.T) { testResourceCastInvalid(t, ` @@ -1677,21 +1632,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { ) }) - t.Run("intersection type -> intersection AnyResource with conformance in type", func(t *testing.T) { - - testResourceCastValid(t, - ` - resource interface I {} - - resource R: I {} - `, - "R{I}", - "{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, ` @@ -1701,13 +1642,13 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { resource R: I1, I2 {} `, - "R{I1}", + "{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, ` @@ -1723,7 +1664,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { ) }) - t.Run("intersection AnyResource -> intersection AnyResource: more types", func(t *testing.T) { + t.Run("intersection -> intersection: more types", func(t *testing.T) { testResourceCastValid(t, ` @@ -1739,7 +1680,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { ) }) - 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, ` @@ -1755,7 +1696,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { ) }) - 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, ` @@ -1772,7 +1713,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { ) }) - 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, ` @@ -1788,7 +1729,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { ) }) - t.Run("AnyResource -> intersection AnyResource", func(t *testing.T) { + t.Run("AnyResource -> intersection", func(t *testing.T) { testResourceCastValid(t, ` @@ -1804,23 +1745,7 @@ func TestInterpretDynamicCastingResourceType(t *testing.T) { // 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, ` @@ -1875,8 +1800,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "S{I1, I2}", - "S{I2}", + "{I1, I2}", + "{I2}", operation, ) }) @@ -1891,8 +1816,8 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "S{I1}", - "S{I1, I2}", + "{I1}", + "{I1, I2}", operation, ) }) @@ -1906,38 +1831,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 {} - `, - "{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 {} - `, - "{SI}", - "T{}", + "{I}", operation, ) }) @@ -1951,7 +1845,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: SI {} `, "AnyStruct", - "S{SI}", + "{SI}", operation, ) }) @@ -1967,7 +1861,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct T: TI {} `, "AnyStruct", - "T{TI}", + "{TI}", operation, ) }) @@ -1982,7 +1876,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I {} `, - "S{I}", + "{I}", "S", operation, ) @@ -2050,9 +1944,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, ` @@ -2066,21 +1960,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { ) }) - t.Run("intersection type -> intersection AnyStruct with conformance in type", func(t *testing.T) { - - testStructCastValid(t, - ` - struct interface I {} - - struct S: I {} - `, - "S{I}", - "{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, ` @@ -2090,13 +1970,13 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { struct S: I1, I2 {} `, - "S{I1}", + "{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, ` @@ -2112,7 +1992,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct: more types", func(t *testing.T) { + t.Run("intersection -> intersection: more types", func(t *testing.T) { testStructCastValid(t, ` @@ -2128,7 +2008,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { ) }) - 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, ` @@ -2144,7 +2024,7 @@ func TestInterpretDynamicCastingStructType(t *testing.T) { ) }) - 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, ` @@ -2203,13 +2083,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, ` @@ -2425,8 +2305,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &R{I1, I2}", - "&R{I2}", + "auth(E) &{I1, I2}", + "&{I2}", operation, true, ) @@ -2444,8 +2324,8 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &R{I1}", - "&R{I1, I2}", + "auth(E) &{I1}", + "&{I1, I2}", operation, true, ) @@ -2462,7 +2342,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &R", - "&R{I}", + "&{I}", operation, true, ) @@ -2479,27 +2359,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &{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) &{RI}", - "&T{}", + "&{RI}", operation, true, ) @@ -2516,7 +2376,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyResource", - "&R{RI}", + "&{RI}", operation, true, ) @@ -2535,7 +2395,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyResource", - "&T{TI}", + "&{TI}", operation, true, ) @@ -2553,7 +2413,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &R{I}", + "auth(E) &{I}", "&R", operation, true, @@ -2660,7 +2520,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &R{I}", + "auth(E) &{I}", "&{I}", operation, true, @@ -2679,7 +2539,7 @@ func TestInterpretDynamicCastingAuthorizedResourceReferenceType(t *testing.T) { entitlement E `, - "auth(E) &R{I1}", + "auth(E) &{I1}", "&{I2}", operation, true, @@ -2809,14 +2669,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, ` @@ -2876,8 +2736,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, ) @@ -2894,8 +2754,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, ) @@ -2911,13 +2771,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,26 +2787,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &{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) &{SI}", - "&T{}", + "&{SI}", operation, false, ) @@ -2962,7 +2803,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyStruct", - "&S{SI}", + "&{SI}", operation, false, ) @@ -2980,31 +2821,13 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { entitlement E `, "auth(E) &AnyStruct", - "&T{TI}", + "&{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", - operation, - false, - ) - }) - - t.Run("intersection AnyStruct -> conforming struct", func(t *testing.T) { + t.Run("intersection -> conforming struct", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3072,9 +2895,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 {} @@ -3088,23 +2911,6 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { 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}", - "&{I}", - operation, - false, - ) - }) - t.Run("intersection type -> intersection AnyStruct with conformance not in type", func(t *testing.T) { testReferenceCastValid(t, @@ -3116,14 +2922,14 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} entitlement E `, - "auth(E) &S{I1}", + "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, ` @@ -3141,7 +2947,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { ) }) - t.Run("intersection AnyStruct -> intersection AnyStruct: more types", func(t *testing.T) { + t.Run("intersection -> intersection: more types", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3159,7 +2965,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { ) }) - 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, ` @@ -3177,7 +2983,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { ) }) - 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, ` @@ -3195,7 +3001,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { ) }) - 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, ` @@ -3213,7 +3019,7 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { ) }) - t.Run("AnyStruct -> intersection AnyStruct", func(t *testing.T) { + t.Run("AnyStruct -> intersection", func(t *testing.T) { testReferenceCastValid(t, ` @@ -3239,24 +3045,6 @@ func TestInterpretDynamicCastingAuthorizedStructReferenceType(t *testing.T) { struct interface I2 {} - 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 `, @@ -3307,8 +3095,8 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I1, I2 {} `, - "&R{I1, I2}", - "&R{I2}", + "&{I1, I2}", + "&{I2}", operation, true, ) @@ -3323,7 +3111,7 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I {} `, "&R", - "&R{I}", + "&{I}", operation, true, ) @@ -3331,7 +3119,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, ` @@ -3346,7 +3134,7 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) ) }) - 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, ` @@ -3354,14 +3142,14 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource R: I {} `, - "&R{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, ` @@ -3388,23 +3176,6 @@ func TestInterpretDynamicCastingUnauthorizedResourceReferenceType(t *testing.T) resource interface I2 {} - 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 {} `, "&{I1}", @@ -3453,8 +3224,8 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: I1, I2 {} `, - "&S{I1, I2}", - "&S{I2}", + "&{I1, I2}", + "&{I2}", operation, false, ) @@ -3469,7 +3240,7 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct S: I {} `, "&S", - "&S{I}", + "&{I}", operation, false, ) @@ -3477,7 +3248,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, ` @@ -3492,22 +3263,7 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { ) }) - t.Run("intersection type -> intersection AnyStruct with conformance in type", func(t *testing.T) { - - testReferenceCastValid(t, - ` - struct interface I {} - - struct S: I {} - `, - "&S{I}", - "&{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, ` @@ -3534,23 +3290,6 @@ func TestInterpretDynamicCastingUnauthorizedStructReferenceType(t *testing.T) { struct interface I2 {} - 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 {} `, "&{I1}", @@ -3928,7 +3667,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 {} @@ -3951,7 +3690,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 51465ccf4c..544697296e 100644 --- a/runtime/tests/interpreter/entitlements_test.go +++ b/runtime/tests/interpreter/entitlements_test.go @@ -533,7 +533,7 @@ func TestInterpretEntitledReferenceCasting(t *testing.T) { fun test(): Bool { let x <- create R() let r = &x as auth(E) &{RI} - let r2 = r as! &R{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 f7b71a3b32..4a5a261943 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -5040,9 +5040,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/memory_metering_test.go b/runtime/tests/interpreter/memory_metering_test.go index 54f262e26e..11cee2c9c9 100644 --- a/runtime/tests/interpreter/memory_metering_test.go +++ b/runtime/tests/interpreter/memory_metering_test.go @@ -8044,7 +8044,6 @@ func TestInterpretInterfaceStaticType(t *testing.T) { let type = Type<{I}>() IntersectionType( - identifier: type.identifier, types: [type.identifier] ) } @@ -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)) diff --git a/runtime/tests/interpreter/runtimetype_test.go b/runtime/tests/interpreter/runtimetype_test.go index 16f8774d39..18a9c4862e 100644 --- a/runtime/tests/interpreter/runtimetype_test.go +++ b/runtime/tests/interpreter/runtimetype_test.go @@ -578,6 +578,8 @@ func TestInterpretIntersectionType(t *testing.T) { let a = IntersectionType(types: ["S.test.R"])! let b = IntersectionType(types: ["S.test.S"])! + let c = IntersectionType(types: []) + let f = IntersectionType(types: ["X"]) let h = Type<@{R}>() @@ -601,6 +603,11 @@ 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{ 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 } `, From 8e5e1f6d39907db2feaa9288ca9c1abf17e78798 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Thu, 22 Jun 2023 11:20:29 -0400 Subject: [PATCH 08/16] fix runtime test --- runtime/capabilitycontrollers_test.go | 46 +++++----- runtime/contract_update_validation_test.go | 10 +-- runtime/ft_test.go | 10 +-- runtime/missingmember_test.go | 90 +++++++++---------- runtime/storage_test.go | 10 +-- runtime/tests/interpreter/interpreter_test.go | 4 +- 6 files changed, 85 insertions(+), 85 deletions(-) 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 2a5d25d00f..a2c225b5c4 100644 --- a/runtime/contract_update_validation_test.go +++ b/runtime/contract_update_validation_test.go @@ -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() { @@ -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 @@ -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}"+ + assert.Contains(t, err.Error(), "access(all) var b: TestStruct"+ "\n | ^^^^^^^^^^^^^^^^^^^^^^^^^ "+ - "incompatible type annotations. expected `{TestInterface}`, found `TestStruct{TestInterface}`") + "incompatible type annotations. expected `{TestInterface}`, found `TestStruct`") }) t.Run("enum valid", func(t *testing.T) { 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/missingmember_test.go b/runtime/missingmember_test.go index 16fbab3842..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, @@ -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") @@ -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") } diff --git a/runtime/storage_test.go b/runtime/storage_test.go index 22f8af8052..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 } diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 4a5a261943..1d3e445db2 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -4956,8 +4956,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{ From f0f26892a7c8d758a2eaa71e11334d76eda05f22 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Thu, 22 Jun 2023 11:35:48 -0400 Subject: [PATCH 09/16] fix ccf tests --- encoding/ccf/ccf_test.go | 134 ++++++++------------------------- encoding/ccf/decode_type.go | 22 ++---- encoding/ccf/encode_type.go | 14 +--- encoding/ccf/traverse_value.go | 2 +- 4 files changed, 43 insertions(+), 129 deletions(-) diff --git a/encoding/ccf/ccf_test.go b/encoding/ccf/ccf_test.go index 94ee79e9d0..4f86d0d1d2 100644 --- a/encoding/ccf/ccf_test.go +++ b/encoding/ccf/ccf_test.go @@ -6674,11 +6674,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 @@ -6749,7 +6744,6 @@ func TestEncodeValueOfIntersectionType(t *testing.T) { ) countSumIntersectionType := cadence.NewIntersectionType( - statsType, []cadence.Type{ hasCountInterfaceType, hasSumInterfaceType, @@ -6776,7 +6770,6 @@ func TestEncodeValueOfIntersectionType(t *testing.T) { ) expectedCountSumIntersectionType := cadence.NewIntersectionType( - expectedStatsType, []cadence.Type{ hasSumInterfaceType, hasCountInterfaceType, @@ -6895,13 +6888,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 @@ -9172,13 +9158,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"} @@ -9197,62 +9177,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) { @@ -9265,7 +9227,6 @@ func TestEncodeType(t *testing.T) { Types: []cadence.Type{ cadence.StringType{}, }, - Type: cadence.IntType{}, }, }, []byte{ @@ -9286,12 +9247,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 @@ -9305,7 +9260,6 @@ func TestEncodeType(t *testing.T) { Types: []cadence.Type{ cadence.StringType{}, }, - Type: cadence.IntType{}, }, }, ) @@ -9323,7 +9277,6 @@ func TestEncodeType(t *testing.T) { cadence.NewAnyStructType(), cadence.StringType{}, }, - Type: cadence.IntType{}, }, }, []byte{ @@ -9344,12 +9297,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 @@ -9368,7 +9315,6 @@ func TestEncodeType(t *testing.T) { cadence.StringType{}, cadence.NewAnyStructType(), }, - Type: cadence.IntType{}, }, }, ) @@ -9382,7 +9328,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"), @@ -9423,12 +9368,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, @@ -9497,7 +9436,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"), @@ -14172,7 +14110,7 @@ func TestEncodeValueOfIntersectedInterface(t *testing.T) { []cadence.Field{ { Type: cadence.NewIntersectionType( - cadence.TheAnyStructType, []cadence.Type{interfaceType}), + []cadence.Type{interfaceType}), Identifier: "field", }, }, @@ -14303,12 +14241,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 diff --git a/encoding/ccf/decode_type.go b/encoding/ccf/decode_type.go index 484e58f6ff..f9477b7979 100644 --- a/encoding/ccf/decode_type.go +++ b/encoding/ccf/decode_type.go @@ -544,23 +544,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 @@ -600,9 +591,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 9d1328ad74..1f0d473977 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 b59f5bc328..ee6b9d4cbc 100644 --- a/encoding/ccf/traverse_value.go +++ b/encoding/ccf/traverse_value.go @@ -141,7 +141,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 From bdaca8d5d4f2b1311e2096f5368ea1dcc2bdfda4 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Thu, 22 Jun 2023 11:43:35 -0400 Subject: [PATCH 10/16] fix remaining tests --- runtime/interpreter/encoding_test.go | 34 ++------------------- runtime/interpreter/statictype_test.go | 33 -------------------- runtime/sema/gen/testdata/fields.cdc | 3 -- runtime/sema/type_test.go | 42 ++++++++++++++++++-------- 4 files changed, 32 insertions(+), 80 deletions(-) diff --git a/runtime/interpreter/encoding_test.go b/runtime/interpreter/encoding_test.go index f23958c050..220d7ca932 100644 --- a/runtime/interpreter/encoding_test.go +++ b/runtime/interpreter/encoding_test.go @@ -4034,22 +4034,6 @@ func TestEncodeDecodePathLinkValue(t *testing.T) { encoded := assemble( // tag 0xd8, CBORTagIntersectionStaticType, - // array, 2 items follow - 0x82, - // tag - 0xd8, CBORTagCompositeStaticType, - // array, 2 items follow - 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, // array, length 2 0x82, // tag @@ -4749,22 +4733,6 @@ func TestEncodeDecodeStorageCapabilityControllerValue(t *testing.T) { 0xf6, // tag 0xd8, CBORTagIntersectionStaticType, - // array, 2 items follow - 0x82, - // tag - 0xd8, CBORTagCompositeStaticType, - // array, 2 items follow - 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, // array, length 2 0x82, // tag @@ -4948,6 +4916,8 @@ func TestEncodeDecodeAccountCapabilityControllerValue(t *testing.T) { 0xf6, // tag 0xd8, CBORTagIntersectionStaticType, + // array, 1 item follows + 0x81, // tag 0xd8, CBORTagInterfaceStaticType, // array, 2 items follow diff --git a/runtime/interpreter/statictype_test.go b/runtime/interpreter/statictype_test.go index 1d32a50e5f..8501d6ea31 100644 --- a/runtime/interpreter/statictype_test.go +++ b/runtime/interpreter/statictype_test.go @@ -799,39 +799,6 @@ func TestIntersectionStaticType_Equal(t *testing.T) { ) }) - t.Run("different intersection type", func(t *testing.T) { - - t.Parallel() - - require.False(t, - (&IntersectionStaticType{ - Types: []InterfaceStaticType{ - { - Location: utils.TestLocation, - QualifiedIdentifier: "X", - }, - { - Location: utils.TestLocation, - QualifiedIdentifier: "Y", - }, - }, - }).Equal( - &IntersectionStaticType{ - Types: []InterfaceStaticType{ - { - Location: utils.TestLocation, - QualifiedIdentifier: "Y", - }, - { - Location: utils.TestLocation, - QualifiedIdentifier: "X", - }, - }, - }, - ), - ) - }) - t.Run("fewer intersections", func(t *testing.T) { t.Parallel() diff --git a/runtime/sema/gen/testdata/fields.cdc b/runtime/sema/gen/testdata/fields.cdc index af62563a57..13a3e97a9e 100644 --- a/runtime/sema/gen/testdata/fields.cdc +++ b/runtime/sema/gen/testdata/fields.cdc @@ -32,9 +32,6 @@ 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/type_test.go b/runtime/sema/type_test.go index a7d415a717..72b54dd749 100644 --- a/runtime/sema/type_test.go +++ b/runtime/sema/type_test.go @@ -1339,12 +1339,19 @@ func TestCommonSuperType(t *testing.T) { Members: &StringMemberOrderedMap{}, } + interfaceType2 := &InterfaceType{ + Location: testLocation, + Identifier: "I2", + CompositeKind: common.CompositeKindStructure, + Members: &StringMemberOrderedMap{}, + } + intersectionType1 := &IntersectionType{ Types: []*InterfaceType{interfaceType1}, } intersectionType2 := &IntersectionType{ - Types: []*InterfaceType{interfaceType1}, + Types: []*InterfaceType{interfaceType2}, } tests := []testCase{ @@ -1362,7 +1369,7 @@ func TestCommonSuperType(t *testing.T) { intersectionType1, intersectionType2, }, - expectedSuperType: InvalidType, + expectedSuperType: AnyStructType, }, } @@ -1381,30 +1388,41 @@ func TestCommonSuperType(t *testing.T) { Members: &StringMemberOrderedMap{}, } - intersectionType1 := &IntersectionType{ - Types: []*InterfaceType{interfaceType1}, + interfaceType2 := &InterfaceType{ + Location: testLocation, + Identifier: "I1", + CompositeKind: common.CompositeKindStructure, + Members: &StringMemberOrderedMap{}, } - intersectionType2 := &IntersectionType{ - 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, }, } From 8291c019b27b33b3a932835d452494b2715ff74d Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Thu, 22 Jun 2023 11:53:41 -0400 Subject: [PATCH 11/16] fix remaining tests --- go.mod | 3 +- go.sum | 2 ++ runtime/contract_update_validation_test.go | 6 ++-- runtime/parser/declaration_test.go | 6 ++-- runtime/parser/type.go | 11 ------- runtime/sema/gen/testdata/fields.cdc | 3 -- runtime/sema/gen/testdata/fields.golden.go | 37 ---------------------- runtime/stdlib/type-comparator.go | 20 ------------ 8 files changed, 10 insertions(+), 78 deletions(-) diff --git a/go.mod b/go.mod index 6389697ac9..52669fba70 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( require ( github.com/SaveTheRbtz/mph v0.1.2 github.com/bytecodealliance/wasmtime-go/v7 v7.0.0 + github.com/k0kubun/pp v3.0.1+incompatible github.com/k0kubun/pp/v3 v3.2.0 github.com/logrusorgru/aurora/v4 v4.0.0 ) @@ -41,7 +42,7 @@ require github.com/zeebo/xxh3 v1.0.2 // indirect require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/fxamacker/circlehash v0.3.0 // indirect - github.com/k0kubun/pp v3.0.1+incompatible // indirect + github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect github.com/klauspost/cpuid/v2 v2.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect diff --git a/go.sum b/go.sum index 989f27cdb8..5472e78ef4 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ github.com/go-test/deep v1.0.5 h1:AKODKU3pDH1RzZzm6YZu77YWtEAq6uh1rLIAQlay2qc= github.com/go-test/deep v1.0.5/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= diff --git a/runtime/contract_update_validation_test.go b/runtime/contract_update_validation_test.go index a2c225b5c4..dbf43a79b6 100644 --- a/runtime/contract_update_validation_test.go +++ b/runtime/contract_update_validation_test.go @@ -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 @@ -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 @@ -1514,7 +1514,7 @@ func TestRuntimeContractUpdateValidation(t *testing.T) { "incompatible type annotations. expected `TestStruct`") assert.Contains(t, err.Error(), "access(all) var b: TestStruct"+ - "\n | ^^^^^^^^^^^^^^^^^^^^^^^^^ "+ + "\n | ^^^^^^^^^^ "+ "incompatible type annotations. expected `{TestInterface}`, found `TestStruct`") }) diff --git a/runtime/parser/declaration_test.go b/runtime/parser/declaration_test.go index 470d3863b3..d9e17cb316 100644 --- a/runtime/parser/declaration_test.go +++ b/runtime/parser/declaration_test.go @@ -3106,7 +3106,7 @@ func TestParseCompositeDeclaration(t *testing.T) { FunctionDeclaration: &ast.FunctionDeclaration{ ParameterList: &ast.ParameterList{ Parameters: []*ast.Parameter{ - &ast.Parameter{ + { TypeAnnotation: &ast.TypeAnnotation{ Type: &ast.NominalType{ Identifier: ast.Identifier{ @@ -4093,7 +4093,7 @@ func TestParseAttachmentDeclaration(t *testing.T) { }, }, RequiredEntitlements: []*ast.NominalType{ - &ast.NominalType{ + { Identifier: ast.Identifier{ Identifier: "X", Pos: ast.Position{ @@ -4103,7 +4103,7 @@ func TestParseAttachmentDeclaration(t *testing.T) { }, }, }, - &ast.NominalType{ + { Identifier: ast.Identifier{ Identifier: "Y", Pos: ast.Position{ diff --git a/runtime/parser/type.go b/runtime/parser/type.go index aa857a0f51..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 diff --git a/runtime/sema/gen/testdata/fields.cdc b/runtime/sema/gen/testdata/fields.cdc index 13a3e97a9e..667f50b712 100644 --- a/runtime/sema/gen/testdata/fields.cdc +++ b/runtime/sema/gen/testdata/fields.cdc @@ -31,7 +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 (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/stdlib/type-comparator.go b/runtime/stdlib/type-comparator.go index 8d8c25a045..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{} @@ -222,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, From 3fcf2e9999db4641a7d3f4033a0a415e8d578a4d Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Fri, 30 Jun 2023 10:00:03 -0400 Subject: [PATCH 12/16] ccf encoding/decoding is backwards compatible --- encoding/ccf/ccf_test.go | 123 +++++++++++++++++++++++++++++++++ encoding/ccf/decode_type.go | 24 +++++-- encoding/ccf/encode_type.go | 23 +++++- encoding/ccf/traverse_value.go | 3 + types.go | 9 +-- 5 files changed, 172 insertions(+), 10 deletions(-) diff --git a/encoding/ccf/ccf_test.go b/encoding/ccf/ccf_test.go index ce2faae934..857b60b4f8 100644 --- a/encoding/ccf/ccf_test.go +++ b/encoding/ccf/ccf_test.go @@ -6805,6 +6805,11 @@ 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 @@ -7019,6 +7024,11 @@ 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 @@ -9468,6 +9478,11 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, + // array, 2 items follow + 0x82, + // type + // null + 0xf6, // array, 0 element follows 0x80, } @@ -9499,6 +9514,11 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, + // array, 2 items follow + 0x82, + // type + // null + 0xf6, // array, 0 element follows 0x80, } @@ -9538,6 +9558,68 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, + // array, 2 items follow + 0x82, + // type + // null + 0xf6, + // array, 1 element follows + 0x81, + // tag + 0xd8, ccf.CBORTagSimpleTypeValue, + // String type ID (1) + 0x01, + }, + // Expected decoded IntersectionType doesn't have type ID. + cadence.TypeValue{ + StaticType: &cadence.IntersectionType{ + Types: []cadence.Type{ + cadence.StringType{}, + }, + }, + }, + ) + + }) + + t.Run("with legacy intersection type", func(t *testing.T) { + t.Parallel() + + testEncodeAndDecodeEx( + t, + cadence.TypeValue{ + StaticType: &cadence.IntersectionType{ + Types: []cadence.Type{ + cadence.StringType{}, + }, + LegacyRestrictedType: cadence.IntType{}, + }, + }, + []byte{ + // language=json, format=json-cdc + // {"type":"Type","value":{"staticType": { "kind": "Intersection", "typeID":"Int{String}", "type" : {"kind" : "Int"}, "types" : [ {"kind" : "String"} ]} } } + // + // language=edn, format=ccf + // 130([137(41), 191([185(4), [185(1)]])]) + // + // 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 items follow + 0x82, + // type + // int type tag + 0xd8, + // int type + 0xb9, 0x04, // array, 1 element follows 0x81, // tag @@ -9551,6 +9633,7 @@ func TestEncodeType(t *testing.T) { Types: []cadence.Type{ cadence.StringType{}, }, + LegacyRestrictedType: cadence.IntType{}, }, }, ) @@ -9588,6 +9671,11 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, + // array, 2 items follow + 0x82, + // type + // null + 0xf6, // array, 2 element follows 0x82, // tag @@ -9659,6 +9747,11 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, + // array, 2 items follow + 0x82, + // type + // null + 0xf6, // 3 sorted types // array, 3 element follows 0x83, @@ -14296,6 +14389,11 @@ func TestDecodeInvalidData(t *testing.T) { 0xd8, ccf.CBORTagIntersectionTypeValue, // array, 2 items follow 0x82, + // type + // null + 0xf6, + // array, 2 items follow + 0x82, // tag 0xd8, ccf.CBORTagStructTypeValue, // array, 5 items follow @@ -14533,6 +14631,11 @@ func TestEncodeValueOfIntersectedInterface(t *testing.T) { 0x66, 0x69, 0x65, 0x6c, 0x64, // tag 0xd8, ccf.CBORTagIntersectionType, + // array, 2 items follow + 0x82, + // type + // null + 0xf6, // array, 1 item follows 0x81, // tag @@ -14851,6 +14954,11 @@ 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 @@ -15040,6 +15148,11 @@ 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 @@ -15229,6 +15342,11 @@ 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 @@ -15418,6 +15536,11 @@ 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 ff35c43578..39a97cce82 100644 --- a/encoding/ccf/decode_type.go +++ b/encoding/ccf/decode_type.go @@ -553,12 +553,24 @@ func (d *Decoder) decodeIntersectionType( decodeTypeFn decodeTypeFn, decodeIntersectionTypeFn decodeTypeFn, ) (cadence.Type, error) { - // types + // Decode array of length 2. + err := decodeCBORArrayWithKnownSize(d.dec, 2) + if err != nil { + return nil, err + } + + // element 0: type + legacyRestrictedType, err := d.decodeNullableTypeValue(types) + if err != nil { + return nil, err + } + + // element 1: types typeCount, err := d.dec.DecodeArrayHead() if err != nil { return nil, err } - if typeCount == 0 { + if typeCount == 0 && legacyRestrictedType == nil { return nil, errors.New("unexpected empty intersection type") } @@ -602,14 +614,16 @@ func (d *Decoder) decodeIntersectionType( intersectionTypes[i] = intersectedType } - if len(intersectionTypes) == 0 { + if len(intersectionTypes) == 0 && legacyRestrictedType == nil { return nil, errors.New("unexpected empty intersection type") } - return cadence.NewMeteredIntersectionType( + intersectionType := cadence.NewMeteredIntersectionType( d.gauge, intersectionTypes, - ), nil + ) + intersectionType.LegacyRestrictedType = legacyRestrictedType + return intersectionType, nil } // decodeCCFTypeID decodes encoded id as diff --git a/encoding/ccf/encode_type.go b/encoding/ccf/encode_type.go index 70f8bc0966..875f5ed48c 100644 --- a/encoding/ccf/encode_type.go +++ b/encoding/ccf/encode_type.go @@ -390,7 +390,28 @@ func (e *Encoder) encodeIntersectionTypeWithRawTag( return err } - // types as array. + // Encode array head of length 2. + err = e.enc.EncodeArrayHead(2) + if err != nil { + return err + } + + // if this is a type in the old format, encode it in the old format + if typ.LegacyRestrictedType != nil { + // element 0: type with given encodeTypeFn + err = encodeTypeFn(typ.LegacyRestrictedType, tids) + if err != nil { + return err + } + } else { + // element 0: otherwise encode nil + err = e.enc.EncodeNil() + if err != nil { + return err + } + } + + // element 1: 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 bb6192cc00..6b8787e759 100644 --- a/encoding/ccf/traverse_value.go +++ b/encoding/ccf/traverse_value.go @@ -146,6 +146,9 @@ func (ct *compositeTypes) traverseType(typ cadence.Type) (checkRuntimeType bool) case *cadence.IntersectionType: check := false + if typ.LegacyRestrictedType != nil { + check = ct.traverseType(typ.LegacyRestrictedType) + } for _, typ := range typ.Types { checkTyp := ct.traverseType(typ) check = check || checkTyp diff --git a/types.go b/types.go index 0e19e69bc4..b7c026da36 100644 --- a/types.go +++ b/types.go @@ -2272,10 +2272,11 @@ func (t *ReferenceType) Equal(other Type) bool { type IntersectionSet = map[Type]struct{} type IntersectionType struct { - typeID string - Types []Type - intersectionSet IntersectionSet - intersectionSetOnce sync.Once + typeID string + Types []Type + LegacyRestrictedType Type + intersectionSet IntersectionSet + intersectionSetOnce sync.Once } func NewIntersectionType( From 685e59d784771ec2d6b6f0e02ff5946edde0155a Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Fri, 30 Jun 2023 10:29:37 -0400 Subject: [PATCH 13/16] interpreter decoding is backwards compatible --- runtime/interpreter/decode.go | 53 +++++++++++++++++- runtime/interpreter/encode.go | 32 ++++++++++- runtime/interpreter/encoding_test.go | 80 ++++++++++++++++++++++++++++ runtime/interpreter/statictype.go | 3 +- 4 files changed, 164 insertions(+), 4 deletions(-) diff --git a/runtime/interpreter/decode.go b/runtime/interpreter/decode.go index 91ed82d675..7bafbede12 100644 --- a/runtime/interpreter/decode.go +++ b/runtime/interpreter/decode.go @@ -1833,6 +1833,52 @@ func (d TypeDecoder) decodeDictionaryStaticType() (StaticType, error) { } func (d TypeDecoder) decodeIntersectionStaticType() (StaticType, error) { + const expectedLength = encodedIntersectionStaticTypeLength + + arraySize, err := d.decoder.DecodeArrayHead() + + if err != nil { + if e, ok := err.(*cbor.WrongTypeError); ok { + return nil, errors.NewUnexpectedError( + "invalid intersection static type encoding: expected [%d]any, got %s", + expectedLength, + e.ActualType.String(), + ) + } + return nil, err + } + + if arraySize != expectedLength { + return nil, errors.NewUnexpectedError( + "invalid intersection static type encoding: expected [%d]any, got [%d]any", + expectedLength, + arraySize, + ) + } + + var legacyRestrictedType StaticType + + t, err := d.decoder.NextType() + if err != nil { + return nil, err + } + + if t != cbor.NilType { + // 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, + ) + } + } else { + err = d.decoder.DecodeNil() + if err != nil { + return nil, err + } + } + // Decode intersected types at array index encodedIntersectionStaticTypeTypesFieldKey intersectionSize, err := d.decoder.DecodeArrayHead() if err != nil { @@ -1884,10 +1930,13 @@ func (d TypeDecoder) decodeIntersectionStaticType() (StaticType, error) { } } - return NewIntersectionStaticType( + staticType := NewIntersectionStaticType( d.memoryGauge, 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 6a4f90f300..7c2ce5d8aa 100644 --- a/runtime/interpreter/encode.go +++ b/runtime/interpreter/encode.go @@ -1559,12 +1559,25 @@ func (t DictionaryStaticType) Encode(e *cbor.StreamEncoder) error { return t.ValueType.Encode(e) } +// NOTE: NEVER change, only add/increment; ensure uint64 +const ( + // encodedIntersectionStaticTypeLegacyTypeFieldKey uint64 = 0 + // encodedIntersectionStaticTypeTypesFieldKey uint64 = 1 + + // !!! *WARNING* !!! + // + // encodedIntersectionStaticTypeLength MUST be updated when new element is added. + // It is used to verify encoded intersection static type length during decoding. + encodedIntersectionStaticTypeLength = 2 +) + // Encode encodes IntersectionStaticType as // // cbor.Tag{ // Number: CBORTagIntersectionStaticType, // Content: cborArray{ -// encodedIntersectionStaticTypeTypesFieldKey: []any(v.Types), +// encodedIntersectionStaticTypeLegacyTypeFieldKey: StaticType(v.LegacyRestrictedType), +// encodedIntersectionStaticTypeTypesFieldKey: []any(v.Types), // }, // } func (t *IntersectionStaticType) Encode(e *cbor.StreamEncoder) error { @@ -1572,15 +1585,32 @@ func (t *IntersectionStaticType) Encode(e *cbor.StreamEncoder) error { err := e.EncodeRawBytes([]byte{ // tag number 0xd8, CBORTagIntersectionStaticType, + // array, 2 items follow + 0x82, }) 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 5245cff584..3d57ba229e 100644 --- a/runtime/interpreter/encoding_test.go +++ b/runtime/interpreter/encoding_test.go @@ -4164,6 +4164,78 @@ func TestEncodeDecodePathLinkValue(t *testing.T) { 0xd8, CBORTagIntersectionStaticType, // array, length 2 0x82, + // nil + 0xf6, + // array, length 2 + 0x82, + // tag + 0xd8, CBORTagInterfaceStaticType, + // array, 2 items follow + 0x82, + // tag + 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 + 0xd8, CBORTagStringLocation, + // UTF-8 string, length 4 + 0x64, + // t, e, s, t + 0x74, 0x65, 0x73, 0x74, + // 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 0xd8, CBORTagInterfaceStaticType, // array, 2 items follow @@ -4863,6 +4935,10 @@ func TestEncodeDecodeStorageCapabilityControllerValue(t *testing.T) { 0xd8, CBORTagIntersectionStaticType, // array, length 2 0x82, + // nil + 0xf6, + // array, length 2 + 0x82, // tag 0xd8, CBORTagInterfaceStaticType, // array, 2 items follow @@ -5044,6 +5120,10 @@ func TestEncodeDecodeAccountCapabilityControllerValue(t *testing.T) { 0xf6, // tag 0xd8, CBORTagIntersectionStaticType, + // array, length 2 + 0x82, + // nil + 0xf6, // array, 1 item follows 0x81, // tag diff --git a/runtime/interpreter/statictype.go b/runtime/interpreter/statictype.go index 6544b5475e..f133f156ac 100644 --- a/runtime/interpreter/statictype.go +++ b/runtime/interpreter/statictype.go @@ -395,7 +395,8 @@ var NilStaticType = OptionalStaticType{ // IntersectionStaticType type IntersectionStaticType struct { - Types []InterfaceStaticType + Types []InterfaceStaticType + LegacyType StaticType } var _ StaticType = &IntersectionStaticType{} From f58a48d656d1722b1818fdb65288c7d636db0411 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Fri, 30 Jun 2023 16:08:30 -0400 Subject: [PATCH 14/16] respond to review --- runtime/interpreter/decode.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime/interpreter/decode.go b/runtime/interpreter/decode.go index 7bafbede12..5c8647ec58 100644 --- a/runtime/interpreter/decode.go +++ b/runtime/interpreter/decode.go @@ -1863,7 +1863,12 @@ func (d TypeDecoder) decodeIntersectionStaticType() (StaticType, error) { return nil, err } - if t != cbor.NilType { + 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 { @@ -1872,11 +1877,6 @@ func (d TypeDecoder) decodeIntersectionStaticType() (StaticType, error) { err, ) } - } else { - err = d.decoder.DecodeNil() - if err != nil { - return nil, err - } } // Decode intersected types at array index encodedIntersectionStaticTypeTypesFieldKey From e6661e2a700943e06d9d64849e170e44460f9578 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Mon, 10 Jul 2023 11:16:46 -0400 Subject: [PATCH 15/16] Revert "ccf encoding/decoding is backwards compatible" This reverts commit 3fcf2e9999db4641a7d3f4033a0a415e8d578a4d. --- encoding/ccf/ccf_test.go | 123 --------------------------------- encoding/ccf/decode_type.go | 24 ++----- encoding/ccf/encode_type.go | 23 +----- encoding/ccf/traverse_value.go | 3 - types.go | 9 ++- 5 files changed, 10 insertions(+), 172 deletions(-) diff --git a/encoding/ccf/ccf_test.go b/encoding/ccf/ccf_test.go index 857b60b4f8..ce2faae934 100644 --- a/encoding/ccf/ccf_test.go +++ b/encoding/ccf/ccf_test.go @@ -6805,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 @@ -7024,11 +7019,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 @@ -9478,11 +9468,6 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, - // array, 2 items follow - 0x82, - // type - // null - 0xf6, // array, 0 element follows 0x80, } @@ -9514,11 +9499,6 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, - // array, 2 items follow - 0x82, - // type - // null - 0xf6, // array, 0 element follows 0x80, } @@ -9558,68 +9538,6 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, - // array, 2 items follow - 0x82, - // type - // null - 0xf6, - // array, 1 element follows - 0x81, - // tag - 0xd8, ccf.CBORTagSimpleTypeValue, - // String type ID (1) - 0x01, - }, - // Expected decoded IntersectionType doesn't have type ID. - cadence.TypeValue{ - StaticType: &cadence.IntersectionType{ - Types: []cadence.Type{ - cadence.StringType{}, - }, - }, - }, - ) - - }) - - t.Run("with legacy intersection type", func(t *testing.T) { - t.Parallel() - - testEncodeAndDecodeEx( - t, - cadence.TypeValue{ - StaticType: &cadence.IntersectionType{ - Types: []cadence.Type{ - cadence.StringType{}, - }, - LegacyRestrictedType: cadence.IntType{}, - }, - }, - []byte{ - // language=json, format=json-cdc - // {"type":"Type","value":{"staticType": { "kind": "Intersection", "typeID":"Int{String}", "type" : {"kind" : "Int"}, "types" : [ {"kind" : "String"} ]} } } - // - // language=edn, format=ccf - // 130([137(41), 191([185(4), [185(1)]])]) - // - // 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 items follow - 0x82, - // type - // int type tag - 0xd8, - // int type - 0xb9, 0x04, // array, 1 element follows 0x81, // tag @@ -9633,7 +9551,6 @@ func TestEncodeType(t *testing.T) { Types: []cadence.Type{ cadence.StringType{}, }, - LegacyRestrictedType: cadence.IntType{}, }, }, ) @@ -9671,11 +9588,6 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, - // array, 2 items follow - 0x82, - // type - // null - 0xf6, // array, 2 element follows 0x82, // tag @@ -9747,11 +9659,6 @@ func TestEncodeType(t *testing.T) { 0x18, 0x29, // tag 0xd8, ccf.CBORTagIntersectionTypeValue, - // array, 2 items follow - 0x82, - // type - // null - 0xf6, // 3 sorted types // array, 3 element follows 0x83, @@ -14389,11 +14296,6 @@ func TestDecodeInvalidData(t *testing.T) { 0xd8, ccf.CBORTagIntersectionTypeValue, // array, 2 items follow 0x82, - // type - // null - 0xf6, - // array, 2 items follow - 0x82, // tag 0xd8, ccf.CBORTagStructTypeValue, // array, 5 items follow @@ -14631,11 +14533,6 @@ func TestEncodeValueOfIntersectedInterface(t *testing.T) { 0x66, 0x69, 0x65, 0x6c, 0x64, // tag 0xd8, ccf.CBORTagIntersectionType, - // array, 2 items follow - 0x82, - // type - // null - 0xf6, // array, 1 item follows 0x81, // tag @@ -14954,11 +14851,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 @@ -15148,11 +15040,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 @@ -15342,11 +15229,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 @@ -15536,11 +15418,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 39a97cce82..ff35c43578 100644 --- a/encoding/ccf/decode_type.go +++ b/encoding/ccf/decode_type.go @@ -553,24 +553,12 @@ 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 - legacyRestrictedType, err := d.decodeNullableTypeValue(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 && legacyRestrictedType == nil { + if typeCount == 0 { return nil, errors.New("unexpected empty intersection type") } @@ -614,16 +602,14 @@ func (d *Decoder) decodeIntersectionType( intersectionTypes[i] = intersectedType } - if len(intersectionTypes) == 0 && legacyRestrictedType == nil { + if len(intersectionTypes) == 0 { return nil, errors.New("unexpected empty intersection type") } - intersectionType := cadence.NewMeteredIntersectionType( + return cadence.NewMeteredIntersectionType( d.gauge, intersectionTypes, - ) - intersectionType.LegacyRestrictedType = legacyRestrictedType - return intersectionType, nil + ), nil } // decodeCCFTypeID decodes encoded id as diff --git a/encoding/ccf/encode_type.go b/encoding/ccf/encode_type.go index 875f5ed48c..70f8bc0966 100644 --- a/encoding/ccf/encode_type.go +++ b/encoding/ccf/encode_type.go @@ -390,28 +390,7 @@ func (e *Encoder) encodeIntersectionTypeWithRawTag( return err } - // Encode array head of length 2. - err = e.enc.EncodeArrayHead(2) - if err != nil { - return err - } - - // if this is a type in the old format, encode it in the old format - if typ.LegacyRestrictedType != nil { - // element 0: type with given encodeTypeFn - err = encodeTypeFn(typ.LegacyRestrictedType, tids) - if err != nil { - return err - } - } else { - // element 0: otherwise encode nil - err = e.enc.EncodeNil() - 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 6b8787e759..bb6192cc00 100644 --- a/encoding/ccf/traverse_value.go +++ b/encoding/ccf/traverse_value.go @@ -146,9 +146,6 @@ func (ct *compositeTypes) traverseType(typ cadence.Type) (checkRuntimeType bool) case *cadence.IntersectionType: check := false - if typ.LegacyRestrictedType != nil { - check = ct.traverseType(typ.LegacyRestrictedType) - } for _, typ := range typ.Types { checkTyp := ct.traverseType(typ) check = check || checkTyp diff --git a/types.go b/types.go index b7c026da36..0e19e69bc4 100644 --- a/types.go +++ b/types.go @@ -2272,11 +2272,10 @@ func (t *ReferenceType) Equal(other Type) bool { type IntersectionSet = map[Type]struct{} type IntersectionType struct { - typeID string - Types []Type - LegacyRestrictedType Type - intersectionSet IntersectionSet - intersectionSetOnce sync.Once + typeID string + Types []Type + intersectionSet IntersectionSet + intersectionSetOnce sync.Once } func NewIntersectionType( From 0419bfbe6271c9c8fbbc8ec9f9285ef98922580a Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Fri, 14 Jul 2023 10:46:23 -0400 Subject: [PATCH 16/16] respond to review --- runtime/sema/type.go | 6 ------ runtime/sema/type_tags.go | 17 ++++------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 720d2b4846..caddea0a40 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -6175,12 +6175,6 @@ func checkSubTypeWithoutEquality(subType Type, superType Type) bool { return true case *IntersectionType: - // `Any` is never a subtype of a intersection type - switch subType { - case AnyResourceType, AnyStructType, AnyType: - return false - } - switch typedSubType := subType.(type) { case *IntersectionType: diff --git a/runtime/sema/type_tags.go b/runtime/sema/type_tags.go index 9a53c8f6ae..bef99a388e 100644 --- a/runtime/sema/type_tags.go +++ b/runtime/sema/type_tags.go @@ -927,24 +927,15 @@ func commonSuperTypeOfComposites(types []Type) Type { } } - var superType Type - if hasResources { - superType = AnyResourceType - } else { - superType = AnyStructType - } - if hasCommonInterface { - if len(commonInterfacesList) == 0 { - panic(errors.NewUnreachableError()) - } - return &IntersectionType{ Types: commonInterfacesList, } + } else if hasResources { + return AnyResourceType + } else { + return AnyStructType } - - return superType } func unwrapOptionals(types []Type) ([]Type, int) {