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