Skip to content

Commit

Permalink
include available declarations in "not declared" error
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent committed Aug 4, 2020
1 parent 802556e commit de4c8a7
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 8 deletions.
52 changes: 44 additions & 8 deletions runtime/sema/check_import_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,21 @@ func (checker *Checker) declareImportDeclaration(declaration *ast.ImportDeclarat

// Attempt to import the requested value declarations

allValueElements := imp.AllValueElements()
foundValues, invalidAccessedValues := checker.importElements(
checker.valueActivations,
declaration.Identifiers,
imp.AllValueElements(),
allValueElements,
imp.IsImportableValue,
)

// Attempt to import the requested type declarations

allTypeElements := imp.AllTypeElements()
foundTypes, invalidAccessedTypes := checker.importElements(
checker.typeActivations,
declaration.Identifiers,
imp.AllTypeElements(),
allTypeElements,
imp.IsImportableType,
)

Expand Down Expand Up @@ -141,22 +143,55 @@ func (checker *Checker) declareImportDeclaration(declaration *ast.ImportDeclarat
)
}

identifierCount := len(declaration.Identifiers)

// Determine which requested declarations could neither be found
// in the value nor in the type declarations of the imported program.
// For each missing import, report an error and declare both a value
// with an invalid type and an invalid type to avoid spurious errors
// due to uses of the inaccessible value or type
// due to uses of the inaccessible value or type.
//
// Also show which declarations are available, to help with debugging.

missing := make([]ast.Identifier, 0, identifierCount)

missing := make(map[ast.Identifier]bool, len(declaration.Identifiers))
for _, identifier := range declaration.Identifiers {
if foundValues[identifier] || foundTypes[identifier] {
continue
}

missing[identifier] = true
missing = append(missing, identifier)
}

checker.handleMissingImports(missing, location)
if len(missing) > 0 {
capacity := len(allValueElements) + len(allTypeElements)
available := make([]string, 0, capacity)
availableSet := make(map[string]struct{}, capacity)

for identifier := range allValueElements {
if _, ok := availableSet[identifier]; ok {
continue
}
if !imp.IsImportableValue(identifier) {
continue
}
availableSet[identifier] = struct{}{}
available = append(available, identifier)
}

for identifier := range allTypeElements {
if _, ok := availableSet[identifier]; ok {
continue
}
if !imp.IsImportableType(identifier) {
continue
}
availableSet[identifier] = struct{}{}
available = append(available, identifier)
}

checker.handleMissingImports(missing, available, location)
}

return nil
}
Expand Down Expand Up @@ -202,12 +237,13 @@ func (checker *Checker) EnsureLoaded(location ast.Location, loadProgram func() *
return subChecker, checkerErr
}

func (checker *Checker) handleMissingImports(missing map[ast.Identifier]bool, importLocation ast.Location) {
for identifier := range missing {
func (checker *Checker) handleMissingImports(missing []ast.Identifier, available []string, importLocation ast.Location) {
for _, identifier := range missing {
checker.report(
&NotExportedError{
Name: identifier.Identifier,
ImportLocation: importLocation,
Available: available,
Pos: identifier.Pos,
},
)
Expand Down
13 changes: 13 additions & 0 deletions runtime/sema/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package sema
import (
"fmt"
"math/big"
"strings"

"github.com/onflow/cadence/runtime/ast"
"github.com/onflow/cadence/runtime/common"
Expand Down Expand Up @@ -1024,6 +1025,7 @@ func (*RepeatedImportError) isSemanticError() {}
type NotExportedError struct {
Name string
ImportLocation ast.Location
Available []string
Pos ast.Position
}

Expand All @@ -1035,6 +1037,17 @@ func (e *NotExportedError) Error() string {
)
}

func (e *NotExportedError) SecondaryError() string {
var builder strings.Builder
builder.WriteString("available exported declarations are:\n")

for _, available := range e.Available {
builder.WriteString(fmt.Sprintf(" - `%s`\n", available))
}

return builder.String()
}

func (*NotExportedError) isSemanticError() {}

func (e *NotExportedError) StartPosition() ast.Position {
Expand Down

0 comments on commit de4c8a7

Please sign in to comment.