From 96d52d4e351f9e104fa794a89d4810893e164c2d Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Mon, 12 Sep 2022 10:16:16 +0000 Subject: [PATCH] [cfe] Handle multiple named record fields in constants This bypasses the hoisting of record elements in constant record literals. The created let variables would otherwise interfere with the constant evaluation. Closes #49915 Change-Id: Ia70387a0f0c435373dc5fcf5cdd526104db8f394 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/258363 Reviewed-by: Chloe Stefantsova Commit-Queue: Johnni Winther --- .../type_inference/inference_visitor.dart | 10 +++++-- .../records/const_record_literal.dart | 20 +++++++++---- .../const_record_literal.dart.strong.expect | 24 +++++++++++----- ...ord_literal.dart.strong.transformed.expect | 24 +++++++++++----- ...record_literal.dart.textual_outline.expect | 20 +++++++++---- .../const_record_literal.dart.weak.expect | 24 +++++++++++----- ...st_record_literal.dart.weak.modular.expect | 24 +++++++++++----- ...st_record_literal.dart.weak.outline.expect | 28 +++++++++++++------ ...ecord_literal.dart.weak.transformed.expect | 24 +++++++++++----- 9 files changed, 141 insertions(+), 57 deletions(-) diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart index 11294436622..937544f57ee 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart @@ -7317,6 +7317,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase // Index into [positional] of the positional element we find next. int positionalIndex = positional.length - 1; + // For const literals we don't hoist to avoid using let variables in + // inside constants. Since the elements of the literal must be constant + // themselves, we know that there is no side effects of performing + // constant evaluation out of order. + final bool enableHoisting = !node.isConst; + // Set to `true` if we need to hoist all preceding elements. bool needsHoisting = false; @@ -7355,7 +7361,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase if (!namedNeedsSorting && element.name != sortedNames[nameIndex]) { // Named elements are not sorted, so we need to hoist and sort them. namedNeedsSorting = true; - needsHoisting = true; + needsHoisting = enableHoisting; } nameIndex--; } else { @@ -7381,7 +7387,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase if (nameIndex >= 0) { // We have not seen all named elements yet, so we must hoist the // remaining named elements and the preceding positional elements. - needsHoisting = true; + needsHoisting = enableHoisting; } } positionalTypes[positionalIndex] = type; diff --git a/pkg/front_end/testcases/records/const_record_literal.dart b/pkg/front_end/testcases/records/const_record_literal.dart index dbc8e59eb33..eb8fb1b38bb 100644 --- a/pkg/front_end/testcases/records/const_record_literal.dart +++ b/pkg/front_end/testcases/records/const_record_literal.dart @@ -3,11 +3,19 @@ // BSD-style license that can be found in the LICENSE file. const dynamic a = (1, 2); -const dynamic b = (a: 1, b: 2); -const dynamic c = (a: a, b: b); -const dynamic d = (c, (1, 2)); +const dynamic b1 = (a: 1, b: 2); +const dynamic b2 = (b: 2, a: 1); +const dynamic b3 = (b: 2, 1); +const dynamic c1 = (a: a, b: b1); +const dynamic c2 = (b: b2, a: a); +const dynamic c3 = (b: b3, a); +const dynamic d = (c1, (1, 2)); dynamic e = const (1, 2); -dynamic f = const (a: 1, b: 2); -dynamic g = const (a: a, b: b); -dynamic h = const (c, (1, 2)); +dynamic f1 = const (a: 1, b: 2); +dynamic f2 = const (b: 2, a: 1); +dynamic f3 = const (b: 2, 1); +dynamic g1 = const (a: a, b: b1); +dynamic g2 = const (b: b2, a: a); +dynamic g3 = const (b: b3, a); +dynamic h = const (c1, (1, 2)); diff --git a/pkg/front_end/testcases/records/const_record_literal.dart.strong.expect b/pkg/front_end/testcases/records/const_record_literal.dart.strong.expect index 6868c00a319..08cf8e34a72 100644 --- a/pkg/front_end/testcases/records/const_record_literal.dart.strong.expect +++ b/pkg/front_end/testcases/records/const_record_literal.dart.strong.expect @@ -3,19 +3,29 @@ import self as self; import "dart:core" as core; static const field dynamic a = #C3; -static const field dynamic b = #C4; -static const field dynamic c = #C5; -static const field dynamic d = #C6; +static const field dynamic b1 = #C4; +static const field dynamic b2 = #C4; +static const field dynamic b3 = #C5; +static const field dynamic c1 = #C6; +static const field dynamic c2 = #C6; +static const field dynamic c3 = #C7; +static const field dynamic d = #C8; static field dynamic e = #C3; -static field dynamic f = #C4; -static field dynamic g = #C5; -static field dynamic h = #C6; +static field dynamic f1 = #C4; +static field dynamic f2 = #C4; +static field dynamic f3 = #C5; +static field dynamic g1 = #C6; +static field dynamic g2 = #C6; +static field dynamic g3 = #C7; +static field dynamic h = #C8; constants { #C1 = 1 #C2 = 2 const (#C1, #C2) const ({a:#C1, b:#C2}) +const (#C1, {b:#C2}) const ({a:#C3, b:#C4}) -const (#C5, #C3) +const (#C3, {b:#C5}) +const (#C6, #C3) } diff --git a/pkg/front_end/testcases/records/const_record_literal.dart.strong.transformed.expect b/pkg/front_end/testcases/records/const_record_literal.dart.strong.transformed.expect index 6868c00a319..08cf8e34a72 100644 --- a/pkg/front_end/testcases/records/const_record_literal.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/records/const_record_literal.dart.strong.transformed.expect @@ -3,19 +3,29 @@ import self as self; import "dart:core" as core; static const field dynamic a = #C3; -static const field dynamic b = #C4; -static const field dynamic c = #C5; -static const field dynamic d = #C6; +static const field dynamic b1 = #C4; +static const field dynamic b2 = #C4; +static const field dynamic b3 = #C5; +static const field dynamic c1 = #C6; +static const field dynamic c2 = #C6; +static const field dynamic c3 = #C7; +static const field dynamic d = #C8; static field dynamic e = #C3; -static field dynamic f = #C4; -static field dynamic g = #C5; -static field dynamic h = #C6; +static field dynamic f1 = #C4; +static field dynamic f2 = #C4; +static field dynamic f3 = #C5; +static field dynamic g1 = #C6; +static field dynamic g2 = #C6; +static field dynamic g3 = #C7; +static field dynamic h = #C8; constants { #C1 = 1 #C2 = 2 const (#C1, #C2) const ({a:#C1, b:#C2}) +const (#C1, {b:#C2}) const ({a:#C3, b:#C4}) -const (#C5, #C3) +const (#C3, {b:#C5}) +const (#C6, #C3) } diff --git a/pkg/front_end/testcases/records/const_record_literal.dart.textual_outline.expect b/pkg/front_end/testcases/records/const_record_literal.dart.textual_outline.expect index 7c54744fd8e..769adb843dd 100644 --- a/pkg/front_end/testcases/records/const_record_literal.dart.textual_outline.expect +++ b/pkg/front_end/testcases/records/const_record_literal.dart.textual_outline.expect @@ -1,8 +1,16 @@ const dynamic a = (1, 2); -const dynamic b = (a: 1, b: 2); -const dynamic c = (a: a, b: b); -const dynamic d = (c, (1, 2)); +const dynamic b1 = (a: 1, b: 2); +const dynamic b2 = (b: 2, a: 1); +const dynamic b3 = (b: 2, 1); +const dynamic c1 = (a: a, b: b1); +const dynamic c2 = (b: b2, a: a); +const dynamic c3 = (b: b3, a); +const dynamic d = (c1, (1, 2)); dynamic e = const (1, 2); -dynamic f = const (a: 1, b: 2); -dynamic g = const (a: a, b: b); -dynamic h = const (c, (1, 2)); +dynamic f1 = const (a: 1, b: 2); +dynamic f2 = const (b: 2, a: 1); +dynamic f3 = const (b: 2, 1); +dynamic g1 = const (a: a, b: b1); +dynamic g2 = const (b: b2, a: a); +dynamic g3 = const (b: b3, a); +dynamic h = const (c1, (1, 2)); diff --git a/pkg/front_end/testcases/records/const_record_literal.dart.weak.expect b/pkg/front_end/testcases/records/const_record_literal.dart.weak.expect index 6868c00a319..08cf8e34a72 100644 --- a/pkg/front_end/testcases/records/const_record_literal.dart.weak.expect +++ b/pkg/front_end/testcases/records/const_record_literal.dart.weak.expect @@ -3,19 +3,29 @@ import self as self; import "dart:core" as core; static const field dynamic a = #C3; -static const field dynamic b = #C4; -static const field dynamic c = #C5; -static const field dynamic d = #C6; +static const field dynamic b1 = #C4; +static const field dynamic b2 = #C4; +static const field dynamic b3 = #C5; +static const field dynamic c1 = #C6; +static const field dynamic c2 = #C6; +static const field dynamic c3 = #C7; +static const field dynamic d = #C8; static field dynamic e = #C3; -static field dynamic f = #C4; -static field dynamic g = #C5; -static field dynamic h = #C6; +static field dynamic f1 = #C4; +static field dynamic f2 = #C4; +static field dynamic f3 = #C5; +static field dynamic g1 = #C6; +static field dynamic g2 = #C6; +static field dynamic g3 = #C7; +static field dynamic h = #C8; constants { #C1 = 1 #C2 = 2 const (#C1, #C2) const ({a:#C1, b:#C2}) +const (#C1, {b:#C2}) const ({a:#C3, b:#C4}) -const (#C5, #C3) +const (#C3, {b:#C5}) +const (#C6, #C3) } diff --git a/pkg/front_end/testcases/records/const_record_literal.dart.weak.modular.expect b/pkg/front_end/testcases/records/const_record_literal.dart.weak.modular.expect index 6868c00a319..08cf8e34a72 100644 --- a/pkg/front_end/testcases/records/const_record_literal.dart.weak.modular.expect +++ b/pkg/front_end/testcases/records/const_record_literal.dart.weak.modular.expect @@ -3,19 +3,29 @@ import self as self; import "dart:core" as core; static const field dynamic a = #C3; -static const field dynamic b = #C4; -static const field dynamic c = #C5; -static const field dynamic d = #C6; +static const field dynamic b1 = #C4; +static const field dynamic b2 = #C4; +static const field dynamic b3 = #C5; +static const field dynamic c1 = #C6; +static const field dynamic c2 = #C6; +static const field dynamic c3 = #C7; +static const field dynamic d = #C8; static field dynamic e = #C3; -static field dynamic f = #C4; -static field dynamic g = #C5; -static field dynamic h = #C6; +static field dynamic f1 = #C4; +static field dynamic f2 = #C4; +static field dynamic f3 = #C5; +static field dynamic g1 = #C6; +static field dynamic g2 = #C6; +static field dynamic g3 = #C7; +static field dynamic h = #C8; constants { #C1 = 1 #C2 = 2 const (#C1, #C2) const ({a:#C1, b:#C2}) +const (#C1, {b:#C2}) const ({a:#C3, b:#C4}) -const (#C5, #C3) +const (#C3, {b:#C5}) +const (#C6, #C3) } diff --git a/pkg/front_end/testcases/records/const_record_literal.dart.weak.outline.expect b/pkg/front_end/testcases/records/const_record_literal.dart.weak.outline.expect index 8f26f0973d8..c88f527142d 100644 --- a/pkg/front_end/testcases/records/const_record_literal.dart.weak.outline.expect +++ b/pkg/front_end/testcases/records/const_record_literal.dart.weak.outline.expect @@ -3,18 +3,30 @@ import self as self; import "dart:core" as core; static const field dynamic a = const (1, 2); -static const field dynamic b = const ({a: 1, b: 2}); -static const field dynamic c = const ({a: self::a, b: self::b}); -static const field dynamic d = const (self::c, const (1, 2)); +static const field dynamic b1 = const ({a: 1, b: 2}); +static const field dynamic b2 = const ({a: 1, b: 2}); +static const field dynamic b3 = const (1, {b: 2}); +static const field dynamic c1 = const ({a: self::a, b: self::b1}); +static const field dynamic c2 = const ({a: self::a, b: self::b2}); +static const field dynamic c3 = const (self::a, {b: self::b3}); +static const field dynamic d = const (self::c1, const (1, 2)); static field dynamic e; -static field dynamic f; -static field dynamic g; +static field dynamic f1; +static field dynamic f2; +static field dynamic f3; +static field dynamic g1; +static field dynamic g2; +static field dynamic g3; static field dynamic h; Extra constant evaluation status: Evaluated: RecordLiteral @ org-dartlang-testcase:///const_record_literal.dart:5:15 -> RecordConstant(const (1, 2)) Evaluated: RecordLiteral @ org-dartlang-testcase:///const_record_literal.dart:6:15 -> RecordConstant(const ({a: 1, b: 2})) -Evaluated: RecordLiteral @ org-dartlang-testcase:///const_record_literal.dart:7:15 -> RecordConstant(const ({a: const (1, 2), b: const ({a: 1, b: 2})})) -Evaluated: RecordLiteral @ org-dartlang-testcase:///const_record_literal.dart:8:15 -> RecordConstant(const (const ({a: const (1, 2), b: const ({a: 1, b: 2})}), const (1, 2))) -Extra constant evaluation: evaluated: 4, effectively constant: 4 +Evaluated: RecordLiteral @ org-dartlang-testcase:///const_record_literal.dart:7:15 -> RecordConstant(const ({a: 1, b: 2})) +Evaluated: RecordLiteral @ org-dartlang-testcase:///const_record_literal.dart:8:15 -> RecordConstant(const (1, {b: 2})) +Evaluated: RecordLiteral @ org-dartlang-testcase:///const_record_literal.dart:9:15 -> RecordConstant(const ({a: const (1, 2), b: const ({a: 1, b: 2})})) +Evaluated: RecordLiteral @ org-dartlang-testcase:///const_record_literal.dart:10:15 -> RecordConstant(const ({a: const (1, 2), b: const ({a: 1, b: 2})})) +Evaluated: RecordLiteral @ org-dartlang-testcase:///const_record_literal.dart:11:15 -> RecordConstant(const (const (1, 2), {b: const (1, {b: 2})})) +Evaluated: RecordLiteral @ org-dartlang-testcase:///const_record_literal.dart:12:15 -> RecordConstant(const (const ({a: const (1, 2), b: const ({a: 1, b: 2})}), const (1, 2))) +Extra constant evaluation: evaluated: 8, effectively constant: 8 diff --git a/pkg/front_end/testcases/records/const_record_literal.dart.weak.transformed.expect b/pkg/front_end/testcases/records/const_record_literal.dart.weak.transformed.expect index 6868c00a319..08cf8e34a72 100644 --- a/pkg/front_end/testcases/records/const_record_literal.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/records/const_record_literal.dart.weak.transformed.expect @@ -3,19 +3,29 @@ import self as self; import "dart:core" as core; static const field dynamic a = #C3; -static const field dynamic b = #C4; -static const field dynamic c = #C5; -static const field dynamic d = #C6; +static const field dynamic b1 = #C4; +static const field dynamic b2 = #C4; +static const field dynamic b3 = #C5; +static const field dynamic c1 = #C6; +static const field dynamic c2 = #C6; +static const field dynamic c3 = #C7; +static const field dynamic d = #C8; static field dynamic e = #C3; -static field dynamic f = #C4; -static field dynamic g = #C5; -static field dynamic h = #C6; +static field dynamic f1 = #C4; +static field dynamic f2 = #C4; +static field dynamic f3 = #C5; +static field dynamic g1 = #C6; +static field dynamic g2 = #C6; +static field dynamic g3 = #C7; +static field dynamic h = #C8; constants { #C1 = 1 #C2 = 2 const (#C1, #C2) const ({a:#C1, b:#C2}) +const (#C1, {b:#C2}) const ({a:#C3, b:#C4}) -const (#C5, #C3) +const (#C3, {b:#C5}) +const (#C6, #C3) }