Skip to content

Commit 80a4002

Browse files
eernstgcommit-bot@chromium.org
authored andcommitted
[cfe] Add initial version of support for nonfunction-type-aliases
Change-Id: I9ff3f0c18a31bd1e0d16ba8b6ccd0cc261250c11 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/127005 Commit-Queue: Erik Ernst <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent 97c2ca5 commit 80a4002

36 files changed

+588
-360
lines changed

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

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2934,6 +2934,27 @@ Message _withArgumentsExtendingRestricted(String name) {
29342934
arguments: {'name': name});
29352935
}
29362936

2937+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2938+
const Code<Null> codeExtendsFutureOr = messageExtendsFutureOr;
2939+
2940+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2941+
const MessageCode messageExtendsFutureOr = const MessageCode("ExtendsFutureOr",
2942+
message: r"""The type 'FutureOr' can't be used in an 'extends' clause.""");
2943+
2944+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2945+
const Code<Null> codeExtendsNever = messageExtendsNever;
2946+
2947+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2948+
const MessageCode messageExtendsNever = const MessageCode("ExtendsNever",
2949+
message: r"""The type 'Never' can't be used in an 'extends' clause.""");
2950+
2951+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2952+
const Code<Null> codeExtendsVoid = messageExtendsVoid;
2953+
2954+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2955+
const MessageCode messageExtendsVoid = const MessageCode("ExtendsVoid",
2956+
message: r"""The type 'void' can't be used in an 'extends' clause.""");
2957+
29372958
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
29382959
const Code<Null> codeExtensionDeclaresAbstractMember =
29392960
messageExtensionDeclaresAbstractMember;
@@ -3904,7 +3925,15 @@ const Code<Null> codeImplementsFutureOr = messageImplementsFutureOr;
39043925
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
39053926
const MessageCode messageImplementsFutureOr = const MessageCode(
39063927
"ImplementsFutureOr",
3907-
message: r"""'FutureOr' can't be used in an 'implements' clause.""");
3928+
message:
3929+
r"""The type 'FutureOr' can't be used in an 'implements' clause.""");
3930+
3931+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3932+
const Code<Null> codeImplementsNever = messageImplementsNever;
3933+
3934+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3935+
const MessageCode messageImplementsNever = const MessageCode("ImplementsNever",
3936+
message: r"""The type 'Never' can't be used in an 'implements' clause.""");
39083937

39093938
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
39103939
const Template<Message Function(String name, int count)>
@@ -3959,6 +3988,13 @@ Message _withArgumentsImplementsSuperClass(String name) {
39593988
arguments: {'name': name});
39603989
}
39613990

