Creater a binder.Context structure

This change introduces a binder.Context structure, with a
*core.Context embedded, that carries additional semantic information
forward to future passes in the compiler.  In particular, this is how
the evaluation/interpretation phase will gain access to types, scopes,
and symbols.
This commit is contained in:
joeduffy 2017-01-24 10:29:37 -08:00
parent f3c69b671a
commit c5aea187c2
7 changed files with 191 additions and 167 deletions

View file

@ -22,47 +22,32 @@ import (
type Binder interface {
core.Phase
// BindCtx represents the contextual information resulting from binding.
BindCtx() *Context
// BindPackages takes a package AST, resolves all dependencies and tokens inside of it, and returns a fully bound
// package symbol that can be used for semantic operations (like interpretation and evaluation).
BindPackage(pkg *pack.Package) *symbols.Package
}
// TypeMap maps AST nodes to their corresponding type. The semantics of this differ based on the kind of node. For
// example, an ast.Expression's type is the type of its evaluation; an ast.LocalVariable's type is the bound type of its
// value. And so on. This is used during binding, type checking, and evaluation, to perform type-sensitive operations.
// This avoids needing to recreate scopes and/or storing type information on every single node in the AST.
type TypeMap map[ast.Node]symbols.Type
// New allocates a fresh binder object with the given workspace, context, and metadata reader.
func New(w workspace.W, ctx *core.Context, reader metadata.Reader) Binder {
// Create a new binder and a new scope with an empty symbol table.
b := &binder{
// Create a new binder with a fresh binding context.
return &binder{
w: w,
ctx: ctx,
ctx: NewContextFrom(ctx),
reader: reader,
types: make(TypeMap),
}
// Create a global scope and populate it with all of the predefined type names. This one's never popped.
NewScope(ctx, &b.scope)
for _, prim := range types.Primitives {
b.scope.MustRegister(prim)
}
return b
}
type binder struct {
w workspace.W // a workspace in which this compilation is happening.
ctx *core.Context // a context shared across all phases of compilation.
ctx *Context // a binding context shared with future phases of compilation.
reader metadata.Reader // a metadata reader (in case we encounter package references).
scope *Scope // the current (mutable) scope.
types TypeMap // the typechecked types for expressions (see TypeMap's comments above).
}
func (b *binder) Diag() diag.Sink {
return b.ctx.Diag
}
func (b *binder) BindCtx() *Context { return b.ctx }
func (b *binder) Diag() diag.Sink { return b.ctx.Diag }
// bindType binds a type token AST node to a symbol.
func (b *binder) bindType(node *ast.TypeToken) symbols.Type {
@ -261,7 +246,7 @@ func (b *binder) requireToken(node ast.Node, tok tokens.Token) symbols.Symbol {
}
} else {
// A simple token has no package, module, or class part. It refers to the symbol table.
if sym := b.scope.Lookup(tok); sym != nil {
if sym := b.ctx.Scope.Lookup(tok); sym != nil {
return sym
} else {
b.Diag().Errorf(errors.ErrorSymbolNotFound.At(node), tok, "simple name not found")
@ -283,101 +268,3 @@ func (b *binder) requireClassMember(node ast.Node, class symbols.Type, tok token
}
return nil
}
// requireType requires that a type exists for the given AST node.
func (b *binder) requireType(node ast.Node) symbols.Type {
ty := b.types[node]
contract.Assertf(ty != nil, "Expected a typemap entry for %v node", node.GetKind())
return ty
}
// requireExprType fetches an expression's non-nil type.
func (b *binder) requireExprType(node ast.Expression) symbols.Type {
return b.requireType(node)
}
// registerExprType registers an expression's type.
func (b *binder) registerExprType(node ast.Expression, tysym symbols.Type) {
contract.Require(tysym != nil, "tysym")
contract.Assert(b.types[node] == nil)
if glog.V(7) {
glog.V(7).Infof("Registered expression type: '%v' => %v", node.GetKind(), tysym.Name())
}
b.types[node] = tysym
}
// requireFunctionType fetches the non-nil registered type for a given function.
func (b *binder) requireFunctionType(node ast.Function) *symbols.FunctionType {
ty := b.requireType(node)
fty, ok := ty.(*symbols.FunctionType)
contract.Assertf(ok, "Expected function type for %v; got %v", node.GetKind(), fty.Token())
return fty
}
// registerFunctionType understands how to turn any function node into a type, and adds it to the type table. This
// works for any kind of function-like AST node: module property, class property, or lambda.
func (b *binder) registerFunctionType(node ast.Function) *symbols.FunctionType {
// Make a function type and inject it into the type table.
var params []symbols.Type
np := node.GetParameters()
if np != nil {
for _, param := range *np {
var ptysym symbols.Type
// If there was an explicit type, look it up.
if param.Type != nil {
ptysym = b.scope.LookupType(param.Type.Tok)
}
// If either the parameter's type was unknown, or the lookup failed (leaving an error), use the any type.
if ptysym == nil {
ptysym = types.Any
}
params = append(params, ptysym)
}
}
var ret symbols.Type
nr := node.GetReturnType()
if nr != nil {
ret = b.scope.LookupType(nr.Tok)
}
tysym := symbols.NewFunctionType(params, ret)
if glog.V(7) {
glog.V(7).Infof("Registered function type: '%v' => %v", node.GetName().Ident, tysym.Name())
}
b.types[node] = tysym
return tysym
}
// requireVariableType fetches the non-nil registered type for a given variable.
func (b *binder) requireVariableType(node ast.Variable) symbols.Type {
return b.requireType(node)
}
// registerVariableType understands how to turn any variable node into a type, and adds it to the type table. This
// works for any kind of variable-like AST node: module property, class property, parameter, or local variable.
func (b *binder) registerVariableType(node ast.Variable) symbols.Type {
var tysym symbols.Type
// If there is an explicit node type, use it.
nt := node.GetType()
if nt != nil {
tysym = b.scope.LookupType(nt.Tok)
}
// Otherwise, either there was no type, or the lookup failed (leaving behind an error); use the any type.
if tysym == nil {
tysym = types.Any
}
if glog.V(7) {
glog.V(7).Infof("Registered variable type: '%v' => %v", node.GetName().Ident, tysym.Name())
}
b.types[node] = tysym
return tysym
}

View file

@ -16,12 +16,12 @@ func (b *binder) bindClass(node *ast.Class, parent *symbols.Module) *symbols.Cla
// Bind base type tokens to actual symbols.
var extends symbols.Type
if node.Extends != nil {
extends = b.scope.LookupType(node.Extends.Tok)
extends = b.ctx.Scope.LookupType(node.Extends.Tok)
}
var implements symbols.Types
if node.Implements != nil {
for _, impltok := range *node.Implements {
if impl := b.scope.LookupType(impltok.Tok); impl != nil {
if impl := b.ctx.Scope.LookupType(impltok.Tok); impl != nil {
implements = append(implements, impl)
}
}
@ -61,7 +61,7 @@ func (b *binder) bindClassProperty(node *ast.ClassProperty, parent *symbols.Clas
glog.V(3).Infof("Binding class '%v' property '%v'", parent.Name(), node.Name.Ident)
// Look up this node's type and inject it into the type table.
ty := b.registerVariableType(node)
ty := b.ctx.RegisterVariableType(node)
return symbols.NewClassPropertySym(node, parent, ty)
}
@ -69,7 +69,7 @@ func (b *binder) bindClassMethod(node *ast.ClassMethod, parent *symbols.Class) *
glog.V(3).Infof("Binding class '%v' method '%v'", parent.Name(), node.Name.Ident)
// Make a function type out of this method and inject it into the type table.
ty := b.registerFunctionType(node)
ty := b.ctx.RegisterFunctionType(node)
// Note that we don't actually bind the body of this method yet. Until we have gone ahead and injected *all*
// top-level symbols into the type table, we would potentially encounter missing intra-module symbols.

View file

@ -0,0 +1,139 @@
// Copyright 2016 Marapongo, Inc. All rights reserved.
package binder
import (
"github.com/golang/glog"
"github.com/marapongo/mu/pkg/compiler/ast"
"github.com/marapongo/mu/pkg/compiler/core"
"github.com/marapongo/mu/pkg/compiler/symbols"
"github.com/marapongo/mu/pkg/compiler/types"
"github.com/marapongo/mu/pkg/util/contract"
)
// Context holds binder-specific context information, like symbol and type binding information.
type Context struct {
*core.Context // inherits all of the other context info.
Scope *Scope // the current (mutable) scope.
Types TypeMap // the type-checked type symbols for expressions.
}
func NewContextFrom(ctx *core.Context) *Context {
bctx := &Context{
Context: ctx,
Types: make(TypeMap),
}
// Create a global scope and populate it with all of the predefined type names. This one's never popped.
NewScope(ctx, &bctx.Scope)
for _, prim := range types.Primitives {
bctx.Scope.MustRegister(prim)
}
return bctx
}
// TypeMap maps AST nodes to their corresponding type. The semantics of this differ based on the kind of node. For
// example, an ast.Expression's type is the type of its evaluation; an ast.LocalVariable's type is the bound type of its
// value. And so on. This is used during binding, type checking, and evaluation, to perform type-sensitive operations.
// This avoids needing to recreate scopes and/or storing type information on every single node in the AST.
type TypeMap map[ast.Node]symbols.Type
// RequireType requires that a type exists for the given AST node.
func (ctx *Context) RequireType(node ast.Node) symbols.Type {
ty := ctx.Types[node]
contract.Assertf(ty != nil, "Expected a typemap entry for %v node", node.GetKind())
return ty
}
// RequireExprType fetches an expression's non-nil type.
func (ctx *Context) RequireExprType(node ast.Expression) symbols.Type {
return ctx.RequireType(node)
}
// RegisterExprType registers an expression's type.
func (ctx *Context) RegisterExprType(node ast.Expression, tysym symbols.Type) {
contract.Require(tysym != nil, "tysym")
contract.Assert(ctx.Types[node] == nil)
if glog.V(7) {
glog.V(7).Infof("Registered expression type: '%v' => %v", node.GetKind(), tysym.Name())
}
ctx.Types[node] = tysym
}
// RequireFunctionType fetches the non-nil registered type for a given function.
func (ctx *Context) RequireFunctionType(node ast.Function) *symbols.FunctionType {
ty := ctx.RequireType(node)
fty, ok := ty.(*symbols.FunctionType)
contract.Assertf(ok, "Expected function type for %v; got %v", node.GetKind(), fty.Token())
return fty
}
// RegisterFunctionType understands how to turn any function node into a type, and adds it to the type table. This
// works for any kind of function-like AST node: module property, class property, or lambda.
func (ctx *Context) RegisterFunctionType(node ast.Function) *symbols.FunctionType {
// Make a function type and inject it into the type table.
var params []symbols.Type
np := node.GetParameters()
if np != nil {
for _, param := range *np {
var ptysym symbols.Type
// If there was an explicit type, look it up.
if param.Type != nil {
ptysym = ctx.Scope.LookupType(param.Type.Tok)
}
// If either the parameter's type was unknown, or the lookup failed (leaving an error), use the any type.
if ptysym == nil {
ptysym = types.Any
}
params = append(params, ptysym)
}
}
var ret symbols.Type
nr := node.GetReturnType()
if nr != nil {
ret = ctx.Scope.LookupType(nr.Tok)
}
tysym := symbols.NewFunctionType(params, ret)
if glog.V(7) {
glog.V(7).Infof("Registered function type: '%v' => %v", node.GetName().Ident, tysym.Name())
}
ctx.Types[node] = tysym
return tysym
}
// RequireVariableType fetches the non-nil registered type for a given variable.
func (ctx *Context) RequireVariableType(node ast.Variable) symbols.Type {
return ctx.RequireType(node)
}
// RegisterVariableType understands how to turn any variable node into a type, and adds it to the type table. This
// works for any kind of variable-like AST node: module property, class property, parameter, or local variable.
func (ctx *Context) RegisterVariableType(node ast.Variable) symbols.Type {
var tysym symbols.Type
// If there is an explicit node type, use it.
nt := node.GetType()
if nt != nil {
tysym = ctx.Scope.LookupType(nt.Tok)
}
// Otherwise, either there was no type, or the lookup failed (leaving behind an error); use the any type.
if tysym == nil {
tysym = types.Any
}
if glog.V(7) {
glog.V(7).Infof("Registered variable type: '%v' => %v", node.GetName().Ident, tysym.Name())
}
ctx.Types[node] = tysym
return tysym
}

View file

@ -10,14 +10,14 @@ import (
// bindFunctionBody binds a function body, including a scope, its parameters, and its expressions and statements.
func (b *binder) bindFunctionBody(node ast.Function) {
// Enter a new scope, bind the parameters, and then bind the body using a visitor.
scope := b.scope.Push()
scope := b.ctx.Scope.Push()
defer scope.Pop()
params := node.GetParameters()
if params != nil {
for _, param := range *params {
// Register this variable's type and associate its name with the identifier.
b.registerVariableType(param)
b.scope.TryRegister(param, symbols.NewLocalVariableSym(param))
b.ctx.RegisterVariableType(param)
b.ctx.Scope.TryRegister(param, symbols.NewLocalVariableSym(param))
}
}

View file

@ -71,37 +71,37 @@ func (b *binder) ValidateStack(stack *ast.Stack) {
// LookupService binds a name to a Service type.
func (b *binder) LookupService(nm tokens.Name) (*ast.Service, bool) {
contract.Assertf(b.scope != nil, "Unexpected empty binding scope during LookupService")
contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during LookupService")
return nil, false
}
// LookupStack binds a name to a Stack type.
func (b *binder) LookupStack(nm tokens.PackageName) (*ast.Stack, bool) {
contract.Assertf(b.scope != nil, "Unexpected empty binding scope during LookupStack")
contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during LookupStack")
return nil, false
}
// LookupUninstStack binds a name to a UninstStack type.
func (b *binder) LookupUninstStack(nm tokens.PackageName) (*ast.UninstStack, bool) {
contract.Assertf(b.scope != nil, "Unexpected empty binding scope during LookupUninstStack")
contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during LookupUninstStack")
return nil, false
}
// LookupSchema binds a name to a Schema type.
func (b *binder) LookupSchema(nm tokens.PackageName) (*ast.Schema, bool) {
contract.Assertf(b.scope != nil, "Unexpected empty binding scope during LookupSchema")
contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during LookupSchema")
return nil, false
}
// LookupSymbol binds a name to any kind of Symbol.
func (b *binder) LookupSymbol(nm tokens.Name) (*legacy.Symbol, bool) {
contract.Assertf(b.scope != nil, "Unexpected empty binding scope during LookupSymbol")
contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during LookupSymbol")
return nil, false
}
// RegisterSymbol registers a symbol with the given name; if it already exists, the function returns false.
func (b *binder) RegisterSymbol(sym *legacy.Symbol) bool {
contract.Assertf(b.scope != nil, "Unexpected empty binding scope during RegisterSymbol")
contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during RegisterSymbol")
return false
}
@ -150,7 +150,6 @@ func (p *binderPreparePhase) VisitStack(stack *ast.Stack) {
// Stack names are required.
if stack.Name == "" {
p.Diag().Errorf(errors.ErrorMissingStackName.At(stack))
}
// Stack versions must be valid semantic versions (and specifically, not ranges). In other words, we need
@ -348,7 +347,6 @@ func (p *binderBindPhase) VisitService(pstack *ast.Stack, parent *ast.Services,
// A service cannot instantiate an abstract stack.
if svc.BoundType != nil && svc.BoundType.Abstract {
p.Diag().Errorf(errors.ErrorCannotCreateAbstractStack.At(pstack), svc.Name, svc.BoundType.Name)
}
}

View file

@ -24,7 +24,7 @@ func (b *binder) bindModule(node *ast.Module, parent *symbols.Package) *symbols.
// First bind all imports to concrete symbols. These will be used to perform initialization later on.
if node.Imports != nil {
for _, imptok := range *node.Imports {
if imp := b.scope.LookupModule(imptok.Tok); imp != nil {
if imp := b.ctx.Scope.LookupModule(imptok.Tok); imp != nil {
module.Imports = append(module.Imports, imp)
}
}
@ -62,7 +62,7 @@ func (b *binder) bindExport(node *ast.Export, parent *symbols.Module) *symbols.E
glog.V(3).Infof("Binding module '%v' export '%v'", parent.Name(), node.Name.Ident)
// To bind an export, simply look up the referent symbol and associate this name with it.
refsym := b.scope.Lookup(node.Referent.Tok)
refsym := b.ctx.Scope.Lookup(node.Referent.Tok)
if refsym == nil {
// TODO: issue a verification error; name not found! Also sub in a "bad" symbol.
contract.Failf("Export name not found: %v", node.Referent)
@ -74,7 +74,7 @@ func (b *binder) bindModuleProperty(node *ast.ModuleProperty, parent *symbols.Mo
glog.V(3).Infof("Binding module '%v' property '%v'", parent.Name(), node.Name.Ident)
// Look up this node's type and inject it into the type table.
ty := b.registerVariableType(node)
ty := b.ctx.RegisterVariableType(node)
return symbols.NewModulePropertySym(node, parent, ty)
}
@ -82,7 +82,7 @@ func (b *binder) bindModuleMethod(node *ast.ModuleMethod, parent *symbols.Module
glog.V(3).Infof("Binding module '%v' method '%v'", parent.Name(), node.Name.Ident)
// Make a function type out of this method and inject it into the type table.
ty := b.registerFunctionType(node)
ty := b.ctx.RegisterFunctionType(node)
// Note that we don't actually bind the body of this method yet. Until we have gone ahead and injected *all*
// top-level symbols into the type table, we would potentially encounter missing intra-module symbols.

View file

@ -65,13 +65,13 @@ func (a *astBinder) After(node ast.Node) {
// Expressions
case *ast.NullLiteral:
a.b.registerExprType(n, types.Null) // register a null type.
a.b.ctx.RegisterExprType(n, types.Null) // register a null type.
case *ast.BoolLiteral:
a.b.registerExprType(n, types.Bool) // register a bool type.
a.b.ctx.RegisterExprType(n, types.Bool) // register a bool type.
case *ast.NumberLiteral:
a.b.registerExprType(n, types.Number) // register as a number type.
a.b.ctx.RegisterExprType(n, types.Number) // register as a number type.
case *ast.StringLiteral:
a.b.registerExprType(n, types.String) // register as a string type.
a.b.ctx.RegisterExprType(n, types.String) // register as a string type.
case *ast.ArrayLiteral:
a.checkArrayLiteral(n)
case *ast.ObjectLiteral:
@ -79,7 +79,7 @@ func (a *astBinder) After(node ast.Node) {
case *ast.LoadLocationExpression:
a.checkLoadLocationExpression(n)
case *ast.LoadDynamicExpression:
a.b.registerExprType(n, types.Any) // register as an any type.
a.b.ctx.RegisterExprType(n, types.Any) // register as an any type.
case *ast.NewExpression:
a.checkNewExpression(n)
case *ast.InvokeFunctionExpression:
@ -102,19 +102,19 @@ func (a *astBinder) After(node ast.Node) {
// Ensure that all expression types resulted in a type registration.
expr, isExpr := node.(ast.Expression)
contract.Assert(!isExpr || a.b.requireExprType(expr) != nil)
contract.Assert(!isExpr || a.b.ctx.RequireExprType(expr) != nil)
}
// Statements
func (a *astBinder) visitBlock(node *ast.Block) {
// Entering a new block requires a fresh lexical scope.
a.b.scope.Push()
a.b.ctx.Scope.Push()
}
func (a *astBinder) checkBlock(node *ast.Block) {
// Exiting a block restores the prior lexical context.
a.b.scope.Pop()
a.b.ctx.Scope.Pop()
}
func (a *astBinder) checkBreakStatement(node *ast.BreakStatement) {
@ -144,8 +144,8 @@ func (a *astBinder) checkIfStatement(node *ast.IfStatement) {
func (a *astBinder) visitLocalVariable(node *ast.LocalVariable) {
// Encountering a new local variable results in registering it; both to the type and symbol table.
a.b.registerVariableType(node)
a.b.scope.TryRegister(node, symbols.NewLocalVariableSym(node))
a.b.ctx.RegisterVariableType(node)
a.b.ctx.Scope.TryRegister(node, symbols.NewLocalVariableSym(node))
}
func (a *astBinder) visitLabeledStatement(node *ast.LabeledStatement) {
@ -159,7 +159,7 @@ func (a *astBinder) visitLabeledStatement(node *ast.LabeledStatement) {
func (a *astBinder) checkReturnStatement(node *ast.ReturnStatement) {
// Ensure that the return expression is correct (present or missing; and its type).
fncty := a.b.requireFunctionType(a.fnc)
fncty := a.b.ctx.RequireFunctionType(a.fnc)
if fncty.Return == nil {
if node.Expression != nil {
// The function has no return type ("void"), and yet the return had an expression.
@ -188,7 +188,7 @@ func (a *astBinder) checkWhileStatement(node *ast.WhileStatement) {
// Expressions
func (a *astBinder) checkExprType(expr ast.Expression, expect symbols.Type) bool {
actual := a.b.requireExprType(expr)
actual := a.b.ctx.RequireExprType(expr)
if !types.CanConvert(actual, expect) {
a.b.Diag().Errorf(errors.ErrorIncorrectExprType.At(expr), expect, actual)
return false
@ -203,10 +203,10 @@ func (a *astBinder) checkArrayLiteral(node *ast.ArrayLiteral) {
}
// Now mark the resulting expression as an array of the right type.
if node.ElemType == nil {
a.b.registerExprType(node, types.AnyArray)
a.b.ctx.RegisterExprType(node, types.AnyArray)
} else {
elemType := a.b.bindType(node.ElemType)
a.b.registerExprType(node, symbols.NewArrayType(elemType))
a.b.ctx.RegisterExprType(node, symbols.NewArrayType(elemType))
// Ensure the elements, if any, are of the right type.
if node.Elements != nil {
@ -220,10 +220,10 @@ func (a *astBinder) checkArrayLiteral(node *ast.ArrayLiteral) {
func (a *astBinder) checkObjectLiteral(node *ast.ObjectLiteral) {
// Mark the resulting object literal with the correct type.
if node.Type == nil {
a.b.registerExprType(node, types.Any)
a.b.ctx.RegisterExprType(node, types.Any)
} else {
ty := a.b.bindType(node.Type)
a.b.registerExprType(node, ty)
a.b.ctx.RegisterExprType(node, ty)
// Only permit object literals for records and interfaces. Classes have constructors.
if !ty.Record() && !ty.Interface() {
@ -268,7 +268,7 @@ func (a *astBinder) checkLoadLocationExpression(node *ast.LoadLocationExpression
sym = a.b.requireToken(node.Name, node.Name.Tok)
} else {
// If there's an object, we are accessing a class member property or function.
typ := a.b.requireExprType(*node.Object)
typ := a.b.ctx.RequireExprType(*node.Object)
sym = a.b.requireClassMember(node.Name, typ, tokens.ClassMember(node.Name.Tok))
}
@ -279,16 +279,16 @@ func (a *astBinder) checkLoadLocationExpression(node *ast.LoadLocationExpression
} else {
switch s := sym.(type) {
case ast.Function:
ty = a.b.requireFunctionType(s)
ty = a.b.ctx.RequireFunctionType(s)
case ast.Variable:
ty = a.b.requireVariableType(s)
ty = a.b.ctx.RequireVariableType(s)
default:
contract.Failf("Unrecognized load location symbol type: %v", sym.Token())
}
}
// Register a pointer type so that this expression is a valid l-expr.
a.b.registerExprType(node, symbols.NewPointerType(ty))
a.b.ctx.RegisterExprType(node, symbols.NewPointerType(ty))
}
func (a *astBinder) checkNewExpression(node *ast.NewExpression) {
@ -306,7 +306,7 @@ func (a *astBinder) checkNewExpression(node *ast.NewExpression) {
}
}
a.b.registerExprType(node, ty)
a.b.ctx.RegisterExprType(node, ty)
}
func (a *astBinder) checkInvokeFunctionExpression(node *ast.InvokeFunctionExpression) {
@ -319,14 +319,14 @@ func (a *astBinder) checkLambdaExpression(node *ast.LambdaExpression) {
var params []symbols.Type
if pparams := node.GetParameters(); pparams != nil {
for _, param := range *pparams {
params = append(params, a.b.requireVariableType(param))
params = append(params, a.b.ctx.RequireVariableType(param))
}
}
var ret symbols.Type
if pret := node.GetReturnType(); pret != nil {
ret = a.b.bindType(pret)
}
a.b.registerExprType(node, symbols.NewFunctionType(params, ret))
a.b.ctx.RegisterExprType(node, symbols.NewFunctionType(params, ret))
}
func (a *astBinder) checkUnaryOperatorExpression(node *ast.UnaryOperatorExpression) {
@ -341,7 +341,7 @@ func (a *astBinder) checkBinaryOperatorExpression(node *ast.BinaryOperatorExpres
func (a *astBinder) checkCastExpression(node *ast.CastExpression) {
// TODO: validate that this is legal.
a.b.registerExprType(node, a.b.bindType(node.Type))
a.b.ctx.RegisterExprType(node, a.b.bindType(node.Type))
}
func (a *astBinder) checkTypeOfExpression(node *ast.TypeOfExpression) {
@ -355,5 +355,5 @@ func (a *astBinder) checkConditionalExpression(node *ast.ConditionalExpression)
func (a *astBinder) checkSequenceExpression(node *ast.SequenceExpression) {
// The type of a sequence expression is just the type of the last expression in the sequence.
// TODO: check that there's at least one!
a.b.registerExprType(node, a.b.requireExprType(node.Expressions[len(node.Expressions)-1]))
a.b.ctx.RegisterExprType(node, a.b.ctx.RequireExprType(node.Expressions[len(node.Expressions)-1]))
}