Fix typechecking of mutually recursive functions.
This commit is contained in:
@@ -486,17 +486,17 @@ we're trying to operate on is global or not? I propose a flag in our
|
||||
this, we update the implementation of `type_env` to map variables to
|
||||
values of a struct `variable_data`:
|
||||
|
||||
{{< codelines "C++" "compiler/12/type_env.hpp" 13 22 >}}
|
||||
{{< codelines "C++" "compiler/12/type_env.hpp" 14 23 >}}
|
||||
|
||||
The `visibility` enum is defined as follows:
|
||||
|
||||
{{< codelines "C++" "compiler/12/type_env.hpp" 10 10 >}}
|
||||
{{< codelines "C++" "compiler/12/type_env.hpp" 11 11 >}}
|
||||
|
||||
As you can see from the above snippet, we also added a `mangled_name` field
|
||||
to the new `variable_data` struct. We will be using this field shortly. We
|
||||
also add a few methods to our `type_env`, and end up with the following:
|
||||
|
||||
{{< codelines "C++" "compiler/12/type_env.hpp" 31 44 >}}
|
||||
{{< codelines "C++" "compiler/12/type_env.hpp" 32 45 >}}
|
||||
|
||||
We will come back to `find_free` and `find_free_except`, as well as
|
||||
`set_mangled_name` and `get_mangled_name`. For now, we just adjust `bind` to
|
||||
@@ -812,9 +812,12 @@ void type_env::find_free_except(const type_mgr& mgr, const std::string& avoid,
|
||||
Why `find_free_except`? When generalizing a variable whose type was already
|
||||
stored in the environment, all the type variables we could generalize would
|
||||
not be 'free'. If they only occur in the type we're generalizing, though,
|
||||
we shouldn't let that stop us! Thus, when finding free type variables, we will
|
||||
avoid looking at the particular variable whose type is being generalized. The
|
||||
implementations of the two methods are straightforward:
|
||||
we shouldn't let that stop us! More generally, if we see type variables that
|
||||
are only found in the same mutually recursive group as the binding we're
|
||||
generalizing, we are free to generalize them too. Thus, we pass in
|
||||
a reference to a `group`, and check if a variable is a member of that group
|
||||
before searching it for free type variables. The implementations of the two
|
||||
methods are straightforward:
|
||||
|
||||
{{< codelines "C++" "compiler/12/type_env.cpp" 4 18 >}}
|
||||
|
||||
@@ -824,7 +827,15 @@ that have the same name as the variable we're generalizing, but aren't found
|
||||
in the same scope. As far as we're concerned, they're different variables!
|
||||
The two methods use another `find_free` method which we add to `type_mgr`:
|
||||
|
||||
{{< codelines "C++" "compiler/12/type.cpp" 206 213 >}}
|
||||
{{< codelines "C++" "compiler/12/type.cpp" 206 219 >}}
|
||||
|
||||
This one is a bit of a hack. Typically, while running `find_free`, a
|
||||
`type_mgr` will resolve any type variables. However, variables from the
|
||||
`forall` quantifier of a type scheme should not be resolved, since they
|
||||
are explicitly generic. To prevent the type manager from erroneously resolving
|
||||
such type variables, we create a new type manager that does not have
|
||||
these variables bound to anything, and thus marks them as free. We then
|
||||
filter these variables out of the final list of free variables.
|
||||
|
||||
Finally, `generalize` makes sure not to use variables that it finds free:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user