Skip to content

Commit 2fa8923

Browse files
johnniwinthercommit-bot@chromium.org
authored andcommitted
[cfe] Handle potentially constant types in instantiations
Part of #46232 Closes #47154 Change-Id: I71fe16d26facf29bdae1b98971c4ccfe18f95e80 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/213772 Reviewed-by: Chloe Stefantsova <[email protected]> Commit-Queue: Johnni Winther <[email protected]>
1 parent 93d2f90 commit 2fa8923

26 files changed

+2402
-164
lines changed

pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ enum NullValue {
6969
TypeList,
7070
TypeVariable,
7171
TypeVariables,
72+
UnresolvedType,
7273
VarFinalOrConstToken,
7374
WithClause,
7475
}
@@ -374,7 +375,7 @@ abstract class StackListener extends Listener {
374375
@override
375376
void handleNoType(Token lastConsumed) {
376377
debugEvent("NoType");
377-
push(NullValue.Type);
378+
push(NullValue.UnresolvedType);
378379
}
379380

380381
@override

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

+141-125
Large diffs are not rendered by default.

pkg/front_end/lib/src/fasta/kernel/expression_generator.dart

+43-23
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,9 @@ abstract class Generator {
260260
Expression_Generator applyTypeArguments(
261261
int fileOffset, List<UnresolvedType>? typeArguments) {
262262
return new Instantiation(
263-
buildSimpleRead(), _helper.buildDartTypeArguments(typeArguments))
263+
buildSimpleRead(),
264+
_helper.buildDartTypeArguments(typeArguments,
265+
allowPotentiallyConstantType: true))
264266
..fileOffset = fileOffset;
265267
}
266268

@@ -270,7 +272,8 @@ abstract class Generator {
270272
/// The type arguments have not been resolved and should be resolved to
271273
/// create a [TypeBuilder] for a valid type.
272274
TypeBuilder buildTypeWithResolvedArguments(
273-
NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments) {
275+
NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments,
276+
{required bool allowPotentiallyConstantType}) {
274277
// TODO(johnniwinther): Could we use a FixedTypeBuilder(InvalidType()) here?
275278
NamedTypeBuilder result = new NamedTypeBuilder(
276279
token.lexeme,
@@ -2897,11 +2900,13 @@ class DeferredAccessGenerator extends Generator {
28972900

28982901
@override
28992902
TypeBuilder buildTypeWithResolvedArguments(
2900-
NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments) {
2903+
NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments,
2904+
{required bool allowPotentiallyConstantType}) {
29012905
String name = "${prefixGenerator._plainNameForRead}."
29022906
"${suffixGenerator._plainNameForRead}";
29032907
TypeBuilder type = suffixGenerator.buildTypeWithResolvedArguments(
2904-
nullabilityBuilder, arguments);
2908+
nullabilityBuilder, arguments,
2909+
allowPotentiallyConstantType: allowPotentiallyConstantType);
29052910
LocatedMessage message;
29062911
if (type is NamedTypeBuilder &&
29072912
type.declaration is InvalidTypeDeclarationBuilder) {
@@ -2912,7 +2917,8 @@ class DeferredAccessGenerator extends Generator {
29122917
int charOffset = offsetForToken(prefixGenerator.token);
29132918
message = templateDeferredTypeAnnotation
29142919
.withArguments(
2915-
_helper.buildDartType(new UnresolvedType(type, charOffset, _uri)),
2920+
_helper.buildDartType(new UnresolvedType(type, charOffset, _uri),
2921+
allowPotentiallyConstantType: allowPotentiallyConstantType),
29162922
prefixGenerator._plainNameForRead,
29172923
_helper.libraryBuilder.isNonNullableByDefault)
29182924
.withLocation(
@@ -3022,17 +3028,19 @@ class TypeUseGenerator extends AbstractReadOnlyAccessGenerator {
30223028

30233029
@override
30243030
TypeBuilder buildTypeWithResolvedArguments(
3025-
NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments) {
3031+
NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments,
3032+
{required bool allowPotentiallyConstantType}) {
30263033
if (declaration.isExtension && !_helper.enableExtensionTypesInLibrary) {
30273034
// Extension declarations cannot be used as types.
3028-
return super
3029-
.buildTypeWithResolvedArguments(nullabilityBuilder, arguments);
3035+
return super.buildTypeWithResolvedArguments(nullabilityBuilder, arguments,
3036+
allowPotentiallyConstantType: allowPotentiallyConstantType);
30303037
}
30313038
if (arguments != null) {
30323039
int expected = declaration.typeVariablesCount;
30333040
if (arguments.length != expected) {
30343041
// Build the type arguments to report any errors they may have.
3035-
_helper.buildDartTypeArguments(arguments);
3042+
_helper.buildDartTypeArguments(arguments,
3043+
allowPotentiallyConstantType: allowPotentiallyConstantType);
30363044
_helper.warnTypeArgumentsMismatch(
30373045
declaration.name, expected, fileOffset);
30383046
// We ignore the provided arguments, which will in turn return the
@@ -3048,11 +3056,8 @@ class TypeUseGenerator extends AbstractReadOnlyAccessGenerator {
30483056
argumentBuilders =
30493057
new List<TypeBuilder>.generate(arguments.length, (int i) {
30503058
return _helper
3051-
.validateTypeUse(arguments![i],
3052-
nonInstanceAccessIsError: false,
3053-
allowPotentiallyConstantType:
3054-
_helper.libraryBuilder.isNonNullableByDefault &&
3055-
_helper.inIsOrAsOperatorType)
3059+
.validateTypeVariableUse(arguments![i],
3060+
allowPotentiallyConstantType: allowPotentiallyConstantType)
30563061
.builder;
30573062
}, growable: false);
30583063
}
@@ -3105,10 +3110,12 @@ class TypeUseGenerator extends AbstractReadOnlyAccessGenerator {
31053110
new UnresolvedType(
31063111
buildTypeWithResolvedArguments(
31073112
_helper.libraryBuilder.nonNullableBuilder,
3108-
typeArguments),
3113+
typeArguments,
3114+
allowPotentiallyConstantType: true),
31093115
fileOffset,
31103116
_uri),
3111-
nonInstanceAccessIsError: true));
3117+
allowPotentiallyConstantType:
3118+
_helper.enableConstructorTearOffsInLibrary));
31123119
}
31133120
}
31143121
return _expression!;
@@ -3131,8 +3138,16 @@ class TypeUseGenerator extends AbstractReadOnlyAccessGenerator {
31313138
isUsedAsClass: true,
31323139
usedAsClassCharOffset: this.fileOffset,
31333140
usedAsClassFileUri: _uri);
3134-
List<TypeBuilder>? aliasedTypeArguments =
3135-
typeArguments?.map((unknownType) => unknownType.builder).toList();
3141+
3142+
bool isConstructorTearOff = send is PropertySelector &&
3143+
_helper.enableConstructorTearOffsInLibrary &&
3144+
declarationBuilder is ClassBuilder;
3145+
List<TypeBuilder>? aliasedTypeArguments = typeArguments
3146+
?.map((unknownType) => _helper
3147+
.validateTypeVariableUse(unknownType,
3148+
allowPotentiallyConstantType: isConstructorTearOff)
3149+
.builder)
3150+
.toList();
31363151
if (aliasedTypeArguments != null &&
31373152
aliasedTypeArguments.length != aliasBuilder.typeVariablesCount) {
31383153
_helper.libraryBuilder.addProblem(
@@ -3236,8 +3251,9 @@ class TypeUseGenerator extends AbstractReadOnlyAccessGenerator {
32363251
_helper.libraryBuilder, unaliasedTypeArguments);
32373252
}
32383253
} else if (typeArguments != null) {
3239-
builtTypeArguments =
3240-
_helper.buildDartTypeArguments(typeArguments);
3254+
builtTypeArguments = _helper.buildDartTypeArguments(
3255+
typeArguments,
3256+
allowPotentiallyConstantType: true);
32413257
}
32423258
if (isGenericTypedefTearOff) {
32433259
if (isProperRenameForClass(_helper.typeEnvironment,
@@ -3670,7 +3686,9 @@ abstract class ErroneousExpressionGenerator extends Generator {
36703686
if (typeArguments != null) {
36713687
assert(_forest.argumentsTypeArguments(arguments).isEmpty);
36723688
_forest.argumentsSetTypeArguments(
3673-
arguments, _helper.buildDartTypeArguments(typeArguments));
3689+
arguments,
3690+
_helper.buildDartTypeArguments(typeArguments,
3691+
allowPotentiallyConstantType: false));
36743692
}
36753693
return buildError(arguments, kind: UnresolvedKind.Constructor);
36763694
}
@@ -4145,7 +4163,8 @@ class UnexpectedQualifiedUseGenerator extends Generator {
41454163

41464164
@override
41474165
TypeBuilder buildTypeWithResolvedArguments(
4148-
NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments) {
4166+
NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments,
4167+
{required bool allowPotentiallyConstantType}) {
41494168
Template<Message Function(String, String)> template = isUnresolved
41504169
? templateUnresolvedPrefixInTypeAnnotation
41514170
: templateNotAPrefixInTypeAnnotation;
@@ -4269,7 +4288,8 @@ class ParserErrorGenerator extends Generator {
42694288

42704289
@override
42714290
TypeBuilder buildTypeWithResolvedArguments(
4272-
NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments) {
4291+
NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments,
4292+
{required bool allowPotentiallyConstantType}) {
42734293
// TODO(johnniwinther): Could we use a FixedTypeBuilder(InvalidType()) here?
42744294
NamedTypeBuilder result = new NamedTypeBuilder(
42754295
token.lexeme,

pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart

+6-9
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ abstract class ExpressionGeneratorHelper implements InferenceHelper {
4848

4949
Member? lookupInstanceMember(Name name, {bool isSetter, bool isSuper});
5050

51-
/// `true` if we are in the type of an as expression.
52-
bool get inIsOrAsOperatorType;
53-
5451
bool get enableExtensionTypesInLibrary;
5552

5653
bool get enableConstFunctionsInLibrary;
@@ -125,9 +122,8 @@ abstract class ExpressionGeneratorHelper implements InferenceHelper {
125122
TypeDeclarationBuilder? typeAliasBuilder,
126123
required UnresolvedKind unresolvedKind});
127124

128-
UnresolvedType validateTypeUse(UnresolvedType unresolved,
129-
{required bool nonInstanceAccessIsError,
130-
required bool allowPotentiallyConstantType});
125+
UnresolvedType validateTypeVariableUse(UnresolvedType unresolved,
126+
{required bool allowPotentiallyConstantType});
131127

132128
void addProblemErrorIfConst(Message message, int charOffset, int length);
133129

@@ -150,12 +146,13 @@ abstract class ExpressionGeneratorHelper implements InferenceHelper {
150146
Arguments arguments, Expression expression);
151147

152148
DartType buildDartType(UnresolvedType unresolvedType,
153-
{bool nonInstanceAccessIsError: false});
149+
{required bool allowPotentiallyConstantType});
154150

155151
DartType buildTypeLiteralDartType(UnresolvedType unresolvedType,
156-
{bool nonInstanceAccessIsError});
152+
{required bool allowPotentiallyConstantType});
157153

158-
List<DartType> buildDartTypeArguments(List<UnresolvedType>? unresolvedTypes);
154+
List<DartType> buildDartTypeArguments(List<UnresolvedType>? unresolvedTypes,
155+
{required bool allowPotentiallyConstantType});
159156

160157
void reportDuplicatedDeclaration(
161158
Builder existing, String name, int charOffset);

pkg/front_end/lib/src/fasta/source/value_kinds.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,15 @@ class ValueKinds {
108108
static const ValueKind TokenOrNull =
109109
const SingleValueKind<type.Token>(NullValue.Token);
110110
static const ValueKind TypeOrNull =
111-
const SingleValueKind<type.UnresolvedType>(NullValue.Type);
111+
const SingleValueKind<type.UnresolvedType>(NullValue.UnresolvedType);
112112
static const ValueKind TypeArguments =
113113
const SingleValueKind<List<type.UnresolvedType>>();
114114
static const ValueKind TypeArgumentsOrNull =
115115
const SingleValueKind<List<type.UnresolvedType>>(NullValue.TypeArguments);
116116
static const ValueKind TypeBuilder =
117117
const SingleValueKind<type.TypeBuilder>();
118118
static const ValueKind TypeBuilderOrNull =
119-
const SingleValueKind<type.TypeBuilder>(NullValue.Type);
119+
const SingleValueKind<type.TypeBuilder>(NullValue.UnresolvedType);
120120
static const ValueKind TypeBuilderListOrNull =
121121
const SingleValueKind<List<type.TypeBuilder>>(NullValue.TypeBuilderList);
122122
static const ValueKind TypeVariableListOrNull =

pkg/front_end/test/spell_checking_list_code.txt

+1
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,7 @@ prime
935935
printer
936936
printf
937937
println
938+
prioritization
938939
proc
939940
producers
940941
product
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) 2021, 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+
// A potentially constant type expression is supported for `as` (and `is`)
6+
class A<X> {
7+
final List<X> x;
8+
const A(x) : x = x is List<X> ? x : x as List<X>;
9+
}
10+
11+
void m<X>(X x) {}
12+
13+
// Generic function instantiation to a type parameter is supported implicitly.
14+
class B<X> {
15+
final void Function(X) f;
16+
const B() : f = m;
17+
}
18+
19+
// But it is not supported explicitly.
20+
class C<X> {
21+
final f;
22+
const C() : f = m<X>; // Error, but should be accepted.
23+
}
24+
25+
void main() {
26+
const A<int>(<int>[1]); // OK.
27+
const b = B<String>(); // OK.
28+
print(b.f.runtimeType); // OK: 'String => void'.
29+
const c = C<
30+
String>(); // Compile-time error in `C`, but should be accepted when it works.
31+
print(c.f.runtimeType); // (Never executed, so we don't know).
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class A<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
6+
final field core::List<self::A::X%> x;
7+
const constructor •(dynamic x) → self::A<self::A::X%>
8+
: self::A::x = x is{ForNonNullableByDefault} core::List<self::A::X%> ?{core::List<self::A::X%>} x{core::List<self::A::X%>} : x as{ForNonNullableByDefault} core::List<self::A::X%>, super core::Object::•()
9+
;
10+
}
11+
class B<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
12+
final field (self::B::X%) → void f;
13+
const constructor •() → self::B<self::B::X%>
14+
: self::B::f = #C1<self::B::X%>, super core::Object::•()
15+
;
16+
}
17+
class C<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
18+
final field dynamic f;
19+
const constructor •() → self::C<self::C::X%>
20+
: self::C::f = #C1<self::C::X%>, super core::Object::•()
21+
;
22+
}
23+
static method m<X extends core::Object? = dynamic>(self::m::X% x) → void {}
24+
static method main() → void {
25+
#C4;
26+
core::print((#C6.{self::B::f}{(core::String) → void} as{TypeError,CovarianceCheck,ForNonNullableByDefault} (core::String) → void).{core::Object::runtimeType}{core::Type});
27+
core::print(#C7.{self::C::f}{dynamic}.{core::Object::runtimeType}{core::Type});
28+
}
29+
30+
constants {
31+
#C1 = static-tearoff self::m
32+
#C2 = 1
33+
#C3 = <core::int>[#C2]
34+
#C4 = self::A<core::int> {x:#C3}
35+
#C5 = instantiation self::m <core::String>
36+
#C6 = self::B<core::String> {f:#C5}
37+
#C7 = self::C<core::String> {f:#C5}
38+
}
39+
40+
41+
Constructor coverage from constants:
42+
org-dartlang-testcase:///issue47154c.dart:
43+
- A. (from org-dartlang-testcase:///issue47154c.dart:8:9)
44+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
45+
- B. (from org-dartlang-testcase:///issue47154c.dart:16:9)
46+
- C. (from org-dartlang-testcase:///issue47154c.dart:22:9)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class A<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
6+
final field core::List<self::A::X%> x;
7+
const constructor •(dynamic x) → self::A<self::A::X%>
8+
: self::A::x = x is{ForNonNullableByDefault} core::List<self::A::X%> ?{core::List<self::A::X%>} x{core::List<self::A::X%>} : x as{ForNonNullableByDefault} core::List<self::A::X%>, super core::Object::•()
9+
;
10+
}
11+
class B<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
12+
final field (self::B::X%) → void f;
13+
const constructor •() → self::B<self::B::X%>
14+
: self::B::f = #C1<self::B::X%>, super core::Object::•()
15+
;
16+
}
17+
class C<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
18+
final field dynamic f;
19+
const constructor •() → self::C<self::C::X%>
20+
: self::C::f = #C1<self::C::X%>, super core::Object::•()
21+
;
22+
}
23+
static method m<X extends core::Object? = dynamic>(self::m::X% x) → void {}
24+
static method main() → void {
25+
#C4;
26+
core::print((#C6.{self::B::f}{(core::String) → void} as{TypeError,CovarianceCheck,ForNonNullableByDefault} (core::String) → void).{core::Object::runtimeType}{core::Type});
27+
core::print(#C7.{self::C::f}{dynamic}.{core::Object::runtimeType}{core::Type});
28+
}
29+
30+
constants {
31+
#C1 = static-tearoff self::m
32+
#C2 = 1
33+
#C3 = <core::int>[#C2]
34+
#C4 = self::A<core::int> {x:#C3}
35+
#C5 = instantiation self::m <core::String>
36+
#C6 = self::B<core::String> {f:#C5}
37+
#C7 = self::C<core::String> {f:#C5}
38+
}
39+
40+
41+
Constructor coverage from constants:
42+
org-dartlang-testcase:///issue47154c.dart:
43+
- A. (from org-dartlang-testcase:///issue47154c.dart:8:9)
44+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
45+
- B. (from org-dartlang-testcase:///issue47154c.dart:16:9)
46+
- C. (from org-dartlang-testcase:///issue47154c.dart:22:9)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class A<X> {
2+
final List<X> x;
3+
const A(x) : x = x is List<X> ? x : x as List<X>;
4+
}
5+
6+
void m<X>(X x) {}
7+
8+
class B<X> {
9+
final void Function(X) f;
10+
const B() : f = m;
11+
}
12+
13+
class C<X> {
14+
final f;
15+
const C() : f = m<X>;
16+
}
17+
18+
void main() {}

0 commit comments

Comments
 (0)