Permalink
Browse files

add experimental tc option to disable namespace fallback for function…

…s and constants

Summary:
- add and implement option
 - make `__FOO__` constants auto-imported regardless (e.g. `__FILE__`, `__DIR__`, `__NAMESPACE__`, `__CLASS__`)
 - make weird operators (e.g. `unset`, `isset`, and `exit`) auto-imported
 - make `vec()`, `dict()`, and `keyset()` autoimported
 - make `is_*` autoimported
 - HHI fixups

Reviewed By: kmeht

Differential Revision: D6877203

fbshipit-source-id: 34bf0ae2d88a4d9ba14eaab7bb4bc2f90df3ce14
  • Loading branch information...
fredemmott authored and hhvm-bot committed Feb 3, 2018
1 parent 242c07c commit 090d143895db7a77b4cd3dd010ac3cc16207484c
@@ -18,6 +18,6 @@ namespace HH\Asio {
function has_finished<T>(Awaitable<T> $awaitable): bool;
function cancel<T>(Awaitable<T> $awaitable, \Exception $exception): bool;
function backtrace<T>(Awaitable<T> $awaitable,
int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT,
int $options = \DEBUG_BACKTRACE_PROVIDE_OBJECT,
int $limit = 0): array<array>;
}
@@ -134,6 +134,7 @@ let parse_options () =
let deregister_attributes = ref false in
let disable_optional_and_unknown_shape_fields = ref false in
let disallow_destruct = ref false in
let no_fallback_in_namespaces = ref false in
let options = [
"--ai",
Arg.String (set_ai),
@@ -241,6 +242,9 @@ let parse_options () =
"--disallow-destruct",
Arg.Set disallow_destruct,
" Disallow definition of destructors without __OptionalDestruct.";
"--no-fallback-in-namespaces",
Arg.Set no_fallback_in_namespaces,
" Treat foo() as namespace\\foo() and MY_CONST as namespace\\MY_CONST.";
"--infer-return-types",
Arg.Unit (set_mode Infer_return_types),
" Infers return types of functions and methods.";
@@ -268,6 +272,8 @@ let parse_options () =
then !forbid_nullable_cast
else if x = GlobalOptions.tco_experimental_disable_optional_and_unknown_shape_fields
then !disable_optional_and_unknown_shape_fields
else if x = GlobalOptions.tco_experimental_no_fallback_in_namespaces
then !no_fallback_in_namespaces
else true
end tcopt.GlobalOptions.tco_experimental_features;
} in
@@ -433,7 +433,15 @@ end = struct
let need_fallback =
genv.namespace.Namespace_env.ns_name <> None &&
not (String.contains (snd x) '\\') in
if need_fallback then begin
let use_fallback =
need_fallback &&
(
(not (TypecheckerOptions.experimental_feature_enabled
genv.tcopt
TypecheckerOptions.experimental_no_fallback_in_namespaces)) ||
((string_starts_with (snd x) "__") && (string_ends_with (snd x) "__"))
) in
if use_fallback then begin
let global_x = (fst x, "\\" ^ (snd x)) in
(* Explicitly add dependencies on both of the consts we could be
* referring to here. Normally naming doesn't have to deal with
@@ -466,7 +474,12 @@ end = struct
let need_fallback =
genv.namespace.Namespace_env.ns_name <> None &&
not (String.contains (snd x) '\\') in
if need_fallback then begin
let use_fallback =
need_fallback &&
not (TypecheckerOptions.experimental_feature_enabled
genv.tcopt
TypecheckerOptions.experimental_no_fallback_in_namespaces) in
if use_fallback then begin
let global_x = (fst x, "\\" ^ (snd x)) in
(* Explicitly add dependencies on both of the functions we could be
* referring to here. Normally naming doesn't have to deal with deps at
@@ -117,6 +117,18 @@ let tco_experimental_no_trait_reuse = "no_trait_reuse"
*)
let tco_experimental_is_expression = "is_expression"
(**
* If enabled:
*
* namespace Foo {
* // does not fall back to \bar() if `bar()` is not 'used' and
* // `Foo\bar()` does not exist
* bar();
* }
*)
let tco_experimental_no_fallback_in_namespaces =
"no_fallback_in_namespaces"
let tco_experimental_all =
SSet.empty |> List.fold_right SSet.add
[
@@ -137,6 +149,7 @@ let tco_experimental_all =
tco_experimental_disable_optional_and_unknown_shape_fields;
tco_experimental_no_trait_reuse;
tco_experimental_is_expression;
tco_experimental_no_fallback_in_namespaces;
]
let tco_migration_flags_all =
@@ -119,6 +119,7 @@ val tco_experimental_disallow_static_memoized : string
val tco_experimental_disable_optional_and_unknown_shape_fields : string
val tco_experimental_no_trait_reuse : string
val tco_experimental_is_expression : string
val tco_experimental_no_fallback_in_namespaces : string
val tco_experimental_all : SSet.t
val tco_migration_flags_all : SSet.t
val ignored_fixme_codes : t -> ISet.t
@@ -49,6 +49,8 @@ let experimental_disable_optional_and_unknown_shape_fields =
GlobalOptions.tco_experimental_disable_optional_and_unknown_shape_fields
let experimental_no_trait_reuse = GlobalOptions.tco_experimental_no_trait_reuse
let experimental_is_expression = GlobalOptions.tco_experimental_is_expression
let experimental_no_fallback_in_namespaces =
GlobalOptions.tco_experimental_no_fallback_in_namespaces
let experimental_all = GlobalOptions.tco_experimental_all
let migration_flags_all = GlobalOptions.tco_migration_flags_all
@@ -70,6 +70,39 @@ let autoimport_funcs = [
"invariant";
"invariant_violation";
"type_structure";
"idx";
"vec";
"dict";
"keyset";
(* should be replaced by is/as, but for now, import them so they're internally
* consistent - no need for \is_array vs \HH\is_vec *)
"is_bool";
"is_int";
"is_integer";
"is_long";
"is_float";
"is_double";
"is_real";
"is_numeric";
"is_string";
"is_object";
"is_resource";
"is_array";
"is_darray";
"is_vec";
"is_dict";
"is_keyset";
"is_varray";
(* typechecker debugging/test functions *)
"hh_show";
"hh_show_env";
(* these are operators, not functions:
* foo() !== \foo(), even in the root namespace *)
"empty";
"isset";
"unset";
"exit";
"die";
]
let autoimport_types = [
"typename";
@@ -0,0 +1 @@
--no-fallback-in-namespaces
@@ -0,0 +1,24 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the "hack" directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
namespace NS;
function returns_dict(): dict<string, int> {
return dict(['a' => 123, 'b' => 456, 'c' => 789]);
}
function returns_keyset(): keyset<string> {
return keyset(['a', 'b', 'c']);
}
function returns_vec(): vec<string> {
return vec(['a', 'b', 'c']);
}
@@ -0,0 +1,20 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the "hack" directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
namespace {
const string FOO = 'bar';
}
namespace NS {
function bar(): void {
\var_dump(FOO);
}
}
@@ -0,0 +1,2 @@
File "no_constant_fallback.php", line 18, characters 15-17:
Unbound name: NS\FOO (a global constant) (Naming[2049])
@@ -0,0 +1,21 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the "hack" directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
namespace {
function foo(): void {
}
}
namespace NS {
function bar(): void {
foo();
}
}
@@ -0,0 +1,2 @@
File "no_function_fallback.php", line 19, characters 5-7:
Unbound name: NS\foo (a global function) (Naming[2049])
@@ -0,0 +1,20 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the "hack" directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
namespace NS;
function foo(mixed $in): void {
/* HH_IGNORE_ERROR[4016] isset() is unsafe, but still defined */
\var_dump(isset($in));
/* HH_IGNORE_ERROR[4135] unsset() is also banned */
unset($in);
exit(0);
}
@@ -0,0 +1,34 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the "hack" directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
namespace NS;
function returns_int(mixed $in): ?int {
if (is_int($in)) {
return $in;
}
return null;
}
/* HH_IGNORE_ERROR[4045] array without generics */
function returns_array(mixed $in): ?array {
if (is_array($in)) {
return $in;
}
return null;
}
function returns_vec(mixed $in): ?vec<mixed> {
if (is_vec($in)) {
return $in;
}
return null;
}

0 comments on commit 090d143

Please sign in to comment.