diff --git a/examples/borrow_err.rs b/examples/borrow_err.rs
new file mode 100644
index 0000000000000000000000000000000000000000..63157b53b2008d714818be0fa0c16f510968c76c
--- /dev/null
+++ b/examples/borrow_err.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let mut a = 5;
+    let b = &mut a;
+    //let q = *b;
+    let c = a;
+    println!("b {:?}", *b);
+}
diff --git a/src/check.rs b/src/check.rs
index 97c8248f8d98a0f9b2306fee53442682fee15048..f8532f716b007ce601a6d32bb183020f36bc2ab3 100644
--- a/src/check.rs
+++ b/src/check.rs
@@ -5,7 +5,7 @@ use log::{trace, LevelFilter};
 use std::convert::From;
 
 use crate::ast::*;
-use crate::env::{new_fn_env, new_type_env, Error, FnEnv, IdType, TypeEnv, VarEnv};
+use crate::env::{new_fn_env, new_type_env, Borrow, Error, FnEnv, IdType, TypeEnv, VarEnv};
 
 // type check
 
@@ -150,7 +150,7 @@ fn expr_type(
             }
         }
 
-        Id(id) => match var_env.get(id.to_string()) {
+        Id(id) => match var_env.get_type(id.to_string()) {
             Some((_, t)) => Ok(t.clone()),
             None => Err(format!("variable not found {}", id)),
         },
@@ -205,7 +205,7 @@ fn lexpr_type<'a>(
     trace!("var_env {:?}", var_env);
 
     match e {
-        Id(id) => match var_env.get_mut(id.to_string()) {
+        Id(id) => match var_env.get_mut_type(id.to_string()) {
             Some(t) => Ok(t),
             None => Err(format!("variable not found {}", id)),
         },
@@ -229,6 +229,26 @@ fn lexpr_type<'a>(
     }
 }
 
+#[test]
+// trace and assert
+fn borrow_test() {
+    use Type::*;
+    let var_env = &mut VarEnv::new();
+    let fn_env = &mut FnEnv::new();
+    let type_env = &TypeEnv::new();
+    var_env.push_empty_scope();
+    var_env.new_id("a".to_owned(), Type::Ref(Box::new(Type::I32)));
+    let e = Expr::DeRef(Box::new(Expr::Id("a".to_string())));
+    let lh = lexpr_type(&e, fn_env, type_env, var_env);
+
+    println!("lh {:?}", lh);
+    // let (_, t) = var_env.get("a".to_string()).unwrap();
+
+    // var_env.borrow("a".to_string(), t);
+
+    println!("{:?}", var_env);
+}
+
 // strip a "mut T" to a T
 fn strip_mut(t: Type) -> Type {
     match t {
@@ -427,7 +447,7 @@ pub fn check(p: &Program) -> Result<(), Error> {
                 true => Type::Mut(Box::new(ty.clone())),
                 _ => ty.clone(),
             };
-            arg_ty.insert(id.to_owned(), ty);
+            arg_ty.insert(id.to_owned(), (Borrow::Free, ty));
         }
 
         var_env.push_param_scope(arg_ty);
diff --git a/src/env.rs b/src/env.rs
index 1b48063dad27b07099d8ed10fb4c1cbc289a6d6c..2539edd67ad95524870c3484b0494085d2d3c7ef 100644
--- a/src/env.rs
+++ b/src/env.rs
@@ -22,46 +22,65 @@ pub fn new_fn_env(v: &Vec<FnDecl>) -> FnEnv {
     HashMap::from_iter(i)
 }
 
-pub type IdType = HashMap<Id, Type>;
+#[derive(Debug, PartialEq)]
+pub enum Borrow {
+    Free, // or maybe owned
+    Unique,
+    Shared(Vec<String>),
+}
 
+pub type Address = i32;
 type Scope = i32;
 
+pub type IdType = HashMap<Id, (Borrow, Type)>;
 #[derive(Debug)]
-pub struct VarEnv(VecDeque<IdType>);
+pub struct VarEnv {
+    env: VecDeque<IdType>,
+}
 
 impl VarEnv {
     pub fn new() -> Self {
-        VarEnv(VecDeque::new())
+        VarEnv {
+            env: VecDeque::<IdType>::new(),
+        }
     }
 
-    pub fn get(&self, id: String) -> Option<(Scope, &Type)> {
-        self.0.iter().enumerate().find_map(|(scope, hm)| {
+    pub fn get(&self, id: String) -> Option<(Scope, &(Borrow, Type))> {
+        self.env.iter().enumerate().find_map(|(scope, hm)| {
             hm.get(id.as_str())
-                .map(|t| ((self.0.len() - scope) as Scope, t))
+                .map(|t| ((self.env.len() - scope) as Scope, t))
         })
     }
 
-    pub fn get_mut(&mut self, id: String) -> Option<&mut Type> {
-        self.0.iter_mut().find_map(|hm| hm.get_mut(id.as_str()))
+    pub fn get_type(&self, id: String) -> Option<(Scope, &Type)> {
+        self.get(id).map(|(s, t)| (s, &t.1))
+    }
+
+    pub fn get_mut(&mut self, id: String) -> Option<&mut (Borrow, Type)> {
+        self.env.iter_mut().find_map(|hm| hm.get_mut(id.as_str()))
+    }
+
+    pub fn get_mut_type(&mut self, id: String) -> Option<&mut Type> {
+        self.get_mut(id).map(|(_, t)| t)
     }
 
     pub fn new_id(&mut self, id: String, ty: Type) {
-        let hm = self.0.front_mut().unwrap();
-        println!("insert id {:?}, in scope {:?}", id, hm);
+        let hm = self.env.front_mut().unwrap();
+        println!("insert id {:?}, in scope {:?}", &id, hm);
 
-        hm.insert(id, ty);
+        hm.insert(id, (Borrow::Free, ty));
     }
 
     pub fn update(&mut self, id: String, ty: Type) -> Result<(), Error> {
         println!("env: update");
         match self.get_mut(id.clone()) {
             Some(ot) => match ot {
-                Type::Unknown => {
+                (_, Type::Unknown) => {
                     // no type assigned
-                    *ot = ty;
+                    (*ot).1 = ty;
                     Ok(())
                 }
-                t => match *t == ty {
+                (_, t) => match *t == ty {
                     true => Ok(()),
                     false => Err(format!("types differ {} <> {}", t, ty)),
                 },
@@ -71,77 +90,93 @@ impl VarEnv {
     }
 
     pub fn push_empty_scope(&mut self) {
-        self.0.push_front(HashMap::new());
+        self.env.push_front(HashMap::new());
     }
 
     pub fn push_param_scope(&mut self, args: IdType) {
-        self.0.push_front(args)
+        self.env.push_front(args)
     }
 
     pub fn pop_scope(&mut self) {
-        self.0.pop_front();
+        self.env.pop_front();
     }
 }
 
 #[test]
 // trace and assert
-fn type_env_test() {
+fn borrow_test() {
     use Type::*;
     let mut var_env = VarEnv::new();
     var_env.push_empty_scope();
-    var_env.new_id("a".to_owned(), Type::Unknown);
-    println!("{:?}", var_env);
+    var_env.new_id("a".to_owned(), Type::Ref(Box::new(Type::I32)));
+    var_env.new_id("b".to_owned(), Type::Ref(Box::new(Type::I32)));
 
-    println!("update a {:?}", var_env.update("a".to_owned(), I32));
-    println!("get a {:?}", var_env.get("a".to_owned()));
-    assert_eq!(var_env.get("a".to_owned()), Some((1, &I32)));
-    println!("update a {:?}", var_env.update("a".to_owned(), I32));
-    assert!(var_env.update("a".to_owned(), I32).is_ok());
+    // let (_, t) = var_env.get("a".to_string()).unwrap();
 
-    println!("update a {:?}", var_env.update("a".to_owned(), Bool));
-    assert!(var_env.update("a".to_owned(), Bool).is_err());
+    // var_env.borrow("a".to_string(), t);
 
-    println!("get b {:?}", var_env.get("b".to_owned()));
-    assert_eq!(var_env.get("b".to_owned()), None);
-
-    println!("update b {:?}", var_env.update("b".to_owned(), Bool));
-    assert!(var_env.update("b".to_owned(), Bool).is_err());
-
-    var_env.push_empty_scope();
-    println!("\n -- push empty scope\n");
-    assert_eq!(var_env.get("a".to_owned()), Some((1, &I32)));
-
-    println!("update a {:?}", var_env.update("a".to_owned(), Bool));
-    assert!(var_env.update("a".to_owned(), Bool).is_err());
-    println!("update a {:?}", var_env.update("a".to_owned(), I32));
-    assert!(var_env.update("a".to_owned(), I32).is_ok());
-
-    var_env.new_id("a".to_owned(), Unknown);
-    println!("get a {:?}", var_env.get("a".to_owned()));
-    assert_eq!(var_env.get("a".to_owned()), Some((2, &Unknown)));
-    println!("update a {:?}", var_env.update("a".to_owned(), Bool));
-    println!("get a {:?}", var_env.get("a".to_owned()));
-    assert_eq!(var_env.get("a".to_owned()), Some((2, &Bool)));
-
-    println!("update a {:?}", var_env.update("a".to_owned(), Bool));
-    assert!(var_env.update("a".to_owned(), Bool).is_ok());
-    println!("update a {:?}", var_env.update("a".to_owned(), Type::I32));
-    assert!(var_env.update("a".to_owned(), I32).is_err());
-
-    println!("\n -- pop scope\n");
-    var_env.pop_scope();
-    println!("get a {:?}", var_env.get("a".to_owned()));
-    assert_eq!(var_env.get("a".to_owned()), Some((1, &I32)));
-
-    println!("update a {:?}", var_env.update("a".to_owned(), Bool));
-    assert!(var_env.update("a".to_owned(), Bool).is_err());
-    println!("update a {:?}", var_env.update("a".to_owned(), I32));
-    assert!(var_env.update("a".to_owned(), I32).is_ok());
-
-    println!("get b {:?}", var_env.get("b".to_owned()));
-    assert_eq!(var_env.get("b".to_owned()), None);
+    println!("{:?}", var_env);
 }
 
+// #[test]
+// // trace and assert
+// fn type_env_test() {
+//     use Type::*;
+//     let mut var_env = VarEnv::new();
+//     var_env.push_empty_scope();
+//     var_env.new_id("a".to_owned(), Type::Unknown);
+//     println!("{:?}", var_env);
+
+//     println!("update a {:?}", var_env.update("a".to_owned(), I32));
+//     println!("get a {:?}", var_env.get("a".to_owned()));
+//     assert_eq!(var_env.get_type("a".to_owned()), Some((1, &I32)));
+//     println!("update a {:?}", var_env.update("a".to_owned(), I32));
+//     assert!(var_env.update("a".to_owned(), I32).is_ok());
+
+//     println!("update a {:?}", var_env.update("a".to_owned(), Bool));
+//     assert!(var_env.update("a".to_owned(), Bool).is_err());
+
+//     println!("get_type b {:?}", var_env.get_type("b".to_owned()));
+//     assert_eq!(var_env.get_type("b".to_owned()), None);
+
+//     println!("update b {:?}", var_env.update("b".to_owned(), Bool));
+//     assert!(var_env.update("b".to_owned(), Bool).is_err());
+
+//     var_env.push_empty_scope();
+//     println!("\n -- push empty scope\n");
+//     assert_eq!(var_env.get_type("a".to_owned()), Some((1, &I32)));
+
+//     println!("update a {:?}", var_env.update("a".to_owned(), Bool));
+//     assert!(var_env.update("a".to_owned(), Bool).is_err());
+//     println!("update a {:?}", var_env.update("a".to_owned(), I32));
+//     assert!(var_env.update("a".to_owned(), I32).is_ok());
+
+//     var_env.new_id("a".to_owned(), Unknown);
+//     println!("get_type a {:?}", var_env.get_type("a".to_owned()));
+//     assert_eq!(var_env.get_type("a".to_owned()), Some((2, &Unknown)));
+//     println!("update a {:?}", var_env.update("a".to_owned(), Bool));
+//     println!("get_type a {:?}", var_env.get_type("a".to_owned()));
+//     assert_eq!(var_env.get_type("a".to_owned()), Some((2, &Bool)));
+
+//     println!("update a {:?}", var_env.update("a".to_owned(), Bool));
+//     assert!(var_env.update("a".to_owned(), Bool).is_ok());
+//     println!("update a {:?}", var_env.update("a".to_owned(), Type::I32));
+//     assert!(var_env.update("a".to_owned(), I32).is_err());
+
+//     println!("\n -- pop scope\n");
+//     var_env.pop_scope();
+//     println!("get_type a {:?}", var_env.get_type("a".to_owned()));
+//     assert_eq!(var_env.get_type("a".to_owned()), Some((1, &I32)));
+
+//     println!("update a {:?}", var_env.update("a".to_owned(), Bool));
+//     assert!(var_env.update("a".to_owned(), Bool).is_err());
+//     println!("update a {:?}", var_env.update("a".to_owned(), I32));
+//     assert!(var_env.update("a".to_owned(), I32).is_ok());
+
+//     println!("get_type b {:?}", var_env.get_type("b".to_owned()));
+//     assert_eq!(var_env.get_type("b".to_owned()), None);
+// }
+
 pub type TypeEnv<'a> = HashMap<&'a str, &'a TypeDecl>;
 
 impl TypeDecl {