Skip to content

Commit

Permalink
[CFE] Fix setter from extension used in for loop
Browse files Browse the repository at this point in the history
Change-Id: I6cfbd7b8c5d72ea508dcdb7f0b15ddaab1e0700d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/398062
Commit-Queue: Jens Johansen <[email protected]>
Reviewed-by: Johnni Winther <[email protected]>
  • Loading branch information
jensjoha authored and Commit Queue committed Nov 28, 2024
1 parent 3572482 commit 7cc9536
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 0 deletions.
52 changes: 52 additions & 0 deletions pkg/front_end/lib/src/type_inference/for_in.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:kernel/ast.dart';

import '../base/instrumentation.dart' show InstrumentationValueForMember;
import '../codes/cfe_codes.dart';
import '../kernel/hierarchy/class_member.dart';
import '../kernel/internal_ast.dart';
import 'inference_results.dart';
import 'inference_visitor.dart';
Expand Down Expand Up @@ -259,6 +260,57 @@ class StaticForInVariable implements ForInVariable {
}
}

class ExtensionSetForInVariable implements ForInVariable {
final ExtensionSet extensionSet;
DartType? setterType;

ExtensionSetForInVariable(this.extensionSet);

@override
DartType computeElementType(InferenceVisitorBase visitor) {
ExpressionInferenceResult receiverResult = visitor.inferExpression(
extensionSet.receiver, const UnknownType(),
isVoidAllowed: false);

List<DartType> extensionTypeArguments =
visitor.computeExtensionTypeArgument(extensionSet.extension,
extensionSet.explicitTypeArguments, receiverResult.inferredType,
treeNodeForTesting: extensionSet);

DartType receiverType = visitor.getExtensionReceiverType(
extensionSet.extension, extensionTypeArguments);

ObjectAccessTarget target = new ExtensionAccessTarget(
receiverType,
extensionSet.target,
null,
ClassMemberKind.Setter,
extensionTypeArguments);

setterType = target.getSetterType(visitor);
return setterType!;
}

@override
Expression inferAssignment(InferenceVisitorBase visitor, DartType rhsType) {
assert(setterType != null);
Expression rhs = visitor.ensureAssignable(
setterType!, rhsType, extensionSet.value,
errorTemplate: templateForInLoopElementTypeNotAssignable,
nullabilityErrorTemplate:
templateForInLoopElementTypeNotAssignableNullability,
nullabilityPartErrorTemplate:
templateForInLoopElementTypeNotAssignablePartNullability,
isVoidAllowed: true);

extensionSet.value = rhs..parent = extensionSet;
ExpressionInferenceResult result = visitor.inferExpression(
extensionSet, const UnknownType(),
isVoidAllowed: true);
return result.expression;
}
}

class InvalidForInVariable implements ForInVariable {
final Expression? expression;

Expand Down
2 changes: 2 additions & 0 deletions pkg/front_end/lib/src/type_inference/inference_visitor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1690,6 +1690,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
return new SuperPropertyForInVariable(syntheticAssignment);
} else if (syntheticAssignment is StaticSet) {
return new StaticForInVariable(syntheticAssignment);
} else if (syntheticAssignment is ExtensionSet) {
return new ExtensionSetForInVariable(syntheticAssignment);
} else if (syntheticAssignment is InvalidExpression || hasProblem) {
return new InvalidForInVariable(syntheticAssignment);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

extension on String {
set foo(int value) {}
bar(List<int> input) {
foo = 42;
for (foo in input) {
print("inside loop");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
library;
import self as self;
import "dart:core" as core;

extension /* unnamed */ _extension#0 on core::String {
method bar = self::_extension#0|bar;
method tearoff bar = self::_extension#0|get#bar;
set foo = self::_extension#0|set#foo;
}
static extension-member method _extension#0|set#foo(lowered final core::String #this, core::int value) → void {}
static extension-member method _extension#0|bar(lowered final core::String #this, core::List<core::int> input) → dynamic {
self::_extension#0|set#foo(#this, 42);
for (final core::int #t1 in input) {
self::_extension#0|set#foo(#this, #t1);
core::print("inside loop");
}
}
static extension-member method _extension#0|get#bar(lowered final core::String #this) → (core::List<core::int>) → dynamic
return (core::List<core::int> input) → dynamic => self::_extension#0|bar(#this, input);
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
library;
import self as self;
import "dart:core" as core;

extension /* unnamed */ _extension#0 on core::String {
method bar = self::_extension#0|bar;
method tearoff bar = self::_extension#0|get#bar;
set foo = self::_extension#0|set#foo;
}
static extension-member method _extension#0|set#foo(lowered final core::String #this, core::int value) → void {}
static extension-member method _extension#0|bar(lowered final core::String #this, core::List<core::int> input) → dynamic {
self::_extension#0|set#foo(#this, 42);
for (final core::int #t1 in input) {
self::_extension#0|set#foo(#this, #t1);
core::print("inside loop");
}
}
static extension-member method _extension#0|get#bar(lowered final core::String #this) → (core::List<core::int>) → dynamic
return (core::List<core::int> input) → dynamic => self::_extension#0|bar(#this, input);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
library;
import self as self;
import "dart:core" as core;

extension /* unnamed */ _extension#0 on core::String {
method bar = self::_extension#0|bar;
method tearoff bar = self::_extension#0|get#bar;
set foo = self::_extension#0|set#foo;
}
static extension-member method _extension#0|set#foo(lowered final core::String #this, core::int value) → void
;
static extension-member method _extension#0|bar(lowered final core::String #this, core::List<core::int> input) → dynamic
;
static extension-member method _extension#0|get#bar(lowered final core::String #this) → (core::List<core::int>) → dynamic
return (core::List<core::int> input) → dynamic => self::_extension#0|bar(#this, input);
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
library;
import self as self;
import "dart:core" as core;

extension /* unnamed */ _extension#0 on core::String {
method bar = self::_extension#0|bar;
method tearoff bar = self::_extension#0|get#bar;
set foo = self::_extension#0|set#foo;
}
static extension-member method _extension#0|set#foo(lowered final core::String #this, core::int value) → void {}
static extension-member method _extension#0|bar(lowered final core::String #this, core::List<core::int> input) → dynamic {
self::_extension#0|set#foo(#this, 42);
{
synthesized core::Iterator<core::int> :sync-for-iterator = input.{core::Iterable::iterator}{core::Iterator<core::int>};
for (; :sync-for-iterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
final core::int #t1 = :sync-for-iterator.{core::Iterator::current}{core::int};
{
self::_extension#0|set#foo(#this, #t1);
core::print("inside loop");
}
}
}
}
static extension-member method _extension#0|get#bar(lowered final core::String #this) → (core::List<core::int>) → dynamic
return (core::List<core::int> input) → dynamic => self::_extension#0|bar(#this, input);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
extension on String {
set foo(int value) {}
bar(List<int> input) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
extension on String {
bar(List<int> input) {}
set foo(int value) {}
}

0 comments on commit 7cc9536

Please sign in to comment.