Skip to content

Fasta strong mode inference confused same class extending Base<C> and mixing class extending Base<B> #31656

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mraleph opened this issue Dec 14, 2017 · 32 comments
Assignees
Labels
customer-flutter customer-vm legacy-area-front-end Legacy: Use area-dart-model instead. P0 A serious issue requiring immediate resolution

Comments

@mraleph
Copy link
Member

mraleph commented Dec 14, 2017

The code below is extracted from Flutter codebase with classes renamed for brevity.

abstract class B {
}

class C extends B {
  bool c;
}

abstract class Base<T extends B> {
  T get f => null;
}

abstract class M extends Base<B> {
}

class X extends Base<C> with M {
  bool problem() => f.c;
}

Here class X is extending Base<C> and also mixing class M which extends Base<B> where C extends B. Base<T> has a getter f returning T. In class X which extends Base<C> therefore it is expected that f returns C. However Fasta in strong mode reports:

flu.dart:19:19: Error: The getter 'c' isn't defined for the class '#lib1::B'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'c'.
   bool get c => f.c;
                   ^

This means it thinks f returns B and not C. Furthermore Fasta also generates throw of a compile error in X.problem body.

    method problem() → core::bool
      return (let final dynamic #t1 = this.{flu::Base::f} in let dynamic _ = null in const core2::_ConstantExpressionError::•().{core2::_ConstantExpressionError::_throw}(new core2::_CompileTimeError::•("file:///usr/local/google/home/vegorov/src/dart/sdk/t/flu.dart:19:23: Error: The getter 'c' isn't defined for the class '#lib1::B'.\nTry correcting the name to the name of an existing getter, or defining a getter or field named 'c'.\n  bool problem() => f.c;\n                      ^"))) as{TypeError} core2::bool;

@lrhn can you take a look at this code and say if it is expected to compile and run correctly according to the current thinking about mixins in Dart 2.

If it is we will need this to be fixed in Fasta.

I am marking this as P0 because this completely blocks us from running Flutter in strong mode with no workaround available.

/cc @lrhn @leafpetersen @stereotype441 @kmillikin @a-siva

@mraleph mraleph added legacy-area-front-end Legacy: Use area-dart-model instead. customer-flutter customer-vm P0 A serious issue requiring immediate resolution labels Dec 14, 2017
@mraleph mraleph added this to the 2.0-alpha milestone Dec 14, 2017
@mraleph
Copy link
Member Author

mraleph commented Dec 14, 2017

@stereotype441 if there is something quick we could patch into the Fasta inference to make this case work that would also be appreciated.

@stereotype441
Copy link
Member

Uh oh. It's a fundamental limitation of both kernel and fasta, as currently implemented, that no class can implement any other class multiple times with different type arguments. IIRC, this limitation was inherited from dart2js, and at some point in the last few months I believe @leafpetersen and @lrhn discussed the idea of making the limitation explicit in the Dart 2.0 spec. @leafpetersen can you confirm?

Fully relaxing this limitation would be nontrivial, because it underlies the design of the kernel ClassHierarchy API, which is used pervasively. Specificially, ClassHierarchy.getClassAsInstanceOf and ClassHierarchy.getTypeAsInstanceOf are intended to return a single result. If we allowed code like you quote above, it's not clear whether ClassHierarchy.getClassAsInstanceOf(X, Base) should return Base<B> or Base<C>.

Unfortunately, I can't think of something quick we could patch into Fasta inference to make this work. The best workaround I can think of is as follows: partially relax the limitation, changing the rule to say "a class can implement another class multiple times with different type arguments, provided that one of the implemented types is a subtype of all the others". Then we could modify ClassHierarchy.getClassAsInstanceOf and ClassHierarchy.getTypeAsInstanceOf to return the implemented type that is a subtype of all the others.

So in the example above, ClassHierarchy.getClassAsInstanceOf(X, Base) would return Base<C> since Base<C> is a subtype of Base<B>. This would fix the @mraleph saw because the front end type inferrer uses ClassHierarchy.getTypeAsInstanceOf to figure out the appropriate substitution to do when inferring the type of f, so it would infer a type of C, and then the getter c would be found in class C.

@kmillikin the would all have to be made to ClassHierarchy, which is not really code I'm terribly familiar with. What do you think? The chief complication as I see it would be that currently ClassHierarchy doesn't contain a reference to TypeEnvironment, so ClassHierarchy can't do the necessary subtype checks to figure out which implementation is a subtype of the others (if any).

I'm happy to discuss this in more detail over VC if that would be helpful.

@stereotype441
Copy link
Member

stereotype441 commented Dec 14, 2017

Here's an idea for a quicker (but more fragile) workaround: change the forEach loop in ClosedWorldClassHierarchy._recordSuperTypes from this:

      superInfo.genericSuperTypes?.forEach((Class key, Supertype type) {
        subInfo.genericSuperTypes[key] = substitution.substituteSupertype(type);
      });

to this:

      superInfo.genericSuperTypes?.forEach((Class key, Supertype type) {
        if (!subInfo.genericSuperTypes.contains(key)) {
          subInfo.genericSuperTypes[key] = substitution.substituteSupertype(type);
        }
      });

When determining which interfaces a given class implements, the supertype is visited first, then mixins, then classes in the "implements" clause. This will ensure that the interface seen first dominates, so in the example above, the extends Base<C> will dominate.

You'll also need to make the same change to IncrementalClassHierarchy._recordSuperTypes.

@lrhn
Copy link
Member

lrhn commented Dec 15, 2017

I can confirm that we sanctioned the "no implementing two different instantiations of the same interface" rule for Dart 2. So no, it's not supposed to compile in Dart 2.

This is one of the reasons we can even add the "extractTypeParameter" function - otherwise its behavior would be underdefined, and it makes the "flatten" spec function well-defined too. It's a good thing.

If being this restrictive turns out to be a problem in practice, we might be able to loosen that in the future, by allowing multiple implementations of the same interface, as long as one of them is the most specific one, and that is the one that is used whenever it matters.
Since dart2js never allowed it, most general purpose code should not have a problem.

@mraleph
Copy link
Member Author

mraleph commented Dec 15, 2017

If being this restrictive turns out to be a problem in practice, we might be able to loosen that in the future, by allowing multiple implementations of the same interface, as long as one of them is the most specific one, and that is the one that is used whenever it matters.

Could we relax it now rather then in the future? It seems absolutely reasonable that application should be able to satisfy mixin requirement with a more specific class. It already works when generics are not involved, so it's not clear why it should not work when generics are involved, especially when these generics are fully instantiated like here.

This seems to be a pretty common pattern in Flutter. To give you a real example:

abstract class State<T extends StatefulWidget> extends Diagnosticable {
  T get widget;
}

abstract class AutomaticKeepAliveClientMixin extends State<StatefulWidget> {
}

class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
   bool get _directionIsXAxis {
    // here widget is expected to be Dismissable
     return widget.direction == DismissDirection.horizontal
         || widget.direction == DismissDirection.endToStart
         || widget.direction == DismissDirection.startToEnd;
   }
}

