Skip to content

Commit af51a02

Browse files
kallentuCommit Queue
authored and
Commit Queue
committed
[cfe] Disallow '.new<int>' and type parameters on constructors for dot shorthands.
Adds errors for this part of the spec behaviour: `.new<typeArgs> and .new<typeArgs>(args) will always be compile-time errors because .new denotes a constructor which is not generic` Bug: #59758 Change-Id: I76074d2314f40f60015324d4b01ece7477a8ffb4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417880 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Kallen Tu <[email protected]>
1 parent f9bf821 commit af51a02

12 files changed

+243
-18
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

+14
Original file line numberDiff line numberDiff line change
@@ -3236,6 +3236,20 @@ const MessageCode messageDirectiveAfterDeclaration = const MessageCode(
32363236
correctionMessage: r"""Try moving the directive before any declarations.""",
32373237
);
32383238

3239+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3240+
const Code<Null> codeDotShorthandsConstructorInvocationWithTypeArguments =
3241+
messageDotShorthandsConstructorInvocationWithTypeArguments;
3242+
3243+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3244+
const MessageCode messageDotShorthandsConstructorInvocationWithTypeArguments =
3245+
const MessageCode(
3246+
"DotShorthandsConstructorInvocationWithTypeArguments",
3247+
problemMessage:
3248+
r"""A dot shorthand constructor invocation can't have type arguments.""",
3249+
correctionMessage:
3250+
r"""Try adding the class name and type arguments explicitly before the constructor name.""",
3251+
);
3252+
32393253
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
32403254
const Template<Message Function(String name)>
32413255
templateDotShorthandsInvalidContext =

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

+18-10
Original file line numberDiff line numberDiff line change
@@ -12146,14 +12146,24 @@ class InferenceVisitorImpl extends InferenceVisitorBase
1214612146
// a constructor of that name instead.
1214712147
Member? constructor =
1214812148
findConstructor(cachedContext, node.name, node.fileOffset);
12149+
12150+
// Dot shorthand constructor invocations with type parameters
12151+
// `.id<type>()` are not allowed.
12152+
if (constructor != null && node.arguments.types.isNotEmpty) {
12153+
return new ExpressionInferenceResult(
12154+
const DynamicType(),
12155+
helper.buildProblem(
12156+
messageDotShorthandsConstructorInvocationWithTypeArguments,
12157+
node.nameOffset,
12158+
node.name.text.length));
12159+
}
12160+
1214912161
if (constructor is Constructor) {
1215012162
if (!constructor.isConst && node.isConst) {
12151-
Expression replacement = helper.buildProblem(
12152-
messageNonConstConstructor,
12153-
node.nameOffset,
12154-
node.name.text.length);
1215512163
return new ExpressionInferenceResult(
12156-
const DynamicType(), replacement);
12164+
const DynamicType(),
12165+
helper.buildProblem(messageNonConstConstructor, node.nameOffset,
12166+
node.name.text.length));
1215712167
}
1215812168

1215912169
expr = new ConstructorInvocation(constructor, node.arguments,
@@ -12164,12 +12174,10 @@ class InferenceVisitorImpl extends InferenceVisitorBase
1216412174
// constructor or a redirecting factory constructor.
1216512175
if (!constructor.isConst && node.isConst) {
1216612176
// Coverage-ignore-block(suite): Not run.
12167-
Expression replacement = helper.buildProblem(
12168-
messageNonConstConstructor,
12169-
node.nameOffset,
12170-
node.name.text.length);
1217112177
return new ExpressionInferenceResult(
12172-
const DynamicType(), replacement);
12178+
const DynamicType(),
12179+
helper.buildProblem(messageNonConstConstructor, node.nameOffset,
12180+
node.name.text.length));
1217312181
}
1217412182

