Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended debug #451

Merged
merged 13 commits into from
Nov 19, 2020
1 change: 1 addition & 0 deletions languageserver/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
Expand Down
27 changes: 27 additions & 0 deletions runtime/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/onflow/cadence/runtime/errors"
"github.com/onflow/cadence/runtime/interpreter"
"github.com/onflow/cadence/runtime/sema"
"github.com/onflow/cadence/runtime/stdlib"
)

// Error is the containing type for all errors produced by the runtime.
Expand Down Expand Up @@ -216,3 +217,29 @@ func (e *TransactionParameterTypeNotStorableError) Error() string {
e.Type.QualifiedString(),
)
}

// ExtendedParsingCheckingError is a special error which aids in debugging checking problems
m4ksio marked this conversation as resolved.
Show resolved Hide resolved
// by providing extra information about the state of the environment
// Separate package to prevent cyclic imports with checker tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite sure I understand this line, can you elaborate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type ExtendedParsingCheckingError struct {
Err error
RuntimeStorage *InterpreterRuntimeStorage
Functions stdlib.StandardLibraryFunctions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are these used for debugging? The fields in interpreterRuntimeStorage are also not exported, so is exposing the storage here (and exporting interpreterRuntimeStorage as InterpreterRuntimeStorage below) useful?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are these used for debugging?

They are dumped to a file for further usage. I didn't analyze what was particularly useful, just grabbed all there is

Copy link
Member

@turbolent turbolent Nov 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the runtime storage value doesn't provide any info, OK if I remove it?
Or we should maybe export the storage's cache, which could be useful to look at for execution errors.

Also, the functions that are injected are always the same, so IDK how useful it it is to include them in the error.

Copy link
Contributor Author

@m4ksio m4ksio Nov 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the runtime storage value doesn't provide any info, OK if I remove it?

Feel free if you think it doesn't provide any value, and add what you think it's best - you are the best person to know what internal elements might be helpful

Code []byte
Location Location
Options []sema.Option
UseCache bool
Checker *sema.Checker
}

func (e *ExtendedParsingCheckingError) ChildErrors() []error {
return []error{e.Err}
}

func (e *ExtendedParsingCheckingError) Error() string {
return e.Err.Error()
}

func (e ExtendedParsingCheckingError) Unwrap() error {
return e.Err
}
54 changes: 49 additions & 5 deletions runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,13 @@ func (r *interpreterRuntime) ExecuteTransaction(

checker, err := r.parseAndCheckProgram(script, runtimeInterface, location, functions, nil, false)
if err != nil {
ee, is := err.(*ExtendedParsingCheckingError)
if is {
ee.RuntimeStorage = runtimeStorage
ee.Functions = functions
//return newError(ee.Err)
turbolent marked this conversation as resolved.
Show resolved Hide resolved
return newError(ee)
}
return newError(err)
}

Expand Down Expand Up @@ -516,21 +523,42 @@ func (r *interpreterRuntime) parseAndCheckProgram(
program, err = runtimeInterface.GetCachedProgram(location)
})
if err != nil {
return nil, err
return nil, &ExtendedParsingCheckingError{
Err: err,
Code: code,
Location: location,
Functions: functions,
Options: options,
UseCache: useCache,
}
}
}

if program == nil {
program, err = r.parse(location, code, runtimeInterface)
if err != nil {
return nil, err
return nil, &ExtendedParsingCheckingError{
Err: err,
Code: code,
Location: location,
Functions: functions,
Options: options,
UseCache: useCache,
}
}
}

importResolver := r.importResolver(runtimeInterface)
err = program.ResolveImports(importResolver)
if err != nil {
return nil, err
return nil, &ExtendedParsingCheckingError{
Err: err,
Code: code,
Location: location,
Functions: functions,
Options: options,
UseCache: useCache,
}
}

valueDeclarations := functions.ToValueDeclarations()
Expand Down Expand Up @@ -568,12 +596,28 @@ func (r *interpreterRuntime) parseAndCheckProgram(
)...,
)
if err != nil {
return nil, err
return nil, &ExtendedParsingCheckingError{
Err: err,
Code: code,
Location: location,
Functions: functions,
Options: options,
UseCache: useCache,
Checker: checker,
}
}

