From 2d4e387532d1c1bd6cd7f6d6849bdd523322c7b9 Mon Sep 17 00:00:00 2001 From: Andrew Kennedy Date: Tue, 3 Mar 2020 07:55:13 -0800 Subject: [PATCH] First stab at hh_check Summary: First code in Rust for type inference. Simple wrapper `hh_check` that is just cut-and-paste from `hh_compile`, with oxidized version of `Typing_env.env` and dependencies. A little bit of `Reason` code and subset of `Typing_make_type`. Reviewed By: dabek Differential Revision: D20034453 fbshipit-source-id: 093210fdfca4cb3191e572924d6f15dbd0108f8f --- hphp/hack/src/cargo/hh_check/Cargo.toml | 24 ++++ hphp/hack/src/hh_check.rs | 129 +++++++++++++++++ hphp/hack/src/hh_oxidize/convert_type_decl.ml | 4 + hphp/hack/src/oxidized/gen/decl_defs.rs | 20 ++- hphp/hack/src/oxidized/gen/mod.rs | 11 +- hphp/hack/src/oxidized/gen/type_parameter_env.rs | 59 ++++++++ hphp/hack/src/oxidized/gen/typing_cont_key.rs | 40 ++++++ hphp/hack/src/oxidized/gen/typing_env_types.rs | 78 +++++++++++ hphp/hack/src/oxidized/gen/typing_fake_members.rs | 54 ++++++++ hphp/hack/src/oxidized/gen/typing_inference_env.rs | 153 +++++++++++++++++++++ hphp/hack/src/oxidized/gen/typing_local_types.rs | 36 +++++ .../hack/src/oxidized/gen/typing_mutability_env.rs | 54 ++++++++ hphp/hack/src/oxidized/gen/typing_per_cont_env.rs | 39 ++++++ .../src/oxidized/gen/typing_tyvar_occurrences.rs | 54 ++++++++ hphp/hack/src/oxidized/lib.rs | 17 +++ hphp/hack/src/oxidized/manual/decl_env.rs | 2 + .../manual/{local_id.rs => internal_type_set.rs} | 10 +- hphp/hack/src/oxidized/manual/local_id.rs | 8 ++ hphp/hack/src/oxidized/manual/mod.rs | 8 ++ hphp/hack/src/oxidized/manual/ty_impl.rs | 22 +++ .../{local_id.rs => typing_continuations.rs} | 11 +- .../src/oxidized/manual/typing_env_return_info.rs | 31 +++++ hphp/hack/src/oxidized/manual/typing_logic.rs | 36 +++++ .../hack/src/oxidized/manual/typing_reason_impl.rs | 112 +++++++++++++++ .../oxidized/manual/{local_id.rs => typing_set.rs} | 10 +- hphp/hack/src/oxidized/regen.sh | 9 ++ hphp/hack/src/typing/cargo/compile/Cargo.toml | 22 +++ .../typing_check_service_rust.rs} | 13 +- hphp/hack/src/typing/typing_check_utils.rs | 111 +++++++++++++++ hphp/hack/src/typing/typing_env.rs | 34 +++++ hphp/hack/src/typing/typing_env_types.ml | 3 +- hphp/hack/src/typing/typing_fake_members.ml | 31 +++-- hphp/hack/src/typing/typing_inference_env.ml | 2 +- hphp/hack/src/typing/typing_make_type.rs | 78 +++++++++++ hphp/hack/src/typing/typing_mutability_env.ml | 2 +- hphp/hack/src/typing/typing_per_cont_env.ml | 12 +- 36 files changed, 1279 insertions(+), 60 deletions(-) create mode 100644 hphp/hack/src/cargo/hh_check/Cargo.toml create mode 100644 hphp/hack/src/hh_check.rs create mode 100644 hphp/hack/src/oxidized/gen/type_parameter_env.rs create mode 100644 hphp/hack/src/oxidized/gen/typing_cont_key.rs create mode 100644 hphp/hack/src/oxidized/gen/typing_env_types.rs create mode 100644 hphp/hack/src/oxidized/gen/typing_fake_members.rs create mode 100644 hphp/hack/src/oxidized/gen/typing_inference_env.rs create mode 100644 hphp/hack/src/oxidized/gen/typing_local_types.rs create mode 100644 hphp/hack/src/oxidized/gen/typing_mutability_env.rs create mode 100644 hphp/hack/src/oxidized/gen/typing_per_cont_env.rs create mode 100644 hphp/hack/src/oxidized/gen/typing_tyvar_occurrences.rs create mode 100644 hphp/hack/src/oxidized/manual/decl_env.rs copy hphp/hack/src/oxidized/manual/{local_id.rs => internal_type_set.rs} (53%) create mode 100644 hphp/hack/src/oxidized/manual/ty_impl.rs copy hphp/hack/src/oxidized/manual/{local_id.rs => typing_continuations.rs} (53%) create mode 100644 hphp/hack/src/oxidized/manual/typing_env_return_info.rs create mode 100644 hphp/hack/src/oxidized/manual/typing_logic.rs create mode 100644 hphp/hack/src/oxidized/manual/typing_reason_impl.rs copy hphp/hack/src/oxidized/manual/{local_id.rs => typing_set.rs} (53%) create mode 100644 hphp/hack/src/typing/cargo/compile/Cargo.toml copy hphp/hack/src/{oxidized/manual/local_id.rs => typing/typing_check_service_rust.rs} (52%) create mode 100644 hphp/hack/src/typing/typing_check_utils.rs create mode 100644 hphp/hack/src/typing/typing_env.rs create mode 100644 hphp/hack/src/typing/typing_make_type.rs diff --git a/hphp/hack/src/cargo/hh_check/Cargo.toml b/hphp/hack/src/cargo/hh_check/Cargo.toml new file mode 100644 index 00000000000..97874b1c836 --- /dev/null +++ b/hphp/hack/src/cargo/hh_check/Cargo.toml @@ -0,0 +1,24 @@ +# @generated +# @autocargo from //hphp/hack/src:hh_check +# Signature +[package] +name = "hh_check" +edition = "2018" +version = "0.0.0" +include = ["../../hh_check.rs"] + +[[bin]] +name = "hh_check" +path = "../../hh_check.rs" + +[dependencies] +multifile_rust = { path = "../../utils/multifile" } +options = { path = "../../hhbc/cargo/options" } +oxidized = { path = "../../oxidized" } +stack_limit = { path = "../../utils/stack_limit" } +typing_check_service_rust = { path = "../../typing/cargo/compile" } +anyhow = "1.0" +atty = "0.2" +itertools = "0.8" +structopt = "0.3.7" +# @end of Signature diff --git a/hphp/hack/src/hh_check.rs b/hphp/hack/src/hh_check.rs new file mode 100644 index 00000000000..5e20948ba74 --- /dev/null +++ b/hphp/hack/src/hh_check.rs @@ -0,0 +1,129 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. + +use ::anyhow::{self, anyhow, Context}; + +use structopt::StructOpt; +use typing_check_service_rust::{ + typing_check_utils::from_text, typing_check_utils::*, typing_env::empty_global_env, + typing_make_type, +}; + +use oxidized::relative_path::{self, RelativePath}; +use stack_limit::{StackLimit, KI, MI}; + +use std::{ + fs::File, + io::Read, + path::{Path, PathBuf}, + sync::Arc, +}; + +// don't consult CARGO_PKG_VERSION (Buck doesn't set it) +#[structopt(no_version)] +#[derive(StructOpt, Clone, Debug)] +// Right now, hh_check accepts only a filename and a verbosity flag +struct Opts { + /// The level of verbosity (can be set multiple times) + #[structopt(long = "verbose", parse(from_occurrences))] + verbosity: isize, + + /// The path to an input Hack file + #[structopt(name = "FILENAME")] + filename: PathBuf, +} + +fn read_file(filepath: &Path) -> anyhow::Result> { + let mut text: Vec = Vec::new(); + File::open(filepath) + .with_context(|| format!("cannot open input file: {}", filepath.display()))? + .read_to_end(&mut text)?; + Ok(text) +} + +fn process_single_file_impl( + opts: &Opts, + filepath: &Path, + content: &[u8], + stack_limit: &StackLimit, +) -> anyhow::Result { + if opts.verbosity > 1 { + eprintln!("processing file: {}", filepath.display()); + } + let rel_path = RelativePath::make(relative_path::Prefix::Dummy, filepath.to_owned()); + let builder = typing_make_type::TypeBuilder::new(); + let env = empty_global_env(&builder, rel_path); + let profile = from_text(env, stack_limit, content)?; + Ok(profile) +} + +fn process_single_file_with_retry( + opts: &Opts, + filepath: PathBuf, + content: Vec, +) -> anyhow::Result { + let ctx = &Arc::new((opts.clone(), filepath, content)); + let job_builder = move || { + let new_ctx = Arc::clone(ctx); + Box::new( + move |stack_limit: &StackLimit, _nonmain_stack_size: Option| { + let (opts, filepath, content) = new_ctx.as_ref(); + process_single_file_impl(opts, filepath, content.as_slice(), stack_limit) + }, + ) + }; + + // Assume peak is 2.5x of stack. + // This is initial estimation, need to be improved later. + let stack_slack = |stack_size| stack_size * 6 / 10; + + let on_retry = &mut |stack_size_tried: usize| { + // Not always printing warning here because this would fail some HHVM tests + if atty::is(atty::Stream::Stderr) || std::env::var_os("HH_TEST_MODE").is_some() { + eprintln!( + "[hrust] warning: hh_check exceeded stack of {} KiB on: {}", + (stack_size_tried - stack_slack(stack_size_tried)) / KI, + ctx.as_ref().1.display(), + ); + } + }; + + let job = stack_limit::retry::Job { + nonmain_stack_min: 13 * MI, + nonmain_stack_max: None, + ..Default::default() + }; + job.with_elastic_stack(&job_builder, on_retry, stack_slack)? +} + +// Parse and typecheck a single file, given the command-line options and the file's contents +fn process_single_file( + opts: &Opts, + filepath: PathBuf, + content: Vec, +) -> anyhow::Result { + match std::panic::catch_unwind(|| process_single_file_with_retry(opts, filepath, content)) { + Ok(r) => r, + Err(panic) => match panic.downcast::() { + Ok(msg) => Err(anyhow!("panic: {}", msg)), + Err(_) => Err(anyhow!("panic: unknown")), + }, + } +} + +fn main() -> anyhow::Result<()> { + // Parse command-line options + let opts = Opts::from_args(); + if opts.verbosity > 1 { + eprintln!("hh_check options/flags: {:#?}", opts); + } + let filename = opts.filename.clone(); + let content = read_file(&filename)?; + let r = process_single_file(&opts, filename, content); + if let Err(e) = r { + eprintln!("Error in file: {}", e); + } + Ok(()) +} diff --git a/hphp/hack/src/hh_oxidize/convert_type_decl.ml b/hphp/hack/src/hh_oxidize/convert_type_decl.ml index 965f69deb52..ef5056a9916 100644 --- a/hphp/hack/src/hh_oxidize/convert_type_decl.ml +++ b/hphp/hack/src/hh_oxidize/convert_type_decl.ml @@ -39,6 +39,10 @@ let derive_blacklists = (* GlobalOptions contains a couple floats, which only implement PartialEq and PartialOrd, and do not implement Hash. *) ("global_options::GlobalOptions", ["Eq"; "Hash"; "Ord"]); + (* And GlobalOptions is used in Genv which is used in Env. We + * don't care about comparison or hashing on environments *) + ("typing_env_types::Env", ["Eq"; "Hash"; "Ord"]); + ("typing_env_types::Genv", ["Eq"; "Hash"; "Ord"]); ] |> List.fold ~init:SMap.empty ~f:(fun map (ty, bl) -> SMap.add ty bl map) diff --git a/hphp/hack/src/oxidized/gen/decl_defs.rs b/hphp/hack/src/oxidized/gen/decl_defs.rs index 3a3650af198..d8dc60a460c 100644 --- a/hphp/hack/src/oxidized/gen/decl_defs.rs +++ b/hphp/hack/src/oxidized/gen/decl_defs.rs @@ -3,7 +3,7 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the "hack" directory of this source tree. // -// @generated SignedSource<> +// @generated SignedSource<<473231a8b0eeb807b76cdb7a14266468>> // // To regenerate this file, run: // hphp/hack/src/oxidized/regen.sh @@ -168,6 +168,24 @@ pub struct MroElement { pub passthrough_abstract_typeconst: bool, } +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub enum LinearizationKind { + MemberResolution, + AncestorTypes, +} + /// name of condition type for conditional reactivity of methods. /// If None - method is unconditionally reactive pub type ConditionTypeName = Option; diff --git a/hphp/hack/src/oxidized/gen/mod.rs b/hphp/hack/src/oxidized/gen/mod.rs index 4693581aba8..39384c1f7a2 100644 --- a/hphp/hack/src/oxidized/gen/mod.rs +++ b/hphp/hack/src/oxidized/gen/mod.rs @@ -3,7 +3,7 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the "hack" directory of this source tree. // -// @generated SignedSource<<603d0db6b2a270ae9c1b05efa2f09abc>> +// @generated SignedSource<> // // To regenerate this file, run: // hphp/hack/src/oxidized/regen.sh @@ -26,7 +26,16 @@ pub mod parser_options; pub mod prim_defs; pub mod scoured_comments; pub mod shallow_decl_defs; +pub mod type_parameter_env; pub mod typechecker_options; +pub mod typing_cont_key; pub mod typing_defs; pub mod typing_defs_core; +pub mod typing_env_types; +pub mod typing_fake_members; +pub mod typing_inference_env; +pub mod typing_local_types; +pub mod typing_mutability_env; +pub mod typing_per_cont_env; pub mod typing_reason; +pub mod typing_tyvar_occurrences; diff --git a/hphp/hack/src/oxidized/gen/type_parameter_env.rs b/hphp/hack/src/oxidized/gen/type_parameter_env.rs new file mode 100644 index 00000000000..798024f8c32 --- /dev/null +++ b/hphp/hack/src/oxidized/gen/type_parameter_env.rs @@ -0,0 +1,59 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +// +// @generated SignedSource<<22c542a71957f4f17d64a32f8b8fec42>> +// +// To regenerate this file, run: +// hphp/hack/src/oxidized/regen.sh + +use ocamlrep_derive::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +#[allow(unused_imports)] +use crate::*; + +pub use typing_defs::*; + +pub use crate::typing_set as ty_set; + +pub type TparamBounds = ty_set::TySet; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct TparamInfo { + pub lower_bounds: TparamBounds, + pub upper_bounds: TparamBounds, + pub reified: aast::ReifyKind, + pub enforceable: bool, + pub newable: bool, +} + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct TypeParameterEnv { + pub tparams: s_map::SMap, + pub consistent: bool, +} diff --git a/hphp/hack/src/oxidized/gen/typing_cont_key.rs b/hphp/hack/src/oxidized/gen/typing_cont_key.rs new file mode 100644 index 00000000000..3a9e7c9ad8e --- /dev/null +++ b/hphp/hack/src/oxidized/gen/typing_cont_key.rs @@ -0,0 +1,40 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +// +// @generated SignedSource<<41906dd4aae61a74bae4b5e5e07d9615>> +// +// To regenerate this file, run: +// hphp/hack/src/oxidized/regen.sh + +use ocamlrep_derive::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +#[allow(unused_imports)] +use crate::*; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub enum TypingContKey { + Next, + Continue, + Break, + Catch, + Do, + Exit, + Fallthrough, + Finally, + Goto(String), +} diff --git a/hphp/hack/src/oxidized/gen/typing_env_types.rs b/hphp/hack/src/oxidized/gen/typing_env_types.rs new file mode 100644 index 00000000000..f395b1ff5c2 --- /dev/null +++ b/hphp/hack/src/oxidized/gen/typing_env_types.rs @@ -0,0 +1,78 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +// +// @generated SignedSource<> +// +// To regenerate this file, run: +// hphp/hack/src/oxidized/regen.sh + +use ocamlrep_derive::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +#[allow(unused_imports)] +use crate::*; + +pub use typing_defs::*; + +pub use crate::internal_type_set as i_ty_set; + +pub type LoclTy = typing_defs::Ty; + +pub type LocalIdSetT = local_id::set::Set; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct LocalEnv { + pub per_cont_env: typing_per_cont_env::TypingPerContEnv, + pub local_mutability: typing_mutability_env::MutabilityEnv, + pub local_reactive: Reactivity, + pub local_using_vars: LocalIdSetT, +} + +#[derive(Clone, Debug, Deserialize, OcamlRep, PartialEq, PartialOrd, Serialize)] +pub struct Env { + pub function_pos: pos::Pos, + pub fresh_typarams: s_set::SSet, + pub lenv: LocalEnv, + pub genv: Genv, + pub decl_env: decl_env::Env, + pub in_loop: bool, + pub in_try: bool, + pub in_case: bool, + pub inside_constructor: bool, + pub inside_ppl_class: bool, + pub global_tpenv: type_parameter_env::TypeParameterEnv, + pub log_levels: s_map::SMap, + pub inference_env: typing_inference_env::TypingInferenceEnv, + pub allow_wildcards: bool, + pub big_envs: std::cell::RefCell)>>, + pub pessimize: bool, +} + +#[derive(Clone, Debug, Deserialize, OcamlRep, PartialEq, PartialOrd, Serialize)] +pub struct Genv { + pub tcopt: typechecker_options::TypecheckerOptions, + pub return_: typing_env_return_info::TypingEnvReturnInfo, + pub params: local_id::map::Map<(Ty, ParamMode)>, + pub condition_types: s_map::SMap, + pub parent: Option<(String, Ty)>, + pub self_: Option<(String, Ty)>, + pub static_: bool, + pub fun_kind: ast_defs::FunKind, + pub val_kind: typing_defs::ValKind, + pub fun_mutable: Option, + pub file: relative_path::RelativePath, +} diff --git a/hphp/hack/src/oxidized/gen/typing_fake_members.rs b/hphp/hack/src/oxidized/gen/typing_fake_members.rs new file mode 100644 index 00000000000..6ce4dde493a --- /dev/null +++ b/hphp/hack/src/oxidized/gen/typing_fake_members.rs @@ -0,0 +1,54 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +// +// @generated SignedSource<> +// +// To regenerate this file, run: +// hphp/hack/src/oxidized/regen.sh + +use ocamlrep_derive::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +#[allow(unused_imports)] +use crate::*; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub enum Blame { + BlameCall(pos::Pos), + BlameLambda(pos::Pos), +} + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub enum TypingFakeMembers { + Valid(local_id::set::Set), + Invalidated { + valid: local_id::set::Set, + invalid: local_id::set::Set, + blame: Blame, + }, +} diff --git a/hphp/hack/src/oxidized/gen/typing_inference_env.rs b/hphp/hack/src/oxidized/gen/typing_inference_env.rs new file mode 100644 index 00000000000..4c6c9dd8526 --- /dev/null +++ b/hphp/hack/src/oxidized/gen/typing_inference_env.rs @@ -0,0 +1,153 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +// +// @generated SignedSource<<25094f75f1963275999ffa0fb1a128f2>> +// +// To regenerate this file, run: +// hphp/hack/src/oxidized/regen.sh + +use ocamlrep_derive::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +#[allow(unused_imports)] +use crate::*; + +pub use typing_defs::*; + +pub use crate::internal_type_set as i_ty_set; +pub use crate::typing_logic as t_l; +pub use crate::typing_tyvar_occurrences as occ; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct TyvarConstraints { + /// Does this type variable appear covariantly in the type of the expression? + pub appears_covariantly: bool, + /// Does this type variable appear contravariantly in the type of the expression? + /// If it appears in an invariant position then both will be true; if it doesn't + /// appear at all then both will be false. + pub appears_contravariantly: bool, + pub lower_bounds: i_ty_set::ITySet, + pub upper_bounds: i_ty_set::ITySet, + /// Map associating a type to each type constant id of this variable. + /// Whenever we localize "T1::T" in a constraint, we add a fresh type variable + /// indexed by "T" in the type_constants of the type variable representing T1. + /// This allows to properly check constraints on "T1::T". + pub type_constants: s_map::SMap<(aast::Sid, Ty)>, + /// Map associating PU information to each instance of + /// C:@E:@#v:@T + /// when the type variable #v is not resolved yet. We introduce a new type + /// variable to 'postpone' the checking of this expression until the end, + /// when #v will be known. + pub pu_accesses: s_map::SMap<(Ty, aast::Sid, Ty, aast::Sid)>, +} + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub enum SolvingInfo { + /// when the type variable is bound to a type + TVIType(Ty), + /// when the type variable is still unsolved + TVIConstraints(TyvarConstraints), +} + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct TyvarInfo { + /// Where was the type variable introduced? (e.g. generic method invocation, + /// new object construction) + pub tyvar_pos: pos::Pos, + pub global_reason: Option, + pub eager_solve_failed: bool, + pub solving_info: SolvingInfo, +} + +pub type Tvenv = i_map::IMap; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct TypingInferenceEnv { + pub tvenv: Tvenv, + pub tyvars_stack: Vec<(pos::Pos, Vec)>, + pub subtype_prop: t_l::SubtypeProp, + pub tyvar_occurrences: typing_tyvar_occurrences::TypingTyvarOccurrences, + pub allow_solve_globals: bool, +} + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct GlobalTyvarInfo { + pub tyvar_reason: reason::Reason, + pub solving_info_g: SolvingInfo, +} + +pub type GlobalTvenv = i_map::IMap; + +pub type TGlobal = GlobalTvenv; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct TGlobalWithPos(pub pos::Pos, pub TGlobal); diff --git a/hphp/hack/src/oxidized/gen/typing_local_types.rs b/hphp/hack/src/oxidized/gen/typing_local_types.rs new file mode 100644 index 00000000000..621bd062997 --- /dev/null +++ b/hphp/hack/src/oxidized/gen/typing_local_types.rs @@ -0,0 +1,36 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +// +// @generated SignedSource<<73420f38f3ade95ec47971a805ae8866>> +// +// To regenerate this file, run: +// hphp/hack/src/oxidized/regen.sh + +use ocamlrep_derive::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +#[allow(unused_imports)] +use crate::*; + +pub use typing_defs::*; + +pub type ExpressionId = ident::Ident; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct Local(pub Ty, pub ExpressionId); + +pub type TypingLocalTypes = local_id::map::Map; diff --git a/hphp/hack/src/oxidized/gen/typing_mutability_env.rs b/hphp/hack/src/oxidized/gen/typing_mutability_env.rs new file mode 100644 index 00000000000..7c883ed5580 --- /dev/null +++ b/hphp/hack/src/oxidized/gen/typing_mutability_env.rs @@ -0,0 +1,54 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +// +// @generated SignedSource<> +// +// To regenerate this file, run: +// hphp/hack/src/oxidized/regen.sh + +use ocamlrep_derive::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +#[allow(unused_imports)] +use crate::*; + +pub use crate::local_id::map as l_map; + +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub enum MutType { + Mutable, + Borrowed, + MaybeMutable, + Immutable, +} + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct Mutability(pub pos::Pos, pub MutType); + +pub type MutabilityEnv = local_id::map::Map; diff --git a/hphp/hack/src/oxidized/gen/typing_per_cont_env.rs b/hphp/hack/src/oxidized/gen/typing_per_cont_env.rs new file mode 100644 index 00000000000..a4a8b72a364 --- /dev/null +++ b/hphp/hack/src/oxidized/gen/typing_per_cont_env.rs @@ -0,0 +1,39 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +// +// @generated SignedSource<<6cb37057fd8e2c33966ab6e42bcaa5ed>> +// +// To regenerate this file, run: +// hphp/hack/src/oxidized/regen.sh + +use ocamlrep_derive::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +#[allow(unused_imports)] +use crate::*; + +pub use crate::typing_continuations as c; +pub use c::map as c_map; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct PerContEntry { + pub local_types: typing_local_types::TypingLocalTypes, + pub fake_members: typing_fake_members::TypingFakeMembers, + pub tpenv: type_parameter_env::TypeParameterEnv, +} + +pub type TypingPerContEnv = typing_continuations::map::Map; diff --git a/hphp/hack/src/oxidized/gen/typing_tyvar_occurrences.rs b/hphp/hack/src/oxidized/gen/typing_tyvar_occurrences.rs new file mode 100644 index 00000000000..cd7b8607b6b --- /dev/null +++ b/hphp/hack/src/oxidized/gen/typing_tyvar_occurrences.rs @@ -0,0 +1,54 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +// +// @generated SignedSource<<64e289fae99e0629c85180b2593511fb>> +// +// To regenerate this file, run: +// hphp/hack/src/oxidized/regen.sh + +use ocamlrep_derive::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +#[allow(unused_imports)] +use crate::*; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct TypingTyvarOccurrences { + /// A map to track where each type variable occurs, + /// more precisely in the type of which other type variables. + /// E.g. if #1 is bound to (#2 | int), then this map contains the entry + /// #2 -> { #1 } + /// This is based on shallow binding, i.e. in the example above, if #2 + /// is mapped to #3, then tyvar_occurrences would be: + /// #2 -> { #1 } + /// #3 -> { #2 } + /// but we would not record that #3 occurs in #1. + /// When a type variable v gets solved or the type bound to it gets simplified, + /// we simplify the unions and intersections of the types bound to the + /// type variables associated to v in this map. + /// So in our example, if #2 gets solved to int, + /// we simplify #1 to (int | int) = int. + /// There are only entries for variables that are unsolved or contain + /// other unsolved type variables. Variables that are solved and contain + /// no other unsolved type variables get removed from this map. + pub yvar_occurrences: i_map::IMap, + /// Mapping of type variables to the type variables contained in their + /// types which are either unsolved or themselves contain unsolved type + /// variables. + /// This is the dual of tyvar_occurrences. + pub yvars_in_tyvar: i_map::IMap, +} diff --git a/hphp/hack/src/oxidized/lib.rs b/hphp/hack/src/oxidized/lib.rs index 8967b034b69..71e53bc89b1 100644 --- a/hphp/hack/src/oxidized/lib.rs +++ b/hphp/hack/src/oxidized/lib.rs @@ -9,6 +9,7 @@ pub use manual::aast_defs_impl; pub use manual::aast_impl; pub use manual::ast; pub use manual::ast_defs_impl; +pub use manual::decl_env; pub use manual::doc_comment; pub use manual::file_info_impl; pub use manual::file_pos_large; @@ -16,6 +17,7 @@ pub use manual::file_pos_small; pub use manual::global_options_impl; pub use manual::i_map; pub use manual::i_set; +pub use manual::internal_type_set; pub use manual::local_id; pub use manual::namespace_env_impl; pub use manual::phase_map; @@ -26,6 +28,12 @@ pub use manual::s_set; pub use manual::scoured_comments_impl; pub use manual::shape_map; pub use manual::tany_sentinel; +pub use manual::ty_impl; +pub use manual::typing_continuations; +pub use manual::typing_env_return_info; +pub use manual::typing_logic; +pub use manual::typing_reason_impl; +pub use manual::typing_set; mod stubs; @@ -57,7 +65,16 @@ pub use gen::parser_options; pub use gen::prim_defs; pub use gen::scoured_comments; pub use gen::shallow_decl_defs; +pub use gen::type_parameter_env; pub use gen::typechecker_options; +pub use gen::typing_cont_key; pub use gen::typing_defs; pub use gen::typing_defs_core; +pub use gen::typing_env_types; +pub use gen::typing_fake_members; +pub use gen::typing_inference_env; +pub use gen::typing_local_types; +pub use gen::typing_mutability_env; +pub use gen::typing_per_cont_env; pub use gen::typing_reason; +pub use gen::typing_tyvar_occurrences; diff --git a/hphp/hack/src/oxidized/manual/decl_env.rs b/hphp/hack/src/oxidized/manual/decl_env.rs new file mode 100644 index 00000000000..41d51faa7d6 --- /dev/null +++ b/hphp/hack/src/oxidized/manual/decl_env.rs @@ -0,0 +1,2 @@ +// Temporary stub type +pub type Env = (); diff --git a/hphp/hack/src/oxidized/manual/local_id.rs b/hphp/hack/src/oxidized/manual/internal_type_set.rs similarity index 53% copy from hphp/hack/src/oxidized/manual/local_id.rs copy to hphp/hack/src/oxidized/manual/internal_type_set.rs index f8197321ec7..ee5c149fcc8 100644 --- a/hphp/hack/src/oxidized/manual/local_id.rs +++ b/hphp/hack/src/oxidized/manual/internal_type_set.rs @@ -3,12 +3,6 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the "hack" directory of this source tree. -pub type LocalId = (isize, String); +use crate::typing_defs::*; -pub fn make_unscoped(name: String) -> LocalId { - (0, name) -} - -pub fn get_name((_, name): &LocalId) -> &String { - name -} +pub type ITySet = std::collections::BTreeSet; diff --git a/hphp/hack/src/oxidized/manual/local_id.rs b/hphp/hack/src/oxidized/manual/local_id.rs index f8197321ec7..d7c49f85acd 100644 --- a/hphp/hack/src/oxidized/manual/local_id.rs +++ b/hphp/hack/src/oxidized/manual/local_id.rs @@ -9,6 +9,14 @@ pub fn make_unscoped(name: String) -> LocalId { (0, name) } +pub mod map { + pub type Map = std::collections::BTreeMap; +} + +pub mod set { + pub type Set = std::collections::BTreeSet; +} + pub fn get_name((_, name): &LocalId) -> &String { name } diff --git a/hphp/hack/src/oxidized/manual/mod.rs b/hphp/hack/src/oxidized/manual/mod.rs index 7bacf9e7472..a06078230d0 100644 --- a/hphp/hack/src/oxidized/manual/mod.rs +++ b/hphp/hack/src/oxidized/manual/mod.rs @@ -7,6 +7,7 @@ pub mod aast_defs_impl; pub mod aast_impl; pub mod ast; pub mod ast_defs_impl; +pub mod decl_env; pub mod doc_comment; pub mod errors_impl; pub mod file_info_impl; @@ -16,6 +17,7 @@ pub mod full_fidelity_parser_env_impl; pub mod global_options_impl; pub mod i_map; pub mod i_set; +pub mod internal_type_set; pub mod local_id; pub mod namespace_env_impl; pub mod naming_types_impl; @@ -27,3 +29,9 @@ pub mod s_set; pub mod scoured_comments_impl; pub mod shape_map; pub mod tany_sentinel; +pub mod ty_impl; +pub mod typing_continuations; +pub mod typing_env_return_info; +pub mod typing_logic; +pub mod typing_reason_impl; +pub mod typing_set; diff --git a/hphp/hack/src/oxidized/manual/ty_impl.rs b/hphp/hack/src/oxidized/manual/ty_impl.rs new file mode 100644 index 00000000000..0b1730a7094 --- /dev/null +++ b/hphp/hack/src/oxidized/manual/ty_impl.rs @@ -0,0 +1,22 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. + +use crate::gen::{typing_defs::*, typing_reason::Reason}; +use crate::pos::Pos; + +// Helper methods on types +impl Ty { + pub fn get_node(&self) -> &Ty_ { + let Ty(_, t) = self; + &*t + } + pub fn get_reason(&self) -> &Reason { + let Ty(r, _) = self; + r + } + pub fn get_pos(&self) -> &Pos { + self.get_reason().get_pos() + } +} diff --git a/hphp/hack/src/oxidized/manual/local_id.rs b/hphp/hack/src/oxidized/manual/typing_continuations.rs similarity index 53% copy from hphp/hack/src/oxidized/manual/local_id.rs copy to hphp/hack/src/oxidized/manual/typing_continuations.rs index f8197321ec7..cdb07886d06 100644 --- a/hphp/hack/src/oxidized/manual/local_id.rs +++ b/hphp/hack/src/oxidized/manual/typing_continuations.rs @@ -3,12 +3,7 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the "hack" directory of this source tree. -pub type LocalId = (isize, String); - -pub fn make_unscoped(name: String) -> LocalId { - (0, name) -} - -pub fn get_name((_, name): &LocalId) -> &String { - name +pub mod map { + pub use crate::typing_cont_key::*; + pub type Map = std::collections::BTreeMap; } diff --git a/hphp/hack/src/oxidized/manual/typing_env_return_info.rs b/hphp/hack/src/oxidized/manual/typing_env_return_info.rs new file mode 100644 index 00000000000..cc3937cd553 --- /dev/null +++ b/hphp/hack/src/oxidized/manual/typing_env_return_info.rs @@ -0,0 +1,31 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +// +use ocamlrep_derive::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +#[allow(unused_imports)] +use crate::*; + +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + OcamlRep, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub struct TypingEnvReturnInfo { + pub type_: typing_defs::PossiblyEnforcedTy, + pub disposable: bool, + pub mutable: bool, + pub explicit: bool, + pub void_to_rx: bool, +} diff --git a/hphp/hack/src/oxidized/manual/typing_logic.rs b/hphp/hack/src/oxidized/manual/typing_logic.rs new file mode 100644 index 00000000000..fd14bbd62c3 --- /dev/null +++ b/hphp/hack/src/oxidized/manual/typing_logic.rs @@ -0,0 +1,36 @@ +use crate::typing_defs::*; +use ocamlrep::OcamlRep; +use serde::Deserialize; +use serde::Serialize; + +/// The reason why something is expected to have a certain type +/// This has to be defined manually (not in oxidized/gen) because there is a function type in the original +/// definition of Disj +/// @TODO: work out what to do about this! +#[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + Serialize +)] +pub enum SubtypeProp { + Coerce(Ty, Ty), + IsSubtype(InternalType, InternalType), + Conj(Vec), + Disj(Vec), +} + +impl OcamlRep for SubtypeProp { + fn to_ocamlrep<'a, A: ocamlrep::Allocator<'a>>(&self, _alloc: &A) -> ocamlrep::Value<'a> { + unimplemented!() + } + + fn from_ocamlrep(_value: ocamlrep::Value<'_>) -> Result { + unimplemented!() + } +} diff --git a/hphp/hack/src/oxidized/manual/typing_reason_impl.rs b/hphp/hack/src/oxidized/manual/typing_reason_impl.rs new file mode 100644 index 00000000000..01ffe45c046 --- /dev/null +++ b/hphp/hack/src/oxidized/manual/typing_reason_impl.rs @@ -0,0 +1,112 @@ +use crate::gen::ast_defs::Id; +use crate::gen::typing_reason::Reason; +use crate::gen::typing_reason::Reason::*; +use crate::pos::Pos; + +// Helper functions on Reason +impl Reason { + // Position is owned by reason + pub fn get_pos(&self) -> &Pos { + match self { + Rnone => { + // TODO: not sure what to do about this + // Maybe return an Option<_> instead + let _p = Pos::make_none(); + panic!("NYI"); + } + Rwitness(p) + | Ridx(p, _) + | RidxVector(p) + | Rappend(p) + | Rfield(p) + | Rforeach(p) + | Rasyncforeach(p) + | Raccess(p) + | Rarith(p) + | RarithRet(p) + | RarithDynamic(p) + | Rstring2(p) + | Rcomp(p) + | Rconcat(p) + | RconcatRet(p) + | Rlogic(p) + | RlogicRet(p) + | Rbitwise(p) + | RbitwiseRet(p) + | Rstmt(p) + | RnoReturn(p) + | RnoReturnAsync(p) + | RretFunKind(p, _) + | Rhint(p) + | RnullCheck(p) + | RnotInCstr(p) + | Rthrow(p) + | Rplaceholder(p) + | Rattr(p) + | Rxhp(p) + | RretDiv(p) + | RyieldGen(p) + | RyieldAsyncgen(p) + | RyieldAsyncnull(p) + | RyieldSend(p) + | Rformat(p, _, _) + | RclassClass(p, _) + | RunknownClass(p) + | RdynamicYield(p, _, _, _) + | RmapAppend(p) + | RvarParam(p) + | RunpackParam(p, _, _) + | RinoutParam(p) + | RnullsafeOp(p) + | RusedAsMap(p) + | RusedAsShape(p) + | Rpredicated(p, _) + | Ris(p) + | Ras(p) + | RvarrayOrDarrayKey(p) + | RfinalProperty(p) + | Rusing(p) + | RdynamicProp(p) + | RdynamicCall(p) + | RidxDict(p) + | RmissingRequiredField(p, _) + | RmissingOptionalField(p, _) + | RarrayFilter(p, _) + | RunsetField(p, _) + | Rregex(p) + | RlambdaUse(p) + | RimplicitUpperBound(p, _) + | RarithInt(p) + | RarithRetFloat(p, _, _) + | RarithRetNum(p, _, _) + | RarithRetInt(p) + | RbitwiseDynamic(p) + | RincdecDynamic(p) + | RtypeVariable(p) + | RtypeVariableGenerics(p, _, _) + | RsolveFail(p) + | RcstrOnGenerics(p, _) + | RlambdaParam(p, _) + | Rshape(p, _) + | Renforceable(p) + | Rdestructure(p) + | RkeyValueCollectionKey(p) + | RglobalClassProp(p) + | RglobalFunParam(p) + | RglobalFunRet(p) => p, + Rcoerced(r, _, _) + | RlostInfo(_, r, _, _) + | Rinstantiate(_, _, r) + | RtypeAccess(r, _) + | RexprDepType(r, _, _) + | RcontravariantGeneric(r, _) + | RinvariantGeneric(r, _) => (*r).get_pos(), + Rtypeconst(r, (p, _), _, _) => match r.as_ref() { + Rnone => p, + r => r.get_pos(), + }, + // Need to get pos out of sid + RtconstNoCstr(Id(p, _)) => p, + } + } +} diff --git a/hphp/hack/src/oxidized/manual/local_id.rs b/hphp/hack/src/oxidized/manual/typing_set.rs similarity index 53% copy from hphp/hack/src/oxidized/manual/local_id.rs copy to hphp/hack/src/oxidized/manual/typing_set.rs index f8197321ec7..dfe075e17e9 100644 --- a/hphp/hack/src/oxidized/manual/local_id.rs +++ b/hphp/hack/src/oxidized/manual/typing_set.rs @@ -3,12 +3,6 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the "hack" directory of this source tree. -pub type LocalId = (isize, String); +use crate::typing_defs::*; -pub fn make_unscoped(name: String) -> LocalId { - (0, name) -} - -pub fn get_name((_, name): &LocalId) -> &String { - name -} +pub type TySet = std::collections::BTreeSet; diff --git a/hphp/hack/src/oxidized/regen.sh b/hphp/hack/src/oxidized/regen.sh index 28a76632a1a..1b050f47d73 100755 --- a/hphp/hack/src/oxidized/regen.sh +++ b/hphp/hack/src/oxidized/regen.sh @@ -36,9 +36,18 @@ BUILD_AND_RUN="hphp/hack/scripts/build_and_run.sh" hphp/hack/src/options/parserOptions.ml \ hphp/hack/src/options/typecheckerOptions.ml \ hphp/hack/src/parser/full_fidelity_parser_env.ml \ + hphp/hack/src/typing/type_parameter_env.ml \ + hphp/hack/src/typing/typing_mutability_env.ml \ + hphp/hack/src/typing/typing_cont_key.ml \ hphp/hack/src/typing/typing_defs.ml \ hphp/hack/src/typing/typing_defs_core.ml \ hphp/hack/src/typing/typing_reason.ml \ + hphp/hack/src/typing/typing_env_types.ml \ + hphp/hack/src/typing/typing_inference_env.ml \ + hphp/hack/src/typing/typing_local_types.ml \ + hphp/hack/src/typing/typing_per_cont_env.ml \ + hphp/hack/src/typing/typing_fake_members.ml \ + hphp/hack/src/typing/typing_tyvar_occurrences.ml \ hphp/hack/src/utils/core/prim_defs.ml \ hphp/hack/src/parser/scoured_comments.ml \ diff --git a/hphp/hack/src/typing/cargo/compile/Cargo.toml b/hphp/hack/src/typing/cargo/compile/Cargo.toml new file mode 100644 index 00000000000..84e2cf1c9d4 --- /dev/null +++ b/hphp/hack/src/typing/cargo/compile/Cargo.toml @@ -0,0 +1,22 @@ +# @generated +# @autocargo from //hphp/hack/src/typing:typing_check_service_rust +# Signature +[package] +name = "typing_check_service_rust" +edition = "2018" +version = "0.0.0" +include = ["../../typing_check_service_rust.rs", "../../typing_check_utils.rs", "../../typing_env.rs", "../../typing_make_type.rs"] + +[lib] +path = "../../typing_check_service_rust.rs" + +[dependencies] +aast_parser = { path = "../../../parser/cargo/aast_parser" } +ocamlrep = { path = "../../../ocamlrep" } +oxidized = { path = "../../../oxidized" } +parser_core_types = { path = "../../../parser/cargo/core_types" } +stack_limit = { path = "../../../utils/stack_limit" } +anyhow = "1.0" +bitflags = "1.2" +itertools = "0.8" +# @end of Signature diff --git a/hphp/hack/src/oxidized/manual/local_id.rs b/hphp/hack/src/typing/typing_check_service_rust.rs similarity index 52% copy from hphp/hack/src/oxidized/manual/local_id.rs copy to hphp/hack/src/typing/typing_check_service_rust.rs index f8197321ec7..32b1d6452fc 100644 --- a/hphp/hack/src/oxidized/manual/local_id.rs +++ b/hphp/hack/src/typing/typing_check_service_rust.rs @@ -2,13 +2,6 @@ // // This source code is licensed under the MIT license found in the // LICENSE file in the "hack" directory of this source tree. - -pub type LocalId = (isize, String); - -pub fn make_unscoped(name: String) -> LocalId { - (0, name) -} - -pub fn get_name((_, name): &LocalId) -> &String { - name -} +pub mod typing_check_utils; +pub mod typing_env; +pub mod typing_make_type; diff --git a/hphp/hack/src/typing/typing_check_utils.rs b/hphp/hack/src/typing/typing_check_utils.rs new file mode 100644 index 00000000000..3a7708f2a4b --- /dev/null +++ b/hphp/hack/src/typing/typing_check_utils.rs @@ -0,0 +1,111 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +use aast_parser::{ + rust_aast_parser_types::{Env as AastEnv, Result as AastResult}, + AastParser, Error as AastError, +}; +use anyhow; +use itertools::{Either, Either::*}; +use ocamlrep::rc::RcOc; +use oxidized::{ + ast as Tast, parser_options::ParserOptions, pos::Pos, relative_path::RelativePath, + typing_env_types::Genv, +}; +use parser_core_types::{indexed_source_text::IndexedSourceText, source_text::SourceText}; +use stack_limit::StackLimit; + +/// Compilation profile. All times are in seconds +#[derive(Debug)] +pub struct Profile { + // Parse time + pub parsing_t: f64, + // Infer time + pub infer_t: f64, + // TAST check time + pub check_t: f64, +} + +pub fn from_text(env: Genv, stack_limit: &StackLimit, text: &[u8]) -> anyhow::Result { + let mut ret = Profile { + parsing_t: 0.0, + infer_t: 0.0, + check_t: 0.0, + }; + + let mut parse_result = profile(&mut ret.parsing_t, || { + parse_file(stack_limit, &env.file, text) + }); + + let _program = match &mut parse_result { + Either::Right((ast, _is_hh_file)) => { + println!("{:?}", ast); + () + } + Either::Left((_pos, _msg, _is_runtime_error)) => (), + }; + + profile(&mut ret.check_t, || {}); + Ok(ret) +} + +/// parse_file returns either error(Left) or ast(Right) +/// - Left((Position, message, is_runtime_error)) +/// - Right((ast, is_hh_file)) +fn parse_file( + //opts: &Options, + stack_limit: &StackLimit, + filepath: &RelativePath, + text: &[u8], +) -> Either<(Pos, String, bool), (Tast::Program, bool)> { + let mut aast_env = AastEnv::default(); + aast_env.codegen = false; + aast_env.keep_errors = true; + aast_env.show_all_errors = true; + aast_env.fail_open = true; + aast_env.parser_options = ParserOptions::default(); + let source_text = SourceText::make(RcOc::new(filepath.clone()), text); + let indexed_source_text = IndexedSourceText::new(source_text); + let ast_result = AastParser::from_text(&aast_env, &indexed_source_text, Some(stack_limit)); + match ast_result { + Err(AastError::Other(msg)) => Left((Pos::make_none(), msg, false)), + Err(AastError::ParserFatal(syntax_error, pos)) => { + Left((pos, syntax_error.message.to_string(), false)) + } + Ok(ast) => match ast { + AastResult { syntax_errors, .. } if !syntax_errors.is_empty() => unimplemented!(), + AastResult { + mut lowpri_errors, .. + } if !lowpri_errors.is_empty() => { + let (pos, msg) = lowpri_errors.pop().unwrap(); + Left((pos, msg, false)) + } + AastResult { + errors, + aast, + file_mode, + .. + } => { + if !errors.is_empty() { + unimplemented!() + } else { + match aast { + Ok(aast) => Right((aast, file_mode.is_hh_file())), + Err(msg) => Left((Pos::make_none(), msg, false)), + } + } + } + }, + } +} + +fn profile(dt: &mut f64, f: F) -> T +where + F: FnOnce() -> T, +{ + let t0 = std::time::Instant::now(); + let ret = f(); + *dt = t0.elapsed().as_secs_f64(); + ret +} diff --git a/hphp/hack/src/typing/typing_env.rs b/hphp/hack/src/typing/typing_env.rs new file mode 100644 index 00000000000..9525d7cec03 --- /dev/null +++ b/hphp/hack/src/typing/typing_env.rs @@ -0,0 +1,34 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. +use crate::typing_make_type::*; +use oxidized::{ + ast_defs::FunKind, relative_path::RelativePath, s_map, typing_defs::ValKind, + typing_env_types::Genv, +}; + +pub fn empty_global_env(builder: &TypeBuilder, file: RelativePath) -> Genv { + Genv { + file, + tcopt: oxidized::global_options::GlobalOptions::default(), + fun_mutable: None, + params: oxidized::local_id::map::Map::new(), + return_: oxidized::typing_env_return_info::TypingEnvReturnInfo { + explicit: false, + mutable: false, + void_to_rx: false, + disposable: false, + type_: oxidized::typing_defs::PossiblyEnforcedTy { + enforced: false, + type_: builder.nothing(oxidized::typing_reason::Reason::Rnone), + }, + }, + static_: false, + self_: None, + parent: None, + fun_kind: FunKind::FSync, + val_kind: ValKind::Other, + condition_types: s_map::SMap::new(), + } +} diff --git a/hphp/hack/src/typing/typing_env_types.ml b/hphp/hack/src/typing/typing_env_types.ml index 3274650f335..f3a049632a7 100644 --- a/hphp/hack/src/typing/typing_env_types.ml +++ b/hphp/hack/src/typing/typing_env_types.ml @@ -10,7 +10,6 @@ (* cf: typing_env_types_sig.mli - These files should be the same *) open Hh_prelude open Typing_defs -module TPEnv = Type_parameter_env module ITySet = Internal_type_set type locl_ty = Typing_defs.locl_ty @@ -64,7 +63,7 @@ type env = { inside_constructor: bool; inside_ppl_class: bool; (* A set of constraints that are global to a given method *) - global_tpenv: TPEnv.t; + global_tpenv: Type_parameter_env.t; log_levels: int SMap.t; inference_env: Typing_inference_env.t; allow_wildcards: bool; diff --git a/hphp/hack/src/typing/typing_fake_members.ml b/hphp/hack/src/typing/typing_fake_members.ml index 276b17d3ab6..f0ac7ae8145 100644 --- a/hphp/hack/src/typing/typing_fake_members.ml +++ b/hphp/hack/src/typing/typing_fake_members.ml @@ -7,8 +7,6 @@ * *) -open Typing_log_value - (* Validation blame: call or lambda *) type blame = | Blame_call of Pos.t @@ -111,23 +109,26 @@ let add fake lid = let blame_as_log_value blame = match blame with - | Blame_call p -> make_map [("Blame_call", pos_as_value p)] - | Blame_lambda p -> make_map [("Blame_lambda", pos_as_value p)] + | Blame_call p -> Typing_log_value.(make_map [("Blame_call", pos_as_value p)]) + | Blame_lambda p -> + Typing_log_value.(make_map [("Blame_lambda", pos_as_value p)]) let as_log_value fake = match fake with - | Valid valid -> make_map [("Valid", local_id_set_as_value valid)] + | Valid valid -> + Typing_log_value.(make_map [("Valid", local_id_set_as_value valid)]) | Invalidated { valid; invalid; blame } -> - make_map - [ - ( "Invalidated", - make_map - [ - ("valid", local_id_set_as_value valid); - ("invalid", local_id_set_as_value invalid); - ("blame", blame_as_log_value blame); - ] ); - ] + Typing_log_value.( + make_map + [ + ( "Invalidated", + make_map + [ + ("valid", local_id_set_as_value valid); + ("invalid", local_id_set_as_value invalid); + ("blame", blame_as_log_value blame); + ] ); + ]) let make_id obj_name member_name = let obj_name = diff --git a/hphp/hack/src/typing/typing_inference_env.ml b/hphp/hack/src/typing/typing_inference_env.ml index ef000979256..b3b3320b1d6 100644 --- a/hphp/hack/src/typing/typing_inference_env.ml +++ b/hphp/hack/src/typing/typing_inference_env.ml @@ -67,7 +67,7 @@ type tvenv = tyvar_info IMap.t type t = { tvenv: tvenv; tyvars_stack: (Pos.t * Ident.t list) list; - subtype_prop: Typing_logic.subtype_prop; + subtype_prop: TL.subtype_prop; tyvar_occurrences: Typing_tyvar_occurrences.t; allow_solve_globals: bool; } diff --git a/hphp/hack/src/typing/typing_make_type.rs b/hphp/hack/src/typing/typing_make_type.rs new file mode 100644 index 00000000000..b7274b5182b --- /dev/null +++ b/hphp/hack/src/typing/typing_make_type.rs @@ -0,0 +1,78 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. + +use oxidized::{aast_defs::*, ident, typing_defs::*, typing_reason::*}; + +// Struct off which we call type builder methods +// This gives us the option to keep some state here e.g. for hash consing +pub struct TypeBuilder {} + +impl TypeBuilder { + pub fn new() -> Self { + TypeBuilder {} + } + // All type construction should go through here + pub fn mk(&self, reason: Reason, ty_: Ty_) -> Ty { + Ty(reason, Box::new(ty_)) + } + pub fn prim(&self, reason: Reason, kind: Tprim) -> Ty { + self.mk(reason, Ty_::Tprim(kind)) + } + pub fn int(&self, reason: Reason) -> Ty { + self.prim(reason, Tprim::Tint) + } + pub fn bool(&self, reason: Reason) -> Ty { + self.prim(reason, Tprim::Tbool) + } + pub fn string(&self, reason: Reason) -> Ty { + self.prim(reason, Tprim::Tstring) + } + pub fn float(&self, reason: Reason) -> Ty { + self.prim(reason, Tprim::Tfloat) + } + pub fn arraykey(&self, reason: Reason) -> Ty { + self.prim(reason, Tprim::Tarraykey) + } + pub fn void(&self, reason: Reason) -> Ty { + self.prim(reason, Tprim::Tvoid) + } + pub fn null(&self, reason: Reason) -> Ty { + self.prim(reason, Tprim::Tnull) + } + pub fn nonnull(&self, reason: Reason) -> Ty { + self.mk(reason, Ty_::Tnonnull) + } + pub fn dynamic(&self, reason: Reason) -> Ty { + self.mk(reason, Ty_::Tdynamic) + } + /* + pub fn object(&self, reason: Reason) -> Ty { + self.mk(reason, Ty_::Tobject) + } + */ + pub fn tyvar(&self, reason: Reason, v: ident::Ident) -> Ty { + self.mk(reason, Ty_::Tvar(v)) + } + pub fn union(&self, reason: Reason, tys: Vec) -> Ty { + self.mk(reason, Ty_::Tunion(tys)) + } + pub fn intersection(&self, reason: Reason, tys: Vec) -> Ty { + self.mk(reason, Ty_::Tintersection(tys)) + } + pub fn nothing(&self, reason: Reason) -> Ty { + self.union(reason, Vec::new()) + } + pub fn nullable(&self, reason: Reason, ty: Ty) -> Ty { + self.mk(reason, Ty_::Toption(ty)) + } + pub fn mixed(&self, reason: Reason) -> Ty { + // TODO: cloning is annoying. We should see if we can change rep of reasons + let reason2 = reason.clone(); + self.nullable(reason, self.nonnull(reason2)) + } + pub fn generic(&self, reason: Reason, name: String) -> Ty { + self.mk(reason, Ty_::Tgeneric(name)) + } +} diff --git a/hphp/hack/src/typing/typing_mutability_env.ml b/hphp/hack/src/typing/typing_mutability_env.ml index e25c33de223..c54b1bfab56 100644 --- a/hphp/hack/src/typing/typing_mutability_env.ml +++ b/hphp/hack/src/typing/typing_mutability_env.ml @@ -48,7 +48,7 @@ let to_string (_, mut) = to_string_ mut - for locals - arguments to move\freeze calls we still keep value in map as MutableUnset to keep mutability flavor information *) -type mutability_env = mutability LMap.t +type mutability_env = mutability Local_id.Map.t (* Given two mutability maps, intersect them. *) let intersect_mutability diff --git a/hphp/hack/src/typing/typing_per_cont_env.ml b/hphp/hack/src/typing/typing_per_cont_env.ml index f71d473cec2..738473c5c0b 100644 --- a/hphp/hack/src/typing/typing_per_cont_env.ml +++ b/hphp/hack/src/typing/typing_per_cont_env.ml @@ -8,8 +8,7 @@ *) open Common module C = Typing_continuations -module CMap = Typing_continuations.Map -module LMap = Local_id.Map +module CMap = C.Map type per_cont_entry = { (* Local types per continuation. For example, the local types of the @@ -52,7 +51,7 @@ let empty_entry = tpenv = Type_parameter_env.empty; } -let initial_locals entry = CMap.add C.Next entry CMap.empty +let initial_locals entry = CMap.add Typing_continuations.Next entry CMap.empty let get_cont_option = CMap.find_opt @@ -69,7 +68,7 @@ let add_to_cont name key value m = | None -> m | Some cont -> let cont = - { cont with local_types = LMap.add key value cont.local_types } + { cont with local_types = Local_id.Map.add key value cont.local_types } in CMap.add name cont m @@ -77,7 +76,10 @@ let remove_from_cont name key m = match CMap.find_opt name m with | None -> m | Some c -> - CMap.add name { c with local_types = LMap.remove key c.local_types } m + CMap.add + name + { c with local_types = Local_id.Map.remove key c.local_types } + m let drop_cont = CMap.remove -- 2.11.4.GIT