Skip to content

Commit d3a0c15

Browse files
kallentuCommit Queue
authored andcommitted
[cfe] Dot Shorthands: Handle constructor tearoffs.
This CL adds support for constructor tearoffs in dot shorthands. If there's any type parameters on the tearoff and it's a constructor, we produce an error. I also updated the expectations of existing tests due to an early return of `InvalidExpression`s and added language + cfe tests for the new behavior. This CL fixes the following co19 tests and is a follow up to dart-lang/co19#3122 co19/LanguageFeatures/Static-access-shorthand/constant_expression_A03_t01 co19/LanguageFeatures/Static-access-shorthand/constant_expression_A04_t01 co19/LanguageFeatures/Static-access-shorthand/semantics_A05_t01 co19/LanguageFeatures/Static-access-shorthand/constant_expression_A03_t02 Bug: #59758, dart-lang/co19#3122 Change-Id: I1ea837342ad818cd3b1de9e422065f42e8a61d6b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/419782 Commit-Queue: Kallen Tu <[email protected]> Reviewed-by: Chloe Stefantsova <[email protected]>
1 parent 33ed2d8 commit d3a0c15

28 files changed

+458
-116
lines changed

pkg/front_end/lib/src/kernel/body_builder.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9323,6 +9323,9 @@ class BodyBuilder extends StackListenerImpl
93239323
pop() as List<TypeBuilder>?; // typeArguments
93249324
if (libraryFeatures.constructorTearoffs.isEnabled) {
93259325
Object? operand = pop();
9326+
if (operand is DotShorthandPropertyGet && typeArguments != null) {
9327+
operand.hasTypeParameters = true;
9328+
}
93269329
if (operand is Generator) {
93279330
push(operand.applyTypeArguments(
93289331
openAngleBracket.charOffset, typeArguments));

pkg/front_end/lib/src/kernel/internal_ast.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3293,7 +3293,14 @@ class DotShorthandPropertyGet extends InternalExpression {
32933293
final Name name;
32943294
final int nameOffset;
32953295

3296-
DotShorthandPropertyGet(this.name, {required this.nameOffset});
3296+
/// Whether this dot shorthand has type parameters.
3297+
///
3298+
/// Used for error checking for constructors with type parameters in the
3299+
/// [InferenceVisitor].
3300+
bool hasTypeParameters;
3301+
3302+
DotShorthandPropertyGet(this.name,
3303+
{required this.nameOffset, this.hasTypeParameters = false});
32973304

32983305
@override
32993306
ExpressionInferenceResult acceptInference(

pkg/front_end/lib/src/type_inference/inference_visitor.dart

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
697697
ExpressionInferenceResult operandResult = inferExpression(
698698
node.expression, const UnknownType(),
699699
isVoidAllowed: true);
700+
if (operandResult.expression is InvalidExpression) return operandResult;
700701
Expression operand = operandResult.expression;
701702
DartType operandType = operandResult.inferredType;
702703
if (operandType is! FunctionType) {
@@ -12289,12 +12290,42 @@ class InferenceVisitorImpl extends InferenceVisitorBase
1228912290
expressionInferenceResult =
1229012291
inferExpression(new StaticGet(member), cachedContext);
1229112292
} else {
12292-
// Tearoff like `Object.new`;
12293-
expressionInferenceResult =
12294-
inferExpression(new StaticTearOff(member), cachedContext);
12293+
// Method tearoffs.
12294+
DartType type =
12295+
member.function.computeFunctionType(Nullability.nonNullable);
12296+
return instantiateTearOff(
12297+
type, typeContext, new StaticTearOff(member));
1229512298
}
1229612299
case Constructor():
1229712300
case null:
12301+
// Handle constructor tearoffs.
12302+
if (cachedContext is TypeDeclarationType) {
12303+
Member? constructor = findConstructor(
12304+
cachedContext, node.name, node.fileOffset,
12305+
isTearoff: true);
12306+
// Dot shorthand constructor invocations with type parameters
12307+
// `.id<type>()` are not allowed.
12308+
if (constructor != null && node.hasTypeParameters) {
12309+
return new ExpressionInferenceResult(
12310+
const DynamicType(),
12311+
helper.buildProblem(
12312+
messageDotShorthandsConstructorInvocationWithTypeArguments,
12313+
node.nameOffset,
12314+
node.name.text.length));
12315+
}
12316+
if (constructor is Constructor) {
12317+
DartType type = constructor.function
12318+
.computeFunctionType(Nullability.nonNullable);
12319+
return instantiateTearOff(
12320+
type, typeContext, new ConstructorTearOff(constructor));
12321+
} else if (constructor is Procedure) {
12322+
DartType type = constructor.function
12323+
.computeFunctionType(Nullability.nonNullable);
12324+
return instantiateTearOff(
12325+
type, typeContext, new StaticTearOff(constructor));
12326+
}
12327+
}
12328+
1229812329
if (isKnown(cachedContext)) {
1229912330
// Error when we can't find the static getter or field [node.name] in
1230012331
// the declaration of [cachedContext].

pkg/front_end/lib/src/type_inference/inference_visitor_base.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,7 +1148,8 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
11481148
}
11491149

11501150
/// Finds a constructor of [type] called [name].
1151-
Member? findConstructor(TypeDeclarationType type, Name name, int fileOffset) {
1151+
Member? findConstructor(TypeDeclarationType type, Name name, int fileOffset,
1152+
{bool isTearoff = false}) {
11521153
// TODO(Dart Model team): Seems like an abstraction level issue to require
11531154
// going from `Class` objects back to builders to find a `Member`.
11541155
DeclarationBuilder builder;
@@ -1164,7 +1165,9 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
11641165

11651166
MemberBuilder? constructorBuilder = builder.findConstructorOrFactory(
11661167
name.text, fileOffset, helper.uri, libraryBuilder);
1167-
return constructorBuilder?.invokeTarget;
1168+
return isTearoff
1169+
? constructorBuilder?.readTarget
1170+
: constructorBuilder?.invokeTarget;
11681171
}
11691172

11701173
/// Finds a member of [receiverType] called [name], and if it is found,

pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart.strong.expect

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,6 @@ library;
179179
// Class<int><int>.named<int>;
180180
// ^^^^^
181181
//
182-
// pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:21:24: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
183-
// Try changing the operand or remove the type arguments.
184-
// Class<int><int>.named<int>;
185-
// ^
186-
//
187182
// pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:22:8: Error: The operator '<' isn't defined for the class 'Type'.
188183
// - 'Type' is from 'dart:core'.
189184
// Try correcting the operator to an existing operator, or defining a '<' operator.
@@ -276,10 +271,11 @@ Try correcting the name to the name of an existing method, or defining a method
276271
- 'Type' is from 'dart:core'.
277272
Try correcting the operator to an existing operator, or defining a '<' operator.
278273
Class<int><int>.named<int>;
279-
^" in #C2{<unresolved>}.<(#C3){dynamic}.>(invalid-expression "pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:21:24: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
280-
Try changing the operand or remove the type arguments.
274+
^" in #C2{<unresolved>}.<(#C3){dynamic}.>(invalid-expression "pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:21:19: Error: The getter 'named' isn't defined for the class 'List<int>'.
275+
- 'List' is from 'dart:core'.
276+
Try correcting the name to the name of an existing getter, or defining a getter or field named 'named'.
281277
Class<int><int>.named<int>;
282-
^");
278+
^^^^^" in <core::int>[]{<unresolved>}.named);
283279
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:22:8: Error: The operator '<' isn't defined for the class 'Type'.
284280
- 'Type' is from 'dart:core'.
285281
Try correcting the operator to an existing operator, or defining a '<' operator.

pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart.strong.modular.expect

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,6 @@ library;
179179
// Class<int><int>.named<int>;
180180
// ^^^^^
181181
//
182-
// pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:21:24: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
183-
// Try changing the operand or remove the type arguments.
184-
// Class<int><int>.named<int>;
185-
// ^
186-
//
187182
// pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:22:8: Error: The operator '<' isn't defined for the class 'Type'.
188183
// - 'Type' is from 'dart:core'.
189184
// Try correcting the operator to an existing operator, or defining a '<' operator.
@@ -276,10 +271,11 @@ Try correcting the name to the name of an existing method, or defining a method
276271
- 'Type' is from 'dart:core'.
277272
Try correcting the operator to an existing operator, or defining a '<' operator.
278273
Class<int><int>.named<int>;
279-
^" in #C2{<unresolved>}.<(#C3){dynamic}.>(invalid-expression "pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:21:24: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
280-
Try changing the operand or remove the type arguments.
274+
^" in #C2{<unresolved>}.<(#C3){dynamic}.>(invalid-expression "pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:21:19: Error: The getter 'named' isn't defined for the class 'List<int>'.
275+
- 'List' is from 'dart:core'.
276+
Try correcting the name to the name of an existing getter, or defining a getter or field named 'named'.
281277
Class<int><int>.named<int>;
282-
^");
278+
^^^^^" in <core::int>[]{<unresolved>}.named);
283279
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:22:8: Error: The operator '<' isn't defined for the class 'Type'.
284280
- 'Type' is from 'dart:core'.
285281
Try correcting the operator to an existing operator, or defining a '<' operator.

pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart.strong.transformed.expect

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,6 @@ library;
179179
// Class<int><int>.named<int>;
180180
// ^^^^^
181181
//
182-
// pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:21:24: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
183-
// Try changing the operand or remove the type arguments.
184-
// Class<int><int>.named<int>;
185-
// ^
186-
//
187182
// pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:22:8: Error: The operator '<' isn't defined for the class 'Type'.
188183
// - 'Type' is from 'dart:core'.
189184
// Try correcting the operator to an existing operator, or defining a '<' operator.
@@ -276,10 +271,11 @@ Try correcting the name to the name of an existing method, or defining a method
276271
- 'Type' is from 'dart:core'.
277272
Try correcting the operator to an existing operator, or defining a '<' operator.
278273
Class<int><int>.named<int>;
279-
^" in #C2{<unresolved>}.<(#C3){dynamic}.>(invalid-expression "pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:21:24: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
280-
Try changing the operand or remove the type arguments.
274+
^" in #C2{<unresolved>}.<(#C3){dynamic}.>(invalid-expression "pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:21:19: Error: The getter 'named' isn't defined for the class 'List<int>'.
275+
- 'List' is from 'dart:core'.
276+
Try correcting the name to the name of an existing getter, or defining a getter or field named 'named'.
281277
Class<int><int>.named<int>;
282-
^");
278+
^^^^^" in core::_GrowableList::•<core::int>(0){<unresolved>}.named);
283279
invalid-expression "pkg/front_end/testcases/constructor_tearoffs/duplicate_instantiation.dart:22:8: Error: The operator '<' isn't defined for the class 'Type'.
284280
- 'Type' is from 'dart:core'.
285281
Try correcting the operator to an existing operator, or defining a '<' operator.

pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ class C {
77
C.named();
88
}
99

10+
extension type ET<T>(T v) {}
11+
1012
void test() {
1113
C newConstructor = .new<int>();
1214
C namedConstructor = .named<int>();
1315
C newTearoff = .new<int>;
16+
C namedTearoff = .new<int>;
17+
ET e = .new<int>;
1418
}

pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart.strong.expect

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,30 @@ library;
22
//
33
// Problems in library:
44
//
5-
// pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:11:23: Error: A dot shorthand constructor invocation can't have type arguments.
5+
// pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:13:23: Error: A dot shorthand constructor invocation can't have type arguments.
66
// Try adding the class name and type arguments explicitly before the constructor name.
77
// C newConstructor = .new<int>();
88
// ^^^
99
//
10-
// pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:12:25: Error: A dot shorthand constructor invocation can't have type arguments.
10+
// pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:14:25: Error: A dot shorthand constructor invocation can't have type arguments.
1111
// Try adding the class name and type arguments explicitly before the constructor name.
1212
// C namedConstructor = .named<int>();
1313
// ^^^^^
1414
//
15-
// pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:13:19: Error: The static getter or field 'new' isn't defined for the type 'C'.
16-
// - 'C' is from 'pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart'.
17-
// Try correcting the name to the name of an existing static getter or field, or defining a getter or field named 'new'.
15+
// pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:15:19: Error: A dot shorthand constructor invocation can't have type arguments.
16+
// Try adding the class name and type arguments explicitly before the constructor name.
1817
// C newTearoff = .new<int>;
1918
// ^^^
2019
//
21-
// pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:13:22: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
22-
// Try changing the operand or remove the type arguments.
23-
// C newTearoff = .new<int>;
24-
// ^
20+
// pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:16:21: Error: A dot shorthand constructor invocation can't have type arguments.
21+
// Try adding the class name and type arguments explicitly before the constructor name.
22+
// C namedTearoff = .new<int>;
23+
// ^^^
24+
//
25+
// pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:17:11: Error: A dot shorthand constructor invocation can't have type arguments.
26+
// Try adding the class name and type arguments explicitly before the constructor name.
27+
// ET e = .new<int>;
28+
// ^^^
2529
//
2630
import self as self;
2731
import "dart:core" as core;
@@ -34,17 +38,36 @@ class C extends core::Object {
3438
: super core::Object::•()
3539
;
3640
}
41+
extension type ET<T extends core::Object? = dynamic>(T% v) {
42+
abstract extension-type-member representation-field get v() → T%;
43+
constructor • = self::ET|constructor#;
44+
constructor tearoff • = self::ET|constructor#_#new#tearOff;
45+
}
46+
static extension-type-member method ET|constructor#<T extends core::Object? = dynamic>(self::ET|constructor#::T% v) → self::ET<self::ET|constructor#::T%>% /* erasure=self::ET|constructor#::T%, declared=! */ {
47+
lowered final self::ET<self::ET|constructor#::T%>% /* erasure=self::ET|constructor#::T%, declared=! */ #this = v;
48+
return #this;
49+
}
50+
static extension-type-member method ET|constructor#_#new#tearOff<T extends core::Object? = dynamic>(self::ET|constructor#_#new#tearOff::T% v) → self::ET<self::ET|constructor#_#new#tearOff::T%>% /* erasure=self::ET|constructor#_#new#tearOff::T%, declared=! */
51+
return self::ET|constructor#<self::ET|constructor#_#new#tearOff::T%>(v);
3752
static method test() → void {
38-
self::C newConstructor = invalid-expression "pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:11:23: Error: A dot shorthand constructor invocation can't have type arguments.
53+
self::C newConstructor = invalid-expression "pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:13:23: Error: A dot shorthand constructor invocation can't have type arguments.
3954
Try adding the class name and type arguments explicitly before the constructor name.
4055
C newConstructor = .new<int>();
4156
^^^" as{TypeError,ForDynamic} self::C;
42-
self::C namedConstructor = invalid-expression "pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:12:25: Error: A dot shorthand constructor invocation can't have type arguments.
57+
self::C namedConstructor = invalid-expression "pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:14:25: Error: A dot shorthand constructor invocation can't have type arguments.
4358
Try adding the class name and type arguments explicitly before the constructor name.
4459
C namedConstructor = .named<int>();
4560
^^^^^" as{TypeError,ForDynamic} self::C;
46-
self::C newTearoff = invalid-expression "pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:13:22: Error: The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
47-
Try changing the operand or remove the type arguments.
61+
self::C newTearoff = invalid-expression "pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:15:19: Error: A dot shorthand constructor invocation can't have type arguments.
62+
Try adding the class name and type arguments explicitly before the constructor name.
4863
C newTearoff = .new<int>;
49-
^";
64+
^^^" as{TypeError,ForDynamic} self::C;
65+
self::C namedTearoff = invalid-expression "pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:16:21: Error: A dot shorthand constructor invocation can't have type arguments.
66+
Try adding the class name and type arguments explicitly before the constructor name.
67+
C namedTearoff = .new<int>;
68+
^^^" as{TypeError,ForDynamic} self::C;
69+
self::ET<dynamic>% /* erasure=dynamic, declared=! */ e = invalid-expression "pkg/front_end/testcases/dot_shorthands/constructor_type_parameter_error.dart:17:11: Error: A dot shorthand constructor invocation can't have type arguments.
70+
Try adding the class name and type arguments explicitly before the constructor name.
71+
ET e = .new<int>;
72+
^^^" as{TypeError,ForDynamic} self::ET<dynamic>% /* erasure=dynamic, declared=! */;
5073
}

0 commit comments

Comments
 (0)