Dart implicit upcast generics warning? - dart

The following code compiles in Dart with no errors or warnings but will fail at runtime. Is there any way to opt in to warnings for implicit upcasting of generics in Dart?
List<Object> objects = <int>[]; // implicit generic upcast
objects.add('hello'); // runtime error: type 'String' is not a subtype of type 'int' of 'value'
I already have implicit-casts: false in my analysis_options.yaml.

There is no static analysis available today. The tracking issue discussing this problem, with some proposed solutions linked, is https://github.com/dart-lang/language/issues/213

Related

[F#][sharppcap][Error] "A type instantiation involves a byref type." what is a workaround in F#

I try to use SharpPcap in F#, but I was blocked by this compiler error for two days.
I find the most releate answer is What is the error "A type instantiation involves a byref type." and what is a workaround in F#, but do not fit my context well.
Please help me work around it, Thank you!
open System
open SharpPcap
open SharpPcap.LibPcap
let device = new CaptureFileReaderDevice("test.pcap")
// try workaround 1
let new_package (sender: Object) (e: PacketCapture) = ()
let handler = new PacketArrivalEventHandler(new_package)
device.OnPacketArrival.AddHandler(handler)
// error: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
// try workaround 2
let new_package (e: PacketCapture) = ()
device.OnPacketArrival.Add(new_package)
// error: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
I think the error is because:
public event PacketArrivalEventHandler OnPacketArrival;
public delegate void PacketArrivalEventHandler(object sender, PacketCapture e);
public readonly ref struct PacketCapture
{...}
The delegate PacketArrivalEventHandler use PacketCapture as param type, but this is a readonly ref struct which can not use to define F# function to add to Event OnPacketArrival.
Pls help me workaround it, Thank you!
I want make this line pass the F# compiler:
device.OnPacketArrival.Add(new_package)
In c# it used in this way:
device.OnPacketArrival += new_package
[FS0412] A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
You can't do this by using the F# IEvent first-class listening points, because in this case the type of device.OnPacketArrival ends up being IEvent<PacketArrivalEventHandler, ref<PacketCapture>>, whose second type parameter ref<PacketCapture> is not allowed. This is what the error message tells you.
But you can use the underlying .NET add_ and remove_ methods, which are analogs of property get_ and set_ methods, but for events. F# allows you to call these "hidden" methods explicitly, even though they're not listed in IDE completion lists.
device.add_OnPacketArrival handler
It works, because it's directly calling a method on the device object, rather than creating a wrapping value of type IEvent<...> and then calling .Add or .AddHandler on it.

F# seems to not leverage implicit .NET conversion operators

According to
https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-6.0#actionresultt-type
https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-6.0#asynchronous-action-1
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.actionresult-1?view=aspnetcore-6.0#operators
The following F# code should be legitimate:
[<HttpPost("post-data-2")>]
[<ProducesResponseType(StatusCodes.Status200OK)>]
[<ProducesResponseType(StatusCodes.Status500InternalServerError)>]
member this.PostData2(data: string): Task<ActionResult<int>> =
task {
try
return this.Ok(0)
with | x ->
return this.StatusCode(StatusCodes.Status500InternalServerError, -1)
}
Instead I get two compilation errors in the two 'return' lines
Error FS0193 Type constraint mismatch. The type
'OkObjectResult' is not compatible with type
'ActionResult'
and
Error FS0193 Type constraint mismatch. The type
'ObjectResult' is not compatible with type
'ActionResult'
This works however:
[<HttpPost("post-data-1")>]
[<ProducesResponseType(StatusCodes.Status200OK)>]
[<ProducesResponseType(StatusCodes.Status500InternalServerError)>]
member this.PostData1(data: string): Task<ActionResult<int>> =
task {
try
return ActionResult<int>(this.Ok(0))
with | x ->
return ActionResult<int>(this.StatusCode(StatusCodes.Status500InternalServerError, -1))
}
Why are the implicit cast operators not recognized by F#?
Not sure there can be much of an answer besides "because the language designers decided for it to be that way". Implicit conversions are only used in a narrow set of circumstances in F#.
In addition to calling the constructor as you have, you should also be able to explicitly call ActionResult.op_Implicit or define you own implicit conversion operator.

Nullability mismatch in simple assignment after switching to sound null safety

I switched to sound null safety and started getting runtime error in a simple assignment, that should never happen with sound null safety:
final widgetOnPressed = widget.onPressed;
Error:
type '(LogData) => void' is not a subtype of type '((LogData?) => void)?'
I can repro it for Flutter versions 2.12.0-4.1.pre and 2.13.0-0.0.pre.505.
PR: https://github.com/flutter/devtools/pull/3971
Failing line: https://github.com/flutter/devtools/blob/9fc560ff2e6749459e2ca6a1dc00bf6fb16ed93b/packages/devtools_app/lib/src/shared/table.dart#L1184
To repro, start DevTools at this PR for macos, connect to an app and click the tab 'Logging'. DevTools will show red screen and error in console.
Is it dart bug or the app bug? If it is the app bug, how can I debug it?
It's a bug in your code.
You didn't say which kind of error you got - a compile-time error or a runtime error. I'm guessing runtime error. (Well, you did say to launch it in the debugger, so that is a good hint too.)
The line final widgetOnPressed = widget.onPressed; looks like it can't possibly fail. After all, the type of the local variable is inferred from the expression assigned to it, and the runtime value of that expression will surely be a subtype of the static type because the type system is sound!
Isn't it? ISN'T IT?
It's not, sorry. Dart 2's type system is mostly sound, even more so with null safety, but class generics is covariant, which can still be unsound. It's fairly hard to hit one of the cases where that unsoundness shows its ugly head, but returning a function where the argument type is the class's type variable is one.
Your state class extends State<TableRow<T?>>, so the widget getter returns a TableRow<T?>. The onPressed of that type has type ItemCallback<T?>?, aka, void Function(T?)?.
You create a _TableRowState<LogData>, with its widget which has static type TableRow<LogData?>, but you somehow manage to pass it a TableRow<LogData> instead. That's fine. Class generics are covariant, so all is apparently fine at compile-time.
Then you do final widgetOnPressed = widget.onPressed;.
The static type of widgetOnPressed is void Function(LogData?) here.
The actual runtime type of onPressed is void Function(LogData) because it's from a TableRow<LogData>.
A void Function(LogData) is-not-a void Function(LogData?) because the former cannot be used in all places where the latter can (in particular, it can't be used in a place where it's called with null).
This assignment is potentially unsound, and actually unsound in this case. The compiler knows this and inserts an extra check to ensure that you don't assign a value to the variable which isn't actually valid. That check triggers and throws the error you see.
How do you avoid that?
Don't create a TableRow<LogData> where a TableRow<LogData?> is required.
Or type the variable as:
final ItemCallback<T>? widgetOnPressed = widget.onPressed;
(no ? on the T).
Or rewrite everything to avoid returning a function with a covariant type parameter (from the class) occurring contra-variantly (as an argument type).
Which solution fits you depends on what you want to be able to do.

Why dart analyzer fails to recognize a type error?

Here's the code:
static const _defaults = <String, dynamic>{
'api_key': '4839234792374',
'enabled': false,
'concurrency': 4,
};
String getString(String key) {
return _remoteConfig == null ?
_defaults.containsKey(key) && _defaults[key] :
_remoteConfig.getString(key);
}
The bug is obvious (and shame on me, was produced by blind copy-paste from similar getBool(key) function. If the _remoteConfig is null, the execution hits the bool && String path and I get the runtime exception type 'String' is not a subtype of type 'bool'. Totally legit, but why does analyzer not see it? The execution flow is crystal clear, one path returns String another path (theoretically) returns dynamic and the return type is String which means that all paths return String.
What I don't understand?
Dart 2.12.0
pedantic 1.11.0
Analyzer options:
include: package:pedantic/analysis_options.yaml
analyzer:
exclude:
- lib/generated/*
- lib/**/*.g.dar
I think you're asking two questions:
Why doesn't the analyzer complain about _defaults.containsKey(key) && _defaults[key]?
Why doesn't the analyzer complain about the ternary expression with different types along its two paths?
For #1: Since _defaults[key] returns type dynamic (which could be a bool at runtime), I wouldn't expect an analysis complaint.
For #2: Since the two paths have different types, the type of the ternary expression is the common base type: Object. If implicit casts are enabled, Object is then automatically cast to the String return type.
The analyzer does catch both errors if you disable implicit casts in your analysis_options.yaml configuration file:
analyzer:
strong-mode:
implicit-casts: false
Running the analyzer then prints:
error • The operands of the operator '&&' must be assignable to 'bool' at ... • (non_bool_operand)
error • A value of type 'Object' can't be returned from the function 'getString' because it has a return type of 'String' at ... • (return_of_invalid_type)
(I'm surprised that implicit-casts: false triggers an analysis error for the && expression with a dynamic operand,; maybe my understanding isn't quite accurate, or maybe that's a bug in the analyzer.)

Cannot convert from `GLib.TypeClass' to `GLib.ObjectClass'

I was trying to compile libfriends (source) against valac (.28) and libgee (1.0). I specifically compiled these against Ubuntu-16.04 stack.
But I am getting following error
entry.vala:397.38-397.38: warning: if-statement without body
if (_selected != value);
^
entry.vala:172.52-172.86: error: Argument 1: Cannot convert from `GLib.TypeClass' to `GLib.ObjectClass'
binding_set = Gtk.BindingSet.by_class (typeof (InputTextView).class_ref ());
I don't really find anything wrong with code. Any Idea?
The entire buildlog is here: https://launchpadlibrarian.net/263631082/buildlog_ubuntu-xenial-i386.libfriends_0.1.2+14.10.20140709+201606051415~ubuntu16.04.1_BUILDING.txt.gz
I just checked and it compiles with valac-0.18, but doesn't compile with valac-0.28.
So there must have been a change between those valac versions that does more strict type checking in this case.
GLib.TypeClass (really GTypeClass in C) is the parent class of GLib.ObjectClass (really GObjectClass in C).
So the compiler is correct to not allow this without a cast. I don't know if the cast is correct in this situation, but it makes the code compile:
binding_set = Gtk.BindingSet.by_class ((ObjectClass) typeof (InputTextView).class_ref ())
See also valadoc for GObjectClass where a similar typecast is done in the example code:
http://valadoc.org/#!api=gobject-2.0/GLib.ObjectClass

Resources