Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1151)

Unified Diff: pkg/analyzer/lib/src/dart/element/type.dart

Issue 1678313002: fix part of #25200, reject non-generic function subtype of generic function (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/src/dart/element/type.dart
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 1b9c290665b16c8ee63d14e80b244efee4f6cf64..076d551523c04d785402ed714f1f36d32d4c88ab 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -534,28 +534,7 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
// To test this, we instantiate both types with the same (unique) type
// variables, and see if the result is equal.
if (typeFormals.isNotEmpty) {
- List<DartType> instantiateTypeArgs = new List<DartType>();
- List<DartType> variablesThis = new List<DartType>();
- List<DartType> variablesOther = new List<DartType>();
- for (int i = 0; i < typeFormals.length; i++) {
- TypeParameterElement pThis = typeFormals[i];
- TypeParameterElement pOther = otherType.typeFormals[i];
- TypeParameterTypeImpl pFresh = new TypeParameterTypeImpl(
- new TypeParameterElementImpl(pThis.name, -1));
- instantiateTypeArgs.add(pFresh);
- variablesThis.add(pThis.type);
- variablesOther.add(pOther.type);
- // Check that the bounds are equal after equating the previous
- // bound variables.
- if (pThis.bound?.substitute2(instantiateTypeArgs, variablesThis) !=
- pOther.bound?.substitute2(instantiateTypeArgs, variablesOther)) {
- return false;
- }
- }
- // After instantiation, they will no longer have typeFormals,
- // so we will continue below.
- return this.instantiate(instantiateTypeArgs) ==
- otherType.instantiate(instantiateTypeArgs);
+ return structuralCompareGeneric(this, otherType, (t, s) => t == s);
}
return returnType == otherType.returnType &&
@@ -722,8 +701,11 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
return relation;
}
Leaf 2016/02/09 21:29:25 Why does this ignore the generic case? If just no
Jennifer Messerly 2016/02/10 22:42:07 Good catch. Fixed!
- return structuralCompare(this, type,
- (TypeImpl t, TypeImpl s) => t.isMoreSpecificThan(s, withDynamic));
+ return structuralCompare(
+ this,
+ type,
+ (DartType t, DartType s) =>
Leaf 2016/02/09 21:29:25 Non-actionable comment, but the TypeImpl/Type dist
Jennifer Messerly 2016/02/10 22:42:07 Yeah, definitely. I'm trying to get things strong
+ (t as TypeImpl).isMoreSpecificThan(s, withDynamic));
}
@override
@@ -732,9 +714,78 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
if (relation != null) {
return relation;
}
+ // This type cast is safe, because _trivialFunctionRelation checks for it.
Leaf 2016/02/09 21:29:25 It feels like this code could become part of struc
Jennifer Messerly 2016/02/10 22:42:07 Great idea. Done.
+ FunctionType f2 = type as FunctionType;
+ if (typeFormals.isNotEmpty) {
+ if (f2.typeFormals.isEmpty) {
+ List<DartType> dynamicTypeArgs = new List<DartType>.filled(
Leaf 2016/02/09 21:29:25 Would be nice to use instantiateToBounds here, but
Jennifer Messerly 2016/02/10 22:42:07 Added instantiateToBounds parameter. I do wonder
+ typeFormals.length, DynamicTypeImpl.instance);
+ return instantiate(dynamicTypeArgs).isSubtypeOf(f2);
+ } else {
+ return structuralCompareGeneric(
+ this, f2, (DartType t, DartType s) => t.isSubtypeOf(s));
+ }
+ } else if (f2.typeFormals.isNotEmpty) {
+ return false;
+ }
return structuralCompare(
Leaf 2016/02/09 21:29:25 See comment below on the structuralCompare/structu
Jennifer Messerly 2016/02/10 22:42:07 Fixed :)
- this, type, (TypeImpl t, TypeImpl s) => t.isAssignableTo(s));
+ this, f2, (DartType t, DartType s) => t.isAssignableTo(s));
+ }
+
+ /**
+ * Check a [functionRelation] (typically isSubtypeOf) between [f1] and [f2]
+ * where f1 and f2 are known to be generic function types (both have type
+ * formals).
+ *
Bob Nystrom 2016/02/09 01:25:18 Writing nit: It's easy to get into the habit of fu
Jennifer Messerly 2016/02/10 22:42:07 Acknowledged.
+ * This will first check that f1 and f2 have the same number of type formals.
+ * It will also check that their bounds (`<T extends LowerBound>`) are
+ * compatible using [relation]. If the formals are not compatible, this will
+ * return `false`.
+ *
+ * If [functionRelation] is omitted, this will use [relation] for both.
+ */
+ static bool structuralCompareGeneric(
Leaf 2016/02/09 21:29:25 I'm not very keen on the current factoring of this
Jennifer Messerly 2016/02/10 22:42:07 All factoring is fixed :D. At least as much as pos
+ FunctionType f1, FunctionType f2, bool relation(DartType t, DartType s),
+ [bool functionRelation(FunctionType t, FunctionType s)]) {
+ functionRelation ??= relation;
+
+ List<TypeParameterElement> params1 = f1.typeFormals;
+ List<TypeParameterElement> params2 = f2.typeFormals;
+ int count = params1.length;
+ if (params2.length != count) {
+ return false;
+ }
+ // We build up a substitution matching up the type parameters
+ // from the two types, {variablesFresh/variables1} and
+ // {variablesFresh/variables2}
+ List<DartType> variables1 = new List<DartType>();
+ List<DartType> variables2 = new List<DartType>();
+ List<DartType> variablesFresh = new List<DartType>();
Bob Nystrom 2016/02/09 01:25:18 <DartType>[]
Jennifer Messerly 2016/02/10 22:42:07 Done.
+ for (int i = 0; i < count; i++) {
+ TypeParameterElement p1 = params1[i];
+ TypeParameterElement p2 = params2[i];
+ TypeParameterElementImpl pFresh =
+ new TypeParameterElementImpl(p2.name, -1);
Bob Nystrom 2016/02/09 01:25:18 What do you think about either making the offset o
Jennifer Messerly 2016/02/10 22:42:07 Done.
+
+ DartType variable1 = p1.type;
+ DartType variable2 = p2.type;
+ DartType variableFresh = new TypeParameterTypeImpl(pFresh);
+
+ variables1.add(variable1);
+ variables2.add(variable2);
+ variablesFresh.add(variableFresh);
+ DartType bound1 = p1.bound ?? DynamicTypeImpl.instance;
+ DartType bound2 = p2.bound ?? DynamicTypeImpl.instance;
+ bound1 = bound1.substitute2(variablesFresh, variables1);
+ bound2 = bound2.substitute2(variablesFresh, variables2);
+ pFresh.bound = bound2;
+ if (!relation(bound2, bound1)) {
+ return false;
+ }
+ }
+ return functionRelation(
+ f1.instantiate(variablesFresh), f2.instantiate(variablesFresh));
}
/**
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/generated/resolver.dart » ('j') | pkg/analyzer/lib/src/generated/resolver.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698