dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.08k stars 1.56k forks source link

Inference can't guess type argument of LinkedHashSet based on type argument of Set constructor #32634

Closed Hixie closed 6 years ago

Hixie commented 6 years ago
import 'dart:collection';

void main() {
  LinkedHashSet x = new Set<int>(); // A value of type 'Set<int>' can't be assigned to a variable of type 'LinkedHashSet'
}

It seems unambiguous that that should be a LinkedHashSet<int>.

zoechi commented 6 years ago

Quite similar to #31865

lrhn commented 6 years ago

It is indeed a duplicate of #31865. Dart 2 doesn't do inference on partial types, only on missing type arguments in expressions (basically in instance creation expressions and generic method calls). It means that Set<int> s = new Set() infers the type argument to the constructor, but Set s = new Set<int>() does not do inference on the type annotation, so Set here means Set<dynamic>.

natebosch commented 6 years ago

I don't think this is a duplicate. The Analyzer/Compiler error here isn't about <int> - it's about LinkedHashSet. @Hixie is asking that the Set factory constructor be able to leak details about the concrete subtype that is returned from a factory ctor- though that seems like an anti-feature to me.

matanlurey commented 6 years ago

Isn't the default Set type LinkedHashSet? https://github.com/dart-lang/sdk/blob/0b2684e6297217c690d082ce6f1d0e23215b5477/sdk/lib/core/set.dart#L49

... regardless, I don't see why this is an error, it should be valid to assign a Set<int> to a Set<dynamic>, just not the other way around. My error (#31865) is more about folks accidentally creating untyped collections when they think they are creating typed ones.

In @Hixie's case, his code looks totally valid, I think the CFE/Dart2 is doing the wrong thing (TM).

natebosch commented 6 years ago

Isn't the default Set type LinkedHashSet?

Yes, but that is an implementation detail, it is not exposed through the signature. Nor, in my opinion, should it be.

I don't see why this is an error, it should be valid to assign a Set<int> to a Set<dynamic>

That is valid and is not the error.

lrhn commented 6 years ago

The issue here is that the type of the variable is LinkedHashSet<dynamic> and the initializer expression has type Set<int>. A Set<int> is not a super- or sub-type of LinkedHashSet<dynamic> (they are both subtypes of Set<dynamic> and both supertypes of LinkedHashSet<int>, but the two types are not directly related. That makes the assignment not an implicit down-(or up-)cast.

Reading issue in #31865 again, it's not exactly the same problem, but it boils down to the issue that there is no inference for LinkedHashSet x = ..., it always becomes LinkedHashSet<dynamic> x = .... That's what's happening here, and it's currently working as intended.

Hixie commented 6 years ago

The issue here is that the type of the variable is LinkedHashSet<dynamic> and the initializer expression has type Set<int>.

Right, this bug was requesting that the variable be typed using inference instead of defaulting to dynamic.