Description
Intended change in behavior
Both the CFE and the Analyzer don't report the error on the inferred type arguments that don't satisfy the type variable bound constraints. Consider the following program.
class TableContext {}
class Column {}
class TableSchema<F extends Column, C extends TableContext> {
factory TableSchema({required Iterable<F> fields, C? context}) =>
new TableSchema._();
TableSchema._();
}
var schema1 = TableSchema(fields: []); // Here the error is reported only with the applied fix.
void method() {
var schema2 = TableSchema(fields: []); // The error was reported here before and continues to be reported after the fix is applied.
// The error message is: Inferred type argument 'dynamic' doesn't conform to the bound 'Column' of the type variable 'F' on 'TableSchema'.
}
Here the type arguments inferred for the initializing expressions of either the schema1
or schema2
are dynamic
and TableContext
, and the first of those inferred type arguments is not a subtype of the corresponding bound Column
of the type variable F
.
However, both the CFE and the Analyzer report the error for the initializer of schema2
, but not for that of the top-level variable schema1
. This proposal suggests reporting the error in all contexts, including the initializers of top-level variables as shown in the example above and other kinds of contexts, for example, initializers of static class fields.
Rationale for making the change
Disallowing programs where some types don't respect their corresponding constraints removes potential soundness issues in the type system. Additionally, the proposed change treats all types that don't satisfy the corresponding bounds uniformly.
Expected impact of this change.
Since both tools are failing to report the erroneous code as a compile-time error, some programs containing top-level fields as described in the motivational example may fail to compile after the change is implemented.
Steps for mitigating the change
One way of adjusting the code that will fail to compile after the change is implemented is to supply the type arguments that satisfy their corresponding bounds in place of the inferred ones. In the example above, the line for schema1
can be corrected as follows:
var schema1 = TableSchema<Column, TableContext>(fields: []);
The line for schema2
can be corrected in a similar way.