mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	merge
This commit is contained in:
		| @@ -38,8 +38,14 @@ async def to_code(config): | ||||
|         condition = await automation.build_condition( | ||||
|             condition, cg.TemplateArguments(), [] | ||||
|         ) | ||||
|         # Generate a stateless lambda that calls condition.check() | ||||
|         # capture="" is safe because condition is a global variable in generated C++ code | ||||
|         # and doesn't need to be captured. This allows implicit conversion to function pointer. | ||||
|         template_ = LambdaExpression( | ||||
|             f"return {condition.check()};", [], return_type=cg.optional.template(bool) | ||||
|             f"return {condition.check()};", | ||||
|             [], | ||||
|             return_type=cg.optional.template(bool), | ||||
|             capture="", | ||||
|         ) | ||||
|         cg.add(var.set_template(template_)) | ||||
|  | ||||
|   | ||||
| @@ -9,10 +9,10 @@ static const char *const TAG = "template.binary_sensor"; | ||||
| void TemplateBinarySensor::setup() { this->loop(); } | ||||
|  | ||||
| void TemplateBinarySensor::loop() { | ||||
|   if (this->f_ == nullptr) | ||||
|   if (!this->f_.has_value()) | ||||
|     return; | ||||
|  | ||||
|   auto s = this->f_(); | ||||
|   auto s = (*this->f_)(); | ||||
|   if (s.has_value()) { | ||||
|     this->publish_state(*s); | ||||
|   } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ namespace template_ { | ||||
|  | ||||
| class TemplateBinarySensor : public Component, public binary_sensor::BinarySensor { | ||||
|  public: | ||||
|   void set_template(std::function<optional<bool>()> &&f) { this->f_ = f; } | ||||
|   void set_template(optional<bool> (*f)()) { this->f_ = f; } | ||||
|  | ||||
|   void setup() override; | ||||
|   void loop() override; | ||||
| @@ -17,7 +17,7 @@ class TemplateBinarySensor : public Component, public binary_sensor::BinarySenso | ||||
|   float get_setup_priority() const override { return setup_priority::HARDWARE; } | ||||
|  | ||||
|  protected: | ||||
|   std::function<optional<bool>()> f_{nullptr}; | ||||
|   optional<optional<bool> (*)()> f_; | ||||
| }; | ||||
|  | ||||
| }  // namespace template_ | ||||
|   | ||||
| @@ -63,7 +63,7 @@ void TemplateCover::loop() { | ||||
| } | ||||
| void TemplateCover::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } | ||||
| void TemplateCover::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; } | ||||
| void TemplateCover::set_state_lambda(std::function<optional<float>()> &&f) { this->state_f_ = f; } | ||||
| void TemplateCover::set_state_lambda(optional<float> (*f)()) { this->state_f_ = f; } | ||||
| float TemplateCover::get_setup_priority() const { return setup_priority::HARDWARE; } | ||||
| Trigger<> *TemplateCover::get_open_trigger() const { return this->open_trigger_; } | ||||
| Trigger<> *TemplateCover::get_close_trigger() const { return this->close_trigger_; } | ||||
| @@ -124,7 +124,7 @@ CoverTraits TemplateCover::get_traits() { | ||||
| } | ||||
| Trigger<float> *TemplateCover::get_position_trigger() const { return this->position_trigger_; } | ||||
| Trigger<float> *TemplateCover::get_tilt_trigger() const { return this->tilt_trigger_; } | ||||
| void TemplateCover::set_tilt_lambda(std::function<optional<float>()> &&tilt_f) { this->tilt_f_ = tilt_f; } | ||||
| void TemplateCover::set_tilt_lambda(optional<float> (*tilt_f)()) { this->tilt_f_ = tilt_f; } | ||||
| void TemplateCover::set_has_stop(bool has_stop) { this->has_stop_ = has_stop; } | ||||
| void TemplateCover::set_has_toggle(bool has_toggle) { this->has_toggle_ = has_toggle; } | ||||
| void TemplateCover::set_has_position(bool has_position) { this->has_position_ = has_position; } | ||||
|   | ||||
| @@ -17,7 +17,7 @@ class TemplateCover : public cover::Cover, public Component { | ||||
|  public: | ||||
|   TemplateCover(); | ||||
|  | ||||
|   void set_state_lambda(std::function<optional<float>()> &&f); | ||||
|   void set_state_lambda(optional<float> (*f)()); | ||||
|   Trigger<> *get_open_trigger() const; | ||||
|   Trigger<> *get_close_trigger() const; | ||||
|   Trigger<> *get_stop_trigger() const; | ||||
| @@ -26,7 +26,7 @@ class TemplateCover : public cover::Cover, public Component { | ||||
|   Trigger<float> *get_tilt_trigger() const; | ||||
|   void set_optimistic(bool optimistic); | ||||
|   void set_assumed_state(bool assumed_state); | ||||
|   void set_tilt_lambda(std::function<optional<float>()> &&tilt_f); | ||||
|   void set_tilt_lambda(optional<float> (*tilt_f)()); | ||||
|   void set_has_stop(bool has_stop); | ||||
|   void set_has_position(bool has_position); | ||||
|   void set_has_tilt(bool has_tilt); | ||||
| @@ -45,8 +45,8 @@ class TemplateCover : public cover::Cover, public Component { | ||||
|   void stop_prev_trigger_(); | ||||
|  | ||||
|   TemplateCoverRestoreMode restore_mode_{COVER_RESTORE}; | ||||
|   optional<std::function<optional<float>()>> state_f_; | ||||
|   optional<std::function<optional<float>()>> tilt_f_; | ||||
|   optional<optional<float> (*)()> state_f_; | ||||
|   optional<optional<float> (*)()> tilt_f_; | ||||
|   bool assumed_state_{false}; | ||||
|   bool optimistic_{false}; | ||||
|   Trigger<> *open_trigger_; | ||||
|   | ||||
| @@ -15,7 +15,7 @@ namespace template_ { | ||||
|  | ||||
| class TemplateDate : public datetime::DateEntity, public PollingComponent { | ||||
|  public: | ||||
|   void set_template(std::function<optional<ESPTime>()> &&f) { this->f_ = f; } | ||||
|   void set_template(optional<ESPTime> (*f)()) { this->f_ = f; } | ||||
|  | ||||
|   void setup() override; | ||||
|   void update() override; | ||||
| @@ -35,7 +35,7 @@ class TemplateDate : public datetime::DateEntity, public PollingComponent { | ||||
|   ESPTime initial_value_{}; | ||||
|   bool restore_value_{false}; | ||||
|   Trigger<ESPTime> *set_trigger_ = new Trigger<ESPTime>(); | ||||
|   optional<std::function<optional<ESPTime>()>> f_; | ||||
|   optional<optional<ESPTime> (*)()> f_; | ||||
|  | ||||
|   ESPPreferenceObject pref_; | ||||
| }; | ||||
|   | ||||
| @@ -15,7 +15,7 @@ namespace template_ { | ||||
|  | ||||
| class TemplateDateTime : public datetime::DateTimeEntity, public PollingComponent { | ||||
|  public: | ||||
|   void set_template(std::function<optional<ESPTime>()> &&f) { this->f_ = f; } | ||||
|   void set_template(optional<ESPTime> (*f)()) { this->f_ = f; } | ||||
|  | ||||
|   void setup() override; | ||||
|   void update() override; | ||||
| @@ -35,7 +35,7 @@ class TemplateDateTime : public datetime::DateTimeEntity, public PollingComponen | ||||
|   ESPTime initial_value_{}; | ||||
|   bool restore_value_{false}; | ||||
|   Trigger<ESPTime> *set_trigger_ = new Trigger<ESPTime>(); | ||||
|   optional<std::function<optional<ESPTime>()>> f_; | ||||
|   optional<optional<ESPTime> (*)()> f_; | ||||
|  | ||||
|   ESPPreferenceObject pref_; | ||||
| }; | ||||
|   | ||||
| @@ -15,7 +15,7 @@ namespace template_ { | ||||
|  | ||||
| class TemplateTime : public datetime::TimeEntity, public PollingComponent { | ||||
|  public: | ||||
|   void set_template(std::function<optional<ESPTime>()> &&f) { this->f_ = f; } | ||||
|   void set_template(optional<ESPTime> (*f)()) { this->f_ = f; } | ||||
|  | ||||
|   void setup() override; | ||||
|   void update() override; | ||||
| @@ -35,7 +35,7 @@ class TemplateTime : public datetime::TimeEntity, public PollingComponent { | ||||
|   ESPTime initial_value_{}; | ||||
|   bool restore_value_{false}; | ||||
|   Trigger<ESPTime> *set_trigger_ = new Trigger<ESPTime>(); | ||||
|   optional<std::function<optional<ESPTime>()>> f_; | ||||
|   optional<optional<ESPTime> (*)()> f_; | ||||
|  | ||||
|   ESPPreferenceObject pref_; | ||||
| }; | ||||
|   | ||||
| @@ -45,7 +45,7 @@ void TemplateLock::open_latch() { | ||||
|   this->open_trigger_->trigger(); | ||||
| } | ||||
| void TemplateLock::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } | ||||
| void TemplateLock::set_state_lambda(std::function<optional<lock::LockState>()> &&f) { this->f_ = f; } | ||||
| void TemplateLock::set_state_lambda(optional<lock::LockState> (*f)()) { this->f_ = f; } | ||||
| float TemplateLock::get_setup_priority() const { return setup_priority::HARDWARE; } | ||||
| Trigger<> *TemplateLock::get_lock_trigger() const { return this->lock_trigger_; } | ||||
| Trigger<> *TemplateLock::get_unlock_trigger() const { return this->unlock_trigger_; } | ||||
|   | ||||
| @@ -13,7 +13,7 @@ class TemplateLock : public lock::Lock, public Component { | ||||
|  | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void set_state_lambda(std::function<optional<lock::LockState>()> &&f); | ||||
|   void set_state_lambda(optional<lock::LockState> (*f)()); | ||||
|   Trigger<> *get_lock_trigger() const; | ||||
|   Trigger<> *get_unlock_trigger() const; | ||||
|   Trigger<> *get_open_trigger() const; | ||||
| @@ -26,7 +26,7 @@ class TemplateLock : public lock::Lock, public Component { | ||||
|   void control(const lock::LockCall &call) override; | ||||
|   void open_latch() override; | ||||
|  | ||||
|   optional<std::function<optional<lock::LockState>()>> f_; | ||||
|   optional<optional<lock::LockState> (*)()> f_; | ||||
|   bool optimistic_{false}; | ||||
|   Trigger<> *lock_trigger_; | ||||
|   Trigger<> *unlock_trigger_; | ||||
|   | ||||
| @@ -10,7 +10,7 @@ namespace template_ { | ||||
|  | ||||
| class TemplateNumber : public number::Number, public PollingComponent { | ||||
|  public: | ||||
|   void set_template(std::function<optional<float>()> &&f) { this->f_ = f; } | ||||
|   void set_template(optional<float> (*f)()) { this->f_ = f; } | ||||
|  | ||||
|   void setup() override; | ||||
|   void update() override; | ||||
| @@ -28,7 +28,7 @@ class TemplateNumber : public number::Number, public PollingComponent { | ||||
|   float initial_value_{NAN}; | ||||
|   bool restore_value_{false}; | ||||
|   Trigger<float> *set_trigger_ = new Trigger<float>(); | ||||
|   optional<std::function<optional<float>()>> f_; | ||||
|   optional<optional<float> (*)()> f_; | ||||
|  | ||||
|   ESPPreferenceObject pref_; | ||||
| }; | ||||
|   | ||||
| @@ -10,7 +10,7 @@ namespace template_ { | ||||
|  | ||||
| class TemplateSelect : public select::Select, public PollingComponent { | ||||
|  public: | ||||
|   void set_template(std::function<optional<std::string>()> &&f) { this->f_ = f; } | ||||
|   void set_template(optional<std::string> (*f)()) { this->f_ = f; } | ||||
|  | ||||
|   void setup() override; | ||||
|   void update() override; | ||||
| @@ -28,7 +28,7 @@ class TemplateSelect : public select::Select, public PollingComponent { | ||||
|   std::string initial_option_; | ||||
|   bool restore_value_ = false; | ||||
|   Trigger<std::string> *set_trigger_ = new Trigger<std::string>(); | ||||
|   optional<std::function<optional<std::string>()>> f_; | ||||
|   optional<optional<std::string> (*)()> f_; | ||||
|  | ||||
|   ESPPreferenceObject pref_; | ||||
| }; | ||||
|   | ||||
| @@ -17,7 +17,7 @@ void TemplateSensor::update() { | ||||
|   } | ||||
| } | ||||
| float TemplateSensor::get_setup_priority() const { return setup_priority::HARDWARE; } | ||||
| void TemplateSensor::set_template(std::function<optional<float>()> &&f) { this->f_ = f; } | ||||
| void TemplateSensor::set_template(optional<float> (*f)()) { this->f_ = f; } | ||||
| void TemplateSensor::dump_config() { | ||||
|   LOG_SENSOR("", "Template Sensor", this); | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
|   | ||||
| @@ -8,7 +8,7 @@ namespace template_ { | ||||
|  | ||||
| class TemplateSensor : public sensor::Sensor, public PollingComponent { | ||||
|  public: | ||||
|   void set_template(std::function<optional<float>()> &&f); | ||||
|   void set_template(optional<float> (*f)()); | ||||
|  | ||||
|   void update() override; | ||||
|  | ||||
| @@ -17,7 +17,7 @@ class TemplateSensor : public sensor::Sensor, public PollingComponent { | ||||
|   float get_setup_priority() const override; | ||||
|  | ||||
|  protected: | ||||
|   optional<std::function<optional<float>()>> f_; | ||||
|   optional<optional<float> (*)()> f_; | ||||
| }; | ||||
|  | ||||
| }  // namespace template_ | ||||
|   | ||||
| @@ -35,7 +35,7 @@ void TemplateSwitch::write_state(bool state) { | ||||
| } | ||||
| void TemplateSwitch::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } | ||||
| bool TemplateSwitch::assumed_state() { return this->assumed_state_; } | ||||
| void TemplateSwitch::set_state_lambda(std::function<optional<bool>()> &&f) { this->f_ = f; } | ||||
| void TemplateSwitch::set_state_lambda(optional<bool> (*f)()) { this->f_ = f; } | ||||
| float TemplateSwitch::get_setup_priority() const { return setup_priority::HARDWARE - 2.0f; } | ||||
| Trigger<> *TemplateSwitch::get_turn_on_trigger() const { return this->turn_on_trigger_; } | ||||
| Trigger<> *TemplateSwitch::get_turn_off_trigger() const { return this->turn_off_trigger_; } | ||||
|   | ||||
| @@ -14,7 +14,7 @@ class TemplateSwitch : public switch_::Switch, public Component { | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void set_state_lambda(std::function<optional<bool>()> &&f); | ||||
|   void set_state_lambda(optional<bool> (*f)()); | ||||
|   Trigger<> *get_turn_on_trigger() const; | ||||
|   Trigger<> *get_turn_off_trigger() const; | ||||
|   void set_optimistic(bool optimistic); | ||||
| @@ -28,7 +28,7 @@ class TemplateSwitch : public switch_::Switch, public Component { | ||||
|  | ||||
|   void write_state(bool state) override; | ||||
|  | ||||
|   optional<std::function<optional<bool>()>> f_; | ||||
|   optional<optional<bool> (*)()> f_; | ||||
|   bool optimistic_{false}; | ||||
|   bool assumed_state_{false}; | ||||
|   Trigger<> *turn_on_trigger_; | ||||
|   | ||||
| @@ -61,7 +61,7 @@ template<uint8_t SZ> class TextSaver : public TemplateTextSaverBase { | ||||
|  | ||||
| class TemplateText : public text::Text, public PollingComponent { | ||||
|  public: | ||||
|   void set_template(std::function<optional<std::string>()> &&f) { this->f_ = f; } | ||||
|   void set_template(optional<std::string> (*f)()) { this->f_ = f; } | ||||
|  | ||||
|   void setup() override; | ||||
|   void update() override; | ||||
| @@ -78,7 +78,7 @@ class TemplateText : public text::Text, public PollingComponent { | ||||
|   bool optimistic_ = false; | ||||
|   std::string initial_value_; | ||||
|   Trigger<std::string> *set_trigger_ = new Trigger<std::string>(); | ||||
|   optional<std::function<optional<std::string>()>> f_{nullptr}; | ||||
|   optional<optional<std::string> (*)()> f_{nullptr}; | ||||
|  | ||||
|   TemplateTextSaverBase *pref_ = nullptr; | ||||
| }; | ||||
|   | ||||
| @@ -16,7 +16,7 @@ void TemplateTextSensor::update() { | ||||
|   } | ||||
| } | ||||
| float TemplateTextSensor::get_setup_priority() const { return setup_priority::HARDWARE; } | ||||
| void TemplateTextSensor::set_template(std::function<optional<std::string>()> &&f) { this->f_ = f; } | ||||
| void TemplateTextSensor::set_template(optional<std::string> (*f)()) { this->f_ = f; } | ||||
| void TemplateTextSensor::dump_config() { LOG_TEXT_SENSOR("", "Template Sensor", this); } | ||||
|  | ||||
| }  // namespace template_ | ||||
|   | ||||
| @@ -9,7 +9,7 @@ namespace template_ { | ||||
|  | ||||
| class TemplateTextSensor : public text_sensor::TextSensor, public PollingComponent { | ||||
|  public: | ||||
|   void set_template(std::function<optional<std::string>()> &&f); | ||||
|   void set_template(optional<std::string> (*f)()); | ||||
|  | ||||
|   void update() override; | ||||
|  | ||||
| @@ -18,7 +18,7 @@ class TemplateTextSensor : public text_sensor::TextSensor, public PollingCompone | ||||
|   void dump_config() override; | ||||
|  | ||||
|  protected: | ||||
|   optional<std::function<optional<std::string>()>> f_{}; | ||||
|   optional<optional<std::string> (*)()> f_{}; | ||||
| }; | ||||
|  | ||||
| }  // namespace template_ | ||||
|   | ||||
| @@ -55,7 +55,7 @@ void TemplateValve::loop() { | ||||
|  | ||||
| void TemplateValve::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } | ||||
| void TemplateValve::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; } | ||||
| void TemplateValve::set_state_lambda(std::function<optional<float>()> &&f) { this->state_f_ = f; } | ||||
| void TemplateValve::set_state_lambda(optional<float> (*f)()) { this->state_f_ = f; } | ||||
| float TemplateValve::get_setup_priority() const { return setup_priority::HARDWARE; } | ||||
|  | ||||
| Trigger<> *TemplateValve::get_open_trigger() const { return this->open_trigger_; } | ||||
|   | ||||
| @@ -17,7 +17,7 @@ class TemplateValve : public valve::Valve, public Component { | ||||
|  public: | ||||
|   TemplateValve(); | ||||
|  | ||||
|   void set_state_lambda(std::function<optional<float>()> &&f); | ||||
|   void set_state_lambda(optional<float> (*f)()); | ||||
|   Trigger<> *get_open_trigger() const; | ||||
|   Trigger<> *get_close_trigger() const; | ||||
|   Trigger<> *get_stop_trigger() const; | ||||
| @@ -42,7 +42,7 @@ class TemplateValve : public valve::Valve, public Component { | ||||
|   void stop_prev_trigger_(); | ||||
|  | ||||
|   TemplateValveRestoreMode restore_mode_{VALVE_NO_RESTORE}; | ||||
|   optional<std::function<optional<float>()>> state_f_; | ||||
|   optional<optional<float> (*)()> state_f_; | ||||
|   bool assumed_state_{false}; | ||||
|   bool optimistic_{false}; | ||||
|   Trigger<> *open_trigger_; | ||||
|   | ||||
| @@ -198,6 +198,8 @@ class LambdaExpression(Expression): | ||||
|         self.return_type = safe_exp(return_type) if return_type is not None else None | ||||
|  | ||||
|     def __str__(self): | ||||
|         # Stateless lambdas (empty capture) implicitly convert to function pointers | ||||
|         # when assigned to function pointer types - no unary + needed | ||||
|         cpp = f"[{self.capture}]({self.parameters})" | ||||
|         if self.return_type is not None: | ||||
|             cpp += f" -> {self.return_type}" | ||||
| @@ -700,6 +702,12 @@ async def process_lambda( | ||||
|             parts[i * 3 + 1] = var | ||||
|         parts[i * 3 + 2] = "" | ||||
|  | ||||
|     # All id() references are global variables in generated C++ code. | ||||
|     # Global variables should not be captured - they're accessible everywhere. | ||||
|     # Use empty capture instead of capture-by-value. | ||||
|     if capture == "=": | ||||
|         capture = "" | ||||
|  | ||||
|     if isinstance(value, ESPHomeDataBase) and value.esp_range is not None: | ||||
|         location = value.esp_range.start_mark | ||||
|         location.line += value.content_offset | ||||
|   | ||||
| @@ -58,7 +58,7 @@ def test_text_config_value_mode_set(generate_main): | ||||
|  | ||||
| def test_text_config_lamda_is_set(generate_main): | ||||
|     """ | ||||
|     Test if lambda is set for lambda mode | ||||
|     Test if lambda is set for lambda mode (optimized with stateless lambda) | ||||
|     """ | ||||
|     # Given | ||||
|  | ||||
| @@ -66,5 +66,6 @@ def test_text_config_lamda_is_set(generate_main): | ||||
|     main_cpp = generate_main("tests/component_tests/text/test_text.yaml") | ||||
|  | ||||
|     # Then | ||||
|     assert "it_4->set_template([=]() -> esphome::optional<std::string> {" in main_cpp | ||||
|     # Stateless lambda optimization: empty capture list allows function pointer conversion | ||||
|     assert "it_4->set_template([]() -> esphome::optional<std::string> {" in main_cpp | ||||
|     assert 'return std::string{"Hello"};' in main_cpp | ||||
|   | ||||
| @@ -173,6 +173,61 @@ class TestLambdaExpression: | ||||
|             "}" | ||||
|         ) | ||||
|  | ||||
|     def test_str__stateless_no_return(self): | ||||
|         """Test stateless lambda (empty capture) generates correctly""" | ||||
|         target = cg.LambdaExpression( | ||||
|             ('ESP_LOGD("main", "Test message");',), | ||||
|             (),  # No parameters | ||||
|             "",  # Empty capture (stateless) | ||||
|         ) | ||||
|  | ||||
|         actual = str(target) | ||||
|  | ||||
|         assert actual == ('[]() {\n  ESP_LOGD("main", "Test message");\n}') | ||||
|  | ||||
|     def test_str__stateless_with_return(self): | ||||
|         """Test stateless lambda with return type generates correctly""" | ||||
|         target = cg.LambdaExpression( | ||||
|             ("return global_value > 0;",), | ||||
|             (),  # No parameters | ||||
|             "",  # Empty capture (stateless) | ||||
|             bool,  # Return type | ||||
|         ) | ||||
|  | ||||
|         actual = str(target) | ||||
|  | ||||
|         assert actual == ("[]() -> bool {\n  return global_value > 0;\n}") | ||||
|  | ||||
|     def test_str__stateless_with_params(self): | ||||
|         """Test stateless lambda with parameters generates correctly""" | ||||
|         target = cg.LambdaExpression( | ||||
|             ("return foo + bar;",), | ||||
|             ((int, "foo"), (float, "bar")), | ||||
|             "",  # Empty capture (stateless) | ||||
|             float, | ||||
|         ) | ||||
|  | ||||
|         actual = str(target) | ||||
|  | ||||
|         assert actual == ( | ||||
|             "[](int32_t foo, float bar) -> float {\n  return foo + bar;\n}" | ||||
|         ) | ||||
|  | ||||
|     def test_str__with_capture(self): | ||||
|         """Test lambda with capture generates correctly""" | ||||
|         target = cg.LambdaExpression( | ||||
|             ("return captured_var + x;",), | ||||
|             ((int, "x"),), | ||||
|             "captured_var",  # Has capture (not stateless) | ||||
|             int, | ||||
|         ) | ||||
|  | ||||
|         actual = str(target) | ||||
|  | ||||
|         assert actual == ( | ||||
|             "[captured_var](int32_t x) -> int32_t {\n  return captured_var + x;\n}" | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class TestLiterals: | ||||
|     @pytest.mark.parametrize( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user