tint: always pass in earliest evaluation stage to intrinsic table lookup
This fixes cases where input args of different type are mixed between constant and runtime evaluated. We initially did this only for builtins (https://dawn-review.googlesource.com/c/dawn/+/104545) to fix cases like `select`, but we also need this for binary operators like shift left/right that also take args of differing types. For consistency, this change also includes passing in the earliest evaluation stage when looking up unary ops and initializer/conversions. Bug: tint:1713 Change-Id: I196c67acfe767aa01aa45298d75cfc4d345d08ea Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/107140 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
6c8603cac1
commit
e0f78f924c
|
@ -995,17 +995,22 @@ class Impl : public IntrinsicTable {
|
||||||
sem::EvaluationStage earliest_eval_stage,
|
sem::EvaluationStage earliest_eval_stage,
|
||||||
const Source& source) override;
|
const Source& source) override;
|
||||||
|
|
||||||
UnaryOperator Lookup(ast::UnaryOp op, const sem::Type* arg, const Source& source) override;
|
UnaryOperator Lookup(ast::UnaryOp op,
|
||||||
|
const sem::Type* arg,
|
||||||
|
sem::EvaluationStage earliest_eval_stage,
|
||||||
|
const Source& source) override;
|
||||||
|
|
||||||
BinaryOperator Lookup(ast::BinaryOp op,
|
BinaryOperator Lookup(ast::BinaryOp op,
|
||||||
const sem::Type* lhs,
|
const sem::Type* lhs,
|
||||||
const sem::Type* rhs,
|
const sem::Type* rhs,
|
||||||
|
sem::EvaluationStage earliest_eval_stage,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
bool is_compound) override;
|
bool is_compound) override;
|
||||||
|
|
||||||
InitOrConv Lookup(InitConvIntrinsic type,
|
InitOrConv Lookup(InitConvIntrinsic type,
|
||||||
const sem::Type* template_arg,
|
const sem::Type* template_arg,
|
||||||
utils::VectorRef<const sem::Type*> args,
|
utils::VectorRef<const sem::Type*> args,
|
||||||
|
sem::EvaluationStage earliest_eval_stage,
|
||||||
const Source& source) override;
|
const Source& source) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1209,6 +1214,7 @@ Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type,
|
||||||
|
|
||||||
IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
|
IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
|
||||||
const sem::Type* arg,
|
const sem::Type* arg,
|
||||||
|
sem::EvaluationStage earliest_eval_stage,
|
||||||
const Source& source) {
|
const Source& source) {
|
||||||
auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair<size_t, const char*> {
|
auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair<size_t, const char*> {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
@ -1240,7 +1246,7 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
|
||||||
|
|
||||||
// Resolve the intrinsic overload
|
// Resolve the intrinsic overload
|
||||||
auto match = MatchIntrinsic(kUnaryOperators[intrinsic_index], intrinsic_name, args,
|
auto match = MatchIntrinsic(kUnaryOperators[intrinsic_index], intrinsic_name, args,
|
||||||
sem::EvaluationStage::kConstant, TemplateState{}, on_no_match);
|
earliest_eval_stage, TemplateState{}, on_no_match);
|
||||||
if (!match.overload) {
|
if (!match.overload) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -1255,6 +1261,7 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
|
||||||
IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
|
IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
|
||||||
const sem::Type* lhs,
|
const sem::Type* lhs,
|
||||||
const sem::Type* rhs,
|
const sem::Type* rhs,
|
||||||
|
sem::EvaluationStage earliest_eval_stage,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
bool is_compound) {
|
bool is_compound) {
|
||||||
auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair<size_t, const char*> {
|
auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair<size_t, const char*> {
|
||||||
|
@ -1317,7 +1324,7 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
|
||||||
|
|
||||||
// Resolve the intrinsic overload
|
// Resolve the intrinsic overload
|
||||||
auto match = MatchIntrinsic(kBinaryOperators[intrinsic_index], intrinsic_name, args,
|
auto match = MatchIntrinsic(kBinaryOperators[intrinsic_index], intrinsic_name, args,
|
||||||
sem::EvaluationStage::kConstant, TemplateState{}, on_no_match);
|
earliest_eval_stage, TemplateState{}, on_no_match);
|
||||||
if (!match.overload) {
|
if (!match.overload) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -1333,6 +1340,7 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
|
||||||
IntrinsicTable::InitOrConv Impl::Lookup(InitConvIntrinsic type,
|
IntrinsicTable::InitOrConv Impl::Lookup(InitConvIntrinsic type,
|
||||||
const sem::Type* template_arg,
|
const sem::Type* template_arg,
|
||||||
utils::VectorRef<const sem::Type*> args,
|
utils::VectorRef<const sem::Type*> args,
|
||||||
|
sem::EvaluationStage earliest_eval_stage,
|
||||||
const Source& source) {
|
const Source& source) {
|
||||||
auto name = str(type);
|
auto name = str(type);
|
||||||
|
|
||||||
|
@ -1372,7 +1380,7 @@ IntrinsicTable::InitOrConv Impl::Lookup(InitConvIntrinsic type,
|
||||||
|
|
||||||
// Resolve the intrinsic overload
|
// Resolve the intrinsic overload
|
||||||
auto match = MatchIntrinsic(kInitializersAndConverters[static_cast<size_t>(type)], name, args,
|
auto match = MatchIntrinsic(kInitializersAndConverters[static_cast<size_t>(type)], name, args,
|
||||||
sem::EvaluationStage::kConstant, templates, on_no_match);
|
earliest_eval_stage, templates, on_no_match);
|
||||||
if (!match.overload) {
|
if (!match.overload) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -1641,6 +1649,7 @@ void Impl::PrintOverload(std::ostream& ss,
|
||||||
const char* intrinsic_name) const {
|
const char* intrinsic_name) const {
|
||||||
TemplateState templates;
|
TemplateState templates;
|
||||||
|
|
||||||
|
// TODO(crbug.com/tint/1730): Use input evaluation stage to output only relevant overloads.
|
||||||
auto earliest_eval_stage = sem::EvaluationStage::kConstant;
|
auto earliest_eval_stage = sem::EvaluationStage::kConstant;
|
||||||
|
|
||||||
ss << intrinsic_name;
|
ss << intrinsic_name;
|
||||||
|
|
|
@ -87,7 +87,7 @@ class IntrinsicTable {
|
||||||
/// @param earliest_eval_stage the the earliest evaluation stage that a call to
|
/// @param earliest_eval_stage the the earliest evaluation stage that a call to
|
||||||
/// the builtin can be made. This can alter the overloads considered.
|
/// the builtin can be made. This can alter the overloads considered.
|
||||||
/// For example, if the earliest evaluation stage is
|
/// For example, if the earliest evaluation stage is
|
||||||
/// `sem::EvaluationStage::kRuntime`, then only concrete argument types
|
/// `sem::EvaluationStage::kRuntime`, then only overloads with concrete argument types
|
||||||
/// will be considered, as all abstract-numerics will have been materialized
|
/// will be considered, as all abstract-numerics will have been materialized
|
||||||
/// after shader creation time (sem::EvaluationStage::kConstant).
|
/// after shader creation time (sem::EvaluationStage::kConstant).
|
||||||
/// @param source the source of the builtin call
|
/// @param source the source of the builtin call
|
||||||
|
@ -101,10 +101,19 @@ class IntrinsicTable {
|
||||||
/// diagnostic if the operator was not found.
|
/// diagnostic if the operator was not found.
|
||||||
/// @param op the unary operator
|
/// @param op the unary operator
|
||||||
/// @param arg the type of the expression passed to the operator
|
/// @param arg the type of the expression passed to the operator
|
||||||
|
/// @param earliest_eval_stage the the earliest evaluation stage that a call to
|
||||||
|
/// the unary operator can be made. This can alter the overloads considered.
|
||||||
|
/// For example, if the earliest evaluation stage is
|
||||||
|
/// `sem::EvaluationStage::kRuntime`, then only overloads with concrete argument types
|
||||||
|
/// will be considered, as all abstract-numerics will have been materialized
|
||||||
|
/// after shader creation time (sem::EvaluationStage::kConstant).
|
||||||
/// @param source the source of the operator call
|
/// @param source the source of the operator call
|
||||||
/// @return the operator call target signature. If the operator was not found
|
/// @return the operator call target signature. If the operator was not found
|
||||||
/// UnaryOperator::result will be nullptr.
|
/// UnaryOperator::result will be nullptr.
|
||||||
virtual UnaryOperator Lookup(ast::UnaryOp op, const sem::Type* arg, const Source& source) = 0;
|
virtual UnaryOperator Lookup(ast::UnaryOp op,
|
||||||
|
const sem::Type* arg,
|
||||||
|
sem::EvaluationStage earliest_eval_stage,
|
||||||
|
const Source& source) = 0;
|
||||||
|
|
||||||
/// Lookup looks for the binary op overload with the given signature, raising an error
|
/// Lookup looks for the binary op overload with the given signature, raising an error
|
||||||
/// diagnostic if the operator was not found.
|
/// diagnostic if the operator was not found.
|
||||||
|
@ -112,12 +121,19 @@ class IntrinsicTable {
|
||||||
/// @param lhs the LHS value type passed to the operator
|
/// @param lhs the LHS value type passed to the operator
|
||||||
/// @param rhs the RHS value type passed to the operator
|
/// @param rhs the RHS value type passed to the operator
|
||||||
/// @param source the source of the operator call
|
/// @param source the source of the operator call
|
||||||
|
/// @param earliest_eval_stage the the earliest evaluation stage that a call to
|
||||||
|
/// the binary operator can be made. This can alter the overloads considered.
|
||||||
|
/// For example, if the earliest evaluation stage is
|
||||||
|
/// `sem::EvaluationStage::kRuntime`, then only overloads with concrete argument types
|
||||||
|
/// will be considered, as all abstract-numerics will have been materialized
|
||||||
|
/// after shader creation time (sem::EvaluationStage::kConstant).
|
||||||
/// @param is_compound true if the binary operator is being used as a compound assignment
|
/// @param is_compound true if the binary operator is being used as a compound assignment
|
||||||
/// @return the operator call target signature. If the operator was not found
|
/// @return the operator call target signature. If the operator was not found
|
||||||
/// BinaryOperator::result will be nullptr.
|
/// BinaryOperator::result will be nullptr.
|
||||||
virtual BinaryOperator Lookup(ast::BinaryOp op,
|
virtual BinaryOperator Lookup(ast::BinaryOp op,
|
||||||
const sem::Type* lhs,
|
const sem::Type* lhs,
|
||||||
const sem::Type* rhs,
|
const sem::Type* rhs,
|
||||||
|
sem::EvaluationStage earliest_eval_stage,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
bool is_compound) = 0;
|
bool is_compound) = 0;
|
||||||
|
|
||||||
|
@ -126,11 +142,19 @@ class IntrinsicTable {
|
||||||
/// @param type the type being constructed or converted
|
/// @param type the type being constructed or converted
|
||||||
/// @param template_arg the optional template argument
|
/// @param template_arg the optional template argument
|
||||||
/// @param args the argument types passed to the initializer / conversion call
|
/// @param args the argument types passed to the initializer / conversion call
|
||||||
|
/// @param earliest_eval_stage the the earliest evaluation stage that a call to
|
||||||
|
/// the initializer or conversion can be made. This can alter the overloads considered.
|
||||||
|
/// For example, if the earliest evaluation stage is
|
||||||
|
/// `sem::EvaluationStage::kRuntime`, then only overloads with concrete argument types
|
||||||
|
/// will be considered, as all abstract-numerics will have been materialized
|
||||||
|
/// after shader creation time (sem::EvaluationStage::kConstant).
|
||||||
|
|
||||||
/// @param source the source of the call
|
/// @param source the source of the call
|
||||||
/// @return a sem::TypeInitializer, sem::TypeConversion or nullptr if nothing matched
|
/// @return a sem::TypeInitializer, sem::TypeConversion or nullptr if nothing matched
|
||||||
virtual InitOrConv Lookup(InitConvIntrinsic type,
|
virtual InitOrConv Lookup(InitConvIntrinsic type,
|
||||||
const sem::Type* template_arg,
|
const sem::Type* template_arg,
|
||||||
utils::VectorRef<const sem::Type*> args,
|
utils::VectorRef<const sem::Type*> args,
|
||||||
|
sem::EvaluationStage earliest_eval_stage,
|
||||||
const Source& source) = 0;
|
const Source& source) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -527,13 +527,14 @@ TEST_F(IntrinsicTableTest, MismatchOpenSizeMatrix) {
|
||||||
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
|
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_ConstantEval) {
|
TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Builtin_ConstantEval) {
|
||||||
auto* af = create<sem::AbstractFloat>();
|
auto* af = create<sem::AbstractFloat>();
|
||||||
auto* bool_ = create<sem::Bool>();
|
auto* bool_ = create<sem::Bool>();
|
||||||
auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{af, af, bool_},
|
auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{af, af, bool_},
|
||||||
sem::EvaluationStage::kConstant, Source{});
|
sem::EvaluationStage::kConstant, Source{});
|
||||||
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
|
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
|
||||||
ASSERT_EQ(Diagnostics().str(), "");
|
ASSERT_EQ(Diagnostics().str(), "");
|
||||||
|
EXPECT_EQ(result.sem->Stage(), sem::EvaluationStage::kConstant);
|
||||||
EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
|
EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
|
||||||
EXPECT_EQ(result.sem->ReturnType(), af);
|
EXPECT_EQ(result.sem->ReturnType(), af);
|
||||||
ASSERT_EQ(result.sem->Parameters().Length(), 3u);
|
ASSERT_EQ(result.sem->Parameters().Length(), 3u);
|
||||||
|
@ -542,7 +543,7 @@ TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_ConstantEval) {
|
||||||
EXPECT_EQ(result.sem->Parameters()[2]->Type(), bool_);
|
EXPECT_EQ(result.sem->Parameters()[2]->Type(), bool_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_RuntimeEval) {
|
TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Builtin_RuntimeEval) {
|
||||||
auto* af = create<sem::AbstractFloat>();
|
auto* af = create<sem::AbstractFloat>();
|
||||||
auto* bool_ref = create<sem::Reference>(create<sem::Bool>(), ast::AddressSpace::kFunction,
|
auto* bool_ref = create<sem::Reference>(create<sem::Bool>(), ast::AddressSpace::kFunction,
|
||||||
ast::Access::kReadWrite);
|
ast::Access::kReadWrite);
|
||||||
|
@ -550,6 +551,7 @@ TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_RuntimeEval) {
|
||||||
sem::EvaluationStage::kRuntime, Source{});
|
sem::EvaluationStage::kRuntime, Source{});
|
||||||
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
|
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
|
||||||
ASSERT_EQ(Diagnostics().str(), "");
|
ASSERT_EQ(Diagnostics().str(), "");
|
||||||
|
EXPECT_EQ(result.sem->Stage(), sem::EvaluationStage::kConstant);
|
||||||
EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
|
EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
|
||||||
EXPECT_TRUE(result.sem->ReturnType()->Is<sem::F32>());
|
EXPECT_TRUE(result.sem->ReturnType()->Is<sem::F32>());
|
||||||
ASSERT_EQ(result.sem->Parameters().Length(), 3u);
|
ASSERT_EQ(result.sem->Parameters().Length(), 3u);
|
||||||
|
@ -558,6 +560,33 @@ TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_RuntimeEval) {
|
||||||
EXPECT_TRUE(result.sem->Parameters()[2]->Type()->Is<sem::Bool>());
|
EXPECT_TRUE(result.sem->Parameters()[2]->Type()->Is<sem::Bool>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(amaiorano): Enable once const eval of left shift lands
|
||||||
|
TEST_F(IntrinsicTableTest, DISABLED_MatchDifferentArgsElementType_Binary_ConstantEval) {
|
||||||
|
auto* ai = create<sem::AbstractInt>();
|
||||||
|
auto* u32 = create<sem::U32>();
|
||||||
|
auto result = table->Lookup(ast::BinaryOp::kShiftLeft, ai, u32, sem::EvaluationStage::kConstant,
|
||||||
|
Source{}, false);
|
||||||
|
ASSERT_NE(result.result, nullptr) << Diagnostics().str();
|
||||||
|
ASSERT_NE(result.const_eval_fn, nullptr) << Diagnostics().str();
|
||||||
|
ASSERT_EQ(Diagnostics().str(), "");
|
||||||
|
EXPECT_EQ(result.result, ai);
|
||||||
|
EXPECT_EQ(result.lhs, ai);
|
||||||
|
EXPECT_EQ(result.rhs, u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Binary_RuntimeEval) {
|
||||||
|
auto* ai = create<sem::AbstractInt>();
|
||||||
|
auto* u32 = create<sem::U32>();
|
||||||
|
auto result = table->Lookup(ast::BinaryOp::kShiftLeft, ai, u32, sem::EvaluationStage::kRuntime,
|
||||||
|
Source{}, false);
|
||||||
|
ASSERT_NE(result.result, nullptr) << Diagnostics().str();
|
||||||
|
ASSERT_NE(result.const_eval_fn, nullptr) << Diagnostics().str();
|
||||||
|
ASSERT_EQ(Diagnostics().str(), "");
|
||||||
|
EXPECT_TRUE(result.result->Is<sem::I32>());
|
||||||
|
EXPECT_TRUE(result.lhs->Is<sem::I32>());
|
||||||
|
EXPECT_TRUE(result.rhs->Is<sem::U32>());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) {
|
TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) {
|
||||||
// None of the arguments match, so expect the overloads with 2 parameters to
|
// None of the arguments match, so expect the overloads with 2 parameters to
|
||||||
// come first
|
// come first
|
||||||
|
@ -663,15 +692,16 @@ TEST_F(IntrinsicTableTest, SameOverloadReturnsSameBuiltinPointer) {
|
||||||
TEST_F(IntrinsicTableTest, MatchUnaryOp) {
|
TEST_F(IntrinsicTableTest, MatchUnaryOp) {
|
||||||
auto* i32 = create<sem::I32>();
|
auto* i32 = create<sem::I32>();
|
||||||
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
||||||
auto result = table->Lookup(ast::UnaryOp::kNegation, vec3_i32, Source{{12, 34}});
|
auto result = table->Lookup(ast::UnaryOp::kNegation, vec3_i32, sem::EvaluationStage::kConstant,
|
||||||
EXPECT_EQ(result.result, vec3_i32);
|
Source{{12, 34}});
|
||||||
EXPECT_EQ(result.result, vec3_i32);
|
EXPECT_EQ(result.result, vec3_i32);
|
||||||
EXPECT_EQ(Diagnostics().str(), "");
|
EXPECT_EQ(Diagnostics().str(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicTableTest, MismatchUnaryOp) {
|
TEST_F(IntrinsicTableTest, MismatchUnaryOp) {
|
||||||
auto* bool_ = create<sem::Bool>();
|
auto* bool_ = create<sem::Bool>();
|
||||||
auto result = table->Lookup(ast::UnaryOp::kNegation, bool_, Source{{12, 34}});
|
auto result = table->Lookup(ast::UnaryOp::kNegation, bool_, sem::EvaluationStage::kConstant,
|
||||||
|
Source{{12, 34}});
|
||||||
ASSERT_EQ(result.result, nullptr);
|
ASSERT_EQ(result.result, nullptr);
|
||||||
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator - (bool)
|
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator - (bool)
|
||||||
|
|
||||||
|
@ -681,10 +711,28 @@ TEST_F(IntrinsicTableTest, MismatchUnaryOp) {
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchUnaryOp_Constant) {
|
||||||
|
auto* ai = create<sem::AbstractInt>();
|
||||||
|
auto result = table->Lookup(ast::UnaryOp::kNegation, ai, sem::EvaluationStage::kConstant,
|
||||||
|
Source{{12, 34}});
|
||||||
|
EXPECT_EQ(result.result, ai);
|
||||||
|
EXPECT_EQ(Diagnostics().str(), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchUnaryOp_Runtime) {
|
||||||
|
auto* ai = create<sem::AbstractInt>();
|
||||||
|
auto result = table->Lookup(ast::UnaryOp::kNegation, ai, sem::EvaluationStage::kRuntime,
|
||||||
|
Source{{12, 34}});
|
||||||
|
EXPECT_NE(result.result, ai);
|
||||||
|
EXPECT_TRUE(result.result->Is<sem::I32>());
|
||||||
|
EXPECT_EQ(Diagnostics().str(), "");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicTableTest, MatchBinaryOp) {
|
TEST_F(IntrinsicTableTest, MatchBinaryOp) {
|
||||||
auto* i32 = create<sem::I32>();
|
auto* i32 = create<sem::I32>();
|
||||||
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
||||||
auto result = table->Lookup(ast::BinaryOp::kMultiply, i32, vec3_i32, Source{{12, 34}},
|
auto result = table->Lookup(ast::BinaryOp::kMultiply, i32, vec3_i32,
|
||||||
|
sem::EvaluationStage::kConstant, Source{{12, 34}},
|
||||||
/* is_compound */ false);
|
/* is_compound */ false);
|
||||||
EXPECT_EQ(result.result, vec3_i32);
|
EXPECT_EQ(result.result, vec3_i32);
|
||||||
EXPECT_EQ(result.lhs, i32);
|
EXPECT_EQ(result.lhs, i32);
|
||||||
|
@ -695,7 +743,8 @@ TEST_F(IntrinsicTableTest, MatchBinaryOp) {
|
||||||
TEST_F(IntrinsicTableTest, MismatchBinaryOp) {
|
TEST_F(IntrinsicTableTest, MismatchBinaryOp) {
|
||||||
auto* f32 = create<sem::F32>();
|
auto* f32 = create<sem::F32>();
|
||||||
auto* bool_ = create<sem::Bool>();
|
auto* bool_ = create<sem::Bool>();
|
||||||
auto result = table->Lookup(ast::BinaryOp::kMultiply, f32, bool_, Source{{12, 34}},
|
auto result = table->Lookup(ast::BinaryOp::kMultiply, f32, bool_,
|
||||||
|
sem::EvaluationStage::kConstant, Source{{12, 34}},
|
||||||
/* is_compound */ false);
|
/* is_compound */ false);
|
||||||
ASSERT_EQ(result.result, nullptr);
|
ASSERT_EQ(result.result, nullptr);
|
||||||
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator * (f32, bool)
|
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator * (f32, bool)
|
||||||
|
@ -716,7 +765,8 @@ TEST_F(IntrinsicTableTest, MismatchBinaryOp) {
|
||||||
TEST_F(IntrinsicTableTest, MatchCompoundOp) {
|
TEST_F(IntrinsicTableTest, MatchCompoundOp) {
|
||||||
auto* i32 = create<sem::I32>();
|
auto* i32 = create<sem::I32>();
|
||||||
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
||||||
auto result = table->Lookup(ast::BinaryOp::kMultiply, i32, vec3_i32, Source{{12, 34}},
|
auto result = table->Lookup(ast::BinaryOp::kMultiply, i32, vec3_i32,
|
||||||
|
sem::EvaluationStage::kConstant, Source{{12, 34}},
|
||||||
/* is_compound */ true);
|
/* is_compound */ true);
|
||||||
EXPECT_EQ(result.result, vec3_i32);
|
EXPECT_EQ(result.result, vec3_i32);
|
||||||
EXPECT_EQ(result.lhs, i32);
|
EXPECT_EQ(result.lhs, i32);
|
||||||
|
@ -727,7 +777,8 @@ TEST_F(IntrinsicTableTest, MatchCompoundOp) {
|
||||||
TEST_F(IntrinsicTableTest, MismatchCompoundOp) {
|
TEST_F(IntrinsicTableTest, MismatchCompoundOp) {
|
||||||
auto* f32 = create<sem::F32>();
|
auto* f32 = create<sem::F32>();
|
||||||
auto* bool_ = create<sem::Bool>();
|
auto* bool_ = create<sem::Bool>();
|
||||||
auto result = table->Lookup(ast::BinaryOp::kMultiply, f32, bool_, Source{{12, 34}},
|
auto result = table->Lookup(ast::BinaryOp::kMultiply, f32, bool_,
|
||||||
|
sem::EvaluationStage::kConstant, Source{{12, 34}},
|
||||||
/* is_compound */ true);
|
/* is_compound */ true);
|
||||||
ASSERT_EQ(result.result, nullptr);
|
ASSERT_EQ(result.result, nullptr);
|
||||||
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator *= (f32, bool)
|
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator *= (f32, bool)
|
||||||
|
@ -749,7 +800,7 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicit) {
|
||||||
auto* i32 = create<sem::I32>();
|
auto* i32 = create<sem::I32>();
|
||||||
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
||||||
auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{i32, i32, i32},
|
auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{i32, i32, i32},
|
||||||
Source{{12, 34}});
|
sem::EvaluationStage::kConstant, Source{{12, 34}});
|
||||||
ASSERT_NE(result.target, nullptr);
|
ASSERT_NE(result.target, nullptr);
|
||||||
EXPECT_EQ(result.target->ReturnType(), vec3_i32);
|
EXPECT_EQ(result.target->ReturnType(), vec3_i32);
|
||||||
EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
|
EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
|
||||||
|
@ -764,7 +815,7 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerExplicit) {
|
||||||
auto* i32 = create<sem::I32>();
|
auto* i32 = create<sem::I32>();
|
||||||
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
||||||
auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{i32, i32, i32},
|
auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{i32, i32, i32},
|
||||||
Source{{12, 34}});
|
sem::EvaluationStage::kConstant, Source{{12, 34}});
|
||||||
ASSERT_NE(result.target, nullptr);
|
ASSERT_NE(result.target, nullptr);
|
||||||
EXPECT_EQ(result.target->ReturnType(), vec3_i32);
|
EXPECT_EQ(result.target->ReturnType(), vec3_i32);
|
||||||
EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
|
EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
|
||||||
|
@ -779,7 +830,7 @@ TEST_F(IntrinsicTableTest, MismatchTypeInitializerImplicit) {
|
||||||
auto* i32 = create<sem::I32>();
|
auto* i32 = create<sem::I32>();
|
||||||
auto* f32 = create<sem::F32>();
|
auto* f32 = create<sem::F32>();
|
||||||
auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{i32, f32, i32},
|
auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{i32, f32, i32},
|
||||||
Source{{12, 34}});
|
sem::EvaluationStage::kConstant, Source{{12, 34}});
|
||||||
ASSERT_EQ(result.target, nullptr);
|
ASSERT_EQ(result.target, nullptr);
|
||||||
EXPECT_EQ(Diagnostics().str(),
|
EXPECT_EQ(Diagnostics().str(),
|
||||||
R"(12:34 error: no matching initializer for vec3(i32, f32, i32)
|
R"(12:34 error: no matching initializer for vec3(i32, f32, i32)
|
||||||
|
@ -805,7 +856,7 @@ TEST_F(IntrinsicTableTest, MismatchTypeInitializerExplicit) {
|
||||||
auto* i32 = create<sem::I32>();
|
auto* i32 = create<sem::I32>();
|
||||||
auto* f32 = create<sem::F32>();
|
auto* f32 = create<sem::F32>();
|
||||||
auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{i32, f32, i32},
|
auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{i32, f32, i32},
|
||||||
Source{{12, 34}});
|
sem::EvaluationStage::kConstant, Source{{12, 34}});
|
||||||
ASSERT_EQ(result.target, nullptr);
|
ASSERT_EQ(result.target, nullptr);
|
||||||
EXPECT_EQ(Diagnostics().str(),
|
EXPECT_EQ(Diagnostics().str(),
|
||||||
R"(12:34 error: no matching initializer for vec3<i32>(i32, f32, i32)
|
R"(12:34 error: no matching initializer for vec3<i32>(i32, f32, i32)
|
||||||
|
@ -832,8 +883,9 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicitMatFromVec) {
|
||||||
auto* vec2_ai = create<sem::Vector>(create<sem::AbstractInt>(), 2u);
|
auto* vec2_ai = create<sem::Vector>(create<sem::AbstractInt>(), 2u);
|
||||||
auto* vec2_af = create<sem::Vector>(af, 2u);
|
auto* vec2_af = create<sem::Vector>(af, 2u);
|
||||||
auto* mat2x2_af = create<sem::Matrix>(vec2_af, 2u);
|
auto* mat2x2_af = create<sem::Matrix>(vec2_af, 2u);
|
||||||
auto result = table->Lookup(InitConvIntrinsic::kMat2x2, nullptr,
|
auto result =
|
||||||
utils::Vector{vec2_ai, vec2_ai}, Source{{12, 34}});
|
table->Lookup(InitConvIntrinsic::kMat2x2, nullptr, utils::Vector{vec2_ai, vec2_ai},
|
||||||
|
sem::EvaluationStage::kConstant, Source{{12, 34}});
|
||||||
ASSERT_NE(result.target, nullptr);
|
ASSERT_NE(result.target, nullptr);
|
||||||
EXPECT_TYPE(result.target->ReturnType(), mat2x2_af);
|
EXPECT_TYPE(result.target->ReturnType(), mat2x2_af);
|
||||||
EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
|
EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
|
||||||
|
@ -843,13 +895,46 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicitMatFromVec) {
|
||||||
EXPECT_NE(result.const_eval_fn, nullptr);
|
EXPECT_NE(result.const_eval_fn, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchTypeInitializer_ConstantEval) {
|
||||||
|
auto* ai = create<sem::AbstractInt>();
|
||||||
|
auto* vec3_ai = create<sem::Vector>(ai, 3u);
|
||||||
|
auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{ai, ai, ai},
|
||||||
|
sem::EvaluationStage::kConstant, Source{{12, 34}});
|
||||||
|
ASSERT_NE(result.target, nullptr);
|
||||||
|
EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant);
|
||||||
|
EXPECT_EQ(result.target->ReturnType(), vec3_ai);
|
||||||
|
EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
|
||||||
|
ASSERT_EQ(result.target->Parameters().Length(), 3u);
|
||||||
|
EXPECT_EQ(result.target->Parameters()[0]->Type(), ai);
|
||||||
|
EXPECT_EQ(result.target->Parameters()[1]->Type(), ai);
|
||||||
|
EXPECT_EQ(result.target->Parameters()[2]->Type(), ai);
|
||||||
|
EXPECT_NE(result.const_eval_fn, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchTypeInitializer_RuntimeEval) {
|
||||||
|
auto* ai = create<sem::AbstractInt>();
|
||||||
|
auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{ai, ai, ai},
|
||||||
|
sem::EvaluationStage::kRuntime, Source{{12, 34}});
|
||||||
|
auto* i32 = create<sem::I32>();
|
||||||
|
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
||||||
|
ASSERT_NE(result.target, nullptr);
|
||||||
|
EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant);
|
||||||
|
EXPECT_EQ(result.target->ReturnType(), vec3_i32);
|
||||||
|
EXPECT_TRUE(result.target->Is<sem::TypeInitializer>());
|
||||||
|
ASSERT_EQ(result.target->Parameters().Length(), 3u);
|
||||||
|
EXPECT_EQ(result.target->Parameters()[0]->Type(), i32);
|
||||||
|
EXPECT_EQ(result.target->Parameters()[1]->Type(), i32);
|
||||||
|
EXPECT_EQ(result.target->Parameters()[2]->Type(), i32);
|
||||||
|
EXPECT_NE(result.const_eval_fn, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicTableTest, MatchTypeConversion) {
|
TEST_F(IntrinsicTableTest, MatchTypeConversion) {
|
||||||
auto* i32 = create<sem::I32>();
|
auto* i32 = create<sem::I32>();
|
||||||
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
||||||
auto* f32 = create<sem::F32>();
|
auto* f32 = create<sem::F32>();
|
||||||
auto* vec3_f32 = create<sem::Vector>(f32, 3u);
|
auto* vec3_f32 = create<sem::Vector>(f32, 3u);
|
||||||
auto result =
|
auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{vec3_f32},
|
||||||
table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{vec3_f32}, Source{{12, 34}});
|
sem::EvaluationStage::kConstant, Source{{12, 34}});
|
||||||
ASSERT_NE(result.target, nullptr);
|
ASSERT_NE(result.target, nullptr);
|
||||||
EXPECT_EQ(result.target->ReturnType(), vec3_i32);
|
EXPECT_EQ(result.target->ReturnType(), vec3_i32);
|
||||||
EXPECT_TRUE(result.target->Is<sem::TypeConversion>());
|
EXPECT_TRUE(result.target->Is<sem::TypeConversion>());
|
||||||
|
@ -860,8 +945,8 @@ TEST_F(IntrinsicTableTest, MatchTypeConversion) {
|
||||||
TEST_F(IntrinsicTableTest, MismatchTypeConversion) {
|
TEST_F(IntrinsicTableTest, MismatchTypeConversion) {
|
||||||
auto* arr = create<sem::Array>(create<sem::U32>(), sem::RuntimeArrayCount{}, 4u, 4u, 4u, 4u);
|
auto* arr = create<sem::Array>(create<sem::U32>(), sem::RuntimeArrayCount{}, 4u, 4u, 4u, 4u);
|
||||||
auto* f32 = create<sem::F32>();
|
auto* f32 = create<sem::F32>();
|
||||||
auto result =
|
auto result = table->Lookup(InitConvIntrinsic::kVec3, f32, utils::Vector{arr},
|
||||||
table->Lookup(InitConvIntrinsic::kVec3, f32, utils::Vector{arr}, Source{{12, 34}});
|
sem::EvaluationStage::kConstant, Source{{12, 34}});
|
||||||
ASSERT_EQ(result.target, nullptr);
|
ASSERT_EQ(result.target, nullptr);
|
||||||
EXPECT_EQ(Diagnostics().str(),
|
EXPECT_EQ(Diagnostics().str(),
|
||||||
R"(12:34 error: no matching initializer for vec3<f32>(array<u32>)
|
R"(12:34 error: no matching initializer for vec3<f32>(array<u32>)
|
||||||
|
@ -883,6 +968,39 @@ TEST_F(IntrinsicTableTest, MismatchTypeConversion) {
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchTypeConversion_ConstantEval) {
|
||||||
|
auto* ai = create<sem::AbstractInt>();
|
||||||
|
auto* af = create<sem::AbstractFloat>();
|
||||||
|
auto* vec3_ai = create<sem::Vector>(ai, 3u);
|
||||||
|
auto* f32 = create<sem::F32>();
|
||||||
|
auto* vec3_f32 = create<sem::Vector>(f32, 3u);
|
||||||
|
auto result = table->Lookup(InitConvIntrinsic::kVec3, af, utils::Vector{vec3_ai},
|
||||||
|
sem::EvaluationStage::kConstant, Source{{12, 34}});
|
||||||
|
ASSERT_NE(result.target, nullptr);
|
||||||
|
EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant);
|
||||||
|
// NOTE: Conversions are explicit, so there's no way to have it return abstracts
|
||||||
|
EXPECT_EQ(result.target->ReturnType(), vec3_f32);
|
||||||
|
EXPECT_TRUE(result.target->Is<sem::TypeConversion>());
|
||||||
|
ASSERT_EQ(result.target->Parameters().Length(), 1u);
|
||||||
|
EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicTableTest, MatchTypeConversion_RuntimeEval) {
|
||||||
|
auto* ai = create<sem::AbstractInt>();
|
||||||
|
auto* af = create<sem::AbstractFloat>();
|
||||||
|
auto* vec3_ai = create<sem::Vector>(ai, 3u);
|
||||||
|
auto* vec3_f32 = create<sem::Vector>(create<sem::F32>(), 3u);
|
||||||
|
auto* vec3_i32 = create<sem::Vector>(create<sem::I32>(), 3u);
|
||||||
|
auto result = table->Lookup(InitConvIntrinsic::kVec3, af, utils::Vector{vec3_ai},
|
||||||
|
sem::EvaluationStage::kRuntime, Source{{12, 34}});
|
||||||
|
ASSERT_NE(result.target, nullptr);
|
||||||
|
EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant);
|
||||||
|
EXPECT_EQ(result.target->ReturnType(), vec3_f32);
|
||||||
|
EXPECT_TRUE(result.target->Is<sem::TypeConversion>());
|
||||||
|
ASSERT_EQ(result.target->Parameters().Length(), 1u);
|
||||||
|
EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_i32);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicTableTest, Err257Arguments) { // crbug.com/1323605
|
TEST_F(IntrinsicTableTest, Err257Arguments) { // crbug.com/1323605
|
||||||
auto* f32 = create<sem::F32>();
|
auto* f32 = create<sem::F32>();
|
||||||
utils::Vector<const sem::Type*, 0> arg_tys;
|
utils::Vector<const sem::Type*, 0> arg_tys;
|
||||||
|
@ -900,7 +1018,8 @@ TEST_F(IntrinsicTableTest, OverloadResolution) {
|
||||||
// The first should win overload resolution.
|
// The first should win overload resolution.
|
||||||
auto* ai = create<sem::AbstractInt>();
|
auto* ai = create<sem::AbstractInt>();
|
||||||
auto* i32 = create<sem::I32>();
|
auto* i32 = create<sem::I32>();
|
||||||
auto result = table->Lookup(InitConvIntrinsic::kI32, nullptr, utils::Vector{ai}, Source{});
|
auto result = table->Lookup(InitConvIntrinsic::kI32, nullptr, utils::Vector{ai},
|
||||||
|
sem::EvaluationStage::kConstant, Source{});
|
||||||
ASSERT_NE(result.target, nullptr);
|
ASSERT_NE(result.target, nullptr);
|
||||||
EXPECT_EQ(result.target->ReturnType(), i32);
|
EXPECT_EQ(result.target->ReturnType(), i32);
|
||||||
EXPECT_EQ(result.target->Parameters().Length(), 1u);
|
EXPECT_EQ(result.target->Parameters().Length(), 1u);
|
||||||
|
@ -942,7 +1061,8 @@ struct IntrinsicTableAbstractBinaryTest : public ResolverTestWithParam<Case> {
|
||||||
TEST_P(IntrinsicTableAbstractBinaryTest, MatchAdd) {
|
TEST_P(IntrinsicTableAbstractBinaryTest, MatchAdd) {
|
||||||
auto* arg_lhs = GetParam().arg_lhs(*this);
|
auto* arg_lhs = GetParam().arg_lhs(*this);
|
||||||
auto* arg_rhs = GetParam().arg_rhs(*this);
|
auto* arg_rhs = GetParam().arg_rhs(*this);
|
||||||
auto result = table->Lookup(ast::BinaryOp::kAdd, arg_lhs, arg_rhs, Source{{12, 34}},
|
auto result = table->Lookup(ast::BinaryOp::kAdd, arg_lhs, arg_rhs,
|
||||||
|
sem::EvaluationStage::kConstant, Source{{12, 34}},
|
||||||
/* is_compound */ false);
|
/* is_compound */ false);
|
||||||
|
|
||||||
bool matched = result.result != nullptr;
|
bool matched = result.result != nullptr;
|
||||||
|
|
|
@ -1780,7 +1780,8 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
||||||
// call for a InitConvIntrinsic with an optional template argument type.
|
// call for a InitConvIntrinsic with an optional template argument type.
|
||||||
auto ct_init_or_conv = [&](InitConvIntrinsic ty, const sem::Type* template_arg) -> sem::Call* {
|
auto ct_init_or_conv = [&](InitConvIntrinsic ty, const sem::Type* template_arg) -> sem::Call* {
|
||||||
auto arg_tys = utils::Transform(args, [](auto* arg) { return arg->Type(); });
|
auto arg_tys = utils::Transform(args, [](auto* arg) { return arg->Type(); });
|
||||||
auto ctor_or_conv = intrinsic_table_->Lookup(ty, template_arg, arg_tys, expr->source);
|
auto ctor_or_conv =
|
||||||
|
intrinsic_table_->Lookup(ty, template_arg, arg_tys, args_stage, expr->source);
|
||||||
if (!ctor_or_conv.target) {
|
if (!ctor_or_conv.target) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2495,7 +2496,8 @@ sem::Expression* Resolver::Binary(const ast::BinaryExpression* expr) {
|
||||||
auto* lhs_ty = lhs->Type()->UnwrapRef();
|
auto* lhs_ty = lhs->Type()->UnwrapRef();
|
||||||
auto* rhs_ty = rhs->Type()->UnwrapRef();
|
auto* rhs_ty = rhs->Type()->UnwrapRef();
|
||||||
|
|
||||||
auto op = intrinsic_table_->Lookup(expr->op, lhs_ty, rhs_ty, expr->source, false);
|
auto stage = sem::EarliestStage(lhs->Stage(), rhs->Stage());
|
||||||
|
auto op = intrinsic_table_->Lookup(expr->op, lhs_ty, rhs_ty, stage, expr->source, false);
|
||||||
if (!op.result) {
|
if (!op.result) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2513,7 +2515,6 @@ sem::Expression* Resolver::Binary(const ast::BinaryExpression* expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* value = nullptr;
|
const sem::Constant* value = nullptr;
|
||||||
auto stage = sem::EarliestStage(lhs->Stage(), rhs->Stage());
|
|
||||||
if (stage == sem::EvaluationStage::kConstant) {
|
if (stage == sem::EvaluationStage::kConstant) {
|
||||||
if (op.const_eval_fn) {
|
if (op.const_eval_fn) {
|
||||||
auto const_args = utils::Vector{lhs->ConstantValue(), rhs->ConstantValue()};
|
auto const_args = utils::Vector{lhs->ConstantValue(), rhs->ConstantValue()};
|
||||||
|
@ -2595,7 +2596,8 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
auto op = intrinsic_table_->Lookup(unary->op, expr_ty, unary->source);
|
stage = expr->Stage();
|
||||||
|
auto op = intrinsic_table_->Lookup(unary->op, expr_ty, stage, unary->source);
|
||||||
if (!op.result) {
|
if (!op.result) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2606,7 +2608,6 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage = expr->Stage();
|
|
||||||
if (stage == sem::EvaluationStage::kConstant) {
|
if (stage == sem::EvaluationStage::kConstant) {
|
||||||
if (op.const_eval_fn) {
|
if (op.const_eval_fn) {
|
||||||
if (auto r = (const_eval_.*op.const_eval_fn)(
|
if (auto r = (const_eval_.*op.const_eval_fn)(
|
||||||
|
@ -3274,7 +3275,9 @@ sem::Statement* Resolver::CompoundAssignmentStatement(
|
||||||
|
|
||||||
auto* lhs_ty = lhs->Type()->UnwrapRef();
|
auto* lhs_ty = lhs->Type()->UnwrapRef();
|
||||||
auto* rhs_ty = rhs->Type()->UnwrapRef();
|
auto* rhs_ty = rhs->Type()->UnwrapRef();
|
||||||
auto* ty = intrinsic_table_->Lookup(stmt->op, lhs_ty, rhs_ty, stmt->source, true).result;
|
auto stage = sem::EarliestStage(lhs->Stage(), rhs->Stage());
|
||||||
|
auto* ty =
|
||||||
|
intrinsic_table_->Lookup(stmt->op, lhs_ty, rhs_ty, stage, stmt->source, true).result;
|
||||||
if (!ty) {
|
if (!ty) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue