Skip to content
Permalink
Browse files

Emit error when type param declaration shadows global type name

Summary:
```
class T<T> {}
```
is banned by this diff. Notably, type parameter names do not go into the naming table. We're treating type parameter declarations like inline class definitions that live for the scope of the type parameter.

Reviewed By: oulgen

Differential Revision: D13868710

fbshipit-source-id: 823d931d0f3e9159e7d7c2aee4b29f4e3dfa5018
  • Loading branch information...
vassilmladenov authored and hhvm-bot committed Feb 2, 2019
1 parent e01593d commit 5711d5d07980d63898e76e691fc48e27383c4dc5
@@ -1431,11 +1431,26 @@ module Make (GetLocals : GetLocals) = struct
List.rev ret

and aast_type_param ~forbid_this env t =
let (genv, _) = env in
if t.Aast.tp_reified && not (TypecheckerOptions.experimental_feature_enabled
(fst env).tcopt
genv.tcopt
TypecheckerOptions.experimental_reified_generics)
then
Errors.experimental_feature (fst t.Aast.tp_name) "reified generics";

(* Treat type params as inline class declarations that don't go into the naming heap *)
let (pos, name) = NS.elaborate_id genv.namespace NS.ElaborateClass t.Aast.tp_name in
let _ = match Naming_heap.TypeIdHeap.get name with
| Some (def_pos, _) ->
let def_pos, _ = GEnv.get_full_pos genv.tcopt (def_pos, name) in
Errors.error_name_already_bound name name pos def_pos
| None ->
match GEnv.type_canon_name name with
| Some canonical ->
let def_pos = Option.value ~default:Pos.none (GEnv.type_pos genv.tcopt canonical) in
Errors.error_name_already_bound name canonical pos def_pos
| None -> () in

{
N.tp_variance = t.Aast.tp_variance;
tp_name = t.Aast.tp_name;
@@ -1 +1,4 @@
No errors
File "refl_subtype.php", line 4, characters 10-11:
Name already bound: Tr (Naming[2012])
File "refl_subtype.php", line 4, characters 7-8:
Previous definition TR differs only in capitalization
@@ -1,2 +1,4 @@
File "instanceof_generic_bad.php", line 5, characters 26-26:
Generics can only be used in type hints since they are erased at runtime. (Typing[4124])
File "instanceof_generic_bad.php", line 4, characters 21-21:
Name already bound: T (Naming[2012])
File "instanceof_generic_bad.php", line 3, characters 7-7:
Previous definition is here
@@ -1,2 +1,4 @@
File "instanceof_generic_bad2.php", line 5, characters 26-26:
Generics can only be used in type hints since they are erased at runtime. (Typing[4124])
File "instanceof_generic_bad2.php", line 3, characters 9-9:
Name already bound: T (Naming[2012])
File "instanceof_generic_bad2.php", line 3, characters 7-7:
Previous definition is here
@@ -1,2 +1,4 @@
File "new_generic_bad.php", line 5, characters 16-16:
Generics can only be used in type hints since they are erased at runtime. (Typing[4124])
File "new_generic_bad.php", line 3, characters 9-9:
Name already bound: T (Naming[2012])
File "new_generic_bad.php", line 3, characters 7-7:
Previous definition is here
@@ -0,0 +1,18 @@
<?hh // strict
// Copyright 2004-present Facebook. All Rights Reserved.
class Ta {}
function f1<TA>(): void {}
function f2<Ta>(): void {}
class C1<TA> {}
class C2<Ta> {}
class CM {
public function m1<TA>(): void {}
public function m2<Ta>(): void {}
}
type T1<TA> = int;
type T2<Ta> = int;
@@ -0,0 +1,32 @@
File "tparams_shadow_classes.php", line 6, characters 13-14:
Name already bound: TA (Naming[2012])
File "tparams_shadow_classes.php", line 4, characters 7-8:
Previous definition Ta differs only in capitalization
File "tparams_shadow_classes.php", line 7, characters 13-14:
Name already bound: Ta (Naming[2012])
File "tparams_shadow_classes.php", line 4, characters 7-8:
Previous definition is here
File "tparams_shadow_classes.php", line 9, characters 10-11:
Name already bound: TA (Naming[2012])
File "tparams_shadow_classes.php", line 4, characters 7-8:
Previous definition Ta differs only in capitalization
File "tparams_shadow_classes.php", line 10, characters 10-11:
Name already bound: Ta (Naming[2012])
File "tparams_shadow_classes.php", line 4, characters 7-8:
Previous definition is here
File "tparams_shadow_classes.php", line 13, characters 22-23:
Name already bound: TA (Naming[2012])
File "tparams_shadow_classes.php", line 4, characters 7-8:
Previous definition Ta differs only in capitalization
File "tparams_shadow_classes.php", line 14, characters 22-23:
Name already bound: Ta (Naming[2012])
File "tparams_shadow_classes.php", line 4, characters 7-8:
Previous definition is here
File "tparams_shadow_classes.php", line 17, characters 9-10:
Name already bound: TA (Naming[2012])
File "tparams_shadow_classes.php", line 4, characters 7-8:
Previous definition Ta differs only in capitalization
File "tparams_shadow_classes.php", line 18, characters 9-10:
Name already bound: Ta (Naming[2012])
File "tparams_shadow_classes.php", line 4, characters 7-8:
Previous definition is here
@@ -0,0 +1,12 @@
<?hh // strict
// Copyright 2004-present Facebook. All Rights Reserved.
namespace A {
class T {}
class C<T> {} // bad
}
namespace {
class C<T> {} // ok
}
@@ -0,0 +1,4 @@
File "tparams_shadow_classes_namespaced.php", line 7, characters 11-11:
Name already bound: A\T (Naming[2012])
File "tparams_shadow_classes_namespaced.php", line 5, characters 9-9:
Previous definition is here
@@ -1,12 +1,12 @@
<?hh // strict
type s = shape(?'x' => mixed, ...);
type t = shape(?'y' => mixed, ...);
type tt = shape(?'y' => mixed, ...);
class C<T> {
public function __construct(T $_) {}
}
function test(s $s): C<t> {
function test(s $s): C<tt> {
return new C($s);
}
@@ -15,9 +15,9 @@ function f<Tv>(Tv $_): I<Tv> {
'y' => string,
);
type t = shape('x' => int);
type tt = shape('x' => int);
function test(t $s): I<s> {
function test(tt $s): I<s> {
Shapes::removeKey(&$s, 'z');
$s = f($s);
// This is legal. See shape28.php

0 comments on commit 5711d5d

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.