1#![allow(dead_code)]
13use super::super::constant::Value;
14use super::super::importer::{ImportKey, Importer, SourceRead, TraceConfig};
15use super::super::objects::{DeclInfoKey, ObjKey, PackageKey, ScopeKey, TCObjects, TypeKey};
16use super::super::operand::OperandMode;
17use super::super::selection::Selection;
18use super::interface::IfaceInfo;
19use go_parser::ast;
20use go_parser::ast::{Expr, Node, NodeId};
21use go_parser::{AstObjects, ErrorList, FilePosErrors, FileSet, IdentKey, Map, Pos};
22use std::cell::RefCell;
23use std::collections::HashSet;
24use std::rc::Rc;
25
26#[derive(Debug, Clone)]
29pub struct TypeAndValue {
30 pub mode: OperandMode,
31 pub typ: TypeKey,
32}
33
34impl TypeAndValue {
35 pub fn get_const_val(&self) -> Option<&Value> {
36 match &self.mode {
37 OperandMode::Constant(v) => Some(v),
38 _ => None,
39 }
40 }
41}
42
43#[derive(Debug)]
47pub struct Initializer {
48 pub lhs: Vec<ObjKey>,
49 pub rhs: Expr,
50}
51
52#[derive(Debug)]
54pub struct TypeInfo {
55 pub types: Map<NodeId, TypeAndValue>,
73 pub defs: Map<IdentKey, Option<ObjKey>>,
83 pub uses: Map<IdentKey, ObjKey>,
89 pub implicits: Map<NodeId, ObjKey>,
96 pub selections: Map<NodeId, Selection>,
99 pub scopes: Map<NodeId, ScopeKey>,
121 pub init_order: Vec<Initializer>,
127 pub ast_files: Vec<ast::File>,
129}
130
131impl TypeInfo {
132 pub fn new() -> TypeInfo {
133 TypeInfo {
134 types: Map::new(),
135 defs: Map::new(),
136 uses: Map::new(),
137 implicits: Map::new(),
138 selections: Map::new(),
139 scopes: Map::new(),
140 init_order: Vec::new(),
141 ast_files: Vec::new(),
142 }
143 }
144}
145
146#[derive(Debug)]
148pub struct ExprInfo {
149 pub is_lhs: bool,
150 pub mode: OperandMode,
151 pub typ: Option<TypeKey>,
152}
153
154#[derive(Clone)]
157pub struct ObjContext {
158 pub decl: Option<DeclInfoKey>,
160 pub scope: Option<ScopeKey>,
162 pub pos: Option<Pos>,
164 pub iota: Option<Value>,
166 pub sig: Option<TypeKey>,
168 pub panics: Option<HashSet<NodeId>>,
170 pub has_label: bool,
172 pub has_call_or_recv: bool,
174}
175
176type DelayedAction<S> = Box<dyn FnOnce(&mut Checker<S>, &mut FilesContext<S>)>;
177
178pub type RcIfaceInfo = Rc<IfaceInfo>;
179
180pub struct FilesContext<'a, S: SourceRead> {
183 pub files: &'a Vec<ast::File>,
185 pub unused_dot_imports: Map<ScopeKey, Map<PackageKey, Pos>>,
187 pub methods: Map<ObjKey, Vec<ObjKey>>,
190 pub ifaces: Map<ObjKey, Option<RcIfaceInfo>>,
193 pub untyped: Map<NodeId, ExprInfo>,
195 pub delayed: Vec<DelayedAction<S>>,
197 pub obj_path: Vec<ObjKey>,
199}
200
201pub struct Checker<'a, S: SourceRead> {
202 pub tc_objs: &'a mut TCObjects,
204 pub ast_objs: &'a mut AstObjects,
206 errors: &'a ErrorList,
208 pub fset: &'a mut FileSet,
210 pub all_pkgs: &'a mut Map<String, PackageKey>,
212 all_results: &'a mut Map<PackageKey, TypeInfo>,
215 pub pkg: PackageKey,
217 pub obj_map: Map<ObjKey, DeclInfoKey>,
219 pub imp_map: Map<ImportKey, PackageKey>,
221 pub octx: ObjContext,
223
224 trace_config: &'a TraceConfig,
225
226 reader: &'a S,
227 pub result: TypeInfo,
229 pub indent: Rc<RefCell<usize>>,
231}
232
233impl ObjContext {
234 pub fn new() -> ObjContext {
235 ObjContext {
236 decl: None,
237 scope: None,
238 pos: None,
239 iota: None,
240 sig: None,
241 panics: None,
242 has_label: false,
243 has_call_or_recv: false,
244 }
245 }
246}
247
248impl<S: SourceRead> FilesContext<'_, S> {
249 pub fn new(files: &Vec<ast::File>) -> FilesContext<'_, S> {
250 FilesContext {
251 files: files,
252 unused_dot_imports: Map::new(),
253 methods: Map::new(),
254 ifaces: Map::new(),
255 untyped: Map::new(),
256 delayed: Vec::new(),
257 obj_path: Vec::new(),
258 }
259 }
260
261 pub fn file_name(&self, index: usize, checker: &Checker<S>) -> String {
263 let file = &self.files[index];
264 let pos = file.pos(checker.ast_objs);
265 if pos > 0 {
266 checker.fset.file(pos).unwrap().name().to_owned()
267 } else {
268 format!("file[{}]", index)
269 }
270 }
271
272 pub fn add_unused_dot_import(&mut self, scope: &ScopeKey, pkg: &PackageKey, pos: Pos) {
273 if !self.unused_dot_imports.contains_key(scope) {
274 self.unused_dot_imports.insert(*scope, Map::new());
275 }
276 self.unused_dot_imports
277 .get_mut(scope)
278 .unwrap()
279 .insert(*pkg, pos);
280 }
281
282 pub fn remember_untyped(&mut self, e: &Expr, ex_info: ExprInfo) {
283 self.untyped.insert(e.id(), ex_info);
284 }
285
286 pub fn later(&mut self, action: DelayedAction<S>) {
291 self.delayed.push(action);
292 }
293
294 pub fn delayed_count(&self) -> usize {
295 self.delayed.len()
296 }
297
298 pub fn process_delayed(&mut self, top: usize, checker: &mut Checker<S>) {
299 let fs: Vec<DelayedAction<S>> = self.delayed.drain(top..).into_iter().collect();
300 for f in fs {
301 f(checker, self);
302 }
303 }
304
305 pub fn push(&mut self, obj: ObjKey) -> usize {
307 self.obj_path.push(obj);
308 self.obj_path.len() - 1
309 }
310
311 pub fn pop(&mut self) -> ObjKey {
312 self.obj_path.pop().unwrap()
313 }
314}
315
316impl TypeAndValue {
317 fn new(mode: OperandMode, typ: TypeKey) -> TypeAndValue {
318 TypeAndValue {
319 mode: mode,
320 typ: typ,
321 }
322 }
323}
324
325impl TypeInfo {
326 pub fn record_type_and_value(&mut self, e: &Expr, mode: OperandMode, typ: TypeKey) {
327 self.record_type_and_value_with_id(e.id(), mode, typ);
328 }
329
330 pub fn record_type_and_value_with_id(&mut self, id: NodeId, mode: OperandMode, typ: TypeKey) {
331 if let OperandMode::Invalid = mode {
332 return;
333 }
334 self.types.insert(id, TypeAndValue::new(mode, typ));
335 }
336
337 pub fn record_builtin_type(&mut self, mode: &OperandMode, e: &Expr, sig: TypeKey) {
338 let mut expr = e;
339 loop {
344 self.record_type_and_value(expr, mode.clone(), sig);
345 match expr {
346 Expr::Ident(_) => break,
347 Expr::Paren(p) => expr = &(*p).expr,
348 _ => unreachable!(),
349 }
350 }
351 }
352
353 pub fn record_comma_ok_types<S: SourceRead>(
354 &mut self,
355 e: &Expr,
356 t: &[TypeKey; 2],
357 tc_objs: &mut TCObjects,
358 ast_objs: &AstObjects,
359 pkg: PackageKey,
360 ) {
361 let pos = e.pos(ast_objs);
362 let mut expr = e;
363 loop {
364 let tv = self.types.get_mut(&expr.id()).unwrap();
365 tv.typ = Checker::<S>::comma_ok_type(tc_objs, pos, pkg, t);
366 match expr {
367 Expr::Paren(p) => expr = &(*p).expr,
368 _ => break,
369 }
370 }
371 }
372
373 pub fn record_def(&mut self, id: IdentKey, obj: Option<ObjKey>) {
374 self.defs.insert(id, obj);
375 }
376
377 pub fn record_use(&mut self, id: IdentKey, obj: ObjKey) {
378 self.uses.insert(id, obj);
379 }
380
381 pub fn record_implicit(&mut self, node: &impl Node, obj: ObjKey) {
382 self.implicits.insert(node.id(), obj);
383 }
384
385 pub fn record_selection(&mut self, expr: &ast::SelectorExpr, sel: Selection) {
386 self.record_use(expr.sel, sel.obj());
387 self.selections.insert(expr.id(), sel);
388 }
389
390 pub fn record_scope(&mut self, node: &impl Node, scope: ScopeKey) {
391 self.scopes.insert(node.id(), scope);
392 }
393
394 pub fn record_init_order(&mut self, init_order: Vec<Initializer>) {
395 self.init_order = init_order;
396 }
397}
398
399impl<'a, S: SourceRead> Checker<'a, S> {
400 pub fn new(
401 tc_objs: &'a mut TCObjects,
402 ast_objs: &'a mut AstObjects,
403 fset: &'a mut FileSet,
404 errors: &'a ErrorList,
405 pkgs: &'a mut Map<String, PackageKey>,
406 all_results: &'a mut Map<PackageKey, TypeInfo>,
407 pkg: PackageKey,
408 cfg: &'a TraceConfig,
409 reader: &'a S,
410 ) -> Checker<'a, S> {
411 Checker {
412 tc_objs: tc_objs,
413 ast_objs: ast_objs,
414 fset: fset,
415 errors: errors,
416 all_pkgs: pkgs,
417 all_results: all_results,
418 pkg: pkg,
419 obj_map: Map::new(),
420 imp_map: Map::new(),
421 octx: ObjContext::new(),
422 trace_config: cfg,
423 reader: reader,
424 result: TypeInfo::new(),
425 indent: Rc::new(RefCell::new(0)),
426 }
427 }
428
429 pub fn check(mut self, mut files: Vec<ast::File>) -> Result<PackageKey, ()> {
430 self.check_files_pkg_name(&files)?;
431 let fctx = &mut FilesContext::new(&files);
432 self.collect_objects(fctx);
433 self.package_objects(fctx);
434 fctx.process_delayed(0, &mut self);
435 self.init_order();
436 self.unused_imports(fctx);
437 self.record_untyped(fctx);
438
439 std::mem::swap(&mut self.result.ast_files, &mut files);
440 self.all_results.insert(self.pkg, self.result);
441 Ok(self.pkg)
442 }
443
444 fn record_untyped(&mut self, fctx: &mut FilesContext<S>) {
445 for (id, info) in fctx.untyped.iter() {
446 if info.mode != OperandMode::Invalid {
447 self.result.record_type_and_value_with_id(
448 id.clone(),
449 info.mode.clone(),
450 info.typ.unwrap(),
451 );
452 }
453 }
454 }
455
456 #[inline]
457 pub fn errors(&self) -> &ErrorList {
458 self.errors
459 }
460
461 #[inline]
462 pub fn trace(&self) -> bool {
463 self.trace_config.trace_checker
464 }
465
466 pub fn new_importer(&mut self, pos: Pos) -> Importer<S> {
467 Importer::new(
468 self.trace_config,
469 self.reader,
470 self.fset,
471 self.all_pkgs,
472 self.all_results,
473 self.ast_objs,
474 self.tc_objs,
475 self.errors,
476 pos,
477 )
478 }
479
480 fn check_files_pkg_name(&mut self, files: &Vec<ast::File>) -> Result<(), ()> {
482 let mut pkg_name: Option<String> = None;
483 for f in files.iter() {
484 let ident = &self.ast_objs.idents[f.name];
485 if pkg_name.is_none() {
486 if ident.name == "_" {
487 self.error(ident.pos, "invalid package name _".to_owned());
488 return Err(());
489 } else {
490 pkg_name = Some(ident.name.clone());
491 }
492 } else if &ident.name != pkg_name.as_ref().unwrap() {
493 self.error(
494 f.package,
495 format!(
496 "package {}; expected {}",
497 ident.name,
498 pkg_name.as_ref().unwrap()
499 ),
500 );
501 return Err(());
502 }
503 }
504 self.tc_objs.pkgs[self.pkg].set_name(pkg_name.unwrap());
505 Ok(())
506 }
507
508 pub fn error(&self, pos: Pos, err: String) {
509 self.error_impl(pos, err, false);
510 }
511
512 pub fn error_str(&self, pos: Pos, err: &str) {
513 self.error_impl(pos, err.to_string(), false);
514 }
515
516 pub fn soft_error(&self, pos: Pos, err: String) {
517 self.error_impl(pos, err, true);
518 }
519
520 pub fn soft_error_str(&self, pos: Pos, err: &str) {
521 self.error_impl(pos, err.to_string(), true);
522 }
523
524 fn error_impl(&self, pos: Pos, err: String, soft: bool) {
525 let file = self.fset.file(pos).unwrap();
526 FilePosErrors::new(file, self.errors).add(pos, err, soft);
527 }
528}