GoPLS Viewer

Home|gopls/go/ssa/coretype.go
1// Copyright 2022 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ssa
6
7import (
8    "go/types"
9
10    "golang.org/x/tools/internal/typeparams"
11)
12
13// Utilities for dealing with core types.
14
15// isBytestring returns true if T has the same terms as interface{[]byte | string}.
16// These act like a core type for some operations: slice expressions, append and copy.
17//
18// See https://go.dev/ref/spec#Core_types for the details on bytestring.
19func isBytestring(T types.Typebool {
20    U := T.Underlying()
21    if _ok := U.(*types.Interface); !ok {
22        return false
23    }
24
25    tset := typeSetOf(U)
26    if tset.Len() != 2 {
27        return false
28    }
29    hasByteshasString := falsefalse
30    underIs(tset, func(t types.Typebool {
31        switch {
32        case isString(t):
33            hasString = true
34        case isByteSlice(t):
35            hasBytes = true
36        }
37        return hasBytes || hasString
38    })
39    return hasBytes && hasString
40}
41
42// termList is a list of types.
43type termList []*typeparams.Term       // type terms of the type set
44func (s termListLen() int            { return len(s) }
45func (s termListAt(i inttypes.Type { return s[i].Type() }
46
47// typeSetOf returns the type set of typ. Returns an empty typeset on an error.
48func typeSetOf(typ types.TypetermList {
49    // This is a adaptation of x/exp/typeparams.NormalTerms which x/tools cannot depend on.
50    var terms []*typeparams.Term
51    var err error
52    switch typ := typ.(type) {
53    case *typeparams.TypeParam:
54        termserr = typeparams.StructuralTerms(typ)
55    case *typeparams.Union:
56        termserr = typeparams.UnionTermSet(typ)
57    case *types.Interface:
58        termserr = typeparams.InterfaceTermSet(typ)
59    default:
60        // Common case.
61        // Specializing the len=1 case to avoid a slice
62        // had no measurable space/time benefit.
63        terms = []*typeparams.Term{typeparams.NewTerm(falsetyp)}
64    }
65
66    if err != nil {
67        return termList(nil)
68    }
69    return termList(terms)
70}
71
72// underIs calls f with the underlying types of the specific type terms
73// of s and reports whether all calls to f returned true. If there are
74// no specific terms, underIs returns the result of f(nil).
75func underIs(s termListf func(types.Typeboolbool {
76    if s.Len() == 0 {
77        return f(nil)
78    }
79    for i := 0i < s.Len(); i++ {
80        u := s.At(i).Underlying()
81        if !f(u) {
82            return false
83        }
84    }
85    return true
86}
87
88// indexType returns the element type and index mode of a IndexExpr over a type.
89// It returns (nil, invalid) if the type is not indexable; this should never occur in a well-typed program.
90func indexType(typ types.Type) (types.TypeindexMode) {
91    switch U := typ.Underlying().(type) {
92    case *types.Array:
93        return U.Elem(), ixArrVar
94    case *types.Pointer:
95        if arrok := U.Elem().Underlying().(*types.Array); ok {
96            return arr.Elem(), ixVar
97        }
98    case *types.Slice:
99        return U.Elem(), ixVar
100    case *types.Map:
101        return U.Elem(), ixMap
102    case *types.Basic:
103        return tByteixValue // must be a string
104    case *types.Interface:
105        tset := typeSetOf(U)
106        if tset.Len() == 0 {
107            return nilixInvalid // no underlying terms or error is empty.
108        }
109
110        elemmode := indexType(tset.At(0))
111        for i := 1i < tset.Len() && mode != ixInvalidi++ {
112            em := indexType(tset.At(i))
113            if !types.Identical(eleme) { // if type checked, just a sanity check
114                return nilixInvalid
115            }
116            // Update the mode to the most constrained address type.
117            mode = mode.meet(m)
118        }
119        if mode != ixInvalid {
120            return elemmode
121        }
122    }
123    return nilixInvalid
124}
125
126// An indexMode specifies the (addressing) mode of an index operand.
127//
128// Addressing mode of an index operation is based on the set of
129// underlying types.
130// Hasse diagram of the indexMode meet semi-lattice:
131//
132//    ixVar     ixMap
133//      |          |
134//    ixArrVar     |
135//      |          |
136//    ixValue      |
137//       \        /
138//      ixInvalid
139type indexMode byte
140
141const (
142    ixInvalid indexMode = iota // index is invalid
143    ixValue                    // index is a computed value (not addressable)
144    ixArrVar                   // like ixVar, but index operand contains an array
145    ixVar                      // index is an addressable variable
146    ixMap                      // index is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
147)
148
149// meet is the address type that is constrained by both x and y.
150func (x indexModemeet(y indexModeindexMode {
151    if (x == ixMap || y == ixMap) && x != y {
152        return ixInvalid
153    }
154    // Use int representation and return min.
155    if x < y {
156        return y
157    }
158    return x
159}
160
MembersX
indexType.typ
indexType.BlockStmt.mode
indexType.BlockStmt.i
indexMode.meet
isBytestring.T
isBytestring.tset
termList
termList.At
termList.Len.s
typeSetOf.terms
indexType.BlockStmt.BlockStmt.e
isBytestring.hasBytes
typeSetOf.err
underIs.i
indexType
indexMode.meet.y
isBytestring.U
termList.At.s
underIs.f
indexType.BlockStmt.tset
indexType.BlockStmt.BlockStmt.m
ixInvalid
indexMode.meet.x
isBytestring
isBytestring.hasString
termList.At.i
underIs
termList.Len
underIs.s
typeSetOf
typeSetOf.typ
underIs.BlockStmt.u
indexType.BlockStmt.elem
indexMode
Members
X