go/analysis: several API renamings

                 Analysis -> Analyzer
                 Unit     -> Pass
                 Output   -> Result
                 Inputs   -> ResultOf
                 Lemma    -> Fact
 Set{Object,Package}Lemma -> Export{Object,Package}Fact
    {Object,Package}Lemma -> Import{Object,Package}Fact
               LemmaTypes -> UsesFacts bool
                 plugins/ -> passes/

Notes:
- Unit.Output is no longer a field; it's the result of calling Analyzer.Run.
- Because analyzers no longer declare their LemmaTypes, they, not the
  driver, are now responsible for registering Fact types with Gob.

A follow-up change will additionally rename:

                  Finding -> Report
              Pass.Syntax -> Pass.Files
                Pass.Info -> Pass.TypesInfo

Change-Id: Iccbdadbea5a0aafe732e23a344dd57fd93681931
Reviewed-on: https://go-review.googlesource.com/137095
Reviewed-by: Ian Cottrell <iancottrell@google.com>
diff --git a/go/analysis/analysis.go b/go/analysis/analysis.go
index e103fde..b1befed 100644
--- a/go/analysis/analysis.go
+++ b/go/analysis/analysis.go
@@ -1,4 +1,4 @@
-// The analysis package defines a uniform interface for static checkers
+// The analysis package defines a uniform interface for static checkers ("Analyzers")
 // of Go source code. By implementing a common interface, checkers from
 // a variety of sources can be easily selected, incorporated, and reused
 // in a wide range of programs including command-line tools, text
@@ -6,7 +6,7 @@
 // and batch pipelines for large code bases. For the design, see
 // https://docs.google.com/document/d/1-azPLXaLgTCKeKDNg0HVMq2ovMlD-e7n1ZHzZVzOlJk
 //
-// Each analysis is invoked once per Go package, and is provided the
+// Each analyzer is invoked once per Go package, and is provided the
 // abstract syntax trees (ASTs) and type information for that package.
 //
 // The principal data types of this package are structs, not interfaces,
@@ -22,65 +22,74 @@
 	"reflect"
 )
 
