diff --git a/languageserver/go.mod b/languageserver/go.mod index 3a66d248..6a593982 100644 --- a/languageserver/go.mod +++ b/languageserver/go.mod @@ -10,6 +10,7 @@ require ( github.com/onflow/cadence v1.0.0-preview.39 github.com/onflow/cadence-tools/lint v1.0.0-preview.35 github.com/onflow/cadence-tools/test v1.0.0-preview.35 + github.com/onflow/flow-go v0.36.4-0.20240724205438-14f9fddeda2b github.com/onflow/flow-go-sdk v1.0.0-preview.42 github.com/onflow/flowkit/v2 v2.0.0-stable-cadence-alpha.27 github.com/sourcegraph/jsonrpc2 v0.1.0 @@ -155,7 +156,6 @@ require ( github.com/onflow/flow-emulator v1.0.0-preview.36 // indirect github.com/onflow/flow-ft/lib/go/contracts v1.0.0 // indirect github.com/onflow/flow-ft/lib/go/templates v1.0.0 // indirect - github.com/onflow/flow-go v0.36.4-0.20240724205438-14f9fddeda2b // indirect github.com/onflow/flow-nft/lib/go/contracts v1.2.1 // indirect github.com/onflow/flow-nft/lib/go/templates v1.2.0 // indirect github.com/onflow/flow/protobuf/go/flow v0.4.5 // indirect diff --git a/languageserver/integration/integration.go b/languageserver/integration/integration.go index e3018ad6..623a63a9 100644 --- a/languageserver/integration/integration.go +++ b/languageserver/integration/integration.go @@ -52,6 +52,7 @@ func NewFlowIntegration(s *server.Server, enableFlowClient bool) (*FlowIntegrati server.WithDiagnosticProvider(diagnostics), server.WithStringImportResolver(resolve.stringImport), server.WithInitializationOptionsHandler(integration.initialize), + server.WithExtendedStandardLibraryValues(FVMStandardLibraryValues()...), } if enableFlowClient { diff --git a/languageserver/integration/stdlib.go b/languageserver/integration/stdlib.go new file mode 100644 index 00000000..21c91ddd --- /dev/null +++ b/languageserver/integration/stdlib.go @@ -0,0 +1,39 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright 2019-2022 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package integration + +import ( + "github.com/onflow/cadence/runtime/common" + "github.com/onflow/cadence/runtime/stdlib" + evmstdlib "github.com/onflow/flow-go/fvm/evm/stdlib" +) + +// FVMtandardLibraryValues returns the standard library values which are provided by the FVM +// these are not part of the Cadence standard library +func FVMStandardLibraryValues() []stdlib.StandardLibraryValue { + return []stdlib.StandardLibraryValue{ + // InternalEVM contract + { + Name: evmstdlib.InternalEVMContractName, + Type: evmstdlib.InternalEVMContractType, + Value: evmstdlib.NewInternalEVMContractValue(nil, nil, common.AddressLocation{}), + Kind: common.DeclarationKindContract, + }, + } +} diff --git a/languageserver/server/server.go b/languageserver/server/server.go index 7acf50ed..7e1d6291 100644 --- a/languageserver/server/server.go +++ b/languageserver/server/server.go @@ -188,6 +188,10 @@ type Server struct { checkerStandardConfig *sema.Config // checkerScriptConfig is a config used to check scripts checkerScriptConfig *sema.Config + // standardLibrary is the default standard library + standardLibrary *standardLibrary + // scriptStandardLibrary is the standard library for scripts + scriptStandardLibrary *standardLibrary } type Option func(*Server) error @@ -278,6 +282,21 @@ func WithMemberAccountAccessHandler(handler sema.MemberAccountAccessHandlerFunc) } } +// WithStandardLibraryValues returns a server option that adds the given function +// as a function that is used to resolve standard library values (in addition to the default standard library) +// +// This is used to provide parts of the standard library that are present in some given environment +// but are not native to the language. +func WithExtendedStandardLibraryValues(values ...stdlib.StandardLibraryValue) Option { + return func(server *Server) error { + for _, value := range values { + server.standardLibrary.baseValueActivation.DeclareValue(value) + server.scriptStandardLibrary.baseValueActivation.DeclareValue(value) + } + return nil + } +} + const GetEntryPointParametersCommand = "cadence.server.getEntryPointParameters" const GetContractInitializerParametersCommand = "cadence.server.getContractInitializerParameters" const ParseEntryPointArgumentsCommand = "cadence.server.parseEntryPointArguments" @@ -307,15 +326,19 @@ func NewServer() (*Server, error) { } } + // create standard libraries + server.standardLibrary = newStandardLibrary() + server.scriptStandardLibrary = newScriptStandardLibrary() + // create checker configurations - server.checkerStandardConfig = newCheckerConfig(server, newStandardLibrary()) - server.checkerScriptConfig = newCheckerConfig(server, newScriptStandardLibrary()) + server.checkerStandardConfig = newCheckerConfig(server, server.standardLibrary) + server.checkerScriptConfig = newCheckerConfig(server, server.scriptStandardLibrary) return server, nil } // newCheckerConfig creates a checker config based on the standard library provided set to base value activations. -func newCheckerConfig(s *Server, lib standardLibrary) *sema.Config { +func newCheckerConfig(s *Server, lib *standardLibrary) *sema.Config { return &sema.Config{ BaseValueActivationHandler: func(_ common.Location) *sema.VariableActivation { return lib.baseValueActivation diff --git a/languageserver/server/stdlib.go b/languageserver/server/stdlib.go index 948b3c7e..49ba067a 100644 --- a/languageserver/server/stdlib.go +++ b/languageserver/server/stdlib.go @@ -273,18 +273,20 @@ func (standardLibrary) IsContractBeingAdded(_ common.AddressLocation) bool { panic(errors.NewUnreachableError()) } -func newStandardLibrary() (result standardLibrary) { +func newStandardLibrary() *standardLibrary { + result := &standardLibrary{} result.baseValueActivation = sema.NewVariableActivation(sema.BaseValueActivation) for _, valueDeclaration := range stdlib.DefaultStandardLibraryValues(result) { result.baseValueActivation.DeclareValue(valueDeclaration) } - return + return result } -func newScriptStandardLibrary() (result standardLibrary) { +func newScriptStandardLibrary() *standardLibrary { + result := &standardLibrary{} result.baseValueActivation = sema.NewVariableActivation(sema.BaseValueActivation) for _, declaration := range stdlib.DefaultScriptStandardLibraryValues(result) { result.baseValueActivation.DeclareValue(declaration) } - return + return result } diff --git a/languageserver/test/index.test.ts b/languageserver/test/index.test.ts index 71a34791..3a9bcb93 100644 --- a/languageserver/test/index.test.ts +++ b/languageserver/test/index.test.ts @@ -319,6 +319,20 @@ describe("diagnostics", () => { ["unused result"] ) ) + + test("InternalEVM contract exists", async() => + testCode( + ` + access(all) + fun main() { + // Checks that the InternalEVM contract exists + // Also that it has the correct value (i.e. the run function exists) + log(InternalEVM.run) + } + `, + [] + ) + ) type TestDoc = { name: string