From 235b6e34d1de0b71c2c8546030a53a4a85fc2f2c Mon Sep 17 00:00:00 2001
From: ychenfo <yc@m-labs.hk>
Date: Tue, 7 Sep 2021 00:20:40 +0800
Subject: [PATCH] nac3core: top level derive fmt::Debug, fix dead lock

---
 nac3core/src/symbol_resolver.rs          |  7 +++
 nac3core/src/toplevel/mod.rs             |  9 ++--
 nac3core/src/toplevel/test.rs            | 68 +++++++++++++-----------
 nac3core/src/toplevel/type_annotation.rs | 14 +++--
 nac3core/src/typecheck/typedef/mod.rs    |  2 +-
 5 files changed, 60 insertions(+), 40 deletions(-)

diff --git a/nac3core/src/symbol_resolver.rs b/nac3core/src/symbol_resolver.rs
index ecf281e1..11ab75a5 100644
--- a/nac3core/src/symbol_resolver.rs
+++ b/nac3core/src/symbol_resolver.rs
@@ -1,4 +1,5 @@
 use std::collections::HashMap;
+use std::fmt::Debug;
 use std::{cell::RefCell, sync::Arc};
 
 use crate::toplevel::{DefinitionId, TopLevelDef};
@@ -219,3 +220,9 @@ impl dyn SymbolResolver + Send + Sync {
         parse_type_annotation(self, top_level_defs, unifier, primitives, expr)
     }
 }
+
+impl Debug for dyn SymbolResolver + Send + Sync {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "")
+    }
+}
\ No newline at end of file
diff --git a/nac3core/src/toplevel/mod.rs b/nac3core/src/toplevel/mod.rs
index cf24c926..7e3b1329 100644
--- a/nac3core/src/toplevel/mod.rs
+++ b/nac3core/src/toplevel/mod.rs
@@ -1,4 +1,4 @@
-use std::{borrow::{Borrow, BorrowMut}, collections::{HashMap, HashSet}, iter::FromIterator, ops::{Deref, DerefMut}, sync::Arc};
+use std::{borrow::BorrowMut, collections::{HashMap, HashSet}, iter::FromIterator, ops::{Deref, DerefMut}, sync::Arc};
 
 use super::typecheck::type_inferencer::PrimitiveStore;
 use super::typecheck::typedef::{FunSignature, FuncArg, SharedUnifier, Type, TypeEnum, Unifier};
@@ -6,11 +6,11 @@ use crate::{
     symbol_resolver::SymbolResolver,
     typecheck::{type_inferencer::CodeLocation, typedef::CallId},
 };
-use itertools::{izip, Itertools};
+use itertools::Itertools;
 use parking_lot::{Mutex, RwLock};
 use rustpython_parser::ast::{self, Stmt};
 
-#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Debug)]
 pub struct DefinitionId(pub usize);
 
 mod type_annotation;
