Skip to content

Commit 66ceec0

Browse files
srawlinscommit-bot@chromium.org
authored andcommitted
Fix redirecting constructor const check
Fixes #27617 Change-Id: Id8629354e844d3f265302eda6348afccc2d63be1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/122120 Commit-Queue: Samuel Rawlins <srawlins@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
1 parent 6f44e99 commit 66ceec0

File tree

5 files changed

+103
-46
lines changed

5 files changed

+103
-46
lines changed

pkg/analyzer/lib/src/error/codes.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3994,7 +3994,7 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
39943994
static const CompileTimeErrorCode REDIRECT_TO_NON_CONST_CONSTRUCTOR =
39953995
const CompileTimeErrorCode(
39963996
'REDIRECT_TO_NON_CONST_CONSTRUCTOR',
3997-
"Constant factory constructor can't delegate to a non-constant "
3997+
"Constant redirecting constructor can't redirect to a non-constant "
39983998
"constructor.",
39993999
correction: "Try redirecting to a different constructor.");
40004000

@@ -6407,8 +6407,8 @@ class StaticWarningCode extends AnalyzerErrorCode {
64076407
* abstract class and <i>q</i> is not a factory constructor.
64086408
*/
64096409
static const StaticWarningCode NEW_WITH_ABSTRACT_CLASS =
6410-
const StaticWarningCode('NEW_WITH_ABSTRACT_CLASS',
6411-
"Abstract classes can't be instantiated.",
6410+
const StaticWarningCode(
6411+
'NEW_WITH_ABSTRACT_CLASS', "Abstract classes can't be instantiated.",
64126412
correction: "Try creating an instance of a subtype.");
64136413

64146414
/**

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
607607
_checkForAllRedirectConstructorErrorCodes(node);
608608
}
609609
_checkForUndefinedConstructorInInitializerImplicit(node);
610-
_checkForRedirectToNonConstConstructor(node, constructorElement);
611610
_checkForReturnInGenerativeConstructor(node);
612611
super.visitConstructorDeclaration(node);
613612
} finally {
@@ -4547,6 +4546,8 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
45474546
parameter.identifier);
45484547
}
45494548
}
4549+
_checkForRedirectToNonConstConstructor(declaration.declaredElement,
4550+
redirectedConstructor.staticElement, redirectedConstructor);
45504551
}
45514552
// check if there are redirected invocations
45524553
int numRedirections = 0;
@@ -4579,6 +4580,10 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
45794580
}
45804581
}
45814582
}
4583+
// [declaration] is a redirecting constructor via a redirecting
4584+
// initializer.
4585+
_checkForRedirectToNonConstConstructor(declaration.declaredElement,
4586+
initializer.staticElement, initializer.constructorName);
45824587
numRedirections++;
45834588
}
45844589
}
@@ -4605,41 +4610,21 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
46054610
}
46064611

46074612
/**
4608-
* Check whether the given constructor [declaration] has redirected
4609-
* constructor and references itself directly or indirectly. The
4610-
* constructor [element] is the element introduced by the declaration.
4613+
* Check whether the redirecting constructor, [element], is const, and
4614+
* [redirectedElement], its redirectee, is not const.
46114615
*
46124616
* See [CompileTimeErrorCode.REDIRECT_TO_NON_CONST_CONSTRUCTOR].
46134617
*/
4614-
void _checkForRedirectToNonConstConstructor(
4615-
ConstructorDeclaration declaration, ConstructorElement element) {
4616-
// prepare redirected constructor
4617-
ConstructorName redirectedConstructorNode =
4618-
declaration.redirectedConstructor;
4619-
if (redirectedConstructorNode == null) {
4620-
return;
4621-
}
4622-
// prepare element
4623-
if (element == null) {
4624-
return;
4625-
}
4626-
// OK, it is not 'const'
4627-
if (!element.isConst) {
4628-
return;
4629-
}
4630-
// prepare redirected constructor
4631-
ConstructorElement redirectedConstructor = element.redirectedConstructor;
4632-
if (redirectedConstructor == null) {
4633-
return;
4634-
}
4635-
// OK, it is also 'const'
4636-
if (redirectedConstructor.isConst) {
4637-
return;
4618+
void _checkForRedirectToNonConstConstructor(ConstructorElement element,
4619+
ConstructorElement redirectedElement, AstNode reportingNode) {
4620+
// This constructor is const, but it redirects to a non-const constructor.
4621+
if (redirectedElement != null &&
4622+
element.isConst &&
4623+
!redirectedElement.isConst) {
4624+
_errorReporter.reportErrorForNode(
4625+
CompileTimeErrorCode.REDIRECT_TO_NON_CONST_CONSTRUCTOR,
4626+
reportingNode);
46384627
}
4639-
4640-
_errorReporter.reportErrorForNode(
4641-
CompileTimeErrorCode.REDIRECT_TO_NON_CONST_CONSTRUCTOR,
4642-
redirectedConstructorNode);
46434628
}
46444629

46454630
void _checkForReferenceBeforeDeclaration(SimpleIdentifier node) {

pkg/analyzer/test/generated/compile_time_error_code.dart

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4418,17 +4418,6 @@ class B {
44184418
]);
44194419
}
44204420

4421-
test_redirectToNonConstConstructor() async {
4422-
await assertErrorsInCode(r'''
4423-
class A {
4424-
A.a() {}
4425-
const factory A.b() = A.a;
4426-
}
4427-
''', [
4428-
error(CompileTimeErrorCode.REDIRECT_TO_NON_CONST_CONSTRUCTOR, 45, 3),
4429-
]);
4430-
}
4431-
44324421
test_referencedBeforeDeclaration_hideInBlock_comment() async {
44334422
await assertNoErrorsInCode(r'''
44344423
main() {
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) 2019, 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+
import 'package:analyzer/src/error/codes.dart';
6+
import 'package:test_reflective_loader/test_reflective_loader.dart';
7+
8+
import '../dart/resolution/driver_resolution.dart';
9+
10+
main() {
11+
defineReflectiveSuite(() {
12+
defineReflectiveTests(RedirectToNonConstConstructorTest);
13+
});
14+
}
15+
16+
@reflectiveTest
17+
class RedirectToNonConstConstructorTest extends DriverResolutionTest {
18+
test_constRedirector_cannotResolveRedirectee() async {
19+
// No crash when redirectee cannot be resolved.
20+
await assertErrorsInCode(r'''
21+
class A {
22+
const factory A.b() = A.a;
23+
}
24+
''', [
25+
error(CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR, 34, 3),
26+
]);
27+
}
28+
29+
test_constRedirector_constRedirectee() async {
30+
await assertNoErrorsInCode(r'''
31+
class A {
32+
const A.a();
33+
const factory A.b() = A.a;
34+
}
35+
''');
36+
}
37+
38+
test_constRedirector_constRedirectee_viaInitializer() async {
39+
await assertNoErrorsInCode(r'''
40+
class A {
41+
const A.a();
42+
const A.b() : this.a();
43+
}
44+
''');
45+
}
46+
47+
test_constRedirector_nonConstRedirectee() async {
48+
await assertErrorsInCode(r'''
49+
class A {
50+
A.a();
51+
const factory A.b() = A.a;
52+
}
53+
''', [
54+
error(CompileTimeErrorCode.REDIRECT_TO_NON_CONST_CONSTRUCTOR, 43, 3),
55+
]);
56+
}
57+
58+
test_constRedirector_nonConstRedirectee_viaInitializer() async {
59+
await assertErrorsInCode(r'''
60+
class A {
61+
A.a();
62+
const A.b() : this.a();
63+
}
64+
''', [
65+
error(CompileTimeErrorCode.REDIRECT_TO_NON_CONST_CONSTRUCTOR, 40, 1),
66+
]);
67+
}
68+
69+
test_constRedirector_viaInitializer_cannotResolveRedirectee() async {
70+
// No crash when redirectee cannot be resolved.
71+
await assertErrorsInCode(r'''
72+
class A {
73+
const A.b() : this.a();
74+
}
75+
''', [
76+
error(CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR, 26,
77+
8),
78+
]);
79+
}
80+
}

pkg/analyzer/test/src/diagnostics/test_all.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ import 'redirect_to_invalid_return_type_test.dart'
267267
import 'redirect_to_missing_constructor_test.dart'
268268
as redirect_to_missing_constructor;
269269
import 'redirect_to_non_class_test.dart' as redirect_to_non_class;
270+
import 'redirect_to_non_const_constructor_test.dart'
271+
as redirect_to_non_const_constructor;
270272
import 'return_without_value_test.dart' as return_without_value;
271273
import 'sdk_version_as_expression_in_const_context_test.dart'
272274
as sdk_version_as_expression_in_const_context;
@@ -538,6 +540,7 @@ main() {
538540
redirect_to_invalid_return_type.main();
539541
redirect_to_missing_constructor.main();
540542
redirect_to_non_class.main();
543+
redirect_to_non_const_constructor.main();
541544
return_without_value.main();
542545
set_element_from_deferred_library.main();
543546
sdk_version_as_expression_in_const_context.main();

0 commit comments

Comments
 (0)