2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SlintAdvent Calendar 2024

Day 20

Slint にバグ報告をしてみました

Last updated at Posted at 2024-12-19

はじめに

この記事は Slint Advent Calendar 2024 20日目の記事です。

昨日は @hermit4 さんによる 祝 Slint 1.9リリース でした。

.slint のドキュメント が大幅に改善されてとてもうれしいです。

実は今年のアドベントカレンダーを書いたりネタを探すのに、リリース前のドキュメント の方もよく見ていたので、途中から薄々感じていたのですが、3日目に書いた .slint のドキュメントの構成をまとめました が台無しになりちょっとだけ悲しいです。

きっかけ

2日前に書いた Slint のダイアルのサンプルコードから学ぶ で Slint のダイアルのサンプルコードを紹介しました。
その TODO にあった Lock the dial so it cannot be rotated between the blank start and end angles. に挑戦しようと思って少しコードを変更していたところ、思ったように動かなかったので調査をしていました。

挙動が変だったコード

そのデバッグで色々なコードを試していたのですが、 Types で定義されている型の1つである、angle に対して、Math にある abs() を利用したところ、思ったように動きませんでした。

Math.abs は2通りの使い方ができて、

Math.abs(-1deg) // 1deg になる

は動いたのですが、

-1deg.abs() // 1deg にならない

の場合は -1deg のままで動きませんでした。

後者の形式は上記のドキュメントに以下の記載があり、書き方はとても自然ですし動いても良さそうです。

They can also be called directly as member function of numeric types. (For example angle.sin() or foo.mod(10)).

サンプルコードでの確認

最初は自分の使い方が何か変なのかなと思ったのですが、シンプルなコードでも再現しました。

export component AbsAngle inherits VerticalLayout {
    Text {
        text: -1deg.abs() / 1deg;  // => -1
    }
    Text {
        text: Math.abs(-1deg) / 1deg; // => 1
    }
}

バグ報告をしました

Slint は GitHub 上で開発が行われていて、そこの Issue からバグの報告を受け付けています。

既に同じ問題が報告されていないかを確認した上で上記のバグ報告を書きました。

自分で直せないか調べてみました

internal/compiler/builtin_macros.rs にある以下の関数で処理をしているようです。

builtin_macros.rs
fn abs_macro(
    node: Option<NodeOrToken>,
    args: Vec<(Expression, Option<NodeOrToken>)>,
    diag: &mut BuildDiagnostics,
) -> Expression {
    if args.len() != 1 {
        diag.push_error("Needs 1 argument".into(), &node);
        return Expression::Invalid;
    }
    let ty = args[0].0.ty();
    let ty = if ty.default_unit().is_some() || matches!(ty, Type::UnitProduct(_)) {
        ty
    } else {
        Type::Float32
    };

    let source_location = node.map(|n| n.to_source_location());
    let function = Box::new(Expression::BuiltinFunctionReference(
        BuiltinFunction::Abs,
        source_location.clone(),
    ));
    if matches!(ty, Type::Float32) {
        let arguments =
            args.into_iter().map(|(e, n)| e.maybe_convert_to(ty.clone(), &n, diag)).collect();
        Expression::FunctionCall { function, arguments, source_location }
    } else {
        Expression::Cast {
            from: Expression::FunctionCall {
                function,
                arguments: args
                    .into_iter()
                    .map(|(a, _)| Expression::Cast { from: a.into(), to: Type::Float32 })
                    .collect(),
                source_location,
            }
            .into(),
            to: ty,
        }
    }
}

ここだけ見ても詳細は分かりませんが、-1deg.abs() の計算が 1deg.abs() を先に処理してから - の演算をしているのかなと思ったので以下のコメントを追記しました。

Is - applied to the result of 1deg.abs()?

すぐにフィードバックがありました

Right, -1deg.abs() is the same as -(1deg.abs()).
This is the same precedence rules as in Rust, C++, and so on.

We can't change the precedence rules because then then things like -self.foo wouldn't work anymore because that would become (-self).foo

If anything we could detect this specific case and have a warning.

仕様としては仕方ないっぽいですね。-1deg.abs() って書けたら自然で美しいんですが、それは難しいようなので (-1deg).abs() もしくは Math.abs(-1deg) のように書きましょう。

おわりに

今回は Slint を利用していて変な挙動を見つけたので、バグ報告をしたことを記事にしました。
結果的には仕様ということでしたが、今後私以外の人が困ったときにこのバグレポにたどり着いたらいいなと思っています。あとは「警告くらいはだせるかも?」とのことなので、将来的に何かしらの改善がなされるのではと思っています。

まぁ普通の人は -1deg.abs() って書く機会はめったにないと思うんですけれど。。。

というわけで、みなさんも Slint を利用して変な挙動を見つけた際には是非バグ報告をしてみてください。

明日は @hermit4 さんによる Slintのバックエンドとレンダラー です。お楽しみに!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?