Skip to content

Commit

Permalink
Update checker for import aliases.
Browse files Browse the repository at this point in the history
  • Loading branch information
RZhang05 committed Dec 16, 2024
1 parent 739a8a9 commit efc00c0
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 2 deletions.
1 change: 1 addition & 0 deletions old_parser/declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,7 @@ func parseImportDeclaration(p *parser) (*ast.ImportDeclaration, error) {
return ast.NewImportDeclaration(
p.memoryGauge,
identifiers,
nil,
location,
ast.NewRange(
p.memoryGauge,
Expand Down
55 changes: 55 additions & 0 deletions parser/declaration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2554,6 +2554,61 @@ func TestParseImportDeclaration(t *testing.T) {
result,
)
})

t.Run("alias same imported function", func(t *testing.T) {

t.Parallel()

result, errs := testParseDeclarations(`
import foo as bar from 0x42
import foo as cab from 0x42
`)
require.Empty(t, errs)

AssertEqualWithDiff(t,
[]ast.Declaration{
&ast.ImportDeclaration{
Identifiers: []ast.Identifier{
{
Identifier: "foo",
Pos: ast.Position{Line: 2, Column: 10, Offset: 11},
},
},
Aliases: map[string]string{
"foo": "bar",
},
Location: common.AddressLocation{
Address: common.MustBytesToAddress([]byte{0x42}),
},
LocationPos: ast.Position{Line: 2, Column: 26, Offset: 27},
Range: ast.Range{
StartPos: ast.Position{Line: 2, Column: 3, Offset: 4},
EndPos: ast.Position{Line: 2, Column: 29, Offset: 30},
},
},
&ast.ImportDeclaration{
Identifiers: []ast.Identifier{
{
Identifier: "foo",
Pos: ast.Position{Line: 3, Column: 10, Offset: 42},
},
},
Aliases: map[string]string{
"foo": "cab",
},
Location: common.AddressLocation{
Address: common.MustBytesToAddress([]byte{0x42}),
},
LocationPos: ast.Position{Line: 3, Column: 26, Offset: 58},
Range: ast.Range{
StartPos: ast.Position{Line: 3, Column: 3, Offset: 35},
EndPos: ast.Position{Line: 3, Column: 29, Offset: 61},
},
},
},
result,
)
})
}

