gopls/internal/analysis/simplifycompositelit: rewrite using types

This is mostly behavior-preserving change that rewrites the analyzer
more simply in terms of types.Types instead of AST and reflection.
The only change is that it emits a type-specific instead of a generic
error message.

This is a preparatory step for supporting go1.28 inference of
literals at toplevel and for structs.

For golang/go#12854

Change-Id: I92f103e9884f9f9c5da5ebd4013b4b8477a5ccfe
Reviewed-on: https://go-review.googlesource.com/c/tools/+/801840
Reviewed-by: Alex Putman <aputman@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/gopls/internal/analysis/simplifycompositelit/simplifycompositelit.go b/gopls/internal/analysis/simplifycompositelit/simplifycompositelit.go
index db5012a..397b135 100644
--- a/gopls/internal/analysis/simplifycompositelit/simplifycompositelit.go
+++ b/gopls/internal/analysis/simplifycompositelit/simplifycompositelit.go
@@ -8,18 +8,17 @@
 package simplifycompositelit
 
 import (
-	"bytes"
 	_ "embed"
 	"fmt"
 	"go/ast"
-	"go/printer"
 	"go/token"
-	"reflect"
+	"go/types"
 
 	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/go/analysis/passes/inspect"
 	"golang.org/x/tools/go/ast/inspector"
 	"golang.org/x/tools/internal/analysis/analyzerutil"
+	"golang.org/x/tools/internal/astutil"
 )
 
 //go:embed doc.go
@@ -43,163 +42,102 @@
 	}
 
 	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
