From f3be170419dbf68799f0aeb27c91b771aae53bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 25 Feb 2021 11:22:23 -0800 Subject: [PATCH] declare base values and base types in activations, reuse them when construction new checkers --- runtime/interpreter/interpreter.go | 2 +- runtime/sema/basefunction.go | 58 ---------- runtime/sema/checker.go | 31 +----- runtime/sema/import.go | 4 +- runtime/sema/type.go | 160 +++++++++++++++++---------- runtime/sema/variable_activations.go | 10 +- 6 files changed, 115 insertions(+), 150 deletions(-) delete mode 100644 runtime/sema/basefunction.go diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index c003b25e2e..d9e0c8154a 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -3427,7 +3427,7 @@ func (interpreter *Interpreter) importResolvedLocation(resolvedLocation sema.Res } // don't import base values - if _, ok := sema.BaseValues.Get(name); ok { + if sema.BaseValueActivation.Find(name) != nil { continue } diff --git a/runtime/sema/basefunction.go b/runtime/sema/basefunction.go deleted file mode 100644 index ff529b2aa3..0000000000 --- a/runtime/sema/basefunction.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Cadence - The resource-oriented smart contract programming language - * - * Copyright 2019-2020 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 sema - -import ( - "github.com/onflow/cadence/runtime/ast" - "github.com/onflow/cadence/runtime/common" -) - -type baseFunction struct { - name string - invokableType InvokableType - argumentLabels []string -} - -func (f baseFunction) ValueDeclarationName() string { - return f.name -} - -func (f baseFunction) ValueDeclarationType() Type { - return f.invokableType -} - -func (baseFunction) ValueDeclarationKind() common.DeclarationKind { - return common.DeclarationKindFunction -} - -func (baseFunction) ValueDeclarationPosition() ast.Position { - return ast.Position{} -} - -func (baseFunction) ValueDeclarationIsConstant() bool { - return true -} - -func (baseFunction) ValueDeclarationAvailable(_ common.Location) bool { - return true -} - -func (f baseFunction) ValueDeclarationArgumentLabels() []string { - return f.argumentLabels -} diff --git a/runtime/sema/checker.go b/runtime/sema/checker.go index 326f6cbc27..da57ee367e 100644 --- a/runtime/sema/checker.go +++ b/runtime/sema/checker.go @@ -220,30 +220,18 @@ func NewChecker(program *ast.Program, location common.Location, options ...Optio return nil, &MissingLocationError{} } + valueActivations := NewValueActivations(BaseValueActivation) + typeActivations := NewValueActivations(BaseTypeActivation) functionActivations := &FunctionActivations{} functionActivations.EnterFunction(&FunctionType{ ReturnTypeAnnotation: NewTypeAnnotation(VoidType)}, 0, ) - typeActivations := NewValueActivations() - baseTypes.Foreach(func(name string, baseType Type) { - _, err := typeActivations.DeclareType(typeDeclaration{ - identifier: ast.Identifier{Identifier: name}, - ty: baseType, - declarationKind: common.DeclarationKindType, - access: ast.AccessPublic, - allowOuterScopeShadowing: false, - }) - if err != nil { - panic(err) - } - }) - checker := &Checker{ Program: program, Location: location, - valueActivations: NewValueActivations(), + valueActivations: valueActivations, resources: NewResources(), typeActivations: typeActivations, functionActivations: functionActivations, @@ -253,8 +241,6 @@ func NewChecker(program *ast.Program, location common.Location, options ...Optio checker.beforeExtractor = NewBeforeExtractor(checker.report) - checker.declareBaseValues() - for _, option := range options { err := option(checker) if err != nil { @@ -284,17 +270,6 @@ func (checker *Checker) SubChecker(program *ast.Program, location common.Locatio ) } -func (checker *Checker) declareBaseValues() { - BaseValues.Foreach(func(_ string, declaration ValueDeclaration) { - variable := checker.declareValue(declaration) - if variable == nil { - return - } - variable.IsBaseValue = true - checker.Elaboration.GlobalValues.Set(variable.Identifier, variable) - }) -} - func (checker *Checker) declareValue(declaration ValueDeclaration) *Variable { if !declaration.ValueDeclarationAvailable(checker.Location) { diff --git a/runtime/sema/import.go b/runtime/sema/import.go index 41be5e183a..299a6ee9da 100644 --- a/runtime/sema/import.go +++ b/runtime/sema/import.go @@ -70,7 +70,7 @@ func (i ElaborationImport) AllValueElements() *StringImportElementOrderedMap { } func (i ElaborationImport) IsImportableValue(name string) bool { - if _, ok := BaseValues.Get(name); ok { + if BaseValueActivation.Find(name) != nil { return false } @@ -83,7 +83,7 @@ func (i ElaborationImport) AllTypeElements() *StringImportElementOrderedMap { } func (i ElaborationImport) IsImportableType(name string) bool { - if _, ok := baseTypes.Get(name); ok { + if BaseTypeActivation.Find(name) != nil { return false } diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 84e8314ac1..43bdbce10b 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -26,6 +26,7 @@ import ( "sync" "github.com/onflow/cadence/fixedpoint" + "github.com/onflow/cadence/runtime/activations" "github.com/onflow/cadence/runtime/ast" "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/errors" @@ -3844,15 +3845,13 @@ func (t *CheckedFunctionType) CheckArgumentExpressions( t.ArgumentExpressionsCheck(checker, argumentExpressions, invocationRange) } -// baseTypes are the nominal types available in programs +// BaseTypeActivation is the base activation that contains +// the types available in programs // -var baseTypes = NewStringTypeOrderedMap() +var BaseTypeActivation = activations.NewActivation(nil) func init() { - baseTypes = NewStringTypeOrderedMap() - baseTypes.Set("", VoidType) - otherTypes := []Type{ MetaType, VoidType, @@ -3883,18 +3882,41 @@ func init() { for _, ty := range types { typeName := ty.String() - // check type is not accidentally redeclared - if _, ok := baseTypes.Get(typeName); ok { + // Check that the type is not accidentally redeclared + + if BaseTypeActivation.Find(typeName) != nil { panic(errors.NewUnreachableError()) } - baseTypes.Set(typeName, ty) + BaseTypeActivation.Set( + typeName, + baseTypeVariable(typeName, ty), + ) } + + // The AST contains empty type annotations, resolve them to Void + + BaseTypeActivation.Set( + "", + BaseTypeActivation.Find("Void"), + ) } -// BaseValues are the values available in programs +func baseTypeVariable(name string, ty Type) *Variable { + return &Variable{ + Identifier: name, + Type: ty, + DeclarationKind: common.DeclarationKindType, + IsConstant: true, + IsBaseValue: true, + Access: ast.AccessPublic, + } +} + +// BaseValueActivation is the base activation that contains +// the values available in programs // -var BaseValues = NewStringValueDeclarationOrderedMap() +var BaseValueActivation = activations.NewActivation(nil) var AllSignedFixedPointTypes = []Type{ &Fix64Type{}, @@ -3972,32 +3994,46 @@ func init() { default: typeName := numberType.String() - // Check that the type is not accidentally redeclared + // Check that the function is not accidentally redeclared - if _, ok := BaseValues.Get(typeName); ok { + if BaseValueActivation.Find(typeName) != nil { panic(errors.NewUnreachableError()) } - BaseValues.Set(typeName, baseFunction{ - name: typeName, - invokableType: &CheckedFunctionType{ - FunctionType: &FunctionType{ - Parameters: []*Parameter{ - { - Label: ArgumentLabelNotRequired, - Identifier: "value", - TypeAnnotation: NewTypeAnnotation(&NumberType{}), + BaseValueActivation.Set( + typeName, + baseFunctionVariable( + typeName, + &CheckedFunctionType{ + FunctionType: &FunctionType{ + Parameters: []*Parameter{ + { + Label: ArgumentLabelNotRequired, + Identifier: "value", + TypeAnnotation: NewTypeAnnotation(&NumberType{}), + }, }, + ReturnTypeAnnotation: NewTypeAnnotation(numberType), }, - ReturnTypeAnnotation: NewTypeAnnotation(numberType), + ArgumentExpressionsCheck: numberFunctionArgumentExpressionsChecker(numberType), }, - ArgumentExpressionsCheck: numberFunctionArgumentExpressionsChecker(numberType), - }, - }) + ), + ) } } } +func baseFunctionVariable(name string, ty InvokableType) *Variable { + return &Variable{ + Identifier: name, + DeclarationKind: common.DeclarationKindFunction, + IsConstant: true, + IsBaseValue: true, + Type: ty, + Access: ast.AccessPublic, + } +} + func init() { // Declare a conversion function for the address type @@ -4005,38 +4041,42 @@ func init() { addressType := &AddressType{} typeName := addressType.String() - // check type is not accidentally redeclared - if _, ok := BaseValues.Get(typeName); ok { + // Check that the function is not accidentally redeclared + + if BaseValueActivation.Find(typeName) != nil { panic(errors.NewUnreachableError()) } - BaseValues.Set(typeName, baseFunction{ - name: typeName, - invokableType: &CheckedFunctionType{ - FunctionType: &FunctionType{ - Parameters: []*Parameter{ - { - Label: ArgumentLabelNotRequired, - Identifier: "value", - TypeAnnotation: NewTypeAnnotation(&IntegerType{}), + BaseValueActivation.Set( + typeName, + baseFunctionVariable( + typeName, + &CheckedFunctionType{ + FunctionType: &FunctionType{ + Parameters: []*Parameter{ + { + Label: ArgumentLabelNotRequired, + Identifier: "value", + TypeAnnotation: NewTypeAnnotation(&IntegerType{}), + }, }, + ReturnTypeAnnotation: NewTypeAnnotation(addressType), }, - ReturnTypeAnnotation: NewTypeAnnotation(addressType), - }, - ArgumentExpressionsCheck: func(checker *Checker, argumentExpressions []ast.Expression, _ ast.Range) { - if len(argumentExpressions) < 1 { - return - } + ArgumentExpressionsCheck: func(checker *Checker, argumentExpressions []ast.Expression, _ ast.Range) { + if len(argumentExpressions) < 1 { + return + } - intExpression, ok := argumentExpressions[0].(*ast.IntegerExpression) - if !ok { - return - } + intExpression, ok := argumentExpressions[0].(*ast.IntegerExpression) + if !ok { + return + } - CheckAddressLiteral(intExpression, checker.report) + CheckAddressLiteral(intExpression, checker.report) + }, }, - }, - }) + ), + ) } func numberFunctionArgumentExpressionsChecker(targetType Type) ArgumentExpressionsCheck { @@ -4177,18 +4217,22 @@ func init() { typeName := MetaType.String() - // check type is not accidentally redeclared - if _, ok := BaseValues.Get(typeName); ok { + // Check that the function is not accidentally redeclared + + if BaseValueActivation.Find(typeName) != nil { panic(errors.NewUnreachableError()) } - BaseValues.Set(typeName, baseFunction{ - name: typeName, - invokableType: &FunctionType{ - TypeParameters: []*TypeParameter{{Name: "T"}}, - ReturnTypeAnnotation: NewTypeAnnotation(MetaType), - }, - }) + BaseValueActivation.Set( + typeName, + baseFunctionVariable( + typeName, + &FunctionType{ + TypeParameters: []*TypeParameter{{Name: "T"}}, + ReturnTypeAnnotation: NewTypeAnnotation(MetaType), + }, + ), + ) } // CompositeType diff --git a/runtime/sema/variable_activations.go b/runtime/sema/variable_activations.go index 5728c06862..6e6e34c538 100644 --- a/runtime/sema/variable_activations.go +++ b/runtime/sema/variable_activations.go @@ -28,9 +28,9 @@ type VariableActivations struct { activations *activations.Activations } -func NewValueActivations() *VariableActivations { +func NewValueActivations(parent *activations.Activation) *VariableActivations { valueActivations := &activations.Activations{} - valueActivations.PushNewWithParent(nil) + valueActivations.PushNewWithParent(parent) return &VariableActivations{ activations: valueActivations, } @@ -158,7 +158,7 @@ func (a *VariableActivations) DeclareImplicitConstant( func (a *VariableActivations) ForEachVariablesDeclaredInAndBelow(depth int, f func(name string, value *Variable)) { - activation := a.activations.Current() + activation := a.Current() _ = activation.ForEach(func(name string, value interface{}) error { variable := value.(*Variable) @@ -170,3 +170,7 @@ func (a *VariableActivations) ForEachVariablesDeclaredInAndBelow(depth int, f fu return nil }) } + +func (a *VariableActivations) Current() *activations.Activation { + return a.activations.Current() +}