Breaking analyzer change: always insert ImplicitCallReference nodes.
Previously, we only inserted these nodes when the
`constructor-tearoffs` feature was active, as a way of reducing the
risk of breaking analyzer clients; however this behavioral
inconsistency is not something we want to keep for the long term.
Note: even though this is technically a breaking change, we haven't
found any analyzer clients that are affected by it, so we're going
ahead and landing it without an analyzer version number bump.
Change-Id: I71f0fb2862b644dd1a81245bd12f5b7b9ca45857
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/233653
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
index 0aa6a8f..6ae7fe4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
@@ -66,10 +66,7 @@
var callInsertion = _resolver.insertImplicitCallReference(initializer);
if (callInsertion != null) {
- var insertedExpression = callInsertion.expression;
- if (insertedExpression != null) {
- initializer = callInsertion.expression;
- }
+ initializer = callInsertion.expression;
}
// Initializers of top-level variables and fields are already included
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index d42e16a..4e32f72 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -81,14 +81,8 @@
/// Data structure describing the result of inserting an implicit call reference
/// into the AST.
class ImplicitCallInsertionResult {
- /// The expression that was inserted, or `null`, if no expression was
- /// inserted.
- ///
- /// The only reason this might be `null` is that, at the moment, we only
- /// insert implicit call reference expressions if the 'constructor-tearoffs'
- /// feature is enabled (to avoid breaking clients).
- /// TODO(paulberry): make this non-nullable when we change this behavior.
- final ImplicitCallReferenceImpl? expression;
+ /// The expression that was inserted.
+ final ImplicitCallReferenceImpl expression;
/// The type of the implicit call tear-off.
final FunctionType staticType;
@@ -862,14 +856,6 @@
typeArgumentTypes = [];
}
- if (!isConstructorTearoffsEnabled) {
- // Temporarily, only create [ImplicitCallReference] nodes under the
- // 'constructor-tearoffs' feature.
- // TODO(srawlins, paulberry): When we are ready to make a breaking change
- // release to the analyzer package, remove this exception.
- return ImplicitCallInsertionResult(null, callMethodType);
- }
-
var callReference = astFactory.implicitCallReference(
expression: expression,
staticElement: callMethod,
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index d79ce34..ed5ca6e 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -1151,6 +1151,18 @@
}
@override
+ DecoratedType? visitImplicitCallReference(ImplicitCallReference node) {
+ return _handlePropertyAccessGeneralized(
+ node: node,
+ target: node.expression,
+ propertyName: 'call',
+ isNullAware: false,
+ isCascaded: false,
+ inSetterContext: false,
+ callee: node.staticElement);
+ }
+
+ @override
DecoratedType? visitIndexExpression(IndexExpression node) {
DecoratedType? targetType;
var target = node.target;
@@ -3112,24 +3124,43 @@
DecoratedType? _handlePropertyAccess(Expression node, Expression? target,
SimpleIdentifier propertyName, bool isNullAware, bool isCascaded) {
- DecoratedType? targetType;
+ if (!isCascaded && _isPrefix(target)) {
+ return _dispatch(propertyName, skipNullCheckHint: true);
+ }
var callee = getWriteOrReadElement(propertyName);
+ return _handlePropertyAccessGeneralized(
+ node: node,
+ target: target,
+ propertyName: propertyName.name,
+ isNullAware: isNullAware,
+ isCascaded: isCascaded,
+ inSetterContext: propertyName.inSetterContext(),
+ callee: callee);
+ }
+
+ DecoratedType? _handlePropertyAccessGeneralized(
+ {required Expression node,
+ required Expression? target,
+ required String propertyName,
+ required bool isNullAware,
+ required bool isCascaded,
+ required bool inSetterContext,
+ required Element? callee}) {
+ DecoratedType? targetType;
bool calleeIsStatic = callee is ExecutableElement && callee.isStatic;
if (isCascaded) {
targetType = _currentCascadeTargetType;
- } else if (_isPrefix(target)) {
- return _dispatch(propertyName, skipNullCheckHint: true);
} else if (calleeIsStatic) {
_dispatch(target);
} else if (isNullAware) {
targetType = _dispatch(target);
} else {
- targetType = _handleTarget(target, propertyName.name, callee);
+ targetType = _handleTarget(target, propertyName, callee);
}
DecoratedType? calleeType;
if (targetType != null &&
targetType.type is FunctionType &&
- propertyName.name == 'call') {
+ propertyName == 'call') {
// If `X` has a function type, then in the expression `X.call`, the
// function being torn off is `X` itself, so the callee type is simply the
// non-nullable counterpart to the type of `X`.
@@ -3148,7 +3179,7 @@
// Dynamic dispatch.
return _makeNullableDynamicType(node);
}
- if (propertyName.inSetterContext()) {
+ if (inSetterContext) {
if (isNullAware) {
_conditionalNodes[node] = targetType!.node;
}