-	nodeFilter := []ast.Node{(*ast.CompositeLit)(nil)}
-	inspect.Preorder(nodeFilter, func(n ast.Node) {
-		if _, ok := generated[pass.Fset.File(n.Pos())]; ok {
-			return // skip checking if it's generated code
+
+	// Find each CompositeLit with an explicit type.
+	// Then attempt to simplify each element that is
+	// itself a CompositeLit with an explicit type.
+	//
+	// TODO(adonovan): note that go1.28 will permit types to be
+	// omitted much more generally, so instead of starting with
+	// the "outer" CompositeLit, we'll need to look for "inner"
+	// literals appearing in a context that determines their type
+	// (assuming we want to take a maximal approach to
+	// simplification). We should also support named and alias
+	// types more thoroughly.
+
+	for curLit := range inspect.Root().Preorder((*ast.CompositeLit)(nil)) {
+		lit := curLit.Node().(*ast.CompositeLit)
+
+		// Skip generated code.
+		if _, ok := generated[pass.Fset.File(lit.Pos())]; ok {
+			continue
 		}
 
-		expr := n.(*ast.CompositeLit)
-
-		outer := expr
-		var keyType, eltType ast.Expr
-		switch typ := outer.Type.(type) {
+		var (
+			kind             string
+			keyType, eltType ast.Expr
+		)
+		switch typ := lit.Type.(type) {
 		case *ast.ArrayType:
 			eltType = typ.Elt
+			if typ.Len != nil {
+				kind = "array"
+			} else {
+				kind = "slice"
+			}
 		case *ast.MapType:
 			keyType = typ.Key
 			eltType = typ.Value
+			kind = "map"
+		default:
+			// e.g. struct, named, or nil (no explicit type)
+			continue
 		}
 
-		if eltType == nil {
-			return
-		}
-		var ktyp reflect.Value
-		if keyType != nil {
-			ktyp = reflect.ValueOf(keyType)
-		}
-		typ := reflect.ValueOf(eltType)
-		for _, x := range outer.Elts {
-			// look at value of indexed/named elements
-			if t, ok := x.(*ast.KeyValueExpr); ok {
-				if keyType != nil {
-					simplifyLiteral(pass, ktyp, keyType, t.Key)
+		for _, elt := range lit.Elts {
+			if kve, ok := elt.(*ast.KeyValueExpr); ok {
+				if keyType != nil { // map
+					simplifyLiteral(pass, keyType, kve.Key, kind)
 				}
-				x = t.Value
+				elt = kve.Value
 			}
-			simplifyLiteral(pass, typ, eltType, x)
+			simplifyLiteral(pass, eltType, elt, kind)
 		}
-	})
+	}
 	return nil, nil
 }
 
-func simplifyLiteral(pass *analysis.Pass, typ reflect.Value, astType, x ast.Expr) {
-	// if the element is a composite literal and its literal type
-	// matches the outer literal's element type exactly, the inner
-	// literal type may be omitted
-	if inner, ok := x.(*ast.CompositeLit); ok && match(typ, reflect.ValueOf(inner.Type)) {
-		var b bytes.Buffer
-		printer.Fprint(&b, pass.Fset, inner.Type) // ignore error
-		createDiagnostic(pass, inner.Type.Pos(), inner.Type.End(), b.String())
+// simplifyLiteral reports a diagnostic if expr's is a T{...} or
+// &T{...} literal whose type is identical to want and therefore
+// redundant.
+func simplifyLiteral(pass *analysis.Pass, want, expr ast.Expr, kind string) {
+	info := pass.TypesInfo
+
+	report := func(start, end token.Pos, amp string, innerType ast.Expr) {
+		start -= token.Pos(len(amp)) // assumes "&" (if any) is immediately before
+		pass.Report(analysis.Diagnostic{
+			Pos:     start,
+			End:     end,
+			Message: fmt.Sprintf("redundant type in %s literal", kind),
+			SuggestedFixes: []analysis.SuggestedFix{{
+				Message: fmt.Sprintf("Remove '%s%s'", amp, astutil.Format(pass.Fset, innerType)),
+				TextEdits: []analysis.TextEdit{{
+					Pos: start,
+					End: end,
+				}},
+			}},
+		})
 	}
+
+	// If the element is a composite literal whose explicit type
+	// is identical to the outer literal's element type,
+	// the inner literal's type may be omitted
+	if inner, ok := expr.(*ast.CompositeLit); ok &&
+		inner.Type != nil &&
+		types.Identical(info.TypeOf(want), info.TypeOf(inner.Type)) {
+		report(inner.Type.Pos(), inner.Type.End(), "", inner.Type)
+	}
+
 	// if the outer literal's element type is a pointer type *T
 	// and the element is & of a composite literal of type T,
 	// the inner &T may be omitted.
-	if ptr, ok := astType.(*ast.StarExpr); ok {
-		if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
-			if inner, ok := addr.X.(*ast.CompositeLit); ok {
-				if match(reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
-					var b bytes.Buffer
-					printer.Fprint(&b, pass.Fset, inner.Type) // ignore error
-					// Account for the & by subtracting 1 from typ.Pos().
-					createDiagnostic(pass, inner.Type.Pos()-1, inner.Type.End(), "&"+b.String())
-				}
+	if star, ok := want.(*ast.StarExpr); ok {
+		if addr, ok := expr.(*ast.UnaryExpr); ok && addr.Op == token.AND {
+			if inner, ok := addr.X.(*ast.CompositeLit); ok &&
+				inner.Type != nil &&
+				types.Identical(info.TypeOf(star.X), info.TypeOf(inner.Type)) {
+				report(inner.Type.Pos(), inner.Type.End(), "&", inner.Type)
 			}
 		}
 	}
 }
-
-func createDiagnostic(pass *analysis.Pass, start, end token.Pos, typ string) {
-	pass.Report(analysis.Diagnostic{
-		Pos:     start,
-		End:     end,
-		Message: "redundant type from array, slice, or map composite literal",
-		SuggestedFixes: []analysis.SuggestedFix{{
-			Message: fmt.Sprintf("Remove '%s'", typ),
-			TextEdits: []analysis.TextEdit{{
-				Pos:     start,
-				End:     end,
-				NewText: []byte{},
-			}},
-		}},
-	})
-}
-
-// match reports whether pattern matches val,
-// recording wildcard submatches in m.
-// If m == nil, match checks whether pattern == val.
-// from https://github.com/golang/go/blob/26154f31ad6c801d8bad5ef58df1e9263c6beec7/src/cmd/gofmt/rewrite.go#L160
-func match(pattern, val reflect.Value) bool {
-	// Otherwise, pattern and val must match recursively.
-	if !pattern.IsValid() || !val.IsValid() {
-		return !pattern.IsValid() && !val.IsValid()
-	}
-	if pattern.Type() != val.Type() {
-		return false
-	}
-
-	// Special cases.
-	switch pattern.Type() {
-	case identType:
-		// For identifiers, only the names need to match
-		// (and none of the other *ast.Object information).
-		// This is a common case, handle it all here instead
-		// of recursing down any further via reflection.
-		p := pattern.Interface().(*ast.Ident)
-		v := val.Interface().(*ast.Ident)
-		return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
-	case objectPtrType, positionType:
-		// object pointers and token positions always match
-		return true
-	case callExprType:
-		// For calls, the Ellipsis fields (token.Position) must
-		// match since that is how f(x) and f(x...) are different.
-		// Check them here but fall through for the remaining fields.
-		p := pattern.Interface().(*ast.CallExpr)
-		v := val.Interface().(*ast.CallExpr)
-		if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() {
-			return false
-		}
-	}
-
-	p := reflect.Indirect(pattern)
-	v := reflect.Indirect(val)
-	if !p.IsValid() || !v.IsValid() {
-		return !p.IsValid() && !v.IsValid()
-	}
-
-	switch p.Kind() {
-	case reflect.Slice:
-		if p.Len() != v.Len() {
-			return false
-		}
-		for i := 0; i < p.Len(); i++ {
-			if !match(p.Index(i), v.Index(i)) {
-				return false
-			}
-		}
-		return true
-
-	case reflect.Struct:
-		for i := 0; i < p.NumField(); i++ {
-			if !match(p.Field(i), v.Field(i)) {
-				return false
-			}
-		}
-		return true
-
-	case reflect.Interface:
-		return match(p.Elem(), v.Elem())
-	}
-
-	// Handle token integers, etc.
-	return p.Interface() == v.Interface()
-}
-
-// Values/types for special cases.
-var (
-	identType     = reflect.TypeFor[*ast.Ident]()
-	objectPtrType = reflect.TypeFor[*ast.Object]()
-	positionType  = reflect.TypeFor[token.Pos]()
-	callExprType  = reflect.TypeFor[*ast.CallExpr]()
-)
diff --git a/gopls/internal/analysis/simplifycompositelit/testdata/src/a/a.go b/gopls/internal/analysis/simplifycompositelit/testdata/src/a/a.go
index 14e0fa3..9c15556 100644
--- a/gopls/internal/analysis/simplifycompositelit/testdata/src/a/a.go
+++ b/gopls/internal/analysis/simplifycompositelit/testdata/src/a/a.go
@@ -13,35 +13,35 @@
 }
 
 var _ = [42]T{
-	T{},     // want "redundant type from array, slice, or map composite literal"
-	T{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	T{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	T{},     // want "redundant type in array literal"
+	T{1, 2}, // want "redundant type in array literal"
+	T{3, 4}, // want "redundant type in array literal"
 }
 
 var _ = [...]T{
-	T{},     // want "redundant type from array, slice, or map composite literal"
-	T{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	T{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	T{},     // want "redundant type in array literal"
+	T{1, 2}, // want "redundant type in array literal"
+	T{3, 4}, // want "redundant type in array literal"
 }
 
 var _ = []T{
-	T{},     // want "redundant type from array, slice, or map composite literal"
-	T{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	T{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	T{},     // want "redundant type in slice literal"
+	T{1, 2}, // want "redundant type in slice literal"
+	T{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []T{
-	T{}, // want "redundant type from array, slice, or map composite literal"
-	10:  T{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	20:  T{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	T{}, // want "redundant type in slice literal"
+	10:  T{1, 2}, // want "redundant type in slice literal"
+	20:  T{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []struct {
 	x, y int
 }{
-	struct{ x, y int }{}, // want "redundant type from array, slice, or map composite literal"
-	10:                   struct{ x, y int }{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	20:                   struct{ x, y int }{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	struct{ x, y int }{}, // want "redundant type in slice literal"
+	10:                   struct{ x, y int }{1, 2}, // want "redundant type in slice literal"
+	20:                   struct{ x, y int }{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []interface{}{
@@ -51,38 +51,38 @@
 }
 
 var _ = [][]int{
-	[]int{},     // want "redundant type from array, slice, or map composite literal"
-	[]int{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	[]int{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	[]int{},     // want "redundant type in slice literal"
+	[]int{1, 2}, // want "redundant type in slice literal"
+	[]int{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = [][]int{
 	([]int{}),
 	([]int{1, 2}),
-	[]int{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	[]int{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = [][][]int{
-	[][]int{}, // want "redundant type from array, slice, or map composite literal"
-	[][]int{ // want "redundant type from array, slice, or map composite literal"
-		[]int{},           // want "redundant type from array, slice, or map composite literal"
-		[]int{0, 1, 2, 3}, // want "redundant type from array, slice, or map composite literal"
-		[]int{4, 5},       // want "redundant type from array, slice, or map composite literal"
+	[][]int{}, // want "redundant type in slice literal"
+	[][]int{ // want "redundant type in slice literal"
+		[]int{},           // want "redundant type in slice literal"
+		[]int{0, 1, 2, 3}, // want "redundant type in slice literal"
+		[]int{4, 5},       // want "redundant type in slice literal"
 	},
 }
 
 var _ = map[string]T{
-	"foo": T{},     // want "redundant type from array, slice, or map composite literal"
-	"bar": T{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": T{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": T{},     // want "redundant type in map literal"
+	"bar": T{1, 2}, // want "redundant type in map literal"
+	"bal": T{3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string]struct {
 	x, y int
 }{
-	"foo": struct{ x, y int }{},     // want "redundant type from array, slice, or map composite literal"
-	"bar": struct{ x, y int }{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": struct{ x, y int }{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": struct{ x, y int }{},     // want "redundant type in map literal"
+	"bar": struct{ x, y int }{1, 2}, // want "redundant type in map literal"
+	"bal": struct{ x, y int }{3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string]interface{}{
@@ -92,15 +92,15 @@
 }
 
 var _ = map[string][]int{
-	"foo": []int{},     // want "redundant type from array, slice, or map composite literal"
-	"bar": []int{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": []int{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": []int{},     // want "redundant type in map literal"
+	"bar": []int{1, 2}, // want "redundant type in map literal"
+	"bal": []int{3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string][]int{
 	"foo": ([]int{}),
 	"bar": ([]int{1, 2}),
-	"bal": []int{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"bal": []int{3, 4}, // want "redundant type in map literal"
 }
 
 type Point struct {
@@ -117,44 +117,44 @@
 	f *Point
 }
 
-// from exp/4s/data.go
+// in exp/4s/data.go
 var pieces3 = []Piece{
-	Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
+	Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
 }
 
 var _ = [42]*T{
-	&T{},     // want "redundant type from array, slice, or map composite literal"
-	&T{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	&T{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	&T{},     // want "redundant type in array literal"
+	&T{1, 2}, // want "redundant type in array literal"
+	&T{3, 4}, // want "redundant type in array literal"
 }
 
 var _ = [...]*T{
-	&T{},     // want "redundant type from array, slice, or map composite literal"
-	&T{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	&T{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	&T{},     // want "redundant type in array literal"
+	&T{1, 2}, // want "redundant type in array literal"
+	&T{3, 4}, // want "redundant type in array literal"
 }
 
 var _ = []*T{
-	&T{},     // want "redundant type from array, slice, or map composite literal"
-	&T{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	&T{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	&T{},     // want "redundant type in slice literal"
+	&T{1, 2}, // want "redundant type in slice literal"
+	&T{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []*T{
-	&T{}, // want "redundant type from array, slice, or map composite literal"
-	10:   &T{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	20:   &T{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	&T{}, // want "redundant type in slice literal"
+	10:   &T{1, 2}, // want "redundant type in slice literal"
+	20:   &T{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []*struct {
 	x, y int
 }{
-	&struct{ x, y int }{}, // want "redundant type from array, slice, or map composite literal"
-	10:                    &struct{ x, y int }{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	20:                    &struct{ x, y int }{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	&struct{ x, y int }{}, // want "redundant type in slice literal"
+	10:                    &struct{ x, y int }{1, 2}, // want "redundant type in slice literal"
+	20:                    &struct{ x, y int }{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []interface{}{
@@ -164,38 +164,38 @@
 }
 
 var _ = []*[]int{
-	&[]int{},     // want "redundant type from array, slice, or map composite literal"
-	&[]int{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	&[]int{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	&[]int{},     // want "redundant type in slice literal"
+	&[]int{1, 2}, // want "redundant type in slice literal"
+	&[]int{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []*[]int{
 	(&[]int{}),
 	(&[]int{1, 2}),
-	&[]int{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	&[]int{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []*[]*[]int{
-	&[]*[]int{}, // want "redundant type from array, slice, or map composite literal"
-	&[]*[]int{ // want "redundant type from array, slice, or map composite literal"
-		&[]int{},           // want "redundant type from array, slice, or map composite literal"
-		&[]int{0, 1, 2, 3}, // want "redundant type from array, slice, or map composite literal"
-		&[]int{4, 5},       // want "redundant type from array, slice, or map composite literal"
+	&[]*[]int{}, // want "redundant type in slice literal"
+	&[]*[]int{ // want "redundant type in slice literal"
+		&[]int{},           // want "redundant type in slice literal"
+		&[]int{0, 1, 2, 3}, // want "redundant type in slice literal"
+		&[]int{4, 5},       // want "redundant type in slice literal"
 	},
 }
 
 var _ = map[string]*T{
-	"foo": &T{},     // want "redundant type from array, slice, or map composite literal"
-	"bar": &T{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": &T{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": &T{},     // want "redundant type in map literal"
+	"bar": &T{1, 2}, // want "redundant type in map literal"
+	"bal": &T{3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string]*struct {
 	x, y int
 }{
-	"foo": &struct{ x, y int }{},     // want "redundant type from array, slice, or map composite literal"
-	"bar": &struct{ x, y int }{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": &struct{ x, y int }{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": &struct{ x, y int }{},     // want "redundant type in map literal"
+	"bar": &struct{ x, y int }{1, 2}, // want "redundant type in map literal"
+	"bal": &struct{ x, y int }{3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string]interface{}{
@@ -205,30 +205,54 @@
 }
 
 var _ = map[string]*[]int{
-	"foo": &[]int{},     // want "redundant type from array, slice, or map composite literal"
-	"bar": &[]int{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": &[]int{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": &[]int{},     // want "redundant type in map literal"
+	"bar": &[]int{1, 2}, // want "redundant type in map literal"
+	"bal": &[]int{3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string]*[]int{
 	"foo": (&[]int{}),
 	"bar": (&[]int{1, 2}),
-	"bal": &[]int{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"bal": &[]int{3, 4}, // want "redundant type in map literal"
 }
 
 var pieces4 = []*Piece{
-	&Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	&Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	&Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	&Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
+	&Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	&Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	&Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	&Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
 }
 
 var _ = map[T]T2{
-	T{1, 2}: T2{3, 4}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	T{5, 6}: T2{7, 8}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
+	T{1, 2}: T2{3, 4}, // want "redundant type in map literal" "redundant type in map literal"
+	T{5, 6}: T2{7, 8}, // want "redundant type in map literal" "redundant type in map literal"
 }
 
 var _ = map[*T]*T2{
-	&T{1, 2}: &T2{3, 4}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	&T{5, 6}: &T2{7, 8}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
+	&T{1, 2}: &T2{3, 4}, // want "redundant type in map literal" "redundant type in map literal"
+	&T{5, 6}: &T2{7, 8}, // want "redundant type in map literal" "redundant type in map literal"
+}
+
+type AliasT = T
+
+var _ = []T{
+	AliasT{}, // want "redundant type in slice literal"
+}
+
+var _ = []AliasT{
+	T{}, // want "redundant type in slice literal"
+}
+
+var _ = []*AliasT{
+	&T{}, // want "redundant type in slice literal"
+}
+
+var _ = map[string]AliasT{
+	"foo": T{}, // want "redundant type in map literal"
+}
+
+type SliceAlias = []T
+
+var _ = SliceAlias{
+	T{},
 }
diff --git a/gopls/internal/analysis/simplifycompositelit/testdata/src/a/a.go.golden b/gopls/internal/analysis/simplifycompositelit/testdata/src/a/a.go.golden
index 6bfed45..e7e9e18 100644
--- a/gopls/internal/analysis/simplifycompositelit/testdata/src/a/a.go.golden
+++ b/gopls/internal/analysis/simplifycompositelit/testdata/src/a/a.go.golden
@@ -13,35 +13,35 @@
 }
 
 var _ = [42]T{
-	{},     // want "redundant type from array, slice, or map composite literal"
-	{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{},     // want "redundant type in array literal"
+	{1, 2}, // want "redundant type in array literal"
+	{3, 4}, // want "redundant type in array literal"
 }
 
 var _ = [...]T{
-	{},     // want "redundant type from array, slice, or map composite literal"
-	{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{},     // want "redundant type in array literal"
+	{1, 2}, // want "redundant type in array literal"
+	{3, 4}, // want "redundant type in array literal"
 }
 
 var _ = []T{
-	{},     // want "redundant type from array, slice, or map composite literal"
-	{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{},     // want "redundant type in slice literal"
+	{1, 2}, // want "redundant type in slice literal"
+	{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []T{
-	{}, // want "redundant type from array, slice, or map composite literal"
-	10: {1, 2}, // want "redundant type from array, slice, or map composite literal"
-	20: {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{}, // want "redundant type in slice literal"
+	10: {1, 2}, // want "redundant type in slice literal"
+	20: {3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []struct {
 	x, y int
 }{
-	{}, // want "redundant type from array, slice, or map composite literal"
-	10: {1, 2}, // want "redundant type from array, slice, or map composite literal"
-	20: {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{}, // want "redundant type in slice literal"
+	10: {1, 2}, // want "redundant type in slice literal"
+	20: {3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []interface{}{
@@ -51,38 +51,38 @@
 }
 
 var _ = [][]int{
-	{},     // want "redundant type from array, slice, or map composite literal"
-	{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{},     // want "redundant type in slice literal"
+	{1, 2}, // want "redundant type in slice literal"
+	{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = [][]int{
 	([]int{}),
 	([]int{1, 2}),
-	{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = [][][]int{
-	{}, // want "redundant type from array, slice, or map composite literal"
-	{ // want "redundant type from array, slice, or map composite literal"
-		{},           // want "redundant type from array, slice, or map composite literal"
-		{0, 1, 2, 3}, // want "redundant type from array, slice, or map composite literal"
-		{4, 5},       // want "redundant type from array, slice, or map composite literal"
+	{}, // want "redundant type in slice literal"
+	{ // want "redundant type in slice literal"
+		{},           // want "redundant type in slice literal"
+		{0, 1, 2, 3}, // want "redundant type in slice literal"
+		{4, 5},       // want "redundant type in slice literal"
 	},
 }
 
 var _ = map[string]T{
-	"foo": {},     // want "redundant type from array, slice, or map composite literal"
-	"bar": {1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": {},     // want "redundant type in map literal"
+	"bar": {1, 2}, // want "redundant type in map literal"
+	"bal": {3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string]struct {
 	x, y int
 }{
-	"foo": {},     // want "redundant type from array, slice, or map composite literal"
-	"bar": {1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": {},     // want "redundant type in map literal"
+	"bar": {1, 2}, // want "redundant type in map literal"
+	"bal": {3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string]interface{}{
@@ -92,15 +92,15 @@
 }
 
 var _ = map[string][]int{
-	"foo": {},     // want "redundant type from array, slice, or map composite literal"
-	"bar": {1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": {},     // want "redundant type in map literal"
+	"bar": {1, 2}, // want "redundant type in map literal"
+	"bal": {3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string][]int{
 	"foo": ([]int{}),
 	"bar": ([]int{1, 2}),
-	"bal": {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"bal": {3, 4}, // want "redundant type in map literal"
 }
 
 type Point struct {
@@ -117,44 +117,44 @@
 	f *Point
 }
 
-// from exp/4s/data.go
+// in exp/4s/data.go
 var pieces3 = []Piece{
-	{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
+	{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
 }
 
 var _ = [42]*T{
-	{},     // want "redundant type from array, slice, or map composite literal"
-	{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{},     // want "redundant type in array literal"
+	{1, 2}, // want "redundant type in array literal"
+	{3, 4}, // want "redundant type in array literal"
 }
 
 var _ = [...]*T{
-	{},     // want "redundant type from array, slice, or map composite literal"
-	{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{},     // want "redundant type in array literal"
+	{1, 2}, // want "redundant type in array literal"
+	{3, 4}, // want "redundant type in array literal"
 }
 
 var _ = []*T{
-	{},     // want "redundant type from array, slice, or map composite literal"
-	{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{},     // want "redundant type in slice literal"
+	{1, 2}, // want "redundant type in slice literal"
+	{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []*T{
-	{}, // want "redundant type from array, slice, or map composite literal"
-	10: {1, 2}, // want "redundant type from array, slice, or map composite literal"
-	20: {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{}, // want "redundant type in slice literal"
+	10: {1, 2}, // want "redundant type in slice literal"
+	20: {3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []*struct {
 	x, y int
 }{
-	{}, // want "redundant type from array, slice, or map composite literal"
-	10: {1, 2}, // want "redundant type from array, slice, or map composite literal"
-	20: {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{}, // want "redundant type in slice literal"
+	10: {1, 2}, // want "redundant type in slice literal"
+	20: {3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []interface{}{
@@ -164,38 +164,38 @@
 }
 
 var _ = []*[]int{
-	{},     // want "redundant type from array, slice, or map composite literal"
-	{1, 2}, // want "redundant type from array, slice, or map composite literal"
-	{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{},     // want "redundant type in slice literal"
+	{1, 2}, // want "redundant type in slice literal"
+	{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []*[]int{
 	(&[]int{}),
 	(&[]int{1, 2}),
-	{3, 4}, // want "redundant type from array, slice, or map composite literal"
+	{3, 4}, // want "redundant type in slice literal"
 }
 
 var _ = []*[]*[]int{
-	{}, // want "redundant type from array, slice, or map composite literal"
-	{ // want "redundant type from array, slice, or map composite literal"
-		{},           // want "redundant type from array, slice, or map composite literal"
-		{0, 1, 2, 3}, // want "redundant type from array, slice, or map composite literal"
-		{4, 5},       // want "redundant type from array, slice, or map composite literal"
+	{}, // want "redundant type in slice literal"
+	{ // want "redundant type in slice literal"
+		{},           // want "redundant type in slice literal"
+		{0, 1, 2, 3}, // want "redundant type in slice literal"
+		{4, 5},       // want "redundant type in slice literal"
 	},
 }
 
 var _ = map[string]*T{
-	"foo": {},     // want "redundant type from array, slice, or map composite literal"
-	"bar": {1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": {},     // want "redundant type in map literal"
+	"bar": {1, 2}, // want "redundant type in map literal"
+	"bal": {3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string]*struct {
 	x, y int
 }{
-	"foo": {},     // want "redundant type from array, slice, or map composite literal"
-	"bar": {1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": {},     // want "redundant type in map literal"
+	"bar": {1, 2}, // want "redundant type in map literal"
+	"bal": {3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string]interface{}{
@@ -205,30 +205,54 @@
 }
 
 var _ = map[string]*[]int{
-	"foo": {},     // want "redundant type from array, slice, or map composite literal"
-	"bar": {1, 2}, // want "redundant type from array, slice, or map composite literal"
-	"bal": {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"foo": {},     // want "redundant type in map literal"
+	"bar": {1, 2}, // want "redundant type in map literal"
+	"bal": {3, 4}, // want "redundant type in map literal"
 }
 
 var _ = map[string]*[]int{
 	"foo": (&[]int{}),
 	"bar": (&[]int{1, 2}),
-	"bal": {3, 4}, // want "redundant type from array, slice, or map composite literal"
+	"bal": {3, 4}, // want "redundant type in map literal"
 }
 
 var pieces4 = []*Piece{
-	{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
+	{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
+	{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil}, // want "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal" "redundant type in slice literal"
 }
 
 var _ = map[T]T2{
-	{1, 2}: {3, 4}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	{5, 6}: {7, 8}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
+	{1, 2}: {3, 4}, // want "redundant type in map literal" "redundant type in map literal"
+	{5, 6}: {7, 8}, // want "redundant type in map literal" "redundant type in map literal"
 }
 
 var _ = map[*T]*T2{
-	{1, 2}: {3, 4}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
-	{5, 6}: {7, 8}, // want "redundant type from array, slice, or map composite literal" "redundant type from array, slice, or map composite literal"
+	{1, 2}: {3, 4}, // want "redundant type in map literal" "redundant type in map literal"
+	{5, 6}: {7, 8}, // want "redundant type in map literal" "redundant type in map literal"
+}
+
+type AliasT = T
+
+var _ = []T{
+	{}, // want "redundant type in slice literal"
+}
+
+var _ = []AliasT{
+	{}, // want "redundant type in slice literal"
+}
+
+var _ = []*AliasT{
+	{}, // want "redundant type in slice literal"
+}
+
+var _ = map[string]AliasT{
+	"foo": {}, // want "redundant type in map literal"
+}
+
+type SliceAlias = []T
+
+var _ = SliceAlias{
+	T{},
 }