// typechecker

foreach(x in {1,3,4}) with y:(int, A()) = 1 do x + 1 /* OK */;;

ref 1  ;;//OK

ref [(int, A())] 1 ;; //OK

ref [(int, A())] true ;;// NOK 

let x = [int^B]1 in ref [int^ A] x ;;//NOK

(ref  [(int, A())] 1) := 2 ;;  // OK

(ref  [(int, A())] 1) := true ;;//NOK

let x=  ref [(int, A())] 1 in 1 ;; //OK

let x= ref [(int, A())] 1 in !x ;;//OK

let x= ref [(int, A())] 1 in x ;; //OK







let x = [(int, A())] 1 in let x = [(bool, B())] true in x;; //OK


if true then 1 else 2 ;;// OK

let c = [(bool, A())] true in (if c then 1+2 else 5) ;;// OK


let c = [(bool, A(1, true, TOP))] true in (if c then 1+2 else 5) ;; //NOK label n existe

let c = [(bool, TOP())] true in 
  (let b1 = [(ref( (int, A()) ), A())] ref [(int, A())] 10 in 
    (if c then !b1 else 5) ) ;; //OK
    
 let x = [int^ U(BOT)] 1 in 
 	( let y = [ bool^ A(BOT,BOT)] true in
 	   if y then
 	     ref 1
 	   else ref 1 ) ;; // insecure flow OK, r=B mas ref BOT
 	   
 let x = [int ^ U(BOT)] 1 in 
 	( let y = [bool^ A(BOT,BOT)] true in
 	   if y then
 	     ref [int^ TOP] 1
 	   else ref [int^ TOP] 1 ) ;; // secure flow OK
 	   
 	   
 	   
[a:(int, A()) = 1, b:(bool, B()) = true, c:(cmd, TOP()) = skip] ;; //OK


\(x:(int, BOT()), y:(bool, A()))[(bool, BOT())].true ;; //OK


let x =  (\(x:(int, BOT()), y:(bool, A()))[(bool, BOT())].true) 
	in x ;;  //OK

let x = 
	(\(x:(int, BOT()), y:(bool, A()))[(bool, BOT())].true) 
	in x ;;   //NOK

	
let x =
	(fun x: int^ BOT, y: bool^ U(BOT) =>true) /* contra-variance on params OK */ 
	in x(1, [bool^ TOP] true) ;;   // OK, contra-variance on app args
	
let x =
	(fun x: int^ BOT, y: bool^ U(BOT) => [bool^TOP]true) /* contra-variance on params OK */ 
	in x(1, [bool^ TOP] true) ;;  /* co-variance on return type OK */
	
	
let x =
	(fun x: int^ BOT, y: bool^ U(BOT) => true) /* contra-variance on params OK */ 
	in x(1) ;; 	//NOK
	
let x =
	(fun x: int^ BOT, y: bool^ U(BOT) => true) /* contra-variance on params OK */ 
	in x(1, true) ;;	// NOK, contra-variance on app args
	


let b = [(bool, TOP())]true in
	(let x = (\(x:(int, BOT()), y:(bool, A()))[(bool, BOT())].(let b = true in b)) 
	  in x(1,b) );; //OK
	
let b = [(bool, TOP())] true in
	(let x = (\(x:(int, BOT()), y:(bool, A()))[(bool, BOT())].
		(let b = [(bool, TOP())] true in b)) 
	  in x(1,b) );; // NOK


let b = [(bool, TOP())] true in
	(let x =  (\(x:(int, BOT()), y:(bool, A()))[(bool,BOT())].(let b = true in b)) 
	  in x(1,b) );; // OK


let r = [Sigma[a: int^ U(BOT), b: bool^ A(BOT,BOT), c: cmd^ TOP]^BOT] 
	[a: int^ U(BOT) = 1, b: bool^ A(BOT,BOT) = true, c: cmd^ TOP = skip] 
in r;; // NOK, pq meet do record e nivel U(BOT) 



let r = [Sigma[a: int^ U(BOT), b: bool^ A(BOT,BOT), c: cmd^ TOP]^U(BOT)] 
	[a: int^ U(BOT) = 1, b: bool^ A(BOT,BOT) = true, c: cmd^ TOP = skip] 
in r;; // OK, pq meet do record e nivel U(BOT) 



let r = [( Sigma[a:(int, A()), b:(bool, D()), c:(cmd, TOP())], BOT())] 
	[a:(int, A()) = 1, b:(bool, D()) = true, c:(cmd, TOP()) = skip] 
in r;; // OK, meet de A, D, TOP = BOT


let r = [ ( Sigma[a:(int, A()), b:(bool, D()), c:(cmd, TOP())], BOT())] 
	[a:(int, A()) = 1, b:(bool, D()) = true, c:(cmd, TOP()) = skip] 
