1use crate::SourceRead;
13
14use super::super::display::{Display, Displayer};
15use super::super::obj;
16use super::super::objects::{DeclInfoKey, ObjKey, PackageKey, ScopeKey, TCObjects, TypeKey};
17use super::super::operand::{Operand, OperandMode};
18use super::super::package::Package;
19use super::super::scope::Scope;
20use super::super::typ::{self, BasicType, Type};
21use super::super::universe::{Builtin, BuiltinInfo};
22use super::check::{Checker, FilesContext};
23use super::resolver::DeclInfo;
24use std::cmp::Ordering;
25
26use go_parser::{ast, ast::Expr, FilePos, IdentKey, Map, Pos};
27
28macro_rules! error_operand {
29 ($x:ident, $fmt:expr, $checker:ident) => {
30 let xd = $checker.new_dis(&$x);
31 $checker.error(xd.pos(), format!($fmt, xd));
32 };
33}
34
35#[derive(Debug)]
36pub enum UnpackResult<'a> {
37 Tuple(Option<Expr>, Vec<Option<TypeKey>>, Ordering), CommaOk(Option<Expr>, [TypeKey; 2]), Mutliple(&'a Vec<Expr>, Ordering), Single(Operand, Ordering), Nothing(Ordering), Error, }
44
45impl<'a> UnpackResult<'a> {
46 pub fn get<S: SourceRead>(
47 &self,
48 checker: &mut Checker<S>,
49 x: &mut Operand,
50 i: usize,
51 fctx: &mut FilesContext<S>,
52 ) {
53 match self {
54 UnpackResult::Tuple(expr, types, _) => {
55 x.mode = OperandMode::Value;
56 x.expr = expr.clone();
57 x.typ = types[i];
58 }
59 UnpackResult::CommaOk(expr, types) => {
60 x.mode = OperandMode::Value;
61 x.expr = expr.clone();
62 x.typ = Some(types[i]);
63 }
64 UnpackResult::Mutliple(exprs, _) => {
65 checker.multi_expr(x, &exprs[i], fctx);
66 }
67 UnpackResult::Single(sx, _) => {
68 x.mode = sx.mode.clone();
69 x.expr = sx.expr.clone();
70 x.typ = sx.typ;
71 }
72 UnpackResult::Nothing(_) => unreachable!(),
73 UnpackResult::Error => unreachable!(),
74 }
75 }
76
77 pub fn rhs_count(&self) -> (usize, Ordering) {
80 match self {
81 UnpackResult::Tuple(_, types, ord) => (types.len(), *ord),
82 UnpackResult::CommaOk(_, types) => (types.len(), Ordering::Equal),
83 UnpackResult::Mutliple(exprs, ord) => (exprs.len(), *ord),
84 UnpackResult::Single(_, ord) => (1, *ord),
85 UnpackResult::Nothing(ord) => (0, *ord),
86 UnpackResult::Error => unreachable!(),
87 }
88 }
89
90 pub fn use_<S: SourceRead>(
91 &self,
92 checker: &mut Checker<S>,
93 from: usize,
94 fctx: &mut FilesContext<S>,
95 ) {
96 let exprs = match self {
97 UnpackResult::Mutliple(exprs, _) => exprs,
98 _ => {
99 return;
100 }
101 };
102
103 let mut x = Operand::new();
104 for i in from..exprs.len() {
105 checker.multi_expr(&mut x, &exprs[i], fctx);
106 }
107 }
108
109 pub fn is_err(&self) -> bool {
110 match self {
111 UnpackResult::Error => true,
112 _ => false,
113 }
114 }
115}
116
117#[derive(Debug)]
118pub struct UnpackedResultLeftovers<'a> {
119 pub leftovers: &'a UnpackResult<'a>,
120 pub consumed: Option<&'a Vec<Operand>>,
121}
122
123impl<'a> UnpackedResultLeftovers<'a> {
124 pub fn new(
125 re: &'a UnpackResult<'a>,
126 consumed: Option<&'a Vec<Operand>>,
127 ) -> UnpackedResultLeftovers<'a> {
128 UnpackedResultLeftovers {
129 leftovers: re,
130 consumed: consumed,
131 }
132 }
133
134 pub fn use_all<S: SourceRead>(&self, checker: &mut Checker<S>, fctx: &mut FilesContext<S>) {
135 let from = if self.consumed.is_none() {
136 0
137 } else {
138 self.consumed.unwrap().len()
139 };
140 self.leftovers.use_(checker, from, fctx);
141 }
142
143 pub fn get<S: SourceRead>(
144 &self,
145 checker: &mut Checker<S>,
146 x: &mut Operand,
147 i: usize,
148 fctx: &mut FilesContext<S>,
149 ) {
150 if self.consumed.is_none() {
151 self.leftovers.get(checker, x, i, fctx);
152 return;
153 }
154 let consumed = self.consumed.unwrap();
155 if i < consumed.len() {
156 let c = &consumed[i];
157 x.mode = c.mode.clone();
158 x.expr = c.expr.clone();
159 x.typ = c.typ;
160 } else {
161 self.leftovers.get(checker, x, i, fctx);
162 }
163 }
164}
165
166impl<'a, S: SourceRead> Checker<'a, S> {
167 pub fn unparen(x: &Expr) -> &Expr {
168 if let Expr::Paren(p) = x {
169 Checker::<S>::unparen(&p.expr)
170 } else {
171 x
172 }
173 }
174
175 pub fn invalid_ast(&self, pos: Pos, err: &str) {
177 self.error(pos, format!("invalid AST: {}", err));
178 }
179
180 pub fn invalid_arg(&self, pos: Pos, err: &str) {
181 self.error(pos, format!("invalid argument: {}", err));
182 }
183
184 pub fn invalid_op(&self, pos: Pos, err: &str) {
185 self.error(pos, format!("invalid operation: {}", err));
186 }
187
188 pub fn obj_path_str(&self, path: &Vec<ObjKey>) -> String {
189 let names: Vec<&str> = path.iter().map(|p| self.lobj(*p).name().as_str()).collect();
190 names[..].join("->")
191 }
192
193 pub fn dump(&self, pos: Option<Pos>, msg: &str) {
194 if let Some(p) = pos {
195 let p = self.fset.position(p);
196 print!("checker dump({}):{}\n", p.unwrap_or(FilePos::null()), msg);
197 } else {
198 print!("checker dump:{}\n", msg);
199 }
200 }
201
202 pub fn print_trace(&self, pos: Pos, msg: &str) {
203 let p = self.fset.position(pos);
204 print!(
205 "{}:\t{}{}\n",
206 p.unwrap_or(FilePos::null()),
207 ". ".repeat(*self.indent.borrow()),
208 msg
209 );
210 }
211
212 pub fn trace_begin(&self, pos: Pos, msg: &str) {
213 self.print_trace(pos, msg);
214 *self.indent.borrow_mut() += 1;
215 }
216
217 pub fn trace_end(&self, pos: Pos, msg: &str) {
218 *self.indent.borrow_mut() -= 1;
219 self.print_trace(pos, msg);
220 }
221
222 pub fn has_cycle(&self, okey: ObjKey, path: &[ObjKey], report: bool) -> bool {
225 if let Some((i, _)) = path.iter().enumerate().find(|(_, &x)| x == okey) {
226 if report {
227 let obj_val = self.lobj(okey);
228 self.error(
229 obj_val.pos(),
230 format!("illegal cycle in declaration of {}", obj_val.name()),
231 );
232 for o in path[i..].iter() {
234 let oval = self.lobj(*o);
235 self.error(oval.pos(), format!("\t{} refers to", oval.name()));
236 }
237 self.error(obj_val.pos(), format!("\t{}", obj_val.name()));
238 }
239 return true;
240 }
241 false
242 }
243
244 pub fn comma_ok_type(
245 tc_objs: &mut TCObjects,
246 pos: usize,
247 pkg: PackageKey,
248 t: &[TypeKey; 2],
249 ) -> TypeKey {
250 let vars = vec![
251 tc_objs.lobjs.insert(obj::LangObj::new_var(
252 pos,
253 Some(pkg),
254 String::new(),
255 Some(t[0]),
256 )),
257 tc_objs.lobjs.insert(obj::LangObj::new_var(
258 pos,
259 Some(pkg),
260 String::new(),
261 Some(t[1]),
262 )),
263 ];
264 tc_objs.new_t_tuple(vars)
265 }
266
267 pub fn unpack<'b>(
268 &mut self,
269 rhs: &'b Vec<Expr>,
270 lhs_len: usize,
271 allow_comma_ok: bool,
272 variadic: bool,
273 fctx: &mut FilesContext<S>,
274 ) -> UnpackResult<'b> {
275 let do_match = |rhs_len: usize| {
276 let order = rhs_len.cmp(&lhs_len);
277 if variadic && order == Ordering::Greater {
278 Ordering::Equal
279 } else {
280 order
281 }
282 };
283 if rhs.len() != 1 {
284 let matching = do_match(rhs.len());
285 return if rhs.len() == 0 {
286 UnpackResult::Nothing(matching)
287 } else {
288 UnpackResult::Mutliple(rhs, matching)
289 };
290 }
291
292 let mut x = Operand::new();
293 self.multi_expr(&mut x, &rhs[0], fctx);
294 if x.invalid() {
295 return UnpackResult::Error;
296 }
297
298 if let Some(t) = self.otype(x.typ.unwrap()).try_as_tuple() {
299 let types: Vec<Option<TypeKey>> =
300 t.vars().iter().map(|x| self.lobj(*x).typ()).collect();
301 let matching = do_match(types.len());
302 return UnpackResult::Tuple(x.expr.clone(), types, matching);
303 } else if x.mode == OperandMode::MapIndex || x.mode == OperandMode::CommaOk {
304 if allow_comma_ok {
305 let types = [x.typ.unwrap(), self.basic_type(BasicType::UntypedBool)];
306 return UnpackResult::CommaOk(x.expr.clone(), types);
307 }
308 x.mode = OperandMode::Value;
309 }
310
311 UnpackResult::Single(x, do_match(1))
312 }
313
314 pub fn use_exprs(&mut self, exprs: &Vec<Expr>, fctx: &mut FilesContext<S>) {
315 let x = &mut Operand::new();
316 for e in exprs.iter() {
317 self.raw_expr(x, &e, None, fctx);
318 }
319 }
320
321 pub fn use_lhs(&mut self, lhs: &Vec<Expr>, fctx: &mut FilesContext<S>) {
326 let x = &mut Operand::new();
327 for e in lhs.iter() {
328 let v = match Checker::<S>::unparen(e) {
329 Expr::Ident(ikey) => match &self.ast_ident(*ikey).name {
330 s if s == "_" => continue,
331 s => Scope::lookup_parent(
332 self.octx.scope.as_ref().unwrap(),
333 s,
334 None,
335 self.tc_objs,
336 )
337 .map(|(_, okey)| okey)
338 .map(|okey| {
339 let lobj = self.lobj(okey);
340 match lobj.entity_type() {
341 obj::EntityType::Var(vp) => match lobj.pkg() == Some(self.pkg) {
342 true => Some((okey, vp.used)),
343 false => None,
344 },
345 _ => None,
346 }
347 }),
348 },
349 _ => None,
350 }
351 .flatten();
352
353 self.raw_expr(x, &e, None, fctx);
354
355 if let Some((okey, used)) = v {
356 match self.lobj_mut(okey).entity_type_mut() {
357 obj::EntityType::Var(vp) => vp.used = used,
358 _ => unreachable!(),
359 }
360 }
361 }
362 }
363
364 pub fn lookup(&self, name: &str) -> Option<ObjKey> {
365 Scope::lookup_parent(
366 self.octx.scope.as_ref().unwrap(),
367 name,
368 self.octx.pos,
369 self.tc_objs,
370 )
371 .map(|(_, okey)| okey)
372 }
373
374 pub fn add_decl_dep(&mut self, to: ObjKey) {
375 if self.octx.decl.is_none() {
376 return;
378 }
379 if !self.obj_map.contains_key(&to) {
380 return;
381 }
382 self.tc_objs.decls[self.octx.decl.unwrap()].add_dep(to);
383 }
384
385 pub fn insert_obj_to_set(&self, set: &mut Map<String, ObjKey>, okey: ObjKey) -> Option<ObjKey> {
386 let obj_val = self.lobj(okey);
387 let id = obj_val.id(self.tc_objs).to_string();
388 set.insert(id, okey)
389 }
390
391 pub fn ast_ident(&self, key: IdentKey) -> &ast::Ident {
392 &self.ast_objs.idents[key]
393 }
394
395 pub fn lobj(&self, key: ObjKey) -> &obj::LangObj {
396 &self.tc_objs.lobjs[key]
397 }
398
399 pub fn lobj_mut(&mut self, key: ObjKey) -> &mut obj::LangObj {
400 &mut self.tc_objs.lobjs[key]
401 }
402
403 pub fn otype(&self, key: TypeKey) -> &Type {
404 &self.tc_objs.types[key]
405 }
406
407 pub fn otype_mut(&mut self, key: TypeKey) -> &mut Type {
408 &mut self.tc_objs.types[key]
409 }
410
411 pub fn otype_interface(&self, key: TypeKey) -> &typ::InterfaceDetail {
412 self.otype(key).try_as_interface().unwrap()
413 }
414
415 pub fn otype_signature(&self, key: TypeKey) -> &typ::SignatureDetail {
416 self.otype(key).try_as_signature().unwrap()
417 }
418
419 pub fn otype_interface_mut(&mut self, key: TypeKey) -> &mut typ::InterfaceDetail {
420 self.otype_mut(key).try_as_interface_mut().unwrap()
421 }
422
423 pub fn otype_signature_mut(&mut self, key: TypeKey) -> &mut typ::SignatureDetail {
424 self.otype_mut(key).try_as_signature_mut().unwrap()
425 }
426
427 pub fn package(&self, key: PackageKey) -> &Package {
428 &self.tc_objs.pkgs[key]
429 }
430
431 pub fn package_mut(&mut self, key: PackageKey) -> &mut Package {
432 &mut self.tc_objs.pkgs[key]
433 }
434
435 pub fn scope(&self, key: ScopeKey) -> &Scope {
436 &self.tc_objs.scopes[key]
437 }
438
439 pub fn decl_info(&self, key: DeclInfoKey) -> &DeclInfo {
440 &self.tc_objs.decls[key]
441 }
442
443 pub fn position(&self, pos: Pos) -> FilePos {
444 self.fset.file(pos).unwrap().position(pos)
445 }
446
447 pub fn builtin_info(&self, id: Builtin) -> &BuiltinInfo {
448 &self.tc_objs.universe().builtins()[&id]
449 }
450
451 pub fn basic_type(&self, t: typ::BasicType) -> TypeKey {
452 self.tc_objs.universe().types()[&t]
453 }
454
455 pub fn invalid_type(&self) -> TypeKey {
456 self.basic_type(typ::BasicType::Invalid)
457 }
458
459 pub fn new_dis<'b>(&'b self, x: &'b impl Display) -> Displayer<'b> {
460 Displayer::new(x, Some(self.ast_objs), Some(self.tc_objs))
461 }
462
463 pub fn new_td_o<'t>(&'t self, t: &'t Option<TypeKey>) -> Displayer<'t> {
464 Displayer::new(t.as_ref().unwrap(), Some(self.ast_objs), Some(self.tc_objs))
465 }
466}