Skip to content

Draft: vala: check legality and usefulness of casts

The Vala compiler could do more to catch faulty and useless casts. For example:

class Foo {}
class Baz {}
class Bar : Foo {}

void main() {
    var baz = (Baz) new Foo ();
    var foo = (Foo) new Bar ();
}

The first cast is faulty. It will never succeed because Baz has no possible relationship to Foo. The second cast is unnecessary, because any Bar is a Foo. With this change, this is what the compiler outputs:

cast2.vala:6.15-6.30: error: Cast will always fail
    6 |     var baz = (Baz) new Foo ();
      |               ^~~~~~~~~~~~~~~~ 
cast2.vala:6.16-6.18: note: `Baz' does not relate to `Foo'
    6 |     var baz = (Baz) new Foo ();
      |                ^~~             
cast2.vala:7.15-7.30: warning: Useless cast from `Bar' to `Foo'
    7 |     var foo = (Foo) new Bar ();
      |               ^~~~~~~~~~~~~~~~ 
cast2.vala:7.16-7.18: note: `Foo' is a supertype of `Bar'
    7 |     var foo = (Foo) new Bar ();
      |                ^~~             
Compilation failed: 1 error(s), 1 warning(s)

This change is already catching some useless casts in real code. For example, Shotwell has many:

...
../src/dialogs/ExportDialog.vala:112.9-112.38: warning: Useless cast from `Gtk.Box' to `Gtk.Box'
  112 |         ((Gtk.Box) get_content_area()).add(table);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~            
../src/searches/SavedSearchDialog.vala:617.13-617.44: warning: Useless cast from `Gtk.Box' to `Gtk.Box'
  617 |             ((Gtk.Box) d.get_content_area()).add(cal);
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~          
../src/searches/SavedSearchDialog.vala:711.13-711.46: warning: Useless cast from `Gtk.HeaderBar' to `Gtk.HeaderBar'
  711 |             ((Gtk.HeaderBar) get_header_bar()).set_custom_title(search_title);
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                
../src/Printing.vala:686.9-686.44: warning: Useless cast from `Gtk.FontButton' to `Gtk.FontChooser'
  686 |         ((Gtk.FontChooser) title_print_font).set_font(fontname);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                    
../src/Printing.vala:686.11-686.25: note: `Gtk.FontChooser' is a supertype of `Gtk.FontButton'
  686 |         ((Gtk.FontChooser) title_print_font).set_font(fontname);
      |           ^~~~~~~~~~~~~~~                                       
../src/Printing.vala:699.16-699.51: warning: Useless cast from `Gtk.FontButton' to `Gtk.FontChooser'
  699 |         return ((Gtk.FontChooser) title_print_font).get_font();
      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~            
../src/Printing.vala:699.18-699.32: note: `Gtk.FontChooser' is a supertype of `Gtk.FontButton'
  699 |         return ((Gtk.FontChooser) title_print_font).get_font();
      |                  ^~~~~~~~~~~~~~~                               
../src/publishing/PublishingUI.vala:39.13-39.46: warning: Useless cast from `Gtk.HeaderBar' to `Gtk.HeaderBar'
   39 |             ((Gtk.HeaderBar) get_header_bar()).set_show_close_button(false);
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...

However, this is still a draft because I haven't yet handled casts between generic types.

Merge request reports