Section TOpsInfer.
  
Require Import String.
  
Require Import List.
  
Require Import Compare_dec.
  
Require Import Program.
  
Require Import Eqdep_dec.
  
Require Import Bool.
  
Require Import EquivDec.
  
Require Import Utils.
  
Require Import Types.
  
Require Import BasicRuntime.
  
Require Import ForeignDataTyping.
  
Require Import ForeignOpsTyping.
  
Require Import TUtil.
  
Require Import TData.
  
Require Import TOps.
  
Require Import TDataSort.
  
  
Context {
fdata:
foreign_data}.
  
Context {
ftype:
foreign_type}.
  
Context {
fdtyping:
foreign_data_typing}.
  
Context {
m:
brand_model}.
  
Hint Rewrite Bottom_proj Top_proj Unit_proj Nat_proj Bool_proj String_proj : 
type_canon.
    
  
Definition tunrecsortable (
sl:
list string) (τ:
rtype) : 
option rtype.
Proof.
  Ltac destructer :=
    
repeat progress
           (
try
              match goal with
              | [
H:
context
                     [
match ?
p with
                      | 
exist _ _ _ => 
_
                      end] |- 
_] => 
destruct p
              | [
H:
context [
match ?
p with | 
_ => 
_ end] |- 
_ ] =>
                
case_eq p; 
intros;
                
repeat match goal with
                       | [
H1: ?
a = ?
a |- 
_ ] => 
clear H1
                       | [
H1: ?
a = ?
b |- 
_ ] => 
rewrite H1 in *
                       
end
              | [
H:
Some _ = 
Some _ |- 
_ ] => 
inversion H; 
clear H
              | [
H:
ex _ |- 
_]  => 
destruct H
              | [
H:
_ /\ 
_ |- 
_]  => 
destruct H
              | [
H:
lift _ _ = 
Some _ |- 
_] => 
apply some_lift in H; 
destruct H
              | [
H:
lift _ _ = 
None |- 
_] => 
apply none_lift in H
                                                                 
              | [
H:
context [
RecMaybe _ (
rec_concat_sort _ _ )] |- 
_ ] => 
rewrite RecMaybe_rec_concat_sort in H
              | [
H:
RecMaybe _ _ = 
Some _ |- 
_ ] => 
apply RecMaybe_some_pf in H; 
destruct H
              | [
H1:
is_list_sorted StringOrder.lt_dec (
domain ?
l) = 
true,
                    
H2:
context[
RecMaybe ?
k ?
l] |- 
_ ] =>
                
rewrite (
RecMaybe_pf_some _ _ H1) 
in H2
              | [
H: 
tuncoll _ = 
_ |- 
_ ] => 
apply tuncoll_correct in H
              | [
H: 
tsingleton _ = 
_ |- 
_ ] => 
apply tsingleton_correct in H
              | [
H: 
tunrec _ = 
_ |- 
_ ] => 
apply tunrec_correct in H; 
destruct H
              | [
H: ` 
_ = 
Bottom₀ |- 
_ ] => 
apply Bottom_canon in H
              | [
H: ` 
_ = 
Brand₀ ?
b |- 
_ ] => 
apply Brand_canon in H
              | [
H: ` 
_ = 
Top₀ |- 
_ ] => 
apply Top_canon in H
              | [
H: ` 
_ = 
Unit₀ |- 
_ ] => 
apply Unit_canon in H
              | [
H: ` 
_ = 
Nat₀ |- 
_ ] => 
apply Nat_canon in H
              | [
H: ` 
_ = 
Bool₀ |- 
_ ] => 
apply Bool_canon in H
              | [
H: ` 
_ = 
String₀ |- 
_ ] => 
apply String_canon in H
              | [
H: ` 
_ = 
Coll₀ ?
A |- 
_] =>
                
match A with
                |  ` 
_  => 
apply Coll_canon in H
                | 
_ => 
destruct (
Coll_inside _ _ H); 
subst; 
apply Coll_canon in H
                end
                  
              | [
H: ?
a = ?
a |- 
_ ] => 
clear H
              | [
H: ?
a = ?
b |- 
_ ] => 
rewrite H in *
              | [
H:
binOp_type _ _ _ _ |- 
_ ] => 
inversion H; 
clear H
              end; 
try autorewrite with type_canon in *; 
try unfold equiv, 
complement, 
rtype in *; 
simpl in *; 
try rtype_equalizer; 
try subst; 
try discriminate; 
try reflexivity).
  
Section b.
    
Context {
fbop:
foreign_binary_op}.
    
Context {
fboptyping:
foreign_binary_op_typing}.
    
Definition infer_binop_type (
b:
binOp) (τ₁ τ₂:
rtype) : 
option rtype :=
      
match b with
      | 
AEq =>
        
if (τ₁ == τ₂) 
then Some Bool else None
      | 
AConcat => 
trecConcat τ₁ τ₂
      | 
AMergeConcat => 
lift Coll (
tmergeConcat τ₁ τ₂)
      | 
AAnd =>
        
match (`τ₁, `τ₂) 
with
        | (
Bool₀, 
Bool₀) => 
Some Bool
        | 
_ => 
None
        end
      | 
AOr =>
        
match (`τ₁, `τ₂) 
with
        | (
Bool₀, 
Bool₀) => 
Some Bool
        | 
_ => 
None
        end
      | 
ABArith _ =>
        
match (`τ₁, `τ₂) 
with
        | (
Nat₀, 
Nat₀) => 
Some Nat
        | 
_ => 
None
        end
      | 
ALt | 
ALe =>
        
match (`τ₁, `τ₂) 
with
        | (
Nat₀, 
Nat₀) => 
Some Bool
        | (
_, 
_) => 
None
        end
      | 
AUnion | 
AMinus | 
AMin | 
AMax =>
        
match (
tuncoll τ₁, 
tuncoll τ₂) 
with
        | (
Some τ₁₀, 
Some τ₂₀) =>
          
if (`τ₁₀ == `τ₂₀) 
then Some τ₁ 
else None
        | 
_ => 
None
        end
      | 
AContains =>
        
match tuncoll τ₂ 
with
        | 
Some τ₂₀ =>
          
if (`τ₁ == `τ₂₀) 
then Some Bool else None
        | 
None => 
None
        end
      | 
ASConcat =>
        
match (`τ₁, `τ₂) 
with
        | (
String₀, 
String₀) => 
Some String
        | (
_, 
_) => 
None
        end
      | 
AForeignBinaryOp fb =>
        
foreign_binary_op_typing_infer fb τ₁ τ₂
      
end.
    
Lemma ATConcat_trec {τ₁ τ₂ τ
out} :
      
trecConcat τ₁ τ₂ = 
Some τ
out ->
      
binOp_type AConcat τ₁ τ₂ τ
out.
Proof.
      destruct τ₁ 
using rtype_rect; 
simpl; 
try discriminate.
      
destruct τ₂ 
using rtype_rect; 
simpl; 
try discriminate.
      
intros.
      
destructer.
      
econstructor; 
eauto.
    Qed.
 
    
    Lemma ATMergeConcat_tmerge {τ₁ τ₂ τ
out} :
      
tmergeConcat τ₁ τ₂ = 
Some τ
out ->
      
binOp_type AMergeConcat τ₁ τ₂ (
Coll τ
out).
Proof.
      destruct τ₁ 
using rtype_rect; 
simpl; 
try discriminate.
      
destruct τ₂ 
using rtype_rect; 
simpl; 
try discriminate.
      
intros.
      
destructer;
        
econstructor; 
eauto.
    Qed.
 
    Theorem infer_binop_type_correct (
b:
binOp) (τ₁ τ₂ τ
out:
rtype) :
      
infer_binop_type b τ₁ τ₂ = 
Some τ
out ->
      
binOp_type b τ₁ τ₂ τ
out.
Proof.
  
    Theorem infer_binop_type_least {
b:
binOp} {τ₁ τ₂:
rtype} {τ
out₁ τ
out₂:
rtype} :
      
infer_binop_type b τ₁ τ₂ = 
Some τ
out₁ ->
      
binOp_type b τ₁ τ₂ τ
out₂ ->
      
subtype τ
out₁ τ
out₂.
Proof.
    Theorem infer_binop_type_complete {
b:
binOp} {τ₁ τ₂:
rtype} (τ
out:
rtype) :
      
infer_binop_type b τ₁ τ₂ = 
None ->
      ~ 
binOp_type b τ₁ τ₂ τ
out.
Proof.
  End b.
  
Section u.
    
Context {
fuop:
foreign_unary_op}.
    
Context {
fuoptyping:
foreign_unary_op_typing}.
    
    
Definition infer_unop_type (
u:
unaryOp) (τ₁:
rtype) : 
option rtype :=
      
match u with
      | 
AIdOp => 
Some τ₁
      | 
ANeg =>
        
match `τ₁ 
with
        | 
Bool₀ => 
Some Bool
        | 
_ => 
None
        end
      | 
AColl => 
Some (
Coll τ₁)
      | 
ASingleton => 
tsingleton τ₁
      | 
AFlatten =>
        
match (
tuncoll τ₁) 
with
        | 
Some τ₁₀ =>
          
match tuncoll τ₁₀ 
with
          | 
Some _ => 
Some τ₁₀
          | 
_ => 
None
          end
        | 
None => 
None
        end
      | 
ADistinct =>
        
olift (
fun x => 
Some (
Coll x)) (
tuncoll τ₁)
      | 
AOrderBy sl =>
        
match (
tuncoll τ₁) 
with
        | 
Some τ₁₀ =>
          
match tunrecsortable (
List.map fst sl) τ₁₀ 
with
          | 
Some _ => 
Some τ₁
          | 
None => 
None
          end
        | 
None => 
None
        end
      | 
ARec s => 
Some (
Rec Closed ((
s, τ₁)::
nil) 
eq_refl)
      | 
ADot s => 
tunrecdot s τ₁
      | 
ARecRemove s => 
tunrecremove s τ₁
      | 
ARecProject sl => 
tunrecproject sl τ₁
      | 
ACount =>
        
match `τ₁ 
with
        | 
Coll₀ 
_ => 
Some Nat
        | 
_ => 
None
        end
      | 
ASum
      | 
ANumMin
      | 
ANumMax
      | 
AArithMean =>
        
match `τ₁ 
with
        | 
Coll₀ 
Nat₀ => 
Some Nat
        | 
_ => 
None
        end
      | 
AToString => 
Some String
      | 
ASubstring _ _ =>
        
match `τ₁ 
with
        | 
String₀ => 
Some String
        | 
_ => 
None
        end
      | 
ALike _ _ =>
        
match `τ₁ 
with
        | 
String₀ => 
Some Bool
        | 
_ => 
None
        end
      | 
ALeft =>
        
Some (
Either τ₁ ⊥)
      | 
ARight =>
        
Some (
Either ⊥ τ₁)
      | 
ABrand b =>
        
if (
rtype_eq_dec τ₁ (
brands_type b)) 
        
then Some (
Brand b)
        
else None
      | 
AUnbrand =>
        
match `τ₁ 
with
        | 
Brand₀ 
b => 
Some (
brands_type b)
        | 
_ => 
None
        end
      | 
ACast b =>
        
match `τ₁ 
with
        | 
Brand₀ 
_ => 
Some (
Option (
Brand b))
        | 
_ => 
None
        end
      | 
AUArith op =>
        
match `τ₁ 
with
        | 
Nat₀ => 
Some Nat
        | 
_ => 
None
        end
      | 
AForeignUnaryOp fu =>
        
foreign_unary_op_typing_infer fu τ₁
      
end.
    
Lemma empty_domain_remove {
A} (
l:
list (
string * 
A)) (
s:
string):
      
domain l = 
nil -> 
domain (
rremove l s) = 
nil.
Proof.
      induction l; intros; [reflexivity|simpl in H; congruence].
    Qed.
  
    Lemma sorted_rremove_done {
A} (
l:
list (
string*
A)) (
a:(
string*
A)) (
s:
string) :
      
is_list_sorted ODT_lt_dec (
domain (
a::
l)) = 
true ->
      
StringOrder.lt s (
fst a) ->
      
domain (
rremove (
a :: 
l) 
s) = 
domain (
a :: 
l).
Proof.
    
    Lemma Forall_rremove {
A} {
a} {
l:
list (
string * 
A)} :
      
Forall (
StringOrder.lt a) (
domain l) ->
      
forall s,
        
Forall (
StringOrder.lt a) (
domain (
rremove l s)).
Proof.
      induction l; 
simpl; 
try constructor.
      
inversion 1; 
subst; 
intros.
      
destruct (
string_dec s (
fst a0)); 
try constructor; 
auto.
    Qed.
 
    Lemma is_sorted_rremove {
A} (
l:
list (
string * 
A)) (
s:
string):
      
is_list_sorted ODT_lt_dec (
domain l) = 
true ->
      
is_list_sorted ODT_lt_dec (
domain (
rremove l s)) = 
true.
Proof.
    Lemma ATDot_tunrec {
s} {τ₁ τ
out} :
      
tunrecdot s τ₁ = 
Some τ
out ->
      
unaryOp_type (
ADot s) τ₁ τ
out.
Proof.
      unfold tunrecdot; 
intros.
      
destructer.
      
constructor; 
auto.
    Qed.
 
    Lemma ATRecRemove_tunrec {
s} {τ₁ τ
out} :
      
tunrecremove s τ₁ = 
Some τ
out ->
      
unaryOp_type (
ARecRemove s) τ₁ τ
out.
Proof.
      unfold tunrecremove; 
intros.
      
destructer.
      
constructor; 
auto.
    Qed.
 
    Lemma ATRecProject_tunrec {
sl} {τ₁ τ
out} :
      
tunrecproject sl τ₁ = 
Some τ
out ->
      
unaryOp_type (
ARecProject sl) τ₁ τ
out.
Proof.
      unfold tunrecproject; 
intros.
      
destructer.
      
constructor; 
auto.
    Qed.
 
    Lemma ATOrderBy_tunrec {
sl} {τ₁ τ
out} :
      
tunrecsortable (
List.map fst sl) τ₁ = 
Some τ
out ->
      
unaryOp_type (
AOrderBy sl) (
Coll τ₁) (
Coll  τ₁).
Proof.
    Lemma ATSingleton_tsingleton {τ₁ τ
out} :
      
tsingleton τ₁ = 
Some τ
out ->
      
unaryOp_type ASingleton τ₁ τ
out.
Proof.
      unfold tsingleton; 
intros.
      
destructer.
      
destruct x; 
try congruence.
      
inversion H; 
simpl in *; 
clear H.
      
destructer.
      
assert ((
exist (
fun τ₀ : 
rtype₀ => 
wf_rtype₀ τ₀ = 
true) (
Coll₀ 
x) 
e) =
              
Coll (
exist (
fun τ₀ : 
rtype₀ => 
wf_rtype₀ τ₀ = 
true) 
x e)).
      
apply rtype_fequal.
      
reflexivity.
      
rewrite H.
      
constructor; 
auto.
    Qed.
 
    Lemma infer_unop_type_correct (
u:
unaryOp) (τ₁ τ
out:
rtype) :
      
infer_unop_type u τ₁ = 
Some τ
out ->
      
unaryOp_type u τ₁ τ
out.
Proof.
      Hint Constructors unaryOp_type.
      
Hint Resolve ATDot_tunrec ATRecRemove_tunrec ATRecProject_tunrec
           ATOrderBy_tunrec ATSingleton_tsingleton.
      
unaryOp_cases (
case_eq u) 
Case; 
intros; 
simpl in *; 
destructer; 
unfold olift in *; 
try autorewrite with type_canon in *; 
destructer;
        
try congruence; 
try solve[ 
erewrite Rec_pr_irrel; 
reflexivity]; 
eauto 3.
      - 
constructor.
      - 
constructor; 
apply foreign_unary_op_typing_infer_correct;
        
apply H0.
    Qed.
 
    Lemma infer_unop_type_least (
u:
unaryOp) (τ₁ τ
out₁ τ
out₂:
rtype) :
      
infer_unop_type u τ₁ = 
Some τ
out₁ ->
      
unaryOp_type u τ₁ τ
out₂ ->
      
subtype τ
out₁ τ
out₂.
Proof.
    Lemma infer_unop_type_complete (
u:
unaryOp) (τ₁ τ
out:
rtype) :
      
infer_unop_type u τ₁ = 
None ->
      ~ 
unaryOp_type u τ₁ τ
out.
Proof.
  End u.
    
End TOpsInfer.