summaryrefslogtreecommitdiff
path: root/src/passes/Precompute.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/Precompute.cpp')
-rw-r--r--src/passes/Precompute.cpp24
1 files changed, 21 insertions, 3 deletions
diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp
index c07286ec9..3e2e7a64f 100644
--- a/src/passes/Precompute.cpp
+++ b/src/passes/Precompute.cpp
@@ -311,9 +311,27 @@ private:
// somehow know the entire expression precomputes to a 42, then we can
// propagate that 42 along to the users, regardless of whatever the call
// did globally.)
- auto values = setValues[set] =
- precomputeValue(Properties::getFallthrough(
- set->value, getPassOptions(), getModule()->features));
+ auto values = precomputeValue(Properties::getFallthrough(
+ set->value, getPassOptions(), getModule()->features));
+ // Fix up the value. The computation we just did was to look at the
+ // fallthrough, then precompute that; that looks through expressions
+ // that pass through the value. Normally that does not matter here,
+ // for example, (block .. (value)) returns the value unmodified.
+ // However, some things change the type, for example RefAsNonNull has
+ // a non-null type, while its input may be nullable. That does not
+ // matter either, as if we managed to precompute it then the value had
+ // the more specific (in this example, non-nullable) type. But there
+ // is a situation where this can cause an issue: RefCast. An attempt to
+ // perform a "bad" cast, say of a function to a struct, is a case where
+ // the fallthrough value's type is very different than the actually
+ // returned value's type. To handle that, if we precomputed a value and
+ // if it has the wrong type then precompute it again without looking
+ // through to the fallthrough.
+ if (values.isConcrete() &&
+ !Type::isSubType(values.getType(), set->value->type)) {
+ values = precomputeValue(set->value);
+ }
+ setValues[set] = values;
if (values.isConcrete()) {
for (auto* get : localGraph.setInfluences[set]) {
work.insert(get);