If you declare a variable with a generic type Generic but omit the parameterized type, it's (usually1) shorthand for Generic<dynamic>. Inference does happen in your assignment, but not in the direction you expect: since you explicitly declared the type of mySet, the type of {1, 2, 3} is inferred from that explicit type (Set/Set<dynamic>) and becomes <dynamic>{1, 2, 3} instead of <int>{1, 2, 3}.
This is one reason why it can be better to omit explicit types and just allow types to be inferred when possible. Using:
var mySet = {1, 2, 3};
would allow mySet to be inferred as Set<int>. If you really want to use explicit types, you should ensure that you specify explicit types for generic type parameters too.
You can catch such errors by setting:
analyzer:
language:
strict-raw-types: true
in your analysis_options.yaml file. (You also might wish to enable:
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
too.)
Also see https://github.com/dart-lang/language/blob/master/resources/type-system/strict-raw-types.md:
void main() {
List a = [1, 2, 3];
}
Developers often think that inference fills in the type of a from the right side of the assignment. It may look like a has the type List<int>. But Dart fills in omitted type arguments, like E on List, with dynamic (or the corresponding type parameter's bound); List a; is purely a shorthand for List<dynamic> a;. Inference then flows from a onto the expression on the right side of the assignment.
1 Strictly speaking, if a generic's type parameter is constrained (e.g. class Generic<T extends Base>), then omitting the type parameter is shorthand for using that constraint (i.e., Generic would be shorthand for Generic<Base>). Most generics don't constraint their type parameters, so therefore it usually ends up being dynamic.