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 = defaultType(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.conf, 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 = defaultType(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.scope.LookupParent(ident.Name, token.NoPos); obj != nil {
157			v, _ = obj.(*Var)
158			if v != nil {
159				v_used = v.used
160			}
161		}
162	}
163
164	var z operand
165	check.expr(&z, lhs)
166	if v != nil {
167		v.used = v_used // restore v.used
168	}
169
170	if z.mode == invalid || z.typ == Typ[Invalid] {
171		return nil
172	}
173
174	// spec: "Each left-hand side operand must be addressable, a map index
175	// expression, or the blank identifier. Operands may be parenthesized."
176	switch z.mode {
177	case invalid:
178		return nil
179	case variable, mapindex:
180		// ok
181	default:
182		check.errorf(z.pos(), "cannot assign to %s", &z)
183		return nil
184	}
185
186	check.assignment(x, z.typ, "assignment")
187	if x.mode == invalid {
188		return nil
189	}
190
191	return x.typ
192}
193
194// If returnPos is valid, initVars is called to type-check the assignment of
195// return expressions, and returnPos is the position of the return statement.
196func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
197	l := len(lhs)
198	get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
199	if get == nil || l != r {
200		// invalidate lhs and use rhs
201		for _, obj := range lhs {
202			if obj.typ == nil {
203				obj.typ = Typ[Invalid]
204			}
205		}
206		if get == nil {
207			return // error reported by unpack
208		}
209		check.useGetter(get, r)
210		if returnPos.IsValid() {
211			check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r)
212			return
213		}
214		check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
215		return
216	}
217
218	context := "assignment"
219	if returnPos.IsValid() {
220		context = "return statement"
221	}
222
223	var x operand
224	if commaOk {
225		var a [2]Type
226		for i := range a {
227			get(&x, i)
228			a[i] = check.initVar(lhs[i], &x, context)
229		}
230		check.recordCommaOkTypes(rhs[0], a)
231		return
232	}
233
234	for i, lhs := range lhs {
235		get(&x, i)
236		check.initVar(lhs, &x, context)
237	}
238}
239
240func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
241	l := len(lhs)
242	get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
243	if get == nil {
244		return // error reported by unpack
245	}
246	if l != r {
247		check.useGetter(get, r)
248		check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
249		return
250	}
251
252	var x operand
253	if commaOk {
254		var a [2]Type
255		for i := range a {
256			get(&x, i)
257			a[i] = check.assignVar(lhs[i], &x)
258		}
259		check.recordCommaOkTypes(rhs[0], a)
260		return
261	}
262
263	for i, lhs := range lhs {
264		get(&x, i)
265		check.assignVar(lhs, &x)
266	}
267}
268
269func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
270	scope := check.scope
271
272	// collect lhs variables
273	var newVars []*Var
274	var lhsVars = make([]*Var, len(lhs))
275	for i, lhs := range lhs {
276		var obj *Var
277		if ident, _ := lhs.(*ast.Ident); ident != nil {
278			// Use the correct obj if the ident is redeclared. The
279			// variable's scope starts after the declaration; so we
280			// must use Scope.Lookup here and call Scope.Insert
281			// (via check.declare) later.
282			name := ident.Name
283			if alt := scope.Lookup(name); alt != nil {
284				// redeclared object must be a variable
285				if alt, _ := alt.(*Var); alt != nil {
286					obj = alt
287				} else {
288					check.errorf(lhs.Pos(), "cannot assign to %s", lhs)
289				}
290				check.recordUse(ident, alt)
291			} else {
292				// declare new variable, possibly a blank (_) variable
293				obj = NewVar(ident.Pos(), check.pkg, name, nil)
294				if name != "_" {
295					newVars = append(newVars, obj)
296				}
297				check.recordDef(ident, obj)
298			}
299		} else {
300			check.errorf(lhs.Pos(), "cannot declare %s", lhs)
301		}
302		if obj == nil {
303			obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
304		}
305		lhsVars[i] = obj
306	}
307
308	check.initVars(lhsVars, rhs, token.NoPos)
309
310	// declare new variables
311	if len(newVars) > 0 {
312		// spec: "The scope of a constant or variable identifier declared inside
313		// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
314		// for short variable declarations) and ends at the end of the innermost
315		// containing block."
316		scopePos := rhs[len(rhs)-1].End()
317		for _, obj := range newVars {
318			check.declare(scope, nil, obj, scopePos) // recordObject already called
319		}
320	} else {
321		check.softErrorf(pos, "no new variables on left side of :=")
322	}
323}
324