in r.b;; // OK, meet de A, D, TOP = BOT

	
let r = [ ( Sigma[a:(int, A()), b:(bool, B()), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = 1, b:(bool, B()) = true, c:(cmd, TOP()) = skip] 
in r;; // OK, subtypping on field a

	
	
let x = ref  [(int, A() )] 1 in x := 1 ;; // OK


let x = [(int, A())] 1 in 
 	( let y = [(bool, B())] true in
 	   if y then
 	     ((ref [(int, TOP())] 1) := 2)
 	   else 
 	     ((ref [(int, TOP())] 1) := 3) );; // OK 
 	  
 let x = [int^U(BOT) ] 1 in 
 	( let y = [bool^A(BOT,BOT)] true in
 	   if y then
 	     (ref 1) := 2
 	   else 
 	     (ref 1) := 3 );; // NOK, t-ref conteudo nivel BOT mas contexto pc tem nivel A(BOT,BOT) 
 	   
 
 let x = [(int, A())] 1 in 
 	( let y = [(bool, B())] true in
 	   if y then
 	     ((ref [(int, TOP())] 1) := x)
 	   else 
 	     ((ref [(int, TOP())] 1) := x) );; //OK, subtyping sobe nivel de x para B
 	     
 let x = 1 in 
   let r = [( ref( (int, G() ) ), A() )] (ref [(int, G())]1) in
 	( let y = [(bool, B())] true in
 	   if y then
 	     r := x
 	   else 
 	     ((ref [(int, G())] 1) := x) );;   // B U A <= G, OK



let x = 1 in 
   let r = [( ref( (int, A() ) ), G())] ref [(int, A())] 1 in r ;;
   // NOK pq nivel de ref é superior ao nivel de conteudo na declaração de tipos (verificado por well-formed types)

 	     
let x = [(int, A())] 1 in 
   let r = [ ( ref( (int, A() ) ), A() )]  ref [(int, A())] 1 in 
 	( let y = [(bool, B())] true in
 	   if y then
 	     r := x
 	   else 
 	     r := x ) ;;   // NOK B U A <= A, t-assign 	  
 	     
 	  
 	  
 [a:(int, A()) = 1, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] ;;     //OK
 
 [a:(int, A()) = 1, b:(bool, A(d)) = true, c:(cmd, TOP()) = skip] ;; // NOK, unexistent field dependency d
 
 
 let x = (\(x:(int, BOT()), y:(bool, A()))[(bool, A(x))].true)  
	in x ;;  // OK 
	
let x = (\(x:(int, BOT()), y:(bool, A()))[(bool, A(z))].true)  
	in x ;;  // NOK, not well-formed because of z
 
 	     
let x = [ ( Pi (x:(int, BOT()), y:(bool, A())).(bool, A()), BOT() )]
	(\(x:(int, BOT()), y:(bool, TOP()))[(bool, A(x))].true)  
	in x ;;  // NOK, pq A() == A(BOT) <= A(x)
	
let x = [( Pi (x:(int, BOT()), y:(bool, A())).(bool, B()), BOT() ) ] 
	(\(x:(int, BOT()), y:(bool, TOP()))[(bool, A(x))].true)  
	in x ;;  // OK
	
let x = [( Pi (x:(int, BOT()), y:(bool, A())).(bool, A(x)), BOT() ) ] 
	(\(x:(int, BOT()), y:(bool, TOP()))[(bool, A(BOT))].true)  
	in x ;;   // OK
	
let x = [( Pi (x:(int, BOT()), y:(bool, A())).(bool, A(x)), BOT() )] 
	(\(x:(int, BOT()), y:(bool, TOP()))[(bool, TOP())].true)  
	in x ;;   // NOK
	
let x = [( Pi (x:(int, BOT()), y:(bool, A())).(bool, A(x)), BOT() ) ] 
	(\(x:(int, BOT()), y:(bool, TOP()))[(bool, A(y))].true)  
	in x ;; //NOK
	
let x = [ ( Pi (x:(int, BOT()), y:(bool, A())).(bool, A(x)), BOT() ) ] 
	(\(x:(int, BOT()), y:(bool, TOP()))[(bool, A(x))].true)  
	in x ;;  // OK
	
	
let r = [ ( Sigma[a:(int, A()), b:(bool, A(a)), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = 1, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] 
in r.b;; // Ok, com unrefine	

let r = [( Sigma[a:(int, A(1,2)), b:(bool, B(a,b,1)), c:(cmd, TOP())], A())] 
	[a:(int, A(1,2)) = 1, b:(bool, B(a,10)) = true, c:(cmd, A(a,b)) = skip] 
in r;; //NOK
	
let x = 1 in	
(let r = [ ( Sigma[a:(int, A()), b:(bool, A(a)), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = x, b:(bool, A(1)) = true, c:(cmd, TOP()) = skip] 
in r);; // OK; refine -- rever typecheck
	

let x = 1 in	
(let r = [ ( Sigma[a:(int, A()), b:(bool, A(a)), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = x, b:(bool, A(2)) = true, c:(cmd, TOP()) = skip] 
in r);; // NOK; refine 


	
let r = [ (Sigma[a:(int, A()), b:(bool, A(1)), c:(cmd, TOP())], A())] 
	[a:(int, BOT()) = 1, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] 
in r;; // OK; unrefine


 [a:(int, BOT()) = 1, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] ;; //OK



let b = [(bool, TOP())] true in
	(let x = [( Pi (x:(int, BOT()), y:(bool, A())).(bool, A(x)), BOT() )] 
	 (\(x:(int, BOT()), y:(bool, A()))[(bool, BOT())].
	 	(let b = true in b) ) 
	  in x );; // OK

let b = [(bool, TOP())] true in
	(let x = [( Pi (x:(int, BOT()), y:(bool, A())).(bool, A(x)), BOT() )] 
	 (\(x:(int, BOT()), y:(bool, A()))[(bool, BOT())].
	 	(let b = true in b) ) 
	  in x(1,b) );; // OK com solver, função depedente
	  
	  
let b = [(bool, TOP())] true in
	(let x = 
	 (\(x:(int, BOT()), y:(bool, A()))[( Sigma[a:(int, A()), b:(bool, A(a)), c:(cmd, TOP())], A() )].
	 	([a:(int, BOT()) = 1, b:(bool, A(1)) = true, c:(cmd, TOP()) = skip] )) 
	  in x );;  // OK com refine no body do lambda	  
	
	  
let b = [(bool, TOP())] true in
	(let x =  
	 (\(x:(int, BOT()), y:(bool, A()))[( Sigma[a:(int, A()), b:(bool, A(1)), c:(cmd, TOP())], A() )].
	 	( [a:(int, BOT()) = 1, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] ) ) 
	  in x );;  // OK com unrefine no body do lambda	
	  

let b = [(bool, TOP())] true in
	(let x =  
	 (\(x:(int, BOT()), y:(bool, A()))[ ( Sigma[a:(int, A()), b:(bool, A(1)), c:(cmd, TOP())], A() )].
	 	([a:(int, BOT()) = 2, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] )) 
	  in x );;  // NOK com unrefine no body do lambda	


let l = {1,3,4} in l ;;  //OK

let l = {1,3,4} in first(l) ;;  //OK

let l = {}:(int,BOT()) in l ;; // NOK, empty list is a list so must be declared as a list

{}:( {(int,BOT())}, BOT());; // OK


let l= {}:( {(int,BOT())}, BOT()) in 1::l ;;  //OK



let x = [( Pi (x:(int, BOT()), y:(bool, BOT())).(bool, A(x)), BOT())] 
	(\(x:(int, BOT()), y:(bool, TOP()))[(bool, A(x))].true)  
	in x(1+1*3, true) ;; // OK


let c = [(bool, D())] true in 
  (let b1 = [(int, A())]  10 in 
    (if c then b1 else 5) ) ;; // OK, int^G  A U D = G


let x = 1 in	
(let r = [ ( Sigma[a:(int, A()), b:(bool, A(a)), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = x, b:(bool, A(1)) = true, c:(cmd, TOP()) = skip] 
in r);; // OK; refine
	
let x = 2 in	
(let r = [ ( Sigma[a:(int, A()), b:(bool, A(a)), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = x, b:(bool, A(1)) = true, c:(cmd, TOP()) = skip] 
in r);; // NOK pq x = 2	
	
	
let r = [ ( Sigma[a:(int, A()), b:(bool, A(1)), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = 1, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] 
in r;; // OK; unrefine


let r = [ ( Sigma[a:(int, A()), b:( Sigma[d:(int, A(a))], A()), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = 1, b:( Sigma[d:(int, A(c))], A()) = [d:(int, A(a)) = 1], c:(cmd, TOP()) = skip] 
in r;; // NOK, well formed fail


let x = ref [(int, A())] 1 in 
  if true then
  	let w = !x in 
  	  let z = ref [ (int, A() )] 1 in !z
 else  
  	  let z = ref 1 in !z ;; // OK
  	  

let r = ref 1 in 
  let x = 1 in 
   let y = [ int^A(42,70)] 2 in
 	 if true then
 	   r := y
 	 else 
 	   r := x  ;;  
	  

/// interesting cases ////



let t = 1 in
let r = [ ( Sigma[a:(int, A()), b:(bool, A(1)), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = 1, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] 
in [e:(int, A()) = t, f:(bool, A(e)) = true, g:(cmd, TOP()) = skip];; 
// OK, com refine de subrecord 




let r = [ ( Sigma[a:(int, A()), b:(bool, A(1)), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = 1, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] 
in [e:(int, A()) = 2, f:(bool, A(e)) = r.b, g:(cmd, TOP()) = skip];; 
// NOK, insecure flow from B(1) to B(2)


/// interesting cases -- ends here////


let r = [ ( Sigma[a:(int, A()), b:(bool, A(1)), c:(cmd, TOP())], A())] 
	[a:(int, BOT()) = 1, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] 
in [e:(int, A()) = 1, f:(bool, A(e)) = r.b, g:(cmd, TOP()) = skip];; 
// OK 

let t = 2 in
let r = [ ( Sigma[a:(int, A()), b:(bool, A(1)), c:(cmd, TOP())], A()) ] 
	[a:(int, BOT()) = 1, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip] 
in [e:(int, A()) = 2, f:(int, A(e)) = t, g:(cmd, TOP()) = skip].f;; 
// OK, com refine de subrecord 







let b = [(bool, TOP())] true in
	(let x = 
	 (\(x:(Sigma[a:(int, A()), b:(bool, A(a)), c:(cmd, TOP())], A()) , y:(int, A()))[(bool, A(y))].
	 	([a:(int, A()) = y, b:(bool, A(a)) = true, c:(cmd, TOP()) = skip].b   )) 
	  in x );; 
	  
	let x = 2 in 
	 [a:(int, BOT()) = x, b:(bool, A(BOT) ) = true] ;; 
	  
	  
	 \(x:(int,BOT()))[(Sigma[a:(int, BOT()), b:(bool, A(x))], BOT() ) ].
	 [a:(int, BOT()) = x, b:(bool, A(a) ) = true] ;;
	 
	 

	 
	 
	 \(z:(int,BOT()))[(bool, A(z)) ].
	 [a:(int, BOT()) = z, b:(bool, A(a) ) = true].b ;;
	 
	 
	 
	-------- 
	  
	  
	 \(x:(int,BOT()))[(int,A(x))] . ( [(int, A(x))] x );;
	 
	 
	 
	 
	  
	( [ (Sigma[a:(int, BOT()), b:(bool, A(a))], BOT() ) ] 
	 [a:(int, BOT()) = 2, b:(bool, A(2) ) = true] ).b ;;
	 
	 
	 
	 
	 
	 [a:(int, BOT()) = 2, b:(bool, A(3) ) = true] ;;
	  




let comment = (

\(u: (int, BOT()), r:  ( Sigma[uid:(int, BOT()), stuff:(int, A(uid)) ], BOT() )  )
						[ (int, A(u)) ].
					(
					   if(r.uid == u) then
							r.stuff
					   else 1 
					 );;



fun u: int^BOT, r:  Sigma[uid: int^BOT, stuff: int^A(uid) ]^BOT =>
						[ int^A(u) ]
					(
					   if(r.uid == u) then
							r.stuff
					   else 1 
					 );;

				  
				  
				  )




////////



let f = (fun x:int^BOT => [int^U(x)] x)
in foreach(x in {1,3,4})
    with y = [int^U(1)] 0 
     do f(x*y) + y ;;



let comment = (\(u: (int, BOT()), s: (int, BOT()), r: ( { ( Sigma[uid:(int, BOT()), 
						sid:(int, BOT()), title:(int, A(uid, sid)), 
						abst:(int, A(uid, sid)), paper:(int, A(uid, sid)) ], BOT() ) }, BOT()) )
						[ (int, A(u,s)) ].(
					 foreach(p in r) with res =  1  do
					   if(p.uid == u and p.sid == s) then
							p.paper
					   else res
						) 
				  ) in comment;;




let comment = (\(u: (int, BOT()), s: (int, BOT()), r:  ( Sigma[uid:(int, BOT()), 
						sid:(int, BOT()), title:(int, A(uid, sid)), 
						abst:(int, A(uid, sid)), paper:(int, A(uid, sid)) ], BOT() )  )
						[ (int, A(u,s)) ].
						( if(r.uid == u and r.sid == s) then
							r.paper
					   	  else 1   )
						
				  ) in comment ;;   


/** ***/
let f = (fun x:int^BOT => [int^U(x)] x)
in	  
foreach(x in {1,3,4})
  with y = [int^U(1)]0 
    do f(x) + y ;;
	

/***** BIG Example *******/

let Users = 
	{}: { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT
in 
let Submissions  = 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT 
in 
let Reviews= 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT 
in 

/** Ex 2.2 -OK **/


 let viewAuthorPapers =  
	( fun uida: int^BOT => 
		[ {  Sigma[uid: int^BOT, sid: int^BOT, 
						title: int^A(uida, sid), abst:int^A(uida, sid), 
						paper:int^A(uida, sid) ]^BOT }^BOT ]
						
	 	( foreach(x in Submissions) with y = {}: {  Sigma[uid: int^BOT, sid: int^BOT, 
											title: int^A(uida, sid), abst:int^A(uida, sid), 
											paper:int^A(uida, sid) ]^BOT }^BOT
			do 
			  let tuple = !x 
	   		 in (  if(tuple.uid == uida ) then tuple::y else y )
		) 
	 )  in let n = 42 in (viewAuthorPapers(n)) ;;





/* entities declarations */

let Users = 
	{}: { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT
in 
let Submissions  = 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT 
in 
let Reviews= 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT 
in 

/** Ex 2.3 - typechecks OK **/


let viewAssignedPapers =  
	 (fun uidr: int^BOT =>
	 	( foreach(x in Reviews) with res_x = {}: {  Sigma[uid: int^BOT, sid: int^BOT, 
	   													title: int^A(uid,sid), abst:int^A(uid,sid), 
	   													paper:int^A(uid,sid) ]^BOT 
													}^BOT 
				do 
			   (
	   			let tuple_rev = !x 
	   			in (  if(tuple_rev.uid == uidr ) then 
	   				( foreach(y in Submissions) with res_y = {}: {  Sigma[uid: int^BOT, sid: int^BOT, 
	   													title: int^A(uid,sid), abst:int^A(uid,sid), 
	   													paper:int^A(uid,sid) ]^BOT 
													}^BOT 
					do (
						let tuple_sub = !y
	   					in ( if(tuple_sub.sid == tuple_rev.sid ) then tuple_sub::res_y else res_y )
	   			   	   ) )
   					
	   			  else res_x )
			) 
			
		) 
	 ) 
	  in let r = first(viewAssignedPapers(42)) in r ;;
	  
	  
/** Ex 2.4 -- bug no solver API, funciona no process **/

let Users = 
	{}: { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT
in 
let Submissions  = 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT 
in 
let Reviews= 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT 
in 

let t = first(
	foreach(x in Submissions) with y = {}: { int^A(42,70) }^A(42,70) do 
	(
	   let t_sub = !x 
	   in ( if(t_sub.uid == 42 and t_sub.sid == 70 ) then t_sub.title::y else y)
	) 
	
	) in 
	
	(foreach(x in Submissions) with y = skip do  
		let t_sub = !x 
	    in ( if(t_sub.uid == 42 and t_sub.sid == 70 ) then 
	    		let new_rec  = 
	    				 	
	    		   		[uid: int^BOT = t_sub.uid, sid: int^BOT = t_sub.sid, 
	    		   		title: int^A(uid, sid) = t, abst: int^A(uid, sid) = t_sub.abst, 
	    		   		paper: int^A(uid, sid) = t_sub.paper ]
	    		in x := new_rec
	    	else skip ) 
	  ) 
;;


/*** negative 2.4 ***/

 
let Users = 
	{}: { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT
in 
let Submissions  = 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT 
in 
let Reviews= 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT 
in 
let t = first(
	foreach(x in Submissions) with y = {}: { int^A(42,70) }^A(42,70) do 
	(
	   let t_sub = !x 
	   in ( if(t_sub.uid == 42 and t_sub.sid == 70 ) then t_sub.title::y else y)
	) 
	
	) in 
	
	(foreach(x in Submissions) with y = skip do  
		let t_sub = !x 
	    in ( if(t_sub.uid == 32 ) then 
	    		let new_rec  = 	
	    		   		[uid: int^BOT = t_sub.uid, sid: int^BOT = t_sub.sid, 
	    		   		title: int^A(uid, sid) = t, abst: int^A(uid, sid) = t_sub.abst, 
	    		   		paper:int^A(uid, sid) = t_sub.paper ]
	    		in x := new_rec
	    	else skip ) 
	  ) 
;;






/** Ex 2.5  **/




/**   let x = [int^U(1)] 100 in [int^PC(1,70)] x;;  ***/
/**   let x = [int^U(2)] 100 in [int^PC(1,70)] x;;  ***/
/**   let x = [int^A(BOT,70)] 100 in [int^A(42,70)] x;;  ***/
/**   let x = [int^U(1)] 100 in [int^PC(2,60)] x;;  ***/
/**   let x = [int^U(1)] 100 in [int^PC(1,70)] x;;  ***/
/**   let x = [int^U(42)] 100 in [int^A(32,60)] x;;  ***/
/**   let x = [int^U(42)] 100 in [int^A(42,70)] x;;  ***/
/**   let x = [int^A(BOT,BOT)] 100 in [int^A(42,BOT)] x;;  ***/


/**   [{ int^TOP }^TOP] {1,2};;  ***/
/** let x = [{ int^TOP }^TOP] {1,2} in [{int^BOT}^BOT] x;;  ***/
/** [ {int^BOT}^TOP ] {1,2};; * not well formed */


let Users = 
	{}: { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT
in 
let Submissions  = 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT 
in 
let Reviews= 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT 
in 
(
let viewAssignedPapers =  
	 (fun uidr: int^BOT =>
	 	( foreach(x in Reviews) with res_x = {}: { Sigma[uid: int^BOT, sid: int^BOT, 
	   													title: int^A(uid, sid), abst: int^A(uid, sid), 
	   													paper: int^A(uid, sid) ]^BOT }^BOT 								  
				do 
			   (
	   			let tuple_rev = !x 
	   			in (  if(tuple_rev.uid == uidr ) then 
	   				( foreach(y in Submissions) with res_y = {}: { Sigma[uid: int^BOT, sid: int^BOT, 
	   													title: int^A(uid, sid), abst: int^A(uid, sid), 
	   													paper: int^A(uid, sid) ]^BOT }^BOT  
					do (
						let tuple_sub = !y
	   					in ( if(tuple_sub.sid == tuple_rev.sid ) then tuple_sub::res_y else res_y )
	   			   	   ) )
   					
	   			  else res_x )
			) 
			
		) 
	 ) 
	  in 
	let comment = fun u: int^BOT, s: int^BOT, 
					r:  Sigma[uid: int^BOT, sid: int^BOT, 
						  title: int^A(uid, sid), abst: int^A(uid, sid), 
						  paper: int^A(uid, sid) ]^BOT 
		=>
			[ int^A(u,s) ]
			(
			   if(r.uid == u and r.sid == s) then
				r.paper
			   else 1 
			 )
	   in   
	  
	  
	(let addCommentSubmission =  
	 (fun uid_r: int^BOT, sidr: int^BOT =>
						
	 	( foreach(p in viewAssignedPapers(uid_r)) with dummy = skip do 
			   (
	   			  if(p.sid == sidr ) then 
	   				( foreach(y in Reviews) with dummy2 = skip do 
	   				  (
						let trev = !y in
	   					 ( if(trev.sid == p.sid ) then 
	   						( let up_rec = [uid: int^BOT = trev.uid, 
	   								sid: int^BOT = trev.sid, 
									PC_only: int^PC(uid,sid) =  comment(p.uid, p.sid, p), 
	   								review: int^A(TOP, sid) = trev.review, 
	   								grade: int^A(TOP, sid) = trev.grade ] 
	   							in y := up_rec ) 
	   					     
	   					     else skip
	   					     )
	   			   	   ) 
	   			   	)
   					
	   			  else skip
	   		  )
		) 
	  ) 
	  in addCommentSubmission )
)
 ;;
 
 
 /***  negative 2.5 - sem if no fim **/
let Users = 
	{}: { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT
in 
let Submissions  = 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT 
in 
let Reviews= 
	{}: { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT 
in 
(
let viewAssignedPapers =  
	 (fun uidr: int^BOT =>
	 	( foreach(x in Reviews) with res_x = {}: { Sigma[uid: int^BOT, sid: int^BOT, 
	   													title: int^A(uid, sid), abst: int^A(uid, sid), 
	   													paper: int^A(uid, sid) ]^BOT }^BOT 								  
				do 
			   (
	   			let tuple_rev = !x 
	   			in (  if(tuple_rev.uid == uidr ) then 
	   				( foreach(y in Submissions) with res_y = {}: { Sigma[uid: int^BOT, sid: int^BOT, 
	   													title: int^A(uid, sid), abst: int^A(uid, sid), 
	   													paper: int^A(uid, sid) ]^BOT }^BOT  
					do (
						let tuple_sub = !y
	   					in ( if(tuple_sub.sid == tuple_rev.sid ) then tuple_sub::res_y else res_y )
	   			   	   ) )
   					
	   			  else res_x )
			) 
			
		) 
	 ) 
	  in 
	let comment = fun u: int^BOT, s: int^BOT, 
					r:  Sigma[uid: int^BOT, sid: int^BOT, 
						  title: int^A(uid, sid), abst: int^A(uid, sid), 
						  paper: int^A(uid, sid) ]^BOT 
		=>
			[ int^A(u,s) ]
			(
			   if(r.uid == u and r.sid == s) then
				r.paper
			   else 1 
			 )
	   in   
	  
	  
	(let addCommentSubmission =  
	 (fun uid_r: int^BOT, sidr: int^BOT =>
						
	 	( foreach(p in viewAssignedPapers(uid_r)) with dummy = skip do 
			   (
	   			  if(p.sid == sidr ) then 
	   				( foreach(y in Reviews) with dummy2 = skip do 
	   				  (
						let trev = !y in
	   					 (  
	   						( let up_rec = [uid: int^BOT = trev.uid, 
	   								sid: int^BOT = trev.sid, 
									PC_only: int^PC(uid,sid) =  comment(p.uid, p.sid, p), 
	   								review: int^A(TOP, sid) = trev.review, 
	   								grade: int^A(TOP, sid) = trev.grade ] 
	   							in y := up_rec ) 

	   					     )
	   			   	   ) 
	   			   	)
   					
	   			  else skip
	   		  )
		) 
	  ) 
	  in addCommentSubmission )
)
 ;;






if true then (if true then 1 else 2) else 4 ;;


**** ****/

(fun x: Sigma[u: int^BOT, n: int^U(u)]^BOT => if x.u == 1 then x.n else [int^U(1)] 0);;

/* Type: ( Pi(x: Sigma[u: int^BOT, n: int^U(u)]^BOT).(int^U(1)) )^BOT */


(fun x:Sigma[u:int^BOT, n:int^U(u)]^BOT => if x.u == 1 then x.n else [int^U(2)] 0);;

/* Type: ( Pi(x: Sigma[u: int^BOT, n: int^U(u)]^BOT).(int^U(TOP)) )^BOT */


(fun x:Sigma[u:int^BOT, n:int^U(u)]^BOT => if x.u == 1 then x.n else [int^A(BOT,BOT)] 0);;

/* Type: ( Pi(x: Sigma[u: int^BOT, n: int^U(u)]^BOT).(int^A(BOT, BOT)) )^BOT */


(fun x:int^BOT => [Sigma[u:int^BOT, n:int^U(u)]^BOT] [u:int^BOT = x, n:int^U(x) = 2]);;

/* Type: ( Pi(x: int^BOT).(Sigma[u: int^BOT, n: int^U(u)]^BOT) )^BOT */


(fun x:int^BOT => [Sigma[u:int^BOT, n:int^U(x)]^BOT] [u:int^BOT = x, n:int^U(x) = 2]);;

/* Type: ( Pi(x: int^BOT).(Sigma[u: int^BOT, n: int^U(x)]^BOT) )^BOT */


(fun x:int^BOT => [Sigma[u:int^BOT, n:int^U(u)]^BOT] [u:int^BOT = 1, n:int^U(x) = 2]);;

/* Wrong type: Expected declared type Sigma[u: int^BOT, n: int^U(u)]^BOT but found type Sigma[u: int^BOT, n: int^U(x)]^BOT */


let f = (fun x:int^BOT => [int^U(x)] x)
in f;;

/* Type: ( Pi(x: int^BOT).(int^U(x)) )^BOT */


let f = (fun x:int^BOT => [int^U(x)] x)
in f(1);;

/* Type: int^U(1) */


let f = (fun x:int^BOT => [int^U(x)] x)
in f(1) + f(2);;

/* Type: int^U(TOP) */


let f = (fun x:int^BOT => [int^U(x)] x)
in foreach(x in {1,3,4})
    with y = [int^U(1)] 0 
     do f(x) + y ;;

/* Type: int^U(TOP) */


foreach(x in {1,3,4})
  with y = [int^U(1)] 0 
    do x + y ;;

/* Type: int^U(1) */


let l = [{int^TOP}^TOP] {1,2,3} in
  foreach (x in l) with c = 0 do c+1;;

/* Type: int^BOT */


let l = [{int^TOP}^TOP]{ 1,2,3} in
  foreach (x in l) with c = 0 do c+1;;

/* Type: int^BOT */


let b = { [s:int^TOP = 0], [s:int^TOP = 1], [s:int^TOP = 2]}
  in foreach (x in b) 
      with c = 0 
        do c+1 ;;

/* Type: int^BOT */


let b = { [s:ref(int^TOP)^BOT = ref [int^TOP] 0], 
          [s:ref(int^TOP)^BOT = ref [int^TOP] 1], 
          [s:ref(int^TOP)^BOT = ref [int^TOP] 2]}
  in foreach (x in b) 
       with c = 0 
         do c + (!(x.s)) ;;

/* Type: int^TOP */

let b = { [s:ref(int^TOP)^BOT = ref [int^TOP] 0], 
          [s:ref(int^TOP)^BOT = ref [int^TOP] 1], 
          [s:ref(int^TOP)^BOT = ref [int^TOP] 2]}
  in 
    foreach (x in b) 
      with c = 0 
        do ( (x.s) := (!(x.s)) + 1 ; (!(x.s)) ) ;;

/* Type: int^TOP */

let b = { [s:ref(int^TOP)^BOT = ref [int^TOP] 0], 
          [s:ref(int^TOP)^BOT = ref [int^TOP] 1], 
          [s:ref(int^TOP)^BOT = ref [int^TOP] 2]}
  in 
    foreach (x in b) 
      with c = 0 
        do ( (x.s) := (!(x.s)) + 1 ; c + 1 ) ;;

/* Type: int^BOT */


let b = { [s:ref(int^TOP)^BOT = ref [int^TOP] 0], 
          [s:ref(int^TOP)^BOT = ref [int^TOP] 1], 
          [s:ref(int^TOP)^BOT = ref [int^TOP] 2]}
  in 
    foreach (x in b) 
      with c = 0 
        do c + 1 ;;

/* Type: int^BOT */


let r = ref [int ^ U(BOT)] 1 in
let v = ref [int ^ U(BOT)] 2
  in (
    r := [ int ^ U(1) ] 1 ;
    if ((!r) == 0) then v := [ int ^ U(BOT) ] 1 else skip
  );;

/* Insecure flow detected from label U(1) to label U(BOT)! */


let r = ref [int ^ U(BOT)] 1 in
let v = ref [int ^ U(BOT)] 2
  in (
    r := [ int ^ U(BOT) ] 1 ;
    if ((!r) == 0) then v := [ int ^ U(BOT) ] 1 else skip
  );;
  
/* Type: cmd^U(BOT) */




/***** Using Typedefs *******/


/** Ex 2.2  **/
typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT in
typedef sub_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type 
in typedef ret_type = { Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uida, sid), abst:int^A(uida, sid), 
						paper:int^A(uida, sid) ]^BOT }^BOT in 

 let viewAuthorPapers = fun uida: int^BOT =>   		
	[ ret_type ]( foreach(x in Submissions) with y = {}: ret_type do 
			    	let tuple = !x in
			    	  if(tuple.uid == uida) then tuple::y else y  ) 
 in let n = 42 in (viewAuthorPapers(n)) ;;

/* Type: { Sigma[uid: int^BOT, sid: int^BOT, title: int^A(42, sid), abst: int^A(42, sid), paper: int^A(42, sid)]^BOT }^BOT */






/* Ex 2.3 */

typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT in
typedef sub_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type
in typedef sub = { Sigma[uid: int^BOT, sid: int^BOT, 
						 title: int^A(uid,sid), abst:int^A(uid,sid), 
	   					 paper:int^A(uid,sid) ]^BOT }^BOT  

in let viewAssignedPapers = fun uidr: int^BOT =>
	 	 foreach(x in Reviews) with res_x = {}: sub do 
	   		let tuple_rev = !x 
	   		  in if(tuple_rev.uid == uidr ) then 
	   			    foreach(y in Submissions) with res_y = {}: sub do 
					   let tuple_sub = !y
	   					in if(tuple_sub.sid == tuple_rev.sid) then tuple_sub::res_y else res_y 	    
	   			 else res_x 
 
  in let r = first(viewAssignedPapers(42)) in r ;;
	  
/* Type: Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid)]^BOT */
	  
	  
	  
	  
	  
/** Ex 2.4 **/

typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT in
typedef sub_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type

in let t = first( foreach(x in Submissions) with y = {}: { int^A(42,70) }^A(42,70) do 
	   let t_sub = !x in 
	     if(t_sub.uid == 42 and t_sub.sid == 70 ) then t_sub.title::y else y) 
   in foreach(x in Submissions) with y = skip do  
		let t_sub = !x 
	    in if(t_sub.uid == 42 and t_sub.sid == 70) then 
	    	  let new_rec  = [uid: int^BOT = t_sub.uid, sid: int^BOT = t_sub.sid, 
	    		   			  title: int^A(uid, sid) = t, abst: int^A(uid, sid) = t_sub.abst, 
	    		   			  paper: int^A(uid, sid) = t_sub.paper ]
	    	  in x := new_rec
	    	else skip    ;;


/* Type: cmd^BOT */





/*** negative 2.4 ***/

 
typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT in
typedef sub_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type

in let t = first( foreach(x in Submissions) with y = {}: { int^A(42,70) }^A(42,70) do 
	   let t_sub = !x in 
	     if(t_sub.uid == 42 and t_sub.sid == 70 ) then t_sub.title::y else y) 
   in foreach(x in Submissions) with y = skip do  
		let t_sub = !x 
	    in if(t_sub.uid == 32) then 
	    	  let new_rec  = [uid: int^BOT = t_sub.uid, sid: int^BOT = t_sub.sid, 
	    		   			  title: int^A(uid, sid) = t, abst: int^A(uid, sid) = t_sub.abst, 
	    		   			  paper: int^A(uid, sid) = t_sub.paper ]
	    	  in x := new_rec
	    	else skip    ;;


/* Wrong type: Expected declared type Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid)]^BOT but found type Sigma[uid: int^BOT, sid: int^BOT, title: int^A(42, 70), abst: int^A(32, TOP), paper: int^A(32, TOP)]^BOT
 */





/** Ex 2.5  **/

typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT in
typedef sub_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type
in typedef sub = { Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), 
	   			   paper: int^A(uid, sid) ]^BOT }^BOT
in typedef rec_sub = Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), 
	   			   paper: int^A(uid, sid) ]^BOT
	   			   
in let viewAssignedPapers = fun uidr: int^BOT =>
	 	 foreach(x in Reviews) with res_x = {}: sub do 
			let tuple_rev = !x 
	   		 in if(tuple_rev.uid == uidr ) then 
	   			   foreach(y in Submissions) with res_y = {}: sub do 
					   let tuple_sub = !y
	   					in if(tuple_sub.sid == tuple_rev.sid) then tuple_sub::res_y else res_y 
	   			   	    
	   			 else res_x  
  in let comment = fun u: int^BOT, s: int^BOT, r: rec_sub =>
	   [ int^A(u,s) ] (if(r.uid == u and r.sid == s) then r.paper else 1) in   
    
    let addCommentSubmission = fun uid_r: int^BOT, sidr: int^BOT =>		
	 	 foreach(p in viewAssignedPapers(uid_r)) with dummy = skip do 
	   	    if(p.sid == sidr ) then 
	   		   foreach(y in Reviews) with dummy2 = skip do 
				  let trev = !y in
	   				if(trev.sid == p.sid ) then 
	   				   let up_rec = [uid: int^BOT = trev.uid, 
	   								sid: int^BOT = trev.sid, 
									PC_only: int^PC(uid,sid) =  comment(p.uid, p.sid, p), 
	   								review: int^A(TOP, sid) = trev.review, 
	   								grade: int^A(TOP, sid) = trev.grade ] 
	   				   in y := up_rec 
	   					     
	   				else skip
	
	   		else skip
    in addCommentSubmission;;
 
 
 /* Type: ( Pi(uid_r: int^BOT, sidr: int^BOT).(cmd^BOT) )^BOT */
 
 
 
 /***  negative 2.5 - sem if no fim **/
typedef usr_type = { ref (Sigma[uid: int^BOT, name: int^U(uid), univ: int^U(uid), email: int^U(uid) ]^BOT)^BOT }^BOT in
typedef sub_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), paper: int^A(uid, sid) ]^BOT )^BOT  }^ BOT in
typedef rev_type = { ref (Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT)^BOT }^BOT in

let Users = {}: usr_type
in let Submissions  = {}: sub_type 
in let Reviews= {}: rev_type
in typedef sub = { Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), 
	   			   paper: int^A(uid, sid) ]^BOT }^BOT
in typedef rec_sub = Sigma[uid: int^BOT, sid: int^BOT, title: int^A(uid, sid), abst: int^A(uid, sid), 
	   			   paper: int^A(uid, sid) ]^BOT
	   			   
in let viewAssignedPapers = fun uidr: int^BOT =>
	 	 foreach(x in Reviews) with res_x = {}: sub do 
			let tuple_rev = !x 
	   		 in if(tuple_rev.uid == uidr ) then 
	   			   foreach(y in Submissions) with res_y = {}: sub do 
					   let tuple_sub = !y
	   					in if(tuple_sub.sid == tuple_rev.sid) then tuple_sub::res_y else res_y 
	   			   	    
	   			 else res_x  
  in let comment = fun u: int^BOT, s: int^BOT, r: rec_sub =>
	   [ int^A(u,s) ] (if(r.uid == u and r.sid == s) then r.paper else 1) in   
    
    let addCommentSubmission = fun uid_r: int^BOT, sidr: int^BOT =>		
	 	 foreach(p in viewAssignedPapers(uid_r)) with dummy = skip do 
	   	    if(p.sid == sidr ) then 
	   		   foreach(y in Reviews) with dummy2 = skip do 
				  let trev = !y in
	   				 let up_rec = [uid: int^BOT = trev.uid, 
	   								sid: int^BOT = trev.sid, 
									PC_only: int^PC(uid,sid) =  comment(p.uid, p.sid, p), 
	   								review: int^A(TOP, sid) = trev.review, 
	   								grade: int^A(TOP, sid) = trev.grade ] 
	   				 in y := up_rec 
	   		else skip
    in addCommentSubmission;;

/* Wrong type: Expected declared type Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^PC(uid, sid), review: int^A(TOP, sid), grade: int^A(TOP, sid)]^BOT but found type Sigma[uid: int^BOT, sid: int^BOT, PC_only: int^A(TOP, sidr), review: int^A(TOP, TOP), grade: int^A(TOP, TOP)]^BOT
 */
 
 
 
typedef usr_type = Sigma[uid: int^BOT,pwd: int^U(uid)]^BOT in
typedef usr_file_type = { ref (usr_type)^BOT } in
typedef pwd_list_type = { int^U(TOP) } in
let get_pwd = 
      fun u:int^BOT, f:usr_file_type => 
         foreach (urec in f) with s = 0 do
            let r = !urec in
              if (r.uid == u) then r.pwd else s 
in 
let reset_pwds =
      fun f:usr_file_type, d:int^U(BOT) => 
         foreach (urec in f) with s = skip do
            let r = !urec in
               urec := [ uid:int^BOT=r.uid, pwd:int^U(uid) = d ] 
in
let list_pwds =
      fun f:usr_file_type => [ { int^U(TOP) } ]
         ( foreach (urec in f) with s = {}:pwd_list_type do
            let r = !urec in r.pwd :: s )
in get_pwd;;
	  