Unclear Error on new SDK

Hi,

I'm trying to get my app up to date wtih the new sdk 4.1.7 I could fix almost all errors but one. This is what the compiler throws at me.

ERROR: fenix7: Rez.mc:25: Invalid '$.Toybox.Lang.Dictionary{:stateHighlighted as Enum<$.Toybox.Graphics.ColorValue>, :background as Enum<$.Toybox.Graphics.ColorValue>, :height as $.Toybox.Lang.Float, :behavior as $.Toybox.Lang.Symbol, :locX as $.Toybox.Lang.Float, :locY as $.Toybox.Lang.Float, :stateDisabled as Enum<$.Toybox.Graphics.ColorValue>, :stateSelected as Enum<$.Toybox.Graphics.ColorValue>, :width as $.Toybox.Lang.Float, :stateDefault as Enum<$.Toybox.Graphics.ColorValue>}' passed as parameter 1 of type '$.Toybox.Lang.Dictionary{:background as $.Toybox.Graphics.ColorType or $.Toybox.WatchUi.Drawable, :height as $.Toybox.Lang.Number, :stateHighlighted as $.Toybox.Graphics.ColorType or $.Toybox.WatchUi.Drawable, :behavior as $.Toybox.Lang.Symbol, :locX as $.Toybox.Lang.Number, :locY as $.Toybox.Lang.Number, :stateDisabled as $.Toybox.Graphics.ColorType or $.Toybox.WatchUi.Drawable, :identifier as $.Toybox.Lang.Object, :width as $.Toybox.Lang.Number, :stateSelected as $.Toybox.Graphics.ColorType or $.Toybox.WatchUi.Drawable, :stateDefault as $.Toybox.Graphics.ColorType or $.Toybox.WatchUi.Drawable, :visible as $.Toybox.Lang.Boolean}'.

Hopefully somebody can help me with this.

Top Replies

