Skip to content

Commit

Permalink
Fix Class<> annotations for subtyping, and require subtyping on inter…
Browse files Browse the repository at this point in the history
…face statics
  • Loading branch information
popham committed May 28, 2016
1 parent 4c9945e commit db81278
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 6 deletions.
33 changes: 27 additions & 6 deletions src/typing/flow_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,8 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace =
(* The sink component of an annotation constrains values flowing
into the annotated site. *)

| _, UseT (use_op, AnnotT (sink_t, _)) ->
| l, UseT (use_op, AnnotT (sink_t, _))
| ClassT (l), UseT (use_op, ClassT (AnnotT (sink_t, _))) ->
let reason = reason_of_t sink_t in
rec_flow cx trace (sink_t, ReposUseT (reason, use_op, l))

Expand Down Expand Up @@ -2429,15 +2430,22 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace =
(***************************************************************)

| (_,
UseT (_, InstanceT (reason_inst, _, super, {
UseT (_, InstanceT (reason_inst, static, super, {
fields_tmap;
methods_tmap;
structural = true;
_;
})))
->
structural_subtype cx trace l reason_inst
(super, fields_tmap, methods_tmap)
(super, fields_tmap, methods_tmap);

(match l, static with
| InstanceT (_, l, _, _),
InstanceT (reason, _, super, { fields_tmap; methods_tmap; _; }) ->
structural_subtype cx trace l reason
(super, fields_tmap, methods_tmap)
| _ -> ())

(********************************************************)
(* runtime types derive static types through annotation *)
Expand Down Expand Up @@ -3464,15 +3472,23 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace =
rec_flow cx trace
(next, UseT (use_op, ExtendsT (try_ts_on_failure, l, u)))

| (MixedT _, UseT (_, ExtendsT ([], l, InstanceT (reason_inst, _, super, {
| (MixedT _,
UseT (_, ExtendsT ([], l, InstanceT (reason_inst, static, super, {
fields_tmap;
methods_tmap;
structural = true;
_;
}))))
->
structural_subtype cx trace l reason_inst
(super, fields_tmap, methods_tmap)
(super, fields_tmap, methods_tmap);

(match l, static with
| InstanceT (_, l, _, _),
InstanceT (reason, _, super, { fields_tmap; methods_tmap; _; }) ->
structural_subtype cx trace l reason
(super, fields_tmap, methods_tmap)
| _ -> ())

| (MixedT _, UseT (_, ExtendsT ([], t, tc))) ->
let msg = "This type is incompatible with" in
Expand Down Expand Up @@ -3693,6 +3709,7 @@ and ground_subtype = function
| (VoidT _, UseT (_, VoidT _))
| (EmptyT _, _)
| (_, UseT (_, MixedT _))
| (_, UseT (_, ClassT (MixedT _)))
| (_, UseT (_, FunProtoT _)) (* MixedT is used for object protos, this is for funcs *)
| (AnyT _, _)
| (_, UseT (_, AnyT _))
Expand Down Expand Up @@ -6091,6 +6108,7 @@ and become cx ?trace r t = match t with

(* set the position of the given def type from a reason *)
and reposition cx ?trace reason t =
let repos t = mod_reason_of_t (repos_reason (loc_of_reason reason)) t in
match t with
| OpenT (r, id) ->
let constraints = find_graph cx id in
Expand All @@ -6115,7 +6133,10 @@ and reposition cx ?trace reason t =
mk_tvar_where cx reason (fun tvar ->
flow_opt cx ?trace (t, ReposLowerT (reason, UseT (UnknownUse, tvar)))
)
| _ -> mod_reason_of_t (repos_reason (loc_of_reason reason)) t
| InstanceT (reason_inst, static, super, insttype) ->
let loc = loc_of_reason reason in
InstanceT (repos_reason loc reason_inst, repos static, super, insttype)
| _ -> repos t

(* given the type of a value v, return the type term
representing the `typeof v` annotation expression *)
Expand Down
40 changes: 40 additions & 0 deletions tests/class_type/test2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
class A {}
class B extends A {}

class K {
static gn() {
return this;
}
}

class L extends K {
static gn() { // NG Bug: False positive.
return L;
}
}

class W {
fn(): Class<A> {
return B;
}
static fn(): Class<A> {
return B;
}
static gn(): Class<W> {
return W;
}
}

class X extends W {
static gn(): Class<this> {
return this;
}
}

class Y extends X {
static gn(): Class<Y> { //NG
return Y;
}
}

var a: Class<W> = X.gn();
21 changes: 21 additions & 0 deletions tests/interface/test4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
interface I {
fn(): number;
static gn(): number;
}

class A {}
var a = new A();
var p: A & I = a; // NG
var P: Class<A> & Class<I> = A; // NG

class B extends A {
fn(): number {
return 1;
}
static gn(): number {
return 2;
}
}
var b = new B();
var q: A & I = b; // OK
var Q: Class<A> & Class<I> = B; // OK

0 comments on commit db81278

Please sign in to comment.