1#![allow(dead_code)]
13use crate::SourceRead;
14
15use super::check::{Checker, FilesContext};
16use super::constant;
17use super::lookup::missing_method;
18use super::objects::{TCObjects, TypeKey};
19use super::typ;
20use super::typ::{fmt_type, BasicType, Type};
21use super::universe::{Builtin, Universe};
22use go_parser::ast::*;
23use go_parser::visitor::{walk_expr, ExprVisitor};
24use go_parser::{AstObjects, FuncTypeKey, IdentKey, Pos, Token};
25use std::fmt;
26use std::fmt::Display;
27use std::fmt::Write;
28
29#[derive(Clone, Debug, PartialEq)]
31pub enum OperandMode {
32 Invalid, NoValue, Builtin(Builtin), TypeExpr, Constant(constant::Value), Variable, MapIndex, Value, CommaOk, }
42
43impl OperandMode {
44 pub fn constant_val(&self) -> Option<&constant::Value> {
45 match self {
46 OperandMode::Constant(v) => Some(v),
47 _ => None,
48 }
49 }
50
51 pub fn builtin_id(&self) -> Option<Builtin> {
52 match self {
53 OperandMode::Builtin(id) => Some(*id),
54 _ => None,
55 }
56 }
57}
58
59impl fmt::Display for OperandMode {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 f.write_str(match self {
62 OperandMode::Invalid => "invalid operand",
63 OperandMode::NoValue => "no value",
64 OperandMode::Builtin(_) => "built-in",
65 OperandMode::TypeExpr => "type",
66 OperandMode::Constant(_) => "constant",
67 OperandMode::Variable => "variable",
68 OperandMode::MapIndex => "map index expression",
69 OperandMode::Value => "value",
70 OperandMode::CommaOk => "comma, ok expression",
71 })
72 }
73}
74
75#[derive(Clone, Debug)]
80pub struct Operand {
81 pub mode: OperandMode,
82 pub expr: Option<Expr>,
83 pub typ: Option<TypeKey>,
84}
85
86impl Operand {
87 pub fn new() -> Operand {
88 Operand::with(OperandMode::Invalid, None, None)
89 }
90
91 pub fn with(mode: OperandMode, expr: Option<Expr>, typ: Option<TypeKey>) -> Operand {
92 Operand {
93 mode: mode,
94 expr: expr,
95 typ: typ,
96 }
97 }
98
99 pub fn invalid(&self) -> bool {
100 self.mode == OperandMode::Invalid
101 }
102
103 pub fn pos(&self, ast_objs: &AstObjects) -> Pos {
104 if let Some(e) = &self.expr {
105 e.pos(ast_objs)
106 } else {
107 0
108 }
109 }
110
111 pub fn set_const(&mut self, t: &Token, u: &Universe) {
112 let bt = match t {
113 Token::INT(_) => BasicType::UntypedInt,
114 Token::FLOAT(_) => BasicType::UntypedFloat,
115 Token::IMAG(_) => BasicType::UntypedComplex,
116 Token::CHAR(_) => BasicType::UntypedRune,
117 Token::STRING(_) => BasicType::UntypedString,
118 _ => unreachable!(),
119 };
120 self.mode = OperandMode::Constant(constant::Value::with_literal(t));
121 self.typ = Some(u.types()[&bt]);
122 }
123
124 pub fn is_nil(&self, u: &Universe) -> bool {
125 match self.mode {
126 OperandMode::Value => self.typ == Some(u.types()[&BasicType::UntypedNil]),
127 _ => false,
128 }
129 }
130
131 pub fn assignable_to<S: SourceRead>(
135 &self,
136 t: TypeKey,
137 reason: Option<&mut String>,
138 checker: &mut Checker<S>,
139 fctx: &mut FilesContext<S>,
140 ) -> bool {
141 let objs = &checker.tc_objs;
142 let u = objs.universe();
143 if self.invalid() || t == u.types()[&BasicType::Invalid] {
144 return true; }
146
147 if typ::identical(self.typ.unwrap(), t, objs) {
148 return true;
149 }
150
151 let (k_left, k_right) = (t, self.typ.unwrap());
152 let t_left = &objs.types[k_left];
153 let t_right = &objs.types[k_right];
154 let ut_key_left = typ::underlying_type(k_left, objs);
155 let ut_key_right = typ::underlying_type(k_right, objs);
156 let ut_left = &objs.types[ut_key_left];
157 let ut_right = &objs.types[ut_key_right];
158
159 if ut_right.is_untyped(objs) {
160 match ut_left {
161 Type::Basic(detail) => {
162 if self.is_nil(u) && detail.typ() == BasicType::UnsafePointer {
163 return true;
164 }
165 if let OperandMode::Constant(val) = &self.mode {
166 return val.representable(detail, None);
167 }
168 if detail.typ() == BasicType::Bool {
171 return ut_right.try_as_basic().unwrap().typ() == BasicType::UntypedBool;
172 }
173 }
174 Type::Interface(detail) => return self.is_nil(u) || detail.is_empty(),
175 Type::Pointer(_)
176 | Type::Signature(_)
177 | Type::Slice(_)
178 | Type::Map(_)
179 | Type::Chan(_) => return self.is_nil(u),
180 _ => {}
181 }
182 }
183
184 if typ::identical(ut_key_right, ut_key_left, objs)
188 && (!t_right.is_named() || !t_left.is_named())
189 {
190 return true;
191 }
192
193 if ut_left.try_as_interface().is_some() {
195 if let Some((m, wrong_type)) = missing_method(k_right, ut_key_left, true, checker, fctx)
196 {
197 if let Some(re) = reason {
198 let msg = if wrong_type {
199 "wrong type for method"
200 } else {
201 "missing method"
202 };
203 *re = format!("{} {}", msg, checker.tc_objs.lobjs[m].name());
204 }
205 return false;
206 }
207 return true;
208 }
209
210 if let Some(cr) = ut_right.try_as_chan() {
214 if cr.dir() == typ::ChanDir::SendRecv {
215 if let Some(cl) = ut_left.try_as_chan() {
216 if typ::identical(cr.elem(), cl.elem(), objs) {
217 return !t_right.is_named() || !t_left.is_named();
218 }
219 }
220 }
221 }
222
223 false
224 }
225
226 pub fn fmt(
253 &self,
254 f: &mut fmt::Formatter<'_>,
255 tc_objs: &TCObjects,
256 ast_objs: &AstObjects,
257 ) -> fmt::Result {
258 let universe = tc_objs.universe();
259 let mut has_expr = true;
260
261 if let Some(expr) = &self.expr {
263 fmt_expr(&expr, f, ast_objs)?;
264 } else {
265 match &self.mode {
266 OperandMode::Builtin(bi) => {
267 f.write_str(universe.builtins()[bi].name)?;
268 }
269 OperandMode::TypeExpr => {
270 fmt_type(self.typ, f, tc_objs)?;
271 }
272 OperandMode::Constant(val) => {
273 f.write_str(&val.to_string())?;
274 }
275 _ => has_expr = false,
276 }
277 }
278 if has_expr {
279 f.write_str(" (")?;
280 }
281
282 let has_type = match self.mode {
284 OperandMode::Invalid
285 | OperandMode::NoValue
286 | OperandMode::Builtin(_)
287 | OperandMode::TypeExpr => false,
288 _ => {
289 let tval = &tc_objs.types[self.typ.unwrap()];
290 if tval.is_untyped(tc_objs) {
291 f.write_str(tval.try_as_basic().unwrap().name())?;
292 f.write_char(' ')?;
293 false
294 } else {
295 true
296 }
297 }
298 };
299
300 self.mode.fmt(f)?;
302
303 if let OperandMode::Constant(val) = &self.mode {
305 if self.expr.is_some() {
306 f.write_char(' ')?;
307 f.write_str(&val.to_string())?;
308 }
309 }
310
311 if has_type {
313 if self.typ != Some(universe.types()[&BasicType::Invalid]) {
314 f.write_str(" of type ")?;
315 fmt_type(self.typ, f, tc_objs)?;
316 } else {
317 f.write_str(" with invalid type")?;
318 }
319 }
320
321 if has_expr {
323 f.write_char(')')?;
324 }
325 Ok(())
326 }
327}
328
329pub fn fmt_expr(expr: &Expr, f: &mut fmt::Formatter<'_>, ast_objs: &AstObjects) -> fmt::Result {
333 ExprFormater {
338 f: f,
339 ast_objs: ast_objs,
340 }
341 .visit_expr(expr)
342}
343
344struct ExprFormater<'a, 'b> {
345 f: &'a mut fmt::Formatter<'b>,
346 ast_objs: &'a AstObjects,
347}
348
349impl<'a, 'b> ExprVisitor for ExprFormater<'a, 'b> {
350 type Result = fmt::Result;
351
352 fn visit_expr_ident(&mut self, _: &Expr, ident: &IdentKey) -> Self::Result {
353 self.fmt_ident(ident)
354 }
355
356 fn visit_expr_ellipsis(&mut self, _: &Expr, els: &Option<Expr>) -> Self::Result {
357 self.f.write_str("...")?;
358 if let Some(e) = els {
359 self.visit_expr(e)?;
360 }
361 Ok(())
362 }
363
364 fn visit_expr_basic_lit(&mut self, _: &Expr, blit: &BasicLit) -> Self::Result {
365 blit.token.fmt(self.f)
366 }
367
368 fn visit_expr_func_lit(&mut self, this: &Expr, flit: &FuncLit) -> Self::Result {
369 self.f.write_char('(')?;
370 self.visit_expr_func_type(this, &flit.typ)?;
371 self.f.write_str(" literal)")
372 }
373
374 fn visit_expr_composit_lit(&mut self, _: &Expr, clit: &CompositeLit) -> Self::Result {
375 self.f.write_char('(')?;
376 match &clit.typ {
377 Some(t) => {
378 self.visit_expr(t)?;
379 }
380 None => {
381 self.f.write_str("(bad expr)")?;
382 }
383 }
384 self.f.write_str(" literal)")
385 }
386
387 fn visit_expr_paren(&mut self, _: &Expr, expr: &Expr) -> Self::Result {
388 self.f.write_char('(')?;
389 self.visit_expr(expr)?;
390 self.f.write_char(')')
391 }
392
393 fn visit_expr_selector(&mut self, this: &Expr, expr: &Expr, ident: &IdentKey) -> Self::Result {
394 self.visit_expr(expr)?;
395 self.f.write_char('.')?;
396 self.visit_expr_ident(this, ident)
397 }
398
399 fn visit_expr_index(&mut self, _: &Expr, expr: &Expr, index: &Expr) -> Self::Result {
400 self.visit_expr(expr)?;
401 self.f.write_char('[')?;
402 self.visit_expr(index)?;
403 self.f.write_char(']')
404 }
405
406 fn visit_expr_slice(
407 &mut self,
408 _: &Expr,
409 expr: &Expr,
410 low: &Option<Expr>,
411 high: &Option<Expr>,
412 max: &Option<Expr>,
413 ) -> Self::Result {
414 self.visit_expr(expr)?;
415 self.f.write_char('[')?;
416 if let Some(l) = low {
417 self.visit_expr(l)?;
418 }
419 self.f.write_char(':')?;
420 if let Some(h) = high {
421 self.visit_expr(h)?;
422 }
423 if let Some(m) = max {
424 self.f.write_char(':')?;
425 self.visit_expr(m)?;
426 }
427 self.f.write_char(']')
428 }
429
430 fn visit_expr_type_assert(
431 &mut self,
432 _: &Expr,
433 expr: &Expr,
434 typ: &Option<Expr>,
435 ) -> Self::Result {
436 self.visit_expr(expr)?;
437 self.f.write_str(".(")?;
438 match &typ {
439 Some(t) => {
440 self.visit_expr(t)?;
441 }
442 None => {
443 self.f.write_str("(bad expr)")?;
444 }
445 }
446 self.f.write_char(')')
447 }
448
449 fn visit_expr_call(
450 &mut self,
451 _: &Expr,
452 func: &Expr,
453 args: &Vec<Expr>,
454 ellipsis: bool,
455 ) -> Self::Result {
456 self.visit_expr(func)?;
457 self.f.write_char('(')?;
458 for (i, arg) in args.iter().enumerate() {
459 if i > 0 {
460 self.f.write_str(", ")?;
461 }
462 self.visit_expr(arg)?;
463 }
464 if ellipsis {
465 self.f.write_str("...")?;
466 }
467 self.f.write_char(')')
468 }
469
470 fn visit_expr_star(&mut self, _: &Expr, expr: &Expr) -> Self::Result {
471 self.f.write_char('*')?;
472 self.visit_expr(expr)
473 }
474
475 fn visit_expr_unary(&mut self, _: &Expr, expr: &Expr, op: &Token) -> Self::Result {
476 op.fmt(self.f)?;
477 self.visit_expr(expr)
478 }
479
480 fn visit_expr_binary(
481 &mut self,
482 _: &Expr,
483 left: &Expr,
484 op: &Token,
485 right: &Expr,
486 ) -> Self::Result {
487 self.visit_expr(left)?;
488 self.f.write_fmt(format_args!(" {} ", op))?;
489 self.visit_expr(right)
490 }
491
492 fn visit_expr_key_value(&mut self, _: &Expr, _: &Expr, _: &Expr) -> Self::Result {
493 self.f.write_str("(bad expr)")
494 }
495
496 fn visit_expr_array_type(&mut self, _: &Expr, len: &Option<Expr>, elm: &Expr) -> Self::Result {
497 self.f.write_char('[')?;
498 if let Some(l) = len {
499 self.visit_expr(l)?;
500 }
501 self.f.write_char(']')?;
502 self.visit_expr(elm)
503 }
504
505 fn visit_expr_struct_type(&mut self, _: &Expr, s: &StructType) -> Self::Result {
506 self.f.write_str("struct{")?;
507 self.fmt_fields(&s.fields, "; ", false)?;
508 self.f.write_char('}')
509 }
510
511 fn visit_expr_func_type(&mut self, _: &Expr, s: &FuncTypeKey) -> Self::Result {
512 self.f.write_str("func")?;
513 self.fmt_sig(&self.ast_objs.ftypes[*s])
514 }
515
516 fn visit_expr_interface_type(&mut self, _: &Expr, s: &InterfaceType) -> Self::Result {
517 self.f.write_str("interface{")?;
518 self.fmt_fields(&s.methods, "; ", true)?;
519 self.f.write_char('}')
520 }
521
522 fn visit_map_type(&mut self, _: &Expr, key: &Expr, val: &Expr, _: &Expr) -> Self::Result {
523 self.f.write_str("map[")?;
524 self.visit_expr(key)?;
525 self.f.write_char(']')?;
526 self.visit_expr(val)
527 }
528
529 fn visit_chan_type(&mut self, _: &Expr, chan: &Expr, dir: &ChanDir) -> Self::Result {
530 let s = match dir {
531 ChanDir::Send => "chan<- ",
532 ChanDir::Recv => "<-chan ",
533 ChanDir::SendRecv => "chan ",
534 };
535 self.f.write_str(s)?;
536 self.visit_expr(chan)
537 }
538
539 fn visit_bad_expr(&mut self, _: &Expr, _: &BadExpr) -> Self::Result {
540 self.f.write_str("(bad expr)")
541 }
542}
543
544impl<'a, 'b> ExprFormater<'a, 'b> {
545 fn visit_expr(&mut self, expr: &Expr) -> fmt::Result {
546 walk_expr(self, expr)
547 }
548
549 fn fmt_sig(&mut self, sig: &FuncType) -> fmt::Result {
550 self.f.write_char('(')?;
551 self.fmt_fields(&sig.params, ", ", false)?;
552 self.f.write_char(')')?;
553 if let Some(re) = &sig.results {
554 self.f.write_char(' ')?;
555 if re.list.len() == 1 {
556 let field = &self.ast_objs.fields[re.list[0]];
557 if field.names.len() == 0 {
558 self.visit_expr(&field.typ)?;
559 }
560 } else {
561 self.f.write_char('(')?;
562 self.fmt_fields(&re, ", ", false)?;
563 self.f.write_char(')')?;
564 }
565 }
566 Ok(())
567 }
568
569 fn fmt_fields(&mut self, fields: &FieldList, sep: &str, iface: bool) -> fmt::Result {
570 for (i, fkey) in fields.list.iter().enumerate() {
571 if i > 0 {
572 self.f.write_str(sep)?;
573 }
574 let field = &self.ast_objs.fields[*fkey];
575 for (i, name) in field.names.iter().enumerate() {
576 if i > 0 {
577 self.f.write_str(", ")?;
578 self.fmt_ident(name)?;
579 }
580 }
581 if iface {
583 match &field.typ {
584 Expr::Func(sig) => {
585 self.fmt_sig(&self.ast_objs.ftypes[*sig])?;
586 }
587 _ => {}
588 }
589 } else {
590 if field.names.len() > 0 {
592 self.f.write_char(' ')?;
593 }
594 self.visit_expr(&field.typ)?;
595 }
596 }
597 Ok(())
598 }
599
600 fn fmt_ident(&mut self, ident: &IdentKey) -> fmt::Result {
601 self.f.write_str(&self.ast_objs.idents[*ident].name)
602 }
603}