Repository: alecthomas/gometalinter
Pull request #297 (2017-06-19 12:53:58)

Update README.md
`go vet --shadow` is not valid, it should be `go tool vet --shadow`.


Patch:
diff --git a/README.md b/README.md
index ae81cfc..fcbd95e 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ It is intended for use with editor/IDE integration.
 ## Supported linters
 
 - [go vet](https://golang.org/cmd/vet/) - Reports potential errors that otherwise compile.
-- [go vet --shadow](https://golang.org/cmd/vet/#hdr-Shadowed_variables) - Reports variables that may have been unintentionally shadowed.
+- [go tool vet --shadow](https://golang.org/cmd/vet/#hdr-Shadowed_variables) - Reports variables that may have been unintentionally shadowed.
 - [gotype](https://golang.org/x/tools/cmd/gotype) - Syntactic and semantic analysis similar to the Go compiler.
 - [deadcode](https://github.com/tsenart/deadcode) - Finds unused code.
 - [gocyclo](https://github.com/alecthomas/gocyclo) - Computes the cyclomatic complexity of functions.
@@ -63,13 +63,12 @@ It is intended for use with editor/IDE integration.
 - [structcheck](https://github.com/opennota/check) - Find unused struct fields.
 - [aligncheck](https://github.com/opennota/check) - Warn about un-optimally aligned structures.
 - [errcheck](https://github.com/kisielk/errcheck) - Check that error return values are used.
+- [megacheck](https://github.com/dominikh/go-tools/tree/master/cmd/megacheck) - Run staticcheck, gosimple and unused, sharing work.
 - [dupl](https://github.com/mibk/dupl) - Reports potentially duplicated code.
 - [ineffassign](https://github.com/gordonklaus/ineffassign/blob/master/list) - Detect when assignments to *existing* variables are not used.
 - [interfacer](https://github.com/mvdan/interfacer) - Suggest narrower interfaces that can be used.
 - [unconvert](https://github.com/mdempsky/unconvert) - Detect redundant type conversions.
 - [goconst](https://github.com/jgautheron/goconst) - Finds repeated strings that could be replaced by a constant.
-- [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) - Report simplifications in code.
-- [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) - Statically detect bugs, both obvious and subtle ones.
 - [gas](https://github.com/GoASTScanner/gas) - Inspects source code for security problems by scanning the Go AST.
 
 Disabled by default (enable with `--enable=<linter>`):
@@ -78,11 +77,13 @@ Disabled by default (enable with `--enable=<linter>`):
 - [test](http://golang.org/pkg/testing/) - Show location of test failures from the stdlib testing module.
 - [gofmt -s](https://golang.org/cmd/gofmt/) - Checks if the code is properly formatted and could not be further simplified.
 - [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) - Checks missing or unreferenced package imports.
+- [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) - Report simplifications in code.
 - [lll](https://github.com/walle/lll) - Report long lines (see `--line-length=N`).
 - [misspell](https://github.com/client9/misspell) - Finds commonly misspelled English words.
 - [unparam](https://github.com/mvdan/unparam) - Find unused function parameters.
 - [unused](https://github.com/dominikh/go-tools/tree/master/cmd/unused) - Find unused variables.
 - [safesql](https://github.com/stripe/safesql) - Finds potential SQL injection vulnerabilities.
+- [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) - Statically detect bugs, both obvious and subtle ones.
 
 Additional linters can be added through the command line with `--linter=NAME:COMMAND:PATTERN` (see [below](#details)).
 
@@ -95,13 +96,13 @@ in `config.go`.
 The configuration file mostly corresponds to command-line flags, with the following exceptions:
 
 - Linters defined in the configuration file will overlay existing definitions, not replace them.
-- "Enable" defines the exact set of linters that will be enabled.
+- "Enable" defines the exact set of linters that will be enabled (default
+  linters are disabled).
 
 Here is an example configuration file:
 
 ```json
 {
-  "DisableAll": true,
   "Enable": ["deadcode", "unconvert"]
 }
 ```
diff --git a/_linters/src/honnef.co/go/tools/cmd/gosimple/gosimple.go b/_linters/src/honnef.co/go/tools/cmd/gosimple/gosimple.go
index 83075c3..a939a27 100644
--- a/_linters/src/honnef.co/go/tools/cmd/gosimple/gosimple.go
+++ b/_linters/src/honnef.co/go/tools/cmd/gosimple/gosimple.go
@@ -14,5 +14,5 @@ func main() {
 	c := simple.NewChecker()
 	c.CheckGenerated = *gen
 
-	lintutil.ProcessFlagSet("gosimple", c, fs)
+	lintutil.ProcessFlagSet(c, fs)
 }
diff --git a/_linters/src/honnef.co/go/tools/cmd/megacheck/LICENSE b/_linters/src/honnef.co/go/tools/cmd/megacheck/LICENSE
new file mode 100644
index 0000000..dfd0314
--- /dev/null
+++ b/_linters/src/honnef.co/go/tools/cmd/megacheck/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2016 Dominik Honnef
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/_linters/src/honnef.co/go/tools/cmd/megacheck/megacheck.go b/_linters/src/honnef.co/go/tools/cmd/megacheck/megacheck.go
new file mode 100644
index 0000000..8477df6
--- /dev/null
+++ b/_linters/src/honnef.co/go/tools/cmd/megacheck/megacheck.go
@@ -0,0 +1,123 @@
+// megacheck runs staticcheck, gosimple and unused.
+package main // import "honnef.co/go/tools/cmd/megacheck"
+
+import (
+	"os"
+
+	"honnef.co/go/tools/lint"
+	"honnef.co/go/tools/lint/lintutil"
+	"honnef.co/go/tools/simple"
+	"honnef.co/go/tools/staticcheck"
+	"honnef.co/go/tools/unused"
+)
+
+type Checker struct {
+	Checkers []lint.Checker
+}
+
+func (c *Checker) Init(prog *lint.Program) {
+	for _, cc := range c.Checkers {
+		cc.Init(prog)
+	}
+}
+
+func (c *Checker) Funcs() map[string]lint.Func {
+	fns := map[string]lint.Func{}
+	for _, cc := range c.Checkers {
+		for k, v := range cc.Funcs() {
+			fns[k] = v
+		}
+	}
+	return fns
+}
+
+func main() {
+	var flags struct {
+		staticcheck struct {
+			enabled   bool
+			generated bool
+		}
+		gosimple struct {
+			enabled   bool
+			generated bool
+		}
+		unused struct {
+			enabled      bool
+			constants    bool
+			fields       bool
+			functions    bool
+			types        bool
+			variables    bool
+			debug        string
+			wholeProgram bool
+			reflection   bool
+		}
+	}
+	fs := lintutil.FlagSet("megacheck")
+	fs.BoolVar(&flags.gosimple.enabled,
+		"simple.enabled", true, "Run gosimple")
+	fs.BoolVar(&flags.gosimple.generated,
+		"simple.generated", false, "Check generated code")
+
+	fs.BoolVar(&flags.staticcheck.enabled,
+		"staticcheck.enabled", true, "Run staticcheck")
+	fs.BoolVar(&flags.staticcheck.generated,
+		"staticcheck.generated", false, "Check generated code (only applies to a subset of checks)")
+
+	fs.BoolVar(&flags.unused.enabled,
+		"unused.enabled", true, "Run unused")
+	fs.BoolVar(&flags.unused.constants,
+		"unused.consts", true, "Report unused constants")
+	fs.BoolVar(&flags.unused.fields,
+		"unused.fields", true, "Report unused fields")
+	fs.BoolVar(&flags.unused.functions,
+		"unused.funcs", true, "Report unused functions and methods")
+	fs.BoolVar(&flags.unused.types,
+		"unused.types", true, "Report unused types")
+	fs.BoolVar(&flags.unused.variables,
+		"unused.vars", true, "Report unused variables")
+	fs.BoolVar(&flags.unused.wholeProgram,
+		"unused.exported", false, "Treat arguments as a program and report unused exported identifiers")
+	fs.BoolVar(&flags.unused.reflection, "unused.reflect", true, "Consider identifiers as used when it's likely they'll be accessed via reflection")
+
+	fs.Parse(os.Args[1:])
+
+	c := &Checker{}
+
+	if flags.staticcheck.enabled {
+		sac := staticcheck.NewChecker()
+		sac.CheckGenerated = flags.staticcheck.generated
+		c.Checkers = append(c.Checkers, sac)
+	}
+
+	if flags.gosimple.enabled {
+		sc := simple.NewChecker()
+		sc.CheckGenerated = flags.gosimple.generated
+		c.Checkers = append(c.Checkers, sc)
+	}
+
+	if flags.unused.enabled {
+		var mode unused.CheckMode
+		if flags.unused.constants {
+			mode |= unused.CheckConstants
+		}
+		if flags.unused.fields {
+			mode |= unused.CheckFields
+		}
+		if flags.unused.functions {
+			mode |= unused.CheckFunctions
+		}
+		if flags.unused.types {
+			mode |= unused.CheckTypes
+		}
+		if flags.unused.variables {
+			mode |= unused.CheckVariables
+		}
+		uc := unused.NewChecker(mode)
+		uc.WholeProgram = flags.unused.wholeProgram
+		uc.ConsiderReflection = flags.unused.reflection
+		c.Checkers = append(c.Checkers, unused.NewLintChecker(uc))
+	}
+
+	lintutil.ProcessFlagSet(c, fs)
+}
diff --git a/_linters/src/honnef.co/go/tools/cmd/staticcheck/staticcheck.go b/_linters/src/honnef.co/go/tools/cmd/staticcheck/staticcheck.go
index 86ad173..46f496c 100644
--- a/_linters/src/honnef.co/go/tools/cmd/staticcheck/staticcheck.go
+++ b/_linters/src/honnef.co/go/tools/cmd/staticcheck/staticcheck.go
@@ -15,5 +15,5 @@ func main() {
 	fs.Parse(os.Args[1:])
 	c := staticcheck.NewChecker()
 	c.CheckGenerated = *gen
-	lintutil.ProcessFlagSet("staticcheck", c, fs)
+	lintutil.ProcessFlagSet(c, fs)
 }
diff --git a/_linters/src/honnef.co/go/tools/cmd/unused/main.go b/_linters/src/honnef.co/go/tools/cmd/unused/main.go
index 3538e6f..9d0abfb 100644
--- a/_linters/src/honnef.co/go/tools/cmd/unused/main.go
+++ b/_linters/src/honnef.co/go/tools/cmd/unused/main.go
@@ -70,5 +70,5 @@ func main() {
 
 	checker := newChecker(mode)
 	l := unused.NewLintChecker(checker)
-	lintutil.ProcessFlagSet("unused", l, fs)
+	lintutil.ProcessFlagSet(l, fs)
 }
diff --git a/_linters/src/honnef.co/go/tools/internal/sharedcheck/LICENSE b/_linters/src/honnef.co/go/tools/internal/sharedcheck/LICENSE
new file mode 100644
index 0000000..dfd0314
--- /dev/null
+++ b/_linters/src/honnef.co/go/tools/internal/sharedcheck/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2016 Dominik Honnef
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/_linters/src/honnef.co/go/tools/internal/sharedcheck/lint.go b/_linters/src/honnef.co/go/tools/internal/sharedcheck/lint.go
new file mode 100644
index 0000000..5f62fc2
--- /dev/null
+++ b/_linters/src/honnef.co/go/tools/internal/sharedcheck/lint.go
@@ -0,0 +1,70 @@
+package sharedcheck
+
+import (
+	"go/ast"
+	"go/types"
+
+	"honnef.co/go/tools/lint"
+	"honnef.co/go/tools/ssa"
+)
+
+func CheckRangeStringRunes(nodeFns map[ast.Node]*ssa.Function, j *lint.Job) {
+	fn := func(node ast.Node) bool {
+		rng, ok := node.(*ast.RangeStmt)
+		if !ok || !lint.IsBlank(rng.Key) {
+			return true
+		}
+		ssafn := nodeFns[rng]
+		if ssafn == nil {
+			return true
+		}
+		v, _ := ssafn.ValueForExpr(rng.X)
+
+		// Check that we're converting from string to []rune
+		val, _ := v.(*ssa.Convert)
+		if val == nil {
+			return true
+		}
+		Tsrc, ok := val.X.Type().(*types.Basic)
+		if !ok || Tsrc.Kind() != types.String {
+			return true
+		}
+		Tdst, ok := val.Type().(*types.Slice)
+		if !ok {
+			return true
+		}
+		TdstElem, ok := Tdst.Elem().(*types.Basic)
+		if !ok || TdstElem.Kind() != types.Int32 {
+			return true
+		}
+
+		// Check that the result of the conversion is only used to
+		// range over
+		refs := val.Referrers()
+		if refs == nil {
+			return true
+		}
+
+		// Expect two refs: one for obtaining the length of the slice,
+		// one for accessing the elements
+		if len(lint.FilterDebug(*refs)) != 2 {
+			// TODO(dh): right now, we check that only one place
+			// refers to our slice. This will miss cases such as
+			// ranging over the slice twice. Ideally, we'd ensure that
+			// the slice is only used for ranging over (without
+			// accessing the key), but that is harder to do because in
+			// SSA form, ranging over a slice looks like an ordinary
+			// loop with index increments and slice accesses. We'd
+			// have to look at the associated AST node to check that
+			// it's a range statement.
+			return true
+		}
+
+		j.Errorf(rng, "should range over string, not []rune(string)")
+
+		return true
+	}
+	for _, f := range j.Program.Files {
+		ast.Inspect(f, fn)
+	}
+}
diff --git a/_linters/src/honnef.co/go/tools/lint/lint.go b/_linters/src/honnef.co/go/tools/lint/lint.go
index b952e1e..db1f6cd 100644
--- a/_linters/src/honnef.co/go/tools/lint/lint.go
+++ b/_linters/src/honnef.co/go/tools/lint/lint.go
@@ -40,8 +40,9 @@ type Ignore struct {
 }
 
 type Program struct {
-	SSA              *ssa.Program
-	Prog             *loader.Program
+	SSA  *ssa.Program
+	Prog *loader.Program
+	// TODO(dh): Rename to InitialPackages?
 	Packages         []*Pkg
 	InitialFunctions []*ssa.Function
 	AllFunctions     []*ssa.Function
@@ -50,7 +51,7 @@ type Program struct {
 	GoVersion        int
 
 	tokenFileMap map[*token.File]*ast.File
-	astFileMap   map[*ast.File]*ssa.Package
+	astFileMap   map[*ast.File]*Pkg
 }
 
 type Func func(*Job)
@@ -137,6 +138,7 @@ func (ps byPosition) Swap(i int, j int) {
 func (l *Linter) Lint(lprog *loader.Program) []Problem {
 	ssaprog := ssautil.CreateProgram(lprog, ssa.GlobalDebug)
 	ssaprog.Build()
+	pkgMap := map[*ssa.Package]*Pkg{}
 	var pkgs []*Pkg
 	for _, pkginfo := range lprog.InitialPackages() {
 		ssapkg := ssaprog.Package(pkginfo.Pkg)
@@ -144,64 +146,81 @@ func (l *Linter) Lint(lprog *loader.Program) []Problem {
 			Package: ssapkg,
 			Info:    pkginfo,
 		}
+		pkgMap[ssapkg] = pkg
 		pkgs = append(pkgs, pkg)
 	}
 	prog := &Program{
-		SSA:      ssaprog,
-		Prog:     lprog,
-		Packages: pkgs,
-		Info: &types.Info{
-			Types:      map[ast.Expr]types.TypeAndValue{},
-			Defs:       map[*ast.Ident]types.Object{},
-			Uses:       map[*ast.Ident]types.Object{},
-			Implicits:  map[ast.Node]types.Object{},
-			Selections: map[*ast.SelectorExpr]*types.Selection{},
-			Scopes:     map[ast.Node]*types.Scope{},
-		},
+		SSA:          ssaprog,
+		Prog:         lprog,
+		Packages:     pkgs,
+		Info:         &types.Info{},
 		GoVersion:    l.GoVersion,
 		tokenFileMap: map[*token.File]*ast.File{},
-		astFileMap:   map[*ast.File]*ssa.Package{},
+		astFileMap:   map[*ast.File]*Pkg{},
+	}
+	initial := map[*types.Package]struct{}{}
+	for _, pkg := range pkgs {
+		initial[pkg.Info.Pkg] = struct{}{}
 	}
 	for fn := range ssautil.AllFunctions(ssaprog) {
+		if fn.Pkg == nil {
+			continue
+		}
 		prog.AllFunctions = append(prog.AllFunctions, fn)
-		// TODO(dh): optimize this function
-		for _, pkg := range lprog.InitialPackages() {
-			if fn.Pkg == nil {
-				continue
-			}
-			if fn.Pkg.Pkg == pkg.Pkg {
-				prog.InitialFunctions = append(prog.InitialFunctions, fn)
-				break
-			}
+		if _, ok := initial[fn.Pkg.Pkg]; ok {
+			prog.InitialFunctions = append(prog.InitialFunctions, fn)
 		}
 	}
-	for _, pkginfo := range lprog.InitialPackages() {
-		prog.Files = append(prog.Files, pkginfo.Files...)
+	for _, pkg := range pkgs {
+		prog.Files = append(prog.Files, pkg.Info.Files...)
 
-		ssapkg := ssaprog.Package(pkginfo.Pkg)
-		for _, f := range pkginfo.Files {
+		ssapkg := ssaprog.Package(pkg.Info.Pkg)
+		for _, f := range pkg.Info.Files {
 			tf := lprog.Fset.File(f.Pos())
 			prog.tokenFileMap[tf] = f
-			prog.astFileMap[f] = ssapkg
+			prog.astFileMap[f] = pkgMap[ssapkg]
 		}
 	}
-	for _, pkginfo := range lprog.InitialPackages() {
-		for k, v := range pkginfo.Info.Types {
+
+	sizes := struct {
+		types      int
+		defs       int
+		uses       int
+		implicits  int
+		selections int
+		scopes     int
+	}{}
+	for _, pkg := range pkgs {
+		sizes.types += len(pkg.Info.Info.Types)
+		sizes.defs += len(pkg.Info.Info.Defs)
+		sizes.uses += len(pkg.Info.Info.Uses)
+		sizes.implicits += len(pkg.Info.Info.Implicits)
+		sizes.selections += len(pkg.Info.Info.Selections)
+		sizes.scopes += len(pkg.Info.Info.Scopes)
+	}
+	prog.Info.Types = make(map[ast.Expr]types.TypeAndValue, sizes.types)
+	prog.Info.Defs = make(map[*ast.Ident]types.Object, sizes.defs)
+	prog.Info.Uses = make(map[*ast.Ident]types.Object, sizes.uses)
+	prog.Info.Implicits = make(map[ast.Node]types.Object, sizes.implicits)
+	prog.Info.Selections = make(map[*ast.SelectorExpr]*types.Selection, sizes.selections)
+	prog.Info.Scopes = make(map[ast.Node]*types.Scope, sizes.scopes)
+	for _, pkg := range pkgs {
+		for k, v := range pkg.Info.Info.Types {
 			prog.Info.Types[k] = v
 		}
-		for k, v := range pkginfo.Info.Defs {
+		for k, v := range pkg.Info.Info.Defs {
 			prog.Info.Defs[k] = v
 		}
-		for k, v := range pkginfo.Info.Uses {
+		for k, v := range pkg.Info.Info.Uses {
 			prog.Info.Uses[k] = v
 		}
-		for k, v := range pkginfo.Info.Implicits {
+		for k, v := range pkg.Info.Info.Implicits {
 			prog.Info.Implicits[k] = v
 		}
-		for k, v := range pkginfo.Info.Selections {
+		for k, v := range pkg.Info.Info.Selections {
 			prog.Info.Selections[k] = v
 		}
-		for k, v := range pkginfo.Info.Scopes {
+		for k, v := range pkg.Info.Info.Scopes {
 			prog.Info.Scopes[k] = v
 		}
 	}
@@ -259,6 +278,17 @@ type packager interface {
 	Package() *ssa.Package
 }
 
+func IsExample(fn *ssa.Function) bool {
+	if !strings.HasPrefix(fn.Name(), "Example") {
+		return false
+	}
+	f := fn.Prog.Fset.File(fn.Pos())
+	if f == nil {
+		return false
+	}
+	return strings.HasSuffix(f.Name(), "_test.go")
+}
+
 func (j *Job) IsInTest(node Positioner) bool {
 	f := j.Program.SSA.Fset.File(node.Pos())
 	return f != nil && strings.HasSuffix(f.Name(), "_test.go")
@@ -377,18 +407,11 @@ func (j *Job) ExprToString(expr ast.Expr) (string, bool) {
 	return constant.StringVal(val), true
 }
 
-func (j *Job) NodePackage(node Positioner) *ssa.Package {
+func (j *Job) NodePackage(node Positioner) *Pkg {
 	f := j.File(node)
 	return j.Program.astFileMap[f]
 }
 
-func (j *Job) EnclosingSSAFunction(node Positioner) *ssa.Function {
-	f := j.File(node)
-	path, _ := astutil.PathEnclosingInterval(f, node.Pos(), node.Pos())
-	pkg := j.Program.astFileMap[f]
-	return ssa.EnclosingFunction(pkg, path)
-}
-
 func IsGenerated(f *ast.File) bool {
 	comments := f.Comments
 	if len(comments) > 0 {
@@ -403,7 +426,7 @@ func (j *Job) IsGoVersion(minor int) bool {
 	return j.Program.GoVersion >= minor
 }
 
-func (j *Job) IsFunctionCallName(node ast.Node, name string) bool {
+func (j *Job) IsCallToAST(node ast.Node, name string) bool {
 	call, ok := node.(*ast.CallExpr)
 	if !ok {
 		return false
@@ -416,9 +439,9 @@ func (j *Job) IsFunctionCallName(node ast.Node, name string) bool {
 	return ok && fn.FullName() == name
 }
 
-func (j *Job) IsFunctionCallNameAny(node ast.Node, names ...string) bool {
+func (j *Job) IsCallToAnyAST(node ast.Node, names ...string) bool {
 	for _, name := range names {
-		if j.IsFunctionCallName(node, name) {
+		if j.IsCallToAST(node, name) {
 			return true
 		}
 	}
@@ -463,16 +486,15 @@ func NodeFns(pkgs []*Pkg) map[ast.Node]*ssa.Function {
 	chNodeFns := make(chan map[ast.Node]*ssa.Function, runtime.NumCPU()*2)
 	for _, pkg := range pkgs {
 		pkg := pkg
-		for _, f := range pkg.Info.Files {
-			f := f
-			wg.Add(1)
-			go func() {
-				m := map[ast.Node]*ssa.Function{}
+		wg.Add(1)
+		go func() {
+			m := map[ast.Node]*ssa.Function{}
+			for _, f := range pkg.Info.Files {
 				ast.Walk(&globalVisitor{m, pkg, f}, f)
-				chNodeFns <- m
-				wg.Done()
-			}()
-		}
+			}
+			chNodeFns <- m
+			wg.Done()
+		}()
 	}
 	go func() {
 		wg.Wait()
@@ -499,7 +521,7 @@ func (v *globalVisitor) Visit(node ast.Node) ast.Visitor {
 	case *ast.CallExpr:
 		v.m[node] = v.pkg.Func("init")
 		return v
-	case *ast.FuncDecl:
+	case *ast.FuncDecl, *ast.FuncLit:
 		nv := &fnVisitor{v.m, v.f, v.pkg, nil}
 		return nv.Visit(node)
 	default:
diff --git a/_linters/src/honnef.co/go/tools/lint/lintutil/util.go b/_linters/src/honnef.co/go/tools/lint/lintutil/util.go
index 376955d..53b9f83 100644
--- a/_linters/src/honnef.co/go/tools/lint/lintutil/util.go
+++ b/_linters/src/honnef.co/go/tools/lint/lintutil/util.go
@@ -14,7 +14,6 @@ import (
 	"go/build"
 	"go/parser"
 	"go/token"
-	"log"
 	"os"
 	"path/filepath"
 	"strconv"
@@ -43,8 +42,6 @@ type runner struct {
 	tags    []string
 	ignores []lint.Ignore
 	version int
-
-	unclean bool
 }
 
 func (runner runner) resolveRelative(importPaths []string) (goFiles bool, err error) {
@@ -132,28 +129,60 @@ func FlagSet(name string) *flag.FlagSet {
 	return flags
 }
 
-func ProcessFlagSet(name string, c lint.Checker, fs *flag.FlagSet) {
+func ProcessFlagSet(c lint.Checker, fs *flag.FlagSet) {
 	tags := fs.Lookup("tags").Value.(flag.Getter).Get().(string)
 	ignore := fs.Lookup("ignore").Value.(flag.Getter).Get().(string)
 	tests := fs.Lookup("tests").Value.(flag.Getter).Get().(bool)
 	version := fs.Lookup("go").Value.(flag.Getter).Get().(int)
 
-	ignores, err := parseIgnore(ignore)
+	ps, lprog, err := Lint(c, fs.Args(), &Options{
+		Tags:      strings.Fields(tags),
+		LintTests: tests,
+		Ignores:   ignore,
+		GoVersion: version,
+	})
 	if err != nil {
 		fmt.Fprintln(os.Stderr, err)
 		os.Exit(1)
 	}
+	unclean := false
+	for _, p := range ps {
+		unclean = true
+		pos := lprog.Fset.Position(p.Position)
+		fmt.Printf("%v: %s\n", relativePositionString(pos), p.Text)
+	}
+	if unclean {
+		os.Exit(1)
+	}
+}
+
+type Options struct {
+	Tags      []string
+	LintTests bool
+	Ignores   string
+	GoVersion int
+}
+
+func Lint(c lint.Checker, pkgs []string, opt *Options) ([]lint.Problem, *loader.Program, error) {
+	// TODO(dh): Instead of returning the loader.Program, we should
+	// store token.Position instead of token.Pos in lint.Problem.
+	if opt == nil {
+		opt = &Options{}
+	}
+	ignores, err := parseIgnore(opt.Ignores)
+	if err != nil {
+		return nil, nil, err
+	}
 	runner := &runner{
 		checker: c,
-		tags:    strings.Fields(tags),
+		tags:    opt.Tags,
 		ignores: ignores,
-		version: version,
+		version: opt.GoVersion,
 	}
-	paths := gotool.ImportPaths(fs.Args())
+	paths := gotool.ImportPaths(pkgs)
 	goFiles, err := runner.resolveRelative(paths)
 	if err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		runner.unclean = true
+		return nil, nil, err
 	}
 	ctx := build.Default
 	ctx.BuildTags = runner.tags
@@ -164,34 +193,16 @@ func ProcessFlagSet(name string, c lint.Checker, fs *flag.FlagSet) {
 	}
 	if goFiles {
 		conf.CreateFromFilenames("adhoc", paths...)
-		lprog, err := conf.Load()
-		if err != nil {
-			log.Fatal(err)
-		}
-		ps := runner.lint(lprog)
-		for _, p := range ps {
-			runner.unclean = true
-			pos := lprog.Fset.Position(p.Position)
-			fmt.Printf("%v: %s\n", relativePositionString(pos), p.Text)
-		}
 	} else {
 		for _, path := range paths {
-			conf.ImportPkgs[path] = tests
-		}
-		lprog, err := conf.Load()
-		if err != nil {
-			log.Fatal(err)
-		}
-		ps := runner.lint(lprog)
-		for _, p := range ps {
-			runner.unclean = true
-			pos := lprog.Fset.Position(p.Position)
-			fmt.Printf("%v: %s\n", relativePositionString(pos), p.Text)
+			conf.ImportPkgs[path] = opt.LintTests
 		}
 	}
-	if runner.unclean {
-		os.Exit(1)
+	lprog, err := conf.Load()
+	if err != nil {
+		return nil, nil, err
 	}
+	return runner.lint(lprog), lprog, nil
 }
 
 func shortPath(path string) string {
@@ -223,7 +234,7 @@ func ProcessArgs(name string, c lint.Checker, args []string) {
 	flags := FlagSet(name)
 	flags.Parse(args)
 
-	ProcessFlagSet(name, c, flags)
+	ProcessFlagSet(c, flags)
 }
 
 func (runner *runner) lint(lprog *loader.Program) []lint.Problem {
diff --git a/_linters/src/honnef.co/go/tools/simple/lint.go b/_linters/src/honnef.co/go/tools/simple/lint.go
index 921ebc7..9ea35d9 100644
--- a/_linters/src/honnef.co/go/tools/simple/lint.go
+++ b/_linters/src/honnef.co/go/tools/simple/lint.go
@@ -11,15 +11,29 @@ import (
 	"strconv"
 	"strings"
 
+	"honnef.co/go/tools/internal/sharedcheck"
 	"honnef.co/go/tools/lint"
+	"honnef.co/go/tools/ssa"
+
+	"golang.org/x/tools/go/types/typeutil"
 )
 
 type Checker struct {
 	CheckGenerated bool
+	MS             *typeutil.MethodSetCache
+
+	nodeFns map[ast.Node]*ssa.Function
+}
+
+func NewChecker() *Checker {
+	return &Checker{
+		MS: &typeutil.MethodSetCache{},
+	}
 }
 
-func NewChecker() *Checker            { return &Checker{} }
-func (c *Checker) Init(*lint.Program) {}
+func (c *Checker) Init(prog *lint.Program) {
+	c.nodeFns = lint.NodeFns(prog.Packages)
+}
 
 func (c *Checker) Funcs() map[string]lint.Func {
 	return map[string]lint.Func{
@@ -48,6 +62,11 @@ func (c *Checker) Funcs() map[string]lint.Func {
 		"S1022": c.LintBlankOK,
 		"S1023": c.LintRedundantBreak,
 		"S1024": c.LintTimeUntil,
+		"S1025": c.LintRedundantSprintf,
+		"S1026": c.LintStringCopy,
+		"S1027": c.LintRedundantReturn,
+		"S1028": c.LintErrorsNewSprintf,
+		"S1029": c.LintRangeStringRunes,
 	}
 }
 
@@ -313,7 +332,7 @@ func (c *Checker) LintBytesCompare(j *lint.Job) {
 		if !ok {
 			return true
 		}
-		if !j.IsFunctionCallName(call, "bytes.Compare") {
+		if !j.IsCallToAST(call, "bytes.Compare") {
 			return true
 		}
 		value, ok := j.ExprToInt(expr.Y)
@@ -376,8 +395,8 @@ func (c *Checker) LintRegexpRaw(j *lint.Job) {
 		if !ok {
 			return true
 		}
-		if !j.IsFunctionCallName(call, "regexp.MustCompile") &&
-			!j.IsFunctionCallName(call, "regexp.Compile") {
+		if !j.IsCallToAST(call, "regexp.MustCompile") &&
+			!j.IsCallToAST(call, "regexp.Compile") {
 			return true
 		}
 		sel, ok := call.Fun.(*ast.SelectorExpr)
@@ -766,7 +785,7 @@ func (c *Checker) LintTimeSince(j *lint.Job) {
 		if !ok {
 			return true
 		}
-		if !j.IsFunctionCallName(sel.X, "time.Now") {
+		if !j.IsCallToAST(sel.X, "time.Now") {
 			return true
 		}
 		if sel.Sel.Name != "Sub" {
@@ -789,10 +808,10 @@ func (c *Checker) LintTimeUntil(j *lint.Job) {
 		if !ok {
 			return true
 		}
-		if !j.IsFunctionCallName(call, "(time.Time).Sub") {
+		if !j.IsCallToAST(call, "(time.Time).Sub") {
 			return true
 		}
-		if !j.IsFunctionCallName(call.Args[0], "time.Now") {
+		if !j.IsCallToAST(call.Args[0], "time.Now") {
 			return true
 		}
 		j.Errorf(call, "should use time.Until instead of t.Sub(time.Now())")
@@ -899,7 +918,7 @@ func (c *Checker) LintSimplerReturn(j *lint.Job) {
 					continue
 				}
 				_, idIface := id1Obj.Type().Underlying().(*types.Interface)
-				_, retIface := j.Program.Info.TypeOf(ret.List[ret.NumFields()-1].Type).Underlying().(*types.Interface)
+				_, retIface := j.Program.Info.TypeOf(ret.List[len(ret.List)-1].Type).Underlying().(*types.Interface)
 
 				if retIface && !idIface {
 					// When the return value is an interface, but the
@@ -958,11 +977,7 @@ func (c *Checker) LintFormatInt(j *lint.Job) {
 		if !ok {
 			return false
 		}
-		switch typ.Kind() {
-		case types.Int, types.Int32:
-			return true
-		}
-		return false
+		return typ.Kind() == types.Int
 	}
 	checkConst := func(v *ast.Ident) bool {
 		c, ok := j.Program.Info.ObjectOf(v).(*types.Const)
@@ -988,7 +1003,7 @@ func (c *Checker) LintFormatInt(j *lint.Job) {
 		if !ok {
 			return true
 		}
-		if !j.IsFunctionCallName(call, "strconv.FormatInt") {
+		if !j.IsCallToAST(call, "strconv.FormatInt") {
 			return true
 		}
 		if len(call.Args) != 2 {
@@ -1639,3 +1654,200 @@ func (c *Checker) LintRedundantBreak(j *lint.Job) {
 		ast.Inspect(f, fn)
 	}
 }
+
+func (c *Checker) Implements(j *lint.Job, typ types.Type, iface string) bool {
+	// OPT(dh): we can cache the type lookup
+	idx := strings.IndexRune(iface, '.')
+	var scope *types.Scope
+	var ifaceName string
+	if idx == -1 {
+		scope = types.Universe
+		ifaceName = iface
+	} else {
+		pkgName := iface[:idx]
+		pkg := j.Program.Prog.Package(pkgName)
+		if pkg == nil {
+			return false
+		}
+		scope = pkg.Pkg.Scope()
+		ifaceName = iface[idx+1:]
+	}
+
+	obj := scope.Lookup(ifaceName)
+	if obj == nil {
+		return false
+	}
+	i, ok := obj.Type().Underlying().(*types.Interface)
+	if !ok {
+		return false
+	}
+	return types.Implements(typ, i)
+}
+
+func (c *Checker) LintRedundantSprintf(j *lint.Job) {
+	fn := func(node ast.Node) bool {
+		call, ok := node.(*ast.CallExpr)
+		if !ok {
+			return true
+		}
+		if !j.IsCallToAST(call, "fmt.Sprintf") {
+			return true
+		}
+		if len(call.Args) != 2 {
+			return true
+		}
+		if s, ok := j.ExprToString(call.Args[0]); !ok || s != "%s" {
+			return true
+		}
+		pkg := j.NodePackage(call)
+		arg := call.Args[1]
+		typ := pkg.Info.TypeOf(arg)
+
+		if c.Implements(j, typ, "fmt.Stringer") {
+			j.Errorf(call, "should use String() instead of fmt.Sprintf")
+			return true
+		}
+
+		if typ.Underlying() == types.Universe.Lookup("string").Type() {
+			if typ == types.Universe.Lookup("string").Type() {
+				j.Errorf(call, "the argument is already a string, there's no need to use fmt.Sprintf")
+			} else {
+				j.Errorf(call, "the argument's underlying type is a string, should use a simple conversion instead of fmt.Sprintf")
+			}
+		}
+		return true
+	}
+	for _, f := range c.filterGenerated(j.Program.Files) {
+		ast.Inspect(f, fn)
+	}
+}
+
+func (c *Checker) LintStringCopy(j *lint.Job) {
+	emptyStringLit := func(e ast.Expr) bool {
+		bl, ok := e.(*ast.BasicLit)
+		return ok && bl.Value == `""`
+	}
+	fn := func(node ast.Node) bool {
+		switch x := node.(type) {
+		case *ast.BinaryExpr: // "" + s, s + ""
+			if x.Op != token.ADD {
+				break
+			}
+			l1 := j.Program.Prog.Fset.Position(x.X.Pos()).Line
+			l2 := j.Program.Prog.Fset.Position(x.Y.Pos()).Line
+			if l1 != l2 {
+				break
+			}
+			var want ast.Expr
+			switch {
+			case emptyStringLit(x.X):
+				want = x.Y
+			case emptyStringLit(x.Y):
+				want = x.X
+			default:
+				return true
+			}
+			j.Errorf(x, "should use %s instead of %s",
+				j.Render(want), j.Render(x))
+		case *ast.CallExpr:
+			if j.IsCallToAST(x, "fmt.Sprint") && len(x.Args) == 1 {
+				// fmt.Sprint(x)
+
+				argT := j.Program.Info.TypeOf(x.Args[0])
+				bt, ok := argT.Underlying().(*types.Basic)
+				if !ok || bt.Kind() != types.String {
+					return true
+				}
+				if c.Implements(j, argT, "fmt.Stringer") || c.Implements(j, argT, "error") {
+					return true
+				}
+
+				j.Errorf(x, "should use %s instead of %s", j.Render(x.Args[0]), j.Render(x))
+				return true
+			}
+
+			// string([]byte(s))
+			bt, ok := j.Program.Info.TypeOf(x.Fun).(*types.Basic)
+			if !ok || bt.Kind() != types.String {
+				break
+			}
+			nested, ok := x.Args[0].(*ast.CallExpr)
+			if !ok {
+				break
+			}
+			st, ok := j.Program.Info.TypeOf(nested.Fun).(*types.Slice)
+			if !ok {
+				break
+			}
+			et, ok := st.Elem().(*types.Basic)
+			if !ok || et.Kind() != types.Byte {
+				break
+			}
+			xt, ok := j.Program.Info.TypeOf(nested.Args[0]).(*types.Basic)
+			if !ok || xt.Kind() != types.String {
+				break
+			}
+			j.Errorf(x, "should use %s instead of %s",
+				j.Render(nested.Args[0]), j.Render(x))
+		}
+		return true
+	}
+	for _, f := range c.filterGenerated(j.Program.Files) {
+		ast.Inspect(f, fn)
+	}
+}
+
+func (c *Checker) LintRedundantReturn(j *lint.Job) {
+	fn := func(node ast.Node) bool {
+		var ret *ast.FieldList
+		var body *ast.BlockStmt
+		switch x := node.(type) {
+		case *ast.FuncDecl:
+			ret = x.Type.Results
+			body = x.Body
+		case *ast.FuncLit:
+			ret = x.Type.Results
+			body = x.Body
+		default:
+			return true
+		}
+		// if the func has results, a return can't be redundant.
+		// similarly, if there are no statements, there can be
+		// no return.
+		if ret != nil || body == nil || len(body.List) < 1 {
+			return true
+		}
+		rst, ok := body.List[len(body.List)-1].(*ast.ReturnStmt)
+		if !ok {
+			return true
+		}
+		// we don't need to check rst.Results as we already
+		// checked x.Type.Results to be nil.
+		j.Errorf(rst, "redundant return statement")
+		return true
+	}
+	for _, f := range c.filterGenerated(j.Program.Files) {
+		ast.Inspect(f, fn)
+	}
+}
+
+func (c *Checker) LintErrorsNewSprintf(j *lint.Job) {
+	fn := func(node ast.Node) bool {
+		if !j.IsCallToAST(node, "errors.New") {
+			return true
+		}
+		call := node.(*ast.CallExpr)
+		if !j.IsCallToAST(call.Args[0], "fmt.Sprintf") {
+			return true
+		}
+		j.Errorf(node, "should use fmt.Errorf(...) instead of errors.New(fmt.Sprintf(...))")
+		return true
+	}
+	for _, f := range c.filterGenerated(j.Program.Files) {
+		ast.Inspect(f, fn)
+	}
+}
+
+func (c *Checker) LintRangeStringRunes(j *lint.Job) {
+	sharedcheck.CheckRangeStringRunes(c.nodeFns, j)
+}
diff --git a/_linters/src/honnef.co/go/tools/ssa/builder.go b/_linters/src/honnef.co/go/tools/ssa/builder.go
index 6d718c5..bfb7a2b 100644
--- a/_linters/src/honnef.co/go/tools/ssa/builder.go
+++ b/_linters/src/honnef.co/go/tools/ssa/builder.go
@@ -970,9 +970,9 @@ func (b *builder) setCall(fn *Function, e *ast.CallExpr, c *CallCommon) {
 }
 
 // assignOp emits to fn code to perform loc += incr or loc -= incr.
-func (b *builder) assignOp(fn *Function, loc lvalue, incr Value, op token.Token) {
+func (b *builder) assignOp(fn *Function, loc lvalue, incr Value, op token.Token, pos token.Pos) {
 	oldv := loc.load(fn)
-	loc.store(fn, emitArith(fn, op, oldv, emitConv(fn, incr, oldv.Type()), loc.typ(), token.NoPos))
+	loc.store(fn, emitArith(fn, op, oldv, emitConv(fn, incr, oldv.Type()), loc.typ(), pos))
 }
 
 // localValueSpec emits to fn code to define all of the vars in the
@@ -1289,11 +1289,7 @@ func (b *builder) switchStmt(fn *Function, s *ast.SwitchStmt, label *lblock) {
 			// followed by If.  Don't forget conversions
 			// though.
 			cond := emitCompare(fn, token.EQL, tag, b.expr(fn, cond), token.NoPos)
-
-			thunk := fn.newBasicBlock("switch.sigma")
-			emitIf(fn, cond, thunk, nextCond)
-			fn.currentBlock = thunk
-			emitJump(fn, body)
+			emitIf(fn, cond, body, nextCond)
 			fn.currentBlock = nextCond
 		}
 		fn.currentBlock = body
@@ -2002,7 +1998,7 @@ start:
 			op = token.SUB
 		}
 		loc := b.addr(fn, s.X, false)
-		b.assignOp(fn, loc, NewConst(exact.MakeInt64(1), loc.typ()), op)
+		b.assignOp(fn, loc, NewConst(exact.MakeInt64(1), loc.typ()), op, s.Pos())
 
 	case *ast.AssignStmt:
 		switch s.Tok {
@@ -2011,7 +2007,7 @@ start:
 
 		default: // +=, etc.
 			op := s.Tok + token.ADD - token.ADD_ASSIGN
-			b.assignOp(fn, b.addr(fn, s.Lhs[0], false), b.expr(fn, s.Rhs[0]), op)
+			b.assignOp(fn, b.addr(fn, s.Lhs[0], false), b.expr(fn, s.Rhs[0]), op, s.Pos())
 		}
 
 	case *ast.GoStmt:
diff --git a/_linters/src/honnef.co/go/tools/ssa/emit.go b/_linters/src/honnef.co/go/tools/ssa/emit.go
index 58d8ab5..400da21 100644
--- a/_linters/src/honnef.co/go/tools/ssa/emit.go
+++ b/_linters/src/honnef.co/go/tools/ssa/emit.go
@@ -149,7 +149,7 @@ func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value {
 //
 func isValuePreserving(ut_src, ut_dst types.Type) bool {
 	// Identical underlying types?
-	if types.Identical(ut_dst, ut_src) {
+	if structTypesIdentical(ut_dst, ut_src) {
 		return true
 	}
 
@@ -279,65 +279,11 @@ func (b *BasicBlock) emitJump(target *BasicBlock) {
 func emitIf(f *Function, cond Value, tblock, fblock *BasicBlock) {
 	b := f.currentBlock
 	b.emit(&If{Cond: cond})
-
-	tt := f.newBasicBlock("if.sigma")
-	ft := f.newBasicBlock("if.sigma")
-
-	addEdge(b, tt)
-	addEdge(b, ft)
-
-	switch cond := cond.(type) {
-	case *BinOp:
-		switch x := cond.X.(type) {
-		case *Const:
-		default:
-			emitSigma(f, tt, x, true)
-			emitSigma(f, ft, x, false)
-		}
-		switch y := cond.Y.(type) {
-		case *Const:
-		default:
-			emitSigma(f, tt, y, true)
-			emitSigma(f, ft, y, false)
-		}
-	}
-
-	tt.emitJump(tblock)
-	ft.emitJump(fblock)
-
+	addEdge(b, tblock)
+	addEdge(b, fblock)
 	f.currentBlock = nil
 }
 
-func emitSigma(f *Function, b *BasicBlock, v Value, branch bool) {
-	f.currentBlock = b
-	switch v := v.(type) {
-	case *UnOp:
-		if alloc, ok := v.X.(*Alloc); !ok || alloc.Heap {
-			return
-		}
-		sigma := &Sigma{
-			X:      v,
-			Branch: branch,
-		}
-		sigma.setType(v.Type())
-		pv := f.emit(sigma)
-		emitStore(f, v.X, pv, 0)
-	case *Call:
-		call, ok := v.Common().Value.(*Builtin)
-		if !ok {
-			return
-		}
-		ops := v.Operands(nil)
-		switch call.Name() {
-		case "len":
-			switch (*ops[1]).Type().Underlying().(type) {
-			case *types.Basic:
-				emitSigma(f, b, *ops[1], branch)
-			}
-		}
-	}
-}
-
 // emitExtract emits to f an instruction to extract the index'th
 // component of tuple.  It returns the extracted value.
 //
diff --git a/_linters/src/honnef.co/go/tools/ssa/func.go b/_linters/src/honnef.co/go/tools/ssa/func.go
index a58a979..86a3da7 100644
--- a/_linters/src/honnef.co/go/tools/ssa/func.go
+++ b/_linters/src/honnef.co/go/tools/ssa/func.go
@@ -353,52 +353,11 @@ func (f *Function) finishBody() {
 		printMu.Unlock()
 	}
 
-	flattenPhis(f)
-	cullSigmas(f)
-	optimizeBlocks(f)
-
 	if f.Prog.mode&SanityCheckFunctions != 0 {
 		mustSanityCheck(f, nil)
 	}
 }
 
-func cullSigmas(fn *Function) {
-	if len(fn.Blocks) == 0 {
-		return
-	}
-	for _, block := range fn.Blocks {
-		var instrs []Instruction
-		for _, ins := range block.Instrs {
-			if sigma, ok := ins.(*Sigma); ok {
-				if refs := sigma.Referrers(); refs == nil || len(*refs) > 0 {
-					instrs = append(instrs, ins)
-				}
-			} else {
-				instrs = append(instrs, ins)
-			}
-		}
-		block.Instrs = instrs
-	}
-}
-
-func flattenPhis(fn *Function) {
-	if len(fn.Blocks) == 0 {
-		return
-	}
-	for _, block := range fn.Blocks {
-		var newInstrs []Instruction
-		for _, ins := range block.Instrs {
-			phi, ok := ins.(*Phi)
-			if !ok || len(phi.Edges) > 1 {
-				newInstrs = append(newInstrs, ins)
-				continue
-			}
-			ReplaceAll(phi, phi.Edges[0])
-		}
-		block.Instrs = newInstrs
-	}
-}
-
 func (f *Function) RemoveNilBlocks() {
 	f.removeNilBlocks()
 }
diff --git a/_linters/src/honnef.co/go/tools/ssa/identical.go b/_linters/src/honnef.co/go/tools/ssa/identical.go
new file mode 100644
index 0000000..53cbee1
--- /dev/null
+++ b/_linters/src/honnef.co/go/tools/ssa/identical.go
@@ -0,0 +1,7 @@
+// +build go1.8
+
+package ssa
+
+import "go/types"
+
+var structTypesIdentical = types.IdenticalIgnoreTags
diff --git a/_linters/src/honnef.co/go/tools/ssa/identical_17.go b/_linters/src/honnef.co/go/tools/ssa/identical_17.go
new file mode 100644
index 0000000..da89d33
--- /dev/null
+++ b/_linters/src/honnef.co/go/tools/ssa/identical_17.go
@@ -0,0 +1,7 @@
+// +build !go1.8
+
+package ssa
+
+import "go/types"
+
+var structTypesIdentical = types.Identical
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/external.go b/_linters/src/honnef.co/go/tools/ssa/interp/external.go
deleted file mode 100644
index 62ddea4..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/external.go
+++ /dev/null
@@ -1,503 +0,0 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.5
-
-package interp
-
-// Emulated functions that we cannot interpret because they are
-// external or because they use "unsafe" or "reflect" operations.
-
-import (
-	"go/types"
-	"math"
-	"os"
-	"runtime"
-	"strings"
-	"sync/atomic"
-	"syscall"
-	"time"
-	"unsafe"
-
-	"honnef.co/go/tools/ssa"
-)
-
-type externalFn func(fr *frame, args []value) value
-
-// TODO(adonovan): fix: reflect.Value abstracts an lvalue or an
-// rvalue; Set() causes mutations that can be observed via aliases.
-// We have not captured that correctly here.
-
-// Key strings are from Function.String().
-var externals map[string]externalFn
-
-func init() {
-	// That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd].
-	externals = map[string]externalFn{
-		"(*sync.Pool).Get":                 ext۰sync۰Pool۰Get,
-		"(*sync.Pool).Put":                 ext۰nop,
-		"(reflect.Value).Bool":             ext۰reflect۰Value۰Bool,
-		"(reflect.Value).CanAddr":          ext۰reflect۰Value۰CanAddr,
-		"(reflect.Value).CanInterface":     ext۰reflect۰Value۰CanInterface,
-		"(reflect.Value).Elem":             ext۰reflect۰Value۰Elem,
-		"(reflect.Value).Field":            ext۰reflect۰Value۰Field,
-		"(reflect.Value).Float":            ext۰reflect۰Value۰Float,
-		"(reflect.Value).Index":            ext۰reflect۰Value۰Index,
-		"(reflect.Value).Int":              ext۰reflect۰Value۰Int,
-		"(reflect.Value).Interface":        ext۰reflect۰Value۰Interface,
-		"(reflect.Value).IsNil":            ext۰reflect۰Value۰IsNil,
-		"(reflect.Value).IsValid":          ext۰reflect۰Value۰IsValid,
-		"(reflect.Value).Kind":             ext۰reflect۰Value۰Kind,
-		"(reflect.Value).Len":              ext۰reflect۰Value۰Len,
-		"(reflect.Value).MapIndex":         ext۰reflect۰Value۰MapIndex,
-		"(reflect.Value).MapKeys":          ext۰reflect۰Value۰MapKeys,
-		"(reflect.Value).NumField":         ext۰reflect۰Value۰NumField,
-		"(reflect.Value).NumMethod":        ext۰reflect۰Value۰NumMethod,
-		"(reflect.Value).Pointer":          ext۰reflect۰Value۰Pointer,
-		"(reflect.Value).Set":              ext۰reflect۰Value۰Set,
-		"(reflect.Value).String":           ext۰reflect۰Value۰String,
-		"(reflect.Value).Type":             ext۰reflect۰Value۰Type,
-		"(reflect.Value).Uint":             ext۰reflect۰Value۰Uint,
-		"(reflect.error).Error":            ext۰reflect۰error۰Error,
-		"(reflect.rtype).Bits":             ext۰reflect۰rtype۰Bits,
-		"(reflect.rtype).Elem":             ext۰reflect۰rtype۰Elem,
-		"(reflect.rtype).Field":            ext۰reflect۰rtype۰Field,
-		"(reflect.rtype).In":               ext۰reflect۰rtype۰In,
-		"(reflect.rtype).Kind":             ext۰reflect۰rtype۰Kind,
-		"(reflect.rtype).NumField":         ext۰reflect۰rtype۰NumField,
-		"(reflect.rtype).NumIn":            ext۰reflect۰rtype۰NumIn,
-		"(reflect.rtype).NumMethod":        ext۰reflect۰rtype۰NumMethod,
-		"(reflect.rtype).NumOut":           ext۰reflect۰rtype۰NumOut,
-		"(reflect.rtype).Out":              ext۰reflect۰rtype۰Out,
-		"(reflect.rtype).Size":             ext۰reflect۰rtype۰Size,
-		"(reflect.rtype).String":           ext۰reflect۰rtype۰String,
-		"bytes.init":                       ext۰nop, // avoid asm dependency
-		"bytes.Equal":                      ext۰bytes۰Equal,
-		"bytes.IndexByte":                  ext۰bytes۰IndexByte,
-		"hash/crc32.haveSSE42":             ext۰crc32۰haveSSE42,
-		"math.Abs":                         ext۰math۰Abs,
-		"math.Exp":                         ext۰math۰Exp,
-		"math.Float32bits":                 ext۰math۰Float32bits,
-		"math.Float32frombits":             ext۰math۰Float32frombits,
-		"math.Float64bits":                 ext۰math۰Float64bits,
-		"math.Float64frombits":             ext۰math۰Float64frombits,
-		"math.Ldexp":                       ext۰math۰Ldexp,
-		"math.Log":                         ext۰math۰Log,
-		"math.Min":                         ext۰math۰Min,
-		"math.hasSSE4":                     ext۰math۰hasSSE4,
-		"os.Pipe":                          ext۰os۰Pipe,
-		"os.runtime_args":                  ext۰os۰runtime_args,
-		"os.runtime_beforeExit":            ext۰nop,
-		"reflect.New":                      ext۰reflect۰New,
-		"reflect.SliceOf":                  ext۰reflect۰SliceOf,
-		"reflect.TypeOf":                   ext۰reflect۰TypeOf,
-		"reflect.ValueOf":                  ext۰reflect۰ValueOf,
-		"reflect.Zero":                     ext۰reflect۰Zero,
-		"reflect.init":                     ext۰reflect۰Init,
-		"reflect.valueInterface":           ext۰reflect۰valueInterface,
-		"runtime.Breakpoint":               ext۰runtime۰Breakpoint,
-		"runtime.Caller":                   ext۰runtime۰Caller,
-		"runtime.Callers":                  ext۰runtime۰Callers,
-		"runtime.FuncForPC":                ext۰runtime۰FuncForPC,
-		"runtime.GC":                       ext۰runtime۰GC,
-		"runtime.GOMAXPROCS":               ext۰runtime۰GOMAXPROCS,
-		"runtime.Goexit":                   ext۰runtime۰Goexit,
-		"runtime.Gosched":                  ext۰runtime۰Gosched,
-		"runtime.init":                     ext۰nop,
-		"runtime.NumCPU":                   ext۰runtime۰NumCPU,
-		"runtime.NumGoroutine":             ext۰runtime۰NumGoroutine,
-		"runtime.ReadMemStats":             ext۰runtime۰ReadMemStats,
-		"runtime.SetFinalizer":             ext۰nop, // ignore
-		"(*runtime.Func).Entry":            ext۰runtime۰Func۰Entry,
-		"(*runtime.Func).FileLine":         ext۰runtime۰Func۰FileLine,
-		"(*runtime.Func).Name":             ext۰runtime۰Func۰Name,
-		"runtime.environ":                  ext۰runtime۰environ,
-		"runtime.getgoroot":                ext۰runtime۰getgoroot,
-		"strings.init":                     ext۰nop, // avoid asm dependency
-		"strings.Index":                    ext۰strings۰Index,
-		"strings.IndexByte":                ext۰strings۰IndexByte,
-		"sync.runtime_Semacquire":          ext۰nop, // unimplementable
-		"sync.runtime_Semrelease":          ext۰nop, // unimplementable
-		"sync.runtime_Syncsemcheck":        ext۰nop, // unimplementable
-		"sync.runtime_notifyListCheck":     ext۰nop,
-		"sync.runtime_registerPoolCleanup": ext۰nop,
-		"sync/atomic.AddInt32":             ext۰atomic۰AddInt32,
-		"sync/atomic.AddUint32":            ext۰atomic۰AddUint32,
-		"sync/atomic.AddUint64":            ext۰atomic۰AddUint64,
-		"sync/atomic.CompareAndSwapInt32":  ext۰atomic۰CompareAndSwapInt32,
-		"sync/atomic.LoadInt32":            ext۰atomic۰LoadInt32,
-		"sync/atomic.LoadUint32":           ext۰atomic۰LoadUint32,
-		"sync/atomic.StoreInt32":           ext۰atomic۰StoreInt32,
-		"sync/atomic.StoreUint32":          ext۰atomic۰StoreUint32,
-		"syscall.Close":                    ext۰syscall۰Close,
-		"syscall.Exit":                     ext۰syscall۰Exit,
-		"syscall.Fstat":                    ext۰syscall۰Fstat,
-		"syscall.Getpid":                   ext۰syscall۰Getpid,
-		"syscall.Getwd":                    ext۰syscall۰Getwd,
-		"syscall.Kill":                     ext۰syscall۰Kill,
-		"syscall.Lstat":                    ext۰syscall۰Lstat,
-		"syscall.Open":                     ext۰syscall۰Open,
-		"syscall.ParseDirent":              ext۰syscall۰ParseDirent,
-		"syscall.RawSyscall":               ext۰syscall۰RawSyscall,
-		"syscall.Read":                     ext۰syscall۰Read,
-		"syscall.ReadDirent":               ext۰syscall۰ReadDirent,
-		"syscall.Readlink":                 ext۰syscall۰Readlink,
-		"syscall.Stat":                     ext۰syscall۰Stat,
-		"syscall.Write":                    ext۰syscall۰Write,
-		"syscall.runtime_envs":             ext۰runtime۰environ,
-		"testing.runExample":               ext۰testing۰runExample,
-		"time.Sleep":                       ext۰time۰Sleep,
-		"time.now":                         ext۰time۰now,
-	}
-}
-
-// wrapError returns an interpreted 'error' interface value for err.
-func wrapError(err error) value {
-	if err == nil {
-		return iface{}
-	}
-	return iface{t: errorType, v: err.Error()}
-}
-
-func ext۰nop(fr *frame, args []value) value { return nil }
-
-func ext۰sync۰Pool۰Get(fr *frame, args []value) value {
-	Pool := fr.i.prog.ImportedPackage("sync").Type("Pool").Object()
-	_, newIndex, _ := types.LookupFieldOrMethod(Pool.Type(), false, Pool.Pkg(), "New")
-
-	if New := (*args[0].(*value)).(structure)[newIndex[0]]; New != nil {
-		return call(fr.i, fr, 0, New, nil)
-	}
-	return nil
-}
-
-func ext۰bytes۰Equal(fr *frame, args []value) value {
-	// func Equal(a, b []byte) bool
-	a := args[0].([]value)
-	b := args[1].([]value)
-	if len(a) != len(b) {
-		return false
-	}
-	for i := range a {
-		if a[i] != b[i] {
-			return false
-		}
-	}
-	return true
-}
-
-func ext۰bytes۰IndexByte(fr *frame, args []value) value {
-	// func IndexByte(s []byte, c byte) int
-	s := args[0].([]value)
-	c := args[1].(byte)
-	for i, b := range s {
-		if b.(byte) == c {
-			return i
-		}
-	}
-	return -1
-}
-
-func ext۰crc32۰haveSSE42(fr *frame, args []value) value {
-	return false
-}
-
-func ext۰math۰Float64frombits(fr *frame, args []value) value {
-	return math.Float64frombits(args[0].(uint64))
-}
-
-func ext۰math۰Float64bits(fr *frame, args []value) value {
-	return math.Float64bits(args[0].(float64))
-}
-
-func ext۰math۰Float32frombits(fr *frame, args []value) value {
-	return math.Float32frombits(args[0].(uint32))
-}
-
-func ext۰math۰Abs(fr *frame, args []value) value {
-	return math.Abs(args[0].(float64))
-}
-
-func ext۰math۰Exp(fr *frame, args []value) value {
-	return math.Exp(args[0].(float64))
-}
-
-func ext۰math۰Float32bits(fr *frame, args []value) value {
-	return math.Float32bits(args[0].(float32))
-}
-
-func ext۰math۰Min(fr *frame, args []value) value {
-	return math.Min(args[0].(float64), args[1].(float64))
-}
-
-func ext۰math۰hasSSE4(fr *frame, args []value) value {
-	return false
-}
-
-func ext۰math۰Ldexp(fr *frame, args []value) value {
-	return math.Ldexp(args[0].(float64), args[1].(int))
-}
-
-func ext۰math۰Log(fr *frame, args []value) value {
-	return math.Log(args[0].(float64))
-}
-
-func ext۰os۰runtime_args(fr *frame, args []value) value {
-	return fr.i.osArgs
-}
-
-func ext۰runtime۰Breakpoint(fr *frame, args []value) value {
-	runtime.Breakpoint()
-	return nil
-}
-
-func ext۰runtime۰Caller(fr *frame, args []value) value {
-	// func Caller(skip int) (pc uintptr, file string, line int, ok bool)
-	skip := 1 + args[0].(int)
-	for i := 0; i < skip; i++ {
-		if fr != nil {
-			fr = fr.caller
-		}
-	}
-	var pc uintptr
-	var file string
-	var line int
-	var ok bool
-	if fr != nil {
-		fn := fr.fn
-		// TODO(adonovan): use pc/posn of current instruction, not start of fn.
-		// (Required to interpret the log package's tests.)
-		pc = uintptr(unsafe.Pointer(fn))
-		posn := fn.Prog.Fset.Position(fn.Pos())
-		file = posn.Filename
-		line = posn.Line
-		ok = true
-	}
-	return tuple{pc, file, line, ok}
-}
-
-func ext۰runtime۰Callers(fr *frame, args []value) value {
-	// Callers(skip int, pc []uintptr) int
-	skip := args[0].(int)
-	pc := args[1].([]value)
-	for i := 0; i < skip; i++ {
-		if fr != nil {
-			fr = fr.caller
-		}
-	}
-	i := 0
-	for fr != nil {
-		pc[i] = uintptr(unsafe.Pointer(fr.fn))
-		i++
-		fr = fr.caller
-	}
-	return i
-}
-
-func ext۰runtime۰FuncForPC(fr *frame, args []value) value {
-	// FuncForPC(pc uintptr) *Func
-	pc := args[0].(uintptr)
-	var fn *ssa.Function
-	if pc != 0 {
-		fn = (*ssa.Function)(unsafe.Pointer(pc)) // indeed unsafe!
-	}
-	var Func value
-	Func = structure{fn} // a runtime.Func
-	return &Func
-}
-
-func ext۰runtime۰environ(fr *frame, args []value) value {
-	// This function also implements syscall.runtime_envs.
-	return environ
-}
-
-func ext۰runtime۰getgoroot(fr *frame, args []value) value {
-	return os.Getenv("GOROOT")
-}
-
-func ext۰strings۰IndexByte(fr *frame, args []value) value {
-	// Call compiled version to avoid asm dependency.
-	return strings.IndexByte(args[0].(string), args[1].(byte))
-}
-
-func ext۰strings۰Index(fr *frame, args []value) value {
-	// Call compiled version to avoid asm dependency.
-	return strings.Index(args[0].(string), args[1].(string))
-}
-
-func ext۰runtime۰GOMAXPROCS(fr *frame, args []value) value {
-	// Ignore args[0]; don't let the interpreted program
-	// set the interpreter's GOMAXPROCS!
-	return runtime.GOMAXPROCS(0)
-}
-
-func ext۰runtime۰Goexit(fr *frame, args []value) value {
-	// TODO(adonovan): don't kill the interpreter's main goroutine.
-	runtime.Goexit()
-	return nil
-}
-
-func ext۰runtime۰GC(fr *frame, args []value) value {
-	runtime.GC()
-	return nil
-}
-
-func ext۰runtime۰Gosched(fr *frame, args []value) value {
-	runtime.Gosched()
-	return nil
-}
-
-func ext۰runtime۰NumCPU(fr *frame, args []value) value {
-	return runtime.NumCPU()
-}
-
-func ext۰runtime۰NumGoroutine(fr *frame, args []value) value {
-	return int(atomic.LoadInt32(&fr.i.goroutines))
-}
-
-func ext۰runtime۰ReadMemStats(fr *frame, args []value) value {
-	// TODO(adonovan): populate args[0].(Struct)
-	return nil
-}
-
-func ext۰atomic۰LoadUint32(fr *frame, args []value) value {
-	// TODO(adonovan): fix: not atomic!
-	return (*args[0].(*value)).(uint32)
-}
-
-func ext۰atomic۰StoreUint32(fr *frame, args []value) value {
-	// TODO(adonovan): fix: not atomic!
-	*args[0].(*value) = args[1].(uint32)
-	return nil
-}
-
-func ext۰atomic۰LoadInt32(fr *frame, args []value) value {
-	// TODO(adonovan): fix: not atomic!
-	return (*args[0].(*value)).(int32)
-}
-
-func ext۰atomic۰StoreInt32(fr *frame, args []value) value {
-	// TODO(adonovan): fix: not atomic!
-	*args[0].(*value) = args[1].(int32)
-	return nil
-}
-
-func ext۰atomic۰CompareAndSwapInt32(fr *frame, args []value) value {
-	// TODO(adonovan): fix: not atomic!
-	p := args[0].(*value)
-	if (*p).(int32) == args[1].(int32) {
-		*p = args[2].(int32)
-		return true
-	}
-	return false
-}
-
-func ext۰atomic۰AddInt32(fr *frame, args []value) value {
-	// TODO(adonovan): fix: not atomic!
-	p := args[0].(*value)
-	newv := (*p).(int32) + args[1].(int32)
-	*p = newv
-	return newv
-}
-
-func ext۰atomic۰AddUint32(fr *frame, args []value) value {
-	// TODO(adonovan): fix: not atomic!
-	p := args[0].(*value)
-	newv := (*p).(uint32) + args[1].(uint32)
-	*p = newv
-	return newv
-}
-
-func ext۰atomic۰AddUint64(fr *frame, args []value) value {
-	// TODO(adonovan): fix: not atomic!
-	p := args[0].(*value)
-	newv := (*p).(uint64) + args[1].(uint64)
-	*p = newv
-	return newv
-}
-
-// Pretend: type runtime.Func struct { entry *ssa.Function }
-
-func ext۰runtime۰Func۰FileLine(fr *frame, args []value) value {
-	// func (*runtime.Func) FileLine(uintptr) (string, int)
-	f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
-	pc := args[1].(uintptr)
-	_ = pc
-	if f != nil {
-		// TODO(adonovan): use position of current instruction, not fn.
-		posn := f.Prog.Fset.Position(f.Pos())
-		return tuple{posn.Filename, posn.Line}
-	}
-	return tuple{"", 0}
-}
-
-func ext۰runtime۰Func۰Name(fr *frame, args []value) value {
-	// func (*runtime.Func) Name() string
-	f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
-	if f != nil {
-		return f.String()
-	}
-	return ""
-}
-
-func ext۰runtime۰Func۰Entry(fr *frame, args []value) value {
-	// func (*runtime.Func) Entry() uintptr
-	f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
-	return uintptr(unsafe.Pointer(f))
-}
-
-// This is a workaround for a bug in go/ssa/testmain.go: it creates
-// InternalExamples even for Example functions with no Output comment.
-// TODO(adonovan): fix (and redesign) testmain.go after Go 1.6.
-func ext۰testing۰runExample(fr *frame, args []value) value {
-	// This is a stripped down runExample that simply calls the function.
-	// It does not capture and compare output nor recover from panic.
-	//
-	// func runExample(eg testing.InternalExample) bool {
-	//     eg.F()
-	//     return true
-	// }
-	F := args[0].(structure)[1]
-	call(fr.i, fr, 0, F, nil)
-	return true
-}
-
-func ext۰time۰now(fr *frame, args []value) value {
-	nano := time.Now().UnixNano()
-	return tuple{int64(nano / 1e9), int32(nano % 1e9)}
-}
-
-func ext۰time۰Sleep(fr *frame, args []value) value {
-	time.Sleep(time.Duration(args[0].(int64)))
-	return nil
-}
-
-func ext۰syscall۰Exit(fr *frame, args []value) value {
-	panic(exitPanic(args[0].(int)))
-}
-
-func ext۰syscall۰Getwd(fr *frame, args []value) value {
-	s, err := syscall.Getwd()
-	return tuple{s, wrapError(err)}
-}
-
-func ext۰syscall۰Getpid(fr *frame, args []value) value {
-	return syscall.Getpid()
-}
-
-func ext۰syscall۰Readlink(fr *frame, args []value) value {
-	path := args[0].(string)
-	buf := valueToBytes(args[1])
-	n, err := syscall.Readlink(path, buf)
-	return tuple{n, wrapError(err)}
-}
-
-func valueToBytes(v value) []byte {
-	in := v.([]value)
-	b := make([]byte, len(in))
-	for i := range in {
-		b[i] = in[i].(byte)
-	}
-	return b
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/external_darwin.go b/_linters/src/honnef.co/go/tools/ssa/interp/external_darwin.go
deleted file mode 100644
index 4974ad6..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/external_darwin.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin
-
-package interp
-
-import "syscall"
-
-func init() {
-	externals["syscall.Sysctl"] = ext۰syscall۰Sysctl
-}
-
-func ext۰syscall۰Sysctl(fr *frame, args []value) value {
-	r, err := syscall.Sysctl(args[0].(string))
-	return tuple{r, wrapError(err)}
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/external_freebsd.go b/_linters/src/honnef.co/go/tools/ssa/interp/external_freebsd.go
deleted file mode 100644
index 5203303..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/external_freebsd.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build freebsd
-
-package interp
-
-import "syscall"
-
-func init() {
-	externals["syscall.Sysctl"] = ext۰syscall۰Sysctl
-	externals["syscall.SysctlUint32"] = ext۰syscall۰SysctlUint32
-}
-
-func ext۰syscall۰Sysctl(fr *frame, args []value) value {
-	r, err := syscall.Sysctl(args[0].(string))
-	return tuple{r, wrapError(err)}
-}
-
-func ext۰syscall۰SysctlUint32(fr *frame, args []value) value {
-	r, err := syscall.SysctlUint32(args[0].(string))
-	return tuple{r, wrapError(err)}
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/external_plan9.go b/_linters/src/honnef.co/go/tools/ssa/interp/external_plan9.go
deleted file mode 100644
index 81bedcf..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/external_plan9.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package interp
-
-import "syscall"
-
-func ext۰os۰Pipe(fr *frame, args []value) value {
-	panic("os.Pipe not yet implemented")
-}
-func ext۰syscall۰Close(fr *frame, args []value) value {
-	panic("syscall.Close not yet implemented")
-}
-func ext۰syscall۰Fstat(fr *frame, args []value) value {
-	panic("syscall.Fstat not yet implemented")
-}
-func ext۰syscall۰Kill(fr *frame, args []value) value {
-	panic("syscall.Kill not yet implemented")
-}
-func ext۰syscall۰Lstat(fr *frame, args []value) value {
-	panic("syscall.Lstat not yet implemented")
-}
-func ext۰syscall۰Open(fr *frame, args []value) value {
-	panic("syscall.Open not yet implemented")
-}
-func ext۰syscall۰ParseDirent(fr *frame, args []value) value {
-	panic("syscall.ParseDirent not yet implemented")
-}
-func ext۰syscall۰Read(fr *frame, args []value) value {
-	panic("syscall.Read not yet implemented")
-}
-func ext۰syscall۰ReadDirent(fr *frame, args []value) value {
-	panic("syscall.ReadDirent not yet implemented")
-}
-func ext۰syscall۰Stat(fr *frame, args []value) value {
-	panic("syscall.Stat not yet implemented")
-}
-func ext۰syscall۰Write(fr *frame, args []value) value {
-	// func Write(fd int, p []byte) (n int, err error)
-	n, err := write(args[0].(int), valueToBytes(args[1]))
-	return tuple{n, wrapError(err)}
-}
-func ext۰syscall۰RawSyscall(fr *frame, args []value) value {
-	return tuple{^uintptr(0), uintptr(0), uintptr(0)}
-}
-
-func syswrite(fd int, b []byte) (int, error) {
-	return syscall.Write(fd, b)
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/external_unix.go b/_linters/src/honnef.co/go/tools/ssa/interp/external_unix.go
deleted file mode 100644
index be12586..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/external_unix.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !windows,!plan9
-
-package interp
-
-import "syscall"
-
-func ext۰os۰Pipe(fr *frame, args []value) value {
-	// func os.Pipe() (r *File, w *File, err error)
-
-	// The portable POSIX pipe(2) call is good enough for our needs.
-	var p [2]int
-	if err := syscall.Pipe(p[:]); err != nil {
-		// TODO(adonovan): fix: return an *os.SyscallError.
-		return tuple{nil, nil, wrapError(err)}
-	}
-
-	NewFile := fr.i.prog.ImportedPackage("os").Func("NewFile")
-	r := call(fr.i, fr, 0, NewFile, []value{uintptr(p[0]), "|0"})
-	w := call(fr.i, fr, 0, NewFile, []value{uintptr(p[1]), "|1"})
-	return tuple{r, w, wrapError(nil)}
-}
-
-func fillStat(st *syscall.Stat_t, stat structure) {
-	stat[0] = st.Dev
-	stat[1] = st.Ino
-	stat[2] = st.Nlink
-	stat[3] = st.Mode
-	stat[4] = st.Uid
-	stat[5] = st.Gid
-
-	stat[7] = st.Rdev
-	stat[8] = st.Size
-	stat[9] = st.Blksize
-	stat[10] = st.Blocks
-	// TODO(adonovan): fix: copy Timespecs.
-	// stat[11] = st.Atim
-	// stat[12] = st.Mtim
-	// stat[13] = st.Ctim
-}
-
-func ext۰syscall۰Close(fr *frame, args []value) value {
-	// func Close(fd int) (err error)
-	return wrapError(syscall.Close(args[0].(int)))
-}
-
-func ext۰syscall۰Fstat(fr *frame, args []value) value {
-	// func Fstat(fd int, stat *Stat_t) (err error)
-	fd := args[0].(int)
-	stat := (*args[1].(*value)).(structure)
-
-	var st syscall.Stat_t
-	err := syscall.Fstat(fd, &st)
-	fillStat(&st, stat)
-	return wrapError(err)
-}
-
-func ext۰syscall۰ReadDirent(fr *frame, args []value) value {
-	// func ReadDirent(fd int, buf []byte) (n int, err error)
-	fd := args[0].(int)
-	p := args[1].([]value)
-	b := make([]byte, len(p))
-	n, err := syscall.ReadDirent(fd, b)
-	for i := 0; i < n; i++ {
-		p[i] = b[i]
-	}
-	return tuple{n, wrapError(err)}
-}
-
-func ext۰syscall۰Kill(fr *frame, args []value) value {
-	// func Kill(pid int, sig Signal) (err error)
-	return wrapError(syscall.Kill(args[0].(int), syscall.Signal(args[1].(int))))
-}
-
-func ext۰syscall۰Lstat(fr *frame, args []value) value {
-	// func Lstat(name string, stat *Stat_t) (err error)
-	name := args[0].(string)
-	stat := (*args[1].(*value)).(structure)
-
-	var st syscall.Stat_t
-	err := syscall.Lstat(name, &st)
-	fillStat(&st, stat)
-	return wrapError(err)
-}
-
-func ext۰syscall۰Open(fr *frame, args []value) value {
-	// func Open(path string, mode int, perm uint32) (fd int, err error) {
-	path := args[0].(string)
-	mode := args[1].(int)
-	perm := args[2].(uint32)
-	fd, err := syscall.Open(path, mode, perm)
-	return tuple{fd, wrapError(err)}
-}
-
-func ext۰syscall۰ParseDirent(fr *frame, args []value) value {
-	// func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string)
-	max := args[1].(int)
-	var names []string
-	for _, iname := range args[2].([]value) {
-		names = append(names, iname.(string))
-	}
-	consumed, count, newnames := syscall.ParseDirent(valueToBytes(args[0]), max, names)
-	var inewnames []value
-	for _, newname := range newnames {
-		inewnames = append(inewnames, newname)
-	}
-	return tuple{consumed, count, inewnames}
-}
-
-func ext۰syscall۰Read(fr *frame, args []value) value {
-	// func Read(fd int, p []byte) (n int, err error)
-	fd := args[0].(int)
-	p := args[1].([]value)
-	b := make([]byte, len(p))
-	n, err := syscall.Read(fd, b)
-	for i := 0; i < n; i++ {
-		p[i] = b[i]
-	}
-	return tuple{n, wrapError(err)}
-}
-
-func ext۰syscall۰Stat(fr *frame, args []value) value {
-	// func Stat(name string, stat *Stat_t) (err error)
-	name := args[0].(string)
-	stat := (*args[1].(*value)).(structure)
-
-	var st syscall.Stat_t
-	err := syscall.Stat(name, &st)
-	fillStat(&st, stat)
-	return wrapError(err)
-}
-
-func ext۰syscall۰Write(fr *frame, args []value) value {
-	// func Write(fd int, p []byte) (n int, err error)
-	n, err := write(args[0].(int), valueToBytes(args[1]))
-	return tuple{n, wrapError(err)}
-}
-
-func ext۰syscall۰RawSyscall(fr *frame, args []value) value {
-	return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)}
-}
-
-func syswrite(fd int, b []byte) (int, error) {
-	return syscall.Write(fd, b)
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/external_windows.go b/_linters/src/honnef.co/go/tools/ssa/interp/external_windows.go
deleted file mode 100644
index 24d1a87..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/external_windows.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package interp
-
-import "syscall"
-
-func ext۰os۰Pipe(fr *frame, args []value) value {
-	panic("os.Pipe not yet implemented")
-}
-func ext۰syscall۰Close(fr *frame, args []value) value {
-	panic("syscall.Close not yet implemented")
-}
-func ext۰syscall۰Fstat(fr *frame, args []value) value {
-	panic("syscall.Fstat not yet implemented")
-}
-func ext۰syscall۰Kill(fr *frame, args []value) value {
-	panic("syscall.Kill not yet implemented")
-}
-func ext۰syscall۰Lstat(fr *frame, args []value) value {
-	panic("syscall.Lstat not yet implemented")
-}
-func ext۰syscall۰Open(fr *frame, args []value) value {
-	panic("syscall.Open not yet implemented")
-}
-func ext۰syscall۰ParseDirent(fr *frame, args []value) value {
-	panic("syscall.ParseDirent not yet implemented")
-}
-func ext۰syscall۰Read(fr *frame, args []value) value {
-	panic("syscall.Read not yet implemented")
-}
-func ext۰syscall۰ReadDirent(fr *frame, args []value) value {
-	panic("syscall.ReadDirent not yet implemented")
-}
-func ext۰syscall۰Stat(fr *frame, args []value) value {
-	panic("syscall.Stat not yet implemented")
-}
-func ext۰syscall۰Write(fr *frame, args []value) value {
-	panic("syscall.Write not yet implemented")
-}
-func ext۰syscall۰RawSyscall(fr *frame, args []value) value {
-	return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)}
-}
-func syswrite(fd int, b []byte) (int, error) {
-	panic("syswrite not yet implemented")
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/interp.go b/_linters/src/honnef.co/go/tools/ssa/interp/interp.go
deleted file mode 100644
index 4861d56..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/interp.go
+++ /dev/null
@@ -1,759 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.5
-
-// Package ssa/interp defines an interpreter for the SSA
-// representation of Go programs.
-//
-// This interpreter is provided as an adjunct for testing the SSA
-// construction algorithm.  Its purpose is to provide a minimal
-// metacircular implementation of the dynamic semantics of each SSA
-// instruction.  It is not, and will never be, a production-quality Go
-// interpreter.
-//
-// The following is a partial list of Go features that are currently
-// unsupported or incomplete in the interpreter.
-//
-// * Unsafe operations, including all uses of unsafe.Pointer, are
-// impossible to support given the "boxed" value representation we
-// have chosen.
-//
-// * The reflect package is only partially implemented.
-//
-// * "sync/atomic" operations are not currently atomic due to the
-// "boxed" value representation: it is not possible to read, modify
-// and write an interface value atomically.  As a consequence, Mutexes
-// are currently broken.  TODO(adonovan): provide a metacircular
-// implementation of Mutex avoiding the broken atomic primitives.
-//
-// * recover is only partially implemented.  Also, the interpreter
-// makes no attempt to distinguish target panics from interpreter
-// crashes.
-//
-// * map iteration is asymptotically inefficient.
-//
-// * the sizes of the int, uint and uintptr types in the target
-// program are assumed to be the same as those of the interpreter
-// itself.
-//
-// * all values occupy space, even those of types defined by the spec
-// to have zero size, e.g. struct{}.  This can cause asymptotic
-// performance degradation.
-//
-// * os.Exit is implemented using panic, causing deferred functions to
-// run.
-package interp // import "honnef.co/go/tools/ssa/interp"
-
-import (
-	"fmt"
-	"go/token"
-	"go/types"
-	"os"
-	"reflect"
-	"runtime"
-	"sync/atomic"
-
-	"honnef.co/go/tools/ssa"
-)
-
-type continuation int
-
-const (
-	kNext continuation = iota
-	kReturn
-	kJump
-)
-
-// Mode is a bitmask of options affecting the interpreter.
-type Mode uint
-
-const (
-	DisableRecover Mode = 1 << iota // Disable recover() in target programs; show interpreter crash instead.
-	EnableTracing                   // Print a trace of all instructions as they are interpreted.
-)
-
-type methodSet map[string]*ssa.Function
-
-// State shared between all interpreted goroutines.
-type interpreter struct {
-	osArgs             []value              // the value of os.Args
-	prog               *ssa.Program         // the SSA program
-	globals            map[ssa.Value]*value // addresses of global variables (immutable)
-	mode               Mode                 // interpreter options
-	reflectPackage     *ssa.Package         // the fake reflect package
-	errorMethods       methodSet            // the method set of reflect.error, which implements the error interface.
-	rtypeMethods       methodSet            // the method set of rtype, which implements the reflect.Type interface.
-	runtimeErrorString types.Type           // the runtime.errorString type
-	sizes              types.Sizes          // the effective type-sizing function
-	goroutines         int32                // atomically updated
-}
-
-type deferred struct {
-	fn    value
-	args  []value
-	instr *ssa.Defer
-	tail  *deferred
-}
-
-type frame struct {
-	i                *interpreter
-	caller           *frame
-	fn               *ssa.Function
-	block, prevBlock *ssa.BasicBlock
-	env              map[ssa.Value]value // dynamic values of SSA variables
-	locals           []value
-	defers           *deferred
-	result           value
-	panicking        bool
-	panic            interface{}
-}
-
-func (fr *frame) get(key ssa.Value) value {
-	switch key := key.(type) {
-	case nil:
-		// Hack; simplifies handling of optional attributes
-		// such as ssa.Slice.{Low,High}.
-		return nil
-	case *ssa.Function, *ssa.Builtin:
-		return key
-	case *ssa.Const:
-		return constValue(key)
-	case *ssa.Global:
-		if r, ok := fr.i.globals[key]; ok {
-			return r
-		}
-	}
-	if r, ok := fr.env[key]; ok {
-		return r
-	}
-	panic(fmt.Sprintf("get: no value for %T: %v", key, key.Name()))
-}
-
-// runDefer runs a deferred call d.
-// It always returns normally, but may set or clear fr.panic.
-//
-func (fr *frame) runDefer(d *deferred) {
-	if fr.i.mode&EnableTracing != 0 {
-		fmt.Fprintf(os.Stderr, "%s: invoking deferred function call\n",
-			fr.i.prog.Fset.Position(d.instr.Pos()))
-	}
-	var ok bool
-	defer func() {
-		if !ok {
-			// Deferred call created a new state of panic.
-			fr.panicking = true
-			fr.panic = recover()
-		}
-	}()
-	call(fr.i, fr, d.instr.Pos(), d.fn, d.args)
-	ok = true
-}
-
-// runDefers executes fr's deferred function calls in LIFO order.
-//
-// On entry, fr.panicking indicates a state of panic; if
-// true, fr.panic contains the panic value.
-//
-// On completion, if a deferred call started a panic, or if no
-// deferred call recovered from a previous state of panic, then
-// runDefers itself panics after the last deferred call has run.
-//
-// If there was no initial state of panic, or it was recovered from,
-// runDefers returns normally.
-//
-func (fr *frame) runDefers() {
-	for d := fr.defers; d != nil; d = d.tail {
-		fr.runDefer(d)
-	}
-	fr.defers = nil
-	if fr.panicking {
-		panic(fr.panic) // new panic, or still panicking
-	}
-}
-
-// lookupMethod returns the method set for type typ, which may be one
-// of the interpreter's fake types.
-func lookupMethod(i *interpreter, typ types.Type, meth *types.Func) *ssa.Function {
-	switch typ {
-	case rtypeType:
-		return i.rtypeMethods[meth.Id()]
-	case errorType:
-		return i.errorMethods[meth.Id()]
-	}
-	return i.prog.LookupMethod(typ, meth.Pkg(), meth.Name())
-}
-
-// visitInstr interprets a single ssa.Instruction within the activation
-// record frame.  It returns a continuation value indicating where to
-// read the next instruction from.
-func visitInstr(fr *frame, instr ssa.Instruction) continuation {
-	switch instr := instr.(type) {
-	case *ssa.DebugRef:
-		// no-op
-
-	case *ssa.UnOp:
-		fr.env[instr] = unop(instr, fr.get(instr.X))
-
-	case *ssa.BinOp:
-		fr.env[instr] = binop(instr.Op, instr.X.Type(), fr.get(instr.X), fr.get(instr.Y))
-
-	case *ssa.Call:
-		fn, args := prepareCall(fr, &instr.Call)
-		fr.env[instr] = call(fr.i, fr, instr.Pos(), fn, args)
-
-	case *ssa.ChangeInterface:
-		fr.env[instr] = fr.get(instr.X)
-
-	case *ssa.ChangeType:
-		fr.env[instr] = fr.get(instr.X) // (can't fail)
-
-	case *ssa.Convert:
-		fr.env[instr] = conv(instr.Type(), instr.X.Type(), fr.get(instr.X))
-
-	case *ssa.MakeInterface:
-		fr.env[instr] = iface{t: instr.X.Type(), v: fr.get(instr.X)}
-
-	case *ssa.Extract:
-		fr.env[instr] = fr.get(instr.Tuple).(tuple)[instr.Index]
-
-	case *ssa.Slice:
-		fr.env[instr] = slice(fr.get(instr.X), fr.get(instr.Low), fr.get(instr.High), fr.get(instr.Max))
-
-	case *ssa.Return:
-		switch len(instr.Results) {
-		case 0:
-		case 1:
-			fr.result = fr.get(instr.Results[0])
-		default:
-			var res []value
-			for _, r := range instr.Results {
-				res = append(res, fr.get(r))
-			}
-			fr.result = tuple(res)
-		}
-		fr.block = nil
-		return kReturn
-
-	case *ssa.RunDefers:
-		fr.runDefers()
-
-	case *ssa.Panic:
-		panic(targetPanic{fr.get(instr.X)})
-
-	case *ssa.Send:
-		fr.get(instr.Chan).(chan value) <- fr.get(instr.X)
-
-	case *ssa.Store:
-		store(deref(instr.Addr.Type()), fr.get(instr.Addr).(*value), fr.get(instr.Val))
-
-	case *ssa.If:
-		succ := 1
-		if fr.get(instr.Cond).(bool) {
-			succ = 0
-		}
-		fr.prevBlock, fr.block = fr.block, fr.block.Succs[succ]
-		return kJump
-
-	case *ssa.Jump:
-		fr.prevBlock, fr.block = fr.block, fr.block.Succs[0]
-		return kJump
-
-	case *ssa.Defer:
-		fn, args := prepareCall(fr, &instr.Call)
-		fr.defers = &deferred{
-			fn:    fn,
-			args:  args,
-			instr: instr,
-			tail:  fr.defers,
-		}
-
-	case *ssa.Go:
-		fn, args := prepareCall(fr, &instr.Call)
-		atomic.AddInt32(&fr.i.goroutines, 1)
-		go func() {
-			call(fr.i, nil, instr.Pos(), fn, args)
-			atomic.AddInt32(&fr.i.goroutines, -1)
-		}()
-
-	case *ssa.MakeChan:
-		fr.env[instr] = make(chan value, asInt(fr.get(instr.Size)))
-
-	case *ssa.Alloc:
-		var addr *value
-		if instr.Heap {
-			// new
-			addr = new(value)
-			fr.env[instr] = addr
-		} else {
-			// local
-			addr = fr.env[instr].(*value)
-		}
-		*addr = zero(deref(instr.Type()))
-
-	case *ssa.MakeSlice:
-		slice := make([]value, asInt(fr.get(instr.Cap)))
-		tElt := instr.Type().Underlying().(*types.Slice).Elem()
-		for i := range slice {
-			slice[i] = zero(tElt)
-		}
-		fr.env[instr] = slice[:asInt(fr.get(instr.Len))]
-
-	case *ssa.MakeMap:
-		reserve := 0
-		if instr.Reserve != nil {
-			reserve = asInt(fr.get(instr.Reserve))
-		}
-		fr.env[instr] = makeMap(instr.Type().Underlying().(*types.Map).Key(), reserve)
-
-	case *ssa.Range:
-		fr.env[instr] = rangeIter(fr.get(instr.X), instr.X.Type())
-
-	case *ssa.Next:
-		fr.env[instr] = fr.get(instr.Iter).(iter).next()
-
-	case *ssa.FieldAddr:
-		x := fr.get(instr.X)
-		// FIXME wrong!  &global.f must not change if we do *global = zero!
-		fr.env[instr] = &(*x.(*value)).(structure)[instr.Field]
-
-	case *ssa.Field:
-		fr.env[instr] = fr.get(instr.X).(structure)[instr.Field]
-
-	case *ssa.IndexAddr:
-		x := fr.get(instr.X)
-		idx := fr.get(instr.Index)
-		switch x := x.(type) {
-		case []value:
-			fr.env[instr] = &x[asInt(idx)]
-		case *value: // *array
-			fr.env[instr] = &(*x).(array)[asInt(idx)]
-		default:
-			panic(fmt.Sprintf("unexpected x type in IndexAddr: %T", x))
-		}
-
-	case *ssa.Index:
-		fr.env[instr] = fr.get(instr.X).(array)[asInt(fr.get(instr.Index))]
-
-	case *ssa.Lookup:
-		fr.env[instr] = lookup(instr, fr.get(instr.X), fr.get(instr.Index))
-
-	case *ssa.MapUpdate:
-		m := fr.get(instr.Map)
-		key := fr.get(instr.Key)
-		v := fr.get(instr.Value)
-		switch m := m.(type) {
-		case map[value]value:
-			m[key] = v
-		case *hashmap:
-			m.insert(key.(hashable), v)
-		default:
-			panic(fmt.Sprintf("illegal map type: %T", m))
-		}
-
-	case *ssa.TypeAssert:
-		fr.env[instr] = typeAssert(fr.i, instr, fr.get(instr.X).(iface))
-
-	case *ssa.MakeClosure:
-		var bindings []value
-		for _, binding := range instr.Bindings {
-			bindings = append(bindings, fr.get(binding))
-		}
-		fr.env[instr] = &closure{instr.Fn.(*ssa.Function), bindings}
-
-	case *ssa.Phi:
-		for i, pred := range instr.Block().Preds {
-			if fr.prevBlock == pred {
-				fr.env[instr] = fr.get(instr.Edges[i])
-				break
-			}
-		}
-
-	case *ssa.Select:
-		var cases []reflect.SelectCase
-		if !instr.Blocking {
-			cases = append(cases, reflect.SelectCase{
-				Dir: reflect.SelectDefault,
-			})
-		}
-		for _, state := range instr.States {
-			var dir reflect.SelectDir
-			if state.Dir == types.RecvOnly {
-				dir = reflect.SelectRecv
-			} else {
-				dir = reflect.SelectSend
-			}
-			var send reflect.Value
-			if state.Send != nil {
-				send = reflect.ValueOf(fr.get(state.Send))
-			}
-			cases = append(cases, reflect.SelectCase{
-				Dir:  dir,
-				Chan: reflect.ValueOf(fr.get(state.Chan)),
-				Send: send,
-			})
-		}
-		chosen, recv, recvOk := reflect.Select(cases)
-		if !instr.Blocking {
-			chosen-- // default case should have index -1.
-		}
-		r := tuple{chosen, recvOk}
-		for i, st := range instr.States {
-			if st.Dir == types.RecvOnly {
-				var v value
-				if i == chosen && recvOk {
-					// No need to copy since send makes an unaliased copy.
-					v = recv.Interface().(value)
-				} else {
-					v = zero(st.Chan.Type().Underlying().(*types.Chan).Elem())
-				}
-				r = append(r, v)
-			}
-		}
-		fr.env[instr] = r
-
-	default:
-		panic(fmt.Sprintf("unexpected instruction: %T", instr))
-	}
-
-	// if val, ok := instr.(ssa.Value); ok {
-	// 	fmt.Println(toString(fr.env[val])) // debugging
-	// }
-
-	return kNext
-}
-
-// prepareCall determines the function value and argument values for a
-// function call in a Call, Go or Defer instruction, performing
-// interface method lookup if needed.
-//
-func prepareCall(fr *frame, call *ssa.CallCommon) (fn value, args []value) {
-	v := fr.get(call.Value)
-	if call.Method == nil {
-		// Function call.
-		fn = v
-	} else {
-		// Interface method invocation.
-		recv := v.(iface)
-		if recv.t == nil {
-			panic("method invoked on nil interface")
-		}
-		if f := lookupMethod(fr.i, recv.t, call.Method); f == nil {
-			// Unreachable in well-typed programs.
-			panic(fmt.Sprintf("method set for dynamic type %v does not contain %s", recv.t, call.Method))
-		} else {
-			fn = f
-		}
-		args = append(args, recv.v)
-	}
-	for _, arg := range call.Args {
-		args = append(args, fr.get(arg))
-	}
-	return
-}
-
-// call interprets a call to a function (function, builtin or closure)
-// fn with arguments args, returning its result.
-// callpos is the position of the callsite.
-//
-func call(i *interpreter, caller *frame, callpos token.Pos, fn value, args []value) value {
-	switch fn := fn.(type) {
-	case *ssa.Function:
-		if fn == nil {
-			panic("call of nil function") // nil of func type
-		}
-		return callSSA(i, caller, callpos, fn, args, nil)
-	case *closure:
-		return callSSA(i, caller, callpos, fn.Fn, args, fn.Env)
-	case *ssa.Builtin:
-		return callBuiltin(caller, callpos, fn, args)
-	}
-	panic(fmt.Sprintf("cannot call %T", fn))
-}
-
-func loc(fset *token.FileSet, pos token.Pos) string {
-	if pos == token.NoPos {
-		return ""
-	}
-	return " at " + fset.Position(pos).String()
-}
-
-// callSSA interprets a call to function fn with arguments args,
-// and lexical environment env, returning its result.
-// callpos is the position of the callsite.
-//
-func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function, args []value, env []value) value {
-	if i.mode&EnableTracing != 0 {
-		fset := fn.Prog.Fset
-		// TODO(adonovan): fix: loc() lies for external functions.
-		fmt.Fprintf(os.Stderr, "Entering %s%s.\n", fn, loc(fset, fn.Pos()))
-		suffix := ""
-		if caller != nil {
-			suffix = ", resuming " + caller.fn.String() + loc(fset, callpos)
-		}
-		defer fmt.Fprintf(os.Stderr, "Leaving %s%s.\n", fn, suffix)
-	}
-	fr := &frame{
-		i:      i,
-		caller: caller, // for panic/recover
-		fn:     fn,
-	}
-	if fn.Parent() == nil {
-		name := fn.String()
-		if ext := externals[name]; ext != nil {
-			if i.mode&EnableTracing != 0 {
-				fmt.Fprintln(os.Stderr, "\t(external)")
-			}
-			return ext(fr, args)
-		}
-		if fn.Blocks == nil {
-			panic("no code for function: " + name)
-		}
-	}
-	fr.env = make(map[ssa.Value]value)
-	fr.block = fn.Blocks[0]
-	fr.locals = make([]value, len(fn.Locals))
-	for i, l := range fn.Locals {
-		fr.locals[i] = zero(deref(l.Type()))
-		fr.env[l] = &fr.locals[i]
-	}
-	for i, p := range fn.Params {
-		fr.env[p] = args[i]
-	}
-	for i, fv := range fn.FreeVars {
-		fr.env[fv] = env[i]
-	}
-	for fr.block != nil {
-		runFrame(fr)
-	}
-	// Destroy the locals to avoid accidental use after return.
-	for i := range fn.Locals {
-		fr.locals[i] = bad{}
-	}
-	return fr.result
-}
-
-// runFrame executes SSA instructions starting at fr.block and
-// continuing until a return, a panic, or a recovered panic.
-//
-// After a panic, runFrame panics.
-//
-// After a normal return, fr.result contains the result of the call
-// and fr.block is nil.
-//
-// A recovered panic in a function without named return parameters
-// (NRPs) becomes a normal return of the zero value of the function's
-// result type.
-//
-// After a recovered panic in a function with NRPs, fr.result is
-// undefined and fr.block contains the block at which to resume
-// control.
-//
-func runFrame(fr *frame) {
-	defer func() {
-		if fr.block == nil {
-			return // normal return
-		}
-		if fr.i.mode&DisableRecover != 0 {
-			return // let interpreter crash
-		}
-		fr.panicking = true
-		fr.panic = recover()
-		if fr.i.mode&EnableTracing != 0 {
-			fmt.Fprintf(os.Stderr, "Panicking: %T %v.\n", fr.panic, fr.panic)
-		}
-		fr.runDefers()
-		fr.block = fr.fn.Recover
-	}()
-
-	for {
-		if fr.i.mode&EnableTracing != 0 {
-			fmt.Fprintf(os.Stderr, ".%s:\n", fr.block)
-		}
-	block:
-		for _, instr := range fr.block.Instrs {
-			if fr.i.mode&EnableTracing != 0 {
-				if v, ok := instr.(ssa.Value); ok {
-					fmt.Fprintln(os.Stderr, "\t", v.Name(), "=", instr)
-				} else {
-					fmt.Fprintln(os.Stderr, "\t", instr)
-				}
-			}
-			switch visitInstr(fr, instr) {
-			case kReturn:
-				return
-			case kNext:
-				// no-op
-			case kJump:
-				break block
-			}
-		}
-	}
-}
-
-// doRecover implements the recover() built-in.
-func doRecover(caller *frame) value {
-	// recover() must be exactly one level beneath the deferred
-	// function (two levels beneath the panicking function) to
-	// have any effect.  Thus we ignore both "defer recover()" and
-	// "defer f() -> g() -> recover()".
-	if caller.i.mode&DisableRecover == 0 &&
-		caller != nil && !caller.panicking &&
-		caller.caller != nil && caller.caller.panicking {
-		caller.caller.panicking = false
-		p := caller.caller.panic
-		caller.caller.panic = nil
-		switch p := p.(type) {
-		case targetPanic:
-			// The target program explicitly called panic().
-			return p.v
-		case runtime.Error:
-			// The interpreter encountered a runtime error.
-			return iface{caller.i.runtimeErrorString, p.Error()}
-		case string:
-			// The interpreter explicitly called panic().
-			return iface{caller.i.runtimeErrorString, p}
-		default:
-			panic(fmt.Sprintf("unexpected panic type %T in target call to recover()", p))
-		}
-	}
-	return iface{}
-}
-
-// setGlobal sets the value of a system-initialized global variable.
-func setGlobal(i *interpreter, pkg *ssa.Package, name string, v value) {
-	if g, ok := i.globals[pkg.Var(name)]; ok {
-		*g = v
-		return
-	}
-	panic("no global variable: " + pkg.Pkg.Path() + "." + name)
-}
-
-var environ []value
-
-func init() {
-	for _, s := range os.Environ() {
-		environ = append(environ, s)
-	}
-	environ = append(environ, "GOSSAINTERP=1")
-	environ = append(environ, "GOARCH="+runtime.GOARCH)
-}
-
-// deleteBodies delete the bodies of all standalone functions except the
-// specified ones.  A missing intrinsic leads to a clear runtime error.
-func deleteBodies(pkg *ssa.Package, except ...string) {
-	keep := make(map[string]bool)
-	for _, e := range except {
-		keep[e] = true
-	}
-	for _, mem := range pkg.Members {
-		if fn, ok := mem.(*ssa.Function); ok && !keep[fn.Name()] {
-			fn.Blocks = nil
-		}
-	}
-}
-
-// Interpret interprets the Go program whose main package is mainpkg.
-// mode specifies various interpreter options.  filename and args are
-// the initial values of os.Args for the target program.  sizes is the
-// effective type-sizing function for this program.
-//
-// Interpret returns the exit code of the program: 2 for panic (like
-// gc does), or the argument to os.Exit for normal termination.
-//
-// The SSA program must include the "runtime" package.
-//
-func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) {
-	i := &interpreter{
-		prog:       mainpkg.Prog,
-		globals:    make(map[ssa.Value]*value),
-		mode:       mode,
-		sizes:      sizes,
-		goroutines: 1,
-	}
-	runtimePkg := i.prog.ImportedPackage("runtime")
-	if runtimePkg == nil {
-		panic("ssa.Program doesn't include runtime package")
-	}
-	i.runtimeErrorString = runtimePkg.Type("errorString").Object().Type()
-
-	initReflect(i)
-
-	i.osArgs = append(i.osArgs, filename)
-	for _, arg := range args {
-		i.osArgs = append(i.osArgs, arg)
-	}
-
-	for _, pkg := range i.prog.AllPackages() {
-		// Initialize global storage.
-		for _, m := range pkg.Members {
-			switch v := m.(type) {
-			case *ssa.Global:
-				cell := zero(deref(v.Type()))
-				i.globals[v] = &cell
-			}
-		}
-
-		// Ad-hoc initialization for magic system variables.
-		switch pkg.Pkg.Path() {
-		case "syscall":
-			setGlobal(i, pkg, "envs", environ)
-
-		case "reflect":
-			deleteBodies(pkg, "DeepEqual", "deepValueEqual")
-
-		case "runtime":
-			sz := sizes.Sizeof(pkg.Pkg.Scope().Lookup("MemStats").Type())
-			setGlobal(i, pkg, "sizeof_C_MStats", uintptr(sz))
-			deleteBodies(pkg, "GOROOT", "gogetenv")
-		}
-	}
-
-	// Top-level error handler.
-	exitCode = 2
-	defer func() {
-		if exitCode != 2 || i.mode&DisableRecover != 0 {
-			return
-		}
-		switch p := recover().(type) {
-		case exitPanic:
-			exitCode = int(p)
-			return
-		case targetPanic:
-			fmt.Fprintln(os.Stderr, "panic:", toString(p.v))
-		case runtime.Error:
-			fmt.Fprintln(os.Stderr, "panic:", p.Error())
-		case string:
-			fmt.Fprintln(os.Stderr, "panic:", p)
-		default:
-			fmt.Fprintf(os.Stderr, "panic: unexpected type: %T: %v\n", p, p)
-		}
-
-		// TODO(adonovan): dump panicking interpreter goroutine?
-		// buf := make([]byte, 0x10000)
-		// runtime.Stack(buf, false)
-		// fmt.Fprintln(os.Stderr, string(buf))
-		// (Or dump panicking target goroutine?)
-	}()
-
-	// Run!
-	call(i, nil, token.NoPos, mainpkg.Func("init"), nil)
-	if mainFn := mainpkg.Func("main"); mainFn != nil {
-		call(i, nil, token.NoPos, mainFn, nil)
-		exitCode = 0
-	} else {
-		fmt.Fprintln(os.Stderr, "No main function.")
-		exitCode = 1
-	}
-	return
-}
-
-// deref returns a pointer's element type; otherwise it returns typ.
-// TODO(adonovan): Import from ssa?
-func deref(typ types.Type) types.Type {
-	if p, ok := typ.Underlying().(*types.Pointer); ok {
-		return p.Elem()
-	}
-	return typ
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/map.go b/_linters/src/honnef.co/go/tools/ssa/interp/map.go
deleted file mode 100644
index 577526f..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/map.go
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.5
-
-package interp
-
-// Custom hashtable atop map.
-// For use when the key's equivalence relation is not consistent with ==.
-
-// The Go specification doesn't address the atomicity of map operations.
-// The FAQ states that an implementation is permitted to crash on
-// concurrent map access.
-
-import (
-	"go/types"
-)
-
-type hashable interface {
-	hash(t types.Type) int
-	eq(t types.Type, x interface{}) bool
-}
-
-type entry struct {
-	key   hashable
-	value value
-	next  *entry
-}
-
-// A hashtable atop the built-in map.  Since each bucket contains
-// exactly one hash value, there's no need to perform hash-equality
-// tests when walking the linked list.  Rehashing is done by the
-// underlying map.
-type hashmap struct {
-	keyType types.Type
-	table   map[int]*entry
-	length  int // number of entries in map
-}
-
-// makeMap returns an empty initialized map of key type kt,
-// preallocating space for reserve elements.
-func makeMap(kt types.Type, reserve int) value {
-	if usesBuiltinMap(kt) {
-		return make(map[value]value, reserve)
-	}
-	return &hashmap{keyType: kt, table: make(map[int]*entry, reserve)}
-}
-
-// delete removes the association for key k, if any.
-func (m *hashmap) delete(k hashable) {
-	if m != nil {
-		hash := k.hash(m.keyType)
-		head := m.table[hash]
-		if head != nil {
-			if k.eq(m.keyType, head.key) {
-				m.table[hash] = head.next
-				m.length--
-				return
-			}
-			prev := head
-			for e := head.next; e != nil; e = e.next {
-				if k.eq(m.keyType, e.key) {
-					prev.next = e.next
-					m.length--
-					return
-				}
-				prev = e
-			}
-		}
-	}
-}
-
-// lookup returns the value associated with key k, if present, or
-// value(nil) otherwise.
-func (m *hashmap) lookup(k hashable) value {
-	if m != nil {
-		hash := k.hash(m.keyType)
-		for e := m.table[hash]; e != nil; e = e.next {
-			if k.eq(m.keyType, e.key) {
-				return e.value
-			}
-		}
-	}
-	return nil
-}
-
-// insert updates the map to associate key k with value v.  If there
-// was already an association for an eq() (though not necessarily ==)
-// k, the previous key remains in the map and its associated value is
-// updated.
-func (m *hashmap) insert(k hashable, v value) {
-	hash := k.hash(m.keyType)
-	head := m.table[hash]
-	for e := head; e != nil; e = e.next {
-		if k.eq(m.keyType, e.key) {
-			e.value = v
-			return
-		}
-	}
-	m.table[hash] = &entry{
-		key:   k,
-		value: v,
-		next:  head,
-	}
-	m.length++
-}
-
-// len returns the number of key/value associations in the map.
-func (m *hashmap) len() int {
-	if m != nil {
-		return m.length
-	}
-	return 0
-}
-
-// entries returns a rangeable map of entries.
-func (m *hashmap) entries() map[int]*entry {
-	if m != nil {
-		return m.table
-	}
-	return nil
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/ops.go b/_linters/src/honnef.co/go/tools/ssa/interp/ops.go
deleted file mode 100644
index e6e0e19..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/ops.go
+++ /dev/null
@@ -1,1396 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.5
-
-package interp
-
-import (
-	"bytes"
-	"fmt"
-	exact "go/constant"
-	"go/token"
-	"go/types"
-	"strings"
-	"sync"
-	"unsafe"
-
-	"honnef.co/go/tools/ssa"
-)
-
-// If the target program panics, the interpreter panics with this type.
-type targetPanic struct {
-	v value
-}
-
-func (p targetPanic) String() string {
-	return toString(p.v)
-}
-
-// If the target program calls exit, the interpreter panics with this type.
-type exitPanic int
-
-// constValue returns the value of the constant with the
-// dynamic type tag appropriate for c.Type().
-func constValue(c *ssa.Const) value {
-	if c.IsNil() {
-		return zero(c.Type()) // typed nil
-	}
-
-	if t, ok := c.Type().Underlying().(*types.Basic); ok {
-		// TODO(adonovan): eliminate untyped constants from SSA form.
-		switch t.Kind() {
-		case types.Bool, types.UntypedBool:
-			return exact.BoolVal(c.Value)
-		case types.Int, types.UntypedInt:
-			// Assume sizeof(int) is same on host and target.
-			return int(c.Int64())
-		case types.Int8:
-			return int8(c.Int64())
-		case types.Int16:
-			return int16(c.Int64())
-		case types.Int32, types.UntypedRune:
-			return int32(c.Int64())
-		case types.Int64:
-			return c.Int64()
-		case types.Uint:
-			// Assume sizeof(uint) is same on host and target.
-			return uint(c.Uint64())
-		case types.Uint8:
-			return uint8(c.Uint64())
-		case types.Uint16:
-			return uint16(c.Uint64())
-		case types.Uint32:
-			return uint32(c.Uint64())
-		case types.Uint64:
-			return c.Uint64()
-		case types.Uintptr:
-			// Assume sizeof(uintptr) is same on host and target.
-			return uintptr(c.Uint64())
-		case types.Float32:
-			return float32(c.Float64())
-		case types.Float64, types.UntypedFloat:
-			return c.Float64()
-		case types.Complex64:
-			return complex64(c.Complex128())
-		case types.Complex128, types.UntypedComplex:
-			return c.Complex128()
-		case types.String, types.UntypedString:
-			if c.Value.Kind() == exact.String {
-				return exact.StringVal(c.Value)
-			}
-			return string(rune(c.Int64()))
-		}
-	}
-
-	panic(fmt.Sprintf("constValue: %s", c))
-}
-
-// asInt converts x, which must be an integer, to an int suitable for
-// use as a slice or array index or operand to make().
-func asInt(x value) int {
-	switch x := x.(type) {
-	case int:
-		return x
-	case int8:
-		return int(x)
-	case int16:
-		return int(x)
-	case int32:
-		return int(x)
-	case int64:
-		return int(x)
-	case uint:
-		return int(x)
-	case uint8:
-		return int(x)
-	case uint16:
-		return int(x)
-	case uint32:
-		return int(x)
-	case uint64:
-		return int(x)
-	case uintptr:
-		return int(x)
-	}
-	panic(fmt.Sprintf("cannot convert %T to int", x))
-}
-
-// asUint64 converts x, which must be an unsigned integer, to a uint64
-// suitable for use as a bitwise shift count.
-func asUint64(x value) uint64 {
-	switch x := x.(type) {
-	case uint:
-		return uint64(x)
-	case uint8:
-		return uint64(x)
-	case uint16:
-		return uint64(x)
-	case uint32:
-		return uint64(x)
-	case uint64:
-		return x
-	case uintptr:
-		return uint64(x)
-	}
-	panic(fmt.Sprintf("cannot convert %T to uint64", x))
-}
-
-// zero returns a new "zero" value of the specified type.
-func zero(t types.Type) value {
-	switch t := t.(type) {
-	case *types.Basic:
-		if t.Kind() == types.UntypedNil {
-			panic("untyped nil has no zero value")
-		}
-		if t.Info()&types.IsUntyped != 0 {
-			// TODO(adonovan): make it an invariant that
-			// this is unreachable.  Currently some
-			// constants have 'untyped' types when they
-			// should be defaulted by the typechecker.
-			t = ssa.DefaultType(t).(*types.Basic)
-		}
-		switch t.Kind() {
-		case types.Bool:
-			return false
-		case types.Int:
-			return int(0)
-		case types.Int8:
-			return int8(0)
-		case types.Int16:
-			return int16(0)
-		case types.Int32:
-			return int32(0)
-		case types.Int64:
-			return int64(0)
-		case types.Uint:
-			return uint(0)
-		case types.Uint8:
-			return uint8(0)
-		case types.Uint16:
-			return uint16(0)
-		case types.Uint32:
-			return uint32(0)
-		case types.Uint64:
-			return uint64(0)
-		case types.Uintptr:
-			return uintptr(0)
-		case types.Float32:
-			return float32(0)
-		case types.Float64:
-			return float64(0)
-		case types.Complex64:
-			return complex64(0)
-		case types.Complex128:
-			return complex128(0)
-		case types.String:
-			return ""
-		case types.UnsafePointer:
-			return unsafe.Pointer(nil)
-		default:
-			panic(fmt.Sprint("zero for unexpected type:", t))
-		}
-	case *types.Pointer:
-		return (*value)(nil)
-	case *types.Array:
-		a := make(array, t.Len())
-		for i := range a {
-			a[i] = zero(t.Elem())
-		}
-		return a
-	case *types.Named:
-		return zero(t.Underlying())
-	case *types.Interface:
-		return iface{} // nil type, methodset and value
-	case *types.Slice:
-		return []value(nil)
-	case *types.Struct:
-		s := make(structure, t.NumFields())
-		for i := range s {
-			s[i] = zero(t.Field(i).Type())
-		}
-		return s
-	case *types.Tuple:
-		if t.Len() == 1 {
-			return zero(t.At(0).Type())
-		}
-		s := make(tuple, t.Len())
-		for i := range s {
-			s[i] = zero(t.At(i).Type())
-		}
-		return s
-	case *types.Chan:
-		return chan value(nil)
-	case *types.Map:
-		if usesBuiltinMap(t.Key()) {
-			return map[value]value(nil)
-		}
-		return (*hashmap)(nil)
-	case *types.Signature:
-		return (*ssa.Function)(nil)
-	}
-	panic(fmt.Sprint("zero: unexpected ", t))
-}
-
-// slice returns x[lo:hi:max].  Any of lo, hi and max may be nil.
-func slice(x, lo, hi, max value) value {
-	var Len, Cap int
-	switch x := x.(type) {
-	case string:
-		Len = len(x)
-	case []value:
-		Len = len(x)
-		Cap = cap(x)
-	case *value: // *array
-		a := (*x).(array)
-		Len = len(a)
-		Cap = cap(a)
-	}
-
-	l := 0
-	if lo != nil {
-		l = asInt(lo)
-	}
-
-	h := Len
-	if hi != nil {
-		h = asInt(hi)
-	}
-
-	m := Cap
-	if max != nil {
-		m = asInt(max)
-	}
-
-	switch x := x.(type) {
-	case string:
-		return x[l:h]
-	case []value:
-		return x[l:h:m]
-	case *value: // *array
-		a := (*x).(array)
-		return []value(a)[l:h:m]
-	}
-	panic(fmt.Sprintf("slice: unexpected X type: %T", x))
-}
-
-// lookup returns x[idx] where x is a map or string.
-func lookup(instr *ssa.Lookup, x, idx value) value {
-	switch x := x.(type) { // map or string
-	case map[value]value, *hashmap:
-		var v value
-		var ok bool
-		switch x := x.(type) {
-		case map[value]value:
-			v, ok = x[idx]
-		case *hashmap:
-			v = x.lookup(idx.(hashable))
-			ok = v != nil
-		}
-		if !ok {
-			v = zero(instr.X.Type().Underlying().(*types.Map).Elem())
-		}
-		if instr.CommaOk {
-			v = tuple{v, ok}
-		}
-		return v
-	case string:
-		return x[asInt(idx)]
-	}
-	panic(fmt.Sprintf("unexpected x type in Lookup: %T", x))
-}
-
-// binop implements all arithmetic and logical binary operators for
-// numeric datatypes and strings.  Both operands must have identical
-// dynamic type.
-//
-func binop(op token.Token, t types.Type, x, y value) value {
-	switch op {
-	case token.ADD:
-		switch x.(type) {
-		case int:
-			return x.(int) + y.(int)
-		case int8:
-			return x.(int8) + y.(int8)
-		case int16:
-			return x.(int16) + y.(int16)
-		case int32:
-			return x.(int32) + y.(int32)
-		case int64:
-			return x.(int64) + y.(int64)
-		case uint:
-			return x.(uint) + y.(uint)
-		case uint8:
-			return x.(uint8) + y.(uint8)
-		case uint16:
-			return x.(uint16) + y.(uint16)
-		case uint32:
-			return x.(uint32) + y.(uint32)
-		case uint64:
-			return x.(uint64) + y.(uint64)
-		case uintptr:
-			return x.(uintptr) + y.(uintptr)
-		case float32:
-			return x.(float32) + y.(float32)
-		case float64:
-			return x.(float64) + y.(float64)
-		case complex64:
-			return x.(complex64) + y.(complex64)
-		case complex128:
-			return x.(complex128) + y.(complex128)
-		case string:
-			return x.(string) + y.(string)
-		}
-
-	case token.SUB:
-		switch x.(type) {
-		case int:
-			return x.(int) - y.(int)
-		case int8:
-			return x.(int8) - y.(int8)
-		case int16:
-			return x.(int16) - y.(int16)
-		case int32:
-			return x.(int32) - y.(int32)
-		case int64:
-			return x.(int64) - y.(int64)
-		case uint:
-			return x.(uint) - y.(uint)
-		case uint8:
-			return x.(uint8) - y.(uint8)
-		case uint16:
-			return x.(uint16) - y.(uint16)
-		case uint32:
-			return x.(uint32) - y.(uint32)
-		case uint64:
-			return x.(uint64) - y.(uint64)
-		case uintptr:
-			return x.(uintptr) - y.(uintptr)
-		case float32:
-			return x.(float32) - y.(float32)
-		case float64:
-			return x.(float64) - y.(float64)
-		case complex64:
-			return x.(complex64) - y.(complex64)
-		case complex128:
-			return x.(complex128) - y.(complex128)
-		}
-
-	case token.MUL:
-		switch x.(type) {
-		case int:
-			return x.(int) * y.(int)
-		case int8:
-			return x.(int8) * y.(int8)
-		case int16:
-			return x.(int16) * y.(int16)
-		case int32:
-			return x.(int32) * y.(int32)
-		case int64:
-			return x.(int64) * y.(int64)
-		case uint:
-			return x.(uint) * y.(uint)
-		case uint8:
-			return x.(uint8) * y.(uint8)
-		case uint16:
-			return x.(uint16) * y.(uint16)
-		case uint32:
-			return x.(uint32) * y.(uint32)
-		case uint64:
-			return x.(uint64) * y.(uint64)
-		case uintptr:
-			return x.(uintptr) * y.(uintptr)
-		case float32:
-			return x.(float32) * y.(float32)
-		case float64:
-			return x.(float64) * y.(float64)
-		case complex64:
-			return x.(complex64) * y.(complex64)
-		case complex128:
-			return x.(complex128) * y.(complex128)
-		}
-
-	case token.QUO:
-		switch x.(type) {
-		case int:
-			return x.(int) / y.(int)
-		case int8:
-			return x.(int8) / y.(int8)
-		case int16:
-			return x.(int16) / y.(int16)
-		case int32:
-			return x.(int32) / y.(int32)
-		case int64:
-			return x.(int64) / y.(int64)
-		case uint:
-			return x.(uint) / y.(uint)
-		case uint8:
-			return x.(uint8) / y.(uint8)
-		case uint16:
-			return x.(uint16) / y.(uint16)
-		case uint32:
-			return x.(uint32) / y.(uint32)
-		case uint64:
-			return x.(uint64) / y.(uint64)
-		case uintptr:
-			return x.(uintptr) / y.(uintptr)
-		case float32:
-			return x.(float32) / y.(float32)
-		case float64:
-			return x.(float64) / y.(float64)
-		case complex64:
-			return x.(complex64) / y.(complex64)
-		case complex128:
-			return x.(complex128) / y.(complex128)
-		}
-
-	case token.REM:
-		switch x.(type) {
-		case int:
-			return x.(int) % y.(int)
-		case int8:
-			return x.(int8) % y.(int8)
-		case int16:
-			return x.(int16) % y.(int16)
-		case int32:
-			return x.(int32) % y.(int32)
-		case int64:
-			return x.(int64) % y.(int64)
-		case uint:
-			return x.(uint) % y.(uint)
-		case uint8:
-			return x.(uint8) % y.(uint8)
-		case uint16:
-			return x.(uint16) % y.(uint16)
-		case uint32:
-			return x.(uint32) % y.(uint32)
-		case uint64:
-			return x.(uint64) % y.(uint64)
-		case uintptr:
-			return x.(uintptr) % y.(uintptr)
-		}
-
-	case token.AND:
-		switch x.(type) {
-		case int:
-			return x.(int) & y.(int)
-		case int8:
-			return x.(int8) & y.(int8)
-		case int16:
-			return x.(int16) & y.(int16)
-		case int32:
-			return x.(int32) & y.(int32)
-		case int64:
-			return x.(int64) & y.(int64)
-		case uint:
-			return x.(uint) & y.(uint)
-		case uint8:
-			return x.(uint8) & y.(uint8)
-		case uint16:
-			return x.(uint16) & y.(uint16)
-		case uint32:
-			return x.(uint32) & y.(uint32)
-		case uint64:
-			return x.(uint64) & y.(uint64)
-		case uintptr:
-			return x.(uintptr) & y.(uintptr)
-		}
-
-	case token.OR:
-		switch x.(type) {
-		case int:
-			return x.(int) | y.(int)
-		case int8:
-			return x.(int8) | y.(int8)
-		case int16:
-			return x.(int16) | y.(int16)
-		case int32:
-			return x.(int32) | y.(int32)
-		case int64:
-			return x.(int64) | y.(int64)
-		case uint:
-			return x.(uint) | y.(uint)
-		case uint8:
-			return x.(uint8) | y.(uint8)
-		case uint16:
-			return x.(uint16) | y.(uint16)
-		case uint32:
-			return x.(uint32) | y.(uint32)
-		case uint64:
-			return x.(uint64) | y.(uint64)
-		case uintptr:
-			return x.(uintptr) | y.(uintptr)
-		}
-
-	case token.XOR:
-		switch x.(type) {
-		case int:
-			return x.(int) ^ y.(int)
-		case int8:
-			return x.(int8) ^ y.(int8)
-		case int16:
-			return x.(int16) ^ y.(int16)
-		case int32:
-			return x.(int32) ^ y.(int32)
-		case int64:
-			return x.(int64) ^ y.(int64)
-		case uint:
-			return x.(uint) ^ y.(uint)
-		case uint8:
-			return x.(uint8) ^ y.(uint8)
-		case uint16:
-			return x.(uint16) ^ y.(uint16)
-		case uint32:
-			return x.(uint32) ^ y.(uint32)
-		case uint64:
-			return x.(uint64) ^ y.(uint64)
-		case uintptr:
-			return x.(uintptr) ^ y.(uintptr)
-		}
-
-	case token.AND_NOT:
-		switch x.(type) {
-		case int:
-			return x.(int) &^ y.(int)
-		case int8:
-			return x.(int8) &^ y.(int8)
-		case int16:
-			return x.(int16) &^ y.(int16)
-		case int32:
-			return x.(int32) &^ y.(int32)
-		case int64:
-			return x.(int64) &^ y.(int64)
-		case uint:
-			return x.(uint) &^ y.(uint)
-		case uint8:
-			return x.(uint8) &^ y.(uint8)
-		case uint16:
-			return x.(uint16) &^ y.(uint16)
-		case uint32:
-			return x.(uint32) &^ y.(uint32)
-		case uint64:
-			return x.(uint64) &^ y.(uint64)
-		case uintptr:
-			return x.(uintptr) &^ y.(uintptr)
-		}
-
-	case token.SHL:
-		y := asUint64(y)
-		switch x.(type) {
-		case int:
-			return x.(int) << y
-		case int8:
-			return x.(int8) << y
-		case int16:
-			return x.(int16) << y
-		case int32:
-			return x.(int32) << y
-		case int64:
-			return x.(int64) << y
-		case uint:
-			return x.(uint) << y
-		case uint8:
-			return x.(uint8) << y
-		case uint16:
-			return x.(uint16) << y
-		case uint32:
-			return x.(uint32) << y
-		case uint64:
-			return x.(uint64) << y
-		case uintptr:
-			return x.(uintptr) << y
-		}
-
-	case token.SHR:
-		y := asUint64(y)
-		switch x.(type) {
-		case int:
-			return x.(int) >> y
-		case int8:
-			return x.(int8) >> y
-		case int16:
-			return x.(int16) >> y
-		case int32:
-			return x.(int32) >> y
-		case int64:
-			return x.(int64) >> y
-		case uint:
-			return x.(uint) >> y
-		case uint8:
-			return x.(uint8) >> y
-		case uint16:
-			return x.(uint16) >> y
-		case uint32:
-			return x.(uint32) >> y
-		case uint64:
-			return x.(uint64) >> y
-		case uintptr:
-			return x.(uintptr) >> y
-		}
-
-	case token.LSS:
-		switch x.(type) {
-		case int:
-			return x.(int) < y.(int)
-		case int8:
-			return x.(int8) < y.(int8)
-		case int16:
-			return x.(int16) < y.(int16)
-		case int32:
-			return x.(int32) < y.(int32)
-		case int64:
-			return x.(int64) < y.(int64)
-		case uint:
-			return x.(uint) < y.(uint)
-		case uint8:
-			return x.(uint8) < y.(uint8)
-		case uint16:
-			return x.(uint16) < y.(uint16)
-		case uint32:
-			return x.(uint32) < y.(uint32)
-		case uint64:
-			return x.(uint64) < y.(uint64)
-		case uintptr:
-			return x.(uintptr) < y.(uintptr)
-		case float32:
-			return x.(float32) < y.(float32)
-		case float64:
-			return x.(float64) < y.(float64)
-		case string:
-			return x.(string) < y.(string)
-		}
-
-	case token.LEQ:
-		switch x.(type) {
-		case int:
-			return x.(int) <= y.(int)
-		case int8:
-			return x.(int8) <= y.(int8)
-		case int16:
-			return x.(int16) <= y.(int16)
-		case int32:
-			return x.(int32) <= y.(int32)
-		case int64:
-			return x.(int64) <= y.(int64)
-		case uint:
-			return x.(uint) <= y.(uint)
-		case uint8:
-			return x.(uint8) <= y.(uint8)
-		case uint16:
-			return x.(uint16) <= y.(uint16)
-		case uint32:
-			return x.(uint32) <= y.(uint32)
-		case uint64:
-			return x.(uint64) <= y.(uint64)
-		case uintptr:
-			return x.(uintptr) <= y.(uintptr)
-		case float32:
-			return x.(float32) <= y.(float32)
-		case float64:
-			return x.(float64) <= y.(float64)
-		case string:
-			return x.(string) <= y.(string)
-		}
-
-	case token.EQL:
-		return eqnil(t, x, y)
-
-	case token.NEQ:
-		return !eqnil(t, x, y)
-
-	case token.GTR:
-		switch x.(type) {
-		case int:
-			return x.(int) > y.(int)
-		case int8:
-			return x.(int8) > y.(int8)
-		case int16:
-			return x.(int16) > y.(int16)
-		case int32:
-			return x.(int32) > y.(int32)
-		case int64:
-			return x.(int64) > y.(int64)
-		case uint:
-			return x.(uint) > y.(uint)
-		case uint8:
-			return x.(uint8) > y.(uint8)
-		case uint16:
-			return x.(uint16) > y.(uint16)
-		case uint32:
-			return x.(uint32) > y.(uint32)
-		case uint64:
-			return x.(uint64) > y.(uint64)
-		case uintptr:
-			return x.(uintptr) > y.(uintptr)
-		case float32:
-			return x.(float32) > y.(float32)
-		case float64:
-			return x.(float64) > y.(float64)
-		case string:
-			return x.(string) > y.(string)
-		}
-
-	case token.GEQ:
-		switch x.(type) {
-		case int:
-			return x.(int) >= y.(int)
-		case int8:
-			return x.(int8) >= y.(int8)
-		case int16:
-			return x.(int16) >= y.(int16)
-		case int32:
-			return x.(int32) >= y.(int32)
-		case int64:
-			return x.(int64) >= y.(int64)
-		case uint:
-			return x.(uint) >= y.(uint)
-		case uint8:
-			return x.(uint8) >= y.(uint8)
-		case uint16:
-			return x.(uint16) >= y.(uint16)
-		case uint32:
-			return x.(uint32) >= y.(uint32)
-		case uint64:
-			return x.(uint64) >= y.(uint64)
-		case uintptr:
-			return x.(uintptr) >= y.(uintptr)
-		case float32:
-			return x.(float32) >= y.(float32)
-		case float64:
-			return x.(float64) >= y.(float64)
-		case string:
-			return x.(string) >= y.(string)
-		}
-	}
-	panic(fmt.Sprintf("invalid binary op: %T %s %T", x, op, y))
-}
-
-// eqnil returns the comparison x == y using the equivalence relation
-// appropriate for type t.
-// If t is a reference type, at most one of x or y may be a nil value
-// of that type.
-//
-func eqnil(t types.Type, x, y value) bool {
-	switch t.Underlying().(type) {
-	case *types.Map, *types.Signature, *types.Slice:
-		// Since these types don't support comparison,
-		// one of the operands must be a literal nil.
-		switch x := x.(type) {
-		case *hashmap:
-			return (x != nil) == (y.(*hashmap) != nil)
-		case map[value]value:
-			return (x != nil) == (y.(map[value]value) != nil)
-		case *ssa.Function:
-			switch y := y.(type) {
-			case *ssa.Function:
-				return (x != nil) == (y != nil)
-			case *closure:
-				return true
-			}
-		case *closure:
-			return (x != nil) == (y.(*ssa.Function) != nil)
-		case []value:
-			return (x != nil) == (y.([]value) != nil)
-		}
-		panic(fmt.Sprintf("eqnil(%s): illegal dynamic type: %T", t, x))
-	}
-
-	return equals(t, x, y)
-}
-
-func unop(instr *ssa.UnOp, x value) value {
-	switch instr.Op {
-	case token.ARROW: // receive
-		v, ok := <-x.(chan value)
-		if !ok {
-			v = zero(instr.X.Type().Underlying().(*types.Chan).Elem())
-		}
-		if instr.CommaOk {
-			v = tuple{v, ok}
-		}
-		return v
-	case token.SUB:
-		switch x := x.(type) {
-		case int:
-			return -x
-		case int8:
-			return -x
-		case int16:
-			return -x
-		case int32:
-			return -x
-		case int64:
-			return -x
-		case uint:
-			return -x
-		case uint8:
-			return -x
-		case uint16:
-			return -x
-		case uint32:
-			return -x
-		case uint64:
-			return -x
-		case uintptr:
-			return -x
-		case float32:
-			return -x
-		case float64:
-			return -x
-		case complex64:
-			return -x
-		case complex128:
-			return -x
-		}
-	case token.MUL:
-		return load(deref(instr.X.Type()), x.(*value))
-	case token.NOT:
-		return !x.(bool)
-	case token.XOR:
-		switch x := x.(type) {
-		case int:
-			return ^x
-		case int8:
-			return ^x
-		case int16:
-			return ^x
-		case int32:
-			return ^x
-		case int64:
-			return ^x
-		case uint:
-			return ^x
-		case uint8:
-			return ^x
-		case uint16:
-			return ^x
-		case uint32:
-			return ^x
-		case uint64:
-			return ^x
-		case uintptr:
-			return ^x
-		}
-	}
-	panic(fmt.Sprintf("invalid unary op %s %T", instr.Op, x))
-}
-
-// typeAssert checks whether dynamic type of itf is instr.AssertedType.
-// It returns the extracted value on success, and panics on failure,
-// unless instr.CommaOk, in which case it always returns a "value,ok" tuple.
-//
-func typeAssert(i *interpreter, instr *ssa.TypeAssert, itf iface) value {
-	var v value
-	err := ""
-	if itf.t == nil {
-		err = fmt.Sprintf("interface conversion: interface is nil, not %s", instr.AssertedType)
-
-	} else if idst, ok := instr.AssertedType.Underlying().(*types.Interface); ok {
-		v = itf
-		err = checkInterface(i, idst, itf)
-
-	} else if types.Identical(itf.t, instr.AssertedType) {
-		v = itf.v // extract value
-
-	} else {
-		err = fmt.Sprintf("interface conversion: interface is %s, not %s", itf.t, instr.AssertedType)
-	}
-
-	if err != "" {
-		if !instr.CommaOk {
-			panic(err)
-		}
-		return tuple{zero(instr.AssertedType), false}
-	}
-	if instr.CommaOk {
-		return tuple{v, true}
-	}
-	return v
-}
-
-// If CapturedOutput is non-nil, all writes by the interpreted program
-// to file descriptors 1 and 2 will also be written to CapturedOutput.
-//
-// (The $GOROOT/test system requires that the test be considered a
-// failure if "BUG" appears in the combined stdout/stderr output, even
-// if it exits zero.  This is a global variable shared by all
-// interpreters in the same process.)
-//
-var CapturedOutput *bytes.Buffer
-var capturedOutputMu sync.Mutex
-
-// write writes bytes b to the target program's file descriptor fd.
-// The print/println built-ins and the write() system call funnel
-// through here so they can be captured by the test driver.
-func write(fd int, b []byte) (int, error) {
-	// TODO(adonovan): fix: on Windows, std{out,err} are not 1, 2.
-	if CapturedOutput != nil && (fd == 1 || fd == 2) {
-		capturedOutputMu.Lock()
-		CapturedOutput.Write(b) // ignore errors
-		capturedOutputMu.Unlock()
-	}
-	return syswrite(fd, b)
-}
-
-// callBuiltin interprets a call to builtin fn with arguments args,
-// returning its result.
-func callBuiltin(caller *frame, callpos token.Pos, fn *ssa.Builtin, args []value) value {
-	switch fn.Name() {
-	case "append":
-		if len(args) == 1 {
-			return args[0]
-		}
-		if s, ok := args[1].(string); ok {
-			// append([]byte, ...string) []byte
-			arg0 := args[0].([]value)
-			for i := 0; i < len(s); i++ {
-				arg0 = append(arg0, s[i])
-			}
-			return arg0
-		}
-		// append([]T, ...[]T) []T
-		return append(args[0].([]value), args[1].([]value)...)
-
-	case "copy": // copy([]T, []T) int or copy([]byte, string) int
-		src := args[1]
-		if _, ok := src.(string); ok {
-			params := fn.Type().(*types.Signature).Params()
-			src = conv(params.At(0).Type(), params.At(1).Type(), src)
-		}
-		return copy(args[0].([]value), src.([]value))
-
-	case "close": // close(chan T)
-		close(args[0].(chan value))
-		return nil
-
-	case "delete": // delete(map[K]value, K)
-		switch m := args[0].(type) {
-		case map[value]value:
-			delete(m, args[1])
-		case *hashmap:
-			m.delete(args[1].(hashable))
-		default:
-			panic(fmt.Sprintf("illegal map type: %T", m))
-		}
-		return nil
-
-	case "print", "println": // print(any, ...)
-		ln := fn.Name() == "println"
-		var buf bytes.Buffer
-		for i, arg := range args {
-			if i > 0 && ln {
-				buf.WriteRune(' ')
-			}
-			buf.WriteString(toString(arg))
-		}
-		if ln {
-			buf.WriteRune('\n')
-		}
-		write(1, buf.Bytes())
-		return nil
-
-	case "len":
-		switch x := args[0].(type) {
-		case string:
-			return len(x)
-		case array:
-			return len(x)
-		case *value:
-			return len((*x).(array))
-		case []value:
-			return len(x)
-		case map[value]value:
-			return len(x)
-		case *hashmap:
-			return x.len()
-		case chan value:
-			return len(x)
-		default:
-			panic(fmt.Sprintf("len: illegal operand: %T", x))
-		}
-
-	case "cap":
-		switch x := args[0].(type) {
-		case array:
-			return cap(x)
-		case *value:
-			return cap((*x).(array))
-		case []value:
-			return cap(x)
-		case chan value:
-			return cap(x)
-		default:
-			panic(fmt.Sprintf("cap: illegal operand: %T", x))
-		}
-
-	case "real":
-		switch c := args[0].(type) {
-		case complex64:
-			return real(c)
-		case complex128:
-			return real(c)
-		default:
-			panic(fmt.Sprintf("real: illegal operand: %T", c))
-		}
-
-	case "imag":
-		switch c := args[0].(type) {
-		case complex64:
-			return imag(c)
-		case complex128:
-			return imag(c)
-		default:
-			panic(fmt.Sprintf("imag: illegal operand: %T", c))
-		}
-
-	case "complex":
-		switch f := args[0].(type) {
-		case float32:
-			return complex(f, args[1].(float32))
-		case float64:
-			return complex(f, args[1].(float64))
-		default:
-			panic(fmt.Sprintf("complex: illegal operand: %T", f))
-		}
-
-	case "panic":
-		// ssa.Panic handles most cases; this is only for "go
-		// panic" or "defer panic".
-		panic(targetPanic{args[0]})
-
-	case "recover":
-		return doRecover(caller)
-
-	case "ssa:wrapnilchk":
-		recv := args[0]
-		if recv.(*value) == nil {
-			recvType := args[1]
-			methodName := args[2]
-			panic(fmt.Sprintf("value method (%s).%s called using nil *%s pointer",
-				recvType, methodName, recvType))
-		}
-		return recv
-	}
-
-	panic("unknown built-in: " + fn.Name())
-}
-
-func rangeIter(x value, t types.Type) iter {
-	switch x := x.(type) {
-	case map[value]value:
-		// TODO(adonovan): fix: leaks goroutines and channels
-		// on each incomplete map iteration.  We need to open
-		// up an iteration interface using the
-		// reflect.(Value).MapKeys machinery.
-		it := make(mapIter)
-		go func() {
-			for k, v := range x {
-				it <- [2]value{k, v}
-			}
-			close(it)
-		}()
-		return it
-	case *hashmap:
-		// TODO(adonovan): fix: leaks goroutines and channels
-		// on each incomplete map iteration.  We need to open
-		// up an iteration interface using the
-		// reflect.(Value).MapKeys machinery.
-		it := make(mapIter)
-		go func() {
-			for _, e := range x.entries() {
-				for e != nil {
-					it <- [2]value{e.key, e.value}
-					e = e.next
-				}
-			}
-			close(it)
-		}()
-		return it
-	case string:
-		return &stringIter{Reader: strings.NewReader(x)}
-	}
-	panic(fmt.Sprintf("cannot range over %T", x))
-}
-
-// widen widens a basic typed value x to the widest type of its
-// category, one of:
-//   bool, int64, uint64, float64, complex128, string.
-// This is inefficient but reduces the size of the cross-product of
-// cases we have to consider.
-//
-func widen(x value) value {
-	switch y := x.(type) {
-	case bool, int64, uint64, float64, complex128, string, unsafe.Pointer:
-		return x
-	case int:
-		return int64(y)
-	case int8:
-		return int64(y)
-	case int16:
-		return int64(y)
-	case int32:
-		return int64(y)
-	case uint:
-		return uint64(y)
-	case uint8:
-		return uint64(y)
-	case uint16:
-		return uint64(y)
-	case uint32:
-		return uint64(y)
-	case uintptr:
-		return uint64(y)
-	case float32:
-		return float64(y)
-	case complex64:
-		return complex128(y)
-	}
-	panic(fmt.Sprintf("cannot widen %T", x))
-}
-
-// conv converts the value x of type t_src to type t_dst and returns
-// the result.
-// Possible cases are described with the ssa.Convert operator.
-//
-func conv(t_dst, t_src types.Type, x value) value {
-	ut_src := t_src.Underlying()
-	ut_dst := t_dst.Underlying()
-
-	// Destination type is not an "untyped" type.
-	if b, ok := ut_dst.(*types.Basic); ok && b.Info()&types.IsUntyped != 0 {
-		panic("oops: conversion to 'untyped' type: " + b.String())
-	}
-
-	// Nor is it an interface type.
-	if _, ok := ut_dst.(*types.Interface); ok {
-		if _, ok := ut_src.(*types.Interface); ok {
-			panic("oops: Convert should be ChangeInterface")
-		} else {
-			panic("oops: Convert should be MakeInterface")
-		}
-	}
-
-	// Remaining conversions:
-	//    + untyped string/number/bool constant to a specific
-	//      representation.
-	//    + conversions between non-complex numeric types.
-	//    + conversions between complex numeric types.
-	//    + integer/[]byte/[]rune -> string.
-	//    + string -> []byte/[]rune.
-	//
-	// All are treated the same: first we extract the value to the
-	// widest representation (int64, uint64, float64, complex128,
-	// or string), then we convert it to the desired type.
-
-	switch ut_src := ut_src.(type) {
-	case *types.Pointer:
-		switch ut_dst := ut_dst.(type) {
-		case *types.Basic:
-			// *value to unsafe.Pointer?
-			if ut_dst.Kind() == types.UnsafePointer {
-				return unsafe.Pointer(x.(*value))
-			}
-		}
-
-	case *types.Slice:
-		// []byte or []rune -> string
-		// TODO(adonovan): fix: type B byte; conv([]B -> string).
-		switch ut_src.Elem().(*types.Basic).Kind() {
-		case types.Byte:
-			x := x.([]value)
-			b := make([]byte, 0, len(x))
-			for i := range x {
-				b = append(b, x[i].(byte))
-			}
-			return string(b)
-
-		case types.Rune:
-			x := x.([]value)
-			r := make([]rune, 0, len(x))
-			for i := range x {
-				r = append(r, x[i].(rune))
-			}
-			return string(r)
-		}
-
-	case *types.Basic:
-		x = widen(x)
-
-		// integer -> string?
-		// TODO(adonovan): fix: test integer -> named alias of string.
-		if ut_src.Info()&types.IsInteger != 0 {
-			if ut_dst, ok := ut_dst.(*types.Basic); ok && ut_dst.Kind() == types.String {
-				return string(asInt(x))
-			}
-		}
-
-		// string -> []rune, []byte or string?
-		if s, ok := x.(string); ok {
-			switch ut_dst := ut_dst.(type) {
-			case *types.Slice:
-				var res []value
-				// TODO(adonovan): fix: test named alias of rune, byte.
-				switch ut_dst.Elem().(*types.Basic).Kind() {
-				case types.Rune:
-					for _, r := range []rune(s) {
-						res = append(res, r)
-					}
-					return res
-				case types.Byte:
-					for _, b := range []byte(s) {
-						res = append(res, b)
-					}
-					return res
-				}
-			case *types.Basic:
-				if ut_dst.Kind() == types.String {
-					return x.(string)
-				}
-			}
-			break // fail: no other conversions for string
-		}
-
-		// unsafe.Pointer -> *value
-		if ut_src.Kind() == types.UnsafePointer {
-			// TODO(adonovan): this is wrong and cannot
-			// really be fixed with the current design.
-			//
-			// return (*value)(x.(unsafe.Pointer))
-			// creates a new pointer of a different
-			// type but the underlying interface value
-			// knows its "true" type and so cannot be
-			// meaningfully used through the new pointer.
-			//
-			// To make this work, the interpreter needs to
-			// simulate the memory layout of a real
-			// compiled implementation.
-			//
-			// To at least preserve type-safety, we'll
-			// just return the zero value of the
-			// destination type.
-			return zero(t_dst)
-		}
-
-		// Conversions between complex numeric types?
-		if ut_src.Info()&types.IsComplex != 0 {
-			switch ut_dst.(*types.Basic).Kind() {
-			case types.Complex64:
-				return complex64(x.(complex128))
-			case types.Complex128:
-				return x.(complex128)
-			}
-			break // fail: no other conversions for complex
-		}
-
-		// Conversions between non-complex numeric types?
-		if ut_src.Info()&types.IsNumeric != 0 {
-			kind := ut_dst.(*types.Basic).Kind()
-			switch x := x.(type) {
-			case int64: // signed integer -> numeric?
-				switch kind {
-				case types.Int:
-					return int(x)
-				case types.Int8:
-					return int8(x)
-				case types.Int16:
-					return int16(x)
-				case types.Int32:
-					return int32(x)
-				case types.Int64:
-					return int64(x)
-				case types.Uint:
-					return uint(x)
-				case types.Uint8:
-					return uint8(x)
-				case types.Uint16:
-					return uint16(x)
-				case types.Uint32:
-					return uint32(x)
-				case types.Uint64:
-					return uint64(x)
-				case types.Uintptr:
-					return uintptr(x)
-				case types.Float32:
-					return float32(x)
-				case types.Float64:
-					return float64(x)
-				}
-
-			case uint64: // unsigned integer -> numeric?
-				switch kind {
-				case types.Int:
-					return int(x)
-				case types.Int8:
-					return int8(x)
-				case types.Int16:
-					return int16(x)
-				case types.Int32:
-					return int32(x)
-				case types.Int64:
-					return int64(x)
-				case types.Uint:
-					return uint(x)
-				case types.Uint8:
-					return uint8(x)
-				case types.Uint16:
-					return uint16(x)
-				case types.Uint32:
-					return uint32(x)
-				case types.Uint64:
-					return uint64(x)
-				case types.Uintptr:
-					return uintptr(x)
-				case types.Float32:
-					return float32(x)
-				case types.Float64:
-					return float64(x)
-				}
-
-			case float64: // floating point -> numeric?
-				switch kind {
-				case types.Int:
-					return int(x)
-				case types.Int8:
-					return int8(x)
-				case types.Int16:
-					return int16(x)
-				case types.Int32:
-					return int32(x)
-				case types.Int64:
-					return int64(x)
-				case types.Uint:
-					return uint(x)
-				case types.Uint8:
-					return uint8(x)
-				case types.Uint16:
-					return uint16(x)
-				case types.Uint32:
-					return uint32(x)
-				case types.Uint64:
-					return uint64(x)
-				case types.Uintptr:
-					return uintptr(x)
-				case types.Float32:
-					return float32(x)
-				case types.Float64:
-					return float64(x)
-				}
-			}
-		}
-	}
-
-	panic(fmt.Sprintf("unsupported conversion: %s  -> %s, dynamic type %T", t_src, t_dst, x))
-}
-
-// checkInterface checks that the method set of x implements the
-// interface itype.
-// On success it returns "", on failure, an error message.
-//
-func checkInterface(i *interpreter, itype *types.Interface, x iface) string {
-	if meth, _ := types.MissingMethod(x.t, itype, true); meth != nil {
-		return fmt.Sprintf("interface conversion: %v is not %v: missing method %s",
-			x.t, itype, meth.Name())
-	}
-	return "" // ok
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/reflect.go b/_linters/src/honnef.co/go/tools/ssa/interp/reflect.go
deleted file mode 100644
index d99a8b9..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/reflect.go
+++ /dev/null
@@ -1,576 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.5
-
-package interp
-
-// Emulated "reflect" package.
-//
-// We completely replace the built-in "reflect" package.
-// The only thing clients can depend upon are that reflect.Type is an
-// interface and reflect.Value is an (opaque) struct.
-
-import (
-	"fmt"
-	"go/token"
-	"go/types"
-	"reflect"
-	"unsafe"
-
-	"honnef.co/go/tools/ssa"
-)
-
-type opaqueType struct {
-	types.Type
-	name string
-}
-
-func (t *opaqueType) String() string { return t.name }
-
-// A bogus "reflect" type-checker package.  Shared across interpreters.
-var reflectTypesPackage = types.NewPackage("reflect", "reflect")
-
-// rtype is the concrete type the interpreter uses to implement the
-// reflect.Type interface.
-//
-// type rtype <opaque>
-var rtypeType = makeNamedType("rtype", &opaqueType{nil, "rtype"})
-
-// error is an (interpreted) named type whose underlying type is string.
-// The interpreter uses it for all implementations of the built-in error
-// interface that it creates.
-// We put it in the "reflect" package for expedience.
-//
-// type error string
-var errorType = makeNamedType("error", &opaqueType{nil, "error"})
-
-func makeNamedType(name string, underlying types.Type) *types.Named {
-	obj := types.NewTypeName(token.NoPos, reflectTypesPackage, name, nil)
-	return types.NewNamed(obj, underlying, nil)
-}
-
-func makeReflectValue(t types.Type, v value) value {
-	return structure{rtype{t}, v}
-}
-
-// Given a reflect.Value, returns its rtype.
-func rV2T(v value) rtype {
-	return v.(structure)[0].(rtype)
-}
-
-// Given a reflect.Value, returns the underlying interpreter value.
-func rV2V(v value) value {
-	return v.(structure)[1]
-}
-
-// makeReflectType boxes up an rtype in a reflect.Type interface.
-func makeReflectType(rt rtype) value {
-	return iface{rtypeType, rt}
-}
-
-func ext۰reflect۰Init(fr *frame, args []value) value {
-	// Signature: func()
-	return nil
-}
-
-func ext۰reflect۰rtype۰Bits(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) int
-	rt := args[0].(rtype).t
-	basic, ok := rt.Underlying().(*types.Basic)
-	if !ok {
-		panic(fmt.Sprintf("reflect.Type.Bits(%T): non-basic type", rt))
-	}
-	return int(fr.i.sizes.Sizeof(basic)) * 8
-}
-
-func ext۰reflect۰rtype۰Elem(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) reflect.Type
-	return makeReflectType(rtype{args[0].(rtype).t.Underlying().(interface {
-		Elem() types.Type
-	}).Elem()})
-}
-
-func ext۰reflect۰rtype۰Field(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype, i int) reflect.StructField
-	st := args[0].(rtype).t.Underlying().(*types.Struct)
-	i := args[1].(int)
-	f := st.Field(i)
-	return structure{
-		f.Name(),
-		f.Pkg().Path(),
-		makeReflectType(rtype{f.Type()}),
-		st.Tag(i),
-		0,         // TODO(adonovan): offset
-		[]value{}, // TODO(adonovan): indices
-		f.Anonymous(),
-	}
-}
-
-func ext۰reflect۰rtype۰In(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype, i int) int
-	i := args[1].(int)
-	return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Params().At(i).Type()})
-}
-
-func ext۰reflect۰rtype۰Kind(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) uint
-	return uint(reflectKind(args[0].(rtype).t))
-}
-
-func ext۰reflect۰rtype۰NumField(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) int
-	return args[0].(rtype).t.Underlying().(*types.Struct).NumFields()
-}
-
-func ext۰reflect۰rtype۰NumIn(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) int
-	return args[0].(rtype).t.(*types.Signature).Params().Len()
-}
-
-func ext۰reflect۰rtype۰NumMethod(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) int
-	return fr.i.prog.MethodSets.MethodSet(args[0].(rtype).t).Len()
-}
-
-func ext۰reflect۰rtype۰NumOut(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) int
-	return args[0].(rtype).t.(*types.Signature).Results().Len()
-}
-
-func ext۰reflect۰rtype۰Out(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype, i int) int
-	i := args[1].(int)
-	return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results().At(i).Type()})
-}
-
-func ext۰reflect۰rtype۰Size(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) uintptr
-	return uintptr(fr.i.sizes.Sizeof(args[0].(rtype).t))
-}
-
-func ext۰reflect۰rtype۰String(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) string
-	return args[0].(rtype).t.String()
-}
-
-func ext۰reflect۰New(fr *frame, args []value) value {
-	// Signature: func (t reflect.Type) reflect.Value
-	t := args[0].(iface).v.(rtype).t
-	alloc := zero(t)
-	return makeReflectValue(types.NewPointer(t), &alloc)
-}
-
-func ext۰reflect۰SliceOf(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) Type
-	return makeReflectType(rtype{types.NewSlice(args[0].(iface).v.(rtype).t)})
-}
-
-func ext۰reflect۰TypeOf(fr *frame, args []value) value {
-	// Signature: func (t reflect.rtype) Type
-	return makeReflectType(rtype{args[0].(iface).t})
-}
-
-func ext۰reflect۰ValueOf(fr *frame, args []value) value {
-	// Signature: func (interface{}) reflect.Value
-	itf := args[0].(iface)
-	return makeReflectValue(itf.t, itf.v)
-}
-
-func ext۰reflect۰Zero(fr *frame, args []value) value {
-	// Signature: func (t reflect.Type) reflect.Value
-	t := args[0].(iface).v.(rtype).t
-	return makeReflectValue(t, zero(t))
-}
-
-func reflectKind(t types.Type) reflect.Kind {
-	switch t := t.(type) {
-	case *types.Named:
-		return reflectKind(t.Underlying())
-	case *types.Basic:
-		switch t.Kind() {
-		case types.Bool:
-			return reflect.Bool
-		case types.Int:
-			return reflect.Int
-		case types.Int8:
-			return reflect.Int8
-		case types.Int16:
-			return reflect.Int16
-		case types.Int32:
-			return reflect.Int32
-		case types.Int64:
-			return reflect.Int64
-		case types.Uint:
-			return reflect.Uint
-		case types.Uint8:
-			return reflect.Uint8
-		case types.Uint16:
-			return reflect.Uint16
-		case types.Uint32:
-			return reflect.Uint32
-		case types.Uint64:
-			return reflect.Uint64
-		case types.Uintptr:
-			return reflect.Uintptr
-		case types.Float32:
-			return reflect.Float32
-		case types.Float64:
-			return reflect.Float64
-		case types.Complex64:
-			return reflect.Complex64
-		case types.Complex128:
-			return reflect.Complex128
-		case types.String:
-			return reflect.String
-		case types.UnsafePointer:
-			return reflect.UnsafePointer
-		}
-	case *types.Array:
-		return reflect.Array
-	case *types.Chan:
-		return reflect.Chan
-	case *types.Signature:
-		return reflect.Func
-	case *types.Interface:
-		return reflect.Interface
-	case *types.Map:
-		return reflect.Map
-	case *types.Pointer:
-		return reflect.Ptr
-	case *types.Slice:
-		return reflect.Slice
-	case *types.Struct:
-		return reflect.Struct
-	}
-	panic(fmt.Sprint("unexpected type: ", t))
-}
-
-func ext۰reflect۰Value۰Kind(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) uint
-	return uint(reflectKind(rV2T(args[0]).t))
-}
-
-func ext۰reflect۰Value۰String(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) string
-	return toString(rV2V(args[0]))
-}
-
-func ext۰reflect۰Value۰Type(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) reflect.Type
-	return makeReflectType(rV2T(args[0]))
-}
-
-func ext۰reflect۰Value۰Uint(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) uint64
-	switch v := rV2V(args[0]).(type) {
-	case uint:
-		return uint64(v)
-	case uint8:
-		return uint64(v)
-	case uint16:
-		return uint64(v)
-	case uint32:
-		return uint64(v)
-	case uint64:
-		return uint64(v)
-	case uintptr:
-		return uint64(v)
-	}
-	panic("reflect.Value.Uint")
-}
-
-func ext۰reflect۰Value۰Len(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) int
-	switch v := rV2V(args[0]).(type) {
-	case string:
-		return len(v)
-	case array:
-		return len(v)
-	case chan value:
-		return cap(v)
-	case []value:
-		return len(v)
-	case *hashmap:
-		return v.len()
-	case map[value]value:
-		return len(v)
-	default:
-		panic(fmt.Sprintf("reflect.(Value).Len(%v)", v))
-	}
-}
-
-func ext۰reflect۰Value۰MapIndex(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) Value
-	tValue := rV2T(args[0]).t.Underlying().(*types.Map).Key()
-	k := rV2V(args[1])
-	switch m := rV2V(args[0]).(type) {
-	case map[value]value:
-		if v, ok := m[k]; ok {
-			return makeReflectValue(tValue, v)
-		}
-
-	case *hashmap:
-		if v := m.lookup(k.(hashable)); v != nil {
-			return makeReflectValue(tValue, v)
-		}
-
-	default:
-		panic(fmt.Sprintf("(reflect.Value).MapIndex(%T, %T)", m, k))
-	}
-	return makeReflectValue(nil, nil)
-}
-
-func ext۰reflect۰Value۰MapKeys(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) []Value
-	var keys []value
-	tKey := rV2T(args[0]).t.Underlying().(*types.Map).Key()
-	switch v := rV2V(args[0]).(type) {
-	case map[value]value:
-		for k := range v {
-			keys = append(keys, makeReflectValue(tKey, k))
-		}
-
-	case *hashmap:
-		for _, e := range v.entries() {
-			for ; e != nil; e = e.next {
-				keys = append(keys, makeReflectValue(tKey, e.key))
-			}
-		}
-
-	default:
-		panic(fmt.Sprintf("(reflect.Value).MapKeys(%T)", v))
-	}
-	return keys
-}
-
-func ext۰reflect۰Value۰NumField(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) int
-	return len(rV2V(args[0]).(structure))
-}
-
-func ext۰reflect۰Value۰NumMethod(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) int
-	return fr.i.prog.MethodSets.MethodSet(rV2T(args[0]).t).Len()
-}
-
-func ext۰reflect۰Value۰Pointer(fr *frame, args []value) value {
-	// Signature: func (v reflect.Value) uintptr
-	switch v := rV2V(args[0]).(type) {
-	case *value:
-		return uintptr(unsafe.Pointer(v))
-	case chan value:
-		return reflect.ValueOf(v).Pointer()
-	case []value:
-		return reflect.ValueOf(v).Pointer()
-	case *hashmap:
-		return reflect.ValueOf(v.entries()).Pointer()
-	case map[value]value:
-		return reflect.ValueOf(v).Pointer()
-	case *ssa.Function:
-		return uintptr(unsafe.Pointer(v))
-	case *closure:
-		return uintptr(unsafe.Pointer(v))
-	default:
-		panic(fmt.Sprintf("reflect.(Value).Pointer(%T)", v))
-	}
-}
-
-func ext۰reflect۰Value۰Index(fr *frame, args []value) value {
-	// Signature: func (v reflect.Value, i int) Value
-	i := args[1].(int)
-	t := rV2T(args[0]).t.Underlying()
-	switch v := rV2V(args[0]).(type) {
-	case array:
-		return makeReflectValue(t.(*types.Array).Elem(), v[i])
-	case []value:
-		return makeReflectValue(t.(*types.Slice).Elem(), v[i])
-	default:
-		panic(fmt.Sprintf("reflect.(Value).Index(%T)", v))
-	}
-}
-
-func ext۰reflect۰Value۰Bool(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) bool
-	return rV2V(args[0]).(bool)
-}
-
-func ext۰reflect۰Value۰CanAddr(fr *frame, args []value) value {
-	// Signature: func (v reflect.Value) bool
-	// Always false for our representation.
-	return false
-}
-
-func ext۰reflect۰Value۰CanInterface(fr *frame, args []value) value {
-	// Signature: func (v reflect.Value) bool
-	// Always true for our representation.
-	return true
-}
-
-func ext۰reflect۰Value۰Elem(fr *frame, args []value) value {
-	// Signature: func (v reflect.Value) reflect.Value
-	switch x := rV2V(args[0]).(type) {
-	case iface:
-		return makeReflectValue(x.t, x.v)
-	case *value:
-		return makeReflectValue(rV2T(args[0]).t.Underlying().(*types.Pointer).Elem(), *x)
-	default:
-		panic(fmt.Sprintf("reflect.(Value).Elem(%T)", x))
-	}
-}
-
-func ext۰reflect۰Value۰Field(fr *frame, args []value) value {
-	// Signature: func (v reflect.Value, i int) reflect.Value
-	v := args[0]
-	i := args[1].(int)
-	return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type(), rV2V(v).(structure)[i])
-}
-
-func ext۰reflect۰Value۰Float(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) float64
-	switch v := rV2V(args[0]).(type) {
-	case float32:
-		return float64(v)
-	case float64:
-		return float64(v)
-	}
-	panic("reflect.Value.Float")
-}
-
-func ext۰reflect۰Value۰Interface(fr *frame, args []value) value {
-	// Signature: func (v reflect.Value) interface{}
-	return ext۰reflect۰valueInterface(fr, args)
-}
-
-func ext۰reflect۰Value۰Int(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) int64
-	switch x := rV2V(args[0]).(type) {
-	case int:
-		return int64(x)
-	case int8:
-		return int64(x)
-	case int16:
-		return int64(x)
-	case int32:
-		return int64(x)
-	case int64:
-		return x
-	default:
-		panic(fmt.Sprintf("reflect.(Value).Int(%T)", x))
-	}
-}
-
-func ext۰reflect۰Value۰IsNil(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) bool
-	switch x := rV2V(args[0]).(type) {
-	case *value:
-		return x == nil
-	case chan value:
-		return x == nil
-	case map[value]value:
-		return x == nil
-	case *hashmap:
-		return x == nil
-	case iface:
-		return x.t == nil
-	case []value:
-		return x == nil
-	case *ssa.Function:
-		return x == nil
-	case *ssa.Builtin:
-		return x == nil
-	case *closure:
-		return x == nil
-	default:
-		panic(fmt.Sprintf("reflect.(Value).IsNil(%T)", x))
-	}
-}
-
-func ext۰reflect۰Value۰IsValid(fr *frame, args []value) value {
-	// Signature: func (reflect.Value) bool
-	return rV2V(args[0]) != nil
-}
-
-func ext۰reflect۰Value۰Set(fr *frame, args []value) value {
-	// TODO(adonovan): implement.
-	return nil
-}
-
-func ext۰reflect۰valueInterface(fr *frame, args []value) value {
-	// Signature: func (v reflect.Value, safe bool) interface{}
-	v := args[0].(structure)
-	return iface{rV2T(v).t, rV2V(v)}
-}
-
-func ext۰reflect۰error۰Error(fr *frame, args []value) value {
-	return args[0]
-}
-
-// newMethod creates a new method of the specified name, package and receiver type.
-func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function {
-	// TODO(adonovan): fix: hack: currently the only part of Signature
-	// that is needed is the "pointerness" of Recv.Type, and for
-	// now, we'll set it to always be false since we're only
-	// concerned with rtype.  Encapsulate this better.
-	sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false)
-	fn := pkg.Prog.NewFunction(name, sig, "fake reflect method")
-	fn.Pkg = pkg
-	return fn
-}
-
-func initReflect(i *interpreter) {
-	i.reflectPackage = &ssa.Package{
-		Prog:    i.prog,
-		Pkg:     reflectTypesPackage,
-		Members: make(map[string]ssa.Member),
-	}
-
-	// Clobber the type-checker's notion of reflect.Value's
-	// underlying type so that it more closely matches the fake one
-	// (at least in the number of fields---we lie about the type of
-	// the rtype field).
-	//
-	// We must ensure that calls to (ssa.Value).Type() return the
-	// fake type so that correct "shape" is used when allocating
-	// variables, making zero values, loading, and storing.
-	//
-	// TODO(adonovan): obviously this is a hack.  We need a cleaner
-	// way to fake the reflect package (almost---DeepEqual is fine).
-	// One approach would be not to even load its source code, but
-	// provide fake source files.  This would guarantee that no bad
-	// information leaks into other packages.
-	if r := i.prog.ImportedPackage("reflect"); r != nil {
-		rV := r.Pkg.Scope().Lookup("Value").Type().(*types.Named)
-
-		// delete bodies of the old methods
-		mset := i.prog.MethodSets.MethodSet(rV)
-		for j := 0; j < mset.Len(); j++ {
-			i.prog.MethodValue(mset.At(j)).Blocks = nil
-		}
-
-		tEface := types.NewInterface(nil, nil).Complete()
-		rV.SetUnderlying(types.NewStruct([]*types.Var{
-			types.NewField(token.NoPos, r.Pkg, "t", tEface, false), // a lie
-			types.NewField(token.NoPos, r.Pkg, "v", tEface, false),
-		}, nil))
-	}
-
-	i.rtypeMethods = methodSet{
-		"Bits":      newMethod(i.reflectPackage, rtypeType, "Bits"),
-		"Elem":      newMethod(i.reflectPackage, rtypeType, "Elem"),
-		"Field":     newMethod(i.reflectPackage, rtypeType, "Field"),
-		"In":        newMethod(i.reflectPackage, rtypeType, "In"),
-		"Kind":      newMethod(i.reflectPackage, rtypeType, "Kind"),
-		"NumField":  newMethod(i.reflectPackage, rtypeType, "NumField"),
-		"NumIn":     newMethod(i.reflectPackage, rtypeType, "NumIn"),
-		"NumMethod": newMethod(i.reflectPackage, rtypeType, "NumMethod"),
-		"NumOut":    newMethod(i.reflectPackage, rtypeType, "NumOut"),
-		"Out":       newMethod(i.reflectPackage, rtypeType, "Out"),
-		"Size":      newMethod(i.reflectPackage, rtypeType, "Size"),
-		"String":    newMethod(i.reflectPackage, rtypeType, "String"),
-	}
-	i.errorMethods = methodSet{
-		"Error": newMethod(i.reflectPackage, errorType, "Error"),
-	}
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/interp/value.go b/_linters/src/honnef.co/go/tools/ssa/interp/value.go
deleted file mode 100644
index 2b91f71..0000000
--- a/_linters/src/honnef.co/go/tools/ssa/interp/value.go
+++ /dev/null
@@ -1,499 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.5
-
-package interp
-
-// Values
-//
-// All interpreter values are "boxed" in the empty interface, value.
-// The range of possible dynamic types within value are:
-//
-// - bool
-// - numbers (all built-in int/float/complex types are distinguished)
-// - string
-// - map[value]value --- maps for which  usesBuiltinMap(keyType)
-//   *hashmap        --- maps for which !usesBuiltinMap(keyType)
-// - chan value
-// - []value --- slices
-// - iface --- interfaces.
-// - structure --- structs.  Fields are ordered and accessed by numeric indices.
-// - array --- arrays.
-// - *value --- pointers.  Careful: *value is a distinct type from *array etc.
-// - *ssa.Function \
-//   *ssa.Builtin   } --- functions.  A nil 'func' is always of type *ssa.Function.
-//   *closure      /
-// - tuple --- as returned by Return, Next, "value,ok" modes, etc.
-// - iter --- iterators from 'range' over map or string.
-// - bad --- a poison pill for locals that have gone out of scope.
-// - rtype -- the interpreter's concrete implementation of reflect.Type
-//
-// Note that nil is not on this list.
-//
-// Pay close attention to whether or not the dynamic type is a pointer.
-// The compiler cannot help you since value is an empty interface.
-
-import (
-	"bytes"
-	"fmt"
-	"go/types"
-	"io"
-	"reflect"
-	"strings"
-	"sync"
-	"unsafe"
-
-	"honnef.co/go/tools/ssa"
-	"golang.org/x/tools/go/types/typeutil"
-)
-
-type value interface{}
-
-type tuple []value
-
-type array []value
-
-type iface struct {
-	t types.Type // never an "untyped" type
-	v value
-}
-
-type structure []value
-
-// For map, array, *array, slice, string or channel.
-type iter interface {
-	// next returns a Tuple (key, value, ok).
-	// key and value are unaliased, e.g. copies of the sequence element.
-	next() tuple
-}
-
-type closure struct {
-	Fn  *ssa.Function
-	Env []value
-}
-
-type bad struct{}
-
-type rtype struct {
-	t types.Type
-}
-
-// Hash functions and equivalence relation:
-
-// hashString computes the FNV hash of s.
-func hashString(s string) int {
-	var h uint32
-	for i := 0; i < len(s); i++ {
-		h ^= uint32(s[i])
-		h *= 16777619
-	}
-	return int(h)
-}
-
-var (
-	mu     sync.Mutex
-	hasher = typeutil.MakeHasher()
-)
-
-// hashType returns a hash for t such that
-// types.Identical(x, y) => hashType(x) == hashType(y).
-func hashType(t types.Type) int {
-	mu.Lock()
-	h := int(hasher.Hash(t))
-	mu.Unlock()
-	return h
-}
-
-// usesBuiltinMap returns true if the built-in hash function and
-// equivalence relation for type t are consistent with those of the
-// interpreter's representation of type t.  Such types are: all basic
-// types (bool, numbers, string), pointers and channels.
-//
-// usesBuiltinMap returns false for types that require a custom map
-// implementation: interfaces, arrays and structs.
-//
-// Panic ensues if t is an invalid map key type: function, map or slice.
-func usesBuiltinMap(t types.Type) bool {
-	switch t := t.(type) {
-	case *types.Basic, *types.Chan, *types.Pointer:
-		return true
-	case *types.Named:
-		return usesBuiltinMap(t.Underlying())
-	case *types.Interface, *types.Array, *types.Struct:
-		return false
-	}
-	panic(fmt.Sprintf("invalid map key type: %T", t))
-}
-
-func (x array) eq(t types.Type, _y interface{}) bool {
-	y := _y.(array)
-	tElt := t.Underlying().(*types.Array).Elem()
-	for i, xi := range x {
-		if !equals(tElt, xi, y[i]) {
-			return false
-		}
-	}
-	return true
-}
-
-func (x array) hash(t types.Type) int {
-	h := 0
-	tElt := t.Underlying().(*types.Array).Elem()
-	for _, xi := range x {
-		h += hash(tElt, xi)
-	}
-	return h
-}
-
-func (x structure) eq(t types.Type, _y interface{}) bool {
-	y := _y.(structure)
-	tStruct := t.Underlying().(*types.Struct)
-	for i, n := 0, tStruct.NumFields(); i < n; i++ {
-		if f := tStruct.Field(i); !f.Anonymous() {
-			if !equals(f.Type(), x[i], y[i]) {
-				return false
-			}
-		}
-	}
-	return true
-}
-
-func (x structure) hash(t types.Type) int {
-	tStruct := t.Underlying().(*types.Struct)
-	h := 0
-	for i, n := 0, tStruct.NumFields(); i < n; i++ {
-		if f := tStruct.Field(i); !f.Anonymous() {
-			h += hash(f.Type(), x[i])
-		}
-	}
-	return h
-}
-
-// nil-tolerant variant of types.Identical.
-func sameType(x, y types.Type) bool {
-	if x == nil {
-		return y == nil
-	}
-	return y != nil && types.Identical(x, y)
-}
-
-func (x iface) eq(t types.Type, _y interface{}) bool {
-	y := _y.(iface)
-	return sameType(x.t, y.t) && (x.t == nil || equals(x.t, x.v, y.v))
-}
-
-func (x iface) hash(_ types.Type) int {
-	return hashType(x.t)*8581 + hash(x.t, x.v)
-}
-
-func (x rtype) hash(_ types.Type) int {
-	return hashType(x.t)
-}
-
-func (x rtype) eq(_ types.Type, y interface{}) bool {
-	return types.Identical(x.t, y.(rtype).t)
-}
-
-// equals returns true iff x and y are equal according to Go's
-// linguistic equivalence relation for type t.
-// In a well-typed program, the dynamic types of x and y are
-// guaranteed equal.
-func equals(t types.Type, x, y value) bool {
-	switch x := x.(type) {
-	case bool:
-		return x == y.(bool)
-	case int:
-		return x == y.(int)
-	case int8:
-		return x == y.(int8)
-	case int16:
-		return x == y.(int16)
-	case int32:
-		return x == y.(int32)
-	case int64:
-		return x == y.(int64)
-	case uint:
-		return x == y.(uint)
-	case uint8:
-		return x == y.(uint8)
-	case uint16:
-		return x == y.(uint16)
-	case uint32:
-		return x == y.(uint32)
-	case uint64:
-		return x == y.(uint64)
-	case uintptr:
-		return x == y.(uintptr)
-	case float32:
-		return x == y.(float32)
-	case float64:
-		return x == y.(float64)
-	case complex64:
-		return x == y.(complex64)
-	case complex128:
-		return x == y.(complex128)
-	case string:
-		return x == y.(string)
-	case *value:
-		return x == y.(*value)
-	case chan value:
-		return x == y.(chan value)
-	case structure:
-		return x.eq(t, y)
-	case array:
-		return x.eq(t, y)
-	case iface:
-		return x.eq(t, y)
-	case rtype:
-		return x.eq(t, y)
-	}
-
-	// Since map, func and slice don't support comparison, this
-	// case is only reachable if one of x or y is literally nil
-	// (handled in eqnil) or via interface{} values.
-	panic(fmt.Sprintf("comparing uncomparable type %s", t))
-}
-
-// Returns an integer hash of x such that equals(x, y) => hash(x) == hash(y).
-func hash(t types.Type, x value) int {
-	switch x := x.(type) {
-	case bool:
-		if x {
-			return 1
-		}
-		return 0
-	case int:
-		return x
-	case int8:
-		return int(x)
-	case int16:
-		return int(x)
-	case int32:
-		return int(x)
-	case int64:
-		return int(x)
-	case uint:
-		return int(x)
-	case uint8:
-		return int(x)
-	case uint16:
-		return int(x)
-	case uint32:
-		return int(x)
-	case uint64:
-		return int(x)
-	case uintptr:
-		return int(x)
-	case float32:
-		return int(x)
-	case float64:
-		return int(x)
-	case complex64:
-		return int(real(x))
-	case complex128:
-		return int(real(x))
-	case string:
-		return hashString(x)
-	case *value:
-		return int(uintptr(unsafe.Pointer(x)))
-	case chan value:
-		return int(uintptr(reflect.ValueOf(x).Pointer()))
-	case structure:
-		return x.hash(t)
-	case array:
-		return x.hash(t)
-	case iface:
-		return x.hash(t)
-	case rtype:
-		return x.hash(t)
-	}
-	panic(fmt.Sprintf("%T is unhashable", x))
-}
-
-// reflect.Value struct values don't have a fixed shape, since the
-// payload can be a scalar or an aggregate depending on the instance.
-// So store (and load) can't simply use recursion over the shape of the
-// rhs value, or the lhs, to copy the value; we need the static type
-// information.  (We can't make reflect.Value a new basic data type
-// because its "structness" is exposed to Go programs.)
-
-// load returns the value of type T in *addr.
-func load(T types.Type, addr *value) value {
-	switch T := T.Underlying().(type) {
-	case *types.Struct:
-		v := (*addr).(structure)
-		a := make(structure, len(v))
-		for i := range a {
-			a[i] = load(T.Field(i).Type(), &v[i])
-		}
-		return a
-	case *types.Array:
-		v := (*addr).(array)
-		a := make(array, len(v))
-		for i := range a {
-			a[i] = load(T.Elem(), &v[i])
-		}
-		return a
-	default:
-		return *addr
-	}
-}
-
-// store stores value v of type T into *addr.
-func store(T types.Type, addr *value, v value) {
-	switch T := T.Underlying().(type) {
-	case *types.Struct:
-		lhs := (*addr).(structure)
-		rhs := v.(structure)
-		for i := range lhs {
-			store(T.Field(i).Type(), &lhs[i], rhs[i])
-		}
-	case *types.Array:
-		lhs := (*addr).(array)
-		rhs := v.(array)
-		for i := range lhs {
-			store(T.Elem(), &lhs[i], rhs[i])
-		}
-	default:
-		*addr = v
-	}
-}
-
-// Prints in the style of built-in println.
-// (More or less; in gc println is actually a compiler intrinsic and
-// can distinguish println(1) from println(interface{}(1)).)
-func writeValue(buf *bytes.Buffer, v value) {
-	switch v := v.(type) {
-	case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string:
-		fmt.Fprintf(buf, "%v", v)
-
-	case map[value]value:
-		buf.WriteString("map[")
-		sep := ""
-		for k, e := range v {
-			buf.WriteString(sep)
-			sep = " "
-			writeValue(buf, k)
-			buf.WriteString(":")
-			writeValue(buf, e)
-		}
-		buf.WriteString("]")
-
-	case *hashmap:
-		buf.WriteString("map[")
-		sep := " "
-		for _, e := range v.entries() {
-			for e != nil {
-				buf.WriteString(sep)
-				sep = " "
-				writeValue(buf, e.key)
-				buf.WriteString(":")
-				writeValue(buf, e.value)
-				e = e.next
-			}
-		}
-		buf.WriteString("]")
-
-	case chan value:
-		fmt.Fprintf(buf, "%v", v) // (an address)
-
-	case *value:
-		if v == nil {
-			buf.WriteString("<nil>")
-		} else {
-			fmt.Fprintf(buf, "%p", v)
-		}
-
-	case iface:
-		fmt.Fprintf(buf, "(%s, ", v.t)
-		writeValue(buf, v.v)
-		buf.WriteString(")")
-
-	case structure:
-		buf.WriteString("{")
-		for i, e := range v {
-			if i > 0 {
-				buf.WriteString(" ")
-			}
-			writeValue(buf, e)
-		}
-		buf.WriteString("}")
-
-	case array:
-		buf.WriteString("[")
-		for i, e := range v {
-			if i > 0 {
-				buf.WriteString(" ")
-			}
-			writeValue(buf, e)
-		}
-		buf.WriteString("]")
-
-	case []value:
-		buf.WriteString("[")
-		for i, e := range v {
-			if i > 0 {
-				buf.WriteString(" ")
-			}
-			writeValue(buf, e)
-		}
-		buf.WriteString("]")
-
-	case *ssa.Function, *ssa.Builtin, *closure:
-		fmt.Fprintf(buf, "%p", v) // (an address)
-
-	case rtype:
-		buf.WriteString(v.t.String())
-
-	case tuple:
-		// Unreachable in well-formed Go programs
-		buf.WriteString("(")
-		for i, e := range v {
-			if i > 0 {
-				buf.WriteString(", ")
-			}
-			writeValue(buf, e)
-		}
-		buf.WriteString(")")
-
-	default:
-		fmt.Fprintf(buf, "<%T>", v)
-	}
-}
-
-// Implements printing of Go values in the style of built-in println.
-func toString(v value) string {
-	var b bytes.Buffer
-	writeValue(&b, v)
-	return b.String()
-}
-
-// ------------------------------------------------------------------------
-// Iterators
-
-type stringIter struct {
-	*strings.Reader
-	i int
-}
-
-func (it *stringIter) next() tuple {
-	okv := make(tuple, 3)
-	ch, n, err := it.ReadRune()
-	ok := err != io.EOF
-	okv[0] = ok
-	if ok {
-		okv[1] = it.i
-		okv[2] = ch
-	}
-	it.i += n
-	return okv
-}
-
-type mapIter chan [2]value
-
-func (it mapIter) next() tuple {
-	kv, ok := <-it
-	return tuple{ok, kv[0], kv[1]}
-}
diff --git a/_linters/src/honnef.co/go/tools/ssa/sanity.go b/_linters/src/honnef.co/go/tools/ssa/sanity.go
index 4babb37..bd7377c 100644
--- a/_linters/src/honnef.co/go/tools/ssa/sanity.go
+++ b/_linters/src/honnef.co/go/tools/ssa/sanity.go
@@ -176,6 +176,8 @@ func (s *sanity) checkInstr(idx int, instr Instruction) {
 	case *TypeAssert:
 	case *UnOp:
 	case *DebugRef:
+	case *BlankStore:
+	case *Sigma:
 		// TODO(adonovan): implement checks.
 	default:
 		panic(fmt.Sprintf("Unknown instruction type: %T", instr))
diff --git a/_linters/src/honnef.co/go/tools/staticcheck/lint.go b/_linters/src/honnef.co/go/tools/staticcheck/lint.go
index cd6098a..c9ab9a9 100644
--- a/_linters/src/honnef.co/go/tools/staticcheck/lint.go
+++ b/_linters/src/honnef.co/go/tools/staticcheck/lint.go
@@ -10,7 +10,6 @@ import (
 	"go/types"
 	htmltemplate "html/template"
 	"net/http"
-	"runtime"
 	"strconv"
 	"strings"
 	"sync"
@@ -18,6 +17,7 @@ import (
 
 	"honnef.co/go/tools/functions"
 	"honnef.co/go/tools/gcsizes"
+	"honnef.co/go/tools/internal/sharedcheck"
 	"honnef.co/go/tools/lint"
 	"honnef.co/go/tools/ssa"
 	"honnef.co/go/tools/staticcheck/vrp"
@@ -33,6 +33,12 @@ func validRegexp(call *Call) {
 	}
 }
 
+type runeSlice []rune
+
+func (rs runeSlice) Len() int               { return len(rs) }
+func (rs runeSlice) Less(i int, j int) bool { return rs[i] < rs[j] }
+func (rs runeSlice) Swap(i int, j int)      { rs[i], rs[j] = rs[j], rs[i] }
+
 func utf8Cutset(call *Call) {
 	arg := call.Args[1]
 	if InvalidUTF8(arg.Value) {
@@ -40,6 +46,13 @@ func utf8Cutset(call *Call) {
 	}
 }
 
+func uniqueCutset(call *Call) {
+	arg := call.Args[1]
+	if !UniqueStringCutset(arg.Value) {
+		arg.Invalid(MsgNonUniqueCutset)
+	}
+}
+
 func unmarshalPointer(name string, arg int) CallCheck {
 	return func(call *Call) {
 		if !Pointer(call.Args[arg].Value) {
@@ -97,7 +110,7 @@ var (
 		},
 	}
 
-	checkDubiousSyncPoolSizeRules = map[string]CallCheck{
+	checkSyncPoolSizeRules = map[string]CallCheck{
 		"(*sync.Pool).Put": func(call *Call) {
 			// TODO(dh): allow users to pass in a custom build environment
 			sizes := gcsizes.ForArch(build.Default.GOARCH)
@@ -129,6 +142,12 @@ var (
 		"strings.TrimRight":    utf8Cutset,
 	}
 
+	checkUniqueCutsetRules = map[string]CallCheck{
+		"strings.Trim":      uniqueCutset,
+		"strings.TrimLeft":  uniqueCutset,
+		"strings.TrimRight": uniqueCutset,
+	}
+
 	checkUnmarshalPointerRules = map[string]CallCheck{
 		"encoding/xml.Unmarshal":          unmarshalPointer("xml.Unmarshal", 1),
 		"(*encoding/xml.Decoder).Decode":  unmarshalPointer("Decode", 0),
@@ -215,6 +234,7 @@ func (c *Checker) Funcs() map[string]lint.Func {
 		"SA1021": c.callChecker(checkBytesEqualIPRules),
 		"SA1022": c.CheckFlagUsage,
 		"SA1023": c.CheckWriterBufferModified,
+		"SA1024": c.callChecker(checkUniqueCutsetRules),
 
 		"SA2000": c.CheckWaitgroupAdd,
 		"SA2001": c.CheckEmptyCriticalSection,
@@ -235,7 +255,7 @@ func (c *Checker) Funcs() map[string]lint.Func {
 		"SA4007": nil,
 		"SA4008": c.CheckLoopCondition,
 		"SA4009": c.CheckArgOverwritten,
-		"SA4010": nil,
+		"SA4010": c.CheckIneffectiveAppend,
 		"SA4011": c.CheckScopedBreak,
 		"SA4012": c.CheckNaNComparison,
 		"SA4013": c.CheckDoubleNegation,
@@ -254,8 +274,11 @@ func (c *Checker) Funcs() map[string]lint.Func {
 		"SA5007": c.CheckInfiniteRecursion,
 
 		"SA6000": c.callChecker(checkRegexpMatchLoopRules),
+		"SA6001": c.CheckMapBytesKey,
+		"SA6002": c.callChecker(checkSyncPoolSizeRules),
+		"SA6003": c.CheckRangeStringRunes,
 
-		"SA9000": c.callChecker(checkDubiousSyncPoolSizeRules),
+		"SA9000": nil,
 		"SA9001": c.CheckDubiousDeferInChannelRangeLoop,
 		"SA9002": c.CheckNonOctalFileMode,
 		"SA9003": c.CheckEmptyBranch,
@@ -280,44 +303,32 @@ func (c *Checker) Init(prog *lint.Program) {
 	c.deprecatedObjs = map[types.Object]string{}
 	c.nodeFns = map[ast.Node]*ssa.Function{}
 
-	fns := prog.AllFunctions
-
-	var pwg sync.WaitGroup
-	var processFn func(*ssa.Function)
-	processFn = func(fn *ssa.Function) {
+	for _, fn := range prog.AllFunctions {
 		if fn.Blocks != nil {
 			applyStdlibKnowledge(fn)
 			ssa.OptimizeBlocks(fn)
 		}
-		pwg.Done()
-	}
-	for _, fn := range fns {
-		pwg.Add(1)
-		go processFn(fn)
 	}
-	pwg.Wait()
 
 	c.nodeFns = lint.NodeFns(prog.Packages)
 
-	chDeprecated := make(chan struct {
-		obj types.Object
-		msg string
-	}, runtime.NumCPU()*2)
+	deprecated := []map[types.Object]string{}
 	wg := &sync.WaitGroup{}
 	for _, pkginfo := range prog.Prog.AllPackages {
 		pkginfo := pkginfo
 		scope := pkginfo.Pkg.Scope()
 		names := scope.Names()
-		for _, name := range names {
-			name := name
-			wg.Add(1)
-			go func() {
+		wg.Add(1)
+
+		m := map[types.Object]string{}
+		deprecated = append(deprecated, m)
+		go func(m map[types.Object]string) {
+			for _, name := range names {
 				obj := scope.Lookup(name)
 				msg := c.deprecationMessage(pkginfo.Files, prog.SSA.Fset, obj)
-				chDeprecated <- struct {
-					obj types.Object
-					msg string
-				}{obj, msg}
+				if msg != "" {
+					m[obj] = msg
+				}
 				if typ, ok := obj.Type().Underlying().(*types.Struct); ok {
 					n := typ.NumFields()
 					for i := 0; i < n; i++ {
@@ -325,22 +336,20 @@ func (c *Checker) Init(prog *lint.Program) {
 						// fields in anonymous structs.
 						field := typ.Field(i)
 						msg := c.deprecationMessage(pkginfo.Files, prog.SSA.Fset, field)
-						chDeprecated <- struct {
-							obj types.Object
-							msg string
-						}{field, msg}
+						if msg != "" {
+							m[field] = msg
+						}
 					}
 				}
-				wg.Done()
-			}()
-		}
+			}
+			wg.Done()
+		}(m)
 	}
-	go func() {
-		wg.Wait()
-		close(chDeprecated)
-	}()
-	for dep := range chDeprecated {
-		c.deprecatedObjs[dep.obj] = dep.msg
+	wg.Wait()
+	for _, m := range deprecated {
+		for k, v := range m {
+			c.deprecatedObjs[k] = v
+		}
 	}
 }
 
@@ -489,7 +498,7 @@ func (c *Checker) CheckUntrappableSignal(j *lint.Job) {
 		if !ok {
 			return true
 		}
-		if !j.IsFunctionCallNameAny(call,
+		if !j.IsCallToAnyAST(call,
 			"os/signal.Ignore", "os/signal.Notify", "os/signal.Reset") {
 			return true
 		}
@@ -519,16 +528,16 @@ func (c *Checker) CheckTemplate(j *lint.Job) {
 			return true
 		}
 		var kind string
-		if j.IsFunctionCallName(call, "(*text/template.Template).Parse") {
+		if j.IsCallToAST(call, "(*text/template.Template).Parse") {
 			kind = "text"
-		} else if j.IsFunctionCallName(call, "(*html/template.Template).Parse") {
+		} else if j.IsCallToAST(call, "(*html/template.Template).Parse") {
 			kind = "html"
 		} else {
 			return true
 		}
 		sel := call.Fun.(*ast.SelectorExpr)
-		if !j.IsFunctionCallName(sel.X, "text/template.New") &&
-			!j.IsFunctionCallName(sel.X, "html/template.New") {
+		if !j.IsCallToAST(sel.X, "text/template.New") &&
+			!j.IsCallToAST(sel.X, "html/template.New") {
 			// TODO(dh): this is a cheap workaround for templates with
 			// different delims. A better solution with less false
 			// negatives would use data flow analysis to see where the
@@ -565,7 +574,7 @@ func (c *Checker) CheckTimeSleepConstant(j *lint.Job) {
 		if !ok {
 			return true
 		}
-		if !j.IsFunctionCallName(call, "time.Sleep") {
+		if !j.IsCallToAST(call, "time.Sleep") {
 			return true
 		}
 		lit, ok := call.Args[0].(*ast.BasicLit)
@@ -637,10 +646,36 @@ func (c *Checker) CheckWaitgroupAdd(j *lint.Job) {
 func (c *Checker) CheckInfiniteEmptyLoop(j *lint.Job) {
 	fn := func(node ast.Node) bool {
 		loop, ok := node.(*ast.ForStmt)
-		if !ok || len(loop.Body.List) != 0 || loop.Cond != nil || loop.Init != nil {
+		if !ok || len(loop.Body.List) != 0 || loop.Post != nil {
+			return true
+		}
+
+		if loop.Init != nil {
+			// TODO(dh): this isn't strictly necessary, it just makes
+			// the check easier.
+			return true
+		}
+		// An empty loop is bad news in two cases: 1) The loop has no
+		// condition. In that case, it's just a loop that spins
+		// forever and as fast as it can, keeping a core busy. 2) The
+		// loop condition only consists of variable or field reads and
+		// operators on those. The only way those could change their
+		// value is with unsynchronised access, which constitutes a
+		// data race.
+		//
+		// If the condition contains any function calls, its behaviour
+		// is dynamic and the loop might terminate. Similarly for
+		// channel receives.
+
+		if loop.Cond != nil && hasSideEffects(loop.Cond) {
 			return true
 		}
-		j.Errorf(loop, "should not use an infinite empty loop. It will spin. Consider select{} instead.")
+
+		j.Errorf(loop, "this loop will spin, using 100%% CPU")
+		if loop.Cond != nil {
+			j.Errorf(loop, "loop condition never changes or has a race condition")
+		}
+
 		return true
 	}
 	for _, f := range j.Program.Files {
@@ -753,7 +788,7 @@ func (c *Checker) CheckTestMainExit(j *lint.Job) {
 
 		callsExit := false
 		fn3 := func(node ast.Node) bool {
-			if j.IsFunctionCallName(node, "os.Exit") {
+			if j.IsCallToAST(node, "os.Exit") {
 				callsExit = true
 				return false
 			}
@@ -795,14 +830,14 @@ func (c *Checker) CheckExec(j *lint.Job) {
 		if !ok {
 			return true
 		}
-		if !j.IsFunctionCallName(call, "os/exec.Command") {
+		if !j.IsCallToAST(call, "os/exec.Command") {
 			return true
 		}
 		val, ok := j.ExprToString(call.Args[0])
 		if !ok {
 			return true
 		}
-		if !strings.Contains(val, " ") || strings.Contains(val, `\`) {
+		if !strings.Contains(val, " ") || strings.Contains(val, `\`) || strings.Contains(val, "/") {
 			return true
 		}
 		j.Errorf(call.Args[0], "first argument to exec.Command looks like a shell command, but a program name or path are expected")
@@ -870,11 +905,16 @@ func (c *Checker) CheckLhsRhsIdentical(j *lint.Job) {
 
 func (c *Checker) CheckScopedBreak(j *lint.Job) {
 	fn := func(node ast.Node) bool {
-		loop, ok := node.(*ast.ForStmt)
-		if !ok {
+		var body *ast.BlockStmt
+		switch node := node.(type) {
+		case *ast.ForStmt:
+			body = node.Body
+		case *ast.RangeStmt:
+			body = node.Body
+		default:
 			return true
 		}
-		for _, stmt := range loop.Body.List {
+		for _, stmt := range body.List {
 			var blocks [][]ast.Stmt
 			switch stmt := stmt.(type) {
 			case *ast.SwitchStmt:
@@ -930,7 +970,7 @@ func (c *Checker) CheckUnsafePrintf(j *lint.Job) {
 		if !ok {
 			return true
 		}
-		if !j.IsFunctionCallNameAny(call, "fmt.Printf", "fmt.Sprintf", "log.Printf") {
+		if !j.IsCallToAnyAST(call, "fmt.Printf", "fmt.Sprintf", "log.Printf") {
 			return true
 		}
 		if len(call.Args) != 1 {
@@ -1033,6 +1073,17 @@ func selectorX(sel *ast.SelectorExpr) ast.Node {
 }
 
 func (c *Checker) CheckEmptyCriticalSection(j *lint.Job) {
+	// Initially it might seem like this check would be easier to
+	// implement in SSA. After all, we're only checking for two
+	// consecutive method calls. In reality, however, there may be any
+	// number of other instructions between the lock and unlock, while
+	// still constituting an empty critical section. For example,
+	// given `m.x().Lock(); m.x().Unlock()`, there will be a call to
+	// x(). In the AST-based approach, this has a tiny potential for a
+	// false positive (the second call to x might be doing work that
+	// is protected by the mutex). In an SSA-based approach, however,
+	// it would miss a lot of real bugs.
+
 	mutexParams := func(s ast.Stmt) (x ast.Expr, funcName string, ok bool) {
 		expr, ok := s.(*ast.ExprStmt)
 		if !ok {
@@ -1313,15 +1364,20 @@ func (c *Checker) CheckIneffecitiveFieldAssignments(j *lint.Job) {
 
 func (c *Checker) CheckUnreadVariableValues(j *lint.Job) {
 	fn := func(node ast.Node) bool {
-		fn, ok := node.(*ast.FuncDecl)
-		if !ok {
+		switch node.(type) {
+		case *ast.FuncDecl, *ast.FuncLit:
+		default:
 			return true
 		}
-		ssafn := c.nodeFns[fn]
+
+		ssafn := c.nodeFns[node]
 		if ssafn == nil {
 			return true
 		}
-		ast.Inspect(fn, func(node ast.Node) bool {
+		if lint.IsExample(ssafn) {
+			return true
+		}
+		ast.Inspect(node, func(node ast.Node) bool {
 			assign, ok := node.(*ast.AssignStmt)
 			if !ok {
 				return true
@@ -1554,7 +1610,7 @@ func (c *Checker) CheckLoopCondition(j *lint.Job) {
 			return true
 		}
 
-		ssafn := j.EnclosingSSAFunction(cond)
+		ssafn := c.nodeFns[cond]
 		if ssafn == nil {
 			return true
 		}
@@ -1593,21 +1649,27 @@ func (c *Checker) CheckLoopCondition(j *lint.Job) {
 
 func (c *Checker) CheckArgOverwritten(j *lint.Job) {
 	fn := func(node ast.Node) bool {
-		fn, ok := node.(*ast.FuncDecl)
-		if !ok {
-			return true
+		var typ *ast.FuncType
+		var body *ast.BlockStmt
+		switch fn := node.(type) {
+		case *ast.FuncDecl:
+			typ = fn.Type
+			body = fn.Body
+		case *ast.FuncLit:
+			typ = fn.Type
+			body = fn.Body
 		}
-		if fn.Body == nil {
+		if body == nil {
 			return true
 		}
-		ssafn := c.nodeFns[fn]
+		ssafn := c.nodeFns[node]
 		if ssafn == nil {
 			return true
 		}
-		if len(fn.Type.Params.List) == 0 {
+		if len(typ.Params.List) == 0 {
 			return true
 		}
-		for _, field := range fn.Type.Params.List {
+		for _, field := range typ.Params.List {
 			for _, arg := range field.Names {
 				obj := j.Program.Info.ObjectOf(arg)
 				var ssaobj *ssa.Parameter
@@ -1629,7 +1691,7 @@ func (c *Checker) CheckArgOverwritten(j *lint.Job) {
 				}
 
 				assigned := false
-				ast.Inspect(fn.Body, func(node ast.Node) bool {
+				ast.Inspect(body, func(node ast.Node) bool {
 					assign, ok := node.(*ast.AssignStmt)
 					if !ok {
 						return true
@@ -1668,15 +1730,20 @@ func (c *Checker) CheckIneffectiveLoop(j *lint.Job) {
 	// - any nested, unlabelled continue, even if it is in another
 	// loop or closure.
 	fn := func(node ast.Node) bool {
-		fn, ok := node.(*ast.FuncDecl)
-		if !ok {
+		var body *ast.BlockStmt
+		switch fn := node.(type) {
+		case *ast.FuncDecl:
+			body = fn.Body
+		case *ast.FuncLit:
+			body = fn.Body
+		default:
 			return true
 		}
-		if fn.Body == nil {
+		if body == nil {
 			return true
 		}
 		labels := map[*ast.Object]ast.Stmt{}
-		ast.Inspect(fn.Body, func(node ast.Node) bool {
+		ast.Inspect(body, func(node ast.Node) bool {
 			label, ok := node.(*ast.LabeledStmt)
 			if !ok {
 				return true
@@ -1685,7 +1752,7 @@ func (c *Checker) CheckIneffectiveLoop(j *lint.Job) {
 			return true
 		})
 
-		ast.Inspect(fn.Body, func(node ast.Node) bool {
+		ast.Inspect(body, func(node ast.Node) bool {
 			var loop ast.Node
 			var body *ast.BlockStmt
 			switch node := node.(type) {
@@ -1835,6 +1902,72 @@ func (c *Checker) CheckSeeker(j *lint.Job) {
 	}
 }
 
+func (c *Checker) CheckIneffectiveAppend(j *lint.Job) {
+	isAppend := func(ins ssa.Value) bool {
+		call, ok := ins.(*ssa.Call)
+		if !ok {
+			return false
+		}
+		if call.Call.IsInvoke() {
+			return false
+		}
+		if builtin, ok := call.Call.Value.(*ssa.Builtin); !ok || builtin.Name() != "append" {
+			return false
+		}
+		return true
+	}
+
+	for _, ssafn := range j.Program.InitialFunctions {
+		for _, block := range ssafn.Blocks {
+			for _, ins := range block.Instrs {
+				val, ok := ins.(ssa.Value)
+				if !ok || !isAppend(val) {
+					continue
+				}
+
+				isUsed := false
+				visited := map[ssa.Instruction]bool{}
+				var walkRefs func(refs []ssa.Instruction)
+				walkRefs = func(refs []ssa.Instruction) {
+				loop:
+					for _, ref := range refs {
+						if visited[ref] {
+							continue
+						}
+						visited[ref] = true
+						if _, ok := ref.(*ssa.DebugRef); ok {
+							continue
+						}
+						switch ref := ref.(type) {
+						case *ssa.Phi:
+							walkRefs(*ref.Referrers())
+						case *ssa.Sigma:
+							walkRefs(*ref.Referrers())
+						case ssa.Value:
+							if !isAppend(ref) {
+								isUsed = true
+							} else {
+								walkRefs(*ref.Referrers())
+							}
+						case ssa.Instruction:
+							isUsed = true
+							break loop
+						}
+					}
+				}
+				refs := val.Referrers()
+				if refs == nil {
+					continue
+				}
+				walkRefs(*refs)
+				if !isUsed {
+					j.Errorf(ins, "this result of append is never used, except maybe in other appends")
+				}
+			}
+		}
+	}
+}
+
 func (c *Checker) CheckConcurrentTesting(j *lint.Job) {
 	for _, ssafn := range j.Program.InitialFunctions {
 		for _, block := range ssafn.Blocks {
@@ -1957,10 +2090,10 @@ func (c *Checker) CheckSliceOutOfBounds(j *lint.Job) {
 func (c *Checker) CheckDeferLock(j *lint.Job) {
 	for _, ssafn := range j.Program.InitialFunctions {
 		for _, block := range ssafn.Blocks {
-			if len(block.Instrs) < 2 {
+			instrs := lint.FilterDebug(block.Instrs)
+			if len(instrs) < 2 {
 				continue
 			}
-			instrs := lint.FilterDebug(block.Instrs)
 			for i, ins := range instrs[:len(instrs)-1] {
 				call, ok := ins.(*ssa.Call)
 				if !ok {
@@ -2114,6 +2247,24 @@ func (c *Checker) CheckDoubleNegation(j *lint.Job) {
 	}
 }
 
+func hasSideEffects(node ast.Node) bool {
+	dynamic := false
+	ast.Inspect(node, func(node ast.Node) bool {
+		switch node := node.(type) {
+		case *ast.CallExpr:
+			dynamic = true
+			return false
+		case *ast.UnaryExpr:
+			if node.Op == token.ARROW {
+				dynamic = true
+				return false
+			}
+		}
+		return true
+	})
+	return dynamic
+}
+
 func (c *Checker) CheckRepeatedIfElse(j *lint.Job) {
 	seen := map[ast.Node]bool{}
 
@@ -2129,23 +2280,6 @@ func (c *Checker) CheckRepeatedIfElse(j *lint.Job) {
 		}
 		return inits, conds
 	}
-	isDynamic := func(node ast.Node) bool {
-		dynamic := false
-		ast.Inspect(node, func(node ast.Node) bool {
-			switch node := node.(type) {
-			case *ast.CallExpr:
-				dynamic = true
-				return false
-			case *ast.UnaryExpr:
-				if node.Op == token.ARROW {
-					dynamic = true
-					return false
-				}
-			}
-			return true
-		})
-		return dynamic
-	}
 	fn := func(node ast.Node) bool {
 		ifstmt, ok := node.(*ast.IfStmt)
 		if !ok {
@@ -2159,7 +2293,7 @@ func (c *Checker) CheckRepeatedIfElse(j *lint.Job) {
 			return true
 		}
 		for _, cond := range conds {
-			if isDynamic(cond) {
+			if hasSideEffects(cond) {
 				return true
 			}
 		}
@@ -2581,6 +2715,10 @@ func (c *Checker) CheckEmptyBranch(j *lint.Job) {
 		if !ok {
 			return true
 		}
+		ssafn := c.nodeFns[node]
+		if lint.IsExample(ssafn) {
+			return true
+		}
 		if ifstmt.Else != nil {
 			b, ok := ifstmt.Else.(*ast.BlockStmt)
 			if !ok || len(b.List) != 0 {
@@ -2598,3 +2736,58 @@ func (c *Checker) CheckEmptyBranch(j *lint.Job) {
 		ast.Inspect(f, fn)
 	}
 }
+
+func (c *Checker) CheckMapBytesKey(j *lint.Job) {
+	for _, fn := range j.Program.InitialFunctions {
+		for _, b := range fn.Blocks {
+		insLoop:
+			for _, ins := range b.Instrs {
+				// find []byte -> string conversions
+				conv, ok := ins.(*ssa.Convert)
+				if !ok || conv.Type() != types.Universe.Lookup("string").Type() {
+					continue
+				}
+				if s, ok := conv.X.Type().(*types.Slice); !ok || s.Elem() != types.Universe.Lookup("byte").Type() {
+					continue
+				}
+				refs := conv.Referrers()
+				// need at least two (DebugRef) references: the
+				// conversion and the *ast.Ident
+				if refs == nil || len(*refs) < 2 {
+					continue
+				}
+				ident := false
+				// skip first reference, that's the conversion itself
+				for _, ref := range (*refs)[1:] {
+					switch ref := ref.(type) {
+					case *ssa.DebugRef:
+						if _, ok := ref.Expr.(*ast.Ident); !ok {
+							// the string seems to be used somewhere
+							// unexpected; the default branch should
+							// catch this already, but be safe
+							continue insLoop
+						} else {
+							ident = true
+						}
+					case *ssa.Lookup:
+					default:
+						// the string is used somewhere else than a
+						// map lookup
+						continue insLoop
+					}
+				}
+
+				// the result of the conversion wasn't assigned to an
+				// identifier
+				if !ident {
+					continue
+				}
+				j.Errorf(conv, "m[string(key)] would be more efficient than k := string(key); m[k]")
+			}
+		}
+	}
+}
+
+func (c *Checker) CheckRangeStringRunes(j *lint.Job) {
+	sharedcheck.CheckRangeStringRunes(c.nodeFns, j)
+}
diff --git a/_linters/src/honnef.co/go/tools/staticcheck/rules.go b/_linters/src/honnef.co/go/tools/staticcheck/rules.go
index 629e8ae..60cc00c 100644
--- a/_linters/src/honnef.co/go/tools/staticcheck/rules.go
+++ b/_linters/src/honnef.co/go/tools/staticcheck/rules.go
@@ -7,6 +7,7 @@ import (
 	"net"
 	"net/url"
 	"regexp"
+	"sort"
 	"strconv"
 	"strings"
 	"time"
@@ -20,6 +21,7 @@ import (
 const (
 	MsgInvalidHostPort = "invalid port or service name in host:port pair"
 	MsgInvalidUTF8     = "argument is not a valid UTF-8 encoded string"
+	MsgNonUniqueCutset = "cutset contains duplicate characters"
 )
 
 type Call struct {
@@ -294,3 +296,26 @@ func ConvertedFrom(v Value, typ string) bool {
 	change, ok := v.Value.(*ssa.ChangeType)
 	return ok && types.TypeString(change.X.Type(), nil) == typ
 }
+
+func UniqueStringCutset(v Value) bool {
+	for _, c := range extractConsts(v.Value) {
+		if c.Value == nil {
+			continue
+		}
+		if c.Value.Kind() != constant.String {
+			continue
+		}
+		s := constant.StringVal(c.Value)
+		rs := runeSlice(s)
+		if len(rs) < 2 {
+			continue
+		}
+		sort.Sort(rs)
+		for i, r := range rs[1:] {
+			if rs[i] == r {
+				return false
+			}
+		}
+	}
+	return true
+}
diff --git a/_linters/src/honnef.co/go/tools/staticcheck/vrp/vrp.go b/_linters/src/honnef.co/go/tools/staticcheck/vrp/vrp.go
index 8da2dbe..cb17f04 100644
--- a/_linters/src/honnef.co/go/tools/staticcheck/vrp/vrp.go
+++ b/_linters/src/honnef.co/go/tools/staticcheck/vrp/vrp.go
@@ -558,7 +558,7 @@ func (g *Graph) Solve() Ranges {
 				v := actives[len(actives)-1]
 				actives = actives[:len(actives)-1]
 				for _, use := range uses[v] {
-					if g.narrow(use, consts) {
+					if g.narrow(use) {
 						actives = append(actives, use.Y())
 					}
 				}
@@ -778,7 +778,7 @@ func (g *Graph) widen(c Constraint, consts []Z) bool {
 	}
 }
 
-func (g *Graph) narrow(c Constraint, consts []Z) bool {
+func (g *Graph) narrow(c Constraint) bool {
 	narrowIntInterval := func(oi, ni IntInterval) (IntInterval, bool) {
 		oLower := oi.Lower
 		oUpper := oi.Upper
diff --git a/_linters/src/manifest b/_linters/src/manifest
index 60be9ef..c07d181 100644
--- a/_linters/src/manifest
+++ b/_linters/src/manifest
@@ -304,7 +304,7 @@
 			"importpath": "honnef.co/go/tools/callgraph",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "callgraph",
 			"notests": true
@@ -313,16 +313,25 @@
 			"importpath": "honnef.co/go/tools/cmd/gosimple",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "/cmd/gosimple",
 			"notests": true
 		},
+		{
+			"importpath": "honnef.co/go/tools/cmd/megacheck",
+			"repository": "https://github.com/dominikh/go-tools",
+			"vcs": "git",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
+			"branch": "master",
+			"path": "/cmd/megacheck",
+			"notests": true
+		},
 		{
 			"importpath": "honnef.co/go/tools/cmd/staticcheck",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "/cmd/staticcheck",
 			"notests": true
@@ -331,7 +340,7 @@
 			"importpath": "honnef.co/go/tools/cmd/unused",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "/cmd/unused",
 			"notests": true
@@ -340,7 +349,7 @@
 			"importpath": "honnef.co/go/tools/functions",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "functions",
 			"notests": true
@@ -349,16 +358,25 @@
 			"importpath": "honnef.co/go/tools/gcsizes",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "gcsizes",
 			"notests": true
 		},
+		{
+			"importpath": "honnef.co/go/tools/internal/sharedcheck",
+			"repository": "https://github.com/dominikh/go-tools",
+			"vcs": "git",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
+			"branch": "master",
+			"path": "/internal/sharedcheck",
+			"notests": true
+		},
 		{
 			"importpath": "honnef.co/go/tools/lint",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "lint",
 			"notests": true
@@ -367,7 +385,7 @@
 			"importpath": "honnef.co/go/tools/simple",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "simple",
 			"notests": true
@@ -376,7 +394,7 @@
 			"importpath": "honnef.co/go/tools/ssa",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "ssa",
 			"notests": true
@@ -385,7 +403,7 @@
 			"importpath": "honnef.co/go/tools/staticcheck",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "staticcheck",
 			"notests": true
@@ -394,7 +412,7 @@
 			"importpath": "honnef.co/go/tools/unused",
 			"repository": "https://github.com/dominikh/go-tools",
 			"vcs": "git",
-			"revision": "89a8bf9d32d7bf42e8a6e83c21177a2a029a2f0c",
+			"revision": "e94d1c1a34c6b61d8d06c7793b8f22cd0dfcdd90",
 			"branch": "master",
 			"path": "unused",
 			"notests": true
diff --git a/config.go b/config.go
index ac1d4e0..9fffd6f 100644
--- a/config.go
+++ b/config.go
@@ -79,6 +79,7 @@ var (
 		"ineffassign": "github.com/gordonklaus/ineffassign",
 		"interfacer":  "github.com/mvdan/interfacer/cmd/interfacer",
 		"lll":         "github.com/walle/lll/cmd/lll",
+		"megacheck":   "honnef.co/go/tools/cmd/megacheck",
 		"misspell":    "github.com/client9/misspell/cmd/misspell",
 		"safesql":     "github.com/stripe/safesql",
 		"staticcheck": "honnef.co/go/tools/cmd/staticcheck",
@@ -88,50 +89,49 @@ var (
 		"unused":      "honnef.co/go/tools/cmd/unused",
 		"varcheck":    "github.com/opennota/check/cmd/varcheck",
 	}
-	acceptsEllipsis = map[string]bool{
-		"aligncheck":  true,
-		"errcheck":    true,
-		"golint":      true,
-		"gosimple":    true,
-		"interfacer":  true,
-		"staticcheck": true,
-		"structcheck": true,
-		"test":        true,
-		"varcheck":    true,
-		"unconvert":   true,
-	}
-	slowLinters = []string{"structcheck", "varcheck", "errcheck", "aligncheck", "testify", "test", "interfacer", "unconvert", "deadcode", "safesql", "staticcheck", "unparam", "unused", "gosimple"}
+	slowLinters = []string{"structcheck", "varcheck", "errcheck", "aligncheck", "testify", "test", "interfacer", "unconvert", "deadcode", "safesql", "staticcheck", "unparam", "unused", "gosimple", "megacheck"}
 	sortKeys    = []string{"none", "path", "line", "column", "severity", "message", "linter"}
 
+	linterTakesFiles = newStringSet([]string{
+		"dupl",
+		"gofmt",
+		"goimports",
+		"lll",
+		"misspell",
+		"vet",
+		"vetshadow",
+	}...)
+
 	// Linter definitions.
 	linterDefinitions = map[string]string{
-		"aligncheck":  `aligncheck {path}:^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
-		"deadcode":    `deadcode {path}:^deadcode: (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
-		"dupl":        `dupl -plumbing -threshold {duplthreshold} {path}/*.go:^(?P<path>.*?\.go):(?P<line>\d+)-\d+:\s*(?P<message>.*)$`,
-		"errcheck":    `errcheck -abspath {path}:PATH:LINE:COL:MESSAGE`,
-		"gas":         `gas -fmt=csv {path}/*.go:^(?P<path>.*?\.go),(?P<line>\d+),(?P<message>[^,]+,[^,]+,[^,]+)`,
-		"goconst":     `goconst -min-occurrences {min_occurrences} -min-length {min_const_length} {path}:PATH:LINE:COL:MESSAGE`,
-		"gocyclo":     `gocyclo -over {mincyclo} {path}:^(?P<cyclo>\d+)\s+\S+\s(?P<function>\S+)\s+(?P<path>.*?\.go):(?P<line>\d+):(\d+)$`,
-		"gofmt":       `gofmt -l -s {path}/*.go:^(?P<path>.*?\.go)$`,
-		"goimports":   `goimports -l {path}/*.go:^(?P<path>.*?\.go)$`,
-		"golint":      "golint -min_confidence {min_confidence} {path}:PATH:LINE:COL:MESSAGE",
-		"gosimple":    "gosimple {path}:PATH:LINE:COL:MESSAGE",
-		"gotype":      "gotype -e {tests=-a} {path}:PATH:LINE:COL:MESSAGE",
-		"ineffassign": `ineffassign -n {path}:PATH:LINE:COL:MESSAGE`,
-		"interfacer":  `interfacer {path}:PATH:LINE:COL:MESSAGE`,
-		"lll":         `lll -g -l {maxlinelength} {path}/*.go:PATH:LINE:MESSAGE`,
-		"misspell":    "misspell -j 1 {path}/*.go:PATH:LINE:COL:MESSAGE",
-		"safesql":     `safesql {path}:^- (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+)$`,
-		"staticcheck": "staticcheck {path}:PATH:LINE:COL:MESSAGE",
-		"structcheck": `structcheck {tests=-t} {path}:^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
-		"test":        `go test {path}:^--- FAIL: .*$\s+(?P<path>.*?\.go):(?P<line>\d+): (?P<message>.*)$`,
-		"testify":     `go test {path}:Location:\s+(?P<path>.*?\.go):(?P<line>\d+)$\s+Error:\s+(?P<message>[^\n]+)`,
-		"unconvert":   "unconvert {path}:PATH:LINE:COL:MESSAGE",
-		"unparam":     `unparam {path}:PATH:LINE:COL:MESSAGE`,
-		"unused":      `unused {path}:PATH:LINE:COL:MESSAGE`,
-		"varcheck":    `varcheck {path}:^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
-		"vet":         `go tool vet {path}/*.go:` + vetRe,
-		"vetshadow":   `go tool vet --shadow {path}/*.go:` + vetRe,
+		"aligncheck":  `aligncheck:^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
+		"deadcode":    `deadcode:^deadcode: (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
+		"dupl":        `dupl -plumbing -threshold {duplthreshold}:^(?P<path>.*?\.go):(?P<line>\d+)-\d+:\s*(?P<message>.*)$`,
+		"errcheck":    `errcheck -abspath:PATH:LINE:COL:MESSAGE`,
+		"gas":         `gas -fmt=csv:^(?P<path>.*?\.go),(?P<line>\d+),(?P<message>[^,]+,[^,]+,[^,]+)`,
+		"goconst":     `goconst -min-occurrences {min_occurrences} -min-length {min_const_length}:PATH:LINE:COL:MESSAGE`,
+		"gocyclo":     `gocyclo -over {mincyclo}:^(?P<cyclo>\d+)\s+\S+\s(?P<function>\S+)\s+(?P<path>.*?\.go):(?P<line>\d+):(\d+)$`,
+		"gofmt":       `gofmt -l -s:^(?P<path>.*?\.go)$`,
+		"goimports":   `goimports -l:^(?P<path>.*?\.go)$`,
+		"golint":      "golint -min_confidence {min_confidence}:PATH:LINE:COL:MESSAGE",
+		"gosimple":    "gosimple:PATH:LINE:COL:MESSAGE",
+		"gotype":      "gotype -e {tests=-a}:PATH:LINE:COL:MESSAGE",
+		"ineffassign": `ineffassign -n:PATH:LINE:COL:MESSAGE`,
+		"interfacer":  `interfacer:PATH:LINE:COL:MESSAGE`,
+		"lll":         `lll -g -l {maxlinelength}:PATH:LINE:MESSAGE`,
+		"megacheck":   "megacheck:PATH:LINE:COL:MESSAGE",
+		"misspell":    "misspell -j 1:PATH:LINE:COL:MESSAGE",
+		"safesql":     `safesql:^- (?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+)$`,
+		"staticcheck": "staticcheck:PATH:LINE:COL:MESSAGE",
+		"structcheck": `structcheck {tests=-t}:^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
+		"test":        `go test:^--- FAIL: .*$\s+(?P<path>.*?\.go):(?P<line>\d+): (?P<message>.*)$`,
+		"testify":     `go test:Location:\s+(?P<path>.*?\.go):(?P<line>\d+)$\s+Error:\s+(?P<message>[^\n]+)`,
+		"unconvert":   "unconvert:PATH:LINE:COL:MESSAGE",
+		"unparam":     `unparam:PATH:LINE:COL:MESSAGE`,
+		"unused":      `unused:PATH:LINE:COL:MESSAGE`,
+		"varcheck":    `varcheck:^(?:[^:]+: )?(?P<path>.*?\.go):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.*)$`,
+		"vet":         `go tool vet:` + vetRe,
+		"vetshadow":   `go tool vet --shadow:` + vetRe,
 	}
 
 	pathsArg = kingpin.Arg("path", "Directories to lint. Defaults to \".\". <path>/... will recurse.").Strings()
@@ -163,11 +163,10 @@ var (
 			"goconst",
 			"gocyclo",
 			"golint",
-			"gosimple",
 			"gotype",
 			"ineffassign",
 			"interfacer",
-			"staticcheck",
+			"megacheck",
 			"structcheck",
 			"unconvert",
 			"varcheck",
diff --git a/directives.go b/directives.go
index 107787b..b1cf1fb 100644
--- a/directives.go
+++ b/directives.go
@@ -31,7 +31,7 @@ func (i *ignoredRange) matches(issue *Issue) bool {
 	return false
 }
 
-func (i *ignoredRange) near(col, start, end int) bool {
+func (i *ignoredRange) near(col, start int) bool {
 	return col == i.col && i.end == start-1
 }
 
@@ -42,15 +42,13 @@ func (ir ignoredRanges) Swap(i, j int)      { ir[i], ir[j] = ir[j], ir[i] }
 func (ir ignoredRanges) Less(i, j int) bool { return ir[i].end < ir[j].end }
 
 type directiveParser struct {
-	paths []string
 	lock  sync.Mutex
 	files map[string]ignoredRanges
 	fset  *token.FileSet
 }
 
-func newDirectiveParser(paths []string) *directiveParser {
+func newDirectiveParser() *directiveParser {
 	return &directiveParser{
-		paths: paths,
 		files: map[string]ignoredRanges{},
 		fset:  token.NewFileSet(),
 	}
@@ -92,7 +90,7 @@ func (a *rangeExpander) Visit(node ast.Node) ast.Visitor {
 	found := sort.Search(len(a.ranges), func(i int) bool {
 		return a.ranges[i].end+1 >= start
 	})
-	if found < len(a.ranges) && a.ranges[found].near(startPos.Column, start, end) {
+	if found < len(a.ranges) && a.ranges[found].near(startPos.Column, start) {
 		r := a.ranges[found]
 		if r.start > start {
 			r.start = start
@@ -144,12 +142,6 @@ func extractCommentGroupRange(fset *token.FileSet, comments ...*ast.CommentGroup
 	return
 }
 
-func (d *directiveParser) in(n ast.Node, issue *Issue) bool {
-	start := d.fset.Position(n.Pos())
-	end := d.fset.Position(n.End())
-	return issue.Line >= start.Line && issue.Line <= end.Line
-}
-
 func filterIssuesViaDirectives(directives *directiveParser, issues chan *Issue) chan *Issue {
 	out := make(chan *Issue, 1000000)
 	go func() {
diff --git a/main.go b/main.go
index 70d147b..6ddd535 100644
--- a/main.go
+++ b/main.go
@@ -26,9 +26,9 @@ import (
 type Severity string
 
 // Linter message severity levels.
-const ( // nolint
-	Warning Severity = "warning"
+const ( // nolint: deadcode
 	Error   Severity = "error"
+	Warning Severity = "warning"
 )
 
 var (
@@ -42,7 +42,6 @@ var (
 type Linter struct {
 	Name             string   `json:"name"`
 	Command          string   `json:"command"`
-	CompositeCommand string   `json:"composite_command,omitempty"`
 	Pattern          string   `json:"pattern"`
 	InstallFrom      string   `json:"install_from"`
 	SeverityOverride Severity `json:"severity,omitempty"`
@@ -287,8 +286,6 @@ func (v Vars) Replace(s string) string {
 }
 
 func main() {
-	// Linters are by their very nature, short lived, so disable GC.
-	// Reduced (user) linting time on kingpin from 0.97s to 0.64s.
 	kingpin.CommandLine.Help = fmt.Sprintf(`Aggregate and normalise the output of a whole bunch of Go linters.
 
 PlaceHolder linters:
@@ -315,7 +312,7 @@ Severity override map (default is "warning"):
 
 	linters := lintersFromFlags()
 	status := 0
-	issues, errch := runLinters(linters, paths, *pathsArg, config.Concurrency, exclude, include)
+	issues, errch := runLinters(linters, paths, config.Concurrency, exclude, include)
 	if config.JSON {
 		status |= outputToJSON(issues)
 	} else if config.Checkstyle {
@@ -342,7 +339,10 @@ func processConfig(config *Config) (include *regexp.Regexp, exclude *regexp.Rege
 	tmpl, err := template.New("output").Parse(config.Format)
 	kingpin.FatalIfError(err, "invalid format %q", config.Format)
 	formatTemplate = tmpl
+
 	if !config.EnableGC {
+		// Linters are by their very nature, short lived, so disable GC.
+		// Reduced (user) linting time on kingpin from 0.97s to 0.64s.
 		_ = os.Setenv("GOGC", "off")
 	}
 	if config.VendoredLinters && config.Install && config.Update {
@@ -413,47 +413,50 @@ func outputToJSON(issues chan *Issue) int {
 	return status
 }
 
-func runLinters(linters map[string]*Linter, paths, ellipsisPaths []string, concurrency int, exclude *regexp.Regexp, include *regexp.Regexp) (chan *Issue, chan error) {
-	errch := make(chan error, len(linters)*(len(paths)+len(ellipsisPaths)))
-	concurrencych := make(chan bool, config.Concurrency)
+func runLinters(linters map[string]*Linter, paths []string, concurrency int, exclude, include *regexp.Regexp) (chan *Issue, chan error) {
+	errch := make(chan error)
+	concurrencych := make(chan bool, concurrency)
 	incomingIssues := make(chan *Issue, 1000000)
-	directives := newDirectiveParser(paths)
-	processedIssues := filterIssuesViaDirectives(directives, maybeSortIssues(maybeAggregateIssues(incomingIssues)))
+	processedIssues := filterIssuesViaDirectives(
+		newDirectiveParser(),
+		maybeSortIssues(maybeAggregateIssues(incomingIssues)))
+
+	vars := Vars{
+		"duplthreshold":    fmt.Sprintf("%d", config.DuplThreshold),
+		"mincyclo":         fmt.Sprintf("%d", config.Cyclo),
+		"maxlinelength":    fmt.Sprintf("%d", config.LineLength),
+		"min_confidence":   fmt.Sprintf("%f", config.MinConfidence),
+		"min_occurrences":  fmt.Sprintf("%d", config.MinOccurrences),
+		"min_const_length": fmt.Sprintf("%d", config.MinConstLength),
+		"tests":            "",
+	}
+	if config.Test {
+		vars["tests"] = "-t"
+	}
+
 	wg := &sync.WaitGroup{}
 	for _, linter := range linters {
-		// Recreated in each loop because it is mutated by executeLinter().
-		vars := Vars{
-			"duplthreshold":    fmt.Sprintf("%d", config.DuplThreshold),
-			"mincyclo":         fmt.Sprintf("%d", config.Cyclo),
-			"maxlinelength":    fmt.Sprintf("%d", config.LineLength),
-			"min_confidence":   fmt.Sprintf("%f", config.MinConfidence),
-			"min_occurrences":  fmt.Sprintf("%d", config.MinOccurrences),
-			"min_const_length": fmt.Sprintf("%d", config.MinConstLength),
-			"tests":            "",
-		}
-		if config.Test {
-			vars["tests"] = "-t"
-		}
-		linterPaths := paths
-		// Most linters don't exclude vendor paths when recursing, so we don't use ... paths.
-		if acceptsEllipsis[linter.Name] && !config.Vendor && len(ellipsisPaths) > 0 {
-			linterPaths = ellipsisPaths
-		}
-		for _, path := range linterPaths {
+		deadline := time.After(config.Deadline)
+		state := &linterState{
+			Linter:   linter,
+			issues:   incomingIssues,
+			paths:    paths,
+			vars:     vars.Copy(),
+			exclude:  exclude,
+			include:  include,
+			deadline: deadline,
+		}
+
+		partitions, err := state.Partitions()
+		if err != nil {
+			errch <- err
+			continue
+		}
+		for _, args := range partitions {
 			wg.Add(1)
-			deadline := time.After(config.Deadline)
-			state := &linterState{
-				Linter:   linter,
-				issues:   incomingIssues,
-				path:     path,
-				vars:     vars.Copy(),
-				exclude:  exclude,
-				include:  include,
-				deadline: deadline,
-			}
 			go func() {
 				concurrencych <- true
-				err := executeLinter(state)
+				err := executeLinter(state, args)
 				if err != nil {
 					errch <- err
 				}
@@ -471,15 +474,12 @@ func runLinters(linters map[string]*Linter, paths, ellipsisPaths []string, concu
 	return processedIssues, errch
 }
 
-// nolint: gocyclo
 func expandPaths(paths, skip []string) []string {
 	if len(paths) == 0 {
-		paths = []string{"."}
-	}
-	skipMap := map[string]bool{}
-	for _, name := range skip {
-		skipMap[name] = true
+		return []string{"."}
 	}
+
+	skipPath := newPathFilter(skip)
 	dirs := map[string]bool{}
 	for _, path := range paths {
 		if strings.HasSuffix(path, "/...") {
@@ -490,8 +490,7 @@ func expandPaths(paths, skip []string) []string {
 					return err
 				}
 
-				base := filepath.Base(p)
-				skip := skipMap[base] || skipMap[p] || (strings.ContainsAny(base[0:1], "_.") && base != "." && base != "..")
+				skip := skipPath(p)
 				if i.IsDir() {
 					if skip {
 						return filepath.SkipDir
@@ -507,7 +506,7 @@ func expandPaths(paths, skip []string) []string {
 	}
 	out := make([]string, 0, len(dirs))
 	for d := range dirs {
-		out = append(out, d)
+		out = append(out, relativePackagePath(d))
 	}
 	sort.Strings(out)
 	for _, d := range out {
@@ -516,6 +515,29 @@ func expandPaths(paths, skip []string) []string {
 	return out
 }
 
+func newPathFilter(skip []string) func(string) bool {
+	filter := map[string]bool{}
+	for _, name := range skip {
+		filter[name] = true
+	}
+
+	return func(path string) bool {
+		base := filepath.Base(path)
+		if filter[base] || filter[path] {
+			return true
+		}
+		return base != "." && base != ".." && strings.ContainsAny(base[0:1], "_.")
+	}
+}
+
+func relativePackagePath(dir string) string {
+	if filepath.IsAbs(dir) || strings.HasPrefix(dir, ".") {
+		return dir
+	}
+	// package names must start with a ./
+	return "./" + dir
+}
+
 func makeInstallCommand(linters ...string) []string {
 	cmd := []string{"get"}
 	if config.VendoredLinters {
@@ -615,9 +637,12 @@ func maybeSortIssues(issues chan *Issue) chan *Issue {
 	return out
 }
 
+// MaxCommandBytes is the maximum number of bytes used when executing a command
+const MaxCommandBytes = 32000
+
 type linterState struct {
 	*Linter
-	path     string
+	paths    []string
 	issues   chan *Issue
 	vars     Vars
 	exclude  *regexp.Regexp
@@ -625,21 +650,43 @@ type linterState struct {
 	deadline <-chan time.Time
 }
 
-func (l *linterState) InterpolatedCommand() string {
-	vars := l.vars.Copy()
-	if l.ShouldChdir() {
-		vars["path"] = "."
-	} else {
-		vars["path"] = l.path
+func (l *linterState) Paths() []string {
+	if !linterTakesFiles.contains(l.Name) {
+		return l.paths
+	}
+	filePaths := []string{}
+	for _, dir := range l.paths {
+		// ignore error because the glob pattern is hardcoded
+		paths, _ := filepath.Glob(filepath.Join(dir, "*.go"))
+		filePaths = append(filePaths, paths...)
 	}
-	return vars.Replace(l.Command)
+	return filePaths
 }
 
-func (l *linterState) ShouldChdir() bool {
-	return config.Vendor || !strings.HasSuffix(l.path, "/...") || !strings.Contains(l.Command, "{path}")
+func (l *linterState) Partitions() ([][]string, error) {
+	command := l.vars.Replace(l.Command)
+	cmd, args, err := parseCommand(command, l.Paths())
+	if err != nil {
+		return nil, err
+	}
+
+	partitions := [][]string{}
+	current := []string{cmd}
+	size := len(cmd)
+	for _, arg := range args {
+		if size+len(arg)+1 >= MaxCommandBytes {
+			partitions = append(partitions, current)
+			current = []string{cmd, arg}
+			size = len(cmd) + len(arg) + 1
+			continue
+		}
+		current = append(current, arg)
+		size += len(arg)
+	}
+	return append(partitions, current), nil
 }
 
-func parseCommand(dir, command string) (string, []string, error) {
+func parseCommand(command string, paths []string) (string, []string, error) {
 	args, err := shlex.Split(command)
 	if err != nil {
 		return "", nil, err
@@ -651,45 +698,23 @@ func parseCommand(dir, command string) (string, []string, error) {
 	if err != nil {
 		return "", nil, err
 	}
-	out := []string{}
-	for _, arg := range args[1:] {
-		if strings.Contains(arg, "*") {
-			pattern := filepath.Join(dir, arg)
-			globbed, err := filepath.Glob(pattern)
-			if err != nil {
-				return "", nil, err
-			}
-			for i, g := range globbed {
-				if strings.HasPrefix(g, dir+string(filepath.Separator)) {
-					globbed[i] = g[len(dir)+1:]
-				}
-			}
-			out = append(out, globbed...)
-		} else {
-			out = append(out, arg)
-		}
-	}
-	return exe, out, nil
+	return exe, append(args[1:], paths...), nil
 }
 
-func executeLinter(state *linterState) error {
-	debug("linting with %s: %s (on %s)", state.Name, state.Command, state.path)
+func executeLinter(state *linterState, args []string) error {
+	if len(args) == 0 {
+		return fmt.Errorf("missing linter command")
+	}
+	debug("linting with %s: %s", state.Name, state.Command)
 
 	start := time.Now()
-	command := state.InterpolatedCommand()
-	exe, args, err := parseCommand(state.path, command)
-	if err != nil {
-		return err
-	}
-	debug("executing %s %q", exe, args)
+	debug("executing %s", strings.Join(args, " "))
 	buf := bytes.NewBuffer(nil)
-	cmd := exec.Command(exe, args...) // nolint: gas
-	if state.ShouldChdir() {
-		cmd.Dir = state.path
-	}
+	command := args[0]
+	cmd := exec.Command(command, args[1:]...) // nolint: gas
 	cmd.Stdout = buf
 	cmd.Stderr = buf
-	err = cmd.Start()
+	err := cmd.Start()
 	if err != nil {
 		return fmt.Errorf("failed to execute linter %s: %s", command, err)
 	}
@@ -705,8 +730,8 @@ func executeLinter(state *linterState) error {
 	case <-done:
 
 	case <-state.deadline:
-		err = fmt.Errorf("deadline exceeded by linter %s on %s (try increasing --deadline)",
-			state.Name, state.path)
+		err = fmt.Errorf("deadline exceeded by linter %s (try increasing --deadline)",
+			state.Name)
 		kerr := cmd.Process.Kill()
 		if kerr != nil {
 			warning("failed to kill %s: %s", state.Name, kerr)
@@ -715,7 +740,7 @@ func executeLinter(state *linterState) error {
 	}
 
 	if err != nil {
-		debug("warning: %s returned %s", command, err)
+		debug("warning: %s returned %s: %s", command, err, buf.String())
 	}
 
 	processOutput(state, buf.Bytes())
@@ -724,25 +749,9 @@ func executeLinter(state *linterState) error {
 	return nil
 }
 
-func (l *linterState) fixPath(path string) string {
-	lpath := strings.TrimSuffix(l.path, "...")
-	labspath, _ := filepath.Abs(lpath)
-
-	if !l.ShouldChdir() {
-		path = strings.TrimPrefix(path, lpath)
-	}
-
-	if !filepath.IsAbs(path) {
-		path, _ = filepath.Abs(filepath.Join(labspath, path))
-	}
-	if strings.HasPrefix(path, labspath) {
-		return filepath.Join(lpath, strings.TrimPrefix(path, labspath))
-	}
-	return path
-}
-
 func lintersFromFlags() map[string]*Linter {
 	out := map[string]*Linter{}
+	config.Enable = replaceWithMegacheck(config.Enable)
 	for _, linter := range config.Enable {
 		out[linter] = LinterFromName(linter)
 	}
@@ -757,11 +766,49 @@ func lintersFromFlags() map[string]*Linter {
 	return out
 }
 
+// replaceWithMegacheck checks enabled linters if they duplicate megacheck and
+// returns a either a revised list removing those and adding megacheck or an
+// unchanged slice. Emits a warning if linters were removed and swapped with
+// megacheck.
+func replaceWithMegacheck(enabled []string) []string {
+	var (
+		staticcheck,
+		gosimple,
+		unused bool
+		revised []string
+	)
+	for _, linter := range enabled {
+		switch linter {
+		case "staticcheck":
+			staticcheck = true
+		case "gosimple":
+			gosimple = true
+		case "unused":
+			unused = true
+		case "megacheck":
+			// Don't add to revised slice, we'll add it later
+		default:
+			revised = append(revised, linter)
+		}
+	}
+	if staticcheck && gosimple && unused {
+		warning("staticcheck, gosimple, and unused are all set, using megacheck instead")
+		return append(revised, "megacheck")
+	}
+	return enabled
+}
+
 // nolint: gocyclo
 func processOutput(state *linterState, out []byte) {
 	re := state.regex
 	all := re.FindAllSubmatchIndex(out, -1)
 	debug("%s hits %d: %s", state.Name, len(all), state.Pattern)
+
+	cwd, err := os.Getwd()
+	if err != nil {
+		warning("failed to get working directory %s", err)
+	}
+
 	for _, indices := range all {
 		group := [][]byte{}
 		for i := 0; i < len(indices); i += 2 {
@@ -784,7 +831,7 @@ func processOutput(state *linterState, out []byte) {
 			}
 			switch name {
 			case "path":
-				issue.Path = state.fixPath(part)
+				issue.Path = relativePath(cwd, part)
 
 			case "line":
 				n, err := strconv.ParseInt(part, 10, 32)
@@ -821,6 +868,18 @@ func processOutput(state *linterState, out []byte) {
 	return
 }
 
+func relativePath(root, path string) string {
+	if !filepath.IsAbs(path) {
+		return path
+	}
+	relative, err := filepath.Rel(root, path)
+	if err != nil {
+		warning("failed to make %s a relative path: %s", path, err)
+		return path
+	}
+	return relative
+}
+
 func findVendoredLinters() string {
 	gopaths := strings.Split(getGoPath(), string(os.PathListSeparator))
 	for _, home := range vendoredSearchPaths {
@@ -833,7 +892,6 @@ func findVendoredLinters() string {
 		}
 	}
 	return ""
-
 }
 
 // Go 1.8 compatible GOPATH.
@@ -906,3 +964,33 @@ func configureEnvironment() {
 	}
 	debug("GOBIN=%s", os.Getenv("GOBIN"))
 }
+
+// TODO: replace dirs in expandPaths() and addPath() with a set (others?)
+type stringSet struct {
+	items map[string]struct{}
+}
+
+func newStringSet(items ...string) *stringSet {
+	setItems := make(map[string]struct{}, len(items))
+	for _, item := range items {
+		setItems[item] = struct{}{}
+	}
+	return &stringSet{items: setItems}
+}
+
+func (s *stringSet) add(item string) {
+	s.items[item] = struct{}{}
+}
+
+func (s *stringSet) contains(item string) bool {
+	_, exists := s.items[item]
+	return exists
+}
+
+func (s *stringSet) asSlice() []string {
+	items := []string{}
+	for item := range s.items {
+		items = append(items, item)
+	}
+	return items
+}


Test patch:
diff --git a/main_test.go b/main_test.go
index 15fb069..8b0d78d 100644
--- a/main_test.go
+++ b/main_test.go
@@ -1,12 +1,126 @@
 package main
 
 import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
 	"sort"
 	"testing"
 
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
+func TestRelativePackagePath(t *testing.T) {
+	var testcases = []struct {
+		dir      string
+		expected string
+	}{
+		{
+			dir:      "/abs/path",
+			expected: "/abs/path",
+		},
+		{
+			dir:      ".",
+			expected: ".",
+		},
+		{
+			dir:      "./foo",
+			expected: "./foo",
+		},
+		{
+			dir:      "relative/path",
+			expected: "./relative/path",
+		},
+	}
+
+	for _, testcase := range testcases {
+		assert.Equal(t, testcase.expected, relativePackagePath(testcase.dir))
+	}
+}
+
+func TestExpandPathsNoPaths(t *testing.T) {
+	paths := expandPaths(nil, nil)
+	assert.Equal(t, []string{"."}, paths)
+}
+
+func TestExpandPathsNoExpands(t *testing.T) {
+	// Non-expanded paths should not be filtered by the skip path list
+	paths := expandPaths([]string{".", "foo", "foo/bar"}, []string{"foo/bar"})
+	expected := []string{".", "./foo", "./foo/bar"}
+	assert.Equal(t, expected, paths)
+}
+
+func TestExpandPathsWithExpands(t *testing.T) {
+	tmpdir, cleanup := setupTempDir(t)
+	defer cleanup()
+
+	mkGoFile(t, tmpdir)
+	mkDir(t, tmpdir, "exclude")
+	mkDir(t, tmpdir, "other", "exclude")
+	mkDir(t, tmpdir, "include")
+	mkDir(t, tmpdir, "include", "foo")
+	mkDir(t, tmpdir, "duplicate")
+	mkDir(t, tmpdir, ".exclude")
+	mkDir(t, tmpdir, "include", ".exclude")
+	mkDir(t, tmpdir, "_exclude")
+	mkDir(t, tmpdir, "include", "_exclude")
+
+	filterPaths := []string{"exclude", "other/exclude"}
+	paths := expandPaths([]string{"./...", "foo", "duplicate"}, filterPaths)
+
+	expected := []string{
+		".",
+		"./duplicate",
+		"./foo",
+		"./include",
+		"./include/foo",
+	}
+	assert.Equal(t, expected, paths)
+}
+
+func setupTempDir(t *testing.T) (string, func()) {
+	tmpdir, err := ioutil.TempDir("", "test-expand-paths")
+	require.NoError(t, err)
+
+	oldwd, err := os.Getwd()
+	require.NoError(t, err)
+	require.NoError(t, os.Chdir(tmpdir))
+
+	return tmpdir, func() {
+		os.RemoveAll(tmpdir)
+		require.NoError(t, os.Chdir(oldwd))
+	}
+}
+
+func mkDir(t *testing.T, paths ...string) {
+	fullPath := filepath.Join(paths...)
+	require.NoError(t, os.MkdirAll(fullPath, 0755))
+	mkGoFile(t, fullPath)
+}
+
+func mkGoFile(t *testing.T, path string) {
+	content := []byte("package foo")
+	err := ioutil.WriteFile(filepath.Join(path, "file.go"), content, 0644)
+	require.NoError(t, err)
+}
+
+func TestLinterStatePaths(t *testing.T) {
+	tmpdir, cleanup := setupTempDir(t)
+	defer cleanup()
+
+	mkGoFile(t, tmpdir)
+	mkDir(t, tmpdir, "two")
+	mkDir(t, tmpdir, "two", "three")
+
+	state := linterState{
+		Linter: &Linter{Name: "gofmt"},
+		paths:  []string{".", "./two", "./two/three"},
+	}
+	expected := []string{"file.go", "two/file.go", "two/three/file.go"}
+	assert.Equal(t, expected, state.Paths())
+}
+
 func TestSortedIssues(t *testing.T) {
 	actual := []*Issue{
 		{Path: "b.go", Line: 5},
diff --git a/regressiontests/megacheck_test.go b/regressiontests/megacheck_test.go
new file mode 100644
index 0000000..1c41dbc
--- /dev/null
+++ b/regressiontests/megacheck_test.go
@@ -0,0 +1,21 @@
+package regressiontests
+
+import "testing"
+
+func TestMegaCheck(t *testing.T) {
+	t.Parallel()
+	source := `package test
+
+func f() {
+	var ok bool
+	if ok == true {
+	}
+}
+`
+	expected := Issues{
+		{Linter: "megacheck", Severity: "warning", Path: "test.go", Line: 3, Col: 6, Message: "func f is unused (U1000)"},
+		{Linter: "megacheck", Severity: "warning", Path: "test.go", Line: 5, Col: 2, Message: "empty branch (SA9003)"},
+		{Linter: "megacheck", Severity: "warning", Path: "test.go", Line: 5, Col: 5, Message: "should omit comparison to bool constant, can be simplified to ok (S1002)"},
+	}
+	ExpectIssues(t, "megacheck", source, expected)
+}
diff --git a/regressiontests/support.go b/regressiontests/support.go
index b1ce418..243e57c 100644
--- a/regressiontests/support.go
+++ b/regressiontests/support.go
@@ -1,6 +1,7 @@
 package regressiontests
 
 import (
+	"bytes"
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
@@ -12,6 +13,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 type Issue struct {
@@ -42,32 +44,28 @@ func (e Issues) Less(i, j int) bool { return e[i].String() < e[j].String() }
 func ExpectIssues(t *testing.T, linter string, source string, expected Issues, extraFlags ...string) {
 	// Write source to temporary directory.
 	dir, err := ioutil.TempDir(".", "gometalinter-")
-	if !assert.NoError(t, err) {
-		return
-	}
+	require.NoError(t, err)
 	defer os.RemoveAll(dir)
-	w, err := os.Create(filepath.Join(dir, "test.go"))
-	if !assert.NoError(t, err) {
-		return
-	}
-	defer os.Remove(w.Name())
-	_, err = w.WriteString(source)
-	_ = w.Close()
-	if !assert.NoError(t, err) {
-		return
-	}
+
+	testFile := filepath.Join(dir, "test.go")
+	err = ioutil.WriteFile(testFile, []byte(source), 0644)
+	require.NoError(t, err)
 
 	// Run gometalinter.
-	args := []string{"go", "run", "../main.go", "../directives.go", "../config.go", "../checkstyle.go", "../aggregate.go", "--disable-all", "--enable", linter, "--json", dir}
+	binary, cleanup := buildBinary(t)
+	defer cleanup()
+	args := []string{"-d", "--disable-all", "--enable", linter, "--json", dir}
 	args = append(args, extraFlags...)
-	cmd := exec.Command(args[0], args[1:]...)
-	if !assert.NoError(t, err) {
-		return
-	}
+	cmd := exec.Command(binary, args...)
+	errBuffer := new(bytes.Buffer)
+	cmd.Stderr = errBuffer
+	require.NoError(t, err)
+
 	output, _ := cmd.Output()
 	var actual Issues
 	err = json.Unmarshal(output, &actual)
 	if !assert.NoError(t, err) {
+		fmt.Printf("Stderr: %s\n", errBuffer)
 		fmt.Printf("Output: %s\n", output)
 		return
 	}
@@ -78,7 +76,7 @@ func ExpectIssues(t *testing.T, linter string, source string, expected Issues, e
 		if issue.Linter == linter || linter == "" {
 			// Normalise path.
 			issue.Path = "test.go"
-			issue.Message = strings.Replace(issue.Message, w.Name(), "test.go", -1)
+			issue.Message = strings.Replace(issue.Message, testFile, "test.go", -1)
 			issue.Message = strings.Replace(issue.Message, dir, "", -1)
 			actualForLinter = append(actualForLinter, issue)
 		}
@@ -86,5 +84,17 @@ func ExpectIssues(t *testing.T, linter string, source string, expected Issues, e
 	sort.Sort(expected)
 	sort.Sort(actualForLinter)
 
-	assert.Equal(t, expected, actualForLinter)
+	if !assert.Equal(t, expected, actualForLinter) {
+		fmt.Printf("Stderr: %s\n", errBuffer)
+		fmt.Printf("Output: %s\n", output)
+	}
+}
+
+func buildBinary(t *testing.T) (string, func()) {
+	tmpdir, err := ioutil.TempDir("", "regression-test")
+	require.NoError(t, err)
+	path := filepath.Join(tmpdir, "binary")
+	cmd := exec.Command("go", "build", "-o", path, "..")
+	require.NoError(t, cmd.Run())
+	return path, func() { os.RemoveAll(tmpdir) }
 }