Skip to content

Test records support in typedefs #3239

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions lib/src/element_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,13 @@ abstract class ElementType extends Privacy
var isGenericTypeAlias = f.alias?.element != null && f is! InterfaceType;
if (f is FunctionType) {
assert(f is ParameterizedType);
// This is an indication we have an extremely out of date analyzer.
assert(!isGenericTypeAlias, 'should never occur: out of date analyzer?');
// And finally, delete this case and its associated class
// after https://dart-review.googlesource.com/c/sdk/+/201520
// is in all published versions of analyzer this version of dartdoc
// is compatible with.
return CallableElementType(f, library, packageGraph, element);
} else if (isGenericTypeAlias) {
}
if (isGenericTypeAlias) {
return GenericTypeAliasElementType(
f as TypeParameterType, library, packageGraph, element);
}
Expand Down Expand Up @@ -315,8 +314,7 @@ abstract class DefinedElementType extends ElementType {
final bound = _bound;
if (bound is InterfaceType &&
!bound.typeArguments.every((t) => t is InterfaceType)) {
var typeSystem = library.element.typeSystem;
return typeSystem.instantiateInterfaceToBounds(
return library.typeSystem.instantiateInterfaceToBounds(
element: bound.element, nullabilitySuffix: _bound.nullabilitySuffix);
} else {
return _bound;
Expand Down
14 changes: 7 additions & 7 deletions lib/src/model/inheriting_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -302,14 +302,14 @@ abstract class InheritingContainer extends Container
var parent = supertype;
while (parent != null) {
typeChain.add(parent);
if (parent.type is InterfaceType) {
// Avoid adding [Object] to the superChain (_supertype already has this
// check)
if ((parent.type as InterfaceType).superclass?.superclass == null) {
parent = null;
final parentType = parent.type;
if (parentType is InterfaceType) {
// Avoid adding [Object] to the [superChain] ([_supertype] already has
// this check).
if (parentType.superclass?.superclass == null) {
break;
} else {
parent = modelBuilder.typeFrom(
(parent.type as InterfaceType).superclass!, library)
parent = modelBuilder.typeFrom(parentType.superclass!, library)
as DefinedElementType?;
}
} else {
Expand Down
3 changes: 2 additions & 1 deletion lib/src/type_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ extension DartTypeExtension on DartType {
} else if (self is TypeParameterType) {
return self.element;
} else {
// Remaining cases like `DynamicType`, `FunctionType`, and `VoidType`.
// Remaining cases like `DynamicType`, `FunctionType`, `RecordType`, and
// `VoidType`.
return null;
}
}
Expand Down
136 changes: 129 additions & 7 deletions test/typedef_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'src/test_descriptor_utils.dart' as d;
import 'src/utils.dart';

void main() {
group('typedefs', () {
group('typedefs of function types', () {
late Library library;

// It is expensive (~10s) to compute a package graph, even skipping
Expand All @@ -33,6 +33,7 @@ typedef Cb1 = void Function();

typedef Cb2<T> = T Function(T);

/// Not unlike [Cb2].
typedef Cb3<T> = Cb2<List<T>>;
'''),
],
Expand All @@ -52,12 +53,12 @@ typedef Cb3<T> = Cb2<List<T>>;
library = packageGraph.libraries.named(libraryName);
});

test('basic typedef', () async {
test('basic function typedef', () async {
final cb1Typedef = library.typedefs.named('Cb1');

expect(cb1Typedef.nameWithGenerics, 'Cb1');
expect(cb1Typedef.genericParameters, '');
expect(cb1Typedef.aliasedType is FunctionType, isTrue);
expect(cb1Typedef.aliasedType, isA<FunctionType>());
expect(cb1Typedef.documentationComment, '''
/// Line _one_.
///
Expand All @@ -72,7 +73,7 @@ Line _two_.''');
<p>Line <em>two</em>.</p>''');
});

test('generic typedef', () async {
test('generic function typedef', () async {
final cb2Typedef = library.typedefs.named('Cb2');

expect(
Expand All @@ -83,10 +84,10 @@ Line _two_.''');
cb2Typedef.genericParameters,
'&lt;<wbr><span class="type-parameter">T</span>&gt;',
);
expect(cb2Typedef.aliasedType is FunctionType, isTrue);
expect(cb2Typedef.aliasedType, isA<FunctionType>());
});

test('generic typedef referring to a generic typedef', () async {
test('generic function typedef referring to a generic typedef', () async {
final cb3Typedef = library.typedefs.named('Cb3');

expect(
Expand All @@ -97,11 +98,132 @@ Line _two_.''');
cb3Typedef.genericParameters,
'&lt;<wbr><span class="type-parameter">T</span>&gt;',
);
expect(cb3Typedef.aliasedType is FunctionType, isTrue);
expect(cb3Typedef.aliasedType, isA<FunctionType>());

expect(cb3Typedef.parameters, hasLength(1));

// TODO(srawlins): Dramatically improve typedef testing.
});

test('typedef in a doc comment reference', () {
final cb3Typedef = library.typedefs.named('Cb3');

expect(cb3Typedef.isDocumented, isTrue);

expect(cb3Typedef.documentation, 'Not unlike [Cb2].');

expect(
cb3Typedef.documentationAsHtml,
'<p>Not unlike '
'<a href="%%__HTMLBASE_dartdoc_internal__%%typedefs/Cb2.html">Cb2</a>.'
'</p>',
);
});
});

group('typedefs of record types', skip: !recordsAllowed, () {
late Library library;

// It is expensive (~10s) to compute a package graph, even skipping
// unreachable Dart SDK libraries, so we set up this package once.
setUpAll(() async {
const libraryName = 'typedefs';
final packageMetaProvider = testPackageMetaProvider;

final packagePath = await d.createPackage(
libraryName,
libFiles: [
d.file('lib.dart', '''
library $libraryName;

/// Line _one_.
///
/// Line _two_.
typedef R1 = (int, String);

typedef R2<T> = (T, String);

/// Not unlike [R2].
typedef R3<T> = R2<List<T>>;
'''),
],
resourceProvider:
packageMetaProvider.resourceProvider as MemoryResourceProvider,
);
final packageConfigProvider =
getTestPackageConfigProvider(packageMetaProvider.defaultSdkDir.path);
packageConfigProvider.addPackageToConfigFor(
packagePath, libraryName, Uri.file('$packagePath/'));

final packageGraph = await bootBasicPackage(
packagePath,
packageMetaProvider,
packageConfigProvider,
);
library = packageGraph.libraries.named(libraryName);
});

test('basic record typedef', () async {
final r1Typedef = library.typedefs.named('R1');

expect(r1Typedef.nameWithGenerics, 'R1');
expect(r1Typedef.genericParameters, '');
expect(r1Typedef.aliasedType, isA<RecordType>());
expect(r1Typedef.documentationComment, '''
/// Line _one_.
///
/// Line _two_.''');
expect(r1Typedef.documentation, '''
Line _one_.

Line _two_.''');
expect(r1Typedef.oneLineDoc, 'Line <em>one</em>.');
expect(r1Typedef.documentationAsHtml, '''
<p>Line <em>one</em>.</p>
<p>Line <em>two</em>.</p>''');
});

test('generic record typedef', () async {
final r2Typedef = library.typedefs.named('R2');

expect(
r2Typedef.nameWithGenerics,
'R2&lt;<wbr><span class="type-parameter">T</span>&gt;',
);
expect(
r2Typedef.genericParameters,
'&lt;<wbr><span class="type-parameter">T</span>&gt;',
);
expect(r2Typedef.aliasedType, isA<RecordType>());
});

test('generic record typedef referring to a generic typedef', () async {
final r3Typedef = library.typedefs.named('R3');

expect(
r3Typedef.nameWithGenerics,
'R3&lt;<wbr><span class="type-parameter">T</span>&gt;',
);
expect(
r3Typedef.genericParameters,
'&lt;<wbr><span class="type-parameter">T</span>&gt;',
);
expect(r3Typedef.aliasedType, isA<RecordType>());
});

test('typedef in a doc comment reference', () {
final r3Typedef = library.typedefs.named('R3');

expect(r3Typedef.isDocumented, isTrue);

expect(r3Typedef.documentation, 'Not unlike [R2].');

expect(
r3Typedef.documentationAsHtml,
'<p>Not unlike '
'<a href="%%__HTMLBASE_dartdoc_internal__%%typedefs/R2.html">R2</a>.'
'</p>',
);
});
});
}
2 changes: 1 addition & 1 deletion tool/mustachio/codegen_runtime_renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ import '${p.basename(_sourceUri.path)}';
return _relevantTypeFrom(bound);
}
} else {
// We can do nothing with function types, etc.
// We can do nothing with function types, record types, etc.
return null;
}
}
Expand Down