As a workaround I guess I could rewrite this code as:

class _DismissibleState extends State<StatefulWidget> with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
  @override
  Dismissible get widget => super.widget; 

   bool get _directionIsXAxis {
     return widget.direction == DismissDirection.horizontal
         || widget.direction == DismissDirection.endToStart
         || widget.direction == DismissDirection.startToEnd;
   }
}

but that also affects few other methods in State<T> that reference T, which would mean you need to override them as well to tighten T.

@leafpetersen
Copy link
Member

I try not to understand mixins, (with a fair bit of success I think it's fair to say), but while I had the same initial thought (that this produced something with two different interfaces at the same type), is that really the case (or rather, should it be)? My understanding of

abstract class M extends Base<B> {
}

when thought of as a mixin would be that Base<B> is a constraint on the superclass, not an interface directly provided by M. I don't remember if Lasse's proposal for Dart 2.0 mixins allow them to be used as interfaces or not? If not, I think there's not problem in Dart 2.0: you just say that X has only the direct interface Base<C> which is a subtype of Base<B>.

If they are usable as interfaces, then perhaps there's a problem, I'm not sure. It doesn't seem like you need to keep both around on the instance, but you do presumably need to know that M <: Base<B>. Or maybe not? Maybe you just say that the interface induced by a super mixin is only itself, not including the super interfaces?

Ahh mixins.

@lrhn
Copy link
Member

lrhn commented Dec 17, 2017

What you are seeing is a consequence of using class syntax to introduce mixins (something it's not very well suited for, and the reason we want to introduce dedicated mixin declarations).

abstract class M extends Base<B> {}

This is a class declaration. It might be intended as a mixin, but here it is just a class declaration. The class M implements Base<B> because the interface of the superclass is always a superinterface of the class.

When you do a mixin application of the mixin derived from M, that mixin application also implements the interface of M - and therefore also implements Base<B>.

I don't remember if we ever decided whether the new mixin syntax would introduce an interface. I'd be willing to say no, because then it wouldn't automatically implement the super-constraints.
Making the mixin a nominative type, but not including its supertypes as superinterfaces, will be odd. It's like saying class X extends private Y ... so that X inherits Y but doesn't implement it. Sure, it's possible, and C++ does it, but it'll feel weird. It'll probably work for mixins because the mixin application will always inherit a suitable super-interface from the superclass, but you would't be able to do: M mixinApplication = ... ; Base<B> b = mixinAppliation;.

Now, I'm not sure mixins is the only problem here.

If we have family polymorphism, like we do in Flutter in some cases, then it's likely we'll see code like:

abstract class Widget<S extends WidgetState> { ... }
class TextWidget implements Widget<TextWidgetState> { ... }
class UnderlinedTextWidget extends TextWidget implements Widget<UnderlinedTextWidgetState> { ... }

(I don't know Flutter well enough to say that it happens, but I wouldn't be surprised).
This has exactly the same issue, without any mixins. You cannot specialize a class implementing SomeWidget<SomeWidgetState> to SpecializedWidget<SpecializedWidgetState>, you have to have a common generic superclass instead.

The question is whether we want to support it, or require it to be rewritten into:

abstract class Widget<S extends WidgetState> { ... }
class TextWidgetBase implements Widget<T extends TextWidgetState> { ... }
class TextWidget extends TextWidgetBase<TextWidgetState> { }
class UnderlinedTextWidget extends TextWidgetBase<UnderlinedTextWidgetState> { ... }

(which is an option).

@leafpetersen
Copy link
Member

My preferred state would be that mixins have their own syntax, and are thought of as functions from classes to classes rather than classes in an of themselves, and hence have no interface of their own (or alternatively, have a higher order interface : Base -> Result).

Obviously, we're not there yet, and we need to get flutter up and running, so I don't see any good alternatives other than allowing multiple interfaces.

It seems like the proposal to allow classes to implement the same interface multiple times so long as there was one most precise version of the interface would be reasonable: it seems like at least for runtime subtyping purposes implementations could only record the most precise interface. For static checking the implementations would need to record all of them. Does this seem right? Can dart2js still use its existing approach and be compliant with this, or are there corner cases where it needs to know all of the super-interfaces?

This is subject to the restriction we discussed, that all concrete method implementations must satsify all of the super-interfaces, not just the most specific one.

@lrhn
Copy link
Member

lrhn commented Jan 2, 2018

It seems like the proposal to allow classes to implement the same interface multiple times so long as there was one most precise version of the interface would be reasonable: it seems like at least for runtime subtyping purposes implementations could only record the most precise interface. For static checking the implementations would need to record all of them. Does this seem right?

I don't see why static checking would be different, as long as it is just subtype checks.

Can dart2js still use its existing approach and be compliant with this, or are there corner cases where it needs to know all of the super-interfaces?

The one corner-case I can think if is covariant parameters. We have so far said that an overriding covariant parameter must be a sub- or super-type of every super-interface parameter that it overrides.
It then matters whether add(num) is an actual super-interface or just a super-type.
I'd love to change that instead, and just require covariant overrides to have to be a super- or sub-type of the immediate super-interface method parameters.
(Or, in other words, I'd like to get to the point where it doesn't matter if something is a super-interface or "just" a super-type—interface declarations would just be one way to introduce a super-type).

The other corner-case is someone wanting to implement interfaces that implement List<Object> and List<dynamic> respectively (and add List<void> for even more "fun"), since either is more specific than the other. We need to pick one of them as the actual static List-type for the class. There is no way to manually disambiguate, so making it an error is likely problematic.
We have similar issues in other places, so maybe we need to find a way to order our infinitely many top-types, void, dynamic, Object, FutureOr<Object>, etc., for preference when we need to choose between them (and in a way that generalizes to choosing between types like Map<Object, void> vs Map<dynamic, Object>). One option is picking the one from the syntactically first interface in the class declaration.

Apart from that, @johnniwinther WDYT?

@johnniwinther
Copy link
Member

The dart2js implementation won't work out-of-the-box. The current implementation assumes that the type-hierarchy of the the superclass can be augmented to create the type-hierarchy for the class itself. With the proposed change this will not be possible, since for instance TextWidget has Widget<TextWidgetState> in its type-hierarchy, but UnderlinedTextWidget would need to replace this by Widget<UnderlinedTextWidget>.

Having done this through-out dart2js, though, the dart2js runtime has no problems with the new rules.

@kmillikin kmillikin self-assigned this Jan 3, 2018
@kmillikin
Copy link

I will try to fix this in Kernel's type hierarchy by always choosing the more specific instantiation.

@kmillikin kmillikin added P1 A high priority bug; for example, a single project is unusable or has many test failures and removed P0 A serious issue requiring immediate resolution labels Jan 3, 2018
@kmillikin
Copy link

The fix for this will be easier when we fix the related issues #30674 and #31118. The code we generate for the named mixin application Base<C> with M and its use looks like:

abstract class Base&M<U> = Base<U> with M;

class X extends Base&M<C> ...

The mixin application class Base&M is inheriting the interface type Base<B> from M and Base<U extends Object> from Base. We would like to choose the more specific of the two interfaces but there isn't one due to the generic mixin application.

@leafpetersen
Copy link
Member

cc @a-siva @aam who just ran into this trying to compile flutter.

@a-siva
Copy link
Contributor

a-siva commented Jan 5, 2018

I think this is a critical issue to fix so we can make progress on getting flutter running in strong mode.
Can we bump the severity back to P0 as it is blocking forward progress.

Also I don't understand why issue #30674 which is related per comment above is not marked at severity P1

@a-siva
Copy link
Contributor

a-siva commented Jan 7, 2018

If you want reproduction instructions compiling the flutter code, you would have to check out flutter/engine and flutter/flutter and then execute -

<flutter_engine_checkout>/engine/src/out/host_release/dart-sdk/bin/dart <flutter_engine_checkout>/engine/src/out/host_release/gen/frontend_server.dart.snapshot --sdk-root <flutter_engine_checkout>/engine/src/out/android_release/flutter_patched_sdk/ --aot --strong
<flutter_flutter_checkout>/flutter/examples/hello_world/lib/main.dart

This will produce a slew of errors -

file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/animated_list.dart:166:46: Error: A value of type '#lib1::State<#lib1::StatefulWidget>' can't be assigned to a variable of type '#lib2::AnimatedListState'. Try changing the type of the left hand side, or casting the right hand side to '#lib2::AnimatedListState'. final AnimatedListState result = context.ancestorStateOfType(const TypeMatcher<AnimatedListState>()); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:212:19: Error: The getter 'direction' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'direction'. return widget.direction == DismissDirection.horizontal ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:213:19: Error: The getter 'direction' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'direction'. || widget.direction == DismissDirection.endToStart ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:214:19: Error: The getter 'direction' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'direction'. || widget.direction == DismissDirection.startToEnd; ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:264:20: Error: The getter 'direction' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'direction'. switch (widget.direction) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:325:19: Error: The getter 'direction' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'direction'. assert(widget.direction != null); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:368:21: Error: The getter 'dismissThresholds' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'dismissThresholds'. if ((widget.dismissThresholds[_dismissDirection] ?? _kDismissThreshold) >= 1.0) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:383:47: Error: The getter 'dismissThresholds' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'dismissThresholds'. if (_moveController.value > (widget.dismissThresholds[_dismissDirection] ?? _kDismissThreshold)) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:404:16: Error: The getter 'resizeDuration' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'resizeDuration'. if (widget.resizeDuration == null) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:405:18: Error: The getter 'onDismissed' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'onDismissed'. if (widget.onDismissed != null) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:408:16: Error: The method 'onDismissed' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing method, or defining a method named 'onDismissed'. widget.onDismissed(direction); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:411:68: Error: The getter 'resizeDuration' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'resizeDuration'. _resizeController = new AnimationController(duration: widget.resizeDuration, vsync: this) ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:430:18: Error: The getter 'onDismissed' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'onDismissed'. if (widget.onDismissed != null) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:433:16: Error: The method 'onDismissed' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing method, or defining a method named 'onDismissed'. widget.onDismissed(direction); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:436:18: Error: The getter 'onResize' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'onResize'. if (widget.onResize != null) ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:437:16: Error: The method 'onResize' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing method, or defining a method named 'onResize'. widget.onResize(); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:447:32: Error: The getter 'background' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'background'. Widget background = widget.background; ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:448:16: Error: The getter 'secondaryBackground' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'secondaryBackground'. if (widget.secondaryBackground != null) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:451:29: Error: The getter 'secondaryBackground' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'secondaryBackground'. background = widget.secondaryBackground; ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/dismissible.dart:481:21: Error: The getter 'child' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'child'. child: widget.child ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:315:36: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. bool get wantKeepAlive => widget.focusNode.hasFocus; ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:322:12: Error: The getter 'controller' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'controller'. widget.controller.addListener(_didChangeTextEditingValue); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:323:12: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. widget.focusNode.addListener(_handleFocusChanged); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:330:34: Error: The getter 'autofocus' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'autofocus'. if (!_didAutoFocus && widget.autofocus) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:331:47: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. FocusScope.of(context).autofocus(widget.focusNode); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:339:16: Error: The getter 'controller' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'controller'. if (widget.controller != oldWidget.controller) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:341:14: Error: The getter 'controller' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'controller'. widget.controller.addListener(_didChangeTextEditingValue); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:344:16: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. if (widget.focusNode != oldWidget.focusNode) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:346:14: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. widget.focusNode.addListener(_handleFocusChanged); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:353:12: Error: The getter 'controller' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'controller'. widget.controller.removeListener(_didChangeTextEditingValue); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:360:12: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. widget.focusNode.removeListener(_handleFocusChanged); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:372:18: Error: The getter 'obscureText' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'obscureText'. if (widget.obscureText && value.text.length == _value.text.length + 1) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:385:16: Error: The getter 'controller' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'controller'. widget.controller.clearComposing(); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:386:16: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. widget.focusNode.unfocus(); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:387:20: Error: The getter 'onSubmitted' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'onSubmitted'. if (widget.onSubmitted != null) ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:388:18: Error: The method 'onSubmitted' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing method, or defining a method named 'onSubmitted'. widget.onSubmitted(_value.text); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:406:41: Error: The getter 'controller' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'controller'. TextEditingValue get _value => widget.controller.value; ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:408:12: Error: The getter 'controller' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'controller'. widget.controller.value = value; ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:411:32: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. bool get _hasFocus => widget.focusNode.hasFocus; ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:412:35: Error: The getter 'maxLines' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'maxLines'. bool get _isMultiline => widget.maxLines != 1; ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:435:33: Error: The getter 'keyboardType' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'keyboardType'. inputType: widget.keyboardType, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:436:35: Error: The getter 'obscureText' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'obscureText'. obscureText: widget.obscureText, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:437:35: Error: The getter 'autocorrect' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'autocorrect'. autocorrect: widget.autocorrect, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:438:35: Error: The getter 'keyboardType' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'keyboardType'. inputAction: widget.keyboardType == TextInputType.multiline ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:456:29: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. if (_hasFocus && widget.focusNode.consumeKeyboardToken()) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:460:14: Error: The getter 'controller' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'controller'. widget.controller.clearComposing(); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:475:50: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. FocusScope.of(context).requestFocus(widget.focusNode); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:495:12: Error: The getter 'controller' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'controller'. widget.controller.selection = selection; ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:503:16: Error: The getter 'selectionControls' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'selectionControls'. if (widget.selectionControls != null) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:511:35: Error: The getter 'selectionControls' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'selectionControls'. selectionControls: widget.selectionControls, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:518:18: Error: The getter 'onSelectionChanged' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'onSelectionChanged'. if (widget.onSelectionChanged != null) ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:519:16: Error: The method 'onSelectionChanged' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing method, or defining a method named 'onSelectionChanged'. widget.onSelectionChanged(selection, cause); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:548:16: Error: The getter 'inputFormatters' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'inputFormatters'. if (widget.inputFormatters != null && widget.inputFormatters.isNotEmpty) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:548:50: Error: The getter 'inputFormatters' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'inputFormatters'. if (widget.inputFormatters != null && widget.inputFormatters.isNotEmpty) { ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:549:51: Error: The getter 'inputFormatters' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'inputFormatters'. for (TextInputFormatter formatter in widget.inputFormatters) ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:556:31: Error: The getter 'onChanged' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'onChanged'. if (textChanged && widget.onChanged != null) ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:557:14: Error: The method 'onChanged' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing method, or defining a method named 'onChanged'. widget.onChanged(value.text); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:626:41: Error: The getter 'textDirection' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'textDirection'. final TextDirection result = widget.textDirection ?? Directionality.of(context); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:633:52: Error: The getter 'focusNode' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'focusNode'. FocusScope.of(context).reparentIfNeeded(widget.focusNode); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:644:27: Error: The getter 'style' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'style'. style: widget.style, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:645:33: Error: The getter 'cursorColor' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'cursorColor'. cursorColor: widget.cursorColor, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:648:30: Error: The getter 'maxLines' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'maxLines'. maxLines: widget.maxLines, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:649:36: Error: The getter 'selectionColor' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'selectionColor'. selectionColor: widget.selectionColor, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:650:37: Error: The getter 'textScaleFactor' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'textScaleFactor'. textScaleFactor: widget.textScaleFactor ?? MediaQuery.of(context, nullOk: true)?.textScaleFactor ?? 1.0, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:651:31: Error: The getter 'textAlign' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'textAlign'. textAlign: widget.textAlign, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:653:33: Error: The getter 'obscureText' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'obscureText'. obscureText: widget.obscureText, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/editable_text.dart:655:33: Error: The getter 'autocorrect' isn't defined for the class '#lib1::StatefulWidget'. Try correcting the name to the name of an existing getter, or defining a getter or field named 'autocorrect'. autocorrect: widget.autocorrect, ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart:284:46: Error: A value of type '#lib1::_FadeInImageState' can't be assigned to a variable of type '#lib2::State<#lib2::StatefulWidget>'. Try changing the type of the left hand side, or casting the right hand side to '#lib2::State<#lib2::StatefulWidget>'. State<StatefulWidget> createState() => new _FadeInImageState(); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/framework.dart:120:50: Error: A value of type 'dart.collection::HashSet<#lib1::GlobalKey<dynamic>>' can't be assigned to a variable of type 'dart.core::Set<#lib1::GlobalKey<#lib1::State<#lib1::StatefulWidget>>>'. Try changing the type of the left hand side, or casting the right hand side to 'dart.core::Set<#lib1::GlobalKey<#lib1::State<#lib1::StatefulWidget>>>'. static final Set<GlobalKey> _removedKeys = new HashSet<GlobalKey>(); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/framework.dart:2272:76: Error: A value of type 'dart.collection::HashMap<#lib1::Element, dart.core::Set<#lib1::GlobalKey<dynamic>>>' can't be assigned to a variable of type 'dart.core::Map<#lib1::Element, dart.core::Set<#lib1::GlobalKey<#lib1::State<#lib1::StatefulWidget>>>>'. Try changing the type of the left hand side, or casting the right hand side to 'dart.core::Map<#lib1::Element, dart.core::Set<#lib1::GlobalKey<#lib1::State<#lib1::StatefulWidget>>>>'. _debugElementsThatWillNeedToBeRebuiltDueToGlobalKeyShenanigans ??= new HashMap<Element, Set<GlobalKey>>(); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/framework.dart:2274:36: Error: A value of type 'dart.collection::HashSet<#lib1::GlobalKey<dynamic>>' can't be assigned to a variable of type 'dart.core::Set<#lib1::GlobalKey<#lib1::State<#lib1::StatefulWidget>>>'. Try changing the type of the left hand side, or casting the right hand side to 'dart.core::Set<#lib1::GlobalKey<#lib1::State<#lib1::StatefulWidget>>>'. .putIfAbsent(node, () => new HashSet<GlobalKey>()); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/navigator.dart:623:46: Error: A value of type '#lib1::State<#lib1::StatefulWidget>' can't be assigned to a variable of type '#lib2::NavigatorState'. Try changing the type of the left hand side, or casting the right hand side to '#lib2::NavigatorState'. final NavigatorState navigator = context.ancestorStateOfType(const TypeMatcher<NavigatorState>()); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/navigator.dart:721:9: Error: A value of type '#lib1::State<#lib1::StatefulWidget>' can't be assigned to a variable of type '#lib2::NavigatorState'. Try changing the type of the left hand side, or casting the right hand side to '#lib2::NavigatorState'. ? context.rootAncestorStateOfType(const TypeMatcher<NavigatorState>()) ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/overlay.dart:238:41: Error: A value of type '#lib1::State<#lib1::StatefulWidget>' can't be assigned to a variable of type '#lib2::OverlayState'. Try changing the type of the left hand side, or casting the right hand side to '#lib2::OverlayState'. final OverlayState result = context.ancestorStateOfType(const TypeMatcher<OverlayState>()); ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart:276:36: Error: A value of type '#lib1::RenderObject' can't be assigned to a variable of type '#lib2::Element'. Try changing the type of the left hand side, or casting the right hand side to '#lib2::Element'. selection.currentElement = object; ^ file:///usr/local/google/home/asiva/workspace/flutter-roll/flutter/packages/flutter/lib/src/rendering/binding.dart:295:11: Warning: Superclass has no method named 'hitTest'. super.hitTest(result, position); // ignore: abstract_super_member_reference

@mit-mit mit-mit added P0 A serious issue requiring immediate resolution and removed P1 A high priority bug; for example, a single project is unusable or has many test failures labels Jan 8, 2018
@mit-mit
Copy link
Member

mit-mit commented Jan 8, 2018

Moving to P0, this is blocking #31789

@mit-mit mit-mit assigned peter-ahe-google and unassigned lrhn Jan 8, 2018
@peter-ahe-google
Copy link
Contributor

The problem doesn't reproduce in this example that should be equivalent.

This is mostly a note to myself, I'll pick this up tomorrow.

$ cat t.dart
abstract class Box {
  Object get t;
}

abstract class Case {
  String get t;
}

abstract class BoxCase implements Case, Box {
  m() {
    t.replaceAll("", "");
  }
}

main() {}
$ ./fasta compile t.dart --dump-ir --strong
Note: strong mode support is preliminary and may not work.
library;
import self as self;
import "dart:core" as core;

abstract class Box extends core::Object {
  default constructor •() → void
    : super core::Object::•()
    ;
  abstract get t() → core::Object;
}
abstract class Case extends core::Object {
  default constructor •() → void
    : super core::Object::•()
    ;
  abstract get t() → core::String;
}
abstract class BoxCase extends core::Object implements self::Box, self::Case {
  default constructor •() → void
    : super core::Object::•()
    ;
  method m() → dynamic {
    this.{self::BoxCase::t}.{core::String::replaceAll}("", "");
  }
  abstract forwarding-stub get t() → core::String;
}
static method main() → dynamic {}

@leafpetersen
Copy link
Member

@ahe I think this is specific to having the same generic class as multiple super-interfaces, instantiated at multiple different types.

@peter-ahe-google
Copy link
Contributor

@leafpetersen that is correct. However, as I discussed this with @sjindel-google, he pointed out that these situations are similar.

Since we add a forwarding stub in my example above, that's probably also how we should solve it for the case reported in this bug.

@peter-ahe-google
Copy link
Contributor

I focused on implicit new for constructor invocations today. Given how much progress I made on that, I'm comfortable dropping everything else and attempt to fix this tomorrow.

However, if @stereotype441 can extend pkg/front_end/lib/src/fasta/type_inference/interface_resolver.dart to handle this case as well as it handles BoxCase above, that would be most welcome!

@mraleph
Copy link
Member Author

mraleph commented Jan 9, 2018

For the sake of completeness: I have tried workaround from the comment #31656 (comment) above and it did not fix the issues we are seeing with Flutter.

Now we see even more issues that all have this issue as root cause. Now the earliest assertion you hit when you try to run Flutter in strong mode is this:

[  +10 ms] I/flutter (32235): The following _CompileTimeError was thrown building                                                        
[   +1 ms] I/flutter (32235): Scaffold-[LabeledGlobalKey<ScaffoldState>#607fd](dirty, state: ScaffoldState#dc69e):                       
[        ] I/flutter (32235): 'package:flutter/src/material/scaffold.dart': error: line 994 pos 16:                                      
[        ] I/flutter (32235): file:///usr/local/google/home/vegorov/src/flutter-clean/flutter/packages/flutter/lib/src/material/scaffold.dart:994:16:
[        ] I/flutter (32235): Error: A value of type '#lib1::GlobalKey<#lib2::DrawerControllerState>' can't be assigned to a             
[        ] I/flutter (32235): variable of type '#lib1::GlobalKey<#lib1::State<#lib1::StatefulWidget>>'.                                  
[        ] I/flutter (32235): Try changing the type of the left hand side, or casting the right hand side to                             
[        ] I/flutter (32235): '#lib1::GlobalKey<#lib1::State<#lib1::StatefulWidget>>'.                                                   
[        ] I/flutter (32235):           key: _drawerKey,                                                                                 
[        ] I/flutter (32235):                ^                                                                                                                                                                                                                                    
[        ] I/flutter (32235):           key: _drawerKey,                                                                                 
[        ] I/flutter (32235):                ^                                                                                           

I think that's the very same issue because #lib2::DrawerControllerState is a subclass of #lib1::State<#lib1::StatefulWidget>, but somehow Fasta does not understand it.

class DrawerController extends StatefulWidget {
}

class DrawerControllerState extends State<DrawerController> with SingleTickerProviderStateMixin {
}

abstract class SingleTickerProviderStateMixin extends State<dynamic> implements TickerProvider { // ignore: TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, https://github.com/dart-lang/sdk/issues/25232
}

@peter-ahe-google
Copy link
Contributor

@jensjoha came up with a temporary workaround. @mraleph could you try it?

$ git diff
diff --git a/pkg/kernel/lib/src/incremental_class_hierarchy.dart b/pkg/kernel/lib/src/incremental_class_hierarchy.dart
index b5e8bd485d..ef25a1ced6 100644
--- a/pkg/kernel/lib/src/incremental_class_hierarchy.dart
+++ b/pkg/kernel/lib/src/incremental_class_hierarchy.dart
@@ -422,7 +422,17 @@ class IncrementalClassHierarchy implements ClassHierarchy {
      superInfo.genericSuperTypes?.forEach((Class key, Supertype type) {
        subInfo.genericSuperTypes[key] = substitution.substituteSupertype(type);
      });
-      subInfo.genericSuperTypes[superclass] = supertype;
+      if (subInfo.genericSuperTypes[superclass] != null) {
+        // Hack: Would otherwise overwrite
+        // ${subInfo.genericSuperTypes[superclass]} with $supertype
+        // now instead overwrite it with whatnot<Dynamic ... >
+        final List<DartType> args = subInfo.genericSuperTypes[superclass].typeArguments;
+        for(int i = 0; i < args.length; i++) {
+          args[i] = const DynamicType();
+        }
+      } else {
+        subInfo.genericSuperTypes[superclass] = supertype;
+      }
    }
  }

@peter-ahe-google
Copy link
Contributor

That workaround only seems to work for simpler cases. Nothing is overwritten in Slava's original example.

@peter-ahe-google
Copy link
Contributor

We're making progress: ClassHierarchy now is able to identify the problematic interfaces instead of picking a random.

But we're not there yet: a quick hack similar to Jens' solution above doesn't remove all compile-time errors.

@peter-ahe-google
Copy link
Contributor

This works around the issue by reporting an error that can be ignored and recovers in a similar fashion to what @stereotype441 suggested (prioritize the extends clause).

@peter-ahe-google peter-ahe-google added P1 A high priority bug; for example, a single project is unusable or has many test failures and removed P0 A serious issue requiring immediate resolution labels Jan 11, 2018
@a-siva
Copy link
Contributor

a-siva commented Jan 11, 2018

Has the work around landed?

@mraleph
Copy link
Member Author

mraleph commented Jan 11, 2018

@a-siva we are working on it. I would say it'll still take few days to arrive to the completely working solution.

@a-siva
Copy link
Contributor

a-siva commented Jan 12, 2018

I understand a fully working solution would take days but landing the work around will help us make short term progress verifying changes being made for #31869

@peter-ahe-google
Copy link
Contributor

The work around isn't completed yet, and as @mraleph said, it will still take a few days to get it completely working.

I'm marking this as P0 again. @mraleph and I agreed to downgrade to P1 as we had agreed on a workaround by rewriting Flutter code. However, that turned out to be infeasible, and we decided to invest our time last night in making progress on brainstorming and implementing a fix in Fasta instead of providing detailed information in this bug report. We naively assumed that would suffice given that we had also provided a link to the CL and stated clearly that "we're working on it".

@peter-ahe-google peter-ahe-google added P0 A serious issue requiring immediate resolution and removed P1 A high priority bug; for example, a single project is unusable or has many test failures labels Jan 12, 2018
@peter-ahe-google
Copy link
Contributor

Unfortunately, my implementation isn't compatible with pkg/front_end/lib/src/incremental_kernel_generator_impl.dart, and
pkg/front_end/lib/src/minimal_incremental_kernel_generator.dart.

So I'll have to remove these first. Fortunately, I have replacement ready for them in pkg/front_end/lib/src/fasta/incremental_compiler.dart. This implementation is already faster than minimal, but not as fast when it comes to body-only changes as the original IKG. However, we already have a prototype implementation that optimizes for body-only changes and then there are no performance regressions at all:

screen shot 2018-01-12 at 12 45 35

@peter-ahe-google
Copy link
Contributor

We've removed the old implementations of IKG, and should be able to land change 33884 shortly.

@peter-ahe-google
Copy link
Contributor

Fixed in 3fcede3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
customer-flutter customer-vm legacy-area-front-end Legacy: Use area-dart-model instead. P0 A serious issue requiring immediate resolution
Projects
None yet
Development

No branches or pull requests

9 participants