1// Copyright 2013 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 initialization and assignment checks.
6
7package types
8
9import (
10	"errors"
11	"go/ast"
12	"go/token"
13)
14
15// assignment reports whether x can be assigned to a variable of type T,
16// if necessary by attempting to convert untyped values to the appropriate
17// type. context describes the context in which the assignment takes place.
18// Use T == nil to indicate assignment to an untyped blank identifier.
19// x.mode is set to invalid if the assignment failed.
20func (check *Checker) assignment(x *operand, T Type, context string) {
21	check.singleValue(x)
22
23	switch x.mode {
24	case invalid:
25		return // error reported before
26	case constant_, variable, mapindex, value, commaok, commaerr:
27		// ok
28	default:
29		unreachable()
30	}
31
32	if isUntyped(x.typ) {
33		target := T
34		// spec: "If an untyped constant is assigned to a variable of interface
35		// type or the blank identifier, the constant is first converted to type
36		// bool, rune, int, float64, complex128 or string respectively, depending
37		// on whether the value is a boolean, rune, integer, floating-point,
38		// complex, or string constant."
39		if T == nil || IsInterface(T) {
40			if T == nil && x.typ == Typ[UntypedNil] {
41				check.errorf(x, _UntypedNil, "use of untyped nil in %s", context)
42				x.mode = invalid
43				return
44			}
45			target = Default(x.typ)
46		}
47		if err := check.canConvertUntyped(x, target); err != nil {
48			msg := check.sprintf("cannot use %s as %s value in %s", x, target, context)
49			code := _IncompatibleAssign
50			var ierr Error
51			if errors.As(err, &ierr) {
52				// Preserve these inner errors, as they are informative.
53				switch ierr.go116code {
54				case _TruncatedFloat:
55					msg += " (truncated)"
56					code = ierr.go116code
57				case _NumericOverflow:
58					msg += " (overflows)"
59					code = ierr.go116code
60				}
61			}
62			check.error(x, code, msg)
63			x.mode = invalid
64			return
65		}
66	}
67	// x.typ is typed
68
69	// spec: "If a left-hand side is the blank identifier, any typed or
70	// non-constant value except for the predeclared identifier nil may
71	// be assigned to it."
72	if T == nil {
73		return
74	}
75
76	reason := ""
77	if ok, code := x.assignableTo(check, T, &reason); !ok {
78		if reason != "" {
79			check.errorf(x, code, "cannot use %s as %s value in %s: %s", x, T, context, reason)
80		} else {
81			check.errorf(x, code, "cannot use %s as %s value in %s", x, T, context)
82		}
83		x.mode = invalid
84	}
85}
86
87func (check *Checker) initConst(lhs *Const, x *operand) {
88	if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
89		if lhs.typ == nil {
90			lhs.typ = Typ[Invalid]
91		}
92		return
93	}
94
95	// rhs must be a constant
96	if x.mode != constant_ {
97		check.errorf(x, _InvalidConstInit, "%s is not constant", x)
98		if lhs.typ == nil {
99			lhs.typ = Typ[Invalid]
100		}
101		return
102	}
103	assert(isConstType(x.typ))
104
105	// If the lhs doesn't have a type yet, use the type of x.
106	if lhs.typ == nil {
107		lhs.typ = x.typ
108	}
109
110	check.assignment(x, lhs.typ, "constant declaration")
111	if x.mode == invalid {
112		return
113	}
114
115	lhs.val = x.val
116}
117
118func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
119	if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
120		if lhs.typ == nil {
121			lhs.typ = Typ[Invalid]
122		}
123		return nil
124	}
125
126	// If the lhs doesn't have a type yet, use the type of x.
127	if lhs.typ == nil {
128		typ := x.typ
129		if isUntyped(typ) {
130			// convert untyped types to default types
131			if typ == Typ[UntypedNil] {
132				check.errorf(x, _UntypedNil, "use of untyped nil in %s", context)
133				lhs.typ = Typ[Invalid]
134				return nil
135			}
136			typ = Default(typ)
137		}
138		lhs.typ = typ
139	}
140
141	check.assignment(x, lhs.typ, context)
142	if x.mode == invalid {
143		return nil
144	}
145
146	return x.typ
147}
148
149func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
150	if x.mode == invalid || x.typ == Typ[Invalid] {
151		return nil
152	}
153
154	// Determine if the lhs is a (possibly parenthesized) identifier.
155	ident, _ := unparen(lhs).(*ast.Ident)
156
157	// Don't evaluate lhs if it is the blank identifier.
158	if ident != nil && ident.Name == "_" {
159		check.recordDef(ident, nil)
160		check.assignment(x, nil, "assignment to _ identifier")
161		if x.mode == invalid {
162			return nil
163		}
164		return x.typ
165	}
166
167	// If the lhs is an identifier denoting a variable v, this assignment
168	// is not a 'use' of v. Remember current value of v.used and restore
169	// after evaluating the lhs via check.expr.
170	var v *Var
171	var v_used bool
172	if ident != nil {
173		if obj := check.lookup(ident.Name); obj != nil {
174			// It's ok to mark non-local variables, but ignore variables
175			// from other packages to avoid potential race conditions with
176			// dot-imported variables.
177			if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
178				v = w
179				v_used = v.used
180			}
181		}
182	}
183
184	var z operand
185	check.expr(&z, lhs)
186	if v != nil {
187		v.used = v_used // restore v.used
188	}
189
190	if z.mode == invalid || z.typ == Typ[Invalid] {
191		return nil
192	}
193
194	// spec: "Each left-hand side operand must be addressable, a map index
195	// expression, or the blank identifier. Operands may be parenthesized."
196	switch z.mode {
197	case invalid:
198		return nil
199	case variable, mapindex:
200		// ok
201	default:
202		if sel, ok := z.expr.(*ast.SelectorExpr); ok {
203			var op operand
204			check.expr(&op, sel.X)
205			if op.mode == mapindex {
206				check.errorf(&z, _UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(z.expr))
207				return nil
208			}
209		}
210		check.errorf(&z, _UnassignableOperand, "cannot assign to %s", &z)
211		return nil
212	}
213
214	check.assignment(x, z.typ, "assignment")
215	if x.mode == invalid {
216		return nil
217	}
218
219	return x.typ
220}
221
222// If returnPos is valid, initVars is called to type-check the assignment of
223// return expressions, and returnPos is the position of the return statement.
224func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
225	l := len(lhs)
226	get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
227	if get == nil || l != r {
228		// invalidate lhs and use rhs
229		for _, obj := range lhs {
230			if obj.typ == nil {
231				obj.typ = Typ[Invalid]
232			}
233		}
234		if get == nil {
235			return // error reported by unpack
236		}
237		check.useGetter(get, r)
238		if returnPos.IsValid() {
239			check.errorf(atPos(returnPos), _WrongResultCount, "wrong number of return values (want %d, got %d)", l, r)
240			return
241		}
242		check.errorf(rhs[0], _WrongAssignCount, "cannot initialize %d variables with %d values", l, r)
243		return
244	}
245
246	context := "assignment"
247	if returnPos.IsValid() {
248		context = "return statement"
249	}
250
251	var x operand
252	if commaOk {
253		var a [2]Type
254		for i := range a {
255			get(&x, i)
256			a[i] = check.initVar(lhs[i], &x, context)
257		}
258		check.recordCommaOkTypes(rhs[0], a)
259		return
260	}
261
262	for i, lhs := range lhs {
263		get(&x, i)
264		check.initVar(lhs, &x, context)
265	}
266}
267
268func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
269	l := len(lhs)
270	get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
271	if get == nil {
272		check.useLHS(lhs...)
273		return // error reported by unpack
274	}
275	if l != r {
276		check.useGetter(get, r)
277		check.errorf(rhs[0], _WrongAssignCount, "cannot assign %d values to %d variables", r, l)
278		return
279	}
280
281	var x operand
282	if commaOk {
283		var a [2]Type
284		for i := range a {
285			get(&x, i)
286			a[i] = check.assignVar(lhs[i], &x)
287		}
288		check.recordCommaOkTypes(rhs[0], a)
289		return
290	}
291
292	for i, lhs := range lhs {
293		get(&x, i)
294		check.assignVar(lhs, &x)
295	}
296}
297
298func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) {
299	top := len(check.delayed)
300	scope := check.scope
301
302	// collect lhs variables
303	var newVars []*Var
304	var lhsVars = make([]*Var, len(lhs))
305	for i, lhs := range lhs {
306		var obj *Var
307		if ident, _ := lhs.(*ast.Ident); ident != nil {
308			// Use the correct obj if the ident is redeclared. The
309			// variable's scope starts after the declaration; so we
310			// must use Scope.Lookup here and call Scope.Insert
311			// (via check.declare) later.
312			name := ident.Name
313			if alt := scope.Lookup(name); alt != nil {
314				// redeclared object must be a variable
315				if alt, _ := alt.(*Var); alt != nil {
316					obj = alt
317				} else {
318					check.errorf(lhs, _UnassignableOperand, "cannot assign to %s", lhs)
319				}
320				check.recordUse(ident, alt)
321			} else {
322				// declare new variable, possibly a blank (_) variable
323				obj = NewVar(ident.Pos(), check.pkg, name, nil)
324				if name != "_" {
325					newVars = append(newVars, obj)
326				}
327				check.recordDef(ident, obj)
328			}
329		} else {
330			check.useLHS(lhs)
331			check.invalidAST(lhs, "cannot declare %s", lhs)
332		}
333		if obj == nil {
334			obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
335		}
336		lhsVars[i] = obj
337	}
338
339	check.initVars(lhsVars, rhs, token.NoPos)
340
341	// process function literals in rhs expressions before scope changes
342	check.processDelayed(top)
343
344	// declare new variables
345	if len(newVars) > 0 {
346		// spec: "The scope of a constant or variable identifier declared inside
347		// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
348		// for short variable declarations) and ends at the end of the innermost
349		// containing block."
350		scopePos := rhs[len(rhs)-1].End()
351		for _, obj := range newVars {
352			check.declare(scope, nil, obj, scopePos) // recordObject already called
353		}
354	} else {
355		check.softErrorf(pos, _NoNewVar, "no new variables on left side of :=")
356	}
357}
358