- Fix regression in Time diff due to operator overloading #2124

- Add `Duration * Int` and `Clock - Clock` overload.
This commit is contained in:
Christoffer Lerno
2025-05-06 22:33:39 +02:00
parent 3f07d1c7b8
commit 584a8a2e60
7 changed files with 59 additions and 42 deletions

View File

@@ -13,22 +13,27 @@ fn Clock now()
fn NanoDuration Clock.mark(&self)
{
Clock mark = now();
NanoDuration diff = (NanoDuration)(mark - *self);
NanoDuration diff = mark - *self;
*self = mark;
return diff;
}
fn Clock Clock.add_nano_duration(self, NanoDuration nano)
fn Clock Clock.add_nano_duration(self, NanoDuration nano) @operator_s(+) @inline
{
return (Clock)((NanoDuration)self + nano);
}
fn Clock Clock.add_duration(self, Duration duration)
fn Clock Clock.add_duration(self, Duration duration) @operator_s(+) @inline
{
return self.add_nano_duration(duration.to_nano());
}
fn NanoDuration Clock.to_now(self)
fn NanoDuration Clock.nano_diff(self, Clock other) @operator(-) @inline
{
return (NanoDuration)(now() - self);
return (NanoDuration)self - (NanoDuration)other;
}
fn NanoDuration Clock.to_now(self) @inline
{
return (NanoDuration)now() - (NanoDuration)self;
}

View File

