Skip to content

Commit bd757f9

Browse files
Redo #28580: instantiate bounds to bounds.
One thing to be careful of here is that function type bounds may be left unbounded. However, their parameters and return type cannot refer to a type parameter for resolve-to-bounds to work. There are also a large number of ways that this can loop infinitely, and a number of new guards had to be added (as well as some test cases) to catch them all. Change-Id: I14322f5f71d1f7b73b27a870553e5c588b2c7e2e Reviewed-on: https://dart-review.googlesource.com/52062 Commit-Queue: Mike Fairhurst <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent 375b32d commit bd757f9

File tree

11 files changed

+383
-88
lines changed

11 files changed

+383
-88
lines changed

pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ class LibraryAnalyzer {
675675
// TODO(scheglov) remove EnumMemberBuilder class
676676

677677
new TypeParameterBoundsResolver(
678-
_typeProvider, _libraryElement, source, errorListener)
678+
_context.typeSystem, _libraryElement, source, errorListener)
679679
.resolveTypeBounds(unit);
680680

681681
unit.accept(new TypeResolverVisitor(

pkg/analyzer/lib/src/dart/element/type.dart

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import 'package:analyzer/src/generated/engine.dart'
1616
import 'package:analyzer/src/generated/type_system.dart';
1717
import 'package:analyzer/src/generated/utilities_collection.dart';
1818
import 'package:analyzer/src/generated/utilities_dart.dart';
19+
import 'package:analyzer/src/summary/resynthesize.dart'
20+
show RecursiveInstantiateToBounds;
1921

2022
/**
2123
* Type of callbacks used by [DeferredFunctionTypeImpl].
@@ -1691,7 +1693,11 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
16911693
@override
16921694
List<DartType> get typeArguments {
16931695
if (_typeArguments == null) {
1694-
_typeArguments = _typeArgumentsComputer();
1696+
try {
1697+
_typeArguments = _typeArgumentsComputer();
1698+
} on RecursiveInstantiateToBounds {
1699+
_hasTypeParameterReferenceInBound = true;
1700+
}
16951701
_typeArgumentsComputer = null;
16961702
}
16971703
return _typeArguments;
@@ -2596,6 +2602,11 @@ abstract class TypeImpl implements DartType {
25962602
*/
25972603
final String name;
25982604

2605+
/**
2606+
* The cached value for [hasTypeParameterReferenceInBound].
2607+
*/
2608+
bool _hasTypeParameterReferenceInBound;
2609+
25992610
/**
26002611
* Initialize a newly created type to be declared by the given [element] and
26012612
* to have the given [name].
@@ -2608,6 +2619,46 @@ abstract class TypeImpl implements DartType {
26082619
@override
26092620
Element get element => _element;
26102621

2622+
/**
2623+
* Return `true` if the type is parameterized and has a type parameter with
2624+
* the bound that references a type parameter.
2625+
*/
2626+
bool get hasTypeParameterReferenceInBound {
2627+
if (_hasTypeParameterReferenceInBound == null) {
2628+
bool hasTypeParameterReference(DartType type) {
2629+
if (type == this) {
2630+
// Cycle detection -- and cycles should be considered unboundable.
2631+
return true;
2632+
} else if (type is TypeImpl &&
2633+
type._hasTypeParameterReferenceInBound == true) {
2634+
return true;
2635+
} else if (type is TypeParameterType) {
2636+
return true;
2637+
} else if (type is FunctionType) {
2638+
return (type as TypeImpl).hasTypeParameterReferenceInBound;
2639+
} else if (type is ParameterizedType) {
2640+
return type.typeArguments.any(hasTypeParameterReference);
2641+
} else {
2642+
return false;
2643+
}
2644+
}
2645+
2646+
Element element = this.element;
2647+
if (element is FunctionTypedElement) {
2648+
_hasTypeParameterReferenceInBound = element.parameters.any(
2649+
(parameter) => hasTypeParameterReference(parameter.type)) ||
2650+
(element.returnType != null &&
2651+
hasTypeParameterReference(element.returnType));
2652+
} else if (element is TypeParameterizedElement) {
2653+
_hasTypeParameterReferenceInBound = element.typeParameters
2654+
.any((parameter) => hasTypeParameterReference(parameter.bound));
2655+
} else {
2656+
_hasTypeParameterReferenceInBound = false;
2657+
}
2658+
}
2659+
return _hasTypeParameterReferenceInBound;
2660+
}
2661+
26112662
@override
26122663
bool get isBottom => false;
26132664

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7277,19 +7277,10 @@ class _UninstantiatedBoundChecker extends RecursiveAstVisitor {
72777277
return;
72787278
}
72797279

7280-
var element = node.type.element;
7281-
if (element is TypeParameterizedElement &&
7282-
element.typeParameters.any((p) => p.bound != null)) {
7280+
final type = node.type;
7281+
if (type is TypeImpl && type.hasTypeParameterReferenceInBound) {
72837282
_errorReporter.reportErrorForNode(
7284-
StrongModeCode.NOT_INSTANTIATED_BOUND, node, [node.type]);
7285-
}
7286-
7287-
var enclosingElement = element?.enclosingElement;
7288-
if (element is GenericFunctionTypeElement &&
7289-
enclosingElement is GenericTypeAliasElement &&
7290-
enclosingElement.typeParameters.any((p) => p.bound != null)) {
7291-
_errorReporter.reportErrorForNode(
7292-
StrongModeCode.NOT_INSTANTIATED_BOUND, node, [node.type]);
7283+
StrongModeCode.NOT_INSTANTIATED_BOUND, node, [type]);
72937284
}
72947285
}
72957286
}

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8885,7 +8885,7 @@ class TypeOverrideManager_TypeOverrideScope {
88858885
* type aliases.
88868886
*/
88878887
class TypeParameterBoundsResolver {
8888-
final TypeProvider typeProvider;
8888+
final TypeSystem typeSystem;
88898889
final LibraryElement library;
88908890
final Source source;
88918891
final AnalysisErrorListener errorListener;
@@ -8894,7 +8894,7 @@ class TypeParameterBoundsResolver {
88948894
TypeNameResolver typeNameResolver = null;
88958895

88968896
TypeParameterBoundsResolver(
8897-
this.typeProvider, this.library, this.source, this.errorListener);
8897+
this.typeSystem, this.library, this.source, this.errorListener);
88988898

88998899
/**
89008900
* Resolve bounds of type parameters of classes, class and function type
@@ -8964,12 +8964,8 @@ class TypeParameterBoundsResolver {
89648964
} else {
89658965
libraryScope ??= new LibraryScope(library);
89668966
typeParametersScope ??= createTypeParametersScope();
8967-
typeNameResolver ??= new TypeNameResolver(
8968-
new TypeSystemImpl(typeProvider),
8969-
typeProvider,
8970-
library,
8971-
source,
8972-
errorListener);
8967+
typeNameResolver ??= new TypeNameResolver(typeSystem,
8968+
typeSystem.typeProvider, library, source, errorListener);
89738969
typeNameResolver.nameScope = typeParametersScope;
89748970
_resolveTypeName(bound);
89758971
typeParameterElement.bound = bound.type;

pkg/analyzer/lib/src/generated/type_system.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,15 @@ class StrongTypeSystemImpl extends TypeSystem {
358358
}
359359
}
360360

361-
List<TypeParameterType> getFreeParameters(DartType type) {
361+
List<TypeParameterType> getFreeParameters(DartType rootType) {
362362
List<TypeParameterType> parameters = null;
363+
Set<DartType> visitedTypes = new HashSet<DartType>();
363364

364365
void appendParameters(DartType type) {
366+
if (visitedTypes.contains(type)) {
367+
return;
368+
}
369+
visitedTypes.add(type);
365370
if (type is TypeParameterType && all.contains(type)) {
366371
parameters ??= <TypeParameterType>[];
367372
parameters.add(type);
@@ -370,7 +375,7 @@ class StrongTypeSystemImpl extends TypeSystem {
370375
}
371376
}
372377

373-
appendParameters(type);
378+
appendParameters(rootType);
374379
return parameters;
375380
}
376381

pkg/analyzer/lib/src/summary/resynthesize.dart

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,8 @@ class _LibraryResynthesizerContext extends LibraryResynthesizerContextMixin
858858
}
859859
}
860860

861+
class RecursiveInstantiateToBounds {}
862+
861863
/// Specialization of [ReferenceInfo] for resynthesis from linked summaries.
862864
class _ReferenceInfo extends ReferenceInfo {
863865
/**
@@ -983,14 +985,27 @@ class _ReferenceInfo extends ReferenceInfo {
983985
InterfaceTypeImpl type =
984986
new InterfaceTypeImpl.elementWithNameAndArgs(element, name, () {
985987
if (typeArguments == null) {
986-
if (libraryResynthesizer.summaryResynthesizer.strongMode &&
987-
instantiateToBoundsAllowed) {
988-
InterfaceType instantiatedToBounds = libraryResynthesizer
989-
.summaryResynthesizer.context.typeSystem
990-
.instantiateToBounds(element.type) as InterfaceType;
991-
return instantiatedToBounds.typeArguments;
988+
if (!_isBeingInstantiatedToBounds) {
989+
_isBeingInstantiatedToBounds = true;
990+
_isRecursiveWhileInstantiateToBounds = false;
991+
try {
992+
if (libraryResynthesizer.summaryResynthesizer.strongMode) {
993+
InterfaceType instantiatedToBounds = libraryResynthesizer
994+
.summaryResynthesizer.context.typeSystem
995+
.instantiateToBounds(element.type) as InterfaceType;
996+
if (_isRecursiveWhileInstantiateToBounds) {
997+
throw new RecursiveInstantiateToBounds();
998+
}
999+
return instantiatedToBounds.typeArguments;
1000+
} else {
1001+
return _dynamicTypeArguments;
1002+
}
1003+
} finally {
1004+
_isBeingInstantiatedToBounds = false;
1005+
}
9921006
} else {
993-
return _dynamicTypeArguments;
1007+
_isRecursiveWhileInstantiateToBounds = true;
1008+
typeArguments = _dynamicTypeArguments;
9941009
}
9951010
}
9961011
return typeArguments;
@@ -1352,6 +1367,7 @@ class _UnitResynthesizer extends UnitResynthesizer with UnitResynthesizerMixin {
13521367
if (declaredType && !referenceInfo.isDeclarableType) {
13531368
return DynamicTypeImpl.instance;
13541369
}
1370+
13551371
return referenceInfo.buildType(
13561372
instantiateToBoundsAllowed,
13571373
type.typeArguments.length,

pkg/analyzer/lib/src/task/dart.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4927,7 +4927,7 @@ class ResolveTopLevelUnitTypeBoundsTask extends SourceBasedAnalysisTask {
49274927
//
49284928
RecordingErrorListener errorListener = new RecordingErrorListener();
49294929
new TypeParameterBoundsResolver(
4930-
typeProvider, library, unitElement.source, errorListener)
4930+
context.typeSystem, library, unitElement.source, errorListener)
49314931
.resolveTypeBounds(unit);
49324932
//
49334933
// Record outputs.

pkg/analyzer/test/generated/strong_mode_driver_test.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ class StrongModeStaticTypeAnalyzer2Test_Driver
6565
test_genericMethod_functionTypedParameter_tearoff() {
6666
return super.test_genericMethod_functionTypedParameter_tearoff();
6767
}
68+
69+
@override
70+
test_notInstantiatedBound_class_error_recursion() {
71+
// overridden because not failing
72+
return super.test_notInstantiatedBound_class_error_recursion();
73+
}
74+
75+
@override
76+
test_notInstantiatedBound_class_error_recursion_less_direct() {
77+
// overridden because not failing
78+
return super.test_notInstantiatedBound_class_error_recursion_less_direct();
79+
}
6880
}
6981

7082
@reflectiveTest

0 commit comments

Comments
 (0)