func TestParseEvent(t *testing.T) {
Expand Down
11 changes: 9 additions & 2 deletions sema/check_import_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (checker *Checker) declareImportDeclaration(declaration *ast.ImportDeclarat
checker.Elaboration.SetImportDeclarationsResolvedLocations(declaration, resolvedLocations)

for _, resolvedLocation := range resolvedLocations {
checker.importResolvedLocation(resolvedLocation, locationRange)
checker.importResolvedLocation(resolvedLocation, locationRange, &declaration.Aliases)
}
}

Expand All @@ -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) {
func (checker *Checker) importResolvedLocation(resolvedLocation ResolvedLocation, locationRange ast.Range, aliases *map[string]string) {

// First, get the Import for the resolved location

Expand Down Expand Up @@ -178,6 +178,7 @@ func (checker *Checker) importResolvedLocation(resolvedLocation ResolvedLocation
checker.valueActivations,
resolvedLocation.Identifiers,
allValueElements,
aliases,
true,
)

Expand All @@ -188,6 +189,7 @@ func (checker *Checker) importResolvedLocation(resolvedLocation ResolvedLocation
checker.typeActivations,
resolvedLocation.Identifiers,
allTypeElements,
aliases,
false,
)

Expand Down Expand Up @@ -302,6 +304,7 @@ func (checker *Checker) importElements(
valueActivations *VariableActivations,
requestedIdentifiers []ast.Identifier,
availableElements *StringImportElementOrderedMap,
aliases *map[string]string,
importValues bool,
) (
found map[ast.Identifier]bool,
Expand All @@ -326,6 +329,10 @@ func (checker *Checker) importElements(
if !ok {
continue
}
alias, ok := (*aliases)[name]
if ok {
name = alias
}
elements.Set(name, element)
found[identifier] = true
explicitlyImported[name] = identifier
Expand Down
192 changes: 192 additions & 0 deletions sema/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -824,3 +824,195 @@ func TestCheckImportContract(t *testing.T) {
})

}

func TestCheckImportAlias(t *testing.T) {

t.Parallel()

t.Run("valid contract import", func(t *testing.T) {

importedChecker, err := ParseAndCheckWithOptions(t,
`
access(all) contract Foo {
access(all) let x: [Int]
access(all) fun answer(): Int {
return 42
}
access(all) struct Bar {}
init() {
self.x = []
}
}`,
ParseAndCheckOptions{
Location: ImportedLocation,
},
)

require.NoError(t, err)

_, err = ParseAndCheckWithOptions(t,
`
import Foo as Bar from "imported"
access(all) fun main() {
var foo: &Bar = Bar
var x: &[Int] = Bar.x
var bar: Bar.Bar = Bar.Bar()
}
`,
ParseAndCheckOptions{
Config: &sema.Config{
ImportHandler: func(_ *sema.Checker, _ common.Location, _ ast.Range) (sema.Import, error) {
return sema.ElaborationImport{
Elaboration: importedChecker.Elaboration,
}, nil
},
},
},
)

require.NoError(t, err)
})

t.Run("valid, multiple alias of same contract", func(t *testing.T) {

importedChecker, err := ParseAndCheckWithOptions(t,
`
access(all) contract Foo {
access(all) let x: [Int]
access(all) fun answer(): Int {
return 42
}
access(all) struct Bar {}
init() {
self.x = []
}
}`,
ParseAndCheckOptions{
Location: ImportedLocation,
},
)

require.NoError(t, err)

_, err = ParseAndCheckWithOptions(t,
`
import Foo as Bar from "imported"
import Foo as Cab from "imported"
access(all) fun main() {
var foo: &Cab = Cab
var x: &[Int] = Bar.x
var bar: Cab.Bar = Cab.Bar()
}
`,
ParseAndCheckOptions{
Config: &sema.Config{
ImportHandler: func(_ *sema.Checker, _ common.Location, _ ast.Range) (sema.Import, error) {
return sema.ElaborationImport{
Elaboration: importedChecker.Elaboration,
}, nil
},
},
},
)

require.NoError(t, err)
})

t.Run("invalid, duplicate aliases", func(t *testing.T) {

importedChecker, err := ParseAndCheckWithOptions(t,
`
access(all) fun a(): Int {
return 42
}
access(all) fun b(): Int {
return 50
}
`,
ParseAndCheckOptions{
Location: ImportedLocation,
},
)

require.NoError(t, err)

_, err = ParseAndCheckWithOptions(t,
`
import a as c from "imported"
import b as c from "imported"
access(all) fun main() {
c() + c()
}
`,
ParseAndCheckOptions{
Config: &sema.Config{
ImportHandler: func(_ *sema.Checker, _ common.Location, _ ast.Range) (sema.Import, error) {
return sema.ElaborationImport{
Elaboration: importedChecker.Elaboration,
}, nil
},
},
},
)

errs := RequireCheckerErrors(t, err, 1)

redeclarationError := &sema.RedeclarationError{}
assert.ErrorAs(t, errs[0], &redeclarationError)

})

t.Run("invalid, missing aliased import", func(t *testing.T) {

importedChecker, err := ParseAndCheckWithOptions(t,
`
access(all) fun a(): Int {
return 42
}
`,
ParseAndCheckOptions{
Location: ImportedLocation,
},
)

require.NoError(t, err)

_, err = ParseAndCheckWithOptions(t,
`
import c as a from "imported"
access(all) fun main() {
c() + c()
}
`,
ParseAndCheckOptions{
Config: &sema.Config{
ImportHandler: func(_ *sema.Checker, _ common.Location, _ ast.Range) (sema.Import, error) {
return sema.ElaborationImport{
Elaboration: importedChecker.Elaboration,
}, nil
},
},
},
)

errs := RequireCheckerErrors(t, err, 0)

notExportedError := &sema.NotExportedError{}
assert.ErrorAs(t, errs[0], &notExportedError)

})

}

0 comments on commit efc00c0

Please sign in to comment.