Skip to content

Commit 4243547

Browse files
johnniwintherCommit Queue
authored and
Commit Queue
committed
[cfe] Check and add non-extension types in implements clause
Closes #51564 Change-Id: I555c367f3650ddb435908a72b78069ceb6d07814 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/317881 Commit-Queue: Johnni Winther <[email protected]> Reviewed-by: Chloe Stefantsova <[email protected]>
1 parent ca3cd5e commit 4243547

File tree

46 files changed

+2393
-115
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2393
-115
lines changed

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12319,6 +12319,56 @@ const MessageCode messageSuperAsIdentifier = const MessageCode(
1231912319
analyzerCodes: <String>["SUPER_AS_EXPRESSION"],
1232012320
problemMessage: r"""Expected identifier, but got 'super'.""");
1232112321

12322+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
12323+
const Template<Message Function(String name)>
12324+
templateSuperExtensionTypeIsIllegal =
12325+
const Template<Message Function(String name)>(
12326+
problemMessageTemplate:
12327+
r"""The type '#name' can't be implemented by an extension type.""",
12328+
withArguments: _withArgumentsSuperExtensionTypeIsIllegal);
12329+
12330+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
12331+
const Code<Message Function(String name)> codeSuperExtensionTypeIsIllegal =
12332+
const Code<Message Function(String name)>(
12333+
"SuperExtensionTypeIsIllegal",
12334+
);
12335+
12336+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
12337+
Message _withArgumentsSuperExtensionTypeIsIllegal(String name) {
12338+
if (name.isEmpty) throw 'No name provided';
12339+
name = demangleMixinApplicationName(name);
12340+
return new Message(codeSuperExtensionTypeIsIllegal,
12341+
problemMessage:
12342+
"""The type '${name}' can't be implemented by an extension type.""",
12343+
arguments: {'name': name});
12344+
}
12345+
12346+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
12347+
const Template<
12348+
Message Function(
12349+
String
12350+
name)> templateSuperExtensionTypeIsTypeVariable = const Template<
12351+
Message Function(String name)>(
12352+
problemMessageTemplate:
12353+
r"""The type variable '#name' can't be implemented by an extension type.""",
12354+
withArguments: _withArgumentsSuperExtensionTypeIsTypeVariable);
12355+
12356+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
12357+
const Code<Message Function(String name)> codeSuperExtensionTypeIsTypeVariable =
12358+
const Code<Message Function(String name)>(
12359+
"SuperExtensionTypeIsTypeVariable",
12360+
);
12361+
12362+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
12363+
Message _withArgumentsSuperExtensionTypeIsTypeVariable(String name) {
12364+
if (name.isEmpty) throw 'No name provided';
12365+
name = demangleMixinApplicationName(name);
12366+
return new Message(codeSuperExtensionTypeIsTypeVariable,
12367+
problemMessage:
12368+
"""The type variable '${name}' can't be implemented by an extension type.""",
12369+
arguments: {'name': name});
12370+
}
12371+
1232212372
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
1232312373
const Code<Null> codeSuperInitializerNotLast = messageSuperInitializerNotLast;
1232412374

pkg/front_end/lib/src/fasta/builder/library_builder.dart

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ library fasta.library_builder;
66

77
import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
88

9-
import 'package:kernel/ast.dart' show Library, Nullability;
9+
import 'package:kernel/ast.dart' show Class, Library, Nullability;
1010

1111
import '../combinator.dart' show CombinatorBuilder;
1212

@@ -177,6 +177,36 @@ abstract class LibraryBuilder implements ModifierBuilder {
177177
NullabilityBuilder get nonNullableBuilder;
178178

179179
NullabilityBuilder nullableBuilderIfTrue(bool isNullable);
180+
181+
/// Returns `true` if [cls] is the 'Function' class defined in [coreLibrary].
182+
static bool isFunction(Class cls, LibraryBuilder coreLibrary) {
183+
return cls.name == 'Function' && _isCoreClass(cls, coreLibrary);
184+
}
185+
186+
/// Returns `true` if [cls] is the 'Record' class defined in [coreLibrary].
187+
static bool isRecord(Class cls, LibraryBuilder coreLibrary) {
188+
return cls.name == 'Record' && _isCoreClass(cls, coreLibrary);
189+
}
190+
191+
/// Returns `true` if [cls] is the 'Object' class defined in [coreLibrary].
192+
static bool isObject(Class cls, LibraryBuilder coreLibrary) {
193+
return cls.name == 'Object' && _isCoreClass(cls, coreLibrary);
194+
}
195+
196+
static bool _isCoreClass(Class cls, LibraryBuilder coreLibrary) {
197+
// We use `superclass.parent` here instead of
198+
// `superclass.enclosingLibrary` to handle platform compilation. If
199+
// we are currently compiling the platform, the enclosing library of
200+
// the core class has not yet been set, so the accessing
201+
// `enclosingLibrary` would result in a cast error. We assume that the
202+
// SDK does not contain this error, which we otherwise not find. If we
203+
// are _not_ compiling the platform, the `superclass.parent` has been
204+
// set, if it is a class from `dart:core`.
205+
if (cls.parent == coreLibrary.library) {
206+
return true;
207+
}
208+
return false;
209+
}
180210
}
181211