-// An Analysis describes an analysis function and its options.
-type Analysis struct {
-	// The Name of the analysis must be a valid Go identifier
+// An Analyzer describes an analysis function and its options.
+type Analyzer struct {
+	// The Name of the analyzer must be a valid Go identifier
 	// as it may appear in command-line flags, URLs, and so on.
 	Name string
 
-	// Doc is the documentation for the analysis.
+	// Doc is the documentation for the analyzer.
 	Doc string
 
-	// Flags defines any flags accepted by the analysis.
+	// Flags defines any flags accepted by the analyzer.
 	// The manner in which these flags are exposed to the user
-	// depends on the driver which runs the analysis.
+	// depends on the driver which runs the analyzer.
 	Flags flag.FlagSet
 
-	// Run applies the analysis to a package.
-	// It returns an error if the analysis failed.
-	Run func(*Unit) error
+	// Run applies the analyzer to a package.
+	// It returns an error if the analyzer failed.
+	//
+	// On success, the Run function may return a result
+	// computed by the Analyzer; its type must match ResultType.
+	// The driver makes this result available as an input to
+	// another Analyzer that depends directly on this one (see
+	// Requires) when it analyzes the same package.
+	//
+	// To pass analysis results between packages (and thus
+	// potentially between address spaces), use Facts, which are
+	// serializable.
+	Run func(*Pass) (interface{}, error)
 
 	// RunDespiteErrors allows the driver to invoke
-	// the Run method of this analysis even on a
+	// the Run method of this analyzer even on a
 	// package that contains parse or type errors.
 	RunDespiteErrors bool
 
-	// Requires is a set of analyses that must run successfully
-	// before this one on a given package. This analysis may inspect
-	// the outputs produced by each analysis in Requires.
-	// The graph over analyses implied by Requires edges must be acyclic.
+	// Requires is a set of analyzers that must run successfully
+	// before this one on a given package. This analyzer may inspect
+	// the outputs produced by each analyzer in Requires.
+	// The graph over analyzers implied by Requires edges must be acyclic.
 	//
 	// Requires establishes a "horizontal" dependency between
-	// analysis units (different analyses, same package).
-	Requires []*Analysis
+	// analysis passes (different analyzers, same package).
+	Requires []*Analyzer
 
-	// OutputType is the type of the optional Output value
-	// computed by this analysis and stored in Unit.Output.
-	// (The Output is provided as an Input to
-	// each analysis that Requires this one.)
-	OutputType reflect.Type
+	// ResultType is the type of the optional result of the Run function.
+	ResultType reflect.Type
 
-	// LemmaTypes is the set of types of lemmas produced and
-	// consumed by this analysis. An analysis that uses lemmas
-	// may assume that its import dependencies have been
-	// similarly analyzed before it runs. Lemmas are pointers.
+	// UsesFacts indicates that this analyzer produces and consumes Facts.
+	// An analyzer that uses facts may assume that its import
+	// dependencies have been similarly analyzed before it runs.
+	// Facts are pointers.
 	//
-	// LemmaTypes establishes a "vertical" dependency between
-	// analysis units (same analysis, different packages).
-	LemmaTypes []reflect.Type
+	// UsesFacts establishes a "vertical" dependency between
+	// analysis passes (same analyzer, different packages).
+	UsesFacts bool
 }
 
-func (a *Analysis) String() string { return a.Name }
+func (a *Analyzer) String() string { return a.Name }
 
-// A Unit provides information to the Run function that
-// applies a specific analysis to a single Go package.
+// A Pass provides information to the Run function that
+// applies a specific analyzer to a single Go package.
 //
 // It forms the interface between the analysis logic and the driver
 // program, and has both input and an output components.
-type Unit struct {
+//
+// As in a compiler, one pass may depend on the result computed by another.
+type Pass struct {
 	// -- inputs --
 
-	Analysis *Analysis // the identity of the current analysis
+	Analyzer *Analyzer // the identity of the current analyzer
 
 	// syntax and type information
 	Fset   *token.FileSet // file position information
@@ -88,28 +97,25 @@
 	Pkg    *types.Package // type information about the package
 	Info   *types.Info    // type information about the syntax trees
 
-	// Inputs provides the inputs to this analysis unit, which are
-	// the corresponding outputs of its prerequisite analysis.
+	// ResultOf provides the inputs to this analysis pass, which are
+	// the corresponding results of its prerequisite analyzers.
 	// The map keys are the elements of Analysis.Required,
 	// and the type of each corresponding value is the required
-	// analysis's OutputType.
-	Inputs map[*Analysis]interface{}
+	// analysis's ResultType.
+	ResultOf map[*Analyzer]interface{}
 
-	// ObjectLemma retrieves a lemma associated with obj.
-	// Given a value ptr of type *T, where *T satisfies Lemma,
-	// ObjectLemma copies the value to *ptr.
+	// ImportObjectFact retrieves a fact associated with obj.
+	// Given a value ptr of type *T, where *T satisfies Fact,
+	// ImportObjectFact copies the value to *ptr.
 	//
-	// ObjectLemma may panic if applied to a lemma type that
-	// the analysis did not declare among its LemmaTypes,
-	// or if called after analysis of the unit is complete.
-	//
-	// ObjectLemma is not concurrency-safe.
-	ObjectLemma func(obj types.Object, lemma Lemma) bool
+	// ImportObjectFact panics if called after the pass is complete.
+	// ImportObjectFact is not concurrency-safe.
+	ImportObjectFact func(obj types.Object, fact Fact) bool
 
-	// PackageLemma retrives a lemma associated with package pkg,
-	// which must be this package or one if its dependencies.
-	// See comments for ObjectLemma.
-	PackageLemma func(pkg *types.Package, lemma Lemma) bool
+	// ImportPackageFact retrieves a fact associated with package pkg,
+	// which must be this package or one of its dependencies.
+	// See comments for ImportObjectFact.
+	ImportPackageFact func(pkg *types.Package, fact Fact) bool
 
 	// -- outputs --
 
@@ -118,32 +124,17 @@
 	// It is populated by the Run function.
 	Findings []*Finding
 
-	// SetObjectLemma associates a lemma of type *T with the obj,
-	// replacing any previous lemma of that type.
+	// ExportObjectFact associates a fact of type *T with the obj,
+	// replacing any previous fact of that type.
 	//
-	// SetObjectLemma panics if the lemma's type is not among
-	// Analysis.LemmaTypes, or if obj does not belong to the package
-	// being analyzed, or if it is called after analysis of the unit
-	// is complete.
-	//
-	// SetObjectLemma is not concurrency-safe.
-	SetObjectLemma func(obj types.Object, lemma Lemma)
+	// ExportObjectFact panics if it is called after the pass is
+	// complete, or if obj does not belong to the package being analyzed.
+	// ExportObjectFact is not concurrency-safe.
+	ExportObjectFact func(obj types.Object, fact Fact)
 
-	// SetPackageLemma associates a lemma with the current package.
-	// See comments for SetObjectLemma.
-	SetPackageLemma func(lemma Lemma)
-
-	// Output is an immutable result computed by this analysis unit
-	// and set by the Run function.
-	// It will be made available as an input to any analysis that
-	// depends directly on this one; see Analysis.Requires.
-	// Its type must match Analysis.OutputType.
-	//
-	// Outputs are available as Inputs to later analyses of the
-	// same package. To pass analysis results between packages (and
-	// thus potentially between address spaces), use Lemmas, which
-	// are serializable.
-	Output interface{}
+	// ExportPackageFact associates a fact with the current package.
+	// See comments for ExportObjectFact.
+	ExportPackageFact func(fact Fact)
 
 	/* Further fields may be added in future. */
 	// For example, suggested or applied refactorings.
@@ -151,58 +142,59 @@
 
 // Findingf is a helper function that creates a new Finding using the
 // specified position and formatted error message, appends it to
-// unit.Findings, and returns it.
-func (unit *Unit) Findingf(pos token.Pos, format string, args ...interface{}) *Finding {
+// pass.Findings, and returns it.
+func (pass *Pass) Findingf(pos token.Pos, format string, args ...interface{}) *Finding {
 	msg := fmt.Sprintf(format, args...)
 	f := &Finding{Pos: pos, Message: msg}
-	unit.Findings = append(unit.Findings, f)
+	pass.Findings = append(pass.Findings, f)
 	return f
 }
 
-func (unit *Unit) String() string {
-	return fmt.Sprintf("%s@%s", unit.Analysis.Name, unit.Pkg.Path())
+func (pass *Pass) String() string {
+	return fmt.Sprintf("%s@%s", pass.Analyzer.Name, pass.Pkg.Path())
 }
 
-// A Lemma is an intermediate fact produced during analysis.
+// A Fact is an intermediate fact produced during analysis.
 //
-// Each lemma is associated with a named declaration (a types.Object).
-// A single object may have multiple associated lemmas, but only one of
-// any particular lemma type.
+// Each fact is associated with a named declaration (a types.Object).
+// A single object may have multiple associated facts, but only one of
+// any particular fact type.
 //
-// A Lemma represents a predicate such as "never returns", but does not
+// A Fact represents a predicate such as "never returns", but does not
 // represent the subject of the predicate such as "function F".
 //
-// Lemmas may be produced in one analysis unit and consumed by another
-// analysis unit even if these are in different address spaces.
-// If package P imports Q, all lemmas about objects of Q produced during
+// Facts may be produced in one analysis pass and consumed by another
+// analysis pass even if these are in different address spaces.
+// If package P imports Q, all facts about objects of Q produced during
 // analysis of that package will be available during later analysis of P.
-// Lemmas are analogous to type export data in a build system:
-// just as export data enables separate compilation of several units,
-// lemmas enable "separate analysis".
+// Facts are analogous to type export data in a build system:
+// just as export data enables separate compilation of several passes,
+// facts enable "separate analysis".
 //
-// Each unit of analysis starts with the set of lemmas produced by the
-// same analysis applied to the packages directly imported by the
-// current one. The analysis may add additional lemmas to the set, and
-// they may be exported in turn. An analysis's Run function may retrieve
-// lemmas by calling Unit.Lemma and set them using Unit.SetLemma.
+// Each pass (a, p) starts with the set of facts produced by the
+// same analyzer a applied to the packages directly imported by p.
+// The analysis may add facts to the set, and they may be exported in turn.
+// An analysis's Run function may retrieve facts by calling
+// Pass.Import{Object,Package}Fact and update them using
+// Pass.Export{Object,Package}Fact.
 //
-// Each type of Lemma may be produced by at most one Analysis.
-// Lemmas are logically private to their Analysis; to pass values
-// between different analysis, use the Input/Output mechanism.
+// A fact is logically private to its Analysis. To pass values
+// between different analyzers, use the results mechanism;
+// see Analyzer.Requires, Analyzer.ResultType, and Pass.ResultOf.
 //
-// A Lemma type must be a pointer. (Unit.GetLemma relies on it.)
-// Lemmas are encoded and decoded using encoding/gob.
-// A Lemma may implement the GobEncoder/GobDecoder interfaces
-// to customize its encoding; Lemma encoding should not fail.
+// A Fact type must be a pointer.
+// Facts are encoded and decoded using encoding/gob.
+// A Fact may implement the GobEncoder/GobDecoder interfaces
+// to customize its encoding. Fact encoding should not fail.
 //
-// A Lemma should not be modified once passed to SetLemma.
-type Lemma interface {
-	IsLemma() // dummy method to avoid type errors
+// A Fact should not be modified once exported.
+type Fact interface {
+	AFact() // dummy method to avoid type errors
 }
 
 // A Finding is a message associated with a source location.
 //
-// An Analysis may return a variety of findings; the optional Category,
+// An Analyzer may return a variety of findings; the optional Category,
 // which should be a constant, may be used to classify them.
 // It is primarily intended to make it easy to look up documentation.
 type Finding struct {
diff --git a/go/analysis/plugin/findcall/findcall.go b/go/analysis/passes/findcall/findcall.go
similarity index 69%
rename from go/analysis/plugin/findcall/findcall.go
rename to go/analysis/passes/findcall/findcall.go
index c794255..5955498 100644
--- a/go/analysis/plugin/findcall/findcall.go
+++ b/go/analysis/passes/findcall/findcall.go
@@ -9,7 +9,7 @@
 	"golang.org/x/tools/go/analysis"
 )
 
-var Analysis = &analysis.Analysis{
+var Analyzer = &analysis.Analyzer{
 	Name:             "findcall",
 	Doc:              "find calls to a particular function",
 	Run:              findcall,
@@ -19,11 +19,11 @@
 var name = "println" // --name flag
 
 func init() {
-	Analysis.Flags.StringVar(&name, "name", name, "name of the function to find")
+	Analyzer.Flags.StringVar(&name, "name", name, "name of the function to find")
 }
 
-func findcall(unit *analysis.Unit) error {
-	for _, f := range unit.Syntax {
+func findcall(pass *analysis.Pass) (interface{}, error) {
+	for _, f := range pass.Syntax {
 		ast.Inspect(f, func(n ast.Node) bool {
 			if call, ok := n.(*ast.CallExpr); ok {
 				var id *ast.Ident
@@ -33,13 +33,13 @@
 				case *ast.SelectorExpr:
 					id = fun.Sel
 				}
-				if id != nil && !unit.Info.Types[id].IsType() && id.Name == name {
-					unit.Findingf(call.Lparen, "call of %s(...)", id.Name)
+				if id != nil && !pass.Info.Types[id].IsType() && id.Name == name {
+					pass.Findingf(call.Lparen, "call of %s(...)", id.Name)
 				}
 			}
 			return true
 		})
 	}
 
-	return nil
+	return nil, nil
 }
diff --git a/go/analysis/passes/pkgfact/pkgfact.go b/go/analysis/passes/pkgfact/pkgfact.go
new file mode 100644
index 0000000..092b4cc
--- /dev/null
+++ b/go/analysis/passes/pkgfact/pkgfact.go
@@ -0,0 +1,110 @@
+// The pkgfact package is a demonstration and test of the package fact
+// mechanism.
+//
+// The output of the pkgfact analysis is a set of key/values pairs
+// gathered from the analyzed package and its imported dependencies.
+// Each key/value pair comes from a top-level constant declaration
+// whose name starts with "_".  For example:
+//
+//      package p
+//
+// 	const _greeting  = "hello"
+// 	const _audience  = "world"
+//
+// the pkgfact analysis output for package p would be:
+//
+//   {"greeting": "hello", "audience": "world"}.
+//
+// In addition, the analysis reports a finding at each import
+// showing which key/value pairs it contributes.
+package pkgfact
+
+import (
+	"fmt"
+	"go/ast"
+	"go/token"
+	"go/types"
+	"reflect"
+	"sort"
+	"strings"
+
+	"golang.org/x/tools/go/analysis"
+)
+
+var Analyzer = &analysis.Analyzer{
+	Name:       "pkgfact",
+	Doc:        "gather name/value pairs from constant declarations",
+	Run:        run,
+	UsesFacts:  true, // *pairsFact
+	ResultType: reflect.TypeOf(map[string]string{}),
+}
+
+// A pairsFact is a package-level fact that records
+// an set of key=value strings accumulated from constant
+// declarations in this package and its dependencies.
+// Elements are ordered by keys, which are unique.
+type pairsFact []string
+
+func (*pairsFact) AFact() {}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+	result := make(map[string]string)
+
+	// At each import, print the fact from the imported
+	// package and accumulate its information into the result.
+	// (Warning: accumulation leads to quadratic growth of work.)
+	doImport := func(spec *ast.ImportSpec) {
+		pkg := pass.Info.Defs[spec.Name].(*types.PkgName).Imported()
+		var fact pairsFact
+		if pass.ImportPackageFact(pkg, &fact) {
+			for _, pair := range fact {
+				eq := strings.IndexByte(pair, '=')
+				result[pair[:eq]] = pair[1+eq:]
+			}
+			pass.Findingf(spec.Pos(), "%s", strings.Join(fact, " "))
+		}
+	}
+
+	// At each "const _name = value", add a fact into env.
+	doConst := func(spec *ast.ValueSpec) {
+		if len(spec.Names) == len(spec.Values) {
+			for i := range spec.Names {
+				name := spec.Names[i].Name
+				if strings.HasPrefix(name, "_") {
+					key := name[1:]
+					value := pass.Info.Types[spec.Values[i]].Value.String()
+					result[key] = value
+				}
+			}
+		}
+	}
+
+	for _, f := range pass.Syntax {
+		for _, decl := range f.Decls {
+			if decl, ok := decl.(*ast.GenDecl); ok {
+				for _, spec := range decl.Specs {
+					switch decl.Tok {
+					case token.IMPORT:
+						doImport(spec.(*ast.ImportSpec))
+					case token.CONST:
+						doConst(spec.(*ast.ValueSpec))
+					}
+				}
+			}
+		}
+	}
+
+	// Sort/deduplicate the result and save it as a package fact.
+	keys := make([]string, 0, len(result))
+	for key := range result {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+	var fact pairsFact
+	for _, key := range keys {
+		fact = append(fact, fmt.Sprintf("%s=%s", key, result[key]))
+	}
+	pass.ExportPackageFact(&fact)
+
+	return result, nil
+}
diff --git a/go/analysis/plugin/README b/go/analysis/plugin/README
deleted file mode 100644
index add86bd..0000000
--- a/go/analysis/plugin/README
+++ /dev/null
@@ -1,8 +0,0 @@
-
-This directory does not contain a Go package,
-but acts as a container for various analyses
-that implement the golang.org/x/tools/go/analysis
-API and may be imported into an analysis tool.
-
-By convention, each package foo provides the analysis,
-and each command foo/cmd/foo provides a standalone driver.
diff --git a/go/analysis/plugin/pkglemma/pkglemma.go b/go/analysis/plugin/pkglemma/pkglemma.go
deleted file mode 100644
index 94b4e17..0000000
--- a/go/analysis/plugin/pkglemma/pkglemma.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// The pkglemma package is a demonstration and test of the package lemma
-// mechanism.
-//
-// The output of the pkglemma analysis is a set of key/values pairs
-// gathered from the analyzed package and its imported dependencies.
-// Each key/value pair comes from a top-level constant declaration
-// whose name starts with "_".  For example:
-//
-//      package p
-//
-// 	const _greeting  = "hello"
-// 	const _audience  = "world"
-//
-// the pkglemma analysis output for package p would be:
-//
-//   {"greeting": "hello", "audience": "world"}.
-//
-// In addition, the analysis reports a finding at each import
-// showing which key/value pairs it contributes.
-package pkglemma
-
-import (
-	"fmt"
-	"go/ast"
-	"go/token"
-	"go/types"
-	"reflect"
-	"sort"
-	"strings"
-
-	"golang.org/x/tools/go/analysis"
-)
-
-var Analysis = &analysis.Analysis{
-	Name:       "pkglemma",
-	Doc:        "gather name/value pairs from constant declarations",
-	Run:        run,
-	LemmaTypes: []reflect.Type{reflect.TypeOf(new(note))},
-	OutputType: reflect.TypeOf(map[string]string{}),
-}
-
-// A note is a package-level lemma that records
-// key/value pairs accumulated from constant
-// declarations in this package and its dependencies.
-type note struct {
-	M map[string]string
-}
-
-func (*note) IsLemma() {}
-
-func run(unit *analysis.Unit) error {
-	m := make(map[string]string)
-
-	// At each import, print the lemma from the imported
-	// package and accumulate its information into m.
-	doImport := func(spec *ast.ImportSpec) {
-		pkg := unit.Info.Defs[spec.Name].(*types.PkgName).Imported()
-		var lemma note
-		if unit.PackageLemma(pkg, &lemma) {
-			var lines []string
-			for k, v := range lemma.M {
-				m[k] = v
-				lines = append(lines, fmt.Sprintf("%s=%s", k, v))
-			}
-			sort.Strings(lines)
-			unit.Findingf(spec.Pos(), "%s", strings.Join(lines, " "))
-		}
-	}
-
-	// At each "const _name = value", add a fact into m.
-	doConst := func(spec *ast.ValueSpec) {
-		if len(spec.Names) == len(spec.Values) {
-			for i := range spec.Names {
-				name := spec.Names[i].Name
-				if strings.HasPrefix(name, "_") {
-					m[name[1:]] = unit.Info.Types[spec.Values[i]].Value.String()
-				}
-			}
-		}
-	}
-
-	for _, f := range unit.Syntax {
-		for _, decl := range f.Decls {
-			if decl, ok := decl.(*ast.GenDecl); ok {
-				for _, spec := range decl.Specs {
-					switch decl.Tok {
-					case token.IMPORT:
-						doImport(spec.(*ast.ImportSpec))
-					case token.CONST:
-						doConst(spec.(*ast.ValueSpec))
-					}
-				}
-			}
-		}
-	}
-
-	unit.Output = m
-
-	unit.SetPackageLemma(&note{m})
-
-	return nil
-}
diff --git a/go/analysis/validate.go b/go/analysis/validate.go
index 7fbb3b5..e91729c 100644
--- a/go/analysis/validate.go
+++ b/go/analysis/validate.go
@@ -2,28 +2,21 @@
 
 import (
 	"fmt"
-	"reflect"
 	"unicode"
 )
 
-// Validate reports an error if any of the analyses are misconfigured.
+// Validate reports an error if any of the analyzers are misconfigured.
 // Checks include:
 // - that the name is a valid identifier;
 // - that analysis names are unique;
-// - that the Requires graph is acylic;
-// - that analyses' lemma and output types are unique.
-// - that each lemma type is a pointer.
-func Validate(analyses []*Analysis) error {
+// - that the Requires graph is acylic.
+func Validate(analyzers []*Analyzer) error {
 	names := make(map[string]bool)
 
-	// Map each lemma/output type to its sole generating analysis.
-	lemmaTypes := make(map[reflect.Type]*Analysis)
-	outputTypes := make(map[reflect.Type]*Analysis)
-
 	// Traverse the Requires graph, depth first.
-	color := make(map[*Analysis]uint8) // 0=white 1=grey 2=black
-	var visit func(a *Analysis) error
-	visit = func(a *Analysis) error {
+	color := make(map[*Analyzer]uint8) // 0=white 1=grey 2=black
+	var visit func(a *Analyzer) error
+	visit = func(a *Analyzer) error {
 		if a == nil {
 			return fmt.Errorf("nil *Analysis")
 		}
@@ -43,30 +36,6 @@
 				return fmt.Errorf("analysis %q is undocumented", a)
 			}
 
-			// lemma types
-			for _, t := range a.LemmaTypes {
-				if t == nil {
-					return fmt.Errorf("analysis %s has nil LemmaType", a)
-				}
-				if prev := lemmaTypes[t]; prev != nil {
-					return fmt.Errorf("lemma type %s registered by two analyses: %v, %v",
-						t, a, prev)
-				}
-				if t.Kind() != reflect.Ptr {
-					return fmt.Errorf("%s: lemma type %s is not a pointer", a, t)
-				}
-				lemmaTypes[t] = a
-			}
-
-			// output types
-			if a.OutputType != nil {
-				if prev := outputTypes[a.OutputType]; prev != nil {
-					return fmt.Errorf("output type %s registered by two analyses: %v, %v",
-						a.OutputType, a, prev)
-				}
-				outputTypes[a.OutputType] = a
-			}
-
 			// recursion
 			for i, req := range a.Requires {
 				if err := visit(req); err != nil {
@@ -78,7 +47,7 @@
 
 		return nil
 	}
-	for _, a := range analyses {
+	for _, a := range analyzers {
 		if err := visit(a); err != nil {
 			return err
 		}