Compiler: use freeze_type as node type if node doesn't have a type #7161
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #7160
When the compiler sees a method return type it will try to resolve it and then set it as the def's
@freeze_type
. This instance variable holds a type that eventually must match the type that is normally inferred. The compiler doesn't use@freeze_type
for anything else.This PR changes that: if there's no inferred type for a node but it has a
@freeze_type
, the node's type will be "inferred" to be that type. So if you say a method's return type isInt32
, even before the compiler can deduce its real type and see if it matchesInt32
it will have anInt32
type. This allows using the method in a recursive method and still be able to fully "infer" it's type (it's a bit of cheating because we are saying the type, but previously this didn't work).One example is the issue this PR solves:
Here the compiler will try to type
Tree.new(...).sum
and for that it will need to type@children.each.map(&.sum)
, which needs the type ofsum
, which isn't computed yet. The compiler before this PR would fail. With this PR it will succeed because we now know the type ofsum
.Don't worry: the compiler will later check that the type is effectively what we told it.
An interesting side effect of this change is that in these recursive scenarios the return type isn't a hint anymore, it's a type that's used for inference. For example, this works as well:
Because
@value
isInt32
andsum
is told to beFloat64
, the right-hand side expression@children...
is deduced to beFloat64
, andInt32 + Float64
givesFloat64
, so this compiles fine. It's a bit spooky, but it's fine :-)@bcardiff Would it be possible to run the script that checks the compiler works fine for many of the major crystal projects? This is a simple change, all specs pass, but I wonder if it could break something that I'm not seeing.