Skip to content

[Breaking change request] Disallow type promotion of this in extensions #44660

@stereotype441

Description

@stereotype441

Summary

Due to a bug in the common front end, any implicit or explicit reference to this in an extension method is treated as equivalent to a local variable; accordingly it can undergo type promotion. The ability to type promote this is being removed for consistency with the specification and the behavior of the analyzer.

What is changing

Previously, any code inside an extension that did an is check on this would promote the type of this, so in the example below, lines (1) through (4) would be allowed (since class D defines property and method), but lines (5) through (8) would lead to compile-time errors (since class C does not):

class C {}

class D extends C {
  int property;
  void method() { ... }
}

extension on C {
  void example() {
    if (this is D) {
      print(this.property); // (1)
      print(property);      // (2)
      this.method();        // (3)
      method();             // (4)
    } else {
      print(this.property); // (5)
      print(property);      // (6)
      this.method();        // (7)
      method();             // (8)
    }
  }
}

However, the Dart analyzer (which also powers integration with editors such as IntelliJ and VSCode) did not allow this, so it considered lines (1) through (8) all to be compile-time errors.

We are changing the behavior of the front end to match the analyzer, so that lines (1) through (8) will all be compile-time errors.

Rationale

Making the analyzer and the common front end consistent should help reduce confusion, since code that is accepted by one tool won't be rejected by another. There are three reasons for going with the analyzer's behavior:

  • The analyzer's behavior is more self-consistent (it disallows promotion of this both in extensions and in classes).
  • The analyzer's behavior is consistent with the language specification (which specifies that only local variables and function parameters can undergo type promotion).
  • Due to architectural constraints in the analyzer, changing its behavior to match that of the common front end would be a much larger undertaking, with greater risk of bugs.

Expected impact

We expect the impact to be extremely small for several reasons:

  • Only a small fraction of Dart code exists inside extension method declarations; code inside class declarations is unaffected by this change.
  • Any code that would be affected by this change would most likely be rendered erroneous by it, and since most users of Dart use the analyzer in some way or another (e.g. through an editor, or using a code generator), they would have already run into this problem and most likely worked around it by not trying to promote this.
  • A trial run of the change through Google's internal source repository showed zero code broken by this change.

Mitigation

If you do have any code that is impacted by this change, you can always restore the old functionality by creating an explicit variable and initializing it to this, for example:

class C {}

class D extends C {
  int property;
  void method() { ... }
}

extension on C {
  void example() {
    var self = this;
    if (self is D) {        // Instead of `if (this is D)`
      print(self.property); // Instead of `property` or `this.property`
      self.method();        // Instead of `method()` or `this.method()`
    }
  }
}

Additional information

Metadata

Metadata

Assignees

Labels

breaking-change-requestThis tracks requests for feedback on breaking changeslegacy-area-front-endLegacy: Use area-dart-model instead.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions