diff --git a/ast/import_test.go b/ast/import_test.go index 9badba2b0..7a221970d 100644 --- a/ast/import_test.go +++ b/ast/import_test.go @@ -40,6 +40,9 @@ func TestImportDeclaration_MarshalJSON(t *testing.T) { Pos: Position{Offset: 1, Line: 2, Column: 3}, }, }, + Aliases: map[string]string{ + "foo": "bar", + }, Location: common.StringLocation("test"), LocationPos: Position{Offset: 4, Line: 5, Column: 6}, Range: Range{ @@ -63,7 +66,9 @@ func TestImportDeclaration_MarshalJSON(t *testing.T) { "EndPos": {"Offset": 3, "Line": 2, "Column": 5} } ], - "Aliases": null, + "Aliases": { + "foo": "bar" + }, "Location": { "Type": "StringLocation", "String": "test" diff --git a/interpreter/import_test.go b/interpreter/import_test.go index c261b5656..59b53df97 100644 --- a/interpreter/import_test.go +++ b/interpreter/import_test.go @@ -542,3 +542,95 @@ func TestInterpretImportWithAlias(t *testing.T) { value, ) } + +func TestInterpretImportAliasGetType(t *testing.T) { + + t.Parallel() + + address := common.MustBytesToAddress([]byte{0x1}) + + importedChecker, err := ParseAndCheckWithOptions(t, + ` + access(all) struct Foo { + } + `, + ParseAndCheckOptions{ + Location: common.AddressLocation{ + Address: address, + Name: "", + }, + }, + ) + require.NoError(t, err) + + importingChecker, err := ParseAndCheckWithOptions(t, + ` + import Foo as Bar from 0x1 + + access(all) fun test(): String { + var bar: Bar = Bar() + return bar.getType().identifier + } + `, + ParseAndCheckOptions{ + Config: &sema.Config{ + LocationHandler: func(identifiers []ast.Identifier, location common.Location) (result []sema.ResolvedLocation, err error) { + + for _, identifier := range identifiers { + result = append(result, sema.ResolvedLocation{ + Location: common.AddressLocation{ + Address: location.(common.AddressLocation).Address, + Name: identifier.Identifier, + }, + Identifiers: []ast.Identifier{ + identifier, + }, + }) + } + return + }, + ImportHandler: func(checker *sema.Checker, importedLocation common.Location, _ ast.Range) (sema.Import, error) { + return sema.ElaborationImport{ + Elaboration: importedChecker.Elaboration, + }, nil + }, + }, + }, + ) + require.NoError(t, err) + + storage := newUnmeteredInMemoryStorage() + + inter, err := interpreter.NewInterpreter( + interpreter.ProgramFromChecker(importingChecker), + importingChecker.Location, + &interpreter.Config{ + Storage: storage, + ImportLocationHandler: func(inter *interpreter.Interpreter, location common.Location) interpreter.Import { + program := interpreter.ProgramFromChecker(importedChecker) + subInterpreter, err := inter.NewSubInterpreter(program, location) + if err != nil { + panic(err) + } + + return interpreter.InterpreterImport{ + Interpreter: subInterpreter, + } + }, + }, + ) + require.NoError(t, err) + + err = inter.Interpret() + require.NoError(t, err) + + value, err := inter.Invoke("test") + require.NoError(t, err) + + AssertValuesEqual( + t, + inter, + interpreter.NewUnmeteredStringValue("A.0000000000000001.Foo"), + value, + ) +} diff --git a/interpreter/interpreter_import.go b/interpreter/interpreter_import.go index 3d7f16983..ff3d50b29 100644 --- a/interpreter/interpreter_import.go +++ b/interpreter/interpreter_import.go @@ -32,13 +32,13 @@ func (interpreter *Interpreter) VisitImportDeclaration(declaration *ast.ImportDe resolvedLocations := interpreter.Program.Elaboration.ImportDeclarationsResolvedLocations(declaration) for _, resolvedLocation := range resolvedLocations { - interpreter.importResolvedLocation(resolvedLocation, &declaration.Aliases) + interpreter.importResolvedLocation(resolvedLocation, declaration.Aliases) } return nil } -func (interpreter *Interpreter) importResolvedLocation(resolvedLocation sema.ResolvedLocation, aliases *map[string]string) { +func (interpreter *Interpreter) importResolvedLocation(resolvedLocation sema.ResolvedLocation, aliases map[string]string) { config := interpreter.SharedState.Config // tracing @@ -63,7 +63,7 @@ func (interpreter *Interpreter) importResolvedLocation(resolvedLocation sema.Res variables = make(map[string]Variable, identifierLength) for _, identifier := range resolvedLocation.Identifiers { name := identifier.Identifier - alias, ok := (*aliases)[name] + alias, ok := aliases[name] if ok { name = alias } diff --git a/parser/declaration.go b/parser/declaration.go index f78fc3544..afde6f6f6 100644 --- a/parser/declaration.go +++ b/parser/declaration.go @@ -645,7 +645,7 @@ func parsePragmaDeclaration(p *parser) (*ast.PragmaDeclaration, error) { // // importDeclaration : // 'import' -// ( identifier (as identifier)? (',' identifier (as identifier)?)* 'from' )? +// ( identifier ('as' identifier)? (',' identifier ('as' identifier)?)* 'from' )? // ( string | hexadecimalLiteral | identifier ) func parseImportDeclaration(p *parser) (*ast.ImportDeclaration, error) { diff --git a/sema/check_import_declaration.go b/sema/check_import_declaration.go index 78a6a6e47..fabf48563 100644 --- a/sema/check_import_declaration.go +++ b/sema/check_import_declaration.go @@ -89,7 +89,7 @@ func (checker *Checker) declareImportDeclaration(declaration *ast.ImportDeclarat checker.Elaboration.SetImportDeclarationsResolvedLocations(declaration, resolvedLocations) for _, resolvedLocation := range resolvedLocations { - checker.importResolvedLocation(resolvedLocation, locationRange, &declaration.Aliases) + checker.importResolvedLocation(resolvedLocation, locationRange, declaration.Aliases) } } @@ -113,7 +113,7 @@ func (checker *Checker) resolveLocation(identifiers []ast.Identifier, location c return locationHandler(identifiers, location) } -func (checker *Checker) importResolvedLocation(resolvedLocation ResolvedLocation, locationRange ast.Range, aliases *map[string]string) { +func (checker *Checker) importResolvedLocation(resolvedLocation ResolvedLocation, locationRange ast.Range, aliases map[string]string) { // First, get the Import for the resolved location @@ -304,7 +304,7 @@ func (checker *Checker) importElements( valueActivations *VariableActivations, requestedIdentifiers []ast.Identifier, availableElements *StringImportElementOrderedMap, - aliases *map[string]string, + aliases map[string]string, importValues bool, ) ( found map[ast.Identifier]bool, @@ -329,7 +329,7 @@ func (checker *Checker) importElements( if !ok { continue } - alias, ok := (*aliases)[name] + alias, ok := aliases[name] if ok { name = alias } diff --git a/sema/import_test.go b/sema/import_test.go index b424e2cfb..4e7ea5d8f 100644 --- a/sema/import_test.go +++ b/sema/import_test.go @@ -833,19 +833,20 @@ func TestCheckImportAlias(t *testing.T) { importedChecker, err := ParseAndCheckWithOptions(t, ` - access(all) contract Foo { - access(all) let x: [Int] + access(all) contract Foo { + access(all) let x: [Int] - access(all) fun answer(): Int { - return 42 - } + access(all) fun answer(): Int { + return 42 + } - access(all) struct Bar {} + access(all) struct Bar {} - init() { - self.x = [] - } - }`, + init() { + self.x = [] + } + } + `, ParseAndCheckOptions{ Location: ImportedLocation, }, @@ -881,19 +882,20 @@ func TestCheckImportAlias(t *testing.T) { importedChecker, err := ParseAndCheckWithOptions(t, ` - access(all) contract Foo { - access(all) let x: [Int] + access(all) contract Foo { + access(all) let x: [Int] - access(all) fun answer(): Int { - return 42 - } + access(all) fun answer(): Int { + return 42 + } - access(all) struct Bar {} + access(all) struct Bar {} - init() { - self.x = [] - } - }`, + init() { + self.x = [] + } + } + `, ParseAndCheckOptions{ Location: ImportedLocation, }, @@ -937,7 +939,6 @@ func TestCheckImportAlias(t *testing.T) { access(all) fun b(): Int { return 50 } - `, ParseAndCheckOptions{ Location: ImportedLocation, @@ -980,7 +981,6 @@ func TestCheckImportAlias(t *testing.T) { access(all) fun a(): Int { return 42 } - `, ParseAndCheckOptions{ Location: ImportedLocation, @@ -1022,7 +1022,6 @@ func TestCheckImportAlias(t *testing.T) { access(all) fun a(): Int { return 42 } - `, ParseAndCheckOptions{ Location: ImportedLocation,