All Replies

  • hopefully someone can provide the relevant lines of code

  • turn off type checking in the monkey c settings

  • This worked thanks. But it's still weird that it doesn't actually tell me which part of the code is responsible for the error.

    I can't find this Rez.mc file that's mentioned in this error line.

  • I think Rez.mc is a file that's autogenerated by the compiler, which would imply that either:

    - this is a compiler bug

    or

    - there's something wrong with your resources

    Either way, it's too bad:

    - there's isn't a better error message

    and/or

    - the contents of Rez.mc aren't available for inspection

    However, if I build a Monkey C app,

    bin/mir/source has .mir files for every source file in my app

    bin/internal-mir has .mir files for every generated source file, including Rez.mir

    (.mir files seem to be some sort of intermediate representation of MC files, somewhere between source code and bytecode. They're full of annotations referring to the original file and line number of the corresponding MC source.)

    If you post the contents of Rez.mir here (or at least the contents corresponding to line 25), maybe it would point to what the problem is.

    Here's an example of Rez.mir for a test app of mine with almost no resources:

    [ @file = "Rez.mc"; @line = 1; ]
    module Rez {
        [ @file = "Rez.mc"; @line = 1; ]
        <init> {
        }
        [ @file = "Rez.mc"; @line = 2; ]
        module Drawables {
            [ @file = "Rez.mc"; @line = 2; ]
            <init> {
            }
            [ @file = "Rez.mc"; @line = 3; ]
            import Toybox.Lang;
            [ @file = "Rez.mc"; @line = 4; initialized = true; ]
            var LauncherIcon as Symbol;
        }
        [ @file = "Rez.mc"; @line = 6; ]
        module Fonts {
            [ @file = "Rez.mc"; @line = 6; ]
            <init> {
            }
        }
        [ @file = "Rez.mc"; @line = 8; ]
        module JsonData {
            [ @file = "Rez.mc"; @line = 8; ]
            <init> {
            }
        }
        [ @file = "Rez.mc"; @line = 10; ]
        module Layouts {
            [ @file = "Rez.mc"; @line = 10; ]
            <init> {
            }
        }
        [ @file = "Rez.mc"; @line = 12; ]
        module Menus {
            [ @file = "Rez.mc"; @line = 12; ]
            <init> {
            }
        }
        [ @file = "Rez.mc"; @line = 14; ]
        module Strings {
            [ @file = "Rez.mc"; @line = 14; ]
            <init> {
            }
            [ @file = "Rez.mc"; @line = 15; ]
            import Toybox.Lang;
            [ @file = "Rez.mc"; @line = 16; initialized = true; ]
            var group1Title as Symbol;
            [ @file = "Rez.mc"; @line = 17; initialized = true; ]
            var Stringy2 as Symbol;
            [ @file = "Rez.mc"; @line = 18; initialized = true; ]
            var prop2Title as Symbol;
            [ @file = "Rez.mc"; @line = 19; initialized = true; ]
            var Stringy as Symbol;
            [ @file = "Rez.mc"; @line = 20; initialized = true; ]
            var group1Description as Symbol;
            [ @file = "Rez.mc"; @line = 21; initialized = true; ]
            var AppName as Symbol;
            [ @file = "Rez.mc"; @line = 22; initialized = true; ]
            var prop1Title as Symbol;
        }
    }
    <init> {
    }
    

    https://developer.garmin.com/connect-iq/core-topics/resources/

    The resource compiler auto-generates a Monkey C module named Rez that contains the resource IDs for the resource file.

  •     function setupStartMatchButton(dc) {
            var options = {
                :locx => 0 as Lang.Number,
                :locY => dc.getHeight() / 3 as Lang.Number,
                :width => dc.getWidth() as Lang.Number,
                :height => dc.getHeight() / 3 as Lang.Number,
                :behavior => :onStartMatch,
                :stateHighlighted => Gfx.COLOR_RED as Gfx.ColorType,
                :stateDefault => Gfx.COLOR_WHITE  as Gfx.ColorType
            };
    
            var button = new Ui.Button(options);
            setLayout([button]);
        }

    I think it has to do with this bit of code. I use this to create buttons. 3 of them and I've also got 3 error messages. 
    This works fine on 4.1.6.

  • TL;DR  the root cause is that the dc argument is untyped. Another issue is that the "as Lang.Number" casts don't have the intended effect, but once dc has the correct type, those casts should be unnecessary anyway.

    ---

    Got it, thanks! As you implied, the compiler seems to be complaining about the options argument to the Button constructor on line 12 (var button = new Ui.Button(options)), so it's not really a compiler bug (nor is it really related to any auto-generated code per se), but it's just not a great error message.

    Couple of issues:

    - "locx" should be "locX" (but I assume that's just a typo in your post, and not something that's in your actual code)

    - "dc.getHeight() / 3 as Lang.Number" doesn't cast "dc.getHeight() / 3" to a Number, it casts "3" to a Number. For that cast to work, you would want to write "(dc.getHeight() / 3) as Number". But you shouldn't have to do that, since dc.getHeight() already returns a number

    - The problem here (at least when I try to recreate your issue) is that the dc argument is untyped. In my case, the compiler thinks locY and height are Any (because the type checker sees dc.getHeight() / 3 as Number to be Any / Number.)

    To be clear, this is the code I added to a data field's View-derived class to recreate your problem:

    import Toybox.Lang;
    import Toybox.WatchUi;
    import Toybox.Graphics;
    // ...
    class TestDataFieldView extends WatchUi.DataField {
    //...
        function setupStartMatchButton(dc) {
            var options = {
                :locX => 0 as Lang.Number,
                :locY => dc.getHeight() / 3 as Lang.Number,
                :width => dc.getWidth() as Lang.Number,
                :height => dc.getHeight() / 3 as Lang.Number,
                // :behavior => :onStartMatch,
                :stateHighlighted => Graphics.COLOR_RED as Graphics.ColorType,
                :stateDefault => Graphics.COLOR_WHITE  as Graphics.ColorType
            };
    
            var button = new WatchUi.Button(options);
            setLayout([button]);
        }
    //...

    These are the error messages I got:

    For the definition of setupStartMatchButton():

     Function return is untyped

    For the call to new WatchUi.Button:

    Passing '$.Toybox.Lang.Dictionary{:height as Any, :stateHighlighted as $.Toybox.Graphics.ColorValue or $.Toybox.Lang.Number, :locX as $.Toybox.Lang.Number, :locY as Any, :width as $.Toybox.Lang.Number, :stateDefault as $.Toybox.Graphics.ColorValue or $.Toybox.Lang.Number}' as parameter 1 of type '$.Toybox.Lang.Dictionary{:background as $.Toybox.Graphics.ColorType or $.Toybox.WatchUi.Drawable, :height as $.Toybox.Lang.Number, :stateHighlighted as $.Toybox.Graphics.ColorType or $.Toybox.WatchUi.Drawable, :behavior as $.Toybox.Lang.Symbol, :locX as $.Toybox.Lang.Number, :locY as $.Toybox.Lang.Number, :stateDisabled as $.Toybox.Graphics.ColorType or $.Toybox.WatchUi.Drawable, :identifier as $.Toybox.Lang.Object, :width as $.Toybox.Lang.Number, :stateSelected as $.Toybox.Graphics.ColorType or $.Toybox.WatchUi.Drawable, :stateDefault as $.Toybox.Graphics.ColorType or $.Toybox.WatchUi.Drawable, :visible as $.Toybox.Lang.Boolean}'.

    For the call to setLayout():

    Passing '$.Toybox.Lang.Array<Any>' as parameter 1 of poly type 'PolyType<Null or $.Toybox.Lang.Array<$.Toybox.WatchUi.Drawable>>'.

    To fix these problems:

    - Specify the return type of setupStartMatchButton()

    - Specify the type of the dc argument to setupStartMatchButton()

    - Remove the unnecessary casts

    - Add a cast to the [button] array (unfortunately, this is currently necessary afaik, since the type checker can't infer container types yet)

    Try something like this:

    function setupStartMatchButton(dc as Graphics.Dc) as Void {
        var options = {
            :locX => 0,
            :locY => dc.getHeight() / 3,
            :width => dc.getWidth(),
            :height => dc.getHeight() / 3,
            // :behavior => :onStartMatch,
            :stateHighlighted => Graphics.COLOR_RED,
            :stateDefault => Graphics.COLOR_WHITE 
        };
    
        var button = new WatchUi.Button(options);
        setLayout([button] as Array<Drawable>); // this cast is unfortunate, but it's necessary due to a limitation in the type checker
    }

  • This didn't change anything for me so I investigated some more and figured that it's not in the mc files. But it's in a template

    <layout id="game_result">
      <label id="game_result_won_text" x="center" y="10%" font="Gfx.FONT_LARGE" color="Gfx.COLOR_WHITE" justification="Gfx.TEXT_JUSTIFY_CENTER" />
      <label id="game_result_score" x="center" y="22%" font="Gfx.FONT_LARGE" color="Gfx.COLOR_WHITE" justification="Gfx.TEXT_JUSTIFY_CENTER" />
      <label id="game_result_lapsed_time" x="center" y="34%" font="Gfx.FONT_SMALL" color="Gfx.COLOR_WHITE" justification="Gfx.TEXT_JUSTIFY_CENTER" />
      <label id="game_result_steps" x="center" y="45%" font="Gfx.FONT_SMALL" color="Gfx.COLOR_WHITE" justification="Gfx.TEXT_JUSTIFY_CENTER" />
      <label id="game_result_match" x="center" y="56%" font="Gfx.FONT_SMALL" color="Gfx.COLOR_WHITE" justification="Gfx.TEXT_JUSTIFY_CENTER" />
      <label id="game_result_what_next" x="center" y="65%" font="Gfx.FONT_XTINY" color="Gfx.COLOR_WHITE" justification="Gfx.TEXT_JUSTIFY_CENTER" />
      <button x="0%" y="75%" width="35%" height="25%" background="Graphics.COLOR_WHITE" behavior="onYouServing">
        <state id="stateDefault" color="Graphics.COLOR_WHITE" />
        <state id="stateHighlighted" color="Graphics.COLOR_PURPLE" />
        <state id="stateSelected" color="Graphics.COLOR_YELLOW" />
        <state id="stateDisabled" color="Graphics.COLOR_BLACK" />
      </button>
      <label id="game_result_next_server_you" x="25%" y="75%" font="Gfx.FONT_SMALL" color="Gfx.COLOR_BLACK" justification="Gfx.TEXT_JUSTIFY_CENTER" />
      <button x="37%" y="75%" width="26%" height="25%" background="Graphics.COLOR_WHITE" behavior="onFinish">
        <state id="stateDefault" color="Graphics.COLOR_WHITE" />
        <state id="stateHighlighted" color="Graphics.COLOR_PURPLE" />
        <state id="stateSelected" color="Graphics.COLOR_YELLOW" />
        <state id="stateDisabled" color="Graphics.COLOR_BLACK" />
      </button>
      <label id="game_result_finish_match" x="50%" y="75%" font="Gfx.FONT_SMALL" color="Gfx.COLOR_BLACK" justification="Gfx.TEXT_JUSTIFY_CENTER" />
      <button x="65%" y="75%" width="35%" height="25%" background="Graphics.COLOR_WHITE" behavior="onOpponentServing">
        <state id="stateDefault" color="Graphics.COLOR_WHITE" />
        <state id="stateHighlighted" color="Graphics.COLOR_PURPLE" />
        <state id="stateSelected" color="Graphics.COLOR_YELLOW" />
        <state id="stateDisabled" color="Graphics.COLOR_BLACK" />
      </button>
      <label id="game_result_next_server_opponent" x="75%" y="75%" font="Gfx.FONT_SMALL" color="Gfx.COLOR_BLACK" justification="Gfx.TEXT_JUSTIFY_CENTER" />
    </layout>

    I've got 3 errors when I remove these buttons the errors disappear. So there's something wrong with this file.
    I can't figure out what though. Hope you know what I'm missing here.

  • This didn't change anything for me so I investigated some more and figured that it's not in the mc files.

    That's what I originally thought, given that the error message referred to Rez.mc, which is auto-generated from your resource files. Maybe I should've been more specific.

    It also makes sense given that your error messages refer to an incorrect type of Float (where Number is expected) as opposed to Any.

    Seems like there's a bug with the type checker where percentages aren't allowed for button elements (although they should be.)

    You'll find the following code triggers the error:

    <layout id="game_result">
        <button x="0%" y="75%" width="35%" height="25%" background="Graphics.COLOR_WHITE" />
    </layout>

    If you remove the "%", the error goes away.

    <layout id="game_result">
        <button x="0" y="75" width="35" height="25" background="Graphics.COLOR_WHITE" />
    </layout>

    The problem doesn't happen for a label with "%" coordinates or dimensions, as you've noted.

    What seems to be happening is that "%" coordinates/dimensions are represented internally by floats (e.g. 99% = .99), but the type checker is trying to enforce a Number type where either Number or Float should be allowed.

    Seems like it's a pretty clear bug, since the Garmin doc explicitly says that "%" is allowed (and ofc bc it worked as expected previously).

    https://developer.garmin.com/connect-iq/core-topics/layouts/

    So it's a combo of what I guessed originally:

    - this is a compiler bug

    or

    - there's something wrong with your resources

    There's a compiler bug where it thinks there's something wrong with your resources.

    Sorry I didn't articulate that more clearly, but I hate making guesses without seeing code.

  • I think what you have here is:
    (dc.getHeight()) / (3 as Lang.Number)

    and what you intend to have is:

    (dc.getHeight() / 3) as Lang.Number

  • I think what you have here is:
    (dc.getHeight()) / (3 as Lang.Number)

    and what you intend to have is:

    (dc.getHeight() / 3) as Lang.Number

    Yeah, I said that above, but:

    - casting the result of (dc.getHeight() / 3) to a Number is unnecessary, *as long as dc is correctly typed as Graphics.Dc*, because dc.getHeight() returns a Number, and a Number divided by a Number is a Number

    - that's not the code which was causing that specific error anyway (note that the error refers to Rez.mc and also says that Float is unexpected where Number is required, but if the error was due to an untyped dc, the error would've referred to Any instead of float.)

    - As established above, the actual problem seems to be with the perfectly legit use of "%" units for the a button's coordinates/dimensions. (Note that the same usage works fine for labels.)

    TL;DR it seems to be a bug with the type checker and auto-genned resource code in the case of "%" units for a button.

    In any case, IMO devs should never see an error message which refers to an auto-genned file (especially when the contents of that file are not directly accessible.)