1// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// This file implements typechecking of conversions.
6
7package types2
8
9import (
10	"fmt"
11	"go/constant"
12	"unicode"
13)
14
15// Conversion type-checks the conversion T(x).
16// The result is in x.
17func (check *Checker) conversion(x *operand, T Type) {
18	constArg := x.mode == constant_
19
20	constConvertibleTo := func(T Type, val *constant.Value) bool {
21		switch t, _ := under(T).(*Basic); {
22		case t == nil:
23			// nothing to do
24		case representableConst(x.val, check, t, val):
25			return true
26		case isInteger(x.typ) && isString(t):
27			codepoint := unicode.ReplacementChar
28			if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
29				codepoint = rune(i)
30			}
31			if val != nil {
32				*val = constant.MakeString(string(codepoint))
33			}
34			return true
35		}
36		return false
37	}
38
39	var ok bool
40	var cause string
41	switch {
42	case constArg && isConstType(T):
43		// constant conversion
44		ok = constConvertibleTo(T, &x.val)
45	case constArg && isTypeParam(T):
46		// x is convertible to T if it is convertible
47		// to each specific type in the type set of T.
48		// If T's type set is empty, or if it doesn't
49		// have specific types, constant x cannot be
50		// converted.
51		ok = T.(*TypeParam).underIs(func(u Type) bool {
52			// t is nil if there are no specific type terms
53			if u == nil {
54				cause = check.sprintf("%s does not contain specific types", T)
55				return false
56			}
57			if !constConvertibleTo(u, nil) {
58				cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T)
59				return false
60			}
61			return true
62		})
63		x.mode = value // type parameters are not constants
64	case x.convertibleTo(check, T, &cause):
65		// non-constant conversion
66		ok = true
67		x.mode = value
68	}
69
70	if !ok {
71		var err error_
72		if check.conf.CompilerErrorMessages {
73			if cause != "" {
74				// Add colon at end of line if we have a following cause.
75				err.errorf(x, "cannot convert %s to type %s:", x, T)
76				err.errorf(nopos, cause)
77			} else {
78				err.errorf(x, "cannot convert %s to type %s", x, T)
79			}
80		} else {
81			err.errorf(x, "cannot convert %s to %s", x, T)
82			if cause != "" {
83				err.errorf(nopos, cause)
84			}
85		}
86		check.report(&err)
87		x.mode = invalid
88		return
89	}
90
91	// The conversion argument types are final. For untyped values the
92	// conversion provides the type, per the spec: "A constant may be
93	// given a type explicitly by a constant declaration or conversion,...".
94	if isUntyped(x.typ) {
95		final := T
96		// - For conversions to interfaces, except for untyped nil arguments,
97		//   use the argument's default type.
98		// - For conversions of untyped constants to non-constant types, also
99		//   use the default type (e.g., []byte("foo") should report string
100		//   not []byte as type for the constant "foo").
101		// - For integer to string conversions, keep the argument type.
102		//   (See also the TODO below.)
103		if x.typ == Typ[UntypedNil] {
104			// ok
105		} else if IsInterface(T) && !isTypeParam(T) || constArg && !isConstType(T) {
106			final = Default(x.typ)
107		} else if isInteger(x.typ) && allString(T) {
108			final = x.typ
109		}
110		check.updateExprType(x.expr, final, true)
111	}
112
113	x.typ = T
114}
115
116// TODO(gri) convertibleTo checks if T(x) is valid. It assumes that the type
117// of x is fully known, but that's not the case for say string(1<<s + 1.0):
118// Here, the type of 1<<s + 1.0 will be UntypedFloat which will lead to the
119// (correct!) refusal of the conversion. But the reported error is essentially
120// "cannot convert untyped float value to string", yet the correct error (per
121// the spec) is that we cannot shift a floating-point value: 1 in 1<<s should
122// be converted to UntypedFloat because of the addition of 1.0. Fixing this
123// is tricky because we'd have to run updateExprType on the argument first.
124// (Issue #21982.)
125
126// convertibleTo reports whether T(x) is valid. In the failure case, *cause
127// may be set to the cause for the failure.
128// The check parameter may be nil if convertibleTo is invoked through an
129// exported API call, i.e., when all methods have been type-checked.
130func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
131	// "x is assignable to T"
132	if ok, _ := x.assignableTo(check, T, cause); ok {
133		return true
134	}
135
136	// "V and T have identical underlying types if tags are ignored
137	// and V and T are not type parameters"
138	V := x.typ
139	Vu := under(V)
140	Tu := under(T)
141	Vp, _ := V.(*TypeParam)
142	Tp, _ := T.(*TypeParam)
143	if IdenticalIgnoreTags(Vu, Tu) && Vp == nil && Tp == nil {
144		return true
145	}
146
147	// "V and T are unnamed pointer types and their pointer base types
148	// have identical underlying types if tags are ignored
149	// and their pointer base types are not type parameters"
150	if V, ok := V.(*Pointer); ok {
151		if T, ok := T.(*Pointer); ok {
152			if IdenticalIgnoreTags(under(V.base), under(T.base)) && !isTypeParam(V.base) && !isTypeParam(T.base) {
153				return true
154			}
155		}
156	}
157
158	// "V and T are both integer or floating point types"
159	if isIntegerOrFloat(Vu) && isIntegerOrFloat(Tu) {
160		return true
161	}
162
163	// "V and T are both complex types"
164	if isComplex(Vu) && isComplex(Tu) {
165		return true
166	}
167
168	// "V is an integer or a slice of bytes or runes and T is a string type"
169	if (isInteger(Vu) || isBytesOrRunes(Vu)) && isString(Tu) {
170		return true
171	}
172
173	// "V is a string and T is a slice of bytes or runes"
174	if isString(Vu) && isBytesOrRunes(Tu) {
175		return true
176	}
177
178	// package unsafe:
179	// "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
180	if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(Tu) {
181		return true
182	}
183	// "and vice versa"
184	if isUnsafePointer(Vu) && (isPointer(Tu) || isUintptr(Tu)) {
185		return true
186	}
187
188	// "V a slice, T is a pointer-to-array type,
189	// and the slice and array types have identical element types."
190	if s, _ := Vu.(*Slice); s != nil {
191		if p, _ := Tu.(*Pointer); p != nil {
192			if a, _ := under(p.Elem()).(*Array); a != nil {
193				if Identical(s.Elem(), a.Elem()) {
194					if check == nil || check.allowVersion(check.pkg, 1, 17) {
195						return true
196					}
197					// check != nil
198					if cause != nil {
199						*cause = "conversion of slices to array pointers requires go1.17 or later"
200						if check.conf.CompilerErrorMessages {
201							*cause += fmt.Sprintf(" (-lang was set to %s; check go.mod)", check.conf.GoVersion)
202						}
203					}
204					return false
205				}
206			}
207		}
208	}
209
210	// optimization: if we don't have type parameters, we're done
211	if Vp == nil && Tp == nil {
212		return false
213	}
214
215	errorf := func(format string, args ...interface{}) {
216		if check != nil && cause != nil {
217			msg := check.sprintf(format, args...)
218			if *cause != "" {
219				msg += "\n\t" + *cause
220			}
221			*cause = msg
222		}
223	}
224
225	// generic cases with specific type terms
226	// (generic operands cannot be constants, so we can ignore x.val)
227	switch {
228	case Vp != nil && Tp != nil:
229		x := *x // don't clobber outer x
230		return Vp.is(func(V *term) bool {
231			if V == nil {
232				return false // no specific types
233			}
234			x.typ = V.typ
235			return Tp.is(func(T *term) bool {
236				if T == nil {
237					return false // no specific types
238				}
239				if !x.convertibleTo(check, T.typ, cause) {
240					errorf("cannot convert %s (in %s) to %s (in %s)", V.typ, Vp, T.typ, Tp)
241					return false
242				}
243				return true
244			})
245		})
246	case Vp != nil:
247		x := *x // don't clobber outer x
248		return Vp.is(func(V *term) bool {
249			if V == nil {
250				return false // no specific types
251			}
252			x.typ = V.typ
253			if !x.convertibleTo(check, T, cause) {
254				errorf("cannot convert %s (in %s) to %s", V.typ, Vp, T)
255				return false
256			}
257			return true
258		})
259	case Tp != nil:
260		return Tp.is(func(T *term) bool {
261			if T == nil {
262				return false // no specific types
263			}
264			if !x.convertibleTo(check, T.typ, cause) {
265				errorf("cannot convert %s to %s (in %s)", x.typ, T.typ, Tp)
266				return false
267			}
268			return true
269		})
270	}
271
272	return false
273}
274
275func isUintptr(typ Type) bool {
276	t, _ := under(typ).(*Basic)
277	return t != nil && t.kind == Uintptr
278}
279
280func isUnsafePointer(typ Type) bool {
281	t, _ := under(typ).(*Basic)
282	return t != nil && t.kind == UnsafePointer
283}
284
285func isPointer(typ Type) bool {
286	_, ok := under(typ).(*Pointer)
287	return ok
288}
289
290func isBytesOrRunes(typ Type) bool {
291	if s, _ := under(typ).(*Slice); s != nil {
292		t, _ := under(s.elem).(*Basic)
293		return t != nil && (t.kind == Byte || t.kind == Rune)
294	}
295	return false
296}
297