@@ -106,7 +106,7 @@ fn TzDateTime DateTime.to_gmt_offset(self, int gmt_offset)
*>
fn TzDateTime TzDateTime.to_gmt_offset(self, int gmt_offset) {
if (self.gmt_offset == gmt_offset) return self;
Time time = self.time + (Time)gmt_offset * (Time)time::SEC;
Time time = self.time + gmt_offset * time::SEC;
DateTime dt = from_time(time);
dt.time = self.time;
return { dt, gmt_offset };

View File

@@ -19,11 +19,11 @@ const Duration MONTH = 30 * DAY;
const Duration YEAR = 36525 * DAY / 100;
const Duration FOREVER = long.max;
fn Duration us(long l) @inline => (Duration)l * US;
fn Duration ms(long l) @inline => (Duration)l * MS;
fn Duration sec(long l) @inline => (Duration)l * SEC;
fn Duration min(long l) @inline => (Duration)l * MIN;
fn Duration hour(long l) @inline => (Duration)l * HOUR;
fn Duration us(long l) @inline => l * US;
fn Duration ms(long l) @inline => l * MS;
fn Duration sec(long l) @inline =>l * SEC;
fn Duration min(long l) @inline => l * MIN;
fn Duration hour(long l) @inline => l * HOUR;
fn Duration from_float(double s) @inline => (Duration)(s * (double)SEC);
struct DateTime
@@ -82,21 +82,21 @@ fn Time now()
$endif
}
fn Time Time.add_seconds(time, long seconds) => time + (Time)(seconds * (long)SEC);
fn Time Time.add_minutes(time, long minutes) => time + (Time)(minutes * (long)MIN);
fn Time Time.add_hours(time, long hours) => time + (Time)(hours * (long)HOUR);
fn Time Time.add_days(time, long days) => time + (Time)(days * (long)DAY);
fn Time Time.add_weeks(time, long weeks) => time + (Time)(weeks * (long)WEEK);
fn Time Time.add_duration(time, Duration duration) @operator(+) => time + (Time)duration;
fn Time Time.add_seconds(time, long seconds) => time + seconds * SEC;
fn Time Time.add_minutes(time, long minutes) => time + minutes * MIN;
fn Time Time.add_hours(time, long hours) => time + hours * HOUR;
fn Time Time.add_days(time, long days) => time + days * DAY;
fn Time Time.add_weeks(time, long weeks) => time + weeks * WEEK;
fn Time Time.add_duration(time, Duration duration) @operator_s(+) @inline => (Time)((long)time + (long)duration);
fn int Time.compare_to(time, Time other)
{
if (time == other) return 0;
if ((long)time == (long)other) return 0;
return time > other ? 1 : -1;
}
fn double Time.to_seconds(time) => (long)time / (double)SEC;
fn Duration Time.diff_us(time, Time other) @operator(-) => (Duration)(time - other);
fn Duration Time.diff_us(time, Time other) @operator(-) => (Duration)((long)time - (long)other);
fn double Time.diff_sec(time, Time other) => (long)time.diff_us(other) / (double)SEC;
fn double Time.diff_min(time, Time other) => (long)time.diff_us(other) / (double)MIN;
fn double Time.diff_hour(time, Time other) => (long)time.diff_us(other) / (double)HOUR;
@@ -108,6 +108,7 @@ fn long NanoDuration.to_ms(nd) => (long)nd / 1_000_000;
fn Duration NanoDuration.to_duration(nd) => (Duration)nd / 1_000;
fn NanoDuration Duration.to_nano(td) => (NanoDuration)td * 1_000;
fn long Duration.to_ms(td) => (long)td / 1_000;
macro Duration Duration.mult(#td, long #val) @operator_s(*) @safemacro => (Duration)((long)#td * #val);
fn usz? NanoDuration.to_format(&self, Formatter* formatter) @dynamic
{

View File

@@ -10,12 +10,14 @@
- Assert when a macro with compile time value is discarded, e.g. `foo();` where `foo()` returns an untyped list. #2117
- Fix stringify for compound initializers #2120.
- Fix No index OOB check for `[:^n]` #2123
- Fix regression in Time diff due to operator overloading #2124
### Stdlib changes
- Added `String.quick_ztr` and `String.is_zstr`
- std::ascii moved into std::core::ascii. Old _m variants are deprecated, as is uint methods.
- Add `String.tokenize_all` to replace the now deprecated `String.splitter`
- Add `String.count` to count the number of instances of a string.
- Add `Duration * Int` and `Clock - Clock` overload.
## 0.7.1 Change list

View File

@@ -1779,6 +1779,7 @@ static Decl *sema_find_exact_typed_operator_in_list(Decl **methods, OperatorOver
FOREACH(Decl *, func, methods)
{
if (func == skipped) continue;
if (!decl_ok(func)) continue;
if (func->func_decl.operator != operator_overload) continue;
if (parent_type && parent_type != typeget(func->func_decl.type_parent)) continue;
if ((overload_type & func->func_decl.overload_type) == 0) continue;

View File

@@ -10964,19 +10964,22 @@ bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *meth
Expr *resolve = method_call;
if (reverse_overload)
{
Decl *temp = decl_new_generated_var(method_decl->func_decl.signature.params[1]->type, VARDECL_LOCAL, parent->span);
Expr *generate = expr_generate_decl(temp, expr_copy(parent));
parent->expr_kind = EXPR_IDENTIFIER;
parent->ident_expr = temp;
parent->resolve_status = RESOLVE_DONE;
parent->type = temp->type;
if (!sema_analyse_expr(context, generate)) return false;
Expr *copied_method = expr_copy(method_call);
expr_rewrite_two(method_call, generate, copied_method);
if (!expr_is_const(parent))
{
Decl *temp = decl_new_generated_var(method_decl->func_decl.signature.params[1]->type, VARDECL_LOCAL, parent->span);
Expr *generate = expr_generate_decl(temp, expr_copy(parent));
parent->expr_kind = EXPR_IDENTIFIER;
parent->ident_expr = temp;
parent->resolve_status = RESOLVE_DONE;
parent->type = temp->type;
if (!sema_analyse_expr(context, generate)) return false;
Expr *copied_method = expr_copy(method_call);
expr_rewrite_two(method_call, generate, copied_method);
method_call = copied_method;
}
Expr *arg0 = arguments[0];
arguments[0] = parent;
parent = arg0;
method_call = copied_method;
}
*method_call = (Expr) { .expr_kind = EXPR_CALL,
.span = original_span,
@@ -11001,19 +11004,6 @@ bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *meth
expr_rewrite_insert_deref(parent);
}
}
else if (!expr_may_ref(parent))
{
Expr *inner = expr_copy(parent);
parent->expr_kind = EXPR_UNARY;
Type *inner_type = inner->type;
bool optional = type_is_optional(inner->type);
parent->type = type_add_optional(type_get_ptr(type_no_optional(inner_type)), optional);
parent->unary_expr.operator = UNARYOP_TADDR;
parent->unary_expr.expr = inner;
parent->resolve_status = RESOLVE_NOT_DONE;
if (!sema_analyse_expr(context, parent)) return false;
expr_rewrite_insert_deref(parent);
}
ASSERT_SPAN(method_call, parent && parent->type && first == parent->type->canonical);
if (!sema_expr_analyse_general_call(context, method_call, method_decl, parent, false,
NULL)) return expr_poison(method_call);

View File

@@ -2,6 +2,24 @@ module nanoduration_test @test;
import std::io;
import std::time;
fn void time_diff()
{
Time t = time::now();
Time t2 = t + time::SEC;
test::eq(t2 - t, time::SEC);
test::ne(t, t2);
test::eq(t, t);
}
fn void clock_diff()
{
Clock c = clock::now();
Clock c2 = c + time::SEC.to_nano();
test::eq(c2 - c, time::SEC.to_nano());
c2 = c + time::DAY;
test::eq(c2 - c, time::DAY.to_nano());
}
fn void to_format()
{
char[32] buffer;