open Prims
type inst_t =
  (FStarC_Ident.lident * FStarC_Syntax_Syntax.universes) Prims.list
let mk (t : 'uuuuu FStarC_Syntax_Syntax.syntax) (s : 'uuuuu1) :
  'uuuuu1 FStarC_Syntax_Syntax.syntax=
  FStarC_Syntax_Syntax.mk s t.FStarC_Syntax_Syntax.pos
let rec inst
  (s :
    FStarC_Syntax_Syntax.term ->
      FStarC_Syntax_Syntax.fv -> FStarC_Syntax_Syntax.term)
  (t : FStarC_Syntax_Syntax.term) : FStarC_Syntax_Syntax.term=
  let t1 = FStarC_Syntax_Subst.compress t in
  let mk1 = mk t1 in
  match t1.FStarC_Syntax_Syntax.n with
  | FStarC_Syntax_Syntax.Tm_delayed uu___ -> failwith "Impossible"
  | FStarC_Syntax_Syntax.Tm_name uu___ -> t1
  | FStarC_Syntax_Syntax.Tm_uvar uu___ -> t1
  | FStarC_Syntax_Syntax.Tm_uvar uu___ -> t1
  | FStarC_Syntax_Syntax.Tm_type uu___ -> t1
  | FStarC_Syntax_Syntax.Tm_bvar uu___ -> t1
  | FStarC_Syntax_Syntax.Tm_constant uu___ -> t1
  | FStarC_Syntax_Syntax.Tm_quoted uu___ -> t1
  | FStarC_Syntax_Syntax.Tm_unknown -> t1
  | FStarC_Syntax_Syntax.Tm_uinst uu___ -> t1
  | FStarC_Syntax_Syntax.Tm_lazy uu___ -> t1
  | FStarC_Syntax_Syntax.Tm_fvar fv -> s t1 fv
  | FStarC_Syntax_Syntax.Tm_abs
      { FStarC_Syntax_Syntax.bs = bs; FStarC_Syntax_Syntax.body = body;
        FStarC_Syntax_Syntax.rc_opt = lopt;_}
      ->
      let bs1 = inst_binders s bs in
      let body1 = inst s body in
      let uu___ =
        let uu___1 =
          let uu___2 = inst_lcomp_opt s lopt in
          {
            FStarC_Syntax_Syntax.bs = bs1;
            FStarC_Syntax_Syntax.body = body1;
            FStarC_Syntax_Syntax.rc_opt = uu___2
          } in
        FStarC_Syntax_Syntax.Tm_abs uu___1 in
      mk1 uu___
  | FStarC_Syntax_Syntax.Tm_arrow
      { FStarC_Syntax_Syntax.bs1 = bs; FStarC_Syntax_Syntax.comp = c;_} ->
      let bs1 = inst_binders s bs in
      let c1 = inst_comp s c in
      mk1
        (FStarC_Syntax_Syntax.Tm_arrow
           { FStarC_Syntax_Syntax.bs1 = bs1; FStarC_Syntax_Syntax.comp = c1 })
  | FStarC_Syntax_Syntax.Tm_refine
      { FStarC_Syntax_Syntax.b = bv; FStarC_Syntax_Syntax.phi = t2;_} ->
      let bv1 =
        let uu___ = inst s bv.FStarC_Syntax_Syntax.sort in
        {
          FStarC_Syntax_Syntax.ppname = (bv.FStarC_Syntax_Syntax.ppname);
          FStarC_Syntax_Syntax.index = (bv.FStarC_Syntax_Syntax.index);
          FStarC_Syntax_Syntax.sort = uu___
        } in
      let t3 = inst s t2 in
      mk1
        (FStarC_Syntax_Syntax.Tm_refine
           { FStarC_Syntax_Syntax.b = bv1; FStarC_Syntax_Syntax.phi = t3 })
  | FStarC_Syntax_Syntax.Tm_app
      { FStarC_Syntax_Syntax.hd = t2; FStarC_Syntax_Syntax.args = args;_} ->
      let uu___ =
        let uu___1 =
          let uu___2 = inst s t2 in
          let uu___3 = inst_args s args in
          {
            FStarC_Syntax_Syntax.hd = uu___2;
            FStarC_Syntax_Syntax.args = uu___3
          } in
        FStarC_Syntax_Syntax.Tm_app uu___1 in
      mk1 uu___
  | FStarC_Syntax_Syntax.Tm_match
      { FStarC_Syntax_Syntax.scrutinee = t2;
        FStarC_Syntax_Syntax.ret_opt = asc_opt;
        FStarC_Syntax_Syntax.brs = pats;
        FStarC_Syntax_Syntax.rc_opt1 = lopt;_}
      ->
      let pats1 =
        FStarC_List.map
          (fun uu___ ->
             match uu___ with
             | (p, wopt, t3) ->
                 let wopt1 =
                   match wopt with
                   | FStar_Pervasives_Native.None ->
                       FStar_Pervasives_Native.None
                   | FStar_Pervasives_Native.Some w ->
                       let uu___1 = inst s w in
                       FStar_Pervasives_Native.Some uu___1 in
                 let t4 = inst s t3 in (p, wopt1, t4)) pats in
      let asc_opt1 =
        match asc_opt with
        | FStar_Pervasives_Native.None -> FStar_Pervasives_Native.None
        | FStar_Pervasives_Native.Some (b, asc) ->
            let uu___ =
              let uu___1 = inst_binder s b in
              let uu___2 = inst_ascription s asc in (uu___1, uu___2) in
            FStar_Pervasives_Native.Some uu___ in
      let uu___ =
        let uu___1 =
          let uu___2 = inst s t2 in
          let uu___3 = inst_lcomp_opt s lopt in
          {
            FStarC_Syntax_Syntax.scrutinee = uu___2;
            FStarC_Syntax_Syntax.ret_opt = asc_opt1;
            FStarC_Syntax_Syntax.brs = pats1;
            FStarC_Syntax_Syntax.rc_opt1 = uu___3
          } in
        FStarC_Syntax_Syntax.Tm_match uu___1 in
      mk1 uu___
  | FStarC_Syntax_Syntax.Tm_ascribed
      { FStarC_Syntax_Syntax.tm = t11; FStarC_Syntax_Syntax.asc = asc;
        FStarC_Syntax_Syntax.eff_opt = f;_}
      ->
      let uu___ =
        let uu___1 =
          let uu___2 = inst s t11 in
          let uu___3 = inst_ascription s asc in
          {
            FStarC_Syntax_Syntax.tm = uu___2;
            FStarC_Syntax_Syntax.asc = uu___3;
            FStarC_Syntax_Syntax.eff_opt = f
          } in
        FStarC_Syntax_Syntax.Tm_ascribed uu___1 in
      mk1 uu___
  | FStarC_Syntax_Syntax.Tm_let
      { FStarC_Syntax_Syntax.lbs = lbs; FStarC_Syntax_Syntax.body1 = t2;_} ->
      let lbs1 =
        let uu___ =
          FStarC_List.map
            (fun lb ->
               let uu___1 = inst s lb.FStarC_Syntax_Syntax.lbtyp in
               let uu___2 = inst s lb.FStarC_Syntax_Syntax.lbdef in
               {
                 FStarC_Syntax_Syntax.lbname =
                   (lb.FStarC_Syntax_Syntax.lbname);
                 FStarC_Syntax_Syntax.lbunivs =
                   (lb.FStarC_Syntax_Syntax.lbunivs);
                 FStarC_Syntax_Syntax.lbtyp = uu___1;
                 FStarC_Syntax_Syntax.lbeff = (lb.FStarC_Syntax_Syntax.lbeff);
                 FStarC_Syntax_Syntax.lbdef = uu___2;
                 FStarC_Syntax_Syntax.lbattrs =
                   (lb.FStarC_Syntax_Syntax.lbattrs);
                 FStarC_Syntax_Syntax.lbpos = (lb.FStarC_Syntax_Syntax.lbpos)
               }) (FStar_Pervasives_Native.snd lbs) in
        ((FStar_Pervasives_Native.fst lbs), uu___) in
      let uu___ =
        let uu___1 =
          let uu___2 = inst s t2 in
          {
            FStarC_Syntax_Syntax.lbs = lbs1;
            FStarC_Syntax_Syntax.body1 = uu___2
          } in
        FStarC_Syntax_Syntax.Tm_let uu___1 in
      mk1 uu___
  | FStarC_Syntax_Syntax.Tm_meta
      { FStarC_Syntax_Syntax.tm2 = t2;
        FStarC_Syntax_Syntax.meta = FStarC_Syntax_Syntax.Meta_pattern
          (bvs, args);_}
      ->
      let uu___ =
        let uu___1 =
          let uu___2 = inst s t2 in
          let uu___3 =
            let uu___4 =
              let uu___5 = FStarC_List.map (inst_args s) args in
              (bvs, uu___5) in
            FStarC_Syntax_Syntax.Meta_pattern uu___4 in
          {
            FStarC_Syntax_Syntax.tm2 = uu___2;
            FStarC_Syntax_Syntax.meta = uu___3
          } in
        FStarC_Syntax_Syntax.Tm_meta uu___1 in
      mk1 uu___
  | FStarC_Syntax_Syntax.Tm_meta
      { FStarC_Syntax_Syntax.tm2 = t2;
        FStarC_Syntax_Syntax.meta = FStarC_Syntax_Syntax.Meta_monadic (m, t');_}
      ->
      let uu___ =
        let uu___1 =
          let uu___2 = inst s t2 in
          let uu___3 =
            let uu___4 = let uu___5 = inst s t' in (m, uu___5) in
            FStarC_Syntax_Syntax.Meta_monadic uu___4 in
          {
            FStarC_Syntax_Syntax.tm2 = uu___2;
            FStarC_Syntax_Syntax.meta = uu___3
          } in
        FStarC_Syntax_Syntax.Tm_meta uu___1 in
      mk1 uu___
  | FStarC_Syntax_Syntax.Tm_meta
      { FStarC_Syntax_Syntax.tm2 = t2; FStarC_Syntax_Syntax.meta = tag;_} ->
      let uu___ =
        let uu___1 =
          let uu___2 = inst s t2 in
          {
            FStarC_Syntax_Syntax.tm2 = uu___2;
            FStarC_Syntax_Syntax.meta = tag
          } in
        FStarC_Syntax_Syntax.Tm_meta uu___1 in
      mk1 uu___
and inst_binder
  (s :
    FStarC_Syntax_Syntax.term ->
      FStarC_Syntax_Syntax.fv -> FStarC_Syntax_Syntax.term)
  (b : FStarC_Syntax_Syntax.binder) : FStarC_Syntax_Syntax.binder=
  let uu___ =
    let uu___1 = b.FStarC_Syntax_Syntax.binder_bv in
    let uu___2 =
      inst s (b.FStarC_Syntax_Syntax.binder_bv).FStarC_Syntax_Syntax.sort in
    {
      FStarC_Syntax_Syntax.ppname = (uu___1.FStarC_Syntax_Syntax.ppname);
      FStarC_Syntax_Syntax.index = (uu___1.FStarC_Syntax_Syntax.index);
      FStarC_Syntax_Syntax.sort = uu___2
    } in
  let uu___1 = FStarC_List.map (inst s) b.FStarC_Syntax_Syntax.binder_attrs in
  {
    FStarC_Syntax_Syntax.binder_bv = uu___;
    FStarC_Syntax_Syntax.binder_qual = (b.FStarC_Syntax_Syntax.binder_qual);
    FStarC_Syntax_Syntax.binder_positivity =
      (b.FStarC_Syntax_Syntax.binder_positivity);
    FStarC_Syntax_Syntax.binder_attrs = uu___1
  }
and inst_binders
  (s :
    FStarC_Syntax_Syntax.term ->
      FStarC_Syntax_Syntax.fv -> FStarC_Syntax_Syntax.term)
  (bs : FStarC_Syntax_Syntax.binders) : FStarC_Syntax_Syntax.binders=
  FStarC_List.map (inst_binder s) bs
and inst_args
  (s :
    FStarC_Syntax_Syntax.term ->
      FStarC_Syntax_Syntax.fv -> FStarC_Syntax_Syntax.term)
  (args :
    (FStarC_Syntax_Syntax.term' FStarC_Syntax_Syntax.syntax *
      FStarC_Syntax_Syntax.arg_qualifier FStar_Pervasives_Native.option)
      Prims.list)
  :
  (FStarC_Syntax_Syntax.term' FStarC_Syntax_Syntax.syntax *
    FStarC_Syntax_Syntax.arg_qualifier FStar_Pervasives_Native.option)
    Prims.list=
  FStarC_List.map
    (fun uu___ ->
       match uu___ with | (a, imp) -> let uu___1 = inst s a in (uu___1, imp))
    args
and inst_comp
  (s :
    FStarC_Syntax_Syntax.term ->
      FStarC_Syntax_Syntax.fv -> FStarC_Syntax_Syntax.term)
  (c : FStarC_Syntax_Syntax.comp' FStarC_Syntax_Syntax.syntax) :
  FStarC_Syntax_Syntax.comp' FStarC_Syntax_Syntax.syntax=
  match c.FStarC_Syntax_Syntax.n with
  | FStarC_Syntax_Syntax.Total t ->
      let uu___ = inst s t in FStarC_Syntax_Syntax.mk_Total uu___
  | FStarC_Syntax_Syntax.GTotal t ->
      let uu___ = inst s t in FStarC_Syntax_Syntax.mk_GTotal uu___
  | FStarC_Syntax_Syntax.Comp ct ->
      let ct1 =
        let uu___ = inst s ct.FStarC_Syntax_Syntax.result_typ in
        let uu___1 = inst_args s ct.FStarC_Syntax_Syntax.effect_args in
        let uu___2 =
          FStarC_List.map
            (fun uu___3 ->
               match uu___3 with
               | FStarC_Syntax_Syntax.DECREASES dec_order ->
                   let uu___4 = inst_decreases_order s dec_order in
                   FStarC_Syntax_Syntax.DECREASES uu___4
               | f -> f) ct.FStarC_Syntax_Syntax.flags in
        {
          FStarC_Syntax_Syntax.comp_univs =
            (ct.FStarC_Syntax_Syntax.comp_univs);
          FStarC_Syntax_Syntax.effect_name =
            (ct.FStarC_Syntax_Syntax.effect_name);
          FStarC_Syntax_Syntax.result_typ = uu___;
          FStarC_Syntax_Syntax.effect_args = uu___1;
          FStarC_Syntax_Syntax.flags = uu___2
        } in
      FStarC_Syntax_Syntax.mk_Comp ct1
and inst_decreases_order
  (s :
    FStarC_Syntax_Syntax.term ->
      FStarC_Syntax_Syntax.fv -> FStarC_Syntax_Syntax.term)
  (uu___ : FStarC_Syntax_Syntax.decreases_order) :
  FStarC_Syntax_Syntax.decreases_order=
  match uu___ with
  | FStarC_Syntax_Syntax.Decreases_lex l ->
      let uu___1 = FStarC_List.map (inst s) l in
      FStarC_Syntax_Syntax.Decreases_lex uu___1
  | FStarC_Syntax_Syntax.Decreases_wf (rel, e) ->
      let uu___1 =
        let uu___2 = inst s rel in let uu___3 = inst s e in (uu___2, uu___3) in
      FStarC_Syntax_Syntax.Decreases_wf uu___1
and inst_lcomp_opt
  (s :
    FStarC_Syntax_Syntax.term ->
      FStarC_Syntax_Syntax.fv -> FStarC_Syntax_Syntax.term)
  (l : FStarC_Syntax_Syntax.residual_comp FStar_Pervasives_Native.option) :
  FStarC_Syntax_Syntax.residual_comp FStar_Pervasives_Native.option=
  match l with
  | FStar_Pervasives_Native.None -> FStar_Pervasives_Native.None
  | FStar_Pervasives_Native.Some rc ->
      let uu___ =
        let uu___1 =
          FStarC_Option.map (inst s) rc.FStarC_Syntax_Syntax.residual_typ in
        {
          FStarC_Syntax_Syntax.residual_effect =
            (rc.FStarC_Syntax_Syntax.residual_effect);
          FStarC_Syntax_Syntax.residual_typ = uu___1;
          FStarC_Syntax_Syntax.residual_flags =
            (rc.FStarC_Syntax_Syntax.residual_flags)
        } in
      FStar_Pervasives_Native.Some uu___
and inst_ascription
  (s :
    FStarC_Syntax_Syntax.term ->
      FStarC_Syntax_Syntax.fv -> FStarC_Syntax_Syntax.term)
  (asc : FStarC_Syntax_Syntax.ascription) :
  ((FStarC_Syntax_Syntax.term' FStarC_Syntax_Syntax.syntax,
    FStarC_Syntax_Syntax.comp' FStarC_Syntax_Syntax.syntax)
    FStar_Pervasives.either * FStarC_Syntax_Syntax.term'
    FStarC_Syntax_Syntax.syntax FStar_Pervasives_Native.option * Prims.bool)=
  let uu___ = asc in
  match uu___ with
  | (annot, topt, use_eq) ->
      let annot1 =
        match annot with
        | FStar_Pervasives.Inl t ->
            let uu___1 = inst s t in FStar_Pervasives.Inl uu___1
        | FStar_Pervasives.Inr c ->
            let uu___1 = inst_comp s c in FStar_Pervasives.Inr uu___1 in
      let topt1 = FStarC_Option.map (inst s) topt in (annot1, topt1, use_eq)
let instantiate (i : inst_t) (t : FStarC_Syntax_Syntax.term) :
  FStarC_Syntax_Syntax.term=
  match i with
  | [] -> t
  | uu___ ->
      let inst_fv t1 fv =
        let uu___1 =
          FStarC_Option.find
            (fun uu___2 ->
               match uu___2 with
               | (x, uu___3) ->
                   FStarC_Ident.lid_equals x fv.FStarC_Syntax_Syntax.fv_name)
            i in
        match uu___1 with
        | FStar_Pervasives_Native.None -> t1
        | FStar_Pervasives_Native.Some (uu___2, us) ->
            mk t1 (FStarC_Syntax_Syntax.Tm_uinst (t1, us)) in
      inst inst_fv t
