1#![allow(dead_code)]
13use crate::SourceRead;
14
15use super::super::obj::EntityType;
16use super::super::objects::{ObjKey, TypeKey};
17use super::super::operand::{Operand, OperandMode};
18use super::super::typ;
19use super::check::{Checker, FilesContext};
20use super::util::UnpackResult;
21use go_parser::ast::Expr;
22use go_parser::ast::Node;
23use go_parser::Pos;
24
25impl<'a, S: SourceRead> Checker<'a, S> {
26 pub fn assignment(
32 &mut self,
33 x: &mut Operand,
34 t: Option<TypeKey>,
35 note: &str,
36 fctx: &mut FilesContext<S>,
37 ) {
38 self.single_value(x);
39 if x.invalid() {
40 return;
41 }
42
43 match x.mode {
44 OperandMode::Constant(_)
45 | OperandMode::Variable
46 | OperandMode::MapIndex
47 | OperandMode::Value
48 | OperandMode::CommaOk => {}
49 _ => unreachable!(),
50 }
51
52 let xt = x.typ.unwrap();
53 if typ::is_untyped(xt, self.tc_objs) {
54 if t.is_none() && xt == self.basic_type(typ::BasicType::UntypedNil) {
55 self.error(
56 x.pos(self.ast_objs),
57 format!("use of untyped nil in {}", note),
58 );
59 x.mode = OperandMode::Invalid;
60 return;
61 }
62 let target = if t.is_none() || typ::is_interface(t.unwrap(), self.tc_objs) {
68 typ::untyped_default_type(xt, self.tc_objs)
69 } else {
70 t.unwrap()
71 };
72 self.convert_untyped(x, target, fctx);
73 if x.invalid() {
74 return;
75 }
76 }
77 if t.is_none() {
83 return;
84 }
85
86 let mut reason = String::new();
87 if !x.assignable_to(t.unwrap(), Some(&mut reason), self, fctx) {
88 let xd = self.new_dis(x);
89 let td = self.new_dis(t.as_ref().unwrap());
90 if reason.is_empty() {
91 self.error(
92 xd.pos(),
93 format!("cannot use {} as {} value in {}", xd, td, note),
94 );
95 } else {
96 self.error(
97 xd.pos(),
98 format!("cannot use {} as {} value in {}: {}", xd, td, note, reason),
99 );
100 }
101 x.mode = OperandMode::Invalid;
102 }
103 }
104
105 pub fn init_const(&mut self, lhskey: ObjKey, x: &mut Operand, fctx: &mut FilesContext<S>) {
106 let invalid_type = self.invalid_type();
107 let lhs = self.lobj_mut(lhskey);
108 if x.invalid() || x.typ == Some(invalid_type) {
109 lhs.set_type(Some(invalid_type));
110 }
111 if lhs.typ() == Some(invalid_type) {
112 return;
113 }
114
115 let lhs = self.lobj_mut(lhskey);
117 if lhs.typ().is_none() {
118 lhs.set_type(x.typ);
119 }
120 if let OperandMode::Constant(_) = &x.mode {
122 debug_assert!(typ::is_const_type(x.typ.unwrap(), self.tc_objs));
123 let t = self.lobj(lhskey).typ();
124 self.assignment(x, t, "constant declaration", fctx);
125 if x.mode != OperandMode::Invalid {
126 self.lobj_mut(lhskey)
127 .set_const_val(x.mode.constant_val().unwrap().clone());
128 }
129 } else {
130 let dis = self.new_dis(x);
131 self.error(dis.pos(), format!("{} is not constant", dis));
132 }
133 }
134
135 pub fn init_var(
136 &mut self,
137 lhskey: ObjKey,
138 x: &mut Operand,
139 msg: &str,
140 fctx: &mut FilesContext<S>,
141 ) -> Option<TypeKey> {
142 let invalid_type = self.invalid_type();
143 let lhs = self.lobj_mut(lhskey);
144 if x.invalid() || x.typ == Some(invalid_type) || lhs.typ() == Some(invalid_type) {
145 if lhs.typ().is_none() {
146 lhs.set_type(Some(invalid_type));
147 }
148 return None;
149 }
150 if lhs.typ().is_none() {
152 let xt = x.typ.unwrap();
153 let lhs_type = if typ::is_untyped(xt, self.tc_objs) {
154 if xt == self.basic_type(typ::BasicType::UntypedNil) {
156 self.error(
157 x.pos(self.ast_objs),
158 format!("use of untyped nil in {}", msg),
159 );
160 invalid_type
161 } else {
162 typ::untyped_default_type(xt, self.tc_objs)
163 }
164 } else {
165 xt
166 };
167
168 self.lobj_mut(lhskey).set_type(Some(lhs_type));
169 if lhs_type == invalid_type {
170 return None;
171 }
172 }
173 let t = self.lobj(lhskey).typ().clone();
174 self.assignment(x, t, msg, fctx);
175 if x.mode != OperandMode::Invalid {
176 x.typ
177 } else {
178 None
179 }
180 }
181
182 pub fn assign_var(
183 &mut self,
184 lhs: &Expr,
185 x: &mut Operand,
186 fctx: &mut FilesContext<S>,
187 ) -> Option<TypeKey> {
188 let invalid_type = self.invalid_type();
189 if x.invalid() || x.typ == Some(invalid_type) {
190 return None;
191 }
192
193 let mut v: Option<ObjKey> = None;
194 let mut v_used = false;
195 if let Expr::Ident(ikey) = Checker::<S>::unparen(lhs) {
197 let name = &self.ast_ident(*ikey).name;
198 if name == "_" {
199 self.result.record_def(*ikey, None);
200 self.assignment(x, None, "assignment to _ identifier", fctx);
201 return if x.mode != OperandMode::Invalid {
202 x.typ
203 } else {
204 None
205 };
206 } else {
207 if let Some(okey) = self.lookup(name) {
211 if let EntityType::Var(prop) = self.lobj(okey).entity_type() {
215 v = Some(okey);
216 v_used = prop.used;
217 }
218 }
219 }
220 }
221
222 let mut z = Operand::new();
223 self.expr(&mut z, lhs, fctx);
224 if let Some(okey) = v {
225 self.lobj_mut(okey)
226 .entity_type_mut()
227 .var_property_mut()
228 .used = v_used; }
230
231 if z.mode == OperandMode::Invalid || z.typ == Some(invalid_type) {
232 return None;
233 }
234
235 match z.mode {
238 OperandMode::Invalid => unreachable!(),
239 OperandMode::Variable | OperandMode::MapIndex => {}
240 _ => {
241 if let Some(expr) = &z.expr {
242 if let Expr::Selector(sexpr) = expr {
243 let mut op = Operand::new();
244 self.expr(&mut op, &sexpr.expr, fctx);
245 if op.mode == OperandMode::MapIndex {
246 let ed = self.new_dis(expr);
247 self.error(
248 ed.pos(),
249 format!("cannot assign to struct field {} in map", ed),
250 );
251 return None;
252 }
253 }
254 }
255 let dis = self.new_dis(&z);
256 self.error(dis.pos(), format!("cannot assign to {}", dis));
257 return None;
258 }
259 }
260
261 self.assignment(x, z.typ, "assignment", fctx);
262 if x.mode != OperandMode::Invalid {
263 x.typ
264 } else {
265 None
266 }
267 }
268
269 pub fn init_vars(
272 &mut self,
273 lhs: &Vec<ObjKey>,
274 rhs: &Vec<Expr>,
275 return_pos: Option<Pos>,
276 fctx: &mut FilesContext<S>,
277 ) {
278 let invalid_type = self.invalid_type();
279 let ll = lhs.len();
280 let result = self.unpack(rhs, ll, ll == 2 && return_pos.is_none(), false, fctx);
286 let mut invalidate_lhs = || {
287 for okey in lhs.iter() {
288 let lobj = self.lobj_mut(*okey);
289 if lobj.typ().is_none() {
290 lobj.set_type(Some(invalid_type));
291 }
292 }
293 };
294
295 match result {
296 UnpackResult::Error => invalidate_lhs(),
297 UnpackResult::Tuple(_, _, _)
298 | UnpackResult::CommaOk(_, _)
299 | UnpackResult::Mutliple(_, _)
300 | UnpackResult::Single(_, _)
301 | UnpackResult::Nothing(_) => match result.rhs_count() {
302 (count, std::cmp::Ordering::Greater) | (count, std::cmp::Ordering::Less) => {
303 invalidate_lhs();
304 result.use_(self, 0, fctx);
305 if let Some(p) = return_pos {
306 self.error(
307 p,
308 format!("wrong number of return values (want {}, got {})", ll, count),
309 )
310 } else {
311 self.error(
312 rhs[0].pos(self.ast_objs),
313 format!("cannot initialize {} variables with {} values", ll, count),
314 )
315 }
316 return;
317 }
318 _ => {
319 let context = if return_pos.is_some() {
320 "return statement"
321 } else {
322 "assignment"
323 };
324 for (i, l) in lhs.iter().enumerate() {
325 let mut x = Operand::new();
326 result.get(self, &mut x, i, fctx);
327 self.init_var(*l, &mut x, context, fctx);
328 }
329 }
330 },
331 }
332 if let UnpackResult::CommaOk(e, types) = result {
333 self.result.record_comma_ok_types::<S>(
334 e.as_ref().unwrap(),
335 &types,
336 self.tc_objs,
337 self.ast_objs,
338 self.pkg,
339 );
340 }
341 }
342
343 pub fn assign_vars(&mut self, lhs: &Vec<Expr>, rhs: &Vec<Expr>, fctx: &mut FilesContext<S>) {
344 let ll = lhs.len();
345 let result = self.unpack(rhs, ll, ll == 2, false, fctx);
346 match result {
347 UnpackResult::Error => self.use_lhs(lhs, fctx),
348 UnpackResult::Tuple(_, _, _)
349 | UnpackResult::CommaOk(_, _)
350 | UnpackResult::Mutliple(_, _)
351 | UnpackResult::Single(_, _)
352 | UnpackResult::Nothing(_) => match result.rhs_count() {
353 (count, std::cmp::Ordering::Greater) | (count, std::cmp::Ordering::Less) => {
354 result.use_(self, 0, fctx);
355 self.error(
356 rhs[0].pos(self.ast_objs),
357 format!("cannot assign {} values to {} variables", count, ll),
358 );
359 return;
360 }
361 _ => {
362 for (i, l) in lhs.iter().enumerate() {
363 let mut x = Operand::new();
364 result.get(self, &mut x, i, fctx);
365 self.assign_var(l, &mut x, fctx);
366 }
367 }
368 },
369 }
370 if let UnpackResult::CommaOk(e, types) = result {
371 self.result.record_comma_ok_types::<S>(
372 e.as_ref().unwrap(),
373 &types,
374 self.tc_objs,
375 self.ast_objs,
376 self.pkg,
377 );
378 }
379 }
380
381 pub fn short_var_decl(
382 &mut self,
383 lhs: &Vec<Expr>,
384 rhs: &Vec<Expr>,
385 pos: Pos,
386 fctx: &mut FilesContext<S>,
387 ) {
388 let top = fctx.delayed_count();
389 let scope_key = self.octx.scope.unwrap();
390 let mut new_vars = Vec::new();
391 let lhs_vars = lhs
392 .iter()
393 .map(|x| {
394 if let Expr::Ident(ikey) = x {
395 let ident = self.ast_ident(*ikey);
400 if let Some(okey) = self.tc_objs.scopes[scope_key].lookup(&ident.name) {
401 self.result.record_use(*ikey, *okey);
402 if self.lobj(*okey).entity_type().is_var() {
403 *okey
404 } else {
405 let pos = x.pos(self.ast_objs);
406 self.error(pos, format!("cannot assign to {}", self.new_dis(x)));
407 self.tc_objs
409 .new_var(pos, Some(self.pkg), "_".to_owned(), None)
410 }
411 } else {
412 let (pos, pkg, name) = (ident.pos, Some(self.pkg), ident.name.clone());
414 let okey = self.tc_objs.new_var(pos, pkg, name.clone(), None);
415 if name != "_" {
416 new_vars.push(okey);
417 }
418 self.result.record_def(*ikey, Some(okey));
419 okey
420 }
421 } else {
422 self.use_lhs(&vec![x.clone()], fctx);
423 let pos = x.pos(self.ast_objs);
424 self.error(pos, format!("cannot declare {}", self.new_dis(x)));
425 self.tc_objs
427 .new_var(pos, Some(self.pkg), "_".to_owned(), None)
428 }
429 })
430 .collect();
431
432 self.init_vars(&lhs_vars, rhs, None, fctx);
433
434 fctx.process_delayed(top, self);
436
437 if new_vars.len() > 0 {
439 let scope_pos = rhs[rhs.len() - 1].end(self.ast_objs);
444 for okey in new_vars.iter() {
445 self.declare(scope_key, None, *okey, scope_pos);
446 }
447 } else {
448 self.soft_error(pos, "no new variables on left side of :=".to_owned());
449 }
450 }
451}