1 // Copyright (c) Facebook, Inc. and its affiliates.
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;
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;
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
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)>,
42 pub enum SolvingInfo<'a> {
43 /// when the type variable is bound to a type
45 /// when the type variable is still unsolved
46 Constraints(&'a TyvarConstraints<'a>),
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>>;
64 pub struct TypingInferenceEnvStruct<'a> {
65 pub builder: &'a TypeBuilder<'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();
78 Ty_::Tvar(v) => match self.expand_var(r, *v) {
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
92 fn get_type(&mut self, r: PReason<'a>, v: Ident) -> Option<Ty<'a>> {
93 let mut aliases = ISet::empty();
97 match self.tvenv.find(&v) {
99 // TODO: This should actually be an error
102 Some(tvinfo) => match &tvinfo.solving_info {
103 SolvingInfo::Type(ty) => {
104 let (r0, ty_) = ty.unpack();
109 panic!("Two type variables are aliasing each other!");
111 aliases = aliases.add(self.builder, *v0);
116 for alias in aliases.into_iter() {
117 self.add(*alias, *ty);
123 SolvingInfo::Constraints(_) => {
124 let ty = self.builder.tyvar(r, v);
125 for alias in aliases.into_iter() {
126 self.add(*alias, ty);
135 fn add(&mut self, v: Ident, ty: Ty<'a>) -> () {
137 // TODO(hrust) update tyvar occurrences
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));