Skip to content

Commit 7807ee1

Browse files
authored
Allow FunctionTypes to work in place of InterfaceType in applicability check (#2109)
* Fix FunctionTypeImpl crash * Add bug number to comment * Remove unnecessary comment * Add TODO for bad cast
1 parent 285b4df commit 7807ee1

File tree

6 files changed

+71
-28
lines changed

6 files changed

+71
-28
lines changed

lib/src/element_type.dart

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,11 @@ class TypeParameterElementType extends DefinedElementType {
205205
String get nameWithGenerics => name;
206206

207207
@override
208-
ClassElement get _boundClassElement => interfaceType.element;
208+
ClassElement get _boundClassElement => type.element;
209209

210210
@override
211-
InterfaceType get interfaceType => (type as TypeParameterType).bound;
211+
// TODO(jcollins-g): This is wrong; bound is not always an InterfaceType.
212+
InterfaceType get _interfaceType => (type as TypeParameterType).bound;
212213
}
213214

214215
/// An [ElementType] associated with an [Element].
@@ -271,18 +272,19 @@ abstract class DefinedElementType extends ElementType {
271272
ClassElement get _boundClassElement => (element.element as ClassElement);
272273
Class get boundClass =>
273274
ModelElement.fromElement(_boundClassElement, packageGraph);
274-
InterfaceType get interfaceType => type;
275+
276+
InterfaceType get _interfaceType => type;
275277

276278
InterfaceType _instantiatedType;
277279

278280
/// Return this type, instantiated to bounds if it isn't already.
279281
DartType get instantiatedType {
280282
if (_instantiatedType == null) {
281-
if (!interfaceType.typeArguments.every((t) => t is InterfaceType)) {
283+
if (!_interfaceType.typeArguments.every((t) => t is InterfaceType)) {
282284
var typeSystem = library.element.typeSystem as TypeSystemImpl;
283-
_instantiatedType = typeSystem.instantiateToBounds(interfaceType);
285+
_instantiatedType = typeSystem.instantiateToBounds(_interfaceType);
284286
} else {
285-
_instantiatedType = interfaceType;
287+
_instantiatedType = _interfaceType;
286288
}
287289
}
288290
return _instantiatedType;
@@ -413,4 +415,7 @@ class CallableGenericTypeAliasElementType extends ParameterizedElementType
413415
}
414416
return _returnType;
415417
}
418+
419+
@override
420+
DartType get instantiatedType => type;
416421
}

lib/src/model/class.dart

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
import 'package:analyzer/dart/element/element.dart';
66
import 'package:analyzer/dart/element/type.dart';
77
import 'package:dartdoc/src/element_type.dart';
8+
import 'package:dartdoc/src/model/extension_target.dart';
89
import 'package:dartdoc/src/model/model.dart';
910
import 'package:dartdoc/src/model_utils.dart' as model_utils;
1011
import 'package:quiver/iterables.dart' as quiver;
1112

1213
class Class extends Container
13-
with TypeParameters, Categorization
14+
with TypeParameters, Categorization, ExtensionTarget
1415
implements EnclosedElement {
1516
List<DefinedElementType> mixins;
1617
DefinedElementType supertype;
@@ -51,22 +52,6 @@ class Class extends Container
5152
return _defaultConstructor;
5253
}
5354

54-
bool get hasPotentiallyApplicableExtensions =>
55-
potentiallyApplicableExtensions.isNotEmpty;
56-
57-
List<Extension> _potentiallyApplicableExtensions;
58-
59-
Iterable<Extension> get potentiallyApplicableExtensions {
60-
if (_potentiallyApplicableExtensions == null) {
61-
_potentiallyApplicableExtensions = model_utils
62-
.filterNonDocumented(packageGraph.extensions)
63-
.where((e) => e.couldApplyTo(this))
64-
.toList(growable: false)
65-
..sort(byName);
66-
}
67-
return _potentiallyApplicableExtensions;
68-
}
69-
7055
Iterable<Method> get allInstanceMethods =>
7156
quiver.concat([instanceMethods, inheritedMethods]);
7257

@@ -223,6 +208,7 @@ class Class extends Container
223208

224209
bool get hasPublicMixins => publicMixins.isNotEmpty;
225210

211+
@override
226212
bool get hasModifiers =>
227213
hasPublicMixins ||
228214
hasAnnotations ||

lib/src/model/extension.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:analyzer/dart/element/element.dart';
88
import 'package:analyzer/dart/element/type.dart';
99
import 'package:analyzer/src/dart/element/element.dart';
1010
import 'package:dartdoc/src/element_type.dart';
11+
import 'package:dartdoc/src/model/extension_target.dart';
1112
import 'package:dartdoc/src/model/model.dart';
1213
import 'package:quiver/iterables.dart' as quiver;
1314

@@ -24,7 +25,8 @@ class Extension extends Container
2425
ElementType.from(_extension.extendedType, library, packageGraph);
2526
}
2627

27-
bool couldApplyTo(Class c) => _couldApplyTo(c.modelType);
28+
bool couldApplyTo<T extends ExtensionTarget>(T c) =>
29+
_couldApplyTo(c.modelType);
2830

2931
/// Return true if this extension could apply to [t].
3032
bool _couldApplyTo(DefinedElementType t) {
@@ -40,13 +42,14 @@ class Extension extends Container
4042
.isSubtypeOf(extendedType.instantiatedType, t.instantiatedType);
4143

4244
bool isBoundSupertypeTo(DefinedElementType t) =>
43-
_isBoundSupertypeTo(t.type, HashSet());
45+
_isBoundSupertypeTo(t.instantiatedType, HashSet());
4446

4547
/// Returns true if at least one supertype (including via mixins and
4648
/// interfaces) is equivalent to or a subtype of [extendedType] when
4749
/// instantiated to bounds.
48-
bool _isBoundSupertypeTo(
49-
InterfaceType superType, HashSet<InterfaceType> visited) {
50+
bool _isBoundSupertypeTo(DartType superType, HashSet<DartType> visited) {
51+
// Only InterfaceTypes can have superTypes.
52+
if (superType is! InterfaceType) return false;
5053
ClassElement superClass = superType?.element;
5154
if (visited.contains(superType)) return false;
5255
visited.add(superType);

lib/src/model/extension_target.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) 2020, 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:dartdoc/src/model/model.dart';
6+
7+
// TODO(jcollins-g): Mix-in ExtensionTarget on Method, ModelFunction, Typedef,
8+
// and other possible documented symbols that could be extended (#2701).
9+
mixin ExtensionTarget on ModelElement {
10+
bool get hasModifiers;
11+
12+
bool get hasPotentiallyApplicableExtensions =>
13+
potentiallyApplicableExtensions.isNotEmpty;
14+
15+
List<Extension> _potentiallyApplicableExtensions;
16+
17+
Iterable<Extension> get potentiallyApplicableExtensions {
18+
if (_potentiallyApplicableExtensions == null) {
19+
_potentiallyApplicableExtensions = packageGraph.documentedExtensions
20+
.where((e) => e.couldApplyTo(this))
21+
.toList(growable: false)
22+
..sort(byName);
23+
}
24+
return _potentiallyApplicableExtensions;
25+
}
26+
}

lib/src/model/package_graph.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,21 @@ class PackageGraph {
152152
return _implementors;
153153
}
154154

155+
List<Extension> _documentedExtensions;
156+
Iterable<Extension> get documentedExtensions {
157+
if (_documentedExtensions == null) {
158+
_documentedExtensions =
159+
utils.filterNonDocumented(extensions).toList(growable: false);
160+
}
161+
return _documentedExtensions;
162+
}
163+
155164
Iterable<Extension> get extensions {
156165
assert(allExtensionsAdded);
157166
return _extensions;
158167
}
159168

160169
Map<String, Set<ModelElement>> _findRefElementCache;
161-
162170
Map<String, Set<ModelElement>> get findRefElementCache {
163171
if (_findRefElementCache == null) {
164172
assert(packageGraph.allLibrariesAdded);

testing/test_package/lib/fake.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,3 +1117,18 @@ abstract class CanonicalPrivateInheritedToolUser
11171117
print('hello, tool world');
11181118
}
11191119
}
1120+
1121+
/*
1122+
* Complex extension methods case.
1123+
*
1124+
* TODO(jcollins-g): add unit tests around behavior when #2701 is implemented.
1125+
* Until #2701 is fixed we mostly are testing that we don't crash because
1126+
* DoSomething2X is declared.
1127+
*/
1128+
1129+
typedef R Function1<A, R>(A a);
1130+
typedef R Function2<A, B, R>(A a, B b);
1131+
1132+
extension DoSomething2X<A, B, R> on Function1<A, Function1<B, R>> {
1133+
Function2<A, B, R> something() => (A first, B second) => this(first)(second);
1134+
}

0 commit comments

Comments
 (0)