3991+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3992+
const Code<Null> codeImplementsVoid = messageImplementsVoid;
3993+
3994+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
3995+
const MessageCode messageImplementsVoid = const MessageCode("ImplementsVoid",
3996+
message: r"""The type 'void' can't be used in an 'implements' clause.""");
3997+
39623998
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
39633999
const Template<
39644000
Message Function(

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

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,13 @@ import '../fasta_codes.dart'
6363
show
6464
LocatedMessage,
6565
Message,
66+
messageExtendsFutureOr,
67+
messageExtendsNever,
68+
messageExtendsVoid,
6669
messageGenericFunctionTypeUsedAsActualTypeArgument,
6770
messageImplementsFutureOr,
71+
messageImplementsNever,
72+
messageImplementsVoid,
6873
messagePatchClassOrigin,
6974
messagePatchClassTypeVariablesMismatch,
7075
messagePatchDeclarationMismatch,
@@ -122,10 +127,14 @@ import 'library_builder.dart';
122127
import 'member_builder.dart';
123128
import 'metadata_builder.dart';
124129
import 'named_type_builder.dart';
130+
import 'never_type_builder.dart';
125131
import 'nullability_builder.dart';
126132
import 'procedure_builder.dart';
133+
import 'type_alias_builder.dart';
127134
import 'type_builder.dart';
135+
import 'type_declaration_builder.dart';
128136
import 'type_variable_builder.dart';
137+
import 'void_type_builder.dart';
129138

130139
abstract class ClassBuilder implements DeclarationBuilder {
131140
/// The type variables declared on a class, extension or mixin declaration.
@@ -635,17 +644,43 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
635644
// This method determines whether the class (that's being built) its super
636645
// class appears both in 'extends' and 'implements' clauses and whether any
637646
// interface appears multiple times in the 'implements' clause.
638-
if (interfaces == null) return;
647+
// Moreover, it checks that `FutureOr` and `void` are not among the
648+
// supertypes.
649+
650+
void fail(NamedTypeBuilder target, Message message) {
651+
int nameOffset = target.nameOffset;
652+
int nameLength = target.nameLength;
653+
// TODO(eernst): nameOffset not fully implemented; use backup.
654+
if (nameOffset == -1) {
655+
nameOffset = this.charOffset;
656+
nameLength = noLength;
657+
}
658+
addProblem(message, nameOffset, nameLength);
659+
}
639660

640-
// Extract super class (if it exists).
661+
// Extract and check superclass (if it exists).
641662
ClassBuilder superClass;
642663
TypeBuilder superClassType = supertype;
643664
if (superClassType is NamedTypeBuilder) {
644-
Builder decl = superClassType.declaration;
645-
if (decl is ClassBuilder) {
665+
TypeDeclarationBuilder decl = superClassType.declaration;
666+
if (decl is TypeAliasBuilder) {
667+
TypeAliasBuilder aliasBuilder = decl;
668+
decl = aliasBuilder.unaliasDeclaration;
669+
}
670+
// TODO(eernst): Should gather 'restricted supertype' checks in one place,
671+
// e.g., dynamic/int/String/Null and more are checked elsewhere.
672+
if (decl is VoidTypeBuilder) {
673+
fail(superClassType, messageExtendsVoid);
674+
} else if (decl is NeverTypeBuilder) {
675+
fail(superClassType, messageExtendsNever);
676+
} else if (decl is ClassBuilder) {
677+
if (decl.cls == coreTypes.futureOrClass) {
678+
fail(superClassType, messageExtendsFutureOr);
679+
}
646680
superClass = decl;
647681
}
648682
}
683+
if (interfaces == null) return;
649684

650685
// Validate interfaces.
651686
Map<ClassBuilder, int> problems;
@@ -654,29 +689,38 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
654689
for (TypeBuilder type in interfaces) {
655690
if (type is NamedTypeBuilder) {
656691
int charOffset = -1; // TODO(ahe): Get offset from type.
657-
Builder decl = type.declaration;
692+
TypeDeclarationBuilder typeDeclaration = type.declaration;
693+
TypeDeclarationBuilder decl = typeDeclaration is TypeAliasBuilder
694+
? typeDeclaration.unaliasDeclaration
695+
: typeDeclaration;
658696
if (decl is ClassBuilder) {
659697
ClassBuilder interface = decl;
660698
if (superClass == interface) {
661699
addProblem(
662700
templateImplementsSuperClass.withArguments(interface.name),
663-
charOffset,
701+
this.charOffset,
664702
noLength);
665703
} else if (implemented.contains(interface)) {
666704
// Aggregate repetitions.
667705
problems ??= new Map<ClassBuilder, int>();
668706
problems[interface] ??= 0;
669707
problems[interface] += 1;
670-
671708
problemsOffsets ??= new Map<ClassBuilder, int>();
672709
problemsOffsets[interface] ??= charOffset;
673710
} else if (interface.cls == coreTypes.futureOrClass) {
674-
addProblem(messageImplementsFutureOr, charOffset,
675-
interface.cls.name.length);
711+
fail(type, messageImplementsFutureOr);
676712
} else {
677713
implemented.add(interface);
678714
}
679715
}
716+
if (decl != superClass) {
717+
// TODO(eernst): Have all 'restricted supertype' checks in one place.
718+
if (decl is VoidTypeBuilder) {
719+
fail(type, messageImplementsVoid);
720+
} else if (decl is NeverTypeBuilder) {
721+
fail(type, messageImplementsNever);
722+
}
723+
}
680724
}
681725
}
682726
if (problems != null) {
@@ -1862,6 +1906,11 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
18621906
if (supertype is NamedTypeBuilder) {
18631907
Object builder = supertype.declaration;
18641908
if (builder is ClassBuilder) return builder;
1909+
if (builder is TypeAliasBuilder) {
1910+
TypeDeclarationBuilder declarationBuilder =
1911+
builder.unaliasDeclaration;
1912+
if (declarationBuilder is ClassBuilder) return declarationBuilder;
1913+
}
18651914
}
18661915
return null;
18671916
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'builder.dart';
1414
import 'class_builder.dart';
1515
import 'library_builder.dart';
1616
import 'prefix_builder.dart';
17+
import 'type_alias_builder.dart';
1718
import 'type_builder.dart';
1819

1920
class ConstructorReferenceBuilder {
@@ -46,6 +47,10 @@ class ConstructorReferenceBuilder {
4647
String prefix = name.qualifier;
4748
String middle = name.name;
4849
declaration = scope.lookup(prefix, charOffset, fileUri);
50+
if (declaration is TypeAliasBuilder) {
51+
TypeAliasBuilder aliasBuilder = declaration;
52+
declaration = aliasBuilder.unaliasDeclaration;
53+
}
4954
if (declaration is PrefixBuilder) {
5055
PrefixBuilder prefix = declaration;
5156
declaration = prefix.lookup(middle, name.charOffset, fileUri);

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import 'modifier_builder.dart';
3535
import 'name_iterator.dart';
3636
import 'nullability_builder.dart';
3737
import 'prefix_builder.dart';
38+
import 'type_alias_builder.dart';
3839
import 'type_builder.dart';
3940

4041
abstract class LibraryBuilder implements ModifierBuilder {
@@ -332,6 +333,10 @@ abstract class LibraryBuilderImpl extends ModifierBuilderImpl
332333
}
333334
Builder cls = (bypassLibraryPrivacy ? scope : exportScope)
334335
.lookup(className, -1, null);
336+
if (cls is TypeAliasBuilder) {
337+
TypeAliasBuilder aliasBuilder = cls;
338+
cls = aliasBuilder.unaliasDeclaration;
339+
}
335340
if (cls is ClassBuilder) {
336341
// TODO(ahe): This code is similar to code in `endNewExpression` in
337342
// `body_builder.dart`, try to share it.

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

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import 'invalid_type_declaration_builder.dart';
3737
import 'library_builder.dart';
3838
import 'nullability_builder.dart';
3939
import 'prefix_builder.dart';
40+
import 'type_alias_builder.dart';
4041
import 'type_builder.dart';
4142
import 'type_declaration_builder.dart';
4243
import 'type_variable_builder.dart';
@@ -63,6 +64,26 @@ class NamedTypeBuilder extends TypeBuilder {
6364
this.declaration = declaration?.origin;
6465
}
6566

67+
int get nameOffset {
68+
if (name is Identifier) {
69+
Identifier identifier = name;
70+
return identifier.charOffset;
71+
}
72+
return -1; // TODO(eernst): make it possible to get offset.
73+
}
74+
75+
int get nameLength {
76+
if (name is Identifier) {
77+
Identifier identifier = name;
78+
return identifier.name.length;
79+
} else if (name is String) {
80+
String nameString = name;
81+
return nameString.length;
82+
} else {
83+
return noLength;
84+
}
85+
}
86+
6687
@override
6788
void resolveIn(
6889
Scope scope, int charOffset, Uri fileUri, LibraryBuilder library) {
@@ -215,6 +236,12 @@ class NamedTypeBuilder extends TypeBuilder {
215236
TypeDeclarationBuilder declaration = this.declaration;
216237
if (declaration is ClassBuilder) {
217238
return declaration.buildSupertype(library, arguments);
239+
} else if (declaration is TypeAliasBuilder) {
240+
TypeDeclarationBuilder declarationBuilder =
241+
declaration.unaliasDeclaration;
242+
if (declarationBuilder is ClassBuilder) {
243+
return declarationBuilder.buildSupertype(library, arguments);
244+
}
218245
} else if (declaration is InvalidTypeDeclarationBuilder) {
219246
library.addProblem(
220247
declaration.message.messageObject,
@@ -223,14 +250,17 @@ class NamedTypeBuilder extends TypeBuilder {
223250
declaration.message.uri,
224251
severity: Severity.error);
225252
return null;
226-
} else {
227-
return handleInvalidSupertype(library, charOffset, fileUri);
228253
}
254+
return handleInvalidSupertype(library, charOffset, fileUri);
229255
}
230256

231257
Supertype buildMixedInType(
232258
LibraryBuilder library, int charOffset, Uri fileUri) {
233259
TypeDeclarationBuilder declaration = this.declaration;
260+
if (declaration is TypeAliasBuilder) {
261+
TypeAliasBuilder aliasBuilder = declaration;
262+
declaration = aliasBuilder.unaliasDeclaration;
263+
}
234264
if (declaration is ClassBuilder) {
235265
return declaration.buildMixedInType(library, arguments);
236266
} else if (declaration is InvalidTypeDeclarationBuilder) {

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import '../problems.dart' show unhandled;
2828

2929
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
3030

31+
import 'class_builder.dart';
3132
import 'formal_parameter_builder.dart';
3233
import 'function_type_builder.dart';
3334
import 'library_builder.dart';
@@ -218,20 +219,50 @@ class TypeAliasBuilder extends TypeDeclarationBuilderImpl {
218219
@override
219220
int get typeVariablesCount => typeVariables?.length ?? 0;
220221

222+
/// Returns `true` if this typedef is an alias of the `Null` type.
223+
bool get isNullAlias {
224+
TypeDeclarationBuilder typeDeclarationBuilder = type.declaration;
225+
return typeDeclarationBuilder is ClassBuilder &&
226+
typeDeclarationBuilder.isNullClass;
227+
}
228+
221229
@override
222230
DartType buildType(LibraryBuilder library,
223231
NullabilityBuilder nullabilityBuilder, List<TypeBuilder> arguments) {
224232
DartType thisType = buildThisType(library);
225233
if (thisType is InvalidType) return thisType;
226234
if (typedef.typeParameters.isEmpty && arguments == null) {
227-
return thisType.withNullability(nullabilityBuilder.build(library));
235+
Nullability nullability = isNullAlias
236+
? Nullability.nullable
237+
: nullabilityBuilder.build(library);
238+
return thisType.withNullability(nullability);
228239
}
229240
// Otherwise, substitute.
230241
return buildTypesWithBuiltArguments(
231242
library,
232243
nullabilityBuilder.build(library),
233244
buildTypeArguments(library, arguments));
234245
}
246+
247+
/// Returns the [TypeDeclarationBuilder] for the aliased type.
248+
///
249+
/// That is, it recursively looks up `type.declaration` and returns the first
250+
/// one which is not a `TypeAliasBuilder`, or the last one if none exist.
251+
TypeDeclarationBuilder get unaliasDeclaration {
252+
Set<TypeDeclarationBuilder> builders = {this};
253+
TypeDeclarationBuilder current = this;
254+
while (current is TypeAliasBuilder) {
255+
TypeAliasBuilder currentAliasBuilder = current;
256+
TypeDeclarationBuilder next = currentAliasBuilder.type?.declaration;
257+
if (next != null) {
258+
current = next;
259+
} else {
260+
return this;
261+
}
262+
if (builders.contains(current)) return this;
263+
}
264+
return current;
265+
}
235266
}
236267

237268
final InvalidType cyclicTypeAliasMarker = new InvalidType();

pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
library fasta.dill_typedef_builder;
66

7-
import 'package:kernel/ast.dart' show DartType, Typedef;
7+
import 'package:kernel/ast.dart' show DartType, Typedef, InterfaceType;
88

99
import '../builder/function_type_builder.dart';
1010
import '../builder/library_builder.dart';
@@ -62,4 +62,16 @@ class DillTypeAliasBuilder extends TypeAliasBuilder {
6262
}
6363
return result;
6464
}
65+
66+
@override
67+
bool get isNullAlias {
68+
DartType dartType = typedef.type;
69+
if (dartType is InterfaceType) {
70+
Uri importUri = dartType.classNode.enclosingLibrary.importUri;
71+
return dartType.classNode.name == "Null" &&
72+
importUri.scheme == "dart" &&
73+
importUri.path == "core";
74+
}
75+
return false;
76+
}
6577
}

0 commit comments

Comments
 (0)