├── LICENSE ├── README.md ├── example_test.go ├── operators.go ├── replace.go └── types ├── api.go ├── api_test.go ├── assignments.go ├── builtins.go ├── builtins_test.go ├── call.go ├── check.go ├── check_test.go ├── conversions.go ├── errors.go ├── eval.go ├── eval_test.go ├── exportdata.go ├── expr.go ├── gcimporter.go ├── gcimporter_test.go ├── go11.go ├── go12.go ├── issues_test.go ├── labels.go ├── lookup.go ├── methodset.go ├── objects.go ├── objset.go ├── operand.go ├── overload.go ├── package.go ├── predicates.go ├── resolver.go ├── resolver_test.go ├── return.go ├── scope.go ├── selection.go ├── self_test.go ├── sizes.go ├── stdlib_test.go ├── stmt.go ├── testdata ├── builtins.src ├── const0.src ├── const1.src ├── constdecl.src ├── conversions.src ├── cycles.src ├── decls0.src ├── decls1.src ├── decls2a.src ├── decls2b.src ├── decls3.src ├── errors.src ├── exports.go ├── expr0.src ├── expr1.src ├── expr2.src ├── expr3.src ├── gotos.src ├── importdecl0a.src ├── importdecl0b.src ├── labels.src ├── methodsets.src ├── shifts.src ├── stmt0.src ├── stmt1.src └── vardecl.src ├── token_test.go ├── typemap ├── typemap.go └── typemap_test.go ├── types.go ├── types_test.go ├── typexpr.go └── universe.go /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Disclaimer: **This is a hack!** 2 | 3 | This project is an attempt to add operator overloading to the Go language. There 4 | are very good reasons why Go doesn't support operator overloading as part of 5 | the language and I fully support and agree with those reasons. 6 | 7 | That being said, there are a few valid cases where it makes sense to have 8 | operators defined for types other than the builtin types. One such valid 9 | case, in my opinion, is for numeric types such as vectors or matrices. Of course, 10 | Go was never designed for writing numeric heavy programs, so you could just 11 | argue that Go is simply not the right tool for the job. Although I wouldn't 12 | disagree with this, I still find Go an exceptionally enjoyable language and 13 | recently I really wanted to write some vector-ish code. 14 | 15 | go-operators allows you to add support for all Go operators to any custom 16 | defined type, by adding appropriate methods on that type. The way this works is 17 | that go-operators is a kind of preprocessor for your Go code which will parse 18 | and rewrite your original source to map operators, on types which do not natively 19 | support operators, to method calls on the operand(s) of the operator. 20 | 21 | First, the original source is converted to an AST by using the builtin go/ast package. 22 | Then, a patched version of go/types (available in go.tools) steps through the 23 | AST and resolves the types of all the expressions in the AST. When an operator 24 | is encountered which operators on non-numeric types, a method lookup is 25 | performed on the first operand type. If the appropriate operator overloading 26 | method can be found (with the correct operands type and return type), then the 27 | AST node representing the operator is replaced with a method call. For binary 28 | operators, if the first operand does not have an appropriate overloaded method, 29 | the second operator is tested for a Pre- overload method. This way you can 30 | overload both `v * 5.0` and `5.0 * v` (for example) on the type of `v`. 31 | 32 | # Using go-operators 33 | To use go-operators you will have to define special methods on your custom type. 34 | These methods are prefixed with `Op_Multiply`, `Op_Add`, `Op_Subtract` etc., 35 | depending on the operator to overload. Any method which has such a prefix is 36 | a potential candidate. Thus, if your type supports operators on various operand 37 | types, then you can add methods such as `Op_MultiplyVec3`, `Op_MultiplyMat3`, 38 | etc. with the appropriate argument types. The return type of the method can be 39 | anything, but there must be extactly one return value. For overloaded binary 40 | operators there must be exactly one argument while for overloaded unary operators 41 | there must be exactly zero arguments. 42 | 43 | The `go-operators` tool uses a set of conventions to parse and process files 44 | for which to replace operators. Each file which needs to be processed should have 45 | the `.op.go` suffix. Furthermore, these files should have the `operators` build 46 | constraint (`// +build operators`). `go-operators` parses these files and 47 | generates a corresponding `.go` file (stripping the `.op.go` suffix) in the 48 | same directory, adding the `!operators` build constraint to avoid conflicts. 49 | You run `go-operators` with the import paths of the packages you want to process. 50 | These packages are obtained from `$GOPATH/src`. 51 | 52 | # List of overloaded operators 53 | 54 | | Operator | Method Prefix | 55 | |----------|---------------| 56 | | a + b | Op_Add | 57 | | a - b | Op_Subtract | 58 | | a * b | Op_Multiply | 59 | | a / b | Op_Divide | 60 | | a % b | Op_Modulo | 61 | | a & b | Op_BitAnd | 62 | | a | b | Op_BitOr | 63 | | a << b | Op_BitShiftLeft | 64 | | a >> b | Op_BitShiftRight | 65 | | a &^ b | Op_BitAndNot | 66 | | a ^ b | Op_BitXor | 67 | | a && b | Op_And | 68 | | a || b | Op_Or | 69 | | a < b | Op_Less | 70 | | a > b | Op_Greater | 71 | | a <= b | Op_LessOrEqual | 72 | | a >= b | Op_GreaterOrEqual | 73 | | -a | Op_Minus | 74 | | +a | Op_Add | 75 | | !a | Op_Not | 76 | 77 | Binary operator methods should have one argument and unary operator methods should have zero arguments. 78 | To support pre-operator methods (i.e. methods defined on `b` instead of `a`), then you can add the 79 | same method but prefixed with `Op_Pre` instead of just `Op_`. Note that the prefixes for binary 80 | and unary methods is the same and they are differentiated by their arguments. Therefore, to support 81 | both unary minus and binary minus (for example), you could write: 82 | 83 | ```go 84 | func (t T) Op_MinusBinary(o T) T { 85 | // ... 86 | } 87 | 88 | func (t T) Op_MinusUnary() T { 89 | // ... 90 | } 91 | 92 | ``` 93 | 94 | # Not using go-operators 95 | There is much to say for not using go-operators. I already mentioned that it's 96 | a hack, right? Using go-operators relies on a preprocessing step which, although 97 | fairly robust, is subject to bugs. The go/types project is still in development 98 | and certain constructs are bound not to be correctly parsed (yet). Additionally, 99 | using go-operators makes your project no longer go-gettable since a preprocessing 100 | step needs to be performed before the code is actually usable. 101 | 102 | # Example 103 | ```go 104 | package main 105 | 106 | import ( 107 | "fmt" 108 | ) 109 | 110 | type vec4 [4]float32 111 | 112 | func (v vec4) Op_Multiply(o vec4) vec4 { 113 | return vec4{v[0] * o[0], v[1] * o[1], v[2] * o[2], v[3] * o[3]} 114 | } 115 | 116 | func (v vec4) Op_MultiplyScalar(o float32) vec4 { 117 | return vec4{v[0] * o, v[1] * o, v[2] * o, v[3] * o} 118 | } 119 | 120 | func (v vec4) Op_PreMultiplyScalar(o float32) vec4 { 121 | return v.Op_MultiplyScalar(o) 122 | } 123 | 124 | func (v vec4) Op_Add(o vec4) vec4 { 125 | return vec4{v[0] + o[0], v[1] + o[1], v[2] + o[2], v[3] + o[3]} 126 | } 127 | 128 | func (v vec4) Op_AddScalar(o float32) vec4 { 129 | return vec4{v[0] + o, v[1] + o, v[2] + o, v[3] + o} 130 | } 131 | 132 | func (v vec4) Op_PreAddScalar(o float32) vec4 { 133 | return v.Op_AddScalar(o) 134 | } 135 | 136 | func (v vec4) Op_Subtract(o vec4) vec4 { 137 | return vec4{v[0] - o[0], v[1] - o[1], v[2] - o[2], v[3] - o[3]} 138 | } 139 | 140 | func (v vec4) Op_SubtractScalar(o float32) vec4 { 141 | return vec4{v[0] - o, v[1] - o, v[2] - o, v[3] - o} 142 | } 143 | 144 | func (v vec4) Op_PreSubtractScalar(o float32) vec4 { 145 | return vec4{o - v[0], o - v[1], o - v[2], o - v[3]} 146 | } 147 | 148 | func ExampleOverload() { 149 | v1 := vec4{1, 2, 3, 4} 150 | v2 := vec4{5, 6, 7, 8} 151 | 152 | // Generates: ret := v1.Op_PreMultiplyScalar(2).Op_Multiply(v2).Op_Add(v1).Op_SubtractScalar(4) 153 | ret := 2*v1*v2 + v1 - 4 154 | 155 | fmt.Println(ret) 156 | } 157 | ``` 158 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type vec4 [4]float32 8 | 9 | func (v vec4) Op_Multiply(o vec4) vec4 { 10 | return vec4{v[0] * o[0], v[1] * o[1], v[2] * o[2], v[3] * o[3]} 11 | } 12 | 13 | func (v vec4) Op_MultiplyScalar(o float32) vec4 { 14 | return vec4{v[0] * o, v[1] * o, v[2] * o, v[3] * o} 15 | } 16 | 17 | func (v vec4) Op_PreMultiplyScalar(o float32) vec4 { 18 | return v.Op_MultiplyScalar(o) 19 | } 20 | 21 | func (v vec4) Op_Add(o vec4) vec4 { 22 | return vec4{v[0] + o[0], v[1] + o[1], v[2] + o[2], v[3] + o[3]} 23 | } 24 | 25 | func (v vec4) Op_AddScalar(o float32) vec4 { 26 | return vec4{v[0] + o, v[1] + o, v[2] + o, v[3] + o} 27 | } 28 | 29 | func (v vec4) Op_PreAddScalar(o float32) vec4 { 30 | return v.Op_AddScalar(o) 31 | } 32 | 33 | func (v vec4) Op_Subtract(o vec4) vec4 { 34 | return vec4{v[0] - o[0], v[1] - o[1], v[2] - o[2], v[3] - o[3]} 35 | } 36 | 37 | func (v vec4) Op_SubtractScalar(o float32) vec4 { 38 | return vec4{v[0] - o, v[1] - o, v[2] - o, v[3] - o} 39 | } 40 | 41 | func (v vec4) Op_PreSubtractScalar(o float32) vec4 { 42 | return vec4{o - v[0], o - v[1], o - v[2], o - v[3]} 43 | } 44 | 45 | func ExampleOverload() { 46 | v1 := vec4{1, 2, 3, 4} 47 | v2 := vec4{5, 6, 7, 8} 48 | 49 | // Generates: ret := v1.Op_PreMultiplyScalar(2).Op_Multiply(v2).Op_Add(v1).Op_SubtractScalar(4) 50 | ret := 2*v1*v2 + v1 - 4 51 | 52 | fmt.Println(ret) 53 | } 54 | -------------------------------------------------------------------------------- /operators.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/jessevdk/go-flags" 6 | "github.com/jessevdk/go-operators/types" 7 | "go/ast" 8 | "go/build" 9 | "go/format" 10 | "go/parser" 11 | "go/token" 12 | "os" 13 | "path" 14 | "strings" 15 | ) 16 | 17 | type TypeCheck struct { 18 | Path string 19 | ImportPath string 20 | Package *types.Package 21 | FileSet *token.FileSet 22 | ParseFiles []string 23 | ProcessFiles []string 24 | FilesToAst map[string]*ast.File 25 | Ast []*ast.File 26 | } 27 | 28 | var typechecks = make(map[string]*TypeCheck) 29 | 30 | func packageLocations(args []string) []string { 31 | if len(args) == 0 { 32 | dirname, err := os.Getwd() 33 | 34 | if err != nil { 35 | fmt.Fprintf(os.Stderr, "Failed to obtain current working directory\n") 36 | os.Exit(1) 37 | } 38 | 39 | return []string{dirname} 40 | } 41 | 42 | return args 43 | } 44 | 45 | func buildFiles(packageDir string) (parse []string, process []string, pkgname string) { 46 | ctx := build.Default 47 | 48 | ctx.BuildTags = []string{"operators"} 49 | 50 | p, err := ctx.ImportDir(packageDir, 0) 51 | 52 | if err != nil { 53 | fmt.Fprintf(os.Stderr, "Error while importing build: %s\n", err) 54 | os.Exit(1) 55 | } 56 | 57 | for _, f := range p.GoFiles { 58 | parse = append(parse, path.Join(packageDir, f)) 59 | 60 | if strings.HasSuffix(f, ".op.go") { 61 | process = append(process, f) 62 | } 63 | } 64 | 65 | return parse, process, p.Name 66 | } 67 | 68 | func parseAST(files []string) (fs *token.FileSet, afs []*ast.File, afsmap map[string]*ast.File) { 69 | fs = token.NewFileSet() 70 | afs = make([]*ast.File, 0, len(files)) 71 | afsmap = make(map[string]*ast.File) 72 | 73 | for _, f := range files { 74 | af, err := parser.ParseFile(fs, f, nil, 0) 75 | 76 | if err != nil { 77 | fmt.Fprintf(os.Stderr, "Error while parsing AST: %s\n", err) 78 | os.Exit(1) 79 | } 80 | 81 | afsmap[f] = af 82 | afs = append(afs, af) 83 | } 84 | 85 | return fs, afs, afsmap 86 | } 87 | 88 | func checkTypes(pkgpath string, importpath string) *TypeCheck { 89 | if ret, ok := typechecks[importpath]; ok { 90 | return ret 91 | } 92 | 93 | parse, process, pkgname := buildFiles(pkgpath) 94 | fs, afs, afsmap := parseAST(parse) 95 | 96 | var conf types.Config 97 | 98 | conf.Import = importSources 99 | 100 | pp, err := conf.Check(pkgname, fs, afs, nil) 101 | 102 | if err != nil { 103 | fmt.Fprintf(os.Stderr, "Error while type checking: %s\n", err) 104 | os.Exit(1) 105 | } 106 | 107 | ret := &TypeCheck{ 108 | Path: pkgpath, 109 | Package: pp, 110 | ImportPath: importpath, 111 | ParseFiles: parse, 112 | ProcessFiles: process, 113 | FileSet: fs, 114 | Ast: afs, 115 | FilesToAst: afsmap, 116 | } 117 | 118 | typechecks[importpath] = ret 119 | return ret 120 | } 121 | 122 | func resolvePackage(importpath string, tryLocal bool) *TypeCheck { 123 | if ret, ok := typechecks[importpath]; ok { 124 | return ret 125 | } 126 | 127 | // Try local first 128 | if tryLocal { 129 | if _, err := os.Stat(importpath); err == nil { 130 | return checkTypes(importpath, importpath) 131 | } 132 | } 133 | 134 | paths := strings.Split(os.Getenv("GOPATH"), ":") 135 | 136 | for _, p := range paths { 137 | src := path.Join(p, "src", importpath) 138 | 139 | if _, err := os.Stat(src); err != nil { 140 | continue 141 | } 142 | 143 | return checkTypes(src, importpath) 144 | } 145 | 146 | fmt.Fprintf(os.Stderr, "Could not find package %s.\n", importpath) 147 | os.Exit(1) 148 | 149 | return nil 150 | } 151 | 152 | func importSource(imports map[string]*types.Package, path string) (pkg *types.Package, err error) { 153 | if pkg, ok := imports[path]; ok { 154 | return pkg, nil 155 | } 156 | 157 | // Try from source 158 | ct := resolvePackage(path, false) 159 | 160 | if ct == nil { 161 | return nil, fmt.Errorf("Could not locate import path %s", path) 162 | } 163 | 164 | imports[ct.ImportPath] = ct.Package 165 | return ct.Package, nil 166 | 167 | } 168 | 169 | func importSources(imports map[string]*types.Package, path string) (pkg *types.Package, err error) { 170 | if operatorPackages[path] { 171 | return importSource(imports, path) 172 | } 173 | 174 | pkg, err = types.GcImport(imports, path) 175 | 176 | if err != nil { 177 | if path == "C" { 178 | return nil, fmt.Errorf("go-operators does not have support for packages that use cgo at the moment") 179 | } 180 | 181 | return importSource(imports, path) 182 | } 183 | 184 | return pkg, err 185 | } 186 | 187 | func replacer(overloads map[ast.Expr]types.OverloadInfo, node ast.Node) ast.Node { 188 | expr, ok := node.(ast.Expr) 189 | 190 | if !ok { 191 | return node 192 | } 193 | 194 | info, ok := overloads[expr] 195 | 196 | if !ok { 197 | return node 198 | } 199 | 200 | sel := &ast.SelectorExpr{ 201 | X: info.Recv, 202 | Sel: ast.NewIdent(info.Func.Name()), 203 | } 204 | 205 | args := []ast.Expr{} 206 | 207 | if info.Oper != nil { 208 | args = append(args, info.Oper) 209 | } 210 | 211 | // Create function call expression 212 | call := &ast.CallExpr{ 213 | Fun: sel, 214 | Args: args, 215 | } 216 | 217 | return call 218 | } 219 | 220 | func replaceOperators(ct *TypeCheck) { 221 | overloads := ct.Package.Overloads() 222 | 223 | for _, f := range ct.ProcessFiles { 224 | af := ct.FilesToAst[path.Join(ct.Path, f)] 225 | 226 | af = replace(func(node ast.Node) ast.Node { 227 | return replacer(overloads, node) 228 | }, af).(*ast.File) 229 | 230 | suffix := ".op.go" 231 | outname := f[:len(f)-len(suffix)] + ".go" 232 | 233 | fn := path.Join(ct.Path, outname) 234 | 235 | of, err := os.Create(fn) 236 | 237 | if err != nil { 238 | fmt.Fprintf(os.Stderr, "Failed to create output file: %s\n", err) 239 | os.Exit(1) 240 | } 241 | 242 | defer of.Close() 243 | 244 | if opts.Verbose { 245 | fmt.Println(fn) 246 | } 247 | 248 | // Write build constraint 249 | fmt.Fprintln(of, "// +build !operators\n") 250 | 251 | if err := format.Node(of, ct.FileSet, af); err != nil { 252 | fmt.Fprintf(os.Stderr, "Failed to write code: %s\n", err) 253 | os.Exit(1) 254 | } 255 | } 256 | } 257 | 258 | var opts struct { 259 | Verbose bool `short:"v" long:"verbose" description:"Enable verbose mode"` 260 | } 261 | 262 | var operatorPackages = make(map[string]bool) 263 | 264 | func main() { 265 | fp := flags.NewParser(&opts, flags.Default) 266 | 267 | args, err := fp.Parse() 268 | 269 | if err != nil { 270 | os.Exit(1) 271 | } 272 | 273 | packageDirs := packageLocations(args) 274 | 275 | for _, p := range packageDirs { 276 | operatorPackages[p] = true 277 | } 278 | 279 | for _, p := range packageDirs { 280 | ct := resolvePackage(p, true) 281 | replaceOperators(ct) 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /types/api.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package types declares the data types and implements 6 | // the algorithms for type-checking of Go packages. 7 | // Use Check and Config.Check to invoke the type-checker. 8 | // 9 | // Type-checking consists of several interdependent phases: 10 | // 11 | // Name resolution maps each identifier (ast.Ident) in the program to the 12 | // language object (Object) it denotes. 13 | // Use Info.Objects, Info.Implicits for the results of name resolution. 14 | // 15 | // Constant folding computes the exact constant value (exact.Value) for 16 | // every expression (ast.Expr) that is a compile-time constant. 17 | // Use Info.Values for the results of constant folding. 18 | // 19 | // Type inference computes the type (Type) of every expression (ast.Expr) 20 | // and checks for compliance with the language specification. 21 | // Use Info.Types for the results of type evaluation. 22 | // 23 | package types 24 | 25 | import ( 26 | "go/ast" 27 | "go/token" 28 | 29 | "code.google.com/p/go.tools/go/exact" 30 | ) 31 | 32 | // Check type-checks a package and returns the resulting complete package 33 | // object, or a nil package and the first error. The package is specified 34 | // by a list of *ast.Files and corresponding file set, and the import path 35 | // the package is identified with. The clean path must not be empty or dot ("."). 36 | // 37 | // For more control over type-checking and results, use Config.Check. 38 | func Check(path string, fset *token.FileSet, files []*ast.File) (*Package, error) { 39 | var conf Config 40 | pkg, err := conf.Check(path, fset, files, nil) 41 | if err != nil { 42 | return nil, err 43 | } 44 | return pkg, nil 45 | } 46 | 47 | // A Config specifies the configuration for type checking. 48 | // The zero value for Config is a ready-to-use default configuration. 49 | type Config struct { 50 | // If IgnoreFuncBodies is set, function bodies are not 51 | // type-checked. 52 | IgnoreFuncBodies bool 53 | 54 | // If FakeImportC is set, `import "C"` (for packages requiring Cgo) 55 | // declares an empty "C" package and errors are omitted for qualified 56 | // identifiers referring to package C (which won't find an object). 57 | // This feature is intended for the standard library cmd/api tool. 58 | // 59 | // Caution: Effects may be unpredictable due to follow-up errors. 60 | // Do not use casually! 61 | FakeImportC bool 62 | 63 | // Packages is used to look up (and thus canonicalize) packages by 64 | // package path. If Packages is nil, it is set to a new empty map. 65 | // During type-checking, imported packages are added to the map. 66 | Packages map[string]*Package 67 | 68 | // If Error != nil, it is called with each error found 69 | // during type checking. The error strings of errors with 70 | // detailed position information are formatted as follows: 71 | // filename:line:column: message 72 | Error func(err error) 73 | 74 | // If Import != nil, it is called for each imported package. 75 | // Otherwise, GcImporter is called. 76 | // An importer resolves import paths to Packages. 77 | // The imports map records packages already known, 78 | // indexed by canonical package path. The type-checker will 79 | // invoke Import with Config.Packages. 80 | // An importer must determine the canonical package path and 81 | // check imports to see if it is already present in the map. 82 | // If so, the Importer can return the map entry. Otherwise, 83 | // the importer must load the package data for the given path 84 | // into a new *Package, record it in imports map, and return 85 | // the package. 86 | Import func(imports map[string]*Package, path string) (pkg *Package, err error) 87 | 88 | // If Sizes != nil, it provides the sizing functions for package unsafe. 89 | // Otherwise &StdSize{WordSize: 8, MaxAlign: 8} is used instead. 90 | Sizes Sizes 91 | } 92 | 93 | // Info holds result type information for a type-checked package. 94 | // Only the information for which a map is provided is collected. 95 | // If the package has type errors, the collected information may 96 | // be incomplete. 97 | type Info struct { 98 | // Types maps expressions to their types. Identifiers on the 99 | // lhs of declarations are collected in Objects, not Types. 100 | // 101 | // For an expression denoting a predeclared built-in function 102 | // the recorded signature is call-site specific. If the call 103 | // result is not a constant, the recorded type is an argument- 104 | // specific signature. Otherwise, the recorded type is invalid. 105 | Types map[ast.Expr]Type 106 | 107 | // Values maps constant expressions to their values. 108 | Values map[ast.Expr]exact.Value 109 | 110 | // Objects maps identifiers to their corresponding objects (including 111 | // package names, dots "." of dot-imports, and blank "_" identifiers). 112 | // For identifiers that do not denote objects (e.g., the package name 113 | // in package clauses, blank identifiers on the lhs of assignments, or 114 | // symbolic variables t in t := x.(type) of type switch headers), the 115 | // corresponding objects are nil. 116 | Objects map[*ast.Ident]Object 117 | 118 | // Implicits maps nodes to their implicitly declared objects, if any. 119 | // The following node and object types may appear: 120 | // 121 | // node declared object 122 | // 123 | // *ast.ImportSpec *PkgName (imports w/o renames), or imported objects (dot-imports) 124 | // *ast.CaseClause type-specific *Var for each type switch case clause (incl. default) 125 | // *ast.Field anonymous struct field or parameter *Var 126 | // 127 | Implicits map[ast.Node]Object 128 | 129 | // Selections maps selector expressions to their corresponding selections. 130 | Selections map[*ast.SelectorExpr]*Selection 131 | 132 | // Scopes maps ast.Nodes to the scopes they define. Note that package scopes 133 | // are not associated with a specific node but with all files belonging to a 134 | // package. Thus, the package scope can be found in the type-checked package 135 | // object. 136 | // 137 | // The following node types may appear in Scopes: 138 | // 139 | // *ast.File 140 | // *ast.FuncType 141 | // *ast.BlockStmt 142 | // *ast.IfStmt 143 | // *ast.SwitchStmt 144 | // *ast.TypeSwitchStmt 145 | // *ast.CaseClause 146 | // *ast.CommClause 147 | // *ast.ForStmt 148 | // *ast.RangeStmt 149 | // 150 | Scopes map[ast.Node]*Scope 151 | } 152 | 153 | // Check type-checks a package and returns the resulting package object, 154 | // the first error if any, and if info != nil, additional type information. 155 | // The package is marked as complete if no errors occurred, otherwise it is 156 | // incomplete. 157 | // 158 | // The package is specified by a list of *ast.Files and corresponding 159 | // file set, and the package path the package is identified with. 160 | // The clean path must not be empty or dot ("."). 161 | func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) { 162 | pkg, err := conf.check(path, fset, files, info) 163 | if err == nil { 164 | pkg.complete = true 165 | } 166 | return pkg, err 167 | } 168 | 169 | // IsAssignableTo reports whether a value of type V is assignable to a variable of type T. 170 | func IsAssignableTo(V, T Type) bool { 171 | x := operand{mode: value, typ: V} 172 | return x.isAssignableTo(nil, T) // config not needed for non-constant x 173 | } 174 | 175 | // Implements reports whether a value of type V implements T, as follows: 176 | // 177 | // 1) For non-interface types V, or if static is set, V implements T if all 178 | // methods of T are present in V. Informally, this reports whether V is a 179 | // subtype of T. 180 | // 181 | // 2) For interface types V, and if static is not set, V implements T if all 182 | // methods of T which are also present in V have matching types. Informally, 183 | // this indicates whether a type assertion x.(T) where x is of type V would 184 | // be legal (the concrete dynamic type of x may implement T even if V does 185 | // not statically implement it). 186 | // 187 | func Implements(V Type, T *Interface, static bool) bool { 188 | f, _ := MissingMethod(V, T, static) 189 | return f == nil 190 | } 191 | 192 | // BUG(gri): Interface vs non-interface comparisons are not correctly implemented. 193 | // BUG(gri): Switch statements don't check duplicate cases for all types for which it is required. 194 | -------------------------------------------------------------------------------- /types/api_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // TODO(gri) This file needs to be expanded significantly. 6 | 7 | package types 8 | 9 | import ( 10 | "fmt" 11 | "go/ast" 12 | "go/parser" 13 | "go/token" 14 | "strings" 15 | "testing" 16 | ) 17 | 18 | func pkgFor(path, source string, info *Info) (*Package, error) { 19 | fset = token.NewFileSet() 20 | f, err := parser.ParseFile(fset, path, source, 0) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | var conf Config 26 | pkg, err := conf.Check(path, fset, []*ast.File{f}, info) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | return pkg, nil 32 | } 33 | 34 | func mustTypecheck(t *testing.T, path, source string, info *Info) *Package { 35 | pkg, err := pkgFor(path, source, info) 36 | if err != nil { 37 | t.Fatalf("%s: didn't type-check (%s)", path, err) 38 | } 39 | return pkg 40 | } 41 | 42 | func TestCommaOkTypes(t *testing.T) { 43 | var tests = []struct { 44 | src string 45 | expr string // comma-ok expression string 46 | typ string // typestring of comma-ok value 47 | }{ 48 | {`package p; var x interface{}; var _, _ = x.(int)`, 49 | `x.(int)`, 50 | `(int, bool)`, 51 | }, 52 | {`package p; var x interface{}; func _() { _, _ = x.(int) }`, 53 | `x.(int)`, 54 | `(int, bool)`, 55 | }, 56 | {`package p; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`, 57 | `m["foo"]`, 58 | `(complex128, p.mybool)`, 59 | }, 60 | {`package p; var c chan string; var _, _ = <-c`, 61 | `<-c`, 62 | `(string, bool)`, 63 | }, 64 | } 65 | 66 | for i, test := range tests { 67 | path := fmt.Sprintf("CommaOkTypes%d", i) 68 | info := Info{Types: make(map[ast.Expr]Type)} 69 | mustTypecheck(t, path, test.src, &info) 70 | 71 | // look for comma-ok expression type 72 | var typ Type 73 | for e, t := range info.Types { 74 | if exprString(e) == test.expr { 75 | typ = t 76 | break 77 | } 78 | } 79 | if typ == nil { 80 | t.Errorf("%s: no type found for %s", path, test.expr) 81 | continue 82 | } 83 | 84 | // check that type is correct 85 | if got := typ.String(); got != test.typ { 86 | t.Errorf("%s: got %s; want %s", path, got, test.typ) 87 | } 88 | } 89 | } 90 | 91 | func TestScopesInfo(t *testing.T) { 92 | var tests = []struct { 93 | src string 94 | scopes []string // list of scope descriptors of the form kind:varlist 95 | }{ 96 | {`package p`, []string{ 97 | "file:", 98 | }}, 99 | {`package p; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{ 100 | "file:fmt m", 101 | }}, 102 | {`package p; func _() {}`, []string{ 103 | "file:", "func:", 104 | }}, 105 | {`package p; func _(x, y int) {}`, []string{ 106 | "file:", "func:x y", 107 | }}, 108 | {`package p; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{ 109 | "file:", "func:x y z", // redeclaration of x 110 | }}, 111 | {`package p; func _(x, y int) (u, _ int) { return }`, []string{ 112 | "file:", "func:u x y", 113 | }}, 114 | {`package p; func _() { { var x int; _ = x } }`, []string{ 115 | "file:", "func:", "block:x", 116 | }}, 117 | {`package p; func _() { if true {} }`, []string{ 118 | "file:", "func:", "if:", "block:", 119 | }}, 120 | {`package p; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{ 121 | "file:", "func:", "if:x", "block:y", 122 | }}, 123 | {`package p; func _() { switch x := 0; x {} }`, []string{ 124 | "file:", "func:", "switch:x", 125 | }}, 126 | {`package p; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{ 127 | "file:", "func:", "switch:x", "case:y", "case:", 128 | }}, 129 | {`package p; func _(t interface{}) { switch t.(type) {} }`, []string{ 130 | "file:", "func:t", "type switch:", 131 | }}, 132 | {`package p; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{ 133 | "file:", "func:t", "type switch:t", 134 | }}, 135 | {`package p; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{ 136 | "file:", "func:t", "type switch:", "case:x", // x implicitly declared 137 | }}, 138 | {`package p; func _() { select{} }`, []string{ 139 | "file:", "func:", 140 | }}, 141 | {`package p; func _(c chan int) { select{ case <-c: } }`, []string{ 142 | "file:", "func:c", "comm:", 143 | }}, 144 | {`package p; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{ 145 | "file:", "func:c", "comm:i x", 146 | }}, 147 | {`package p; func _() { for{} }`, []string{ 148 | "file:", "func:", "for:", "block:", 149 | }}, 150 | {`package p; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{ 151 | "file:", "func:n", "for:i", "block:", 152 | }}, 153 | {`package p; func _(a []int) { for i := range a { _ = i} }`, []string{ 154 | "file:", "func:a", "range:i", "block:", 155 | }}, 156 | {`package p; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{ 157 | "file:", "func:a", "range:i x", "block:", 158 | }}, 159 | } 160 | 161 | for i, test := range tests { 162 | path := fmt.Sprintf("ScopesInfo%d", i) 163 | info := Info{Scopes: make(map[ast.Node]*Scope)} 164 | mustTypecheck(t, path, test.src, &info) 165 | 166 | // number of scopes must match 167 | if len(info.Scopes) != len(test.scopes) { 168 | t.Errorf("%s: got %d scopes; want %d", path, len(info.Scopes), len(test.scopes)) 169 | } 170 | 171 | // scope descriptions must match 172 | for node, scope := range info.Scopes { 173 | kind := "" 174 | switch node.(type) { 175 | case *ast.File: 176 | kind = "file" 177 | case *ast.FuncType: 178 | kind = "func" 179 | case *ast.BlockStmt: 180 | kind = "block" 181 | case *ast.IfStmt: 182 | kind = "if" 183 | case *ast.SwitchStmt: 184 | kind = "switch" 185 | case *ast.TypeSwitchStmt: 186 | kind = "type switch" 187 | case *ast.CaseClause: 188 | kind = "case" 189 | case *ast.CommClause: 190 | kind = "comm" 191 | case *ast.ForStmt: 192 | kind = "for" 193 | case *ast.RangeStmt: 194 | kind = "range" 195 | } 196 | 197 | // look for matching scope description 198 | desc := kind + ":" + strings.Join(scope.Names(), " ") 199 | found := false 200 | for _, d := range test.scopes { 201 | if desc == d { 202 | found = true 203 | break 204 | } 205 | } 206 | if !found { 207 | t.Errorf("%s: no matching scope found for %s", path, desc) 208 | } 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /types/builtins_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package types 6 | 7 | import ( 8 | "fmt" 9 | "go/ast" 10 | "go/parser" 11 | "testing" 12 | ) 13 | 14 | var builtinCalls = []struct { 15 | id builtinId 16 | src string 17 | sig string 18 | }{ 19 | {_Append, `var s []int; _ = append(s)`, `func([]int, ...int) []int`}, 20 | {_Append, `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`}, 21 | {_Append, `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`}, 22 | {_Append, `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`}, 23 | // Note that ...uint8 (instead of ..byte) appears below because that is the type 24 | // that corresponds to Typ[byte] (an alias) - in the other cases, the type name 25 | // is chosen by the source. Either way, byte and uint8 denote identical types. 26 | {_Append, `var s []byte; _ = append(s, "foo"...)`, `func([]byte, ...uint8) []byte`}, 27 | {_Append, `type T []byte; var s T; _ = append(s, "foo"...)`, `func(p.T, ...uint8) p.T`}, 28 | 29 | {_Cap, `var s [10]int; _ = cap(s)`, `invalid type`}, // constant 30 | {_Cap, `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant 31 | {_Cap, `var s []int64; _ = cap(s)`, `func([]int64) int`}, 32 | {_Cap, `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`}, 33 | 34 | {_Len, `_ = len("foo")`, `invalid type`}, // constant 35 | {_Len, `var s string; _ = len(s)`, `func(string) int`}, 36 | {_Len, `var s [10]int; _ = len(s)`, `invalid type`}, // constant 37 | {_Len, `var s [10]int; _ = len(&s)`, `invalid type`}, // constant 38 | {_Len, `var s []int64; _ = len(s)`, `func([]int64) int`}, 39 | {_Len, `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`}, 40 | {_Len, `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`}, 41 | 42 | {_Close, `var c chan int; close(c)`, `func(chan int)`}, 43 | {_Close, `var c chan<- chan string; close(c)`, `func(chan<- chan string)`}, 44 | 45 | {_Complex, `_ = complex(1, 0)`, `invalid type`}, // constant 46 | {_Complex, `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`}, 47 | {_Complex, `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`}, 48 | {_Complex, `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`}, 49 | {_Complex, `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`}, 50 | 51 | {_Copy, `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`}, 52 | {_Copy, `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func([][]int, [][]int) int`}, 53 | 54 | {_Delete, `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`}, 55 | {_Delete, `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`}, 56 | 57 | {_Imag, `_ = imag(1i)`, `invalid type`}, // constant 58 | {_Imag, `var c complex64; _ = imag(c)`, `func(complex64) float32`}, 59 | {_Imag, `var c complex128; _ = imag(c)`, `func(complex128) float64`}, 60 | {_Imag, `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`}, 61 | {_Imag, `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`}, 62 | 63 | {_Real, `_ = real(1i)`, `invalid type`}, // constant 64 | {_Real, `var c complex64; _ = real(c)`, `func(complex64) float32`}, 65 | {_Real, `var c complex128; _ = real(c)`, `func(complex128) float64`}, 66 | {_Real, `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`}, 67 | {_Real, `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`}, 68 | 69 | {_Make, `_ = make([]int, 10)`, `func([]int, int) []int`}, 70 | {_Make, `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`}, 71 | 72 | {_New, `_ = new(int)`, `func(int) *int`}, 73 | {_New, `type T struct{}; _ = new(T)`, `func(p.T) *p.T`}, 74 | 75 | {_Panic, `panic(0)`, `func(interface{})`}, 76 | {_Panic, `panic("foo")`, `func(interface{})`}, 77 | 78 | {_Print, `print()`, `func()`}, 79 | {_Print, `print(0)`, `func(int)`}, 80 | {_Print, `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`}, 81 | 82 | {_Println, `println()`, `func()`}, 83 | {_Println, `println(0)`, `func(int)`}, 84 | {_Println, `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`}, 85 | 86 | {_Recover, `recover()`, `func() interface{}`}, 87 | {_Recover, `_ = recover()`, `func() interface{}`}, 88 | 89 | {_Alignof, `_ = unsafe.Alignof(0)`, `invalid type`}, // constant 90 | {_Alignof, `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant 91 | 92 | {_Offsetof, `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`}, // constant 93 | {_Offsetof, `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant 94 | 95 | {_Sizeof, `_ = unsafe.Sizeof(0)`, `invalid type`}, // constant 96 | {_Sizeof, `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant 97 | 98 | {_Assert, `assert(true)`, `invalid type`}, // constant 99 | {_Assert, `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant 100 | 101 | // no tests for trace since it produces output as a side-effect 102 | } 103 | 104 | func TestBuiltinSignatures(t *testing.T) { 105 | defPredeclaredTestFuncs() 106 | 107 | seen := map[builtinId]bool{_Trace: true} // no test for _Trace; add it manually 108 | for _, call := range builtinCalls { 109 | testBuiltinSignature(t, call.id, call.src, call.sig) 110 | seen[call.id] = true 111 | } 112 | 113 | // make sure we didn't miss one 114 | for i := range predeclaredFuncs { 115 | if id := builtinId(i); !seen[id] { 116 | t.Errorf("missing test for %s", predeclaredFuncs[id].name) 117 | } 118 | } 119 | } 120 | 121 | func testBuiltinSignature(t *testing.T, id builtinId, src0, want string) { 122 | src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0) 123 | f, err := parser.ParseFile(fset, "", src, 0) 124 | if err != nil { 125 | t.Errorf("%s: %s", src0, err) 126 | return 127 | } 128 | 129 | var conf Config 130 | objects := make(map[*ast.Ident]Object) 131 | types := make(map[ast.Expr]Type) 132 | _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Objects: objects, Types: types}) 133 | if err != nil { 134 | t.Errorf("%s: %s", src0, err) 135 | return 136 | } 137 | 138 | // find called function 139 | n := 0 140 | var fun ast.Expr 141 | for x, _ := range types { 142 | if call, _ := x.(*ast.CallExpr); call != nil { 143 | fun = call.Fun 144 | n++ 145 | } 146 | } 147 | if n != 1 { 148 | t.Errorf("%s: got %d CallExprs; want 1", src0, n) 149 | return 150 | } 151 | 152 | // check recorded types for fun and descendents (may be parenthesized) 153 | for { 154 | // the recorded type for the built-in must match the wanted signature 155 | typ := types[fun] 156 | if typ == nil { 157 | t.Errorf("%s: no type recorded for %s", src0, exprString(fun)) 158 | return 159 | } 160 | if got := typ.String(); got != want { 161 | t.Errorf("%s: got type %s; want %s", src0, got, want) 162 | return 163 | } 164 | 165 | // called function must be a (possibly parenthesized, qualified) 166 | // identifier denoting the expected built-in 167 | switch p := fun.(type) { 168 | case *ast.Ident: 169 | obj := objects[p] 170 | if obj == nil { 171 | t.Errorf("%s: no object found for %s", src0, p) 172 | return 173 | } 174 | bin, _ := obj.(*Builtin) 175 | if bin == nil { 176 | t.Errorf("%s: %s does not denote a built-in", src0, p) 177 | return 178 | } 179 | if bin.id != id { 180 | t.Errorf("%s: got built-in %s; want %s", src0, bin.name, predeclaredFuncs[id].name) 181 | return 182 | } 183 | return // we're done 184 | 185 | case *ast.ParenExpr: 186 | fun = p.X // unpack 187 | 188 | case *ast.SelectorExpr: 189 | // built-in from package unsafe - ignore details 190 | return // we're done 191 | 192 | default: 193 | t.Errorf("%s: invalid function call", src0) 194 | return 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /types/check.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements the Check function, which drives type-checking. 6 | 7 | package types 8 | 9 | import ( 10 | "fmt" 11 | "go/ast" 12 | "go/token" 13 | "path" 14 | 15 | "code.google.com/p/go.tools/go/exact" 16 | ) 17 | 18 | // debugging/development support 19 | const ( 20 | debug = true // leave on during development 21 | trace = false // turn on for detailed type resolution traces 22 | ) 23 | 24 | // exprInfo stores type and constant value for an untyped expression. 25 | type exprInfo struct { 26 | isLhs bool // expression is lhs operand of a shift with delayed type-check 27 | typ *Basic 28 | val exact.Value // constant value; or nil (if not a constant) 29 | } 30 | 31 | // A checker is an instance of the type-checker. 32 | type checker struct { 33 | conf *Config 34 | fset *token.FileSet 35 | pkg *Package 36 | 37 | methods map[string][]*Func // maps type names to associated methods 38 | conversions map[*ast.CallExpr]bool // set of type-checked conversions (to distinguish from calls) 39 | untyped map[ast.Expr]exprInfo // map of expressions without final type 40 | lhsVarsList [][]*Var // type switch lhs variable sets, for 'declared but not used' errors 41 | 42 | firstErr error // first error encountered 43 | Info // collected type info 44 | 45 | objMap map[Object]declInfo // if set we are in the package-level declaration phase (otherwise all objects seen must be declared) 46 | topScope *Scope // current topScope for lookups 47 | iota exact.Value // value of iota in a constant declaration; nil otherwise 48 | 49 | // functions 50 | funcList []funcInfo // list of functions/methods with correct signatures and non-empty bodies 51 | funcSig *Signature // signature of currently type-checked function 52 | hasLabel bool // set if a function makes use of labels (only ~1% of functions) 53 | 54 | // debugging 55 | indent int // indentation for tracing 56 | } 57 | 58 | func newChecker(conf *Config, fset *token.FileSet, pkg *Package) *checker { 59 | return &checker{ 60 | conf: conf, 61 | fset: fset, 62 | pkg: pkg, 63 | methods: make(map[string][]*Func), 64 | conversions: make(map[*ast.CallExpr]bool), 65 | untyped: make(map[ast.Expr]exprInfo), 66 | } 67 | } 68 | 69 | func (check *checker) recordTypeAndValue(x ast.Expr, typ Type, val exact.Value) { 70 | assert(x != nil && typ != nil) 71 | if m := check.Types; m != nil { 72 | m[x] = typ 73 | } 74 | if val != nil { 75 | if m := check.Values; m != nil { 76 | m[x] = val 77 | } 78 | } 79 | } 80 | 81 | func (check *checker) recordBuiltinType(f ast.Expr, sig *Signature) { 82 | // f must be a (possibly parenthesized) identifier denoting a built-in 83 | // (built-ins in package unsafe always produce a constant result and 84 | // we don't record their signatures, so we don't see qualified idents 85 | // here): record the signature for f and possible children. 86 | for { 87 | check.recordTypeAndValue(f, sig, nil) 88 | switch p := f.(type) { 89 | case *ast.Ident: 90 | return // we're done 91 | case *ast.ParenExpr: 92 | f = p.X 93 | default: 94 | unreachable() 95 | } 96 | } 97 | } 98 | 99 | func (check *checker) recordCommaOkTypes(x ast.Expr, t1, t2 Type) { 100 | assert(x != nil && isTyped(t1) && isTyped(t2) && isBoolean(t2)) 101 | if m := check.Types; m != nil { 102 | assert(m[x] != nil) // should have been recorded already 103 | pos := x.Pos() 104 | m[x] = NewTuple( 105 | NewVar(pos, check.pkg, "", t1), 106 | NewVar(pos, check.pkg, "", t2), 107 | ) 108 | } 109 | } 110 | 111 | func (check *checker) recordObject(id *ast.Ident, obj Object) { 112 | assert(id != nil) 113 | if m := check.Objects; m != nil { 114 | m[id] = obj 115 | } 116 | } 117 | 118 | func (check *checker) recordImplicit(node ast.Node, obj Object) { 119 | assert(node != nil && obj != nil) 120 | if m := check.Implicits; m != nil { 121 | m[node] = obj 122 | } 123 | } 124 | 125 | func (check *checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) { 126 | assert(obj != nil && (recv == nil || len(index) > 0)) 127 | check.recordObject(x.Sel, obj) 128 | // TODO(gri) Should we also call recordTypeAndValue? 129 | if m := check.Selections; m != nil { 130 | m[x] = &Selection{kind, recv, obj, index, indirect} 131 | } 132 | } 133 | 134 | func (check *checker) recordScope(node ast.Node, scope *Scope) { 135 | assert(node != nil && scope != nil) 136 | if m := check.Scopes; m != nil { 137 | m[node] = scope 138 | } 139 | } 140 | 141 | // A bailout panic is raised to indicate early termination. 142 | type bailout struct{} 143 | 144 | func (check *checker) handleBailout(err *error) { 145 | switch p := recover().(type) { 146 | case nil, bailout: 147 | // normal return or early exit 148 | *err = check.firstErr 149 | default: 150 | // unexpected panic: don't crash clients 151 | // TODO(gri) add a test case for this scenario 152 | *err = fmt.Errorf("types internal error: %v", p) 153 | if debug { 154 | check.dump("INTERNAL PANIC: %v", p) 155 | panic(p) 156 | } 157 | } 158 | } 159 | 160 | func (conf *Config) check(pkgPath string, fset *token.FileSet, files []*ast.File, info *Info) (pkg *Package, err error) { 161 | // make sure we have a package canonicalization map 162 | if conf.Packages == nil { 163 | conf.Packages = make(map[string]*Package) 164 | } 165 | 166 | pkg = NewPackage(pkgPath, "", NewScope(Universe)) // package name is set below 167 | check := newChecker(conf, fset, pkg) 168 | defer check.handleBailout(&err) 169 | 170 | // we need a reasonable package path to continue 171 | if path.Clean(pkgPath) == "." { 172 | check.errorf(token.NoPos, "invalid package path provided: %q", pkgPath) 173 | return 174 | } 175 | 176 | // determine package name and files 177 | i := 0 178 | for _, file := range files { 179 | switch name := file.Name.Name; pkg.name { 180 | case "": 181 | pkg.name = name 182 | fallthrough 183 | case name: 184 | files[i] = file 185 | i++ 186 | default: 187 | check.errorf(file.Package, "package %s; expected %s", name, pkg.name) 188 | // ignore this file 189 | } 190 | } 191 | 192 | // install optional info 193 | if info != nil { 194 | check.Info = *info 195 | } 196 | 197 | check.resolveFiles(files[:i]) 198 | 199 | // remaining untyped expressions must indeed be untyped 200 | if debug { 201 | for x, info := range check.untyped { 202 | if isTyped(info.typ) { 203 | check.dump("%s: %s (type %s) is typed", x.Pos(), x, info.typ) 204 | panic(0) 205 | } 206 | } 207 | } 208 | 209 | // notify client of any untyped types left 210 | // TODO(gri) Consider doing this before and 211 | // after function body checking for smaller 212 | // map size and more immediate feedback. 213 | if check.Types != nil || check.Values != nil { 214 | for x, info := range check.untyped { 215 | check.recordTypeAndValue(x, info.typ, info.val) 216 | } 217 | } 218 | 219 | return 220 | } 221 | -------------------------------------------------------------------------------- /types/check_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements a typechecker test harness. The packages specified 6 | // in tests are typechecked. Error messages reported by the typechecker are 7 | // compared against the error messages expected in the test files. 8 | // 9 | // Expected errors are indicated in the test files by putting a comment 10 | // of the form /* ERROR "rx" */ immediately following an offending token. 11 | // The harness will verify that an error matching the regular expression 12 | // rx is reported at that source position. Consecutive comments may be 13 | // used to indicate multiple errors for the same token position. 14 | // 15 | // For instance, the following test file indicates that a "not declared" 16 | // error should be reported for the undeclared variable x: 17 | // 18 | // package p 19 | // func f() { 20 | // _ = x /* ERROR "not declared" */ + 1 21 | // } 22 | 23 | package types 24 | 25 | import ( 26 | "flag" 27 | "go/ast" 28 | "go/parser" 29 | "go/scanner" 30 | "go/token" 31 | "io/ioutil" 32 | "regexp" 33 | "strings" 34 | "testing" 35 | ) 36 | 37 | var ( 38 | listErrors = flag.Bool("list", false, "list errors") 39 | testFiles = flag.String("files", "", "space-separated list of test files") 40 | ) 41 | 42 | // The test filenames do not end in .go so that they are invisible 43 | // to gofmt since they contain comments that must not change their 44 | // positions relative to surrounding tokens. 45 | 46 | // Each tests entry is list of files belonging to the same package. 47 | var tests = [][]string{ 48 | {"testdata/errors.src"}, 49 | {"testdata/importdecl0a.src", "testdata/importdecl0b.src"}, 50 | {"testdata/cycles.src"}, 51 | {"testdata/decls0.src"}, 52 | {"testdata/decls1.src"}, 53 | {"testdata/decls2a.src", "testdata/decls2b.src"}, 54 | {"testdata/decls3.src"}, 55 | {"testdata/const0.src"}, 56 | {"testdata/const1.src"}, 57 | {"testdata/constdecl.src"}, 58 | {"testdata/vardecl.src"}, 59 | {"testdata/expr0.src"}, 60 | {"testdata/expr1.src"}, 61 | {"testdata/expr2.src"}, 62 | {"testdata/expr3.src"}, 63 | {"testdata/methodsets.src"}, 64 | {"testdata/shifts.src"}, 65 | {"testdata/builtins.src"}, 66 | {"testdata/conversions.src"}, 67 | {"testdata/stmt0.src"}, 68 | {"testdata/stmt1.src"}, 69 | {"testdata/gotos.src"}, 70 | {"testdata/labels.src"}, 71 | } 72 | 73 | var fset = token.NewFileSet() 74 | 75 | // Positioned errors are of the form filename:line:column: message . 76 | var posMsgRx = regexp.MustCompile(`^(.*:[0-9]+:[0-9]+): *(.*)`) 77 | 78 | // splitError splits an error's error message into a position string 79 | // and the actual error message. If there's no position information, 80 | // pos is the empty string, and msg is the entire error message. 81 | // 82 | func splitError(err error) (pos, msg string) { 83 | msg = err.Error() 84 | if m := posMsgRx.FindStringSubmatch(msg); len(m) == 3 { 85 | pos = m[1] 86 | msg = m[2] 87 | } 88 | return 89 | } 90 | 91 | func parseFiles(t *testing.T, filenames []string) ([]*ast.File, []error) { 92 | var files []*ast.File 93 | var errlist []error 94 | for _, filename := range filenames { 95 | file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors) 96 | if file == nil { 97 | t.Fatalf("%s: %s", filename, err) 98 | } 99 | files = append(files, file) 100 | if err != nil { 101 | if list, _ := err.(scanner.ErrorList); len(list) > 0 { 102 | for _, err := range list { 103 | errlist = append(errlist, err) 104 | } 105 | } else { 106 | errlist = append(errlist, err) 107 | } 108 | } 109 | } 110 | return files, errlist 111 | } 112 | 113 | // ERROR comments must start with text `ERROR "rx"` or `ERROR rx` where 114 | // rx is a regular expression that matches the expected error message. 115 | // Space around "rx" or rx is ignored. 116 | // 117 | var errRx = regexp.MustCompile(`^ *ERROR *"?([^"]*)"?`) 118 | 119 | // errMap collects the regular expressions of ERROR comments found 120 | // in files and returns them as a map of error positions to error messages. 121 | // 122 | func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string { 123 | // map of position strings to lists of error message patterns 124 | errmap := make(map[string][]string) 125 | 126 | for _, file := range files { 127 | filename := fset.Position(file.Package).Filename 128 | src, err := ioutil.ReadFile(filename) 129 | if err != nil { 130 | t.Fatalf("%s: could not read %s", testname, filename) 131 | } 132 | 133 | var s scanner.Scanner 134 | s.Init(fset.AddFile(filename, -1, len(src)), src, nil, scanner.ScanComments) 135 | var prev string // position string of last non-comment, non-semicolon token 136 | 137 | scanFile: 138 | for { 139 | pos, tok, lit := s.Scan() 140 | switch tok { 141 | case token.EOF: 142 | break scanFile 143 | case token.COMMENT: 144 | if lit[1] == '*' { 145 | lit = lit[:len(lit)-2] // strip trailing */ 146 | } 147 | if s := errRx.FindStringSubmatch(lit[2:]); len(s) == 2 { 148 | errmap[prev] = append(errmap[prev], strings.TrimSpace(s[1])) 149 | } 150 | case token.SEMICOLON: 151 | // ignore automatically inserted semicolon 152 | if lit == "\n" { 153 | continue scanFile 154 | } 155 | fallthrough 156 | default: 157 | prev = fset.Position(pos).String() 158 | } 159 | } 160 | } 161 | 162 | return errmap 163 | } 164 | 165 | func eliminate(t *testing.T, errmap map[string][]string, errlist []error) { 166 | for _, err := range errlist { 167 | pos, gotMsg := splitError(err) 168 | list := errmap[pos] 169 | index := -1 // list index of matching message, if any 170 | // we expect one of the messages in list to match the error at pos 171 | for i, wantRx := range list { 172 | rx, err := regexp.Compile(wantRx) 173 | if err != nil { 174 | t.Errorf("%s: %v", pos, err) 175 | continue 176 | } 177 | if rx.MatchString(gotMsg) { 178 | index = i 179 | break 180 | } 181 | } 182 | if index >= 0 { 183 | // eliminate from list 184 | if n := len(list) - 1; n > 0 { 185 | // not the last entry - swap in last element and shorten list by 1 186 | list[index] = list[n] 187 | errmap[pos] = list[:n] 188 | } else { 189 | // last entry - remove list from map 190 | delete(errmap, pos) 191 | } 192 | } else { 193 | t.Errorf("%s: no error expected: %q", pos, gotMsg) 194 | } 195 | } 196 | } 197 | 198 | func checkFiles(t *testing.T, testfiles []string) { 199 | // parse files and collect parser errors 200 | files, errlist := parseFiles(t, testfiles) 201 | 202 | pkgName := "" 203 | if len(files) > 0 { 204 | pkgName = files[0].Name.Name 205 | } 206 | 207 | if *listErrors && len(errlist) > 0 { 208 | t.Errorf("--- %s:", pkgName) 209 | for _, err := range errlist { 210 | t.Error(err) 211 | } 212 | } 213 | 214 | // typecheck and collect typechecker errors 215 | var conf Config 216 | conf.Error = func(err error) { 217 | if *listErrors { 218 | t.Error(err) 219 | return 220 | } 221 | // Ignore error messages containing "other declaration": 222 | // They are follow-up error messages after a redeclaration 223 | // error. 224 | if !strings.Contains(err.Error(), "other declaration") { 225 | errlist = append(errlist, err) 226 | } 227 | } 228 | conf.Check(pkgName, fset, files, nil) 229 | 230 | if *listErrors { 231 | return 232 | } 233 | 234 | // match and eliminate errors; 235 | // we are expecting the following errors 236 | errmap := errMap(t, pkgName, files) 237 | eliminate(t, errmap, errlist) 238 | 239 | // there should be no expected errors left 240 | if len(errmap) > 0 { 241 | t.Errorf("--- %s: %d source positions with expected (but not reported) errors:", pkgName, len(errmap)) 242 | for pos, list := range errmap { 243 | for _, rx := range list { 244 | t.Errorf("%s: %q", pos, rx) 245 | } 246 | } 247 | } 248 | } 249 | 250 | func TestCheck(t *testing.T) { 251 | // Declare builtins for testing. 252 | defPredeclaredTestFuncs() 253 | 254 | // If explicit test files are specified, only check those. 255 | if files := *testFiles; files != "" { 256 | checkFiles(t, strings.Split(files, " ")) 257 | return 258 | } 259 | 260 | // Otherwise, run all the tests. 261 | for _, files := range tests { 262 | checkFiles(t, files) 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /types/conversions.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements typechecking of conversions. 6 | 7 | package types 8 | 9 | import "code.google.com/p/go.tools/go/exact" 10 | 11 | // Conversion type-checks the conversion T(x). 12 | // The result is in x. 13 | func (check *checker) conversion(x *operand, T Type) { 14 | var ok bool 15 | switch { 16 | case x.mode == constant && isConstType(T): 17 | // constant conversion 18 | switch t := T.Underlying().(*Basic); { 19 | case isRepresentableConst(x.val, check.conf, t.kind, &x.val): 20 | ok = true 21 | case x.isInteger() && isString(t): 22 | codepoint := int64(-1) 23 | if i, ok := exact.Int64Val(x.val); ok { 24 | codepoint = i 25 | } 26 | // If codepoint < 0 the absolute value is too large (or unknown) for 27 | // conversion. This is the same as converting any other out-of-range 28 | // value - let string(codepoint) do the work. 29 | x.val = exact.MakeString(string(codepoint)) 30 | ok = true 31 | } 32 | case x.isConvertible(check.conf, T): 33 | // non-constant conversion 34 | x.mode = value 35 | ok = true 36 | } 37 | 38 | if !ok { 39 | check.errorf(x.pos(), "cannot convert %s to %s", x, T) 40 | x.mode = invalid 41 | return 42 | } 43 | 44 | // The conversion argument types are final. For untyped values the 45 | // conversion provides the type, per the spec: "A constant may be 46 | // given a type explicitly by a constant declaration or conversion,...". 47 | final := x.typ 48 | if isUntyped(final) { 49 | final = T 50 | // For conversions to interfaces, use the argument type's 51 | // default type instead. Keep untyped nil for untyped nil 52 | // arguments. 53 | if isInterface(T) { 54 | final = defaultType(x.typ) 55 | } 56 | } 57 | 58 | x.typ = T 59 | check.updateExprType(x.expr, final, true) 60 | } 61 | 62 | func (x *operand) isConvertible(conf *Config, T Type) bool { 63 | // "x is assignable to T" 64 | if x.isAssignableTo(conf, T) { 65 | return true 66 | } 67 | 68 | // "x's type and T have identical underlying types" 69 | V := x.typ 70 | Vu := V.Underlying() 71 | Tu := T.Underlying() 72 | if IsIdentical(Vu, Tu) { 73 | return true 74 | } 75 | 76 | // "x's type and T are unnamed pointer types and their pointer base types have identical underlying types" 77 | if V, ok := V.(*Pointer); ok { 78 | if T, ok := T.(*Pointer); ok { 79 | if IsIdentical(V.base.Underlying(), T.base.Underlying()) { 80 | return true 81 | } 82 | } 83 | } 84 | 85 | // "x's type and T are both integer or floating point types" 86 | if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) { 87 | return true 88 | } 89 | 90 | // "x's type and T are both complex types" 91 | if isComplex(V) && isComplex(T) { 92 | return true 93 | } 94 | 95 | // "x is an integer or a slice of bytes or runes and T is a string type" 96 | if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) { 97 | return true 98 | } 99 | 100 | // "x is a string and T is a slice of bytes or runes" 101 | if isString(V) && isBytesOrRunes(Tu) { 102 | return true 103 | } 104 | 105 | // package unsafe: 106 | // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer" 107 | if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) { 108 | return true 109 | } 110 | // "and vice versa" 111 | if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) { 112 | return true 113 | } 114 | 115 | return false 116 | } 117 | 118 | func isUintptr(typ Type) bool { 119 | t, ok := typ.Underlying().(*Basic) 120 | return ok && t.kind == Uintptr 121 | } 122 | 123 | func isUnsafePointer(typ Type) bool { 124 | // TODO(gri): Is this (typ.Underlying() instead of just typ) correct? 125 | // The spec does't say so, but gc claims it is. See also 126 | // issue 6326. 127 | t, ok := typ.Underlying().(*Basic) 128 | return ok && t.kind == UnsafePointer 129 | } 130 | 131 | func isPointer(typ Type) bool { 132 | _, ok := typ.Underlying().(*Pointer) 133 | return ok 134 | } 135 | 136 | func isBytesOrRunes(typ Type) bool { 137 | if s, ok := typ.(*Slice); ok { 138 | t, ok := s.elt.Underlying().(*Basic) 139 | return ok && (t.kind == Byte || t.kind == Rune) 140 | } 141 | return false 142 | } 143 | -------------------------------------------------------------------------------- /types/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements various error reporters. 6 | 7 | package types 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "go/ast" 13 | "go/token" 14 | "strings" 15 | ) 16 | 17 | // TODO(gri) eventually assert should disappear. 18 | func assert(p bool) { 19 | if !p { 20 | panic("assertion failed") 21 | } 22 | } 23 | 24 | func unreachable() { 25 | panic("unreachable") 26 | } 27 | 28 | func (check *checker) formatMsg(format string, args []interface{}) string { 29 | for i, arg := range args { 30 | switch a := arg.(type) { 31 | case nil: 32 | args[i] = "" 33 | case operand: 34 | panic("internal error: should always pass *operand") 35 | case token.Pos: 36 | args[i] = check.fset.Position(a) 37 | case ast.Expr: 38 | args[i] = exprString(a) 39 | } 40 | } 41 | return fmt.Sprintf(format, args...) 42 | } 43 | 44 | func (check *checker) trace(pos token.Pos, format string, args ...interface{}) { 45 | fmt.Printf("%s:\t%s%s\n", 46 | check.fset.Position(pos), 47 | strings.Repeat(". ", check.indent), 48 | check.formatMsg(format, args), 49 | ) 50 | } 51 | 52 | // dump is only needed for debugging 53 | func (check *checker) dump(format string, args ...interface{}) { 54 | fmt.Println(check.formatMsg(format, args)) 55 | } 56 | 57 | func (check *checker) err(err error) { 58 | if check.firstErr == nil { 59 | check.firstErr = err 60 | } 61 | f := check.conf.Error 62 | if f == nil { 63 | panic(bailout{}) // report only first error 64 | } 65 | f(err) 66 | } 67 | 68 | func (check *checker) errorf(pos token.Pos, format string, args ...interface{}) { 69 | check.err(fmt.Errorf("%s: %s", check.fset.Position(pos), check.formatMsg(format, args))) 70 | } 71 | 72 | func (check *checker) invalidAST(pos token.Pos, format string, args ...interface{}) { 73 | check.errorf(pos, "invalid AST: "+format, args...) 74 | } 75 | 76 | func (check *checker) invalidArg(pos token.Pos, format string, args ...interface{}) { 77 | check.errorf(pos, "invalid argument: "+format, args...) 78 | } 79 | 80 | func (check *checker) invalidOp(pos token.Pos, format string, args ...interface{}) { 81 | check.errorf(pos, "invalid operation: "+format, args...) 82 | } 83 | 84 | // exprString returns a (simplified) string representation for an expression. 85 | func exprString(expr ast.Expr) string { 86 | var buf bytes.Buffer 87 | writeExpr(&buf, expr) 88 | return buf.String() 89 | } 90 | 91 | // TODO(gri) Need to merge with typeString since some expressions are types (try: ([]int)(a)) 92 | func writeExpr(buf *bytes.Buffer, expr ast.Expr) { 93 | switch x := expr.(type) { 94 | case *ast.Ident: 95 | buf.WriteString(x.Name) 96 | 97 | case *ast.BasicLit: 98 | buf.WriteString(x.Value) 99 | 100 | case *ast.FuncLit: 101 | buf.WriteString("(func literal)") 102 | 103 | case *ast.CompositeLit: 104 | buf.WriteString("(composite literal)") 105 | 106 | case *ast.ParenExpr: 107 | buf.WriteByte('(') 108 | writeExpr(buf, x.X) 109 | buf.WriteByte(')') 110 | 111 | case *ast.SelectorExpr: 112 | writeExpr(buf, x.X) 113 | buf.WriteByte('.') 114 | buf.WriteString(x.Sel.Name) 115 | 116 | case *ast.IndexExpr: 117 | writeExpr(buf, x.X) 118 | buf.WriteByte('[') 119 | writeExpr(buf, x.Index) 120 | buf.WriteByte(']') 121 | 122 | case *ast.SliceExpr: 123 | writeExpr(buf, x.X) 124 | buf.WriteByte('[') 125 | if x.Low != nil { 126 | writeExpr(buf, x.Low) 127 | } 128 | buf.WriteByte(':') 129 | if x.High != nil { 130 | writeExpr(buf, x.High) 131 | } 132 | buf.WriteByte(']') 133 | 134 | case *ast.TypeAssertExpr: 135 | writeExpr(buf, x.X) 136 | buf.WriteString(".(") 137 | // TODO(gri) expand writeExpr so that types are not handled by default case 138 | writeExpr(buf, x.Type) 139 | buf.WriteByte(')') 140 | 141 | case *ast.CallExpr: 142 | writeExpr(buf, x.Fun) 143 | buf.WriteByte('(') 144 | for i, arg := range x.Args { 145 | if i > 0 { 146 | buf.WriteString(", ") 147 | } 148 | writeExpr(buf, arg) 149 | } 150 | buf.WriteByte(')') 151 | 152 | case *ast.StarExpr: 153 | buf.WriteByte('*') 154 | writeExpr(buf, x.X) 155 | 156 | case *ast.UnaryExpr: 157 | buf.WriteString(x.Op.String()) 158 | writeExpr(buf, x.X) 159 | 160 | case *ast.BinaryExpr: 161 | // The AST preserves source-level parentheses so there is 162 | // no need to introduce parentheses here for correctness. 163 | writeExpr(buf, x.X) 164 | buf.WriteByte(' ') 165 | buf.WriteString(x.Op.String()) 166 | buf.WriteByte(' ') 167 | writeExpr(buf, x.Y) 168 | 169 | default: 170 | // TODO(gri) Consider just calling x.String(). May cause 171 | // infinite recursion if we missed a local type. 172 | fmt.Fprintf(buf, "", x) 173 | } 174 | } 175 | 176 | // typeString returns a string representation for typ. 177 | func typeString(typ Type) string { 178 | var buf bytes.Buffer 179 | writeType(&buf, typ) 180 | return buf.String() 181 | } 182 | 183 | func writeTuple(buf *bytes.Buffer, tup *Tuple, isVariadic bool) { 184 | buf.WriteByte('(') 185 | if tup != nil { 186 | for i, v := range tup.vars { 187 | if i > 0 { 188 | buf.WriteString(", ") 189 | } 190 | if v.name != "" { 191 | buf.WriteString(v.name) 192 | buf.WriteByte(' ') 193 | } 194 | typ := v.typ 195 | if isVariadic && i == len(tup.vars)-1 { 196 | buf.WriteString("...") 197 | typ = typ.(*Slice).elt 198 | } 199 | writeType(buf, typ) 200 | } 201 | } 202 | buf.WriteByte(')') 203 | } 204 | 205 | func writeSignature(buf *bytes.Buffer, sig *Signature) { 206 | writeTuple(buf, sig.params, sig.isVariadic) 207 | 208 | n := sig.results.Len() 209 | if n == 0 { 210 | // no result 211 | return 212 | } 213 | 214 | buf.WriteByte(' ') 215 | if n == 1 && sig.results.vars[0].name == "" { 216 | // single unnamed result 217 | writeType(buf, sig.results.vars[0].typ) 218 | return 219 | } 220 | 221 | // multiple or named result(s) 222 | writeTuple(buf, sig.results, false) 223 | } 224 | 225 | func writeType(buf *bytes.Buffer, typ Type) { 226 | switch t := typ.(type) { 227 | case nil: 228 | buf.WriteString("") 229 | 230 | case *Basic: 231 | buf.WriteString(t.name) 232 | 233 | case *Array: 234 | fmt.Fprintf(buf, "[%d]", t.len) 235 | writeType(buf, t.elt) 236 | 237 | case *Slice: 238 | buf.WriteString("[]") 239 | writeType(buf, t.elt) 240 | 241 | case *Struct: 242 | buf.WriteString("struct{") 243 | for i, f := range t.fields { 244 | if i > 0 { 245 | buf.WriteString("; ") 246 | } 247 | if !f.anonymous { 248 | buf.WriteString(f.name) 249 | buf.WriteByte(' ') 250 | } 251 | writeType(buf, f.typ) 252 | if tag := t.Tag(i); tag != "" { 253 | fmt.Fprintf(buf, " %q", tag) 254 | } 255 | } 256 | buf.WriteByte('}') 257 | 258 | case *Pointer: 259 | buf.WriteByte('*') 260 | writeType(buf, t.base) 261 | 262 | case *Tuple: 263 | writeTuple(buf, t, false) 264 | 265 | case *Signature: 266 | buf.WriteString("func") 267 | writeSignature(buf, t) 268 | 269 | case *Builtin: 270 | fmt.Fprintf(buf, "", t.name) 271 | 272 | case *Interface: 273 | buf.WriteString("interface{") 274 | for i, m := range t.methods { 275 | if i > 0 { 276 | buf.WriteString("; ") 277 | } 278 | buf.WriteString(m.name) 279 | writeSignature(buf, m.typ.(*Signature)) 280 | } 281 | buf.WriteByte('}') 282 | 283 | case *Map: 284 | buf.WriteString("map[") 285 | writeType(buf, t.key) 286 | buf.WriteByte(']') 287 | writeType(buf, t.elt) 288 | 289 | case *Chan: 290 | var s string 291 | switch t.dir { 292 | case ast.SEND: 293 | s = "chan<- " 294 | case ast.RECV: 295 | s = "<-chan " 296 | default: 297 | s = "chan " 298 | } 299 | buf.WriteString(s) 300 | writeType(buf, t.elt) 301 | 302 | case *Named: 303 | s := "" 304 | if obj := t.obj; obj != nil { 305 | if obj.pkg != nil { 306 | // TODO(gri) Ideally we only want the qualification 307 | // if we are referring to a type that was imported; 308 | // but not when we are at the "top". We don't have 309 | // this information easily available here. 310 | buf.WriteString(obj.pkg.name) 311 | buf.WriteByte('.') 312 | } 313 | s = t.obj.name 314 | } 315 | buf.WriteString(s) 316 | 317 | default: 318 | // For externally defined implementations of Type. 319 | buf.WriteString(t.String()) 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /types/eval.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements New, Eval and EvalNode. 6 | 7 | package types 8 | 9 | import ( 10 | "fmt" 11 | "go/ast" 12 | "go/parser" 13 | "go/token" 14 | 15 | "code.google.com/p/go.tools/go/exact" 16 | ) 17 | 18 | // New is a convenience function to create a new type from a given 19 | // expression or type literal string evaluated in Universe scope. 20 | // New(str) is shorthand for Eval(str, nil, nil), but only returns 21 | // the type result, and panics in case of an error. 22 | // Position info for objects in the result type is undefined. 23 | // 24 | func New(str string) Type { 25 | typ, _, err := Eval(str, nil, nil) 26 | if err != nil { 27 | panic(err) 28 | } 29 | return typ 30 | } 31 | 32 | // Eval returns the type and, if constant, the value for the 33 | // expression or type literal string str evaluated in scope. 34 | // If the expression contains function literals, the function 35 | // bodies are ignored (though they must be syntactically correct). 36 | // 37 | // If pkg == nil, the Universe scope is used and the provided 38 | // scope is ignored. Otherwise, the scope must belong to the 39 | // package (either the package scope, or nested within the 40 | // package scope). 41 | // 42 | // An error is returned if the scope is incorrect, the string 43 | // has syntax errors, or if it cannot be evaluated in the scope. 44 | // Position info for objects in the result type is undefined. 45 | // 46 | // Note: Eval should not be used instead of running Check to compute 47 | // types and values, but in addition to Check. Eval will re-evaluate 48 | // its argument each time, and it also does not know about the context 49 | // in which an expression is used (e.g., an assignment). Thus, top- 50 | // level untyped constants will return an untyped type rather then the 51 | // respective context-specific type. 52 | // 53 | func Eval(str string, pkg *Package, scope *Scope) (typ Type, val exact.Value, err error) { 54 | node, err := parser.ParseExpr(str) 55 | if err != nil { 56 | return nil, nil, err 57 | } 58 | 59 | // Create a file set that looks structurally identical to the 60 | // one created by parser.ParseExpr for correct error positions. 61 | fset := token.NewFileSet() 62 | fset.AddFile("", len(str), fset.Base()).SetLinesForContent([]byte(str)) 63 | 64 | return EvalNode(fset, node, pkg, scope) 65 | } 66 | 67 | // EvalNode is like Eval but instead of string it accepts 68 | // an expression node and respective file set. 69 | // 70 | // An error is returned if the scope is incorrect 71 | // if the node cannot be evaluated in the scope. 72 | // 73 | func EvalNode(fset *token.FileSet, node ast.Expr, pkg *Package, scope *Scope) (typ Type, val exact.Value, err error) { 74 | // verify package/scope relationship 75 | if pkg == nil { 76 | scope = Universe 77 | } else { 78 | s := scope 79 | for s != nil && s != pkg.scope { 80 | s = s.parent 81 | } 82 | // s == nil || s == pkg.scope 83 | if s == nil { 84 | return nil, nil, fmt.Errorf("scope does not belong to package %s", pkg.name) 85 | } 86 | } 87 | 88 | // initialize checker 89 | var conf Config 90 | check := newChecker(&conf, fset, pkg) 91 | check.topScope = scope 92 | defer check.handleBailout(&err) 93 | 94 | // evaluate node 95 | var x operand 96 | check.exprOrType(&x, node) 97 | switch x.mode { 98 | case invalid, novalue: 99 | fallthrough 100 | default: 101 | unreachable() // or bailed out with error 102 | case constant: 103 | val = x.val 104 | fallthrough 105 | case typexpr, variable, mapindex, value, commaok: 106 | typ = x.typ 107 | } 108 | 109 | return 110 | } 111 | -------------------------------------------------------------------------------- /types/eval_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests for Eval. 6 | 7 | package types 8 | 9 | import ( 10 | "go/ast" 11 | "go/parser" 12 | "go/token" 13 | "strings" 14 | "testing" 15 | ) 16 | 17 | func testEval(t *testing.T, pkg *Package, scope *Scope, str string, typ Type, typStr, valStr string) { 18 | gotTyp, gotVal, err := Eval(str, pkg, scope) 19 | if err != nil { 20 | t.Errorf("Eval(%q) failed: %s", str, err) 21 | return 22 | } 23 | if gotTyp == nil { 24 | t.Errorf("Eval(%q) got nil type but no error", str) 25 | return 26 | } 27 | 28 | // compare types 29 | if typ != nil { 30 | // we have a type, check identity 31 | if !IsIdentical(gotTyp, typ) { 32 | t.Errorf("Eval(%q) got type %s, want %s", str, gotTyp, typ) 33 | return 34 | } 35 | } else { 36 | // we have a string, compare type string 37 | gotStr := gotTyp.String() 38 | if gotStr != typStr { 39 | t.Errorf("Eval(%q) got type %s, want %s", str, gotStr, typStr) 40 | return 41 | } 42 | } 43 | 44 | // compare values 45 | gotStr := "" 46 | if gotVal != nil { 47 | gotStr = gotVal.String() 48 | } 49 | if gotStr != valStr { 50 | t.Errorf("Eval(%q) got value %s, want %s", str, gotStr, valStr) 51 | } 52 | } 53 | 54 | func TestEvalBasic(t *testing.T) { 55 | for _, typ := range Typ[Bool : String+1] { 56 | testEval(t, nil, nil, typ.name, typ, "", "") 57 | } 58 | } 59 | 60 | func TestEvalComposite(t *testing.T) { 61 | for _, test := range testTypes { 62 | testEval(t, nil, nil, test.src, nil, test.str, "") 63 | } 64 | } 65 | 66 | func TestEvalArith(t *testing.T) { 67 | var tests = []string{ 68 | `true`, 69 | `false == false`, 70 | `12345678 + 87654321 == 99999999`, 71 | `10 * 20 == 200`, 72 | `(1<<1000)*2 >> 100 == 2<<900`, 73 | `"foo" + "bar" == "foobar"`, 74 | `"abc" <= "bcd"`, 75 | `len([10]struct{}{}) == 2*5`, 76 | } 77 | for _, test := range tests { 78 | testEval(t, nil, nil, test, Typ[UntypedBool], "", "true") 79 | } 80 | } 81 | 82 | func TestEvalContext(t *testing.T) { 83 | src := ` 84 | package p 85 | import "fmt" 86 | import m "math" 87 | const c = 3.0 88 | type T []int 89 | func f(a int, s string) float64 { 90 | fmt.Println("calling f") 91 | _ = m.Pi // use package math 92 | const d int = c + 1 93 | var x int 94 | x = a + len(s) 95 | return float64(x) 96 | } 97 | ` 98 | fset := token.NewFileSet() 99 | file, err := parser.ParseFile(fset, "p", src, 0) 100 | if err != nil { 101 | t.Fatal(err) 102 | } 103 | 104 | pkg, err := Check("p", fset, []*ast.File{file}) 105 | if err != nil { 106 | t.Fatal(err) 107 | } 108 | 109 | pkgScope := pkg.scope 110 | if n := pkgScope.NumChildren(); n != 1 { 111 | t.Fatalf("got %d file scopes, want 1", n) 112 | } 113 | 114 | fileScope := pkgScope.Child(0) 115 | if n := fileScope.NumChildren(); n != 1 { 116 | t.Fatalf("got %d functions scopes, want 1", n) 117 | } 118 | 119 | funcScope := fileScope.Child(0) 120 | 121 | var tests = []string{ 122 | `true => true, untyped boolean`, 123 | `fmt.Println => , func(a·3 ...interface{}) (n·1 int, err·2 error)`, 124 | `c => 3, untyped float`, 125 | `T => , p.T`, 126 | `a => , int`, 127 | `s => , string`, 128 | `d => 4, int`, 129 | `x => , int`, 130 | `d/c => 1, int`, 131 | `c/2 => 3/2, untyped float`, 132 | `m.Pi < m.E => false, untyped boolean`, 133 | } 134 | for _, test := range tests { 135 | str, typ := split(test, ", ") 136 | str, val := split(str, "=>") 137 | testEval(t, pkg, funcScope, str, nil, typ, val) 138 | } 139 | } 140 | 141 | // split splits string s at the first occurrence of s. 142 | func split(s, sep string) (string, string) { 143 | i := strings.Index(s, sep) 144 | return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):]) 145 | } 146 | -------------------------------------------------------------------------------- /types/exportdata.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements FindGcExportData. 6 | 7 | package types 8 | 9 | import ( 10 | "bufio" 11 | "errors" 12 | "fmt" 13 | "io" 14 | "strconv" 15 | "strings" 16 | ) 17 | 18 | func readGopackHeader(r *bufio.Reader) (name string, size int, err error) { 19 | // See $GOROOT/include/ar.h. 20 | hdr := make([]byte, 16+12+6+6+8+10+2) 21 | _, err = io.ReadFull(r, hdr) 22 | if err != nil { 23 | return 24 | } 25 | // leave for debugging 26 | if false { 27 | fmt.Printf("header: %s", hdr) 28 | } 29 | s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10])) 30 | size, err = strconv.Atoi(s) 31 | if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' { 32 | err = errors.New("invalid archive header") 33 | return 34 | } 35 | name = strings.TrimSpace(string(hdr[:16])) 36 | return 37 | } 38 | 39 | // FindGcExportData positions the reader r at the beginning of the 40 | // export data section of an underlying GC-created object/archive 41 | // file by reading from it. The reader must be positioned at the 42 | // start of the file before calling this function. 43 | // 44 | func FindGcExportData(r *bufio.Reader) (err error) { 45 | // Read first line to make sure this is an object file. 46 | line, err := r.ReadSlice('\n') 47 | if err != nil { 48 | return 49 | } 50 | if string(line) == "!\n" { 51 | // Archive file. Scan to __.PKGDEF, which should 52 | // be second archive entry. 53 | var name string 54 | var size int 55 | 56 | // First entry should be __.GOSYMDEF. 57 | // Older archives used __.SYMDEF, so allow that too. 58 | // Read and discard. 59 | if name, size, err = readGopackHeader(r); err != nil { 60 | return 61 | } 62 | if name != "__.SYMDEF" && name != "__.GOSYMDEF" { 63 | err = errors.New("go archive does not begin with __.SYMDEF or __.GOSYMDEF") 64 | return 65 | } 66 | const block = 4096 67 | tmp := make([]byte, block) 68 | for size > 0 { 69 | n := size 70 | if n > block { 71 | n = block 72 | } 73 | if _, err = io.ReadFull(r, tmp[:n]); err != nil { 74 | return 75 | } 76 | size -= n 77 | } 78 | 79 | // Second entry should be __.PKGDEF. 80 | if name, size, err = readGopackHeader(r); err != nil { 81 | return 82 | } 83 | if name != "__.PKGDEF" { 84 | err = errors.New("go archive is missing __.PKGDEF") 85 | return 86 | } 87 | 88 | // Read first line of __.PKGDEF data, so that line 89 | // is once again the first line of the input. 90 | if line, err = r.ReadSlice('\n'); err != nil { 91 | return 92 | } 93 | } 94 | 95 | // Now at __.PKGDEF in archive or still at beginning of file. 96 | // Either way, line should begin with "go object ". 97 | if !strings.HasPrefix(string(line), "go object ") { 98 | err = errors.New("not a go object file") 99 | return 100 | } 101 | 102 | // Skip over object header to export data. 103 | // Begins after first line with $$. 104 | for line[0] != '$' { 105 | if line, err = r.ReadSlice('\n'); err != nil { 106 | return 107 | } 108 | } 109 | 110 | return 111 | } 112 | -------------------------------------------------------------------------------- /types/gcimporter_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package types 6 | 7 | import ( 8 | "go/ast" 9 | "go/build" 10 | "io/ioutil" 11 | "os" 12 | "os/exec" 13 | "path/filepath" 14 | "runtime" 15 | "strings" 16 | "testing" 17 | "time" 18 | ) 19 | 20 | var gcPath string // Go compiler path 21 | 22 | func init() { 23 | // determine compiler 24 | var gc string 25 | switch runtime.GOARCH { 26 | case "386": 27 | gc = "8g" 28 | case "amd64": 29 | gc = "6g" 30 | case "arm": 31 | gc = "5g" 32 | default: 33 | gcPath = "unknown-GOARCH-compiler" 34 | return 35 | } 36 | gcPath = filepath.Join(build.ToolDir, gc) 37 | } 38 | 39 | func compile(t *testing.T, dirname, filename string) string { 40 | cmd := exec.Command(gcPath, filename) 41 | cmd.Dir = dirname 42 | out, err := cmd.CombinedOutput() 43 | if err != nil { 44 | t.Logf("%s", out) 45 | t.Fatalf("%s %s failed: %s", gcPath, filename, err) 46 | } 47 | archCh, _ := build.ArchChar(runtime.GOARCH) 48 | // filename should end with ".go" 49 | return filepath.Join(dirname, filename[:len(filename)-2]+archCh) 50 | } 51 | 52 | // Use the same global imports map for all tests. The effect is 53 | // as if all tested packages were imported into a single package. 54 | var imports = make(map[string]*Package) 55 | 56 | func testPath(t *testing.T, path string) bool { 57 | t0 := time.Now() 58 | _, err := GcImport(imports, path) 59 | if err != nil { 60 | t.Errorf("testPath(%s): %s", path, err) 61 | return false 62 | } 63 | t.Logf("testPath(%s): %v", path, time.Since(t0)) 64 | return true 65 | } 66 | 67 | const maxTime = 30 * time.Second 68 | 69 | func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) { 70 | dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir) 71 | list, err := ioutil.ReadDir(dirname) 72 | if err != nil { 73 | t.Fatalf("testDir(%s): %s", dirname, err) 74 | } 75 | for _, f := range list { 76 | if time.Now().After(endTime) { 77 | t.Log("testing time used up") 78 | return 79 | } 80 | switch { 81 | case !f.IsDir(): 82 | // try extensions 83 | for _, ext := range pkgExts { 84 | if strings.HasSuffix(f.Name(), ext) { 85 | name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension 86 | if testPath(t, filepath.Join(dir, name)) { 87 | nimports++ 88 | } 89 | } 90 | } 91 | case f.IsDir(): 92 | nimports += testDir(t, filepath.Join(dir, f.Name()), endTime) 93 | } 94 | } 95 | return 96 | } 97 | 98 | func TestGcImport(t *testing.T) { 99 | // On cross-compile builds, the path will not exist. 100 | // Need to use GOHOSTOS, which is not available. 101 | if _, err := os.Stat(gcPath); err != nil { 102 | t.Skipf("skipping test: %v", err) 103 | } 104 | 105 | if outFn := compile(t, "testdata", "exports.go"); outFn != "" { 106 | defer os.Remove(outFn) 107 | } 108 | 109 | nimports := 0 110 | if testPath(t, "./testdata/exports") { 111 | nimports++ 112 | } 113 | nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages 114 | t.Logf("tested %d imports", nimports) 115 | } 116 | 117 | var importedObjectTests = []struct { 118 | name string 119 | kind ast.ObjKind 120 | typ string 121 | }{ 122 | {"unsafe.Pointer", ast.Typ, "Pointer"}, 123 | {"math.Pi", ast.Con, "untyped float"}, 124 | {"io.Reader", ast.Typ, "interface{Read(p []byte) (n int, err error)}"}, 125 | {"io.ReadWriter", ast.Typ, "interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"}, 126 | {"math.Sin", ast.Fun, "func(x·2 float64) (_ float64)"}, 127 | // TODO(gri) add more tests 128 | } 129 | 130 | func TestGcImportedTypes(t *testing.T) { 131 | // This package does not yet know how to read gccgo export data. 132 | if runtime.Compiler == "gccgo" { 133 | return 134 | } 135 | for _, test := range importedObjectTests { 136 | s := strings.Split(test.name, ".") 137 | if len(s) != 2 { 138 | t.Fatal("inconsistent test data") 139 | } 140 | importPath := s[0] 141 | objName := s[1] 142 | 143 | pkg, err := GcImport(imports, importPath) 144 | if err != nil { 145 | t.Error(err) 146 | continue 147 | } 148 | 149 | obj := pkg.scope.Lookup(objName) 150 | 151 | // TODO(gri) should define an accessor on Object 152 | var kind ast.ObjKind 153 | var typ Type 154 | switch obj := obj.(type) { 155 | case *Const: 156 | kind = ast.Con 157 | typ = obj.typ 158 | case *TypeName: 159 | kind = ast.Typ 160 | typ = obj.typ 161 | case *Var: 162 | kind = ast.Var 163 | typ = obj.typ 164 | case *Func: 165 | kind = ast.Fun 166 | typ = obj.typ 167 | default: 168 | unreachable() 169 | } 170 | 171 | if kind != test.kind { 172 | t.Errorf("%s: got kind = %q; want %q", test.name, kind, test.kind) 173 | } 174 | 175 | str := typeString(typ.Underlying()) 176 | if str != test.typ { 177 | t.Errorf("%s: got type = %q; want %q", test.name, typ, test.typ) 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /types/go11.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !go1.2 6 | 7 | package types 8 | 9 | import "go/ast" 10 | 11 | func slice3(x *ast.SliceExpr) bool { 12 | return false 13 | } 14 | 15 | func sliceMax(x *ast.SliceExpr) ast.Expr { 16 | return nil 17 | } 18 | -------------------------------------------------------------------------------- /types/go12.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build go1.2 6 | 7 | package types 8 | 9 | import "go/ast" 10 | 11 | func slice3(x *ast.SliceExpr) bool { 12 | return x.Slice3 13 | } 14 | 15 | func sliceMax(x *ast.SliceExpr) ast.Expr { 16 | return x.Max 17 | } 18 | -------------------------------------------------------------------------------- /types/issues_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements tests for various issues. 6 | 7 | package types 8 | 9 | import ( 10 | "go/ast" 11 | "go/parser" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func TestIssue5770(t *testing.T) { 17 | src := `package p; type S struct{T}` 18 | f, err := parser.ParseFile(fset, "", src, 0) 19 | if err != nil { 20 | t.Fatal(err) 21 | } 22 | 23 | _, err = Check(f.Name.Name, fset, []*ast.File{f}) // do not crash 24 | want := "undeclared name: T" 25 | if err == nil || !strings.Contains(err.Error(), want) { 26 | t.Errorf("got: %v; want: %s", err, want) 27 | } 28 | } 29 | 30 | func TestIssue5849(t *testing.T) { 31 | src := ` 32 | package p 33 | var ( 34 | s uint 35 | _ = uint8(8) 36 | _ = uint16(16) << s 37 | _ = uint32(32 << s) 38 | _ = uint64(64 << s + s) 39 | _ = (interface{})("foo") 40 | _ = (interface{})(nil) 41 | )` 42 | f, err := parser.ParseFile(fset, "", src, 0) 43 | if err != nil { 44 | t.Fatal(err) 45 | } 46 | 47 | var conf Config 48 | types := make(map[ast.Expr]Type) 49 | _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types}) 50 | if err != nil { 51 | t.Fatal(err) 52 | } 53 | 54 | for x, typ := range types { 55 | var want Type 56 | switch x := x.(type) { 57 | case *ast.BasicLit: 58 | switch x.Value { 59 | case `8`: 60 | want = Typ[Uint8] 61 | case `16`: 62 | want = Typ[Uint16] 63 | case `32`: 64 | want = Typ[Uint32] 65 | case `64`: 66 | want = Typ[Uint] // because of "+ s", s is of type uint 67 | case `"foo"`: 68 | want = Typ[String] 69 | } 70 | case *ast.Ident: 71 | if x.Name == "nil" { 72 | want = Typ[UntypedNil] 73 | } 74 | } 75 | if want != nil && !IsIdentical(typ, want) { 76 | t.Errorf("got %s; want %s", typ, want) 77 | } 78 | } 79 | } 80 | 81 | func TestIssue5815(t *testing.T) { 82 | pkg, err := GcImport(make(map[string]*Package), "strings") 83 | if err != nil { 84 | t.Fatal(err) 85 | } 86 | 87 | for _, obj := range pkg.scope.elems { 88 | if obj.Pkg() == nil { 89 | t.Errorf("no pkg for %s", obj) 90 | } 91 | if tname, _ := obj.(*TypeName); tname != nil { 92 | if named, _ := tname.typ.(*Named); named != nil { 93 | for _, m := range named.methods { 94 | if m.pkg == nil { 95 | t.Errorf("no pkg for %s", m) 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | func TestIssue6413(t *testing.T) { 104 | src := ` 105 | package p 106 | func f() int { 107 | defer f() 108 | go f() 109 | return 0 110 | } 111 | ` 112 | f, err := parser.ParseFile(fset, "", src, 0) 113 | if err != nil { 114 | t.Fatal(err) 115 | } 116 | 117 | var conf Config 118 | types := make(map[ast.Expr]Type) 119 | _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types}) 120 | if err != nil { 121 | t.Fatal(err) 122 | } 123 | 124 | want := Typ[Int] 125 | n := 0 126 | for x, got := range types { 127 | if _, ok := x.(*ast.CallExpr); ok { 128 | if got != want { 129 | t.Errorf("%s: got %s; want %s", fset.Position(x.Pos()), got, want) 130 | } 131 | n++ 132 | } 133 | } 134 | 135 | if n != 2 { 136 | t.Errorf("got %d CallExprs; want 2", n) 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /types/labels.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package types 6 | 7 | import ( 8 | "go/ast" 9 | "go/token" 10 | ) 11 | 12 | // labels checks correct label use in body. 13 | func (check *checker) labels(body *ast.BlockStmt) { 14 | // set of all labels in this body 15 | all := NewScope(nil) 16 | 17 | fwdJumps := check.blockBranches(all, nil, nil, body.List) 18 | 19 | // If there are any forward jumps left, no label was found for 20 | // the corresponding goto statements. Either those labels were 21 | // never defined, or they are inside blocks and not reachable 22 | // for the respective gotos. 23 | for _, jmp := range fwdJumps { 24 | var msg string 25 | name := jmp.Label.Name 26 | if alt := all.Lookup(name); alt != nil { 27 | msg = "goto %s jumps into block" 28 | alt.(*Label).used = true // avoid another error 29 | } else { 30 | msg = "label %s not declared" 31 | } 32 | check.errorf(jmp.Label.Pos(), msg, name) 33 | } 34 | 35 | // spec: "It is illegal to define a label that is never used." 36 | for _, obj := range all.elems { 37 | if lbl := obj.(*Label); !lbl.used { 38 | check.errorf(lbl.pos, "label %s declared but not used", lbl.name) 39 | } 40 | } 41 | } 42 | 43 | // A block tracks label declarations in a block and its enclosing blocks. 44 | type block struct { 45 | parent *block // enclosing block 46 | lstmt *ast.LabeledStmt // labeled statement to which this block belongs, or nil 47 | labels map[string]*ast.LabeledStmt // allocated lazily 48 | } 49 | 50 | // insert records a new label declaration for the current block. 51 | // The label must not have been declared before in any block. 52 | func (b *block) insert(s *ast.LabeledStmt) { 53 | name := s.Label.Name 54 | if debug { 55 | assert(b.gotoTarget(name) == nil) 56 | } 57 | labels := b.labels 58 | if labels == nil { 59 | labels = make(map[string]*ast.LabeledStmt) 60 | b.labels = labels 61 | } 62 | labels[name] = s 63 | } 64 | 65 | // gotoTarget returns the labeled statement in the current 66 | // or an enclosing block with the given label name, or nil. 67 | func (b *block) gotoTarget(name string) *ast.LabeledStmt { 68 | for s := b; s != nil; s = s.parent { 69 | if t := s.labels[name]; t != nil { 70 | return t 71 | } 72 | } 73 | return nil 74 | } 75 | 76 | // enclosingTarget returns the innermost enclosing labeled 77 | // statement with the given label name, or nil. 78 | func (b *block) enclosingTarget(name string) *ast.LabeledStmt { 79 | for s := b; s != nil; s = s.parent { 80 | if t := s.lstmt; t != nil && t.Label.Name == name { 81 | return t 82 | } 83 | } 84 | return nil 85 | } 86 | 87 | // blockBranches processes a block's statement list and returns the set of outgoing forward jumps. 88 | // all is the scope of all declared labels, parent the set of labels declared in the immediately 89 | // enclosing block, and lstmt is the labeled statement this block is associated with (or nil). 90 | func (check *checker) blockBranches(all *Scope, parent *block, lstmt *ast.LabeledStmt, list []ast.Stmt) []*ast.BranchStmt { 91 | b := &block{parent: parent, lstmt: lstmt} 92 | 93 | var ( 94 | varDeclPos token.Pos 95 | fwdJumps, badJumps []*ast.BranchStmt 96 | ) 97 | 98 | // All forward jumps jumping over a variable declaration are possibly 99 | // invalid (they may still jump out of the block and be ok). 100 | // recordVarDecl records them for the given position. 101 | recordVarDecl := func(pos token.Pos) { 102 | varDeclPos = pos 103 | badJumps = append(badJumps[:0], fwdJumps...) // copy fwdJumps to badJumps 104 | } 105 | 106 | jumpsOverVarDecl := func(jmp *ast.BranchStmt) bool { 107 | if varDeclPos.IsValid() { 108 | for _, bad := range badJumps { 109 | if jmp == bad { 110 | return true 111 | } 112 | } 113 | } 114 | return false 115 | } 116 | 117 | blockBranches := func(lstmt *ast.LabeledStmt, list []ast.Stmt) { 118 | // Unresolved forward jumps inside the nested block 119 | // become forward jumps in the current block. 120 | fwdJumps = append(fwdJumps, check.blockBranches(all, b, lstmt, list)...) 121 | } 122 | 123 | var stmtBranches func(ast.Stmt) 124 | stmtBranches = func(s ast.Stmt) { 125 | switch s := s.(type) { 126 | case *ast.DeclStmt: 127 | if d, _ := s.Decl.(*ast.GenDecl); d != nil && d.Tok == token.VAR { 128 | recordVarDecl(d.Pos()) 129 | } 130 | 131 | case *ast.LabeledStmt: 132 | // declare label 133 | name := s.Label.Name 134 | lbl := NewLabel(s.Label.Pos(), name) 135 | if alt := all.Insert(lbl); alt != nil { 136 | check.errorf(lbl.pos, "label %s already declared", name) 137 | check.reportAltDecl(alt) 138 | // ok to continue 139 | } else { 140 | b.insert(s) 141 | check.recordObject(s.Label, lbl) 142 | } 143 | // resolve matching forward jumps and remove them from fwdJumps 144 | i := 0 145 | for _, jmp := range fwdJumps { 146 | if jmp.Label.Name == name { 147 | // match 148 | lbl.used = true 149 | check.recordObject(jmp.Label, lbl) 150 | if jumpsOverVarDecl(jmp) { 151 | check.errorf( 152 | jmp.Label.Pos(), 153 | "goto %s jumps over variable declaration at line %d", 154 | name, 155 | check.fset.Position(varDeclPos).Line, 156 | ) 157 | // ok to continue 158 | } 159 | } else { 160 | // no match - record new forward jump 161 | fwdJumps[i] = jmp 162 | i++ 163 | } 164 | } 165 | fwdJumps = fwdJumps[:i] 166 | lstmt = s 167 | stmtBranches(s.Stmt) 168 | 169 | case *ast.BranchStmt: 170 | if s.Label == nil { 171 | return // checked in 1st pass (check.stmt) 172 | } 173 | 174 | // determine and validate target 175 | name := s.Label.Name 176 | switch s.Tok { 177 | case token.BREAK: 178 | // spec: "If there is a label, it must be that of an enclosing 179 | // "for", "switch", or "select" statement, and that is the one 180 | // whose execution terminates." 181 | valid := false 182 | if t := b.enclosingTarget(name); t != nil { 183 | switch t.Stmt.(type) { 184 | case *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt, *ast.ForStmt, *ast.RangeStmt: 185 | valid = true 186 | } 187 | } 188 | if !valid { 189 | check.errorf(s.Label.Pos(), "invalid break label %s", name) 190 | return 191 | } 192 | 193 | case token.CONTINUE: 194 | // spec: "If there is a label, it must be that of an enclosing 195 | // "for" statement, and that is the one whose execution advances." 196 | valid := false 197 | if t := b.enclosingTarget(name); t != nil { 198 | switch t.Stmt.(type) { 199 | case *ast.ForStmt, *ast.RangeStmt: 200 | valid = true 201 | } 202 | } 203 | if !valid { 204 | check.errorf(s.Label.Pos(), "invalid continue label %s", name) 205 | return 206 | } 207 | 208 | case token.GOTO: 209 | if b.gotoTarget(name) == nil { 210 | // label may be declared later - add branch to forward jumps 211 | fwdJumps = append(fwdJumps, s) 212 | return 213 | } 214 | 215 | default: 216 | check.invalidAST(s.Pos(), "branch statement: %s %s", s.Tok, name) 217 | return 218 | } 219 | 220 | // record label use 221 | obj := all.Lookup(name) 222 | obj.(*Label).used = true 223 | check.recordObject(s.Label, obj) 224 | 225 | case *ast.AssignStmt: 226 | if s.Tok == token.DEFINE { 227 | recordVarDecl(s.Pos()) 228 | } 229 | 230 | case *ast.BlockStmt: 231 | blockBranches(lstmt, s.List) 232 | 233 | case *ast.IfStmt: 234 | stmtBranches(s.Body) 235 | if s.Else != nil { 236 | stmtBranches(s.Else) 237 | } 238 | 239 | case *ast.CaseClause: 240 | blockBranches(nil, s.Body) 241 | 242 | case *ast.SwitchStmt: 243 | stmtBranches(s.Body) 244 | 245 | case *ast.TypeSwitchStmt: 246 | stmtBranches(s.Body) 247 | 248 | case *ast.CommClause: 249 | blockBranches(nil, s.Body) 250 | 251 | case *ast.SelectStmt: 252 | stmtBranches(s.Body) 253 | 254 | case *ast.ForStmt: 255 | stmtBranches(s.Body) 256 | 257 | case *ast.RangeStmt: 258 | stmtBranches(s.Body) 259 | } 260 | } 261 | 262 | for _, s := range list { 263 | stmtBranches(s) 264 | } 265 | 266 | return fwdJumps 267 | } 268 | -------------------------------------------------------------------------------- /types/objset.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements objsets. 6 | // 7 | // An objset is similar to a Scope but objset elements 8 | // are identified by their unique id, instead of their 9 | // object name. 10 | 11 | package types 12 | 13 | // An objset is a set of objects identified by their unique id. 14 | // The zero value for objset is a ready-to-use empty objset. 15 | type objset struct { 16 | elems map[string]Object // allocated lazily 17 | } 18 | 19 | // insert attempts to insert an object obj into objset s. 20 | // If s already contains an alternative object alt with 21 | // the same name, insert leaves s unchanged and returns alt. 22 | // Otherwise it inserts obj and returns nil. Objects with 23 | // blank "_" names are ignored. 24 | func (s *objset) insert(obj Object) Object { 25 | name := obj.Name() 26 | if name == "_" { 27 | return nil 28 | } 29 | id := Id(obj.Pkg(), name) 30 | if alt := s.elems[id]; alt != nil { 31 | return alt 32 | } 33 | if s.elems == nil { 34 | s.elems = make(map[string]Object) 35 | } 36 | s.elems[id] = obj 37 | return nil 38 | } 39 | -------------------------------------------------------------------------------- /types/overload.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "go/ast" 5 | "go/token" 6 | "strings" 7 | ) 8 | 9 | type OverloadInfo struct { 10 | Func *Func 11 | Recv ast.Expr 12 | Oper ast.Expr 13 | } 14 | 15 | func (check *checker) overloadTokenToName(op token.Token) string { 16 | switch op { 17 | case token.ADD: 18 | return "Add" 19 | case token.SUB: 20 | return "Subtract" 21 | case token.MUL: 22 | return "Multiply" 23 | case token.QUO: 24 | return "Divide" 25 | case token.REM: 26 | return "Modulo" 27 | case token.AND: 28 | return "BitAnd" 29 | case token.OR: 30 | return "BitOr" 31 | case token.SHL: 32 | return "BitShiftLeft" 33 | case token.SHR: 34 | return "BitShiftRight" 35 | case token.AND_NOT: 36 | return "BitAndNot" 37 | case token.XOR: 38 | return "BitXor" 39 | case token.LAND: 40 | return "And" 41 | case token.LOR: 42 | return "Or" 43 | case token.EQL: 44 | return "Equal" 45 | case token.LSS: 46 | return "Less" 47 | case token.GTR: 48 | return "Greater" 49 | case token.NOT: 50 | return "Not" 51 | case token.NEQ: 52 | return "NotEqual" 53 | case token.LEQ: 54 | return "LessOrEqual" 55 | case token.GEQ: 56 | return "GreaterOrEqual" 57 | default: 58 | return "" 59 | } 60 | } 61 | 62 | func (check *checker) overloadIsAddressable(recv *operand) bool { 63 | if recv.mode == variable { 64 | return true 65 | } 66 | 67 | switch recv.expr.(type) { 68 | case *ast.SliceExpr, *ast.CompositeLit, *ast.StarExpr: 69 | return true 70 | } 71 | 72 | return false 73 | } 74 | 75 | func (check *checker) overloadOperandType(oper *operand) Type { 76 | if oper == nil { 77 | return Typ[Invalid] 78 | } 79 | 80 | return oper.typ 81 | } 82 | 83 | func (check *checker) withIgnoredErrors(f func()) bool { 84 | err := check.firstErr 85 | errorf := check.conf.Error 86 | 87 | ret := true 88 | 89 | check.conf.Error = func(error) { 90 | ret = false 91 | } 92 | 93 | f() 94 | 95 | check.firstErr = err 96 | check.conf.Error = errorf 97 | 98 | return ret 99 | } 100 | 101 | func (check *checker) overloadLookupType(recv Type, oper *operand, name string) (*Func, Type) { 102 | ms := recv.MethodSet() 103 | 104 | for i := 0; i < ms.Len(); i++ { 105 | sel := ms.At(i) 106 | 107 | if sel.Kind() != MethodVal { 108 | continue 109 | } 110 | 111 | f := sel.Obj().(*Func) 112 | 113 | if !strings.HasPrefix(f.Name(), name) { 114 | continue 115 | } 116 | 117 | sig := f.Type().(*Signature) 118 | 119 | if sig.IsVariadic() { 120 | continue 121 | } 122 | 123 | if sig.Results().Len() != 1 { 124 | continue 125 | } 126 | 127 | params := sig.Params() 128 | 129 | if oper != nil { 130 | if params.Len() != 1 { 131 | continue 132 | } 133 | 134 | pt := params.At(0) 135 | 136 | if isUntyped(oper.typ) { 137 | mode := oper.mode 138 | 139 | ok := check.withIgnoredErrors(func() { 140 | check.convertUntyped(oper, pt.Type()) 141 | }) 142 | 143 | if !ok { 144 | oper.mode = mode 145 | continue 146 | } 147 | } else if pt.Type().String() != oper.typ.String() { 148 | continue 149 | } 150 | } else if params.Len() != 0 { 151 | continue 152 | } 153 | 154 | return f, sig.Results().At(0).Type() 155 | } 156 | 157 | return nil, Typ[Invalid] 158 | } 159 | 160 | func (check *checker) overloadLookupAddressable(recv *operand, oper *operand, name string) (*Func, Type) { 161 | if _, ok := recv.typ.(*Pointer); !ok { 162 | if check.overloadIsAddressable(recv) { 163 | return check.overloadLookupType(NewPointer(recv.typ), oper, name) 164 | } 165 | } 166 | 167 | return nil, Typ[Invalid] 168 | } 169 | 170 | func (check *checker) overloadLookup(recv *operand, oper *operand, name string) (*Func, Type) { 171 | if isUntyped(recv.typ) { 172 | return nil, Typ[Invalid] 173 | } 174 | 175 | // Try addressable first 176 | f, tp := check.overloadLookupAddressable(recv, oper, name) 177 | 178 | if f == nil { 179 | f, tp = check.overloadLookupType(recv.typ, oper, name) 180 | } 181 | 182 | return f, tp 183 | } 184 | 185 | func (check *checker) overloadBinaryOperator(x, y *operand, e ast.Expr) bool { 186 | xuntyp := isUntyped(x.typ) 187 | yuntyp := isUntyped(y.typ) 188 | 189 | if xuntyp && yuntyp { 190 | return false 191 | } 192 | 193 | be, ok := e.(*ast.BinaryExpr) 194 | 195 | if !ok { 196 | return false 197 | } 198 | 199 | n := check.overloadTokenToName(be.Op) 200 | 201 | if len(n) == 0 { 202 | return false 203 | } 204 | 205 | // Lookup method name on x satisfying type of y 206 | recv := x 207 | oper := y 208 | 209 | f, typ := check.overloadLookup(recv, oper, "Op_"+n) 210 | 211 | if f == nil { 212 | // Pre maybe? 213 | oper, recv = recv, oper 214 | 215 | f, typ = check.overloadLookup(recv, oper, "Op_Pre"+n) 216 | 217 | if f == nil { 218 | return false 219 | } 220 | } 221 | 222 | check.pkg.overloads[e] = OverloadInfo{ 223 | Func: f, 224 | Recv: recv.expr, 225 | Oper: oper.expr, 226 | } 227 | 228 | // Resultant type would be of the result 229 | x.typ = typ 230 | x.mode = value 231 | 232 | return true 233 | } 234 | 235 | func (check *checker) overloadUnaryOperator(x *operand, e ast.Expr) bool { 236 | if isUntyped(x.typ) { 237 | return false 238 | } 239 | 240 | ue, ok := e.(*ast.UnaryExpr) 241 | 242 | if !ok { 243 | return false 244 | } 245 | 246 | n := check.overloadTokenToName(ue.Op) 247 | 248 | if len(n) == 0 { 249 | return false 250 | } 251 | 252 | // Lookup method name on x satisfying type of y 253 | f, typ := check.overloadLookup(x, nil, "Op_"+n) 254 | 255 | if f == nil { 256 | return false 257 | } 258 | 259 | check.pkg.overloads[e] = OverloadInfo{ 260 | Func: f, 261 | Recv: x.expr, 262 | Oper: nil, 263 | } 264 | 265 | // Resultant type would be of the result 266 | x.typ = typ 267 | x.mode = value 268 | 269 | return true 270 | } 271 | -------------------------------------------------------------------------------- /types/package.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package types 6 | 7 | import "go/ast" 8 | 9 | // A Package describes a Go package. 10 | type Package struct { 11 | path string 12 | name string 13 | scope *Scope 14 | complete bool 15 | imports []*Package 16 | fake bool // scope lookup errors are silently dropped if package is fake (internal use only) 17 | 18 | // overloaded operators 19 | overloads map[ast.Expr]OverloadInfo 20 | } 21 | 22 | // NewPackage returns a new Package for the given package path, 23 | // name, and scope. The package is not complete and contains no 24 | // explicit imports. 25 | func NewPackage(path, name string, scope *Scope) *Package { 26 | return &Package{path: path, name: name, scope: scope, overloads: make(map[ast.Expr]OverloadInfo)} 27 | } 28 | 29 | // Path returns the package path. 30 | func (pkg *Package) Path() string { return pkg.path } 31 | 32 | // Name returns the package name. 33 | func (pkg *Package) Name() string { return pkg.name } 34 | 35 | // Scope returns the (complete or incomplete) package scope 36 | // holding the objects declared at package level (TypeNames, 37 | // Consts, Vars, and Funcs). 38 | func (pkg *Package) Scope() *Scope { return pkg.scope } 39 | 40 | // A package is complete if its scope contains (at least) all 41 | // exported objects; otherwise it is incomplete. 42 | func (pkg *Package) Complete() bool { return pkg.complete } 43 | 44 | // Imports returns the list of packages explicitly imported by 45 | // pkg; the list is in source order. Package unsafe is excluded. 46 | func (pkg *Package) Imports() []*Package { return pkg.imports } 47 | 48 | func (pkg *Package) Overloads() map[ast.Expr]OverloadInfo { return pkg.overloads } 49 | -------------------------------------------------------------------------------- /types/predicates.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements commonly used type predicates. 6 | 7 | package types 8 | 9 | func isNamed(typ Type) bool { 10 | if _, ok := typ.(*Basic); ok { 11 | return ok 12 | } 13 | _, ok := typ.(*Named) 14 | return ok 15 | } 16 | 17 | func isBoolean(typ Type) bool { 18 | t, ok := typ.Underlying().(*Basic) 19 | return ok && t.info&IsBoolean != 0 20 | } 21 | 22 | func isInteger(typ Type) bool { 23 | t, ok := typ.Underlying().(*Basic) 24 | return ok && t.info&IsInteger != 0 25 | } 26 | 27 | func isUnsigned(typ Type) bool { 28 | t, ok := typ.Underlying().(*Basic) 29 | return ok && t.info&IsUnsigned != 0 30 | } 31 | 32 | func isFloat(typ Type) bool { 33 | t, ok := typ.Underlying().(*Basic) 34 | return ok && t.info&IsFloat != 0 35 | } 36 | 37 | func isComplex(typ Type) bool { 38 | t, ok := typ.Underlying().(*Basic) 39 | return ok && t.info&IsComplex != 0 40 | } 41 | 42 | func isNumeric(typ Type) bool { 43 | t, ok := typ.Underlying().(*Basic) 44 | return ok && t.info&IsNumeric != 0 45 | } 46 | 47 | func isString(typ Type) bool { 48 | t, ok := typ.Underlying().(*Basic) 49 | return ok && t.info&IsString != 0 50 | } 51 | 52 | func isTyped(typ Type) bool { 53 | t, ok := typ.Underlying().(*Basic) 54 | return !ok || t.info&IsUntyped == 0 55 | } 56 | 57 | func isUntyped(typ Type) bool { 58 | t, ok := typ.Underlying().(*Basic) 59 | return ok && t.info&IsUntyped != 0 60 | } 61 | 62 | func isOrdered(typ Type) bool { 63 | t, ok := typ.Underlying().(*Basic) 64 | return ok && t.info&IsOrdered != 0 65 | } 66 | 67 | func isConstType(typ Type) bool { 68 | t, ok := typ.Underlying().(*Basic) 69 | return ok && t.info&IsConstType != 0 70 | } 71 | 72 | func isInterface(typ Type) bool { 73 | _, ok := typ.Underlying().(*Interface) 74 | return ok 75 | } 76 | 77 | func isComparable(typ Type) bool { 78 | switch t := typ.Underlying().(type) { 79 | case *Basic: 80 | return t.kind != Invalid && t.kind != UntypedNil 81 | case *Pointer, *Interface, *Chan: 82 | // assumes types are equal for pointers and channels 83 | return true 84 | case *Struct: 85 | for _, f := range t.fields { 86 | if !isComparable(f.typ) { 87 | return false 88 | } 89 | } 90 | return true 91 | case *Array: 92 | return isComparable(t.elt) 93 | } 94 | return false 95 | } 96 | 97 | // hasNil reports whether a type includes the nil value. 98 | func hasNil(typ Type) bool { 99 | switch t := typ.Underlying().(type) { 100 | case *Basic: 101 | return t.kind == UnsafePointer 102 | case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan: 103 | return true 104 | } 105 | return false 106 | } 107 | 108 | // IsIdentical returns true if x and y are identical. 109 | func IsIdentical(x, y Type) bool { 110 | if x == y { 111 | return true 112 | } 113 | 114 | switch x := x.(type) { 115 | case *Basic: 116 | // Basic types are singletons except for the rune and byte 117 | // aliases, thus we cannot solely rely on the x == y check 118 | // above. 119 | if y, ok := y.(*Basic); ok { 120 | return x.kind == y.kind 121 | } 122 | 123 | case *Array: 124 | // Two array types are identical if they have identical element types 125 | // and the same array length. 126 | if y, ok := y.(*Array); ok { 127 | return x.len == y.len && IsIdentical(x.elt, y.elt) 128 | } 129 | 130 | case *Slice: 131 | // Two slice types are identical if they have identical element types. 132 | if y, ok := y.(*Slice); ok { 133 | return IsIdentical(x.elt, y.elt) 134 | } 135 | 136 | case *Struct: 137 | // Two struct types are identical if they have the same sequence of fields, 138 | // and if corresponding fields have the same names, and identical types, 139 | // and identical tags. Two anonymous fields are considered to have the same 140 | // name. Lower-case field names from different packages are always different. 141 | if y, ok := y.(*Struct); ok { 142 | if x.NumFields() == y.NumFields() { 143 | for i, f := range x.fields { 144 | g := y.fields[i] 145 | if f.anonymous != g.anonymous || 146 | x.Tag(i) != y.Tag(i) || 147 | !f.sameId(g.pkg, g.name) || 148 | !IsIdentical(f.typ, g.typ) { 149 | return false 150 | } 151 | } 152 | return true 153 | } 154 | } 155 | 156 | case *Pointer: 157 | // Two pointer types are identical if they have identical base types. 158 | if y, ok := y.(*Pointer); ok { 159 | return IsIdentical(x.base, y.base) 160 | } 161 | 162 | case *Tuple: 163 | // Two tuples types are identical if they have the same number of elements 164 | // and corresponding elements have identical types. 165 | if y, ok := y.(*Tuple); ok { 166 | return identicalTuples(x, y) 167 | } 168 | 169 | case *Signature: 170 | // Two function types are identical if they have the same number of parameters 171 | // and result values, corresponding parameter and result types are identical, 172 | // and either both functions are variadic or neither is. Parameter and result 173 | // names are not required to match. 174 | if y, ok := y.(*Signature); ok { 175 | return x.isVariadic == y.isVariadic && 176 | identicalTuples(x.params, y.params) && 177 | identicalTuples(x.results, y.results) 178 | } 179 | 180 | case *Interface: 181 | // Two interface types are identical if they have the same set of methods with 182 | // the same names and identical function types. Lower-case method names from 183 | // different packages are always different. The order of the methods is irrelevant. 184 | if y, ok := y.(*Interface); ok { 185 | return identicalMethods(x.methods, y.methods) 186 | } 187 | 188 | case *Map: 189 | // Two map types are identical if they have identical key and value types. 190 | if y, ok := y.(*Map); ok { 191 | return IsIdentical(x.key, y.key) && IsIdentical(x.elt, y.elt) 192 | } 193 | 194 | case *Chan: 195 | // Two channel types are identical if they have identical value types 196 | // and the same direction. 197 | if y, ok := y.(*Chan); ok { 198 | return x.dir == y.dir && IsIdentical(x.elt, y.elt) 199 | } 200 | 201 | case *Named: 202 | // Two named types are identical if their type names originate 203 | // in the same type declaration. 204 | if y, ok := y.(*Named); ok { 205 | return x.obj == y.obj 206 | } 207 | } 208 | 209 | return false 210 | } 211 | 212 | // identicalTuples returns true if both tuples a and b have the 213 | // same length and corresponding elements have identical types. 214 | func identicalTuples(a, b *Tuple) bool { 215 | if a.Len() != b.Len() { 216 | return false 217 | } 218 | if a != nil { 219 | for i, x := range a.vars { 220 | y := b.vars[i] 221 | if !IsIdentical(x.typ, y.typ) { 222 | return false 223 | } 224 | } 225 | } 226 | return true 227 | } 228 | 229 | // identicalMethods returns true if both slices a and b have the 230 | // same length and corresponding entries have identical types. 231 | // TODO(gri) make this more efficient (e.g., sort them on completion) 232 | func identicalMethods(a, b []*Func) bool { 233 | if len(a) != len(b) { 234 | return false 235 | } 236 | 237 | m := make(map[string]*Func) 238 | for _, x := range a { 239 | key := x.Id() 240 | assert(m[key] == nil) // method list must not have duplicate entries 241 | m[key] = x 242 | } 243 | 244 | for _, y := range b { 245 | key := y.Id() 246 | if x := m[key]; x == nil || !IsIdentical(x.typ, y.typ) { 247 | return false 248 | } 249 | } 250 | 251 | return true 252 | } 253 | 254 | // defaultType returns the default "typed" type for an "untyped" type; 255 | // it returns the incoming type for all other types. The default type 256 | // for untyped nil is untyped nil. 257 | // 258 | func defaultType(typ Type) Type { 259 | if t, ok := typ.(*Basic); ok { 260 | k := t.kind 261 | switch k { 262 | case UntypedBool: 263 | k = Bool 264 | case UntypedInt: 265 | k = Int 266 | case UntypedRune: 267 | k = Rune 268 | case UntypedFloat: 269 | k = Float64 270 | case UntypedComplex: 271 | k = Complex128 272 | case UntypedString: 273 | k = String 274 | } 275 | typ = Typ[k] 276 | } 277 | return typ 278 | } 279 | -------------------------------------------------------------------------------- /types/resolver_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package types 6 | 7 | import ( 8 | "fmt" 9 | "go/ast" 10 | "go/parser" 11 | "go/token" 12 | "testing" 13 | ) 14 | 15 | var sources = []string{ 16 | ` 17 | package p 18 | import "fmt" 19 | import "math" 20 | const pi = math.Pi 21 | func sin(x float64) float64 { 22 | return math.Sin(x) 23 | } 24 | var Println = fmt.Println 25 | `, 26 | ` 27 | package p 28 | import "fmt" 29 | func f() string { 30 | _ = "foo" 31 | return fmt.Sprintf("%d", g()) 32 | } 33 | func g() (x int) { return } 34 | `, 35 | ` 36 | package p 37 | import . "go/parser" 38 | import "sync" 39 | func h() Mode { return ImportsOnly } 40 | var _, x int = 1, 2 41 | func init() {} 42 | type T struct{ sync.Mutex; a, b, c int} 43 | type I interface{ m() } 44 | var _ = T{a: 1, b: 2, c: 3} 45 | func (_ T) m() {} 46 | func (T) _() {} 47 | var i I 48 | var _ = i.m 49 | func _(s []int) { for i, x := range s { _, _ = i, x } } 50 | func _(x interface{}) { 51 | switch x := x.(type) { 52 | case int: 53 | _ = x 54 | } 55 | } 56 | `, 57 | ` 58 | package p 59 | type S struct{} 60 | func (T) _() {} 61 | func (T) _() {} 62 | `, 63 | ` 64 | package p 65 | func _() { 66 | L0: 67 | L1: 68 | goto L0 69 | for { 70 | goto L1 71 | } 72 | if true { 73 | goto L2 74 | } 75 | L2: 76 | } 77 | `, 78 | } 79 | 80 | var pkgnames = []string{ 81 | "fmt", 82 | "math", 83 | } 84 | 85 | func TestResolveIdents(t *testing.T) { 86 | // parse package files 87 | fset := token.NewFileSet() 88 | var files []*ast.File 89 | for i, src := range sources { 90 | f, err := parser.ParseFile(fset, fmt.Sprintf("sources[%d]", i), src, parser.DeclarationErrors) 91 | if err != nil { 92 | t.Fatal(err) 93 | } 94 | files = append(files, f) 95 | } 96 | 97 | // resolve and type-check package AST 98 | var conf Config 99 | idents := make(map[*ast.Ident]Object) 100 | _, err := conf.Check("testResolveIdents", fset, files, &Info{Objects: idents}) 101 | if err != nil { 102 | t.Fatal(err) 103 | } 104 | 105 | // check that all packages were imported 106 | for _, name := range pkgnames { 107 | if conf.Packages[name] == nil { 108 | t.Errorf("package %s not imported", name) 109 | } 110 | } 111 | 112 | // check that qualified identifiers are resolved 113 | for _, f := range files { 114 | ast.Inspect(f, func(n ast.Node) bool { 115 | if s, ok := n.(*ast.SelectorExpr); ok { 116 | if x, ok := s.X.(*ast.Ident); ok { 117 | obj := idents[x] 118 | if obj == nil { 119 | t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name) 120 | return false 121 | } 122 | if _, ok := obj.(*PkgName); ok && idents[s.Sel] == nil { 123 | t.Errorf("%s: unresolved selector %s", fset.Position(s.Sel.Pos()), s.Sel.Name) 124 | return false 125 | } 126 | return false 127 | } 128 | return false 129 | } 130 | return true 131 | }) 132 | } 133 | 134 | // check that each identifier in the source is found in the idents map 135 | for _, f := range files { 136 | ast.Inspect(f, func(n ast.Node) bool { 137 | if x, ok := n.(*ast.Ident); ok { 138 | if _, found := idents[x]; found { 139 | delete(idents, x) 140 | } else { 141 | t.Errorf("%s: unresolved identifier %s", fset.Position(x.Pos()), x.Name) 142 | } 143 | return false 144 | } 145 | return true 146 | }) 147 | } 148 | 149 | // any left-over identifiers didn't exist in the source 150 | for x := range idents { 151 | t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name) 152 | } 153 | 154 | // TODO(gri) add tests to check ImplicitObj callbacks 155 | } 156 | -------------------------------------------------------------------------------- /types/return.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements isTerminating. 6 | 7 | package types 8 | 9 | import ( 10 | "go/ast" 11 | "go/token" 12 | ) 13 | 14 | // isTerminating reports if s is a terminating statement. 15 | // If s is labeled, label is the label name; otherwise s 16 | // is "". 17 | func (check *checker) isTerminating(s ast.Stmt, label string) bool { 18 | switch s := s.(type) { 19 | default: 20 | unreachable() 21 | 22 | case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.SendStmt, 23 | *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, *ast.DeferStmt, 24 | *ast.RangeStmt: 25 | // no chance 26 | 27 | case *ast.LabeledStmt: 28 | return check.isTerminating(s.Stmt, s.Label.Name) 29 | 30 | case *ast.ExprStmt: 31 | // the predeclared (possibly parenthesized) panic() function is terminating 32 | if call, _ := unparen(s.X).(*ast.CallExpr); call != nil { 33 | if id, _ := call.Fun.(*ast.Ident); id != nil { 34 | if obj := check.topScope.LookupParent(id.Name); obj != nil { 35 | if b, _ := obj.(*Builtin); b != nil && b.id == _Panic { 36 | return true 37 | } 38 | } 39 | } 40 | } 41 | 42 | case *ast.ReturnStmt: 43 | return true 44 | 45 | case *ast.BranchStmt: 46 | if s.Tok == token.GOTO || s.Tok == token.FALLTHROUGH { 47 | return true 48 | } 49 | 50 | case *ast.BlockStmt: 51 | return check.isTerminatingList(s.List, "") 52 | 53 | case *ast.IfStmt: 54 | if s.Else != nil && 55 | check.isTerminating(s.Body, "") && 56 | check.isTerminating(s.Else, "") { 57 | return true 58 | } 59 | 60 | case *ast.SwitchStmt: 61 | return check.isTerminatingSwitch(s.Body, label) 62 | 63 | case *ast.TypeSwitchStmt: 64 | return check.isTerminatingSwitch(s.Body, label) 65 | 66 | case *ast.SelectStmt: 67 | for _, s := range s.Body.List { 68 | cc := s.(*ast.CommClause) 69 | if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) { 70 | return false 71 | } 72 | 73 | } 74 | return true 75 | 76 | case *ast.ForStmt: 77 | if s.Cond == nil && !hasBreak(s.Body, label, true) { 78 | return true 79 | } 80 | } 81 | 82 | return false 83 | } 84 | 85 | func (check *checker) isTerminatingList(list []ast.Stmt, label string) bool { 86 | n := len(list) 87 | return n > 0 && check.isTerminating(list[n-1], label) 88 | } 89 | 90 | func (check *checker) isTerminatingSwitch(body *ast.BlockStmt, label string) bool { 91 | hasDefault := false 92 | for _, s := range body.List { 93 | cc := s.(*ast.CaseClause) 94 | if cc.List == nil { 95 | hasDefault = true 96 | } 97 | if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) { 98 | return false 99 | } 100 | } 101 | return hasDefault 102 | } 103 | 104 | // TODO(gri) For nested breakable statements, the current implementation of hasBreak 105 | // will traverse the same subtree repeatedly, once for each label. Replace 106 | // with a single-pass label/break matching phase. 107 | 108 | // hasBreak reports if s is or contains a break statement 109 | // referring to the label-ed statement or implicit-ly the 110 | // closest outer breakable statement. 111 | func hasBreak(s ast.Stmt, label string, implicit bool) bool { 112 | switch s := s.(type) { 113 | default: 114 | unreachable() 115 | 116 | case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.ExprStmt, 117 | *ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, 118 | *ast.DeferStmt, *ast.ReturnStmt: 119 | // no chance 120 | 121 | case *ast.LabeledStmt: 122 | return hasBreak(s.Stmt, label, implicit) 123 | 124 | case *ast.BranchStmt: 125 | if s.Tok == token.BREAK { 126 | if s.Label == nil { 127 | return implicit 128 | } 129 | if s.Label.Name == label { 130 | return true 131 | } 132 | } 133 | 134 | case *ast.BlockStmt: 135 | return hasBreakList(s.List, label, implicit) 136 | 137 | case *ast.IfStmt: 138 | if hasBreak(s.Body, label, implicit) || 139 | s.Else != nil && hasBreak(s.Else, label, implicit) { 140 | return true 141 | } 142 | 143 | case *ast.CaseClause: 144 | return hasBreakList(s.Body, label, implicit) 145 | 146 | case *ast.SwitchStmt: 147 | if label != "" && hasBreak(s.Body, label, false) { 148 | return true 149 | } 150 | 151 | case *ast.TypeSwitchStmt: 152 | if label != "" && hasBreak(s.Body, label, false) { 153 | return true 154 | } 155 | 156 | case *ast.CommClause: 157 | return hasBreakList(s.Body, label, implicit) 158 | 159 | case *ast.SelectStmt: 160 | if label != "" && hasBreak(s.Body, label, false) { 161 | return true 162 | } 163 | 164 | case *ast.ForStmt: 165 | if label != "" && hasBreak(s.Body, label, false) { 166 | return true 167 | } 168 | 169 | case *ast.RangeStmt: 170 | if label != "" && hasBreak(s.Body, label, false) { 171 | return true 172 | } 173 | } 174 | 175 | return false 176 | } 177 | 178 | func hasBreakList(list []ast.Stmt, label string, implicit bool) bool { 179 | for _, s := range list { 180 | if hasBreak(s, label, implicit) { 181 | return true 182 | } 183 | } 184 | return false 185 | } 186 | -------------------------------------------------------------------------------- /types/scope.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements Scopes. 6 | 7 | package types 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "io" 13 | "sort" 14 | "strings" 15 | ) 16 | 17 | // TODO(gri) Provide scopes with a name or other mechanism so that 18 | // objects can use that information for better printing. 19 | 20 | // A Scope maintains a set of objects and links to its containing 21 | // (parent) and contained (children) scopes. Objects may be inserted 22 | // and looked up by name. The zero value for Scope is a ready-to-use 23 | // empty scope. 24 | type Scope struct { 25 | parent *Scope 26 | children []*Scope 27 | elems map[string]Object // lazily allocated 28 | } 29 | 30 | // NewScope returns a new, empty scope contained in the given parent 31 | // scope, if any. 32 | func NewScope(parent *Scope) *Scope { 33 | s := &Scope{parent: parent} 34 | // don't add children to Universe scope! 35 | if parent != nil && parent != Universe { 36 | parent.children = append(parent.children, s) 37 | } 38 | return s 39 | } 40 | 41 | // Parent returns the scope's containing (parent) scope. 42 | func (s *Scope) Parent() *Scope { return s.parent } 43 | 44 | // Len() returns the number of scope elements. 45 | func (s *Scope) Len() int { return len(s.elems) } 46 | 47 | // Names returns the scope's element names in sorted order. 48 | func (s *Scope) Names() []string { 49 | names := make([]string, len(s.elems)) 50 | i := 0 51 | for name := range s.elems { 52 | names[i] = name 53 | i++ 54 | } 55 | sort.Strings(names) 56 | return names 57 | } 58 | 59 | // NumChildren() returns the number of scopes nested in s. 60 | func (s *Scope) NumChildren() int { return len(s.children) } 61 | 62 | // Child returns the i'th child scope for 0 <= i < NumChildren(). 63 | func (s *Scope) Child(i int) *Scope { return s.children[i] } 64 | 65 | // Lookup returns the object in scope s with the given name if such an 66 | // object exists; otherwise the result is nil. 67 | func (s *Scope) Lookup(name string) Object { 68 | return s.elems[name] 69 | } 70 | 71 | // LookupParent follows the parent chain of scopes starting with s until 72 | // it finds a scope where Lookup(name) returns a non-nil object, and then 73 | // returns that object. If no such scope exists, the result is nil. 74 | func (s *Scope) LookupParent(name string) Object { 75 | for ; s != nil; s = s.parent { 76 | if obj := s.elems[name]; obj != nil { 77 | return obj 78 | } 79 | } 80 | return nil 81 | } 82 | 83 | // TODO(gri): Should Insert not be exported? 84 | 85 | // Insert attempts to insert an object obj into scope s. 86 | // If s already contains an alternative object alt with 87 | // the same name, Insert leaves s unchanged and returns alt. 88 | // Otherwise it inserts obj, sets the object's scope to 89 | // s, and returns nil. Objects with blank "_" names are 90 | // not inserted, but have their parent field set to s. 91 | func (s *Scope) Insert(obj Object) Object { 92 | name := obj.Name() 93 | // spec: "The blank identifier, represented by the underscore 94 | // character _, may be used in a declaration like any other 95 | // identifier but the declaration does not introduce a new 96 | // binding." 97 | if name == "_" { 98 | obj.setParent(s) 99 | return nil 100 | } 101 | if alt := s.elems[name]; alt != nil { 102 | return alt 103 | } 104 | if s.elems == nil { 105 | s.elems = make(map[string]Object) 106 | } 107 | s.elems[name] = obj 108 | obj.setParent(s) 109 | return nil 110 | } 111 | 112 | // WriteTo writes a string representation of the scope to w, 113 | // with the scope elements sorted by name. 114 | // The level of indentation is controlled by n >= 0, with 115 | // n == 0 for no indentation. 116 | // If recurse is set, it also writes nested (children) scopes. 117 | func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) { 118 | const ind = ". " 119 | indn := strings.Repeat(ind, n) 120 | 121 | if len(s.elems) == 0 { 122 | fmt.Fprintf(w, "%sscope %p {}\n", indn, s) 123 | return 124 | } 125 | 126 | fmt.Fprintf(w, "%sscope %p {\n", indn, s) 127 | indn1 := indn + ind 128 | for _, name := range s.Names() { 129 | fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name]) 130 | } 131 | 132 | if recurse { 133 | for _, s := range s.children { 134 | fmt.Fprintln(w) 135 | s.WriteTo(w, n+1, recurse) 136 | } 137 | } 138 | 139 | fmt.Fprintf(w, "%s}", indn) 140 | } 141 | 142 | // String returns a string representation of the scope, for debugging. 143 | func (s *Scope) String() string { 144 | var buf bytes.Buffer 145 | s.WriteTo(&buf, 0, false) 146 | return buf.String() 147 | } 148 | -------------------------------------------------------------------------------- /types/selection.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements Selections. 6 | 7 | package types 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | ) 13 | 14 | // SelectionKind describes the kind of a selector expression x.f. 15 | type SelectionKind int 16 | 17 | const ( 18 | FieldVal SelectionKind = iota // x.f is a struct field selector 19 | MethodVal // x.f is a method selector 20 | MethodExpr // x.f is a method expression 21 | PackageObj // x.f is a qualified identifier 22 | ) 23 | 24 | // A Selection describes a selector expression x.f. 25 | // For the declarations: 26 | // 27 | // type T struct{ x int; E } 28 | // type E struct{} 29 | // func (e E) m() {} 30 | // var p *T 31 | // 32 | // the following relations exist: 33 | // 34 | // Selector Kind Recv Obj Type Index Indirect 35 | // 36 | // p.x FieldVal T x int {0} true 37 | // p.m MethodVal *T m func (e *T) m() {1, 0} true 38 | // T.m MethodExpr T m func m(_ T) {1, 0} false 39 | // math.Pi PackageObj nil Pi untyped numeric nil false 40 | // 41 | type Selection struct { 42 | kind SelectionKind 43 | recv Type // type of x, nil if kind == PackageObj 44 | obj Object // object denoted by x.f 45 | index []int // path from x to x.f, nil if kind == PackageObj 46 | indirect bool // set if there was any pointer indirection on the path, false if kind == PackageObj 47 | } 48 | 49 | // Kind returns the selection kind. 50 | func (s *Selection) Kind() SelectionKind { return s.kind } 51 | 52 | // Recv returns the type of x in x.f. 53 | // The result is nil if x.f is a qualified identifier (PackageObj). 54 | func (s *Selection) Recv() Type { return s.recv } 55 | 56 | // Obj returns the object denoted by x.f. 57 | // The following object types may appear: 58 | // 59 | // Kind Object 60 | // 61 | // FieldVal *Var field 62 | // MethodVal *Func method 63 | // MethodExpr *Func method 64 | // PackageObj *Const, *Type, *Var, *Func imported const, type, var, or func 65 | // 66 | func (s *Selection) Obj() Object { return s.obj } 67 | 68 | // Type returns the type of x.f, which may be different from the type of f. 69 | // See Selection for more information. 70 | func (s *Selection) Type() Type { 71 | switch s.kind { 72 | case MethodVal: 73 | // The type of x.f is a method with its receiver type set 74 | // to the type of x. 75 | sig := *s.obj.(*Func).typ.(*Signature) 76 | recv := *sig.recv 77 | recv.typ = s.recv 78 | sig.recv = &recv 79 | return &sig 80 | 81 | case MethodExpr: 82 | // The type of x.f is a function (without receiver) 83 | // and an additional first argument with the same type as x. 84 | // TODO(gri) Similar code is already in call.go - factor! 85 | sig := *s.obj.(*Func).typ.(*Signature) 86 | arg0 := *sig.recv 87 | arg0.typ = s.recv 88 | var params []*Var 89 | if sig.params != nil { 90 | params = sig.params.vars 91 | } 92 | sig.params = NewTuple(append([]*Var{&arg0}, params...)...) 93 | return &sig 94 | } 95 | 96 | // In all other cases, the type of x.f is the type of x. 97 | return s.obj.Type() 98 | } 99 | 100 | // Index describes the path from x to f in x.f. 101 | // The result is nil if x.f is a qualified identifier (PackageObj). 102 | // 103 | // The last index entry is the field or method index of the type declaring f; 104 | // either: 105 | // 106 | // 1) the list of declared methods of a named type; or 107 | // 2) the list of methods of an interface type; or 108 | // 3) the list of fields of a struct type. 109 | // 110 | // The earlier index entries are the indices of the embedded fields implicitly 111 | // traversed to get from (the type of) x to f, starting at embedding depth 0. 112 | func (s *Selection) Index() []int { return s.index } 113 | 114 | // Indirect reports whether any pointer indirection was required to get from 115 | // x to f in x.f. 116 | // The result is false if x.f is a qualified identifier (PackageObj). 117 | func (s *Selection) Indirect() bool { return s.indirect } 118 | 119 | func (s *Selection) String() string { 120 | var k string 121 | switch s.kind { 122 | case FieldVal: 123 | k = "field" 124 | case MethodVal: 125 | k = "method" 126 | case MethodExpr: 127 | k = "method expr" 128 | case PackageObj: 129 | return fmt.Sprintf("qualified ident %s", s.obj) 130 | default: 131 | unreachable() 132 | } 133 | var buf bytes.Buffer 134 | fmt.Fprintf(&buf, "%s (%s) %s", k, s.Recv(), s.obj.Name()) 135 | writeSignature(&buf, s.Type().(*Signature)) 136 | return buf.String() 137 | } 138 | -------------------------------------------------------------------------------- /types/self_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package types 6 | 7 | import ( 8 | "fmt" 9 | "go/ast" 10 | "go/parser" 11 | "go/token" 12 | "testing" 13 | "time" 14 | ) 15 | 16 | func TestSelf(t *testing.T) { 17 | filenames := pkgfiles(t, ".") // from stdlib_test.go 18 | 19 | // parse package files 20 | fset := token.NewFileSet() 21 | var files []*ast.File 22 | for _, filename := range filenames { 23 | file, err := parser.ParseFile(fset, filename, nil, 0) 24 | if err != nil { 25 | t.Fatal(err) 26 | } 27 | files = append(files, file) 28 | } 29 | 30 | _, err := Check("go/types", fset, files) 31 | if err != nil { 32 | // Importing go.tools/go/exact doensn't work in the 33 | // build dashboard environment at the moment. Don't 34 | // report an error for now so that the build remains 35 | // green. 36 | // TODO(gri) fix this 37 | t.Log(err) // replace w/ t.Fatal eventually 38 | return 39 | } 40 | 41 | if testing.Short() { 42 | return // skip benchmark in short mode 43 | } 44 | 45 | benchmark(fset, files, false) 46 | benchmark(fset, files, true) 47 | } 48 | 49 | func benchmark(fset *token.FileSet, files []*ast.File, full bool) { 50 | b := testing.Benchmark(func(b *testing.B) { 51 | for i := 0; i < b.N; i++ { 52 | conf := Config{IgnoreFuncBodies: !full} 53 | conf.Check("go/types", fset, files, nil) 54 | } 55 | }) 56 | 57 | // determine line count 58 | lineCount := 0 59 | fset.Iterate(func(f *token.File) bool { 60 | lineCount += f.LineCount() 61 | return true 62 | }) 63 | 64 | d := time.Duration(b.NsPerOp()) 65 | fmt.Printf( 66 | "%s/op, %d lines/s, %d KB/op (%d iterations)\n", 67 | d, 68 | int64(float64(lineCount)/d.Seconds()), 69 | b.AllocedBytesPerOp()>>10, 70 | b.N, 71 | ) 72 | } 73 | -------------------------------------------------------------------------------- /types/sizes.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements Sizes. 6 | 7 | package types 8 | 9 | // Sizes defines the sizing functions for package unsafe. 10 | type Sizes interface { 11 | // Alignof returns the alignment of a variable of type T. 12 | // Alignof must implement the alignment guarantees required by the spec. 13 | Alignof(T Type) int64 14 | 15 | // Offsetsof returns the offsets of the given struct fields, in bytes. 16 | // Offsetsof must implement the offset guarantees required by the spec. 17 | Offsetsof(fields []*Var) []int64 18 | 19 | // Sizeof returns the size of a variable of type T. 20 | // Sizeof must implement the size guarantees required by the spec. 21 | Sizeof(T Type) int64 22 | } 23 | 24 | // StdSizes is a convenience type for creating commonly used Sizes. 25 | // It makes the following simplifying assumptions: 26 | // 27 | // - The size of explicitly sized basic types (int16, etc.) is the 28 | // specified size. 29 | // - The size of strings, functions, and interfaces is 2*WordSize. 30 | // - The size of slices is 3*WordSize. 31 | // - All other types have size WordSize. 32 | // - Arrays and structs are aligned per spec definition; all other 33 | // types are naturally aligned with a maximum alignment MaxAlign. 34 | // 35 | // *StdSizes implements Sizes. 36 | // 37 | type StdSizes struct { 38 | WordSize int64 // word size in bytes - must be >= 4 (32bits) 39 | MaxAlign int64 // maximum alignment in bytes - must be >= 1 40 | } 41 | 42 | func (s *StdSizes) Alignof(T Type) int64 { 43 | // For arrays and structs, alignment is defined in terms 44 | // of alignment of the elements and fields, respectively. 45 | switch t := T.Underlying().(type) { 46 | case *Array: 47 | // spec: "For a variable x of array type: unsafe.Alignof(x) 48 | // is the same as unsafe.Alignof(x[0]), but at least 1." 49 | return s.Alignof(t.elt) 50 | case *Struct: 51 | // spec: "For a variable x of struct type: unsafe.Alignof(x) 52 | // is the largest of the values unsafe.Alignof(x.f) for each 53 | // field f of x, but at least 1." 54 | max := int64(1) 55 | for _, f := range t.fields { 56 | if a := s.Alignof(f.typ); a > max { 57 | max = a 58 | } 59 | } 60 | return max 61 | } 62 | a := s.Sizeof(T) // may be 0 63 | // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." 64 | if a < 1 { 65 | return 1 66 | } 67 | if a > s.MaxAlign { 68 | return s.MaxAlign 69 | } 70 | return a 71 | } 72 | 73 | func (s *StdSizes) Offsetsof(fields []*Var) []int64 { 74 | offsets := make([]int64, len(fields)) 75 | var o int64 76 | for i, f := range fields { 77 | a := s.Alignof(f.typ) 78 | o = align(o, a) 79 | offsets[i] = o 80 | o += s.Sizeof(f.typ) 81 | } 82 | return offsets 83 | } 84 | 85 | func (s *StdSizes) Sizeof(T Type) int64 { 86 | switch t := T.Underlying().(type) { 87 | case *Basic: 88 | if z := t.size; z > 0 { 89 | return z 90 | } 91 | if t.kind == String { 92 | return s.WordSize * 2 93 | } 94 | case *Array: 95 | a := s.Alignof(t.elt) 96 | z := s.Sizeof(t.elt) 97 | return align(z, a) * t.len // may be 0 98 | case *Slice: 99 | return s.WordSize * 3 100 | case *Struct: 101 | n := t.NumFields() 102 | if n == 0 { 103 | return 0 104 | } 105 | offsets := t.offsets 106 | if t.offsets == nil { 107 | // compute offsets on demand 108 | offsets = s.Offsetsof(t.fields) 109 | t.offsets = offsets 110 | } 111 | return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) 112 | case *Signature, *Interface: 113 | return s.WordSize * 2 114 | } 115 | return s.WordSize // catch-all 116 | } 117 | 118 | // stdSizes is used if Config.Sizes == nil. 119 | var stdSizes = StdSizes{8, 8} 120 | 121 | func (conf *Config) alignof(T Type) int64 { 122 | if s := conf.Sizes; s != nil { 123 | if a := s.Alignof(T); a >= 1 { 124 | return a 125 | } 126 | panic("Config.Sizes.Alignof returned an alignment < 1") 127 | } 128 | return stdSizes.Alignof(T) 129 | } 130 | 131 | func (conf *Config) offsetsof(T *Struct) []int64 { 132 | offsets := T.offsets 133 | if offsets == nil && T.NumFields() > 0 { 134 | // compute offsets on demand 135 | if s := conf.Sizes; s != nil { 136 | offsets = s.Offsetsof(T.fields) 137 | // sanity checks 138 | if len(offsets) != T.NumFields() { 139 | panic("Config.Sizes.Offsetsof returned the wrong number of offsets") 140 | } 141 | for _, o := range offsets { 142 | if o < 0 { 143 | panic("Config.Sizes.Offsetsof returned an offset < 0") 144 | } 145 | } 146 | } else { 147 | offsets = stdSizes.Offsetsof(T.fields) 148 | } 149 | T.offsets = offsets 150 | } 151 | return offsets 152 | } 153 | 154 | // offsetof returns the offset of the field specified via 155 | // the index sequence relative to typ. All embedded fields 156 | // must be structs (rather than pointer to structs). 157 | func (conf *Config) offsetof(typ Type, index []int) int64 { 158 | var o int64 159 | for _, i := range index { 160 | s := typ.Underlying().(*Struct) 161 | o += conf.offsetsof(s)[i] 162 | typ = s.fields[i].typ 163 | } 164 | return o 165 | } 166 | 167 | func (conf *Config) sizeof(T Type) int64 { 168 | if s := conf.Sizes; s != nil { 169 | if z := s.Sizeof(T); z >= 0 { 170 | return z 171 | } 172 | panic("Config.Sizes.Sizeof returned a size < 0") 173 | } 174 | return stdSizes.Sizeof(T) 175 | } 176 | 177 | // align returns the smallest y >= x such that y % a == 0. 178 | func align(x, a int64) int64 { 179 | y := x + a - 1 180 | return y - y%a 181 | } 182 | -------------------------------------------------------------------------------- /types/stdlib_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file tests types.Check by using it to 6 | // typecheck the standard library and tests. 7 | 8 | package types 9 | 10 | import ( 11 | "flag" 12 | "fmt" 13 | "go/ast" 14 | "go/build" 15 | "go/parser" 16 | "go/scanner" 17 | "go/token" 18 | "io/ioutil" 19 | "os" 20 | "path/filepath" 21 | "runtime" 22 | "strings" 23 | "testing" 24 | "time" 25 | ) 26 | 27 | var verbose = flag.Bool("types.v", false, "verbose mode") 28 | 29 | var ( 30 | pkgCount int // number of packages processed 31 | start = time.Now() 32 | ) 33 | 34 | func TestStdlib(t *testing.T) { 35 | walkDirs(t, filepath.Join(runtime.GOROOT(), "src/pkg")) 36 | if *verbose { 37 | fmt.Println(pkgCount, "packages typechecked in", time.Since(start)) 38 | } 39 | } 40 | 41 | // firstComment returns the contents of the first comment in 42 | // the given file, assuming there's one within the first KB. 43 | func firstComment(filename string) string { 44 | f, err := os.Open(filename) 45 | if err != nil { 46 | return "" 47 | } 48 | defer f.Close() 49 | 50 | var src [1 << 10]byte // read at most 1KB 51 | n, _ := f.Read(src[:]) 52 | 53 | var s scanner.Scanner 54 | s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil, scanner.ScanComments) 55 | for { 56 | _, tok, lit := s.Scan() 57 | switch tok { 58 | case token.COMMENT: 59 | // remove trailing */ of multi-line comment 60 | if lit[1] == '*' { 61 | lit = lit[:len(lit)-2] 62 | } 63 | return strings.TrimSpace(lit[2:]) 64 | case token.EOF: 65 | return "" 66 | } 67 | } 68 | } 69 | 70 | func testTestDir(t *testing.T, path string, ignore ...string) { 71 | files, err := ioutil.ReadDir(path) 72 | if err != nil { 73 | t.Fatal(err) 74 | } 75 | 76 | excluded := make(map[string]bool) 77 | for _, filename := range ignore { 78 | excluded[filename] = true 79 | } 80 | 81 | fset := token.NewFileSet() 82 | for _, f := range files { 83 | // filter directory contents 84 | if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] { 85 | continue 86 | } 87 | 88 | // get per-file instructions 89 | expectErrors := false 90 | filename := filepath.Join(path, f.Name()) 91 | if cmd := firstComment(filename); cmd != "" { 92 | switch cmd { 93 | case "skip", "compiledir": 94 | continue // ignore this file 95 | case "errorcheck": 96 | expectErrors = true 97 | } 98 | } 99 | 100 | // parse and type-check file 101 | file, err := parser.ParseFile(fset, filename, nil, 0) 102 | if err == nil { 103 | _, err = Check(filename, fset, []*ast.File{file}) 104 | } 105 | 106 | if expectErrors { 107 | if err == nil { 108 | t.Errorf("expected errors but found none in %s", filename) 109 | } 110 | } else { 111 | if err != nil { 112 | t.Error(err) 113 | } 114 | } 115 | } 116 | } 117 | 118 | func TestStdtest(t *testing.T) { 119 | testTestDir(t, filepath.Join(runtime.GOROOT(), "test"), 120 | "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore 121 | "mapnan.go", "sigchld.go", // don't work on Windows; testTestDir should consult build tags 122 | "sizeof.go", "switch.go", // TODO(gri) tone down duplicate checking in expr switches 123 | "typeswitch2.go", // TODO(gri) implement duplicate checking in type switches 124 | ) 125 | } 126 | 127 | func TestStdfixed(t *testing.T) { 128 | testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"), 129 | "bug251.go", // TODO(gri) incorrect cycle checks for interface types 130 | "bug165.go", // TODO(gri) isComparable not working for incomplete struct type 131 | "bug200.go", // TODO(gri) complete duplicate checking in expr switches 132 | "bug223.go", "bug413.go", "bug459.go", // TODO(gri) complete initialization checks 133 | "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore 134 | "bug250.go", // TODO(gri) fix recursive interfaces 135 | "issue3924.go", // TODO(gri) && and || produce bool result (not untyped bool) 136 | "issue4847.go", // TODO(gri) initialization cycle error not found 137 | ) 138 | } 139 | 140 | func TestStdken(t *testing.T) { 141 | testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken")) 142 | } 143 | 144 | // Package paths of excluded packages. 145 | var excluded = map[string]bool{ 146 | "builtin": true, 147 | } 148 | 149 | // typecheck typechecks the given package files. 150 | func typecheck(t *testing.T, path string, filenames []string) { 151 | fset := token.NewFileSet() 152 | 153 | // parse package files 154 | var files []*ast.File 155 | for _, filename := range filenames { 156 | file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors) 157 | if err != nil { 158 | // the parser error may be a list of individual errors; report them all 159 | if list, ok := err.(scanner.ErrorList); ok { 160 | for _, err := range list { 161 | t.Error(err) 162 | } 163 | return 164 | } 165 | t.Error(err) 166 | return 167 | } 168 | 169 | if *verbose { 170 | if len(files) == 0 { 171 | fmt.Println("package", file.Name.Name) 172 | } 173 | fmt.Println("\t", filename) 174 | } 175 | 176 | files = append(files, file) 177 | } 178 | 179 | // typecheck package files 180 | var conf Config 181 | conf.Error = func(err error) { t.Error(err) } 182 | conf.Check(path, fset, files, nil) 183 | pkgCount++ 184 | } 185 | 186 | // pkgfiles returns the list of package files for the given directory. 187 | func pkgfiles(t *testing.T, dir string) []string { 188 | ctxt := build.Default 189 | ctxt.CgoEnabled = false 190 | pkg, err := ctxt.ImportDir(dir, 0) 191 | if err != nil { 192 | if _, nogo := err.(*build.NoGoError); !nogo { 193 | t.Error(err) 194 | } 195 | return nil 196 | } 197 | if excluded[pkg.ImportPath] { 198 | return nil 199 | } 200 | var filenames []string 201 | for _, name := range pkg.GoFiles { 202 | filenames = append(filenames, filepath.Join(pkg.Dir, name)) 203 | } 204 | for _, name := range pkg.TestGoFiles { 205 | filenames = append(filenames, filepath.Join(pkg.Dir, name)) 206 | } 207 | return filenames 208 | } 209 | 210 | // Note: Could use filepath.Walk instead of walkDirs but that wouldn't 211 | // necessarily be shorter or clearer after adding the code to 212 | // terminate early for -short tests. 213 | 214 | func walkDirs(t *testing.T, dir string) { 215 | // limit run time for short tests 216 | if testing.Short() && time.Since(start) >= 750*time.Millisecond { 217 | return 218 | } 219 | 220 | fis, err := ioutil.ReadDir(dir) 221 | if err != nil { 222 | t.Error(err) 223 | return 224 | } 225 | 226 | // typecheck package in directory 227 | if files := pkgfiles(t, dir); files != nil { 228 | typecheck(t, dir, files) 229 | } 230 | 231 | // traverse subdirectories, but don't walk into testdata 232 | for _, fi := range fis { 233 | if fi.IsDir() && fi.Name() != "testdata" { 234 | walkDirs(t, filepath.Join(dir, fi.Name())) 235 | } 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /types/testdata/const0.src: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // constant declarations 6 | 7 | package const0 8 | 9 | // constants declarations must be initialized by constants 10 | var x = 0 11 | const c0 = x /* ERROR "not constant" */ 12 | 13 | // untyped constants 14 | const ( 15 | // boolean values 16 | ub0 = false 17 | ub1 = true 18 | ub2 = 2 < 1 19 | ub3 = ui1 == uf1 20 | ub4 = true /* ERROR "cannot convert" */ == 0 21 | 22 | // integer values 23 | ui0 = 0 24 | ui1 = 1 25 | ui2 = 42 26 | ui3 = 3141592653589793238462643383279502884197169399375105820974944592307816406286 27 | ui4 = -10 28 | 29 | ui5 = ui0 + ui1 30 | ui6 = ui1 - ui1 31 | ui7 = ui2 * ui1 32 | ui8 = ui3 / ui3 33 | ui9 = ui3 % ui3 34 | 35 | ui10 = 1 / 0 /* ERROR "division by zero" */ 36 | ui11 = ui1 / 0 /* ERROR "division by zero" */ 37 | ui12 = ui3 / ui0 /* ERROR "division by zero" */ 38 | ui13 = 1 % 0 /* ERROR "division by zero" */ 39 | ui14 = ui1 % 0 /* ERROR "division by zero" */ 40 | ui15 = ui3 % ui0 /* ERROR "division by zero" */ 41 | 42 | ui16 = ui2 & ui3 43 | ui17 = ui2 | ui3 44 | ui18 = ui2 ^ ui3 45 | ui19 = 1 /* ERROR "invalid operation" */ % 1.0 46 | 47 | // floating point values 48 | uf0 = 0. 49 | uf1 = 1. 50 | uf2 = 4.2e1 51 | uf3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286 52 | uf4 = 1e-1 53 | 54 | uf5 = uf0 + uf1 55 | uf6 = uf1 - uf1 56 | uf7 = uf2 * uf1 57 | uf8 = uf3 / uf3 58 | uf9 = uf3 /* ERROR "not defined" */ % uf3 59 | 60 | uf10 = 1 / 0 /* ERROR "division by zero" */ 61 | uf11 = uf1 / 0 /* ERROR "division by zero" */ 62 | uf12 = uf3 / uf0 /* ERROR "division by zero" */ 63 | 64 | uf16 = uf2 /* ERROR "not defined" */ & uf3 65 | uf17 = uf2 /* ERROR "not defined" */ | uf3 66 | uf18 = uf2 /* ERROR "not defined" */ ^ uf3 67 | 68 | // complex values 69 | uc0 = 0.i 70 | uc1 = 1.i 71 | uc2 = 4.2e1i 72 | uc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i 73 | uc4 = 1e-1i 74 | 75 | uc5 = uc0 + uc1 76 | uc6 = uc1 - uc1 77 | uc7 = uc2 * uc1 78 | uc8 = uc3 / uc3 79 | uc9 = uc3 /* ERROR "not defined" */ % uc3 80 | 81 | uc10 = 1 / 0 /* ERROR "division by zero" */ 82 | uc11 = uc1 / 0 /* ERROR "division by zero" */ 83 | uc12 = uc3 / uc0 /* ERROR "division by zero" */ 84 | 85 | uc16 = uc2 /* ERROR "not defined" */ & uc3 86 | uc17 = uc2 /* ERROR "not defined" */ | uc3 87 | uc18 = uc2 /* ERROR "not defined" */ ^ uc3 88 | ) 89 | 90 | type ( 91 | mybool bool 92 | myint int 93 | myfloat float64 94 | mycomplex complex128 95 | ) 96 | 97 | // typed constants 98 | const ( 99 | // boolean values 100 | tb0 bool = false 101 | tb1 bool = true 102 | tb2 mybool = 2 < 1 103 | tb3 mybool = ti1 /* ERROR "cannot compare" */ == tf1 104 | 105 | // integer values 106 | ti0 int8 = ui0 107 | ti1 int32 = ui1 108 | ti2 int64 = ui2 109 | ti3 myint = ui3 /* ERROR "overflows" */ 110 | ti4 myint = ui4 111 | 112 | ti5 = ti0 /* ERROR "mismatched types" */ + ti1 113 | ti6 = ti1 - ti1 114 | ti7 = ti2 /* ERROR "mismatched types" */ * ti1 115 | ti8 = ti3 / ti3 116 | ti9 = ti3 % ti3 117 | 118 | ti10 = 1 / 0 /* ERROR "division by zero" */ 119 | ti11 = ti1 / 0 /* ERROR "division by zero" */ 120 | ti12 = ti3 /* ERROR "mismatched types" */ / ti0 121 | ti13 = 1 % 0 /* ERROR "division by zero" */ 122 | ti14 = ti1 % 0 /* ERROR "division by zero" */ 123 | ti15 = ti3 /* ERROR "mismatched types" */ % ti0 124 | 125 | ti16 = ti2 /* ERROR "mismatched types" */ & ti3 126 | ti17 = ti2 /* ERROR "mismatched types" */ | ti4 127 | ti18 = ti2 ^ ti5 // no mismatched types error because the type of ti5 is unknown 128 | 129 | // floating point values 130 | tf0 float32 = 0. 131 | tf1 float32 = 1. 132 | tf2 float64 = 4.2e1 133 | tf3 myfloat = 3.141592653589793238462643383279502884197169399375105820974944592307816406286 134 | tf4 myfloat = 1e-1 135 | 136 | tf5 = tf0 + tf1 137 | tf6 = tf1 - tf1 138 | tf7 = tf2 /* ERROR "mismatched types" */ * tf1 139 | tf8 = tf3 / tf3 140 | tf9 = tf3 /* ERROR "not defined" */ % tf3 141 | 142 | tf10 = 1 / 0 /* ERROR "division by zero" */ 143 | tf11 = tf1 / 0 /* ERROR "division by zero" */ 144 | tf12 = tf3 /* ERROR "mismatched types" */ / tf0 145 | 146 | tf16 = tf2 /* ERROR "mismatched types" */ & tf3 147 | tf17 = tf2 /* ERROR "mismatched types" */ | tf3 148 | tf18 = tf2 /* ERROR "mismatched types" */ ^ tf3 149 | 150 | // complex values 151 | tc0 = 0.i 152 | tc1 = 1.i 153 | tc2 = 4.2e1i 154 | tc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i 155 | tc4 = 1e-1i 156 | 157 | tc5 = tc0 + tc1 158 | tc6 = tc1 - tc1 159 | tc7 = tc2 * tc1 160 | tc8 = tc3 / tc3 161 | tc9 = tc3 /* ERROR "not defined" */ % tc3 162 | 163 | tc10 = 1 / 0 /* ERROR "division by zero" */ 164 | tc11 = tc1 / 0 /* ERROR "division by zero" */ 165 | tc12 = tc3 / tc0 /* ERROR "division by zero" */ 166 | 167 | tc16 = tc2 /* ERROR "not defined" */ & tc3 168 | tc17 = tc2 /* ERROR "not defined" */ | tc3 169 | tc18 = tc2 /* ERROR "not defined" */ ^ tc3 170 | ) 171 | 172 | // initialization cycles 173 | const ( 174 | a /* ERROR "cycle" */ = a 175 | b /* ERROR "cycle" */ , c /* ERROR "cycle" */, d, e = e, d, c, b // TODO(gri) should only have one cycle error 176 | f float64 = d 177 | ) 178 | 179 | // multiple initialization 180 | const ( 181 | a1, a2, a3 = 7, 3.1415926, "foo" 182 | b1, b2, b3 = b3, b1, 42 183 | c1, c2, c3 /* ERROR "missing init expr for c3" */ = 1, 2 184 | d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */ 185 | _p0 = assert(a1 == 7) 186 | _p1 = assert(a2 == 3.1415926) 187 | _p2 = assert(a3 == "foo") 188 | _p3 = assert(b1 == 42) 189 | _p4 = assert(b2 == 42) 190 | _p5 = assert(b3 == 42) 191 | ) 192 | 193 | func _() { 194 | const ( 195 | a1, a2, a3 = 7, 3.1415926, "foo" 196 | b1, b2, b3 = b3, b1, 42 197 | c1, c2, c3 /* ERROR "missing init expr for c3" */ = 1, 2 198 | d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */ 199 | _p0 = assert(a1 == 7) 200 | _p1 = assert(a2 == 3.1415926) 201 | _p2 = assert(a3 == "foo") 202 | _p3 = assert(b1 == 42) 203 | _p4 = assert(b2 == 42) 204 | _p5 = assert(b3 == 42) 205 | ) 206 | } 207 | 208 | // iota 209 | const ( 210 | iota0 = iota 211 | iota1 = iota 212 | iota2 = iota*2 213 | _a0 = assert(iota0 == 0) 214 | _a1 = assert(iota1 == 1) 215 | _a2 = assert(iota2 == 4) 216 | iota6 = iota*3 217 | 218 | iota7 219 | iota8 220 | _a3 = assert(iota7 == 21) 221 | _a4 = assert(iota8 == 24) 222 | ) 223 | 224 | const ( 225 | _b0 = iota 226 | _b1 = assert(iota + iota2 == 5) 227 | _b2 = len([iota]int{}) // iota may appear in a type! 228 | _b3 = assert(_b2 == 2) 229 | _b4 = len(A /* ERROR "invalid composite literal" */ {}) 230 | ) 231 | 232 | type A [iota /* ERROR "cannot use iota" */ ]int 233 | 234 | // constant expressions with operands accross different 235 | // constant declarations must use the right iota values 236 | const ( 237 | _c0 = iota 238 | _c1 239 | _c2 240 | _x = _c2 + _d1 + _e0 // 3 241 | ) 242 | 243 | const ( 244 | _d0 = iota 245 | _d1 246 | ) 247 | 248 | const ( 249 | _e0 = iota 250 | ) 251 | 252 | var _ = assert(_x == 3) 253 | 254 | // special cases 255 | const ( 256 | _n0 = nil /* ERROR "not constant" */ 257 | _n1 = [ /* ERROR "not constant" */ ]int{} 258 | ) 259 | 260 | // iotas must not be usable in expressions outside constant declarations 261 | type _ [iota /* ERROR "iota outside constant decl" */ ]byte 262 | var _ = iota /* ERROR "iota outside constant decl" */ 263 | func _() { 264 | _ = iota /* ERROR "iota outside constant decl" */ 265 | const _ = iota 266 | _ = iota /* ERROR "iota outside constant decl" */ 267 | } 268 | 269 | func _() { 270 | iota := 123 271 | const x = iota /* ERROR "is not constant" */ 272 | var y = iota 273 | _ = y 274 | } 275 | -------------------------------------------------------------------------------- /types/testdata/constdecl.src: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package constdecl 6 | 7 | import "math" 8 | 9 | var v int 10 | 11 | // Const decls must be initialized by constants. 12 | const _ = v /* ERROR "not constant" */ 13 | const _ = math /* ERROR "not constant" */ .Sin(0) 14 | const _ = int /* ERROR "not an expression" */ 15 | 16 | func _() { 17 | const _ = v /* ERROR "not constant" */ 18 | const _ = math /* ERROR "not constant" */ .Sin(0) 19 | const _ = int /* ERROR "not an expression" */ 20 | } 21 | 22 | // Identifier and expression arity must match. 23 | const _ /* ERROR "missing init expr for _" */ 24 | const _ = 1, 2 /* ERROR "extra init expr 2" */ 25 | 26 | const _ /* ERROR "missing init expr for _" */ int 27 | const _ int = 1, 2 /* ERROR "extra init expr 2" */ 28 | 29 | const ( 30 | _ /* ERROR "missing init expr for _" */ 31 | _ = 1, 2 /* ERROR "extra init expr 2" */ 32 | 33 | _ /* ERROR "missing init expr for _" */ int 34 | _ int = 1, 2 /* ERROR "extra init expr 2" */ 35 | ) 36 | 37 | const ( 38 | _ = 1 39 | _ 40 | _, _ /* ERROR "missing init expr for _" */ 41 | _ 42 | ) 43 | 44 | const ( 45 | _, _ = 1, 2 46 | _, _ 47 | _ /* ERROR "extra init expr at" */ 48 | _, _ 49 | _, _, _ /* ERROR "missing init expr for _" */ 50 | _, _ 51 | ) 52 | 53 | func _() { 54 | const _ /* ERROR "missing init expr for _" */ 55 | const _ = 1, 2 /* ERROR "extra init expr 2" */ 56 | 57 | const _ /* ERROR "missing init expr for _" */ int 58 | const _ int = 1, 2 /* ERROR "extra init expr 2" */ 59 | 60 | const ( 61 | _ /* ERROR "missing init expr for _" */ 62 | _ = 1, 2 /* ERROR "extra init expr 2" */ 63 | 64 | _ /* ERROR "missing init expr for _" */ int 65 | _ int = 1, 2 /* ERROR "extra init expr 2" */ 66 | ) 67 | 68 | const ( 69 | _ = 1 70 | _ 71 | _, _ /* ERROR "missing init expr for _" */ 72 | _ 73 | ) 74 | 75 | const ( 76 | _, _ = 1, 2 77 | _, _ 78 | _ /* ERROR "extra init expr at" */ 79 | _, _ 80 | _, _, _ /* ERROR "missing init expr for _" */ 81 | _, _ 82 | ) 83 | } 84 | 85 | // TODO(gri) move extra tests from testdata/const0.src into here -------------------------------------------------------------------------------- /types/testdata/conversions.src: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // conversions 6 | 7 | package conversions 8 | 9 | import "unsafe" 10 | 11 | // argument count 12 | var ( 13 | _ = int() /* ERROR "missing argument" */ 14 | _ = int(1, 2 /* ERROR "too many arguments" */ ) 15 | ) 16 | 17 | // numeric constant conversions are in const1.src. 18 | 19 | func string_conversions() { 20 | const A = string(65) 21 | assert(A == "A") 22 | const E = string(-1) 23 | assert(E == "\uFFFD") 24 | assert(E == string(1234567890)) 25 | 26 | type myint int 27 | assert(A == string(myint(65))) 28 | 29 | type mystring string 30 | const _ mystring = mystring("foo") 31 | 32 | const _ = string(true /* ERROR "cannot convert" */ ) 33 | const _ = string(1.2 /* ERROR "cannot convert" */ ) 34 | const _ = string(nil /* ERROR "cannot convert" */ ) 35 | } 36 | 37 | func interface_conversions() { 38 | type E interface{} 39 | 40 | type I1 interface{ 41 | m1() 42 | } 43 | 44 | type I2 interface{ 45 | m1() 46 | m2(x int) 47 | } 48 | 49 | type I3 interface{ 50 | m1() 51 | m2() int 52 | } 53 | 54 | var e E 55 | var i1 I1 56 | var i2 I2 57 | var i3 I3 58 | 59 | _ = E(0) 60 | _ = E(nil) 61 | _ = E(e) 62 | _ = E(i1) 63 | _ = E(i2) 64 | 65 | _ = I1(0 /* ERROR "cannot convert" */ ) 66 | _ = I1(nil) 67 | _ = I1(i1) 68 | _ = I1(e /* ERROR "cannot convert" */ ) 69 | _ = I1(i2) 70 | 71 | _ = I2(nil) 72 | _ = I2(i1 /* ERROR "cannot convert" */ ) 73 | _ = I2(i2) 74 | _ = I2(i3 /* ERROR "cannot convert" */ ) 75 | 76 | _ = I3(nil) 77 | _ = I3(i1 /* ERROR "cannot convert" */ ) 78 | _ = I3(i2 /* ERROR "cannot convert" */ ) 79 | _ = I3(i3) 80 | 81 | // TODO(gri) add more tests, improve error message 82 | } 83 | 84 | func issue6326() { 85 | type T unsafe.Pointer 86 | var x T 87 | _ = uintptr(x) // see issue 6326 88 | } 89 | -------------------------------------------------------------------------------- /types/testdata/cycles.src: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package cycles 6 | 7 | type ( 8 | T0 int 9 | T1 /* ERROR "cycle" */ T1 10 | T2 *T2 11 | 12 | T3 /* ERROR "cycle" */ T4 13 | T4 T5 14 | T5 T3 15 | 16 | T6 T7 17 | T7 *T8 18 | T8 T6 19 | 20 | // arrays 21 | A0 /* ERROR "cycle" */ [10]A0 22 | A1 [10]*A1 23 | 24 | A2 /* ERROR "cycle" */ [10]A3 25 | A3 [10]A4 26 | A4 A2 27 | 28 | A5 [10]A6 29 | A6 *A5 30 | 31 | // slices 32 | L0 []L0 33 | 34 | // structs 35 | S0 /* ERROR "cycle" */ struct{ _ S0 } 36 | S1 /* ERROR "cycle" */ struct{ S1 } 37 | S2 struct{ _ *S2 } 38 | S3 struct{ *S3 } 39 | 40 | S4 /* ERROR "cycle" */ struct{ S5 } 41 | S5 struct{ S6 } 42 | S6 S4 43 | 44 | // pointers 45 | P0 *P0 46 | 47 | // functions 48 | F0 func(F0) 49 | F1 func() F1 50 | F2 func(F2) F2 51 | 52 | // interfaces 53 | I0 /* ERROR "cycle" */ interface{ I0 } 54 | 55 | I1 /* ERROR "cycle" */ interface{ I2 } 56 | I2 interface{ I3 } 57 | I3 interface{ I1 } 58 | 59 | I4 interface{ f(I4) } 60 | 61 | // testcase for issue 5090 62 | I5 interface{ f(I6) } 63 | I6 interface{ I5 } 64 | 65 | // maps 66 | M0 map[M0 /* ERROR "invalid map key" */ ]M0 67 | 68 | // channels 69 | C0 chan C0 70 | ) 71 | 72 | func _() { 73 | type ( 74 | t1 /* ERROR "cycle" */ t1 75 | t2 *t2 76 | 77 | t3 t4 /* ERROR "undeclared" */ 78 | t4 t5 /* ERROR "undeclared" */ 79 | t5 t3 80 | 81 | // arrays 82 | a0 /* ERROR "cycle" */ [10]a0 83 | a1 [10]*a1 84 | 85 | // slices 86 | l0 []l0 87 | 88 | // structs 89 | s0 /* ERROR "cycle" */ struct{ _ s0 } 90 | s1 /* ERROR "cycle" */ struct{ s1 } 91 | s2 struct{ _ *s2 } 92 | s3 struct{ *s3 } 93 | 94 | // pointers 95 | p0 *p0 96 | 97 | // functions 98 | f0 func(f0) 99 | f1 func() f1 100 | f2 func(f2) f2 101 | 102 | // interfaces 103 | i0 /* ERROR "cycle" */ interface{ i0 } 104 | 105 | // maps 106 | m0 map[m0 /* ERROR "invalid map key" */ ]m0 107 | 108 | // channels 109 | c0 chan c0 110 | ) 111 | } -------------------------------------------------------------------------------- /types/testdata/decls0.src: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // type declarations 6 | 7 | package decls0 8 | 9 | import "unsafe" 10 | 11 | const pi = 3.1415 12 | 13 | type ( 14 | N undeclared /* ERROR "undeclared" */ 15 | B bool 16 | I int32 17 | A [10]P 18 | T struct { 19 | x, y P 20 | } 21 | P *T 22 | R (*R) 23 | F func(A) I 24 | Y interface { 25 | f(A) I 26 | } 27 | S [](((P))) 28 | M map[I]F 29 | C chan<- I 30 | 31 | // blank types must be typechecked 32 | _ pi /* ERROR "not a type" */ 33 | _ struct{} 34 | _ struct{ pi /* ERROR "not a type" */ } 35 | ) 36 | 37 | 38 | // declarations of init 39 | const _, init /* ERROR "cannot declare init" */ , _ = 0, 1, 2 40 | type init /* ERROR "cannot declare init" */ struct{} 41 | var _, init /* ERROR "cannot declare init" */ int 42 | 43 | func init() {} 44 | func init /* ERROR "missing function body" */ () 45 | 46 | func _() { const init = 0 } 47 | func _() { type init int } 48 | func _() { var init int; _ = init } 49 | 50 | // invalid array types 51 | type ( 52 | iA0 [... /* ERROR "invalid use of '...'" */ ]byte 53 | iA1 [1 /* ERROR "invalid array length" */ <<100]int 54 | iA2 [- /* ERROR "invalid array length" */ 1]complex128 55 | iA3 ["foo" /* ERROR "must be integer" */ ]string 56 | ) 57 | 58 | 59 | type ( 60 | p1 pi /* ERROR "no field or method foo" */ .foo 61 | p2 unsafe.Pointer 62 | ) 63 | 64 | 65 | type ( 66 | Pi pi /* ERROR "not a type" */ 67 | 68 | a /* ERROR "illegal cycle" */ a 69 | a /* ERROR "redeclared" */ int 70 | 71 | // where the cycle error appears depends on the 72 | // order in which declarations are processed 73 | // (which depends on the order in which a map 74 | // is iterated through) 75 | b /* ERROR "illegal cycle" */ c 76 | c d 77 | d e 78 | e b 79 | 80 | t *t 81 | 82 | U V 83 | V *W 84 | W U 85 | 86 | P1 *S2 87 | P2 P1 88 | 89 | S0 struct { 90 | } 91 | S1 struct { 92 | a, b, c int 93 | u, v, a /* ERROR "redeclared" */ float32 94 | } 95 | S2 struct { 96 | S0 // anonymous field 97 | S0 /* ERROR "redeclared" */ int 98 | } 99 | S3 struct { 100 | x S2 101 | } 102 | S4/* ERROR "illegal cycle" */ struct { 103 | S4 104 | } 105 | S5 /* ERROR "illegal cycle" */ struct { 106 | S6 107 | } 108 | S6 struct { 109 | field S7 110 | } 111 | S7 struct { 112 | S5 113 | } 114 | 115 | L1 []L1 116 | L2 []int 117 | 118 | A1 [10.0]int 119 | A2 /* ERROR "illegal cycle" */ [10]A2 120 | A3 /* ERROR "illegal cycle" */ [10]struct { 121 | x A4 122 | } 123 | A4 [10]A3 124 | 125 | F1 func() 126 | F2 func(x, y, z float32) 127 | F3 func(x, y, x /* ERROR "redeclared" */ float32) 128 | F4 func() (x, y, x /* ERROR "redeclared" */ float32) 129 | F5 func(x int) (x /* ERROR "redeclared" */ float32) 130 | F6 func(x ...int) 131 | 132 | I1 interface{} 133 | I2 interface { 134 | m1() 135 | } 136 | I3 interface { 137 | m1() 138 | m1 /* ERROR "redeclared" */ () 139 | } 140 | I4 interface { 141 | m1(x, y, x /* ERROR "redeclared" */ float32) 142 | m2() (x, y, x /* ERROR "redeclared" */ float32) 143 | m3(x int) (x /* ERROR "redeclared" */ float32) 144 | } 145 | I5 interface { 146 | m1(I5) 147 | } 148 | I6 interface { 149 | S0 /* ERROR "not an interface" */ 150 | } 151 | I7 interface { 152 | I1 153 | I1 154 | } 155 | I8 /* ERROR "illegal cycle" */ interface { 156 | I8 157 | } 158 | // Use I09 (rather than I9) because it appears lexically before 159 | // I10 so that we get the illegal cycle here rather then in the 160 | // declaration of I10. If the implementation sorts by position 161 | // rather than name, the error message will still be here. 162 | I09 /* ERROR "illegal cycle" */ interface { 163 | I10 164 | } 165 | I10 interface { 166 | I11 167 | } 168 | I11 interface { 169 | I09 170 | } 171 | 172 | C1 chan int 173 | C2 <-chan int 174 | C3 chan<- C3 175 | C4 chan C5 176 | C5 chan C6 177 | C6 chan C4 178 | 179 | M1 map[Last]string 180 | M2 map[string]M2 181 | 182 | Last int 183 | ) 184 | 185 | // cycles in function/method declarations 186 | // (test cases for issue 5217 and variants) 187 | func f1(x f1 /* ERROR "not a type" */ ) {} 188 | func f2(x *f2 /* ERROR "not a type" */ ) {} 189 | func f3() (x f3 /* ERROR "not a type" */ ) { return } 190 | func f4() (x *f4 /* ERROR "not a type" */ ) { return } 191 | 192 | func (S0) m1(x S0 /* ERROR "field or method" */ .m1) {} 193 | func (S0) m2(x *S0 /* ERROR "field or method" */ .m2) {} 194 | func (S0) m3() (x S0 /* ERROR "field or method" */ .m3) { return } 195 | func (S0) m4() (x *S0 /* ERROR "field or method" */ .m4) { return } 196 | 197 | // interfaces may have blank methods 198 | type BlankI interface { 199 | _() 200 | _(int) 201 | _() int 202 | _(int) int 203 | } 204 | 205 | // non-interface types may have blank methods 206 | type BlankT struct{} 207 | 208 | func (BlankT) _() {} 209 | func (BlankT) _(int) {} 210 | func (BlankT) _() int { return 0 } 211 | func (BlankT) _(int) int { return 0} 212 | 213 | // no type can ever satisfy an interface with a _ method 214 | func _() { 215 | var i BlankI 216 | var x BlankT 217 | i = x /* ERROR "cannot assign" */ 218 | _ = i 219 | } 220 | -------------------------------------------------------------------------------- /types/testdata/decls1.src: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // variable declarations 6 | 7 | package decls1 8 | 9 | import ( 10 | "math" 11 | ) 12 | 13 | // Global variables without initialization 14 | var ( 15 | a, b bool 16 | c byte 17 | d uint8 18 | r rune 19 | i int 20 | j, k, l int 21 | x, y float32 22 | xx, yy float64 23 | u, v complex64 24 | uu, vv complex128 25 | s, t string 26 | array []byte 27 | iface interface{} 28 | 29 | blank _ /* ERROR "cannot use _" */ 30 | ) 31 | 32 | // Global variables with initialization 33 | var ( 34 | s1 = i + j 35 | s2 = i /* ERROR "mismatched types" */ + x 36 | s3 = c + d 37 | s4 = s + t 38 | s5 = s /* ERROR "invalid operation" */ / t 39 | s6 = array[t1] 40 | s7 = array[x /* ERROR "integer" */] 41 | s8 = &a 42 | s10 = &42 /* ERROR "cannot take address" */ 43 | s11 = &v 44 | s12 = -(u + *t11) / *&v 45 | s13 = a /* ERROR "shifted operand" */ << d 46 | s14 = i << j /* ERROR "must be unsigned" */ 47 | s18 = math.Pi * 10.0 48 | s19 = s1 /* ERROR "cannot call" */ () 49 | s20 = f0 /* ERROR "no value" */ () 50 | s21 = f6(1, s1, i) 51 | s22 = f6(1, s1, uu /* ERROR "cannot pass argument" */ ) 52 | 53 | t1 int = i + j 54 | t2 int = i /* ERROR "mismatched types" */ + x 55 | t3 int = c /* ERROR "cannot initialize" */ + d 56 | t4 string = s + t 57 | t5 string = s /* ERROR "invalid operation" */ / t 58 | t6 byte = array[t1] 59 | t7 byte = array[x /* ERROR "must be integer" */] 60 | t8 *int = & /* ERROR "cannot initialize" */ a 61 | t10 *int = &42 /* ERROR "cannot take address" */ 62 | t11 *complex64 = &v 63 | t12 complex64 = -(u + *t11) / *&v 64 | t13 int = a /* ERROR "shifted operand" */ << d 65 | t14 int = i << j /* ERROR "must be unsigned" */ 66 | t15 math /* ERROR "not in selector" */ 67 | t16 math /* ERROR "not declared" */ .xxx 68 | t17 math /* ERROR "not a type" */ .Pi 69 | t18 float64 = math.Pi * 10.0 70 | t19 int = t1 /* ERROR "cannot call" */ () 71 | t20 int = f0 /* ERROR "no value" */ () 72 | ) 73 | 74 | // Various more complex expressions 75 | var ( 76 | u1 = x /* ERROR "not an interface" */ .(int) 77 | u2 = iface.([]int) 78 | u3 = iface.(a /* ERROR "not a type" */ ) 79 | u4, ok = iface.(int) 80 | u5, ok2, ok3 = iface /* ERROR "assignment count mismatch" */ .(int) 81 | ) 82 | 83 | // Constant expression initializations 84 | var ( 85 | v1 = 1 /* ERROR "cannot convert" */ + "foo" 86 | v2 = c + 255 87 | v3 = c + 256 /* ERROR "overflows" */ 88 | v4 = r + 2147483647 89 | v5 = r + 2147483648 /* ERROR "overflows" */ 90 | v6 = 42 91 | v7 = v6 + 9223372036854775807 92 | v8 = v6 + 9223372036854775808 /* ERROR "overflows" */ 93 | v9 = i + 1 << 10 94 | v10 byte = 1024 /* ERROR "overflows" */ 95 | v11 = xx/yy*yy - xx 96 | v12 = true && false 97 | v13 = nil /* ERROR "use of untyped nil" */ 98 | ) 99 | 100 | // Multiple assignment expressions 101 | var ( 102 | m1a, m1b = 1, 2 103 | m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2 104 | m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */ 105 | ) 106 | 107 | func _() { 108 | var ( 109 | m1a, m1b = 1, 2 110 | m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2 111 | m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */ 112 | ) 113 | 114 | _, _ = m1a, m1b 115 | _, _, _ = m2a, m2b, m2c 116 | _, _ = m3a, m3b 117 | } 118 | 119 | // Declaration of parameters and results 120 | func f0() {} 121 | func f1(a /* ERROR "not a type" */) {} 122 | func f2(a, b, c d /* ERROR "not a type" */) {} 123 | 124 | func f3() int { return 0 } 125 | func f4() a /* ERROR "not a type" */ { return 0 } 126 | func f5() (a, b, c d /* ERROR "not a type" */) { return } 127 | 128 | func f6(a, b, c int) complex128 { return 0 } 129 | 130 | // Declaration of receivers 131 | type T struct{} 132 | 133 | func (T) m0() {} 134 | func (*T) m1() {} 135 | func (x T) m2() {} 136 | func (x *T) m3() {} 137 | 138 | // Initialization functions 139 | func init() {} 140 | func /* ERROR "no arguments and no return values" */ init(int) {} 141 | func /* ERROR "no arguments and no return values" */ init() int { return 0 } 142 | func /* ERROR "no arguments and no return values" */ init(int) int { return 0 } 143 | func (T) init(int) int { return 0 } 144 | -------------------------------------------------------------------------------- /types/testdata/decls2a.src: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // method declarations 6 | 7 | package decls2 8 | 9 | import "time" 10 | import "unsafe" 11 | 12 | // T1 declared before its methods. 13 | type T1 struct{ 14 | f int 15 | } 16 | 17 | func (T1) m() {} 18 | func (T1) m /* ERROR "already declared" */ () {} 19 | func (x *T1) f /* ERROR "field and method" */ () {} 20 | 21 | // Conflict between embedded field and method name, 22 | // with the embedded field being a basic type. 23 | type T1b struct { 24 | int 25 | } 26 | 27 | func (T1b) int /* ERROR "field and method" */ () {} 28 | 29 | type T1c struct { 30 | time.Time 31 | } 32 | 33 | func (T1c) Time /* ERROR "field and method" */ () int { return 0 } 34 | 35 | // Disabled for now: LookupFieldOrMethod will find Pointer even though 36 | // it's double-declared (it would cost extra in the common case to verify 37 | // this). But the MethodSet computation will not find it due to the name 38 | // collision caused by the double-declaration, leading to an internal 39 | // inconsistency while we are verifying one computation against the other. 40 | // var _ = T1c{}.Pointer 41 | 42 | // T2's method declared before the type. 43 | func (*T2) f /* ERROR "field and method" */ () {} 44 | 45 | type T2 struct { 46 | f int 47 | } 48 | 49 | // Methods declared without a declared type. 50 | func (undeclared /* ERROR "undeclared" */) m() {} 51 | func (x *undeclared /* ERROR "undeclared" */) m() {} 52 | 53 | func (pi /* ERROR "not a type" */) m1() {} 54 | func (x pi /* ERROR "not a type" */) m2() {} 55 | func (x *pi /* ERROR "not a type" */ ) m3() {} 56 | 57 | // Blank types. 58 | type _ struct { m int } 59 | type _ struct { m int } 60 | 61 | func (_ /* ERROR "cannot use _" */) m() {} 62 | func m(_ /* ERROR "cannot use _" */) {} 63 | 64 | // Methods with receiver base type declared in another file. 65 | func (T3) m1() {} 66 | func (*T3) m2() {} 67 | func (x T3) m3() {} 68 | func (x *T3) f /* ERROR "field and method" */ () {} 69 | 70 | // Methods of non-struct type. 71 | type T4 func() 72 | 73 | func (self T4) m() func() { return self } 74 | 75 | // Methods associated with an interface. 76 | type T5 interface { 77 | m() int 78 | } 79 | 80 | func (T5 /* ERROR "invalid receiver" */ ) m1() {} 81 | func (T5 /* ERROR "invalid receiver" */ ) m2() {} 82 | 83 | // Methods associated with non-local or unnamed types. 84 | func (int /* ERROR "invalid receiver" */ ) m() {} 85 | func ([ /* ERROR "identifier" */ ]int) m() {} 86 | func (time /* ERROR "identifier" */ .Time) m() {} 87 | func (*time /* ERROR "identifier" */ .Time) m() {} 88 | func (x interface /* ERROR "identifier" */ {}) m() {} 89 | 90 | // Unsafe.Pointer is treated like a pointer when used as receiver type. 91 | type UP unsafe.Pointer 92 | func (UP /* ERROR "invalid" */ ) m1() {} 93 | func (* /* ERROR "invalid" */ UP) m2() {} 94 | 95 | // Double declarations across package files 96 | const c_double = 0 97 | type t_double int 98 | var v_double int 99 | func f_double() {} 100 | -------------------------------------------------------------------------------- /types/testdata/decls2b.src: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // method declarations 6 | 7 | package decls2 8 | 9 | import "io" 10 | 11 | const pi = 3.1415 12 | 13 | func (T1) m /* ERROR "already declared" */ () {} 14 | func (T2) m(io.Writer) {} 15 | 16 | type T3 struct { 17 | f *T3 18 | } 19 | 20 | type T6 struct { 21 | x int 22 | } 23 | 24 | func (t *T6) m1() int { 25 | return t.x 26 | } 27 | 28 | func f() { 29 | var t *T6 30 | t.m1() 31 | } 32 | 33 | // Double declarations across package files 34 | const c_double /* ERROR "redeclared" */ = 0 35 | type t_double /* ERROR "redeclared" */ int 36 | var v_double /* ERROR "redeclared" */ int 37 | func f_double /* ERROR "redeclared" */ () {} 38 | 39 | // Blank methods need to be type-checked. 40 | // Verify by checking that errors are reported. 41 | func (T /* ERROR "undeclared" */ ) _() {} 42 | func (T1) _(undeclared /* ERROR "undeclared" */ ) {} 43 | func (T1) _() int { return "foo" /* ERROR "cannot convert" */ } 44 | 45 | // Methods with undeclared receiver type can still be checked. 46 | // Verify by checking that errors are reported. 47 | func (Foo /* ERROR "undeclared" */ ) m() {} 48 | func (Foo /* ERROR "undeclared" */ ) m(undeclared /* ERROR "undeclared" */ ) {} 49 | func (Foo /* ERROR "undeclared" */ ) m() int { return "foo" /* ERROR "cannot convert" */ } 50 | 51 | func (Foo /* ERROR "undeclared" */ ) _() {} 52 | func (Foo /* ERROR "undeclared" */ ) _(undeclared /* ERROR "undeclared" */ ) {} 53 | func (Foo /* ERROR "undeclared" */ ) _() int { return "foo" /* ERROR "cannot convert" */ } 54 | -------------------------------------------------------------------------------- /types/testdata/decls3.src: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // embedded types 6 | 7 | package decls3 8 | 9 | import "unsafe" 10 | import "fmt" 11 | 12 | // fields with the same name at the same level cancel each other out 13 | 14 | func _() { 15 | type ( 16 | T1 struct { X int } 17 | T2 struct { X int } 18 | T3 struct { T1; T2 } // X is embedded twice at the same level via T1->X, T2->X 19 | ) 20 | 21 | var t T3 22 | _ = t /* ERROR "ambiguous selector" */ .X 23 | } 24 | 25 | func _() { 26 | type ( 27 | T1 struct { X int } 28 | T2 struct { T1 } 29 | T3 struct { T1 } 30 | T4 struct { T2; T3 } // X is embedded twice at the same level via T2->T1->X, T3->T1->X 31 | ) 32 | 33 | var t T4 34 | _ = t /* ERROR "ambiguous selector" */ .X 35 | } 36 | 37 | func issue4355() { 38 | type ( 39 | T1 struct {X int} 40 | T2 struct {T1} 41 | T3 struct {T2} 42 | T4 struct {T2} 43 | T5 struct {T3; T4} // X is embedded twice at the same level via T3->T2->T1->X, T4->T2->T1->X 44 | ) 45 | 46 | var t T5 47 | _ = t /* ERROR "ambiguous selector" */ .X 48 | } 49 | 50 | func _() { 51 | type State int 52 | type A struct{ State } 53 | type B struct{ fmt.State } 54 | type T struct{ A; B } 55 | 56 | var t T 57 | _ = t /* ERROR "ambiguous selector" */ .State 58 | } 59 | 60 | // Embedded fields can be predeclared types. 61 | 62 | func _() { 63 | type T0 struct{ 64 | int 65 | float32 66 | f int 67 | } 68 | var x T0 69 | _ = x.int 70 | _ = x.float32 71 | _ = x.f 72 | 73 | type T1 struct{ 74 | T0 75 | } 76 | var y T1 77 | _ = y.int 78 | _ = y.float32 79 | _ = y.f 80 | } 81 | 82 | // Restrictions on embedded field types. 83 | 84 | func _() { 85 | type I1 interface{} 86 | type I2 interface{} 87 | type P1 *int 88 | type P2 *int 89 | type UP unsafe.Pointer 90 | 91 | type T1 struct { 92 | I1 93 | * /* ERROR "cannot be a pointer to an interface" */ I2 94 | * /* ERROR "cannot be a pointer to an interface" */ error 95 | P1 /* ERROR "cannot be a pointer" */ 96 | * /* ERROR "cannot be a pointer" */ P2 97 | } 98 | 99 | // unsafe.Pointers are treated like regular pointers when embedded 100 | type T2 struct { 101 | unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer 102 | */* ERROR "cannot be unsafe.Pointer" */ unsafe.Pointer 103 | UP /* ERROR "cannot be unsafe.Pointer" */ 104 | * /* ERROR "cannot be unsafe.Pointer" */ UP 105 | } 106 | } 107 | 108 | // Named types that are pointers. 109 | 110 | type S struct{ x int } 111 | func (*S) m() {} 112 | type P *S 113 | 114 | func _() { 115 | var s *S 116 | _ = s.x 117 | _ = s.m 118 | 119 | var p P 120 | _ = p.x 121 | _ = p /* ERROR "no field or method" */ .m 122 | _ = P /* ERROR "no field or method" */ .m 123 | } 124 | 125 | // Borrowed from the FieldByName test cases in reflect/all_test.go. 126 | 127 | type D1 struct { 128 | d int 129 | } 130 | type D2 struct { 131 | d int 132 | } 133 | 134 | type S0 struct { 135 | A, B, C int 136 | D1 137 | D2 138 | } 139 | 140 | type S1 struct { 141 | B int 142 | S0 143 | } 144 | 145 | type S2 struct { 146 | A int 147 | *S1 148 | } 149 | 150 | type S1x struct { 151 | S1 152 | } 153 | 154 | type S1y struct { 155 | S1 156 | } 157 | 158 | type S3 struct { 159 | S1x 160 | S2 161 | D, E int 162 | *S1y 163 | } 164 | 165 | type S4 struct { 166 | *S4 167 | A int 168 | } 169 | 170 | // The X in S6 and S7 annihilate, but they also block the X in S8.S9. 171 | type S5 struct { 172 | S6 173 | S7 174 | S8 175 | } 176 | 177 | type S6 struct { 178 | X int 179 | } 180 | 181 | type S7 S6 182 | 183 | type S8 struct { 184 | S9 185 | } 186 | 187 | type S9 struct { 188 | X int 189 | Y int 190 | } 191 | 192 | // The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9. 193 | type S10 struct { 194 | S11 195 | S12 196 | S13 197 | } 198 | 199 | type S11 struct { 200 | S6 201 | } 202 | 203 | type S12 struct { 204 | S6 205 | } 206 | 207 | type S13 struct { 208 | S8 209 | } 210 | 211 | func _() { 212 | _ = struct /* ERROR "no field or method" */ {}{}.Foo 213 | _ = S0{}.A 214 | _ = S0 /* ERROR "no field or method" */ {}.D 215 | _ = S1{}.A 216 | _ = S1{}.B 217 | _ = S1{}.S0 218 | _ = S1{}.C 219 | _ = S2{}.A 220 | _ = S2{}.S1 221 | _ = S2{}.B 222 | _ = S2{}.C 223 | _ = S2 /* ERROR "no field or method" */ {}.D 224 | _ = S3 /* ERROR "ambiguous selector" */ {}.S1 225 | _ = S3{}.A 226 | _ = S3 /* ERROR "ambiguous selector" */ {}.B 227 | _ = S3{}.D 228 | _ = S3{}.E 229 | _ = S4{}.A 230 | _ = S4 /* ERROR "no field or method" */ {}.B 231 | _ = S5 /* ERROR "ambiguous selector" */ {}.X 232 | _ = S5{}.Y 233 | _ = S10 /* ERROR "ambiguous selector" */ {}.X 234 | _ = S10{}.Y 235 | } 236 | 237 | // Borrowed from the FieldByName benchmark in reflect/all_test.go. 238 | 239 | type R0 struct { 240 | *R1 241 | *R2 242 | *R3 243 | *R4 244 | } 245 | 246 | type R1 struct { 247 | *R5 248 | *R6 249 | *R7 250 | *R8 251 | } 252 | 253 | type R2 R1 254 | type R3 R1 255 | type R4 R1 256 | 257 | type R5 struct { 258 | *R9 259 | *R10 260 | *R11 261 | *R12 262 | } 263 | 264 | type R6 R5 265 | type R7 R5 266 | type R8 R5 267 | 268 | type R9 struct { 269 | *R13 270 | *R14 271 | *R15 272 | *R16 273 | } 274 | 275 | type R10 R9 276 | type R11 R9 277 | type R12 R9 278 | 279 | type R13 struct { 280 | *R17 281 | *R18 282 | *R19 283 | *R20 284 | } 285 | 286 | type R14 R13 287 | type R15 R13 288 | type R16 R13 289 | 290 | type R17 struct { 291 | *R21 292 | *R22 293 | *R23 294 | *R24 295 | } 296 | 297 | type R18 R17 298 | type R19 R17 299 | type R20 R17 300 | 301 | type R21 struct { 302 | X int 303 | } 304 | 305 | type R22 R21 306 | type R23 R21 307 | type R24 R21 308 | 309 | var _ = R0 /* ERROR "ambiguous selector" */ {}.X -------------------------------------------------------------------------------- /types/testdata/errors.src: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // testing precise operand formatting in error messages 6 | // (matching messages are regular expressions, hence the \'s) 7 | 8 | package errors 9 | 10 | func f(x int, m map[string]int) { 11 | // no values 12 | _ = f /* ERROR "f\(0, m\) \(no value\) used as value" */ (0, m) 13 | 14 | // built-ins 15 | _ = println /* ERROR "println \(built-in\) must be called" */ 16 | 17 | // types 18 | _ = complex128 /* ERROR "complex128 \(type\) is not an expression" */ 19 | 20 | // constants 21 | const c1 = 991 22 | const c2 float32 = 0.5 23 | 0 /* ERROR "0 \(untyped integer constant\) is not used" */ 24 | c1 /* ERROR "c1 \(untyped integer constant 991\) is not used" */ 25 | c2 /* ERROR "c2 \(constant 1/2 of type float32\) is not used" */ 26 | c1 /* ERROR "c1 \+ c2 \(constant 1983/2 of type float32\) is not used" */ + c2 27 | 28 | // variables 29 | x /* ERROR "x \(variable of type int\) is not used" */ 30 | 31 | // values 32 | x /* ERROR "x != x \(untyped boolean value\) is not used" */ != x 33 | x /* ERROR "x \+ x \(value of type int\) is not used" */ + x 34 | 35 | // value, ok's 36 | const s = "foo" 37 | m /* ERROR "m\[s\] \(map index expression of type int\) is not used" */ [s] 38 | } 39 | 40 | // Valid ERROR comments can have a variety of forms. 41 | func _() { 42 | 0 /* ERROR "0 .* is not used" */ 43 | 0 /* ERROR 0 .* is not used */ 44 | 0 // ERROR "0 .* is not used" 45 | 0 // ERROR 0 .* is not used 46 | } 47 | -------------------------------------------------------------------------------- /types/testdata/exports.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file is used to generate an object file which 6 | // serves as test file for gcimporter_test.go. 7 | 8 | package exports 9 | 10 | import ( 11 | "go/ast" 12 | ) 13 | 14 | // Issue 3682: Correctly read dotted identifiers from export data. 15 | const init1 = 0 16 | 17 | func init() {} 18 | 19 | const ( 20 | C0 int = 0 21 | C1 = 3.14159265 22 | C2 = 2.718281828i 23 | C3 = -123.456e-789 24 | C4 = +123.456E+789 25 | C5 = 1234i 26 | C6 = "foo\n" 27 | C7 = `bar\n` 28 | ) 29 | 30 | type ( 31 | T1 int 32 | T2 [10]int 33 | T3 []int 34 | T4 *int 35 | T5 chan int 36 | T6a chan<- int 37 | T6b chan (<-chan int) 38 | T6c chan<- (chan int) 39 | T7 <-chan *ast.File 40 | T8 struct{} 41 | T9 struct { 42 | a int 43 | b, c float32 44 | d []string `go:"tag"` 45 | } 46 | T10 struct { 47 | T8 48 | T9 49 | _ *T10 50 | } 51 | T11 map[int]string 52 | T12 interface{} 53 | T13 interface { 54 | m1() 55 | m2(int) float32 56 | } 57 | T14 interface { 58 | T12 59 | T13 60 | m3(x ...struct{}) []T9 61 | } 62 | T15 func() 63 | T16 func(int) 64 | T17 func(x int) 65 | T18 func() float32 66 | T19 func() (x float32) 67 | T20 func(...interface{}) 68 | T21 struct{ next *T21 } 69 | T22 struct{ link *T23 } 70 | T23 struct{ link *T22 } 71 | T24 *T24 72 | T25 *T26 73 | T26 *T27 74 | T27 *T25 75 | T28 func(T28) T28 76 | ) 77 | 78 | var ( 79 | V0 int 80 | V1 = -991.0 81 | ) 82 | 83 | func F1() {} 84 | func F2(x int) {} 85 | func F3() int { return 0 } 86 | func F4() float32 { return 0 } 87 | func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10) 88 | 89 | func (p *T1) M1() 90 | -------------------------------------------------------------------------------- /types/testdata/expr0.src: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // unary expressions 6 | 7 | package expr0 8 | 9 | var ( 10 | // bool 11 | b0 = true 12 | b1 bool = b0 13 | b2 = !true 14 | b3 = !b1 15 | b4 bool = !true 16 | b5 bool = !b4 17 | b6 = +b0 /* ERROR "not defined" */ 18 | b7 = -b0 /* ERROR "not defined" */ 19 | b8 = ^b0 /* ERROR "not defined" */ 20 | b9 = *b0 /* ERROR "cannot indirect" */ 21 | b10 = &true /* ERROR "cannot take address" */ 22 | b11 = &b0 23 | b12 = <-b0 /* ERROR "cannot receive" */ 24 | 25 | // int 26 | i0 = 1 27 | i1 int = i0 28 | i2 = +1 29 | i3 = +i0 30 | i4 int = +1 31 | i5 int = +i4 32 | i6 = -1 33 | i7 = -i0 34 | i8 int = -1 35 | i9 int = -i4 36 | i10 = !i0 /* ERROR "not defined" */ 37 | i11 = ^1 38 | i12 = ^i0 39 | i13 int = ^1 40 | i14 int = ^i4 41 | i15 = *i0 /* ERROR "cannot indirect" */ 42 | i16 = &i0 43 | i17 = *i16 44 | i18 = <-i16 /* ERROR "cannot receive" */ 45 | 46 | // uint 47 | u0 = uint(1) 48 | u1 uint = u0 49 | u2 = +1 50 | u3 = +u0 51 | u4 uint = +1 52 | u5 uint = +u4 53 | u6 = -1 54 | u7 = -u0 55 | u8 uint = - /* ERROR "overflows" */ 1 56 | u9 uint = -u4 57 | u10 = !u0 /* ERROR "not defined" */ 58 | u11 = ^1 59 | u12 = ^i0 60 | u13 uint = ^ /* ERROR "overflows" */ 1 61 | u14 uint = ^u4 62 | u15 = *u0 /* ERROR "cannot indirect" */ 63 | u16 = &u0 64 | u17 = *u16 65 | u18 = <-u16 /* ERROR "cannot receive" */ 66 | u19 = ^uint(0) 67 | 68 | // float64 69 | f0 = float64(1) 70 | f1 float64 = f0 71 | f2 = +1 72 | f3 = +f0 73 | f4 float64 = +1 74 | f5 float64 = +f4 75 | f6 = -1 76 | f7 = -f0 77 | f8 float64 = -1 78 | f9 float64 = -f4 79 | f10 = !f0 /* ERROR "not defined" */ 80 | f11 = ^1 81 | f12 = ^i0 82 | f13 float64 = ^1 83 | f14 float64 = ^f4 /* ERROR "not defined" */ 84 | f15 = *f0 /* ERROR "cannot indirect" */ 85 | f16 = &f0 86 | f17 = *u16 87 | f18 = <-u16 /* ERROR "cannot receive" */ 88 | 89 | // complex128 90 | c0 = complex128(1) 91 | c1 complex128 = c0 92 | c2 = +1 93 | c3 = +c0 94 | c4 complex128 = +1 95 | c5 complex128 = +c4 96 | c6 = -1 97 | c7 = -c0 98 | c8 complex128 = -1 99 | c9 complex128 = -c4 100 | c10 = !c0 /* ERROR "not defined" */ 101 | c11 = ^1 102 | c12 = ^i0 103 | c13 complex128 = ^1 104 | c14 complex128 = ^c4 /* ERROR "not defined" */ 105 | c15 = *c0 /* ERROR "cannot indirect" */ 106 | c16 = &c0 107 | c17 = *u16 108 | c18 = <-u16 /* ERROR "cannot receive" */ 109 | 110 | // string 111 | s0 = "foo" 112 | s1 = +"foo" /* ERROR "not defined" */ 113 | s2 = -s0 /* ERROR "not defined" */ 114 | s3 = !s0 /* ERROR "not defined" */ 115 | s4 = ^s0 /* ERROR "not defined" */ 116 | s5 = *s4 /* ERROR "cannot indirect" */ 117 | s6 = &s4 118 | s7 = *s6 119 | s8 = <-s7 /* ERROR "cannot receive" */ 120 | 121 | // channel 122 | ch chan int 123 | rc <-chan float64 124 | sc chan <- string 125 | ch0 = +ch /* ERROR "not defined" */ 126 | ch1 = -ch /* ERROR "not defined" */ 127 | ch2 = !ch /* ERROR "not defined" */ 128 | ch3 = ^ch /* ERROR "not defined" */ 129 | ch4 = *ch /* ERROR "cannot indirect" */ 130 | ch5 = &ch 131 | ch6 = *ch5 132 | ch7 = <-ch 133 | ch8 = <-rc 134 | ch9 = <-sc /* ERROR "cannot receive" */ 135 | ) 136 | 137 | // address of composite literals 138 | type T struct{x, y int} 139 | 140 | func f() T { return T{} } 141 | 142 | var ( 143 | _ = &T{1, 2} 144 | _ = &[...]int{} 145 | _ = &[]int{} 146 | _ = &[]int{} 147 | _ = &map[string]T{} 148 | _ = &(T{1, 2}) 149 | _ = &((((T{1, 2})))) 150 | _ = &f /* ERROR "cannot take address" */ () 151 | ) 152 | 153 | // recursive pointer types 154 | type P *P 155 | 156 | var ( 157 | p1 P = new(P) 158 | p2 P = *p1 159 | p3 P = &p2 160 | ) 161 | 162 | -------------------------------------------------------------------------------- /types/testdata/expr1.src: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // binary expressions 6 | 7 | package expr1 8 | -------------------------------------------------------------------------------- /types/testdata/expr2.src: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // comparisons 6 | 7 | package expr2 8 | 9 | func _bool() { 10 | const t = true == true 11 | const f = true == false 12 | _ = t /* ERROR "cannot compare" */ < f 13 | _ = 0 /* ERROR "cannot convert" */ == t 14 | var b bool 15 | var x, y float32 16 | b = x < y 17 | _ = b 18 | _ = struct{b bool}{x < y} 19 | } 20 | 21 | // corner cases 22 | var ( 23 | v0 = nil /* ERROR "cannot compare" */ == nil 24 | ) -------------------------------------------------------------------------------- /types/testdata/importdecl0a.src: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package importdecl0 6 | 7 | import () 8 | 9 | import ( 10 | // we can have multiple blank imports (was bug) 11 | _ "math" 12 | _ "net/rpc" 13 | init /* ERROR "cannot declare init" */ "fmt" 14 | // reflect defines a type "flag" which shows up in the gc export data 15 | "reflect" 16 | . /* ERROR "imported but not used" */ "reflect" 17 | ) 18 | 19 | import "math" /* ERROR "imported but not used" */ 20 | import m /* ERROR "imported but not used" */ "math" 21 | import _ "math" 22 | 23 | import ( 24 | "math/big" /* ERROR "imported but not used" */ 25 | b /* ERROR "imported but not used" */ "math/big" 26 | _ "math/big" 27 | ) 28 | 29 | import "fmt" 30 | import f "fmt" 31 | 32 | // reflect.flag must not be visible in this package 33 | type flag int 34 | type _ reflect /* ERROR "not exported" */ .flag 35 | 36 | // dot-imported exported objects may conflict with local objects 37 | type Value /* ERROR "already declared in this file" */ struct{} 38 | 39 | var _ = fmt.Println // use "fmt" 40 | 41 | func _() { 42 | f.Println() // use "fmt" 43 | } 44 | -------------------------------------------------------------------------------- /types/testdata/importdecl0b.src: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package importdecl0 6 | 7 | import "math" 8 | import m "math" 9 | 10 | import . "testing" // declares T in file scope 11 | import . /* ERROR "imported but not used" */ "unsafe" 12 | import . "fmt" // declares Println in file scope 13 | 14 | // using "math" in this file doesn't affect its use in other files 15 | const Pi0 = math.Pi 16 | const Pi1 = m.Pi 17 | 18 | type _ T // use "testing" 19 | 20 | func _() func() interface{} { 21 | return func() interface{} { 22 | return Println // use "fmt" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /types/testdata/labels.src: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file is a modified concatenation of the files 6 | // $GOROOT/test/label.go and $GOROOT/test/label1.go. 7 | 8 | package labels 9 | 10 | var x int 11 | 12 | func f0() { 13 | L1 /* ERROR "label L1 declared but not used" */ : 14 | for { 15 | } 16 | L2 /* ERROR "label L2 declared but not used" */ : 17 | select { 18 | } 19 | L3 /* ERROR "label L3 declared but not used" */ : 20 | switch { 21 | } 22 | L4 /* ERROR "label L4 declared but not used" */ : 23 | if true { 24 | } 25 | L5 /* ERROR "label L5 declared but not used" */ : 26 | f0() 27 | L6: 28 | f0() 29 | L6 /* ERROR "label L6 already declared" */ : 30 | f0() 31 | if x == 20 { 32 | goto L6 33 | } 34 | 35 | L7: 36 | for { 37 | break L7 38 | break L8 /* ERROR "invalid break label L8" */ 39 | } 40 | 41 | // A label must be directly associated with a switch, select, or 42 | // for statement; it cannot be the label of a labeled statement. 43 | 44 | L7a /* ERROR "declared but not used" */ : L7b: 45 | for { 46 | break L7a /* ERROR "invalid break label L7a" */ 47 | continue L7a /* ERROR "invalid continue label L7a" */ 48 | continue L7b 49 | } 50 | 51 | L8: 52 | for { 53 | if x == 21 { 54 | continue L8 55 | continue L7 /* ERROR "invalid continue label L7" */ 56 | } 57 | } 58 | 59 | L9: 60 | switch { 61 | case true: 62 | break L9 63 | defalt /* ERROR "label defalt declared but not used" */ : 64 | } 65 | 66 | L10: 67 | select { 68 | default: 69 | break L10 70 | break L9 /* ERROR "invalid break label L9" */ 71 | } 72 | 73 | goto L10a 74 | L10a: L10b: 75 | select { 76 | default: 77 | break L10a /* ERROR "invalid break label L10a" */ 78 | break L10b 79 | continue L10b /* ERROR "invalid continue label L10b" */ 80 | } 81 | } 82 | 83 | func f1() { 84 | L1: 85 | for { 86 | if x == 0 { 87 | break L1 88 | } 89 | if x == 1 { 90 | continue L1 91 | } 92 | goto L1 93 | } 94 | 95 | L2: 96 | select { 97 | default: 98 | if x == 0 { 99 | break L2 100 | } 101 | if x == 1 { 102 | continue L2 /* ERROR "invalid continue label L2" */ 103 | } 104 | goto L2 105 | } 106 | 107 | L3: 108 | switch { 109 | case x > 10: 110 | if x == 11 { 111 | break L3 112 | } 113 | if x == 12 { 114 | continue L3 /* ERROR "invalid continue label L3" */ 115 | } 116 | goto L3 117 | } 118 | 119 | L4: 120 | if true { 121 | if x == 13 { 122 | break L4 /* ERROR "invalid break label L4" */ 123 | } 124 | if x == 14 { 125 | continue L4 /* ERROR "invalid continue label L4" */ 126 | } 127 | if x == 15 { 128 | goto L4 129 | } 130 | } 131 | 132 | L5: 133 | f1() 134 | if x == 16 { 135 | break L5 /* ERROR "invalid break label L5" */ 136 | } 137 | if x == 17 { 138 | continue L5 /* ERROR "invalid continue label L5" */ 139 | } 140 | if x == 18 { 141 | goto L5 142 | } 143 | 144 | for { 145 | if x == 19 { 146 | break L1 /* ERROR "invalid break label L1" */ 147 | } 148 | if x == 20 { 149 | continue L1 /* ERROR "invalid continue label L1" */ 150 | } 151 | if x == 21 { 152 | goto L1 153 | } 154 | } 155 | } 156 | 157 | // Additional tests not in the original files. 158 | 159 | func f2() { 160 | L1 /* ERROR "label L1 declared but not used" */ : 161 | if x == 0 { 162 | for { 163 | continue L1 /* ERROR "invalid continue label L1" */ 164 | } 165 | } 166 | } 167 | 168 | func f3() { 169 | L1: 170 | L2: 171 | L3: 172 | for { 173 | break L1 /* ERROR "invalid break label L1" */ 174 | break L2 /* ERROR "invalid break label L2" */ 175 | break L3 176 | continue L1 /* ERROR "invalid continue label L1" */ 177 | continue L2 /* ERROR "invalid continue label L2" */ 178 | continue L3 179 | goto L1 180 | goto L2 181 | goto L3 182 | } 183 | } -------------------------------------------------------------------------------- /types/testdata/methodsets.src: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package methodsets 6 | 7 | type T0 struct {} 8 | 9 | func (T0) v0() {} 10 | func (*T0) p0() {} 11 | 12 | type T1 struct {} // like T0 with different method names 13 | 14 | func (T1) v1() {} 15 | func (*T1) p1() {} 16 | 17 | type T2 interface { 18 | v2() 19 | p2() 20 | } 21 | 22 | type T3 struct { 23 | T0 24 | *T1 25 | T2 26 | } 27 | 28 | // Method expressions 29 | func _() { 30 | var ( 31 | _ func(T0) = T0.v0 32 | _ = T0 /* ERROR "not in method set" */ .p0 33 | 34 | _ func (*T0) = (*T0).v0 35 | _ func (*T0) = (*T0).p0 36 | 37 | // T1 is like T0 38 | 39 | _ func(T2) = T2.v2 40 | _ func(T2) = T2.p2 41 | 42 | _ func(T3) = T3.v0 43 | _ func(T3) = T3 /* ERROR "not in method set" */ .p0 44 | _ func(T3) = T3.v1 45 | _ func(T3) = T3.p1 46 | _ func(T3) = T3.v2 47 | _ func(T3) = T3.p2 48 | 49 | _ func(*T3) = (*T3).v0 50 | _ func(*T3) = (*T3).p0 51 | _ func(*T3) = (*T3).v1 52 | _ func(*T3) = (*T3).p1 53 | _ func(*T3) = (*T3).v2 54 | _ func(*T3) = (*T3).p2 55 | ) 56 | } 57 | 58 | // Method values with addressable receivers 59 | func _() { 60 | var ( 61 | v0 T0 62 | _ func() = v0.v0 63 | _ func() = v0.p0 64 | ) 65 | 66 | var ( 67 | p0 *T0 68 | _ func() = p0.v0 69 | _ func() = p0.p0 70 | ) 71 | 72 | // T1 is like T0 73 | 74 | var ( 75 | v2 T2 76 | _ func() = v2.v2 77 | _ func() = v2.p2 78 | ) 79 | 80 | var ( 81 | v4 T3 82 | _ func() = v4.v0 83 | _ func() = v4.p0 84 | _ func() = v4.v1 85 | _ func() = v4.p1 86 | _ func() = v4.v2 87 | _ func() = v4.p2 88 | ) 89 | 90 | var ( 91 | p4 *T3 92 | _ func() = p4.v0 93 | _ func() = p4.p0 94 | _ func() = p4.v1 95 | _ func() = p4.p1 96 | _ func() = p4.v2 97 | _ func() = p4.p2 98 | ) 99 | } 100 | 101 | // Method calls with addressable receivers 102 | func _() { 103 | var v0 T0 104 | v0.v0() 105 | v0.p0() 106 | 107 | var p0 *T0 108 | p0.v0() 109 | p0.p0() 110 | 111 | // T1 is like T0 112 | 113 | var v2 T2 114 | v2.v2() 115 | v2.p2() 116 | 117 | var v4 T3 118 | v4.v0() 119 | v4.p0() 120 | v4.v1() 121 | v4.p1() 122 | v4.v2() 123 | v4.p2() 124 | 125 | var p4 *T3 126 | p4.v0() 127 | p4.p0() 128 | p4.v1() 129 | p4.p1() 130 | p4.v2() 131 | p4.p2() 132 | } 133 | 134 | // Method values with value receivers 135 | func _() { 136 | var ( 137 | _ func() = T0{}.v0 138 | _ func() = T0 /* ERROR "not in method set" */ {}.p0 139 | 140 | _ func() = (&T0{}).v0 141 | _ func() = (&T0{}).p0 142 | 143 | // T1 is like T0 144 | 145 | // no values for T2 146 | 147 | _ func() = T3{}.v0 148 | _ func() = T3 /* ERROR "not in method set" */ {}.p0 149 | _ func() = T3{}.v1 150 | _ func() = T3{}.p1 151 | _ func() = T3{}.v2 152 | _ func() = T3{}.p2 153 | 154 | _ func() = (&T3{}).v0 155 | _ func() = (&T3{}).p0 156 | _ func() = (&T3{}).v1 157 | _ func() = (&T3{}).p1 158 | _ func() = (&T3{}).v2 159 | _ func() = (&T3{}).p2 160 | ) 161 | } 162 | 163 | // Method calls with value receivers 164 | func _() { 165 | T0{}.v0() 166 | T0 /* ERROR "not in method set" */ {}.p0() 167 | 168 | (&T0{}).v0() 169 | (&T0{}).p0() 170 | 171 | // T1 is like T0 172 | 173 | // no values for T2 174 | 175 | T3{}.v0() 176 | T3 /* ERROR "not in method set" */ {}.p0() 177 | T3{}.v1() 178 | T3{}.p1() 179 | T3{}.v2() 180 | T3{}.p2() 181 | 182 | (&T3{}).v0() 183 | (&T3{}).p0() 184 | (&T3{}).v1() 185 | (&T3{}).p1() 186 | (&T3{}).v2() 187 | (&T3{}).p2() 188 | } 189 | 190 | // *T has no methods if T is an interface type 191 | func issue5918() { 192 | var ( 193 | err error 194 | _ = err.Error() 195 | _ func() string = err.Error 196 | _ func(error) string = error.Error 197 | 198 | perr = &err 199 | _ = perr /* ERROR "no field or method" */ .Error() 200 | _ func() string = perr /* ERROR "no field or method" */ .Error 201 | _ func(*error) string = ( /* ERROR "no field or method" */ *error).Error 202 | ) 203 | 204 | type T *interface{ m() int } 205 | var ( 206 | x T 207 | _ = (*x).m() 208 | _ = (*x).m 209 | 210 | _ = x /* ERROR "no field or method" */ .m() 211 | _ = x /* ERROR "no field or method" */ .m 212 | _ = T /* ERROR "no field or method" */ .m 213 | ) 214 | } 215 | -------------------------------------------------------------------------------- /types/testdata/stmt1.src: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // terminating statements 6 | 7 | package stmt1 8 | 9 | func _() {} 10 | 11 | func _() int {} /* ERROR "missing return" */ 12 | 13 | func _() int { panic(0) } 14 | func _() int { (panic(0)) } 15 | 16 | // block statements 17 | func _(x, y int) (z int) { 18 | { 19 | return 20 | } 21 | } 22 | 23 | func _(x, y int) (z int) { 24 | { 25 | } 26 | } /* ERROR "missing return" */ 27 | 28 | // if statements 29 | func _(x, y int) (z int) { 30 | if x < y { return } 31 | return 1 32 | } 33 | 34 | func _(x, y int) (z int) { 35 | if x < y { return } 36 | } /* ERROR "missing return" */ 37 | 38 | func _(x, y int) (z int) { 39 | if x < y { 40 | } else { return 1 41 | } 42 | } /* ERROR "missing return" */ 43 | 44 | func _(x, y int) (z int) { 45 | if x < y { return 46 | } else { return 47 | } 48 | } 49 | 50 | // for statements 51 | func _(x, y int) (z int) { 52 | for x < y { 53 | return 54 | } 55 | } /* ERROR "missing return" */ 56 | 57 | func _(x, y int) (z int) { 58 | for { 59 | return 60 | } 61 | } 62 | 63 | func _(x, y int) (z int) { 64 | for { 65 | return 66 | break 67 | } 68 | } /* ERROR "missing return" */ 69 | 70 | func _(x, y int) (z int) { 71 | for { 72 | for { break } 73 | return 74 | } 75 | } 76 | 77 | func _(x, y int) (z int) { 78 | L: for { 79 | for { break L } 80 | return 81 | } 82 | } /* ERROR "missing return" */ 83 | 84 | // switch statements 85 | func _(x, y int) (z int) { 86 | switch x { 87 | case 0: return 88 | default: return 89 | } 90 | } 91 | 92 | func _(x, y int) (z int) { 93 | switch x { 94 | case 0: return 95 | } 96 | } /* ERROR "missing return" */ 97 | 98 | func _(x, y int) (z int) { 99 | switch x { 100 | case 0: return 101 | case 1: break 102 | } 103 | } /* ERROR "missing return" */ 104 | 105 | func _(x, y int) (z int) { 106 | switch x { 107 | case 0: return 108 | default: 109 | switch y { 110 | case 0: break 111 | } 112 | panic(0) 113 | } 114 | } 115 | 116 | func _(x, y int) (z int) { 117 | L: switch x { 118 | case 0: return 119 | default: 120 | switch y { 121 | case 0: break L 122 | } 123 | panic(0) 124 | } 125 | } /* ERROR "missing return" */ 126 | 127 | // select statements 128 | func _(ch chan int) (z int) { 129 | select {} 130 | } // nice! 131 | 132 | func _(ch chan int) (z int) { 133 | select { 134 | default: break 135 | } 136 | } /* ERROR "missing return" */ 137 | 138 | func _(ch chan int) (z int) { 139 | select { 140 | case <-ch: return 141 | default: break 142 | } 143 | } /* ERROR "missing return" */ 144 | 145 | func _(ch chan int) (z int) { 146 | select { 147 | case <-ch: return 148 | default: 149 | for i := 0; i < 10; i++ { 150 | break 151 | } 152 | return 153 | } 154 | } 155 | 156 | func _(ch chan int) (z int) { 157 | L: select { 158 | case <-ch: return 159 | default: 160 | for i := 0; i < 10; i++ { 161 | break L 162 | } 163 | return 164 | } 165 | } /* ERROR "missing return" */ 166 | -------------------------------------------------------------------------------- /types/testdata/vardecl.src: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package vardecl 6 | 7 | // Prerequisites. 8 | func f() {} 9 | func g() (x, y int) { return } 10 | var m map[string]int 11 | 12 | // Var decls must have a type or an initializer. 13 | var _ int 14 | var _, _ int 15 | 16 | var _ /* ERROR "missing type or init expr" */ 17 | var _ /* ERROR "missing type or init expr" */, _ 18 | var _ /* ERROR "missing type or init expr" */, _, _ 19 | 20 | // The initializer must be an expression. 21 | var _ = int /* ERROR "not an expression" */ 22 | var _ = f /* ERROR "used as value" */ () 23 | 24 | // Identifier and expression arity must match. 25 | var _, _ = 1, 2 26 | var _ = 1, 2 /* ERROR "extra init expr 2" */ 27 | var _, _ = 1 /* ERROR "assignment count mismatch" */ 28 | var _, _, _ /* ERROR "missing init expr for _" */ = 1, 2 29 | 30 | var _ = g /* ERROR "2-valued expr" */ () 31 | var _, _ = g() 32 | var _, _, _ = g /* ERROR "assignment count mismatch" */ () 33 | 34 | var _ = m["foo"] 35 | var _, _ = m["foo"] 36 | var _, _, _ = m /* ERROR "assignment count mismatch" */ ["foo"] 37 | 38 | var _, _ int = 1, 2 39 | var _ int = 1, 2 /* ERROR "extra init expr 2" */ 40 | var _, _ int = 1 /* ERROR "assignment count mismatch" */ 41 | var _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2 42 | 43 | var ( 44 | _, _ = 1, 2 45 | _ = 1, 2 /* ERROR "extra init expr 2" */ 46 | _, _ = 1 /* ERROR "assignment count mismatch" */ 47 | _, _, _ /* ERROR "missing init expr for _" */ = 1, 2 48 | 49 | _ = g /* ERROR "2-valued expr" */ () 50 | _, _ = g() 51 | _, _, _ = g /* ERROR "assignment count mismatch" */ () 52 | 53 | _ = m["foo"] 54 | _, _ = m["foo"] 55 | _, _, _ = m /* ERROR "assignment count mismatch" */ ["foo"] 56 | 57 | _, _ int = 1, 2 58 | _ int = 1, 2 /* ERROR "extra init expr 2" */ 59 | _, _ int = 1 /* ERROR "assignment count mismatch" */ 60 | _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2 61 | ) 62 | 63 | // Variables declared in function bodies must be 'used'. 64 | type T struct{} 65 | func (r T) _(a, b, c int) (u, v, w int) { 66 | var x1 /* ERROR "declared but not used" */ int 67 | var x2 /* ERROR "declared but not used" */ int 68 | x1 = 1 69 | (x2) = 2 70 | 71 | y1 /* ERROR "declared but not used" */ := 1 72 | y2 /* ERROR "declared but not used" */ := 2 73 | y1 = 1 74 | (y1) = 2 75 | 76 | { 77 | var x1 /* ERROR "declared but not used" */ int 78 | var x2 /* ERROR "declared but not used" */ int 79 | x1 = 1 80 | (x2) = 2 81 | 82 | y1 /* ERROR "declared but not used" */ := 1 83 | y2 /* ERROR "declared but not used" */ := 2 84 | y1 = 1 85 | (y1) = 2 86 | } 87 | 88 | if x /* ERROR "declared but not used" */ := 0; a < b {} 89 | 90 | switch x /* ERROR "declared but not used" */, y := 0, 1; a { 91 | case 0: 92 | _ = y 93 | case 1: 94 | x /* ERROR "declared but not used" */ := 0 95 | } 96 | 97 | var t interface{} 98 | switch t /* ERROR "declared but not used" */ := t.(type) {} 99 | 100 | switch t /* ERROR "declared but not used" */ := t.(type) { 101 | case int: 102 | } 103 | 104 | switch t /* ERROR "declared but not used" */ := t.(type) { 105 | case int: 106 | case float32, complex64: 107 | t = nil 108 | } 109 | 110 | switch t := t.(type) { 111 | case int: 112 | case float32, complex64: 113 | _ = t 114 | } 115 | 116 | switch t := t.(type) { 117 | case int: 118 | case float32: 119 | case string: 120 | _ = func() string { 121 | return t 122 | } 123 | } 124 | 125 | switch t := t; t /* ERROR "declared but not used" */ := t.(type) {} 126 | 127 | var z1 /* ERROR "declared but not used" */ int 128 | var z2 int 129 | _ = func(a, b, c int) (u, v, w int) { 130 | z1 = a 131 | (z1) = b 132 | a = z2 133 | return 134 | } 135 | 136 | var s []int 137 | var i /* ERROR "declared but not used" */ , j int 138 | for i, j = range s { 139 | _ = j 140 | } 141 | 142 | for i, j /* ERROR "declared but not used" */ := range s { 143 | _ = func() int { 144 | return i 145 | } 146 | } 147 | return 148 | } 149 | 150 | // TODO(gri) consolidate other var decl checks in this file -------------------------------------------------------------------------------- /types/token_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file checks invariants of token.Token ordering that we rely on 6 | // since package go/token doesn't provide any guarantees at the moment. 7 | 8 | package types 9 | 10 | import ( 11 | "go/token" 12 | "testing" 13 | ) 14 | 15 | var assignOps = map[token.Token]token.Token{ 16 | token.ADD_ASSIGN: token.ADD, 17 | token.SUB_ASSIGN: token.SUB, 18 | token.MUL_ASSIGN: token.MUL, 19 | token.QUO_ASSIGN: token.QUO, 20 | token.REM_ASSIGN: token.REM, 21 | token.AND_ASSIGN: token.AND, 22 | token.OR_ASSIGN: token.OR, 23 | token.XOR_ASSIGN: token.XOR, 24 | token.SHL_ASSIGN: token.SHL, 25 | token.SHR_ASSIGN: token.SHR, 26 | token.AND_NOT_ASSIGN: token.AND_NOT, 27 | } 28 | 29 | func TestZeroTok(t *testing.T) { 30 | // zero value for token.Token must be token.ILLEGAL 31 | var zero token.Token 32 | if token.ILLEGAL != zero { 33 | t.Errorf("%s == %d; want 0", token.ILLEGAL, zero) 34 | } 35 | } 36 | 37 | func TestAssignOp(t *testing.T) { 38 | // there are fewer than 256 tokens 39 | for i := 0; i < 256; i++ { 40 | tok := token.Token(i) 41 | got := assignOp(tok) 42 | want := assignOps[tok] 43 | if got != want { 44 | t.Errorf("for assignOp(%s): got %s; want %s", tok, got, want) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /types/typemap/typemap_test.go: -------------------------------------------------------------------------------- 1 | package typemap_test 2 | 3 | // TODO(adonovan): 4 | // - test use of explicit hasher across two maps. 5 | // - test hashcodes are consistent with equals for a range of types 6 | // (e.g. all types generated by type-checking some body of real code). 7 | 8 | import ( 9 | "go/ast" 10 | "testing" 11 | 12 | "code.google.com/p/go.tools/go/types" 13 | "code.google.com/p/go.tools/go/types/typemap" 14 | ) 15 | 16 | var ( 17 | tStr = types.Typ[types.String] // string 18 | tPStr1 = types.NewPointer(tStr) // *string 19 | tPStr2 = types.NewPointer(tStr) // *string, again 20 | tInt = types.Typ[types.Int] // int 21 | tChanInt1 = types.NewChan(ast.RECV, tInt) // <-chan int 22 | tChanInt2 = types.NewChan(ast.RECV, tInt) // <-chan int, again 23 | ) 24 | 25 | func checkEqualButNotIdentical(t *testing.T, x, y types.Type, comment string) { 26 | if !types.IsIdentical(x, y) { 27 | t.Errorf("%s: not equal: %s, %s", comment, x, y) 28 | } 29 | if x == y { 30 | t.Errorf("%s: identical: %p, %p", comment, x, y) 31 | } 32 | } 33 | 34 | func TestAxioms(t *testing.T) { 35 | checkEqualButNotIdentical(t, tPStr1, tPStr2, "tPstr{1,2}") 36 | checkEqualButNotIdentical(t, tChanInt1, tChanInt2, "tChanInt{1,2}") 37 | } 38 | 39 | func TestTypeMap(t *testing.T) { 40 | var tmap *typemap.M 41 | 42 | // All methods but Set are safe on on (*T)(nil). 43 | tmap.Len() 44 | tmap.At(tPStr1) 45 | tmap.Delete(tPStr1) 46 | tmap.KeysString() 47 | tmap.String() 48 | 49 | tmap = new(typemap.M) 50 | 51 | // Length of empty map. 52 | if l := tmap.Len(); l != 0 { 53 | t.Errorf("Len() on empty typemap: got %d, want 0", l) 54 | } 55 | // At of missing key. 56 | if v := tmap.At(tPStr1); v != nil { 57 | t.Errorf("At() on empty typemap: got %v, want nil", v) 58 | } 59 | // Deletion of missing key. 60 | if tmap.Delete(tPStr1) { 61 | t.Errorf("Delete() on empty typemap: got true, want false") 62 | } 63 | // Set of new key. 64 | if prev := tmap.Set(tPStr1, "*string"); prev != nil { 65 | t.Errorf("Set() on empty map returned non-nil previous value %s", prev) 66 | } 67 | 68 | // Now: {*string: "*string"} 69 | 70 | // Length of non-empty map. 71 | if l := tmap.Len(); l != 1 { 72 | t.Errorf("Len(): got %d, want 1", l) 73 | } 74 | // At via insertion key. 75 | if v := tmap.At(tPStr1); v != "*string" { 76 | t.Errorf("At(): got %q, want \"*string\"", v) 77 | } 78 | // At via equal key. 79 | if v := tmap.At(tPStr2); v != "*string" { 80 | t.Errorf("At(): got %q, want \"*string\"", v) 81 | } 82 | // Iteration over sole entry. 83 | tmap.Iterate(func(key types.Type, value interface{}) { 84 | if key != tPStr1 { 85 | t.Errorf("Iterate: key: got %s, want %s", key, tPStr1) 86 | } 87 | if want := "*string"; value != want { 88 | t.Errorf("Iterate: value: got %s, want %s", value, want) 89 | } 90 | }) 91 | 92 | // Setion with key equal to present one. 93 | if prev := tmap.Set(tPStr2, "*string again"); prev != "*string" { 94 | t.Errorf("Set() previous value: got %s, want \"*string\"", prev) 95 | } 96 | 97 | // Setion of another association. 98 | if prev := tmap.Set(tChanInt1, "<-chan int"); prev != nil { 99 | t.Errorf("Set() previous value: got %s, want nil", prev) 100 | } 101 | 102 | // Now: {*string: "*string again", <-chan int: "<-chan int"} 103 | 104 | want1 := "{*string: \"*string again\", <-chan int: \"<-chan int\"}" 105 | want2 := "{<-chan int: \"<-chan int\", *string: \"*string again\"}" 106 | if s := tmap.String(); s != want1 && s != want2 { 107 | t.Errorf("String(): got %s, want %s", s, want1) 108 | } 109 | 110 | want1 = "{*string, <-chan int}" 111 | want2 = "{<-chan int, *string}" 112 | if s := tmap.KeysString(); s != want1 && s != want2 { 113 | t.Errorf("KeysString(): got %s, want %s", s, want1) 114 | } 115 | 116 | // Keys(). 117 | I := types.IsIdentical 118 | switch k := tmap.Keys(); { 119 | case I(k[0], tChanInt1) && I(k[1], tPStr1): // ok 120 | case I(k[1], tChanInt1) && I(k[0], tPStr1): // ok 121 | default: 122 | t.Errorf("Keys(): got %v, want %s", k, want2) 123 | } 124 | 125 | if l := tmap.Len(); l != 2 { 126 | t.Errorf("Len(): got %d, want 1", l) 127 | } 128 | // At via original key. 129 | if v := tmap.At(tPStr1); v != "*string again" { 130 | t.Errorf("At(): got %q, want \"*string again\"", v) 131 | } 132 | hamming := 1 133 | tmap.Iterate(func(key types.Type, value interface{}) { 134 | switch { 135 | case I(key, tChanInt1): 136 | hamming *= 2 // ok 137 | case I(key, tPStr1): 138 | hamming *= 3 // ok 139 | } 140 | }) 141 | if hamming != 6 { 142 | t.Errorf("Iterate: hamming: got %d, want %d", hamming, 6) 143 | } 144 | 145 | if v := tmap.At(tChanInt2); v != "<-chan int" { 146 | t.Errorf("At(): got %q, want \"<-chan int\"", v) 147 | } 148 | // Deletion with key equal to present one. 149 | if !tmap.Delete(tChanInt2) { 150 | t.Errorf("Delete() of existing key: got false, want true") 151 | } 152 | 153 | // Now: {*string: "*string again"} 154 | 155 | if l := tmap.Len(); l != 1 { 156 | t.Errorf("Len(): got %d, want 1", l) 157 | } 158 | // Deletion again. 159 | if !tmap.Delete(tPStr2) { 160 | t.Errorf("Delete() of existing key: got false, want true") 161 | } 162 | 163 | // Now: {} 164 | 165 | if l := tmap.Len(); l != 0 { 166 | t.Errorf("Len(): got %d, want %d", l, 0) 167 | } 168 | if s := tmap.String(); s != "{}" { 169 | t.Errorf("Len(): got %q, want %q", s, "") 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /types/types_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file contains tests verifying the types associated with an AST after 6 | // type checking. 7 | 8 | package types 9 | 10 | import ( 11 | "go/ast" 12 | "go/parser" 13 | "testing" 14 | ) 15 | 16 | const filename = "" 17 | 18 | func makePkg(t *testing.T, src string) (*Package, error) { 19 | file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors) 20 | if err != nil { 21 | return nil, err 22 | } 23 | // use the package name as package path 24 | return Check(file.Name.Name, fset, []*ast.File{file}) 25 | } 26 | 27 | type testEntry struct { 28 | src, str string 29 | } 30 | 31 | // dup returns a testEntry where both src and str are the same. 32 | func dup(s string) testEntry { 33 | return testEntry{s, s} 34 | } 35 | 36 | var testTypes = []testEntry{ 37 | // basic types 38 | dup("int"), 39 | dup("float32"), 40 | dup("string"), 41 | 42 | // arrays 43 | dup("[10]int"), 44 | 45 | // slices 46 | dup("[]int"), 47 | dup("[][]int"), 48 | 49 | // structs 50 | dup("struct{}"), 51 | dup("struct{x int}"), 52 | {`struct { 53 | x, y int 54 | z float32 "foo" 55 | }`, `struct{x int; y int; z float32 "foo"}`}, 56 | {`struct { 57 | string 58 | elems []complex128 59 | }`, `struct{string; elems []complex128}`}, 60 | 61 | // pointers 62 | dup("*int"), 63 | dup("***struct{}"), 64 | dup("*struct{a int; b float32}"), 65 | 66 | // functions 67 | dup("func()"), 68 | dup("func(x int)"), 69 | {"func(x, y int)", "func(x int, y int)"}, 70 | {"func(x, y int, z string)", "func(x int, y int, z string)"}, 71 | dup("func(int)"), 72 | {"func(int, string, byte)", "func(int, string, byte)"}, 73 | 74 | dup("func() int"), 75 | {"func() (string)", "func() string"}, 76 | dup("func() (u int)"), 77 | {"func() (u, v int, w string)", "func() (u int, v int, w string)"}, 78 | 79 | dup("func(int) string"), 80 | dup("func(x int) string"), 81 | dup("func(x int) (u string)"), 82 | {"func(x, y int) (u string)", "func(x int, y int) (u string)"}, 83 | 84 | dup("func(...int) string"), 85 | dup("func(x ...int) string"), 86 | dup("func(x ...int) (u string)"), 87 | {"func(x, y ...int) (u string)", "func(x int, y ...int) (u string)"}, 88 | 89 | // interfaces 90 | dup("interface{}"), 91 | dup("interface{m()}"), 92 | dup(`interface{m(int) float32; String() string}`), 93 | // TODO(gri) add test for interface w/ anonymous field 94 | 95 | // maps 96 | dup("map[string]int"), 97 | {"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"}, 98 | 99 | // channels 100 | dup("chan int"), 101 | dup("chan<- func()"), 102 | dup("<-chan []func() int"), 103 | } 104 | 105 | func TestTypes(t *testing.T) { 106 | for _, test := range testTypes { 107 | src := "package p; type T " + test.src 108 | pkg, err := makePkg(t, src) 109 | if err != nil { 110 | t.Errorf("%s: %s", src, err) 111 | continue 112 | } 113 | typ := pkg.scope.Lookup("T").Type().Underlying() 114 | str := typeString(typ) 115 | if str != test.str { 116 | t.Errorf("%s: got %s, want %s", test.src, str, test.str) 117 | } 118 | } 119 | } 120 | 121 | var testExprs = []testEntry{ 122 | // basic type literals 123 | dup("x"), 124 | dup("true"), 125 | dup("42"), 126 | dup("3.1415"), 127 | dup("2.71828i"), 128 | dup(`'a'`), 129 | dup(`"foo"`), 130 | dup("`bar`"), 131 | 132 | // arbitrary expressions 133 | dup("&x"), 134 | dup("*&x"), 135 | dup("(x)"), 136 | dup("x + y"), 137 | dup("x + y * 10"), 138 | dup("t.foo"), 139 | dup("s[0]"), 140 | dup("s[x:y]"), 141 | dup("s[:y]"), 142 | dup("s[x:]"), 143 | dup("s[:]"), 144 | dup("f(1, 2.3)"), 145 | dup("-f(10, 20)"), 146 | dup("f(x + y, +3.1415)"), 147 | {"func(a, b int) {}", "(func literal)"}, 148 | {"func(a, b int) []int {}(1, 2)[x]", "(func literal)(1, 2)[x]"}, 149 | {"[]int{1, 2, 3}", "(composite literal)"}, 150 | {"[]int{1, 2, 3}[x:]", "(composite literal)[x:]"}, 151 | {"i.([]string)", "i.()"}, 152 | } 153 | 154 | func TestExprs(t *testing.T) { 155 | for _, test := range testExprs { 156 | src := "package p; var _ = " + test.src + "; var (x, y int; s []string; f func(int, float32) int; i interface{}; t interface { foo() })" 157 | file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors) 158 | if err != nil { 159 | t.Errorf("%s: %s", src, err) 160 | continue 161 | } 162 | // TODO(gri) writing the code below w/o the decl variable will 163 | // cause a 386 compiler error (out of fixed registers) 164 | decl := file.Decls[0].(*ast.GenDecl) 165 | expr := decl.Specs[0].(*ast.ValueSpec).Values[0] 166 | str := exprString(expr) 167 | if str != test.str { 168 | t.Errorf("%s: got %s, want %s", test.src, str, test.str) 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /types/universe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements the universe and unsafe package scopes. 6 | 7 | package types 8 | 9 | import ( 10 | "go/token" 11 | "strings" 12 | 13 | "code.google.com/p/go.tools/go/exact" 14 | ) 15 | 16 | var ( 17 | Universe *Scope 18 | Unsafe *Package 19 | universeIota *Const 20 | ) 21 | 22 | var Typ = [...]*Basic{ 23 | Invalid: {Invalid, 0, 0, "invalid type"}, 24 | 25 | Bool: {Bool, IsBoolean, 1, "bool"}, 26 | Int: {Int, IsInteger, 0, "int"}, 27 | Int8: {Int8, IsInteger, 1, "int8"}, 28 | Int16: {Int16, IsInteger, 2, "int16"}, 29 | Int32: {Int32, IsInteger, 4, "int32"}, 30 | Int64: {Int64, IsInteger, 8, "int64"}, 31 | Uint: {Uint, IsInteger | IsUnsigned, 0, "uint"}, 32 | Uint8: {Uint8, IsInteger | IsUnsigned, 1, "uint8"}, 33 | Uint16: {Uint16, IsInteger | IsUnsigned, 2, "uint16"}, 34 | Uint32: {Uint32, IsInteger | IsUnsigned, 4, "uint32"}, 35 | Uint64: {Uint64, IsInteger | IsUnsigned, 8, "uint64"}, 36 | Uintptr: {Uintptr, IsInteger | IsUnsigned, 0, "uintptr"}, 37 | Float32: {Float32, IsFloat, 4, "float32"}, 38 | Float64: {Float64, IsFloat, 8, "float64"}, 39 | Complex64: {Complex64, IsComplex, 8, "complex64"}, 40 | Complex128: {Complex128, IsComplex, 16, "complex128"}, 41 | String: {String, IsString, 0, "string"}, 42 | UnsafePointer: {UnsafePointer, 0, 0, "Pointer"}, 43 | 44 | UntypedBool: {UntypedBool, IsBoolean | IsUntyped, 0, "untyped boolean"}, 45 | UntypedInt: {UntypedInt, IsInteger | IsUntyped, 0, "untyped integer"}, 46 | UntypedRune: {UntypedRune, IsInteger | IsUntyped, 0, "untyped rune"}, 47 | UntypedFloat: {UntypedFloat, IsFloat | IsUntyped, 0, "untyped float"}, 48 | UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, 0, "untyped complex"}, 49 | UntypedString: {UntypedString, IsString | IsUntyped, 0, "untyped string"}, 50 | UntypedNil: {UntypedNil, IsUntyped, 0, "untyped nil"}, 51 | } 52 | 53 | var aliases = [...]*Basic{ 54 | {Byte, IsInteger | IsUnsigned, 1, "byte"}, 55 | {Rune, IsInteger, 4, "rune"}, 56 | } 57 | 58 | func defPredeclaredTypes() { 59 | for _, t := range Typ { 60 | def(NewTypeName(token.NoPos, nil, t.name, t)) 61 | } 62 | for _, t := range aliases { 63 | def(NewTypeName(token.NoPos, nil, t.name, t)) 64 | } 65 | 66 | // Error has a nil package in its qualified name since it is in no package 67 | res := NewVar(token.NoPos, nil, "", Typ[String]) 68 | sig := &Signature{results: NewTuple(res)} 69 | err := NewFunc(token.NoPos, nil, "Error", sig) 70 | typ := &Named{underlying: &Interface{methods: []*Func{err}}, complete: true} 71 | sig.recv = NewVar(token.NoPos, nil, "", typ) 72 | def(NewTypeName(token.NoPos, nil, "error", typ)) 73 | } 74 | 75 | var predeclaredConsts = [...]struct { 76 | name string 77 | kind BasicKind 78 | val exact.Value 79 | }{ 80 | {"true", UntypedBool, exact.MakeBool(true)}, 81 | {"false", UntypedBool, exact.MakeBool(false)}, 82 | {"iota", UntypedInt, exact.MakeInt64(0)}, 83 | } 84 | 85 | func defPredeclaredConsts() { 86 | for _, c := range predeclaredConsts { 87 | def(NewConst(token.NoPos, nil, c.name, Typ[c.kind], c.val)) 88 | } 89 | } 90 | 91 | func defPredeclaredNil() { 92 | def(&Nil{object{name: "nil", typ: Typ[UntypedNil]}}) 93 | } 94 | 95 | // A builtinId is the id of a builtin function. 96 | type builtinId int 97 | 98 | const ( 99 | // universe scope 100 | _Append builtinId = iota 101 | _Cap 102 | _Close 103 | _Complex 104 | _Copy 105 | _Delete 106 | _Imag 107 | _Len 108 | _Make 109 | _New 110 | _Panic 111 | _Print 112 | _Println 113 | _Real 114 | _Recover 115 | 116 | // package unsafe 117 | _Alignof 118 | _Offsetof 119 | _Sizeof 120 | 121 | // testing support 122 | _Assert 123 | _Trace 124 | ) 125 | 126 | var predeclaredFuncs = [...]struct { 127 | name string 128 | nargs int 129 | variadic bool 130 | kind exprKind 131 | }{ 132 | _Append: {"append", 1, true, expression}, 133 | _Cap: {"cap", 1, false, expression}, 134 | _Close: {"close", 1, false, statement}, 135 | _Complex: {"complex", 2, false, expression}, 136 | _Copy: {"copy", 2, false, statement}, 137 | _Delete: {"delete", 2, false, statement}, 138 | _Imag: {"imag", 1, false, expression}, 139 | _Len: {"len", 1, false, expression}, 140 | _Make: {"make", 1, true, expression}, 141 | _New: {"new", 1, false, expression}, 142 | _Panic: {"panic", 1, false, statement}, 143 | _Print: {"print", 0, true, statement}, 144 | _Println: {"println", 0, true, statement}, 145 | _Real: {"real", 1, false, expression}, 146 | _Recover: {"recover", 0, false, statement}, 147 | 148 | _Alignof: {"Alignof", 1, false, expression}, 149 | _Offsetof: {"Offsetof", 1, false, expression}, 150 | _Sizeof: {"Sizeof", 1, false, expression}, 151 | 152 | _Assert: {"assert", 1, false, statement}, 153 | _Trace: {"trace", 0, true, statement}, 154 | } 155 | 156 | func defPredeclaredFuncs() { 157 | for i := range predeclaredFuncs { 158 | id := builtinId(i) 159 | if id == _Assert || id == _Trace { 160 | continue // only define these in testing environment 161 | } 162 | def(newBuiltin(id)) 163 | } 164 | } 165 | 166 | func defPredeclaredTestFuncs() { 167 | if Universe.Lookup("assert") != nil { 168 | return // already defined 169 | } 170 | def(newBuiltin(_Assert)) 171 | def(newBuiltin(_Trace)) 172 | } 173 | 174 | func init() { 175 | Universe = NewScope(nil) 176 | Unsafe = NewPackage("unsafe", "unsafe", NewScope(Universe)) 177 | Unsafe.complete = true 178 | 179 | defPredeclaredTypes() 180 | defPredeclaredConsts() 181 | defPredeclaredNil() 182 | defPredeclaredFuncs() 183 | 184 | universeIota = Universe.Lookup("iota").(*Const) 185 | } 186 | 187 | // Objects with names containing blanks are internal and not entered into 188 | // a scope. Objects with exported names are inserted in the unsafe package 189 | // scope; other objects are inserted in the universe scope. 190 | // 191 | func def(obj Object) { 192 | name := obj.Name() 193 | if strings.Index(name, " ") >= 0 { 194 | return // nothing to do 195 | } 196 | // fix Obj link for named types 197 | if typ, ok := obj.Type().(*Named); ok { 198 | typ.obj = obj.(*TypeName) 199 | } 200 | // exported identifiers go into package unsafe 201 | scope := Universe 202 | if obj.IsExported() { 203 | scope = Unsafe.scope 204 | // set Pkg field 205 | switch obj := obj.(type) { 206 | case *TypeName: 207 | obj.pkg = Unsafe 208 | case *Builtin: 209 | obj.pkg = Unsafe 210 | default: 211 | unreachable() 212 | } 213 | } 214 | if scope.Insert(obj) != nil { 215 | panic("internal error: double declaration") 216 | } 217 | } 218 | --------------------------------------------------------------------------------