@@ -19,7 +19,7 @@ mod helper;
 #[cfg(test)]
 mod test;
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct FunInstance {
     pub body: Vec<Stmt<Option<Type>>>,
     pub calls: HashMap<CodeLocation, CallId>,
@@ -27,6 +27,7 @@ pub struct FunInstance {
     pub unifier_id: usize,
 }
 
+#[derive(Debug)]
 pub enum TopLevelDef {
     Class {
         // name for error messages and symbols
diff --git a/nac3core/src/toplevel/test.rs b/nac3core/src/toplevel/test.rs
index 36aabe05..d4b3538c 100644
--- a/nac3core/src/toplevel/test.rs
+++ b/nac3core/src/toplevel/test.rs
@@ -8,12 +8,12 @@ use crate::{
     },
 };
 use indoc::indoc;
-use parking_lot::{Mutex, RwLock};
-use rustpython_parser::{ast::fold::Fold, parser::parse_program};
-use std::{borrow::BorrowMut, collections::{HashMap, HashSet}, sync::Arc};
+use parking_lot::Mutex;
+use rustpython_parser::parser::parse_program;
+use std::{collections::HashMap, sync::Arc};
 use test_case::test_case;
 
-use super::TopLevelComposer;
+use super::*;
 
 struct Resolver {
     id_to_type: HashMap<String, Type>,
@@ -48,13 +48,13 @@ impl SymbolResolver for Resolver {
 #[test_case(
     vec![
         indoc! {"
-            def fun(a: int) -> int:
+            def fun(a: int32) -> int32:
                 return a
         "},
         indoc! {"
             class A:
                 def __init__(self):
-                    self.a: int = 3
+                    self.a: int32 = 3
         "},
         indoc! {"
             class B:
@@ -71,7 +71,7 @@ impl SymbolResolver for Resolver {
         indoc! {"
             class C(B):
                 def __init__(self):
-                    self.c: int = 4
+                    self.c: int32 = 4
                     self.a: bool = True
         "}
     ]
@@ -90,35 +90,30 @@ fn test_simple_register(source: Vec<&str>) {
 #[test_case(
     vec![
         indoc! {"
-            def fun(a: int) -> int:
+            def fun(a: int32) -> int32:
                 return a
         "},
-        // indoc! {"
-        //     class A:
-        //         def __init__(self):
-        //             self.a: int = 3
-        // "},
-        // indoc! {"
-        //     class B:
-        //         def __init__(self):
-        //             self.b: float = 4.3
-                
-        //         def fun(self):
-        //             self.b = self.b + 3.0
-        // "},
-        // indoc! {"
-        //     def foo(a: float):
-        //         a + 1.0
-        // "},
-        // indoc! {"
-        //     class C(B):
-        //         def __init__(self):
-        //             self.c: int = 4
-        //             self.a: bool = True
-        // "}
+        indoc! {"
+            def foo(a: float):
+                a + 1.0
+        "},
+        indoc! {"
+            def f(b: int64) -> int32:
+                return 3
+        "},
+    ],
+    vec![
+        "fn[[a=0], 0]",
+        "fn[[a=2], 4]",
+        "fn[[b=1], 0]",
+    ],
+    vec![
+        "fun",
+        "foo",
+        "f"
     ]
 )]
-fn test_simple_analyze(source: Vec<&str>) {
+fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&str>) {
     let mut composer = TopLevelComposer::new();
     
     let resolver = Arc::new(Mutex::new(Box::new(Resolver {
@@ -136,4 +131,13 @@ fn test_simple_analyze(source: Vec<&str>) {
     }
 
     composer.start_analysis().unwrap();
+    
+    for (i, (def, _)) in composer.definition_ast_list.into_iter().enumerate() {
+        let def = &*def.read();
+        if let TopLevelDef::Function { signature, name, .. } = def {
+            let ty_str = composer.unifier.stringify(*signature, &mut |id| id.to_string(), &mut |id| id.to_string());
+            assert_eq!(ty_str, tys[i]);
+            assert_eq!(name, names[i]);
+        }
+    }
 }
diff --git a/nac3core/src/toplevel/type_annotation.rs b/nac3core/src/toplevel/type_annotation.rs
index a38d99d4..eba78733 100644
--- a/nac3core/src/toplevel/type_annotation.rs
+++ b/nac3core/src/toplevel/type_annotation.rs
@@ -2,7 +2,7 @@ use crate::typecheck::typedef::TypeVarMeta;
 
 use super::*;
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub enum TypeAnnotation {
     PrimitiveKind(Type),
     // we use type vars kind at params to represent self type
@@ -33,7 +33,12 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
             "bool" => Ok(TypeAnnotation::PrimitiveKind(primitives.bool)),
             "None" => Ok(TypeAnnotation::PrimitiveKind(primitives.none)),
             x => {
-                if let Some(obj_id) = resolver.lock().get_identifier_def(x) {
+                if let Some(obj_id) = {
+                    // write this way because the lock in the if/let construct lives
+                    // for the whole if let construct
+                    let id = resolver.lock().get_identifier_def(x);
+                    id
+                } {
                     let def = top_level_defs[obj_id.0].read();
                     if let TopLevelDef::Class { type_vars, .. } = &*def {
                         // also check param number here
@@ -47,7 +52,10 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
                     } else {
                         Err("function cannot be used as a type".into())
                     }
-                } else if let Some(ty) = resolver.lock().get_symbol_type(unifier, primitives, id) {
+                } else if let Some(ty) = {
+                    let ty = resolver.lock().get_symbol_type(unifier, primitives, id);
+                    ty
+                } {
                     if let TypeEnum::TVar { .. } = unifier.get_ty(ty).as_ref() {
                         Ok(TypeAnnotation::TypeVarKind(ty))
                     } else {
diff --git a/nac3core/src/typecheck/typedef/mod.rs b/nac3core/src/typecheck/typedef/mod.rs
index aea8642c..e4599945 100644
--- a/nac3core/src/typecheck/typedef/mod.rs
+++ b/nac3core/src/typecheck/typedef/mod.rs
@@ -16,7 +16,7 @@ mod test;
 /// Handle for a type, implementated as a key in the unification table.
 pub type Type = UnificationKey;
 
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub struct CallId(usize);
 
 pub type Mapping<K, V = Type> = HashMap<K, V>;