182212
abstract class LibraryBuilderImpl extends ModifierBuilderImpl

pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5265,6 +5265,78 @@ Message _withArgumentsSuperBoundedHint(
52655265
arguments: {'type': _type, 'type2': _type2});
52665266
}
52675267

5268+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
5269+
const Template<
5270+
Message Function(
5271+
String name, DartType _type, bool isNonNullableByDefault)>
5272+
templateSuperExtensionTypeIsIllegalAliased = const Template<
5273+
Message Function(
5274+
String name, DartType _type, bool isNonNullableByDefault)>(
5275+
problemMessageTemplate:
5276+
r"""The type '#name' which is an alias of '#type' can't be implemented by an extension type.""",
5277+
withArguments: _withArgumentsSuperExtensionTypeIsIllegalAliased);
5278+
5279+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
5280+
const Code<
5281+
Message Function(
5282+
String name, DartType _type, bool isNonNullableByDefault)>
5283+
codeSuperExtensionTypeIsIllegalAliased = const Code<
5284+
Message Function(
5285+
String name, DartType _type, bool isNonNullableByDefault)>(
5286+
"SuperExtensionTypeIsIllegalAliased",
5287+
);
5288+
5289+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
5290+
Message _withArgumentsSuperExtensionTypeIsIllegalAliased(
5291+
String name, DartType _type, bool isNonNullableByDefault) {
5292+
if (name.isEmpty) throw 'No name provided';
5293+
name = demangleMixinApplicationName(name);
5294+
TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
5295+
List<Object> typeParts = labeler.labelType(_type);
5296+
String type = typeParts.join();
5297+
return new Message(codeSuperExtensionTypeIsIllegalAliased,
5298+
problemMessage:
5299+
"""The type '${name}' which is an alias of '${type}' can't be implemented by an extension type.""" +
5300+
labeler.originMessages,
5301+
arguments: {'name': name, 'type': _type});
5302+
}
5303+
5304+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
5305+
const Template<
5306+
Message Function(
5307+
String name, DartType _type, bool isNonNullableByDefault)>
5308+
templateSuperExtensionTypeIsNullableAliased = const Template<
5309+
Message Function(
5310+
String name, DartType _type, bool isNonNullableByDefault)>(
5311+
problemMessageTemplate:
5312+
r"""The type '#name' which is an alias of '#type' can't be implemented by an extension type because it is nullable.""",
5313+
withArguments: _withArgumentsSuperExtensionTypeIsNullableAliased);
5314+
5315+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
5316+
const Code<
5317+
Message Function(
5318+
String name, DartType _type, bool isNonNullableByDefault)>
5319+
codeSuperExtensionTypeIsNullableAliased = const Code<
5320+
Message Function(
5321+
String name, DartType _type, bool isNonNullableByDefault)>(
5322+
"SuperExtensionTypeIsNullableAliased",
5323+
);
5324+
5325+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
5326+
Message _withArgumentsSuperExtensionTypeIsNullableAliased(
5327+
String name, DartType _type, bool isNonNullableByDefault) {
5328+
if (name.isEmpty) throw 'No name provided';
5329+
name = demangleMixinApplicationName(name);
5330+
TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
5331+
List<Object> typeParts = labeler.labelType(_type);
5332+
String type = typeParts.join();
5333+
return new Message(codeSuperExtensionTypeIsNullableAliased,
5334+
problemMessage:
5335+
"""The type '${name}' which is an alias of '${type}' can't be implemented by an extension type because it is nullable.""" +
5336+
labeler.originMessages,
5337+
arguments: {'name': name, 'type': _type});
5338+
}
5339+
52685340
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
52695341
const Template<
52705342
Message Function(

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

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ class SourceClassBuilder extends ClassBuilderImpl
245245
supertypeBuilder = _checkSupertype(supertypeBuilder!);
246246
}
247247
Supertype? supertype = supertypeBuilder?.buildSupertype(libraryBuilder);
248-
if (_isFunction(supertype, coreLibrary)) {
248+
if (supertype != null &&
249+
LibraryBuilder.isFunction(supertype.classNode, coreLibrary)) {
249250
supertype = null;
250251
supertypeBuilder = null;
251252
}
@@ -273,7 +274,8 @@ class SourceClassBuilder extends ClassBuilderImpl
273274
}
274275
Supertype? mixedInType =
275276
mixedInTypeBuilder?.buildMixedInType(libraryBuilder);
276-
if (_isFunction(mixedInType, coreLibrary)) {
277+
if (mixedInType != null &&
278+
LibraryBuilder.isFunction(mixedInType.classNode, coreLibrary)) {
277279
mixedInType = null;
278280
mixedInTypeBuilder = null;
279281
actualCls.isAnonymousMixin = false;
@@ -301,7 +303,7 @@ class SourceClassBuilder extends ClassBuilderImpl
301303
Supertype? supertype =
302304
interfaceBuilders![i].buildSupertype(libraryBuilder);
303305
if (supertype != null) {
304-
if (_isFunction(supertype, coreLibrary)) {
306+
if (LibraryBuilder.isFunction(supertype.classNode, coreLibrary)) {
305307
continue;
306308
}
307309
// TODO(ahe): Report an error if supertype is null.
@@ -350,25 +352,6 @@ class SourceClassBuilder extends ClassBuilderImpl
350352
return cls;
351353
}
352354

353-
bool _isFunction(Supertype? supertype, LibraryBuilder coreLibrary) {
354-
if (supertype != null) {
355-
Class superclass = supertype.classNode;
356-
if (superclass.name == 'Function' &&
357-
// We use `superclass.parent` here instead of
358-
// `superclass.enclosingLibrary` to handle platform compilation. If
359-
// we are currently compiling the platform, the enclosing library of
360-
// `Function` has not yet been set, so the accessing
361-
// `enclosingLibrary` would result in a cast error. We assume that the
362-
// SDK does not contain this error, which we otherwise not find. If we
363-
// are _not_ compiling the platform, the `superclass.parent` has been
364-
// set, if it is `Function` from `dart:core`.
365-
superclass.parent == coreLibrary.library) {
366-
return true;
367-
}
368-
}
369-
return false;
370-
}
371-
372355
BodyBuilderContext get bodyBuilderContext =>
373356
new ClassBodyBuilderContext(this);
374357

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

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,8 @@ import '../builder/type_alias_builder.dart';
1919
import '../builder/type_builder.dart';
2020
import '../builder/type_declaration_builder.dart';
2121
import '../builder/type_variable_builder.dart';
22-
import '../fasta_codes.dart'
23-
show
24-
messagePatchDeclarationMismatch,
25-
messagePatchDeclarationOrigin,
26-
noLength;
2722
import '../kernel/kernel_helper.dart';
23+
import '../messages.dart';
2824
import '../problems.dart';
2925
import '../scope.dart';
3026
import '../util/helpers.dart';
@@ -123,10 +119,96 @@ class SourceExtensionTypeDeclarationBuilder
123119
{required bool addMembersToLibrary}) {
124120
if (interfaceBuilders != null) {
125121
for (int i = 0; i < interfaceBuilders!.length; ++i) {
126-
DartType? interface =
127-
interfaceBuilders![i].build(libraryBuilder, TypeUse.superType);
122+
TypeBuilder typeBuilder = interfaceBuilders![i];
123+
TypeAliasBuilder? aliasBuilder =
124+
typeBuilder.declaration is TypeAliasBuilder
125+
? typeBuilder.declaration as TypeAliasBuilder
126+
: null;
127+
DartType interface =
128+
typeBuilder.build(libraryBuilder, TypeUse.superType);
129+
Message? errorMessage;
130+
List<LocatedMessage>? errorContext;
128131
if (interface is ExtensionType) {
129-
extensionTypeDeclaration.implements.add(interface);
132+
if (interface.isPotentiallyNullable) {
133+
errorMessage =
134+
templateSuperExtensionTypeIsNullableAliased.withArguments(
135+
typeBuilder.fullNameForErrors,
136+
interface,
137+
libraryBuilder.isNonNullableByDefault);
138+
if (aliasBuilder != null) {
139+
errorContext = [
140+
messageTypedefCause.withLocation(
141+
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
142+
];
143+
}
144+
} else {
145+
extensionTypeDeclaration.implements.add(interface);
146+
}
147+
} else if (interface is InterfaceType) {
148+
if (interface.isPotentiallyNullable) {
149+
errorMessage =
150+
templateSuperExtensionTypeIsNullableAliased.withArguments(
151+
typeBuilder.fullNameForErrors,
152+
interface,
153+
libraryBuilder.isNonNullableByDefault);
154+
if (aliasBuilder != null) {
155+
errorContext = [
156+
messageTypedefCause.withLocation(
157+
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
158+
];
159+
}
160+
} else {
161+
Class cls = interface.classNode;
162+
if (LibraryBuilder.isObject(cls, coreLibrary) ||
163+
LibraryBuilder.isFunction(cls, coreLibrary) ||
164+
LibraryBuilder.isRecord(cls, coreLibrary)) {
165+
if (aliasBuilder != null) {
166+
errorMessage =
167+
templateSuperExtensionTypeIsIllegalAliased.withArguments(
168+
typeBuilder.fullNameForErrors,
169+
interface,
170+
libraryBuilder.isNonNullableByDefault);
171+
errorContext = [
172+
messageTypedefCause.withLocation(
173+
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
174+
];
175+
} else {
176+
errorMessage = templateSuperExtensionTypeIsIllegal
177+
.withArguments(typeBuilder.fullNameForErrors);
178+
}
179+
} else {
180+
extensionTypeDeclaration.implements.add(interface);
181+
}
182+
}
183+
} else if (interface is TypeParameterType) {
184+
errorMessage = templateSuperExtensionTypeIsTypeVariable
185+
.withArguments(typeBuilder.fullNameForErrors);
186+
if (aliasBuilder != null) {
187+
errorContext = [
188+
messageTypedefCause.withLocation(
189+
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
190+
];
191+
}
192+
} else {
193+
if (aliasBuilder != null) {
194+
errorMessage =
195+
templateSuperExtensionTypeIsIllegalAliased.withArguments(
196+
typeBuilder.fullNameForErrors,
197+
interface,
198+
libraryBuilder.isNonNullableByDefault);
199+
errorContext = [
200+
messageTypedefCause.withLocation(
201+
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
202+
];
203+
} else {
204+
errorMessage = templateSuperExtensionTypeIsIllegal
205+
.withArguments(typeBuilder.fullNameForErrors);
206+
}
207+
}
208+
if (errorMessage != null) {
209+
libraryBuilder.addProblem(errorMessage, typeBuilder.charOffset!,
210+
noLength, typeBuilder.fileUri,
211+
context: errorContext);
130212
}
131213
}
132214
}

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

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,18 +1023,22 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
10231023
targetMember, targetTearoff, targetKind!, extensionType.typeArguments,
10241024
isPotentiallyNullable: isReceiverTypePotentiallyNullable);
10251025
} else {
1026-
for (ExtensionType implement
1026+
for (DartType implement
10271027
in extensionType.extensionTypeDeclaration.implements) {
1028-
ExtensionType supertype = hierarchyBuilder.getExtensionTypeAsInstanceOf(
1029-
extensionType, implement.extensionTypeDeclaration,
1030-
isNonNullableByDefault: isNonNullableByDefault)!;
1031-
ObjectAccessTarget? target = _findDirectExtensionTypeMember(
1032-
receiverType, supertype, name, fileOffset,
1033-
isSetter: isSetter,
1034-
isReceiverTypePotentiallyNullable:
1035-
isReceiverTypePotentiallyNullable);
1036-
if (target != null) {
1037-
return target;
1028+
// TODO(johnniwinther): Handle non-extension type supertypes.
1029+
if (implement is ExtensionType) {
1030+
ExtensionType supertype =
1031+
hierarchyBuilder.getExtensionTypeAsInstanceOf(
1032+
extensionType, implement.extensionTypeDeclaration,
1033+
isNonNullableByDefault: isNonNullableByDefault)!;
1034+
ObjectAccessTarget? target = _findDirectExtensionTypeMember(
1035+
receiverType, supertype, name, fileOffset,
1036+
isSetter: isSetter,
1037+
isReceiverTypePotentiallyNullable:
1038+
isReceiverTypePotentiallyNullable);
1039+
if (target != null) {
1040+
return target;
1041+
}
10381042
}
10391043
}
10401044
return null;

pkg/front_end/messages.status

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,10 @@ StrongWithWeakDillLibrary/example: Fail
937937
StrongWithWeakDillLibrary/spelling: Fail
938938
SuperAsExpression/example: Fail
939939
SuperAsIdentifier/example: Fail
940+
SuperExtensionTypeIsIllegal/analyzerCode: Fail
941+
SuperExtensionTypeIsIllegalAliased/analyzerCode: Fail
942+
SuperExtensionTypeIsNullableAliased/analyzerCode: Fail
943+
SuperExtensionTypeIsTypeVariable/analyzerCode: Fail
940944
SuperNullAware/example: Fail
941945
SuperParameterInitializerOutsideConstructor/analyzerCode: Fail
942946
SuperParameterInitializerOutsideConstructor/example: Fail

0 commit comments

Comments
 (0)