Make Ty abstract
[hiphop-php.git] / hphp / hack / src / typing / typing_inference_env.rs
blob982cbe77d5b3b5f78cf0e8e96196d0a350e7bad7
1 // Copyright (c) Facebook, Inc. and its affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
5 use arena_trait::Arena;
6 use bumpalo::collections::Vec;
8 use oxidized::aast;
9 use oxidized::ident::Ident;
10 use oxidized::pos::Pos;
12 use typing_collections_rust::{IMap, ISet, SMap};
13 use typing_defs_rust::{ITySet, PReason, Ty, Ty_};
15 use crate::typing_make_type::TypeBuilder;
16 use crate::typing_tyvar_occurrences;
18 #[derive(Clone)]
19 pub struct TyvarConstraints<'a> {
20     /// Does this type variable appear covariantly in the type of the expression?
21     pub appears_covariantly: bool,
22     /// Does this type variable appear contravariantly in the type of the expression?
23     /// If it appears in an invariant position then both will be true; if it doesn't
24     /// appear at all then both will be false.
25     pub appears_contravariantly: bool,
26     pub lower_bounds: ITySet<'a>,
27     pub upper_bounds: ITySet<'a>,
28     /// Map associating a type to each type constant id of this variable.
29     /// Whenever we localize "T1::T" in a constraint, we add a fresh type variable
30     /// indexed by "T" in the type_constants of the type variable representing T1.
31     /// This allows to properly check constraints on "T1::T".
32     pub type_constants: SMap<'a, (&'a aast::Sid, Ty<'a>)>,
33     /// Map associating PU information to each instance of
34     /// C:@E:@#v:@T
35     /// when the type variable #v is not resolved yet. We introduce a new type
36     /// variable to 'postpone' the checking of this expression until the end,
37     /// when #v will be known.
38     pub pu_accesses: SMap<'a, (Ty<'a>, &'a aast::Sid, Ty<'a>, &'a aast::Sid)>,
41 #[derive(Clone)]
42 pub enum SolvingInfo<'a> {
43     /// when the type variable is bound to a type
44     Type(Ty<'a>),
45     /// when the type variable is still unsolved
46     Constraints(&'a TyvarConstraints<'a>),
49 #[derive(Clone)]
50 pub struct TyvarInfoStruct<'a> {
51     /// Where was the type variable introduced? (e.g. generic method invocation,
52     /// new object construction)
53     pub tyvar_pos: &'a Pos,
54     pub global_reason: Option<PReason<'a>>,
55     pub eager_solve_failed: bool,
56     pub solving_info: SolvingInfo<'a>,
59 pub type TyvarInfo<'a> = &'a TyvarInfoStruct<'a>;
61 pub type Tvenv<'a> = IMap<'a, TyvarInfo<'a>>;
63 #[derive(Clone)]
64 pub struct TypingInferenceEnvStruct<'a> {
65     pub builder: &'a TypeBuilder<'a>,
66     pub tvenv: Tvenv<'a>,
67     pub tyvars_stack: Vec<'a, (&'a Pos, Vec<'a, Ident>)>,
68     pub tyvar_occurrences: &'a typing_tyvar_occurrences::TypingTyvarOccurrences<'a>,
69     pub allow_solve_globals: bool,
72 pub type TypingInferenceEnv<'a> = &'a TypingInferenceEnvStruct<'a>;
74 impl<'a> TypingInferenceEnvStruct<'a> {
75     pub fn expand_type(&mut self, ty: Ty<'a>) -> Ty<'a> {
76         let (r, ty_) = ty.unpack();
77         match ty_ {
78             Ty_::Tvar(v) => match self.expand_var(r, *v) {
79                 None => ty,
80                 Some(ty) => ty,
81             },
82             _ => ty,
83         }
84     }
86     fn expand_var(&mut self, r: PReason<'a>, v: Ident) -> Option<Ty<'a>> {
87         let ty = self.get_type(r, v);
88         // TODO(hrust) port eager_solve_fail logic
89         ty
90     }
92     fn get_type(&mut self, r: PReason<'a>, v: Ident) -> Option<Ty<'a>> {
93         let mut aliases = ISet::empty();
94         let mut v = v;
95         let mut r = r;
96         loop {
97             match self.tvenv.find(&v) {
98                 None => {
99                     // TODO: This should actually be an error
100                     return None;
101                 }
102                 Some(tvinfo) => match &tvinfo.solving_info {
103                     SolvingInfo::Type(ty) => {
104                         let (r0, ty_) = ty.unpack();
105                         r = r0;
106                         match ty_ {
107                             Ty_::Tvar(v0) => {
108                                 if aliases.mem(v0) {
109                                     panic!("Two type variables are aliasing each other!");
110                                 }
111                                 aliases = aliases.add(self.builder, *v0);
112                                 v = *v0;
113                                 continue;
114                             }
115                             _ => {
116                                 for alias in aliases.into_iter() {
117                                     self.add(*alias, *ty);
118                                 }
119                                 return Some(*ty);
120                             }
121                         }
122                     }
123                     SolvingInfo::Constraints(_) => {
124                         let ty = self.builder.tyvar(r, v);
125                         for alias in aliases.into_iter() {
126                             self.add(*alias, ty);
127                         }
128                         return Some(ty);
129                     }
130                 },
131             }
132         }
133     }
135     fn add(&mut self, v: Ident, ty: Ty<'a>) -> () {
136         self.bind(v, ty);
137         // TODO(hrust) update tyvar occurrences
138     }
140     fn bind(&mut self, v: Ident, ty: Ty<'a>) -> () {
141         /* TODO(hrust): the following indexing might panic,
142         as somehow sometimes we're missing variables in the environment,
143         The OCaml error, would create an empty tyvar_info in this case
144         to avoid throwing. */
146         let mut tvinfo = self.tvenv.find(&v).unwrap().clone();
147         tvinfo.solving_info = SolvingInfo::Type(ty);
148         self.tvenv = self.tvenv.add(self.builder, v, self.builder.alloc(tvinfo));
149     }