err = checker.Check()
if err != nil {
return nil, err
return nil, &ExtendedParsingCheckingError{
Err: err,
Code: code,
Location: location,
Functions: functions,
Options: options,
UseCache: useCache,
Checker: checker,
}
}

// After the program has passed semantic analysis, cache the program AST.
Expand Down
3 changes: 3 additions & 0 deletions runtime/runtime_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ type interpreterRuntimeStorage struct {
cache map[storageKey]cacheEntry
}

// temporary export the type for usage in ExtendedParsingCheckingError
type InterpreterRuntimeStorage = interpreterRuntimeStorage

func newInterpreterRuntimeStorage(runtimeInterface Interface) *interpreterRuntimeStorage {
highLevelStorageEnabled := false
highLevelStorage, ok := runtimeInterface.(HighLevelStorage)
Expand Down
47 changes: 44 additions & 3 deletions runtime/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import (
"github.com/onflow/cadence/runtime/interpreter"
"github.com/onflow/cadence/runtime/sema"
"github.com/onflow/cadence/runtime/stdlib"
"github.com/onflow/cadence/runtime/tests/checker"
"github.com/onflow/cadence/runtime/tests/utils"
)

Expand Down Expand Up @@ -2377,7 +2376,14 @@ func TestRuntimeCyclicImport(t *testing.T) {

require.Error(t, err)
require.IsType(t, Error{}, err)
assert.IsType(t, ast.CyclicImportsError{}, err.(Error).Unwrap())

// Temporary to help catch checking error
ee := err.(Error).Unwrap()

require.IsType(t, &ExtendedParsingCheckingError{}, ee)
eee := ee.(*ExtendedParsingCheckingError)

assert.IsType(t, ast.CyclicImportsError{}, eee.Unwrap())
m4ksio marked this conversation as resolved.
Show resolved Hide resolved
}

func ArrayValueFromBytes(bytes []byte) *interpreter.ArrayValue {
Expand Down Expand Up @@ -3338,7 +3344,7 @@ func TestRuntimeTransactionTopLevelDeclarations(t *testing.T) {
require.IsType(t, Error{}, err)
err = err.(Error).Unwrap()

errs := checker.ExpectCheckerErrors(t, err, 1)
errs := ExpectCheckerErrors(t, err, 1)

assert.IsType(t, &sema.InvalidTopLevelDeclarationError{}, errs[0])
})
Expand Down Expand Up @@ -4774,3 +4780,38 @@ func TestRuntime(t *testing.T) {
test(testCase)
}
}

// Copied to prevent import cycle while importing from tests/checker package
// while using ExtendedParsingCheckingError
// This now required `runtime` to get access `ExtendedParsingCheckingError`
// which in turns requires `runtime` so any import of original function from
// any other module will introduce cycle
// If we decide to keep extended debug functionality beyond original
// debug possible race condition, this would need to be refactored
func ExpectCheckerErrors(t *testing.T, err error, count int) []error {
if count <= 0 && err == nil {
return nil
}

require.Error(t, err)

// Temporary to help catch checking error
ee, is := err.(*ExtendedParsingCheckingError)
if is {
err = ee.Unwrap()
}

assert.IsType(t, &sema.CheckerError{}, err)

errs := err.(*sema.CheckerError).Errors

require.Len(t, errs, count)

// Get the error message, to check that it can be successfully generated

for _, checkerErr := range errs {
_ = checkerErr.Error()
}

return errs
}
7 changes: 7 additions & 0 deletions runtime/tests/checker/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/onflow/cadence/runtime"
"github.com/onflow/cadence/runtime/ast"
"github.com/onflow/cadence/runtime/errors"
"github.com/onflow/cadence/runtime/parser2"
Expand Down Expand Up @@ -92,6 +93,12 @@ func ExpectCheckerErrors(t *testing.T, err error, count int) []error {

require.Error(t, err)

// Temporary to help catch checking error
ee, is := err.(*runtime.ExtendedParsingCheckingError)
if is {
err = ee.Unwrap()
}

assert.IsType(t, &sema.CheckerError{}, err)
m4ksio marked this conversation as resolved.
Show resolved Hide resolved

errs := err.(*sema.CheckerError).Errors
Expand Down