tint: Allow ConstEval functions to fail

They now return a utils::Result so they can add an error to diagnostics
and return Failure. Returning nullptr still means cannot evaluate at
compile time, but not a failure.

Bug: tint:1581
Change-Id: Ic30d782fb9fa725ec2faf89a87f74de6282d0304
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/98107
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index ab25bfb..317a91a 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -1501,7 +1501,12 @@
     }
 
     auto stage = sem::EarliestStage(obj->Stage(), idx->Stage());
-    auto val = const_eval_.Index(obj, idx);
+    const sem::Constant* val = nullptr;
+    if (auto r = const_eval_.Index(obj, idx)) {
+        val = r.Get();
+    } else {
+        return nullptr;
+    }
     bool has_side_effects = idx->HasSideEffects() || obj->HasSideEffects();
     auto* sem = builder_->create<sem::IndexAccessorExpression>(
         expr, ty, stage, obj, idx, current_statement_, std::move(val), has_side_effects,
@@ -1520,7 +1525,12 @@
         return nullptr;
     }
 
-    auto val = const_eval_.Bitcast(ty, inner);
+    const sem::Constant* val = nullptr;
+    if (auto r = const_eval_.Bitcast(ty, inner)) {
+        val = r.Get();
+    } else {
+        return nullptr;
+    }
     auto stage = sem::EvaluationStage::kRuntime;  // TODO(crbug.com/tint/1581)
     auto* sem = builder_->create<sem::Expression>(expr, ty, stage, current_statement_,
                                                   std::move(val), inner->HasSideEffects());
@@ -1575,8 +1585,12 @@
         const sem::Constant* value = nullptr;
         auto stage = sem::EarliestStage(ctor_or_conv.target->Stage(), args_stage);
         if (stage == sem::EvaluationStage::kConstant) {
-            value =
-                (const_eval_.*ctor_or_conv.const_eval_fn)(ctor_or_conv.target->ReturnType(), args);
+            if (auto r = (const_eval_.*ctor_or_conv.const_eval_fn)(
+                    ctor_or_conv.target->ReturnType(), args)) {
+                value = r.Get();
+            } else {
+                return nullptr;
+            }
         }
         return builder_->create<sem::Call>(expr, ctor_or_conv.target, stage, std::move(args),
                                            current_statement_, value, has_side_effects);
@@ -1593,7 +1607,11 @@
         auto stage = args_stage;               // The evaluation stage of the call
         const sem::Constant* value = nullptr;  // The constant value for the call
         if (stage == sem::EvaluationStage::kConstant) {
-            value = const_eval_.ArrayOrStructCtor(ty, args);
+            if (auto r = const_eval_.ArrayOrStructCtor(ty, args)) {
+                value = r.Get();
+            } else {
+                return nullptr;
+            }
             if (!value) {
                 // Constant evaluation failed.
                 // Can happen for expressions that will fail validation (later).
@@ -1873,7 +1891,11 @@
     // If the builtin is @const, and all arguments have constant values, evaluate the builtin now.
     const sem::Constant* value = nullptr;
     if (stage == sem::EvaluationStage::kConstant) {
-        value = (const_eval_.*builtin.const_eval_fn)(builtin.sem->ReturnType(), args);
+        if (auto r = (const_eval_.*builtin.const_eval_fn)(builtin.sem->ReturnType(), args)) {
+            value = r.Get();
+        } else {
+            return nullptr;
+        }
     }
 
     bool has_side_effects =
@@ -2035,7 +2057,12 @@
         return nullptr;
     }
 
-    auto val = const_eval_.Literal(ty, literal);
+    const sem::Constant* val = nullptr;
+    if (auto r = const_eval_.Literal(ty, literal)) {
+        val = r.Get();
+    } else {
+        return nullptr;
+    }
     return builder_->create<sem::Expression>(literal, ty, sem::EvaluationStage::kConstant,
                                              current_statement_, std::move(val),
                                              /* has_side_effects */ false);
@@ -2156,7 +2183,12 @@
             ret = builder_->create<sem::Reference>(ret, ref->StorageClass(), ref->Access());
         }
 
-        auto* val = const_eval_.MemberAccess(object, member);
+        const sem::Constant* val = nullptr;
+        if (auto r = const_eval_.MemberAccess(object, member)) {
+            val = r.Get();
+        } else {
+            return nullptr;
+        }
         return builder_->create<sem::StructMemberAccess>(expr, ret, current_statement_, val, object,
                                                          member, has_side_effects, source_var);
     }
@@ -2224,9 +2256,12 @@
             // the swizzle.
             ret = builder_->create<sem::Vector>(vec->type(), static_cast<uint32_t>(size));
         }
-        auto* val = const_eval_.Swizzle(ret, object, swizzle);
-        return builder_->create<sem::Swizzle>(expr, ret, current_statement_, val, object,
-                                              std::move(swizzle), has_side_effects, source_var);
+        if (auto r = const_eval_.Swizzle(ret, object, swizzle)) {
+            auto* val = r.Get();
+            return builder_->create<sem::Swizzle>(expr, ret, current_statement_, val, object,
+                                                  std::move(swizzle), has_side_effects, source_var);
+        }
+        return nullptr;
     }
 
     AddError("invalid member accessor expression. Expected vector or struct, got '" +
@@ -2240,7 +2275,6 @@
     const auto* rhs = sem_.Get(expr->rhs);
     auto* lhs_ty = lhs->Type()->UnwrapRef();
     auto* rhs_ty = rhs->Type()->UnwrapRef();
-    auto stage = sem::EvaluationStage::kRuntime;  // TODO(crbug.com/tint/1581)
 
     auto op = intrinsic_table_->Lookup(expr->op, lhs_ty, rhs_ty, expr->source, false);
     if (!op.result) {
@@ -2260,8 +2294,17 @@
     }
 
     const sem::Constant* value = nullptr;
-    if (op.const_eval_fn) {
-        value = (const_eval_.*op.const_eval_fn)(op.result, utils::Vector{lhs, rhs});
+    auto stage = sem::EarliestStage(lhs->Stage(), rhs->Stage());
+    if (stage == sem::EvaluationStage::kConstant) {
+        if (op.const_eval_fn) {
+            if (auto r = (const_eval_.*op.const_eval_fn)(op.result, utils::Vector{lhs, rhs})) {
+                value = r.Get();
+            } else {
+                return nullptr;
+            }
+        } else {
+            stage = sem::EvaluationStage::kRuntime;
+        }
     }
 
     bool has_side_effects = lhs->HasSideEffects() || rhs->HasSideEffects();
@@ -2337,7 +2380,11 @@
             stage = expr->Stage();
             if (stage == sem::EvaluationStage::kConstant) {
                 if (op.const_eval_fn) {
-                    value = (const_eval_.*op.const_eval_fn)(ty, utils::Vector{expr});
+                    if (auto r = (const_eval_.*op.const_eval_fn)(ty, utils::Vector{expr})) {
+                        value = r.Get();
+                    } else {
+                        return nullptr;
+                    }
                 } else {
                     stage = sem::EvaluationStage::kRuntime;
                 }