1217512183
if (constructor.isRedirectingFactory) {

pkg/front_end/messages.status

+1
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ DirectiveAfterDeclaration/part_wrapped_script1: Fail
200200
DirectiveAfterDeclaration/part_wrapped_script2: Fail
201201
DirectiveAfterDeclaration/script1: Fail
202202
DirectiveAfterDeclaration/script2: Fail
203+
DotShorthandsConstructorInvocationWithTypeArguments/analyzerCode: Fail # TODO(kallentu): https://github.com/dart-lang/sdk/issues/59835
203204
DotShorthandsInvalidContext/analyzerCode: Fail # TODO(kallentu): https://github.com/dart-lang/sdk/issues/59835
204205
DotShorthandsUndefinedGetter/analyzerCode: Fail # TODO(kallentu): https://github.com/dart-lang/sdk/issues/59835
205206
DotShorthandsUndefinedInvocation/analyzerCode: Fail # TODO(kallentu): https://github.com/dart-lang/sdk/issues/59835

pkg/front_end/messages.yaml

+12
Original file line numberDiff line numberDiff line change
@@ -7421,6 +7421,18 @@ ImplicitSuperInitializerMissingArguments:
74217421
script: |
74227422
class A { A(int foo); } class B extends A { B(); }
74237423
7424+
DotShorthandsConstructorInvocationWithTypeArguments:
7425+
problemMessage: "A dot shorthand constructor invocation can't have type arguments."
7426+
correctionMessage: "Try adding the class name and type arguments explicitly before the constructor name."
7427+
experiments: dot-shorthands
7428+
script: >
7429+
class C<X> {
7430+
C.foo();
7431+
}
7432+
void main() {
7433+
C c = .foo<int>();
7434+
}
7435+
74247436
DotShorthandsInvalidContext:
74257437
problemMessage: "No type was provided to find the dot shorthand '#name'."
74267438
experiments: dot-shorthands
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
class C {
6+
C();
7+
C.named();
8+
}
9+
10+
void test() {
11+
C newConstructor = .new<int>();
12+
C namedConstructor = .named<int>();
13+
C newTearoff = .new<int>;
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
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.
6+
// Try adding the class name and type arguments explicitly before the constructor name.
7+
// C newConstructor = .new<int>();
8+
// ^^^
9+
//
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.
11+
// Try adding the class name and type arguments explicitly before the constructor name.
12+
// C namedConstructor = .named<int>();
13+
// ^^^^^
14+
//
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'.
18+
// C newTearoff = .new<int>;
19+
// ^^^
20+
//
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+
// ^
25+
//
26+
import self as self;
27+
import "dart:core" as core;
28+
29+
class C extends core::Object {
30+
constructor •() → self::C
31+
: super core::Object::•()
32+
;
33+
constructor named() → self::C
34+
: super core::Object::•()
35+
;
36+
}
37+
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.
39+
Try adding the class name and type arguments explicitly before the constructor name.
40+
C newConstructor = .new<int>();
41+
^^^" 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.
43+
Try adding the class name and type arguments explicitly before the constructor name.
44+
C namedConstructor = .named<int>();
45+
^^^^^" 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.
48+
C newTearoff = .new<int>;
49+
^";
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
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.
6+
// Try adding the class name and type arguments explicitly before the constructor name.
7+
// C newConstructor = .new<int>();
8+
// ^^^
9+
//
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.
11+
// Try adding the class name and type arguments explicitly before the constructor name.
12+
// C namedConstructor = .named<int>();
13+
// ^^^^^
14+
//
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'.
18+
// C newTearoff = .new<int>;
19+
// ^^^
20+
//
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+
// ^
25+
//
26+
import self as self;
27+
import "dart:core" as core;
28+
29+
class C extends core::Object {
30+
constructor •() → self::C
31+
: super core::Object::•()
32+
;
33+
constructor named() → self::C
34+
: super core::Object::•()
35+
;
36+
}
37+
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.
39+
Try adding the class name and type arguments explicitly before the constructor name.
40+
C newConstructor = .new<int>();
41+
^^^" 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.
43+
Try adding the class name and type arguments explicitly before the constructor name.
44+
C namedConstructor = .named<int>();
45+
^^^^^" 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.
48+
C newTearoff = .new<int>;
49+
^";
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class C extends core::Object {
6+
constructor •() → self::C
7+
;
8+
constructor named() → self::C
9+
;
10+
}
11+
static method test() → void
12+
;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
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.
6+
// Try adding the class name and type arguments explicitly before the constructor name.
7+
// C newConstructor = .new<int>();
8+
// ^^^
9+
//
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.
11+
// Try adding the class name and type arguments explicitly before the constructor name.
12+
// C namedConstructor = .named<int>();
13+
// ^^^^^
14+
//
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'.
18+
// C newTearoff = .new<int>;
19+
// ^^^
20+
//
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+
// ^
25+
//
26+
import self as self;
27+
import "dart:core" as core;
28+
29+
class C extends core::Object {
30+
constructor •() → self::C
31+
: super core::Object::•()
32+
;
33+
constructor named() → self::C
34+
: super core::Object::•()
35+
;
36+
}
37+
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.
39+
Try adding the class name and type arguments explicitly before the constructor name.
40+
C newConstructor = .new<int>();
41+
^^^" as{TypeError,ForDynamic,Unchecked} 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.
43+
Try adding the class name and type arguments explicitly before the constructor name.
44+
C namedConstructor = .named<int>();
45+
^^^^^" as{TypeError,ForDynamic,Unchecked} 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.
48+
C newTearoff = .new<int>;
49+
^";
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class C {
2+
C();
3+
C.named();
4+
}
5+
6+
void test() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class C {
2+
C();
3+
C.named();
4+
}
5+
6+
void test() {}

tests/language/dot_shorthands/type_parameter/type_parameter_error_test.dart

+10-8
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,26 @@ import '../dot_shorthand_helper.dart';
1111

1212
void main() {
1313
StaticMember<int> s = .memberType<String, String>('s');
14-
// ^
14+
// ^
1515
// [analyzer] unspecified
16-
// [cfe] unspecified
16+
// [cfe] A value of type 'StaticMember<String>' can't be assigned to a variable of type 'StaticMember<int>'.
1717

1818
// Constructors doesn't have type parameters.
1919
StaticMember<int> constructorTypeParameter = .constNamed<int>(1);
20-
// ^
20+
// ^^^^^^^^^^
2121
// [analyzer] unspecified
22-
// [cfe] unspecified
22+
// [cfe] A dot shorthand constructor invocation can't have type arguments.
2323

2424
// `.new<type-args>()` and `.new<type-args>` are a compile-time error.
2525
UnnamedConstructorTypeParameters typeParameters = .new<int>();
26-
// ^
26+
// ^^^
2727
// [analyzer] unspecified
28-
// [cfe] unspecified
28+
// [cfe] A dot shorthand constructor invocation can't have type arguments.
2929

3030
UnnamedConstructorTypeParameters Function() tearOff = .new<int>;
31-
// ^
31+
// ^^^
3232
// [analyzer] unspecified
33-
// [cfe] unspecified
33+
// [cfe] The static getter or field 'new' isn't defined for the type 'UnnamedConstructorTypeParameters<dynamic> Function()'.
34+
// ^
35+
// [cfe] The static type of the explicit instantiation operand must be a generic function type but is 'dynamic'.
3436
}

0 commit comments

Comments
 (0)