From d399b681a4d307fa5a09dd15c8cf96adeccb6db4 Mon Sep 17 00:00:00 2001 From: Andrew Wilkins Date: Thu, 26 Jul 2012 11:47:46 -0700 Subject: [PATCH] exp/types: process ast.Fun in checkObj; fix variadic function building Fixed creation of Func's, taking IsVariadic from parameter list rather than results. Updated checkObj to process ast.Fun objects. R=gri CC=golang-dev https://golang.org/cl/6402046 --- src/pkg/exp/types/check.go | 20 ++++++++-- src/pkg/exp/types/types_test.go | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/pkg/exp/types/types_test.go diff --git a/src/pkg/exp/types/check.go b/src/pkg/exp/types/check.go index ae0beb4e9b0..aebabd6421b 100644 --- a/src/pkg/exp/types/check.go +++ b/src/pkg/exp/types/check.go @@ -158,8 +158,8 @@ func (c *checker) makeType(x ast.Expr, cycleOk bool) (typ Type) { return &Struct{Fields: fields, Tags: tags} case *ast.FuncType: - params, _, _ := c.collectFields(token.FUNC, t.Params, true) - results, _, isVariadic := c.collectFields(token.FUNC, t.Results, true) + params, _, isVariadic := c.collectFields(token.FUNC, t.Params, true) + results, _, _ := c.collectFields(token.FUNC, t.Results, true) return &Func{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic} case *ast.InterfaceType: @@ -200,7 +200,21 @@ func (c *checker) checkObj(obj *ast.Object, ref bool) { // TODO(gri) complete this case ast.Fun: - // TODO(gri) complete this + fdecl := obj.Decl.(*ast.FuncDecl) + ftyp := c.makeType(fdecl.Type, ref).(*Func) + obj.Type = ftyp + if fdecl.Recv != nil { + recvField := fdecl.Recv.List[0] + if len(recvField.Names) > 0 { + ftyp.Recv = recvField.Names[0].Obj + } else { + ftyp.Recv = ast.NewObj(ast.Var, "_") + ftyp.Recv.Decl = recvField + } + c.checkObj(ftyp.Recv, ref) + // TODO(axw) add method to a list in the receiver type. + } + // TODO(axw) check function body, if non-nil. default: panic("unreachable") diff --git a/src/pkg/exp/types/types_test.go b/src/pkg/exp/types/types_test.go new file mode 100644 index 00000000000..feb39485531 --- /dev/null +++ b/src/pkg/exp/types/types_test.go @@ -0,0 +1,67 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests verifying the types associated with an AST after +// type checking. + +package types + +import ( + "go/ast" + "go/parser" + "testing" +) + +func checkSource(t *testing.T, src string) *ast.Package { + const filename = "" + file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors) + if err != nil { + t.Fatal(err) + } + files := map[string]*ast.File{filename: file} + pkg, err := ast.NewPackage(fset, files, GcImport, Universe) + if err != nil { + t.Fatal(err) + } + _, err = Check(fset, pkg) + if err != nil { + t.Fatal(err) + } + return pkg +} + +func TestVariadicFunctions(t *testing.T) { + pkg := checkSource(t, ` +package p +func f1(arg ...int) +func f2(arg1 string, arg2 ...int) +func f3() +func f4(arg int) + `) + f1 := pkg.Scope.Lookup("f1") + f2 := pkg.Scope.Lookup("f2") + for _, f := range [...](*ast.Object){f1, f2} { + ftype := f.Type.(*Func) + if !ftype.IsVariadic { + t.Errorf("expected %s to be variadic", f.Name) + } + param := ftype.Params[len(ftype.Params)-1] + if param.Type != Int { + t.Errorf("expected last parameter of %s to have type int, found %T", f.Name, param.Type) + } + } + + f3 := pkg.Scope.Lookup("f3") + f4 := pkg.Scope.Lookup("f4") + for _, f := range [...](*ast.Object){f3, f4} { + ftype := f.Type.(*Func) + if ftype.IsVariadic { + t.Fatalf("expected %s to not be variadic", f.Name) + } + } + // TODO(axw) replace this function's innards with table driven tests. + // We should have a helper function that prints a type signature. Then + // we can have a table of function declarations and expected type + // signatures which can be easily expanded. +}