(**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *)

open Reason

val find_constraints:
  Context.t ->
  Constraint.ident ->
  Constraint.ident * Constraint.constraints
val find_graph: Context.t -> Constraint.ident -> Constraint.constraints

(* propagates sources to sinks following a subtype relation *)
val flow: Context.t -> (Type.t * Type.use_t) -> unit
val flow_t: Context.t -> (Type.t * Type.t) -> unit

(* given a use type, return a tvar constrained by the use type *)
val tvar_with_constraint: Context.t -> ?trace:Trace.t -> ?derivable:bool -> Type.use_t -> Type.t

val unify: Context.t -> Type.t -> Type.t -> unit

val reposition: Context.t -> ?trace:Trace.t -> Loc.t -> ?desc:reason_desc -> Type.t -> Type.t

(* constraint utils *)
val filter_optional: Context.t -> ?trace:Trace.t -> reason -> Type.t -> Type.t

module Cache: sig
  val clear: unit -> unit
  val stats_poly_instantiation: unit -> Hashtbl.statistics
  val summarize_flow_constraint: unit -> (string * int) list
end

val mk_tvar: Context.t -> reason -> Type.t
val mk_tvar_where: Context.t -> reason -> (Type.t -> unit) -> Type.t
val mk_tvar_derivable_where: Context.t -> reason -> (Type.t -> unit) -> Type.t

val get_builtin_typeapp: Context.t -> ?trace:Trace.t -> reason -> string -> Type.t list -> Type.t

val resolve_spread_list:
  Context.t ->
  use_op:Type.use_op ->
  reason_op:Reason.t ->
  Type.unresolved_param list ->
  Type.spread_resolve ->
  unit

(* polymorphism *)

val subst: Context.t -> ?force:bool -> (Type.t SMap.t) -> Type.t -> Type.t
val generate_tests: Context.t -> reason -> Type.typeparam list -> (Type.t SMap.t -> unit)
  -> unit
val match_this_binding: Type.t SMap.t -> (Type.t -> bool) -> bool

val check_polarity:
  Context.t -> ?trace:Trace.t -> Type.polarity -> Type.t -> unit

(* selectors *)

val visit_eval_id : Context.t -> int -> (Type.t -> unit) -> unit

(* object/method types *)

val mk_methodtype :
  Type.t -> Type.t list ->
  rest_param:(string option * Loc.t * Type.t) option -> def_reason: Reason.t ->
  ?frame:int -> ?params_names:string list -> ?is_predicate:bool ->
  Type.t -> Type.funtype

val mk_methodcalltype :
  Type.t -> Type.call_arg list ->
  ?frame:int ->
  ?call_strict_arity:bool ->
  Type.t -> Type.funcalltype

val mk_boundfunctiontype :
  Type.t list ->
  rest_param:(string option * Loc.t * Type.t) option -> def_reason: Reason.t ->
  ?frame:int -> ?params_names:string list -> ?is_predicate:bool ->
  Type.t -> Type.funtype

val mk_functiontype :
  reason ->
  Type.t list ->
  rest_param:(string option * Loc.t * Type.t) option -> def_reason: Reason.t ->
  ?frame:int -> ?params_names:string list -> ?is_predicate:bool ->
  Type.t -> Type.funtype

val mk_functioncalltype :
  reason ->
  Type.call_arg list ->
  ?frame:int ->
  ?call_strict_arity:bool ->
  Type.t -> Type.funcalltype

val dummy_this : Type.t
val dummy_static : reason -> Type.t
val dummy_prototype : Type.t

val mk_objecttype : ?flags:Type.flags ->
  Type.dicttype option -> Type.Properties.id -> Type.t -> Type.objtype

val mk_object_with_proto : Context.t -> reason ->
  ?dict:Type.dicttype ->
  Type.t -> Type.t

val mk_object_with_map_proto : Context.t -> reason ->
  ?sealed:bool -> ?exact:bool -> ?frozen:bool ->
  ?dict:Type.dicttype -> Type.Properties.t -> Type.t -> Type.t

val mk_object: Context.t -> reason -> Type.t

(* ... *)

val mk_nominal: Context.t -> int

val mk_default: Context.t -> reason ->
  expr:(Context.t -> 'a -> Type.t) ->
  'a Default.t -> Type.t

(* val graph: bounds IMap.t ref *)
val lookup_module: Context.t -> string -> Type.t

(* contexts *)
val fresh_context: Context.metadata -> File_key.t -> string -> Context.t
val add_output: Context.t -> ?trace:Trace.t -> Flow_error.error_message -> unit

(* builtins *)

val builtins: Context.t -> Type.t
val get_builtin: Context.t -> ?trace:Trace.t -> string -> reason -> Type.t
val lookup_builtin: Context.t -> ?trace:Trace.t -> string -> reason -> Type.lookup_kind -> Type.t -> unit
val get_builtin_type: Context.t -> ?trace:Trace.t -> reason -> ?use_desc:bool -> string -> Type.t
val resolve_builtin_class: Context.t -> ?trace:Trace.t -> Type.t -> Type.t
val set_builtin: Context.t -> ?trace:Trace.t -> string -> Type.t -> unit

val mk_instance: Context.t -> ?trace:Trace.t -> reason -> ?for_type:bool -> ?use_desc:bool -> Type.t -> Type.t
val mk_typeof_annotation: Context.t -> ?trace:Trace.t -> reason -> ?use_desc:bool -> Type.t -> Type.t

(* strict *)
val enforce_strict: Context.t -> Constraint.ident -> string list -> unit
val merge_type: Context.t -> (Type.t * Type.t) -> Type.t
val resolve_type: Context.t -> Type.t -> Type.t
val possible_types: Context.t -> Constraint.ident -> Type.t list
val possible_types_of_type: Context.t -> Type.t -> Type.t list
val possible_uses: Context.t -> Constraint.ident -> Type.use_t list

module Members : sig
  type t =
    | Success of Type.t SMap.t
    | SuccessModule of Type.t SMap.t * (Type.t option)
    | FailureMaybeType
    | FailureAnyType
    | FailureUnhandledType of Type.t

  val to_command_result: t -> (Type.t SMap.t, string) result

  val extract: Context.t -> Type.t -> t
end
