| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 library kernel.type_algebra; | 4 library kernel.type_algebra; |
| 5 | 5 |
| 6 import 'ast.dart'; | 6 import 'ast.dart'; |
| 7 import 'type_algebra.dart' as toplevel; | |
| 8 | 7 |
| 9 /// Returns a type where all occurrences of the given type parameters have been | 8 /// Returns a type where all occurrences of the given type parameters have been |
| 10 /// replaced with the corresponding types. | 9 /// replaced with the corresponding types. |
| 11 /// | 10 /// |
| 12 /// This will copy only the subterms of [type] that contain substituted | 11 /// This will copy only the subterms of [type] that contain substituted |
| 13 /// variables; all other [DartType] objects will be reused. | 12 /// variables; all other [DartType] objects will be reused. |
| 14 /// | 13 /// |
| 15 /// In particular, if no variables were substituted, this is guaranteed to | 14 /// In particular, if no variables were substituted, this is guaranteed to |
| 16 /// return the [type] instance (not a copy), so the caller may use [identical] | 15 /// return the [type] instance (not a copy), so the caller may use [identical] |
| 17 /// to efficiently check if a distinct type was created. | 16 /// to efficiently check if a distinct type was created. |
| 18 DartType substitute(DartType type, Map<TypeParameter, DartType> substitution) { | 17 DartType substitute(DartType type, Map<TypeParameter, DartType> substitution) { |
| 19 if (substitution.isEmpty) return type; | 18 if (substitution.isEmpty) return type; |
| 20 return new _TypeSubstitutor(substitution, substitution).visit(type); | 19 return Substitution.fromMap(substitution).substituteType(type); |
| 21 } | 20 } |
| 22 | 21 |
| 23 /// Returns a mapping from the type parameters declared on the class of [type] | 22 /// Returns a mapping from the type parameters declared on the class of [type] |
| 24 /// to the actual type arguments provided in [type]. | 23 /// to the actual type arguments provided in [type]. |
| 25 /// | 24 /// |
| 26 /// This can be passed as argument to [substitute]. | 25 /// This can be passed as argument to [substitute]. |
| 27 Map<TypeParameter, DartType> getSubstitutionMap(InterfaceType type) { | 26 Map<TypeParameter, DartType> getSubstitutionMap(Supertype type) { |
| 28 return type.typeArguments.isEmpty | 27 return type.typeArguments.isEmpty |
| 29 ? const <TypeParameter, DartType>{} | 28 ? const <TypeParameter, DartType>{} |
| 30 : new Map<TypeParameter, DartType>.fromIterables( | 29 : new Map<TypeParameter, DartType>.fromIterables( |
| 31 type.classNode.typeParameters, type.typeArguments); | 30 type.classNode.typeParameters, type.typeArguments); |
| 32 } | 31 } |
| 33 | 32 |
| 34 /// Like [substitute], but the substitution map is given as a list of keys | |
| 35 /// and a list of values. | |
| 36 DartType substitutePairwise(DartType type, List<TypeParameter> typeParameters, | |
| 37 List<DartType> typeArguments) { | |
| 38 if (typeParameters.isEmpty) return type; | |
| 39 // TODO: Investigate if it is more efficient to implement substitution based | |
| 40 // on parallel pairwise lists instead of Maps. | |
| 41 return substitute( | |
| 42 type, | |
| 43 new Map<TypeParameter, DartType>.fromIterables( | |
| 44 typeParameters, typeArguments)); | |
| 45 } | |
| 46 | |
| 47 /// Returns [type] where the type parameters declared on the class of [thisType] | |
| 48 /// have been substituted with the type arguments provided in [thisType]. | |
| 49 /// | |
| 50 /// For example, if [thisType] is `Iterable<String>`, this will substitute | |
| 51 /// `Iterable::E` with `String` in [type]. | |
| 52 /// | |
| 53 /// If `thisType` is null, nothing is substituted. | |
| 54 DartType substituteThisType(DartType type, InterfaceType thisType) { | |
| 55 if (thisType == null) return type; | |
| 56 return substitutePairwise( | |
| 57 type, thisType.classNode.typeParameters, thisType.typeArguments); | |
| 58 } | |
| 59 | |
| 60 /// Returns a type where all occurrences of the given type parameters have been | |
| 61 /// replaced with the corresponding upper or lower bound, depending on the | |
| 62 /// variance of the context where it occurs. | |
| 63 /// | |
| 64 /// For example the type `(T) => T` with the bounds `bottom <: T <: num` | |
| 65 /// becomes `(bottom) => num` (in this example, `num` is the upper bound, | |
| 66 /// and `bottom` is the lower bound). | |
| 67 /// | |
| 68 /// This is a way to obtain an upper bound for a type while eliminating all | |
| 69 /// references to certain type variables. | |
| 70 /// | |
| 71 /// This will copy only the subterms of [type] that contain substituted | |
| 72 /// variables; all other [DartType] objects will be reused. | |
| 73 /// | |
| 74 /// In particular, if no variables were substituted, this is guaranteed to | |
| 75 /// return the [type] instance (not a copy), so the caller may use [identical] | |
| 76 /// to efficiently check if a distinct type was created. | |
| 77 DartType substituteBounds( | |
| 78 DartType type, | |
| 79 Map<TypeParameter, DartType> upperBounds, | |
| 80 Map<TypeParameter, DartType> lowerBounds) { | |
| 81 assert(upperBounds.length == lowerBounds.length); | |
| 82 if (upperBounds.isEmpty) return type; | |
| 83 return new _TypeSubstitutor(upperBounds, lowerBounds).visit(type); | |
| 84 } | |
| 85 | |
| 86 /// Like [substitute], except when a type in the [substitution] map references | 33 /// Like [substitute], except when a type in the [substitution] map references |
| 87 /// another substituted type variable, the mapping for that type is recursively | 34 /// another substituted type variable, the mapping for that type is recursively |
| 88 /// inserted. | 35 /// inserted. |
| 89 /// | 36 /// |
| 90 /// For example `Set<G>` substituted with `{T -> String, G -> List<T>}` results | 37 /// For example `Set<G>` substituted with `{T -> String, G -> List<T>}` results |
| 91 /// in `Set<List<String>>`. | 38 /// in `Set<List<String>>`. |
| 92 /// | 39 /// |
| 93 /// Returns `null` if the substitution map contains a cycle reachable from a | 40 /// Returns `null` if the substitution map contains a cycle reachable from a |
| 94 /// type variable in [type] (the resulting type would be infinite). | 41 /// type variable in [type] (the resulting type would be infinite). |
| 95 /// | 42 /// |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 | 86 |
| 140 /// Generates a fresh copy of the given type parameters, with their bounds | 87 /// Generates a fresh copy of the given type parameters, with their bounds |
| 141 /// substituted to reference the new parameters. | 88 /// substituted to reference the new parameters. |
| 142 /// | 89 /// |
| 143 /// The returned object contains the fresh type parameter list as well as a | 90 /// The returned object contains the fresh type parameter list as well as a |
| 144 /// mapping to be used for replacing other types to use the new type parameters. | 91 /// mapping to be used for replacing other types to use the new type parameters. |
| 145 FreshTypeParameters getFreshTypeParameters(List<TypeParameter> typeParameters) { | 92 FreshTypeParameters getFreshTypeParameters(List<TypeParameter> typeParameters) { |
| 146 var freshParameters = new List<TypeParameter>.generate( | 93 var freshParameters = new List<TypeParameter>.generate( |
| 147 typeParameters.length, (i) => new TypeParameter(typeParameters[i].name), | 94 typeParameters.length, (i) => new TypeParameter(typeParameters[i].name), |
| 148 growable: true); | 95 growable: true); |
| 149 var substitution = <TypeParameter, DartType>{}; | 96 var map = <TypeParameter, DartType>{}; |
| 150 for (int i = 0; i < typeParameters.length; ++i) { | 97 for (int i = 0; i < typeParameters.length; ++i) { |
| 151 substitution[typeParameters[i]] = new TypeParameterType(freshParameters[i]); | 98 map[typeParameters[i]] = new TypeParameterType(freshParameters[i]); |
| 152 freshParameters[i].bound = | 99 freshParameters[i].bound = substitute(typeParameters[i].bound, map); |
| 153 substitute(typeParameters[i].bound, substitution); | |
| 154 } | 100 } |
| 155 return new FreshTypeParameters(freshParameters, substitution); | 101 return new FreshTypeParameters(freshParameters, Substitution.fromMap(map)); |
| 156 } | 102 } |
| 157 | 103 |
| 158 class FreshTypeParameters { | 104 class FreshTypeParameters { |
| 159 final List<TypeParameter> freshTypeParameters; | 105 final List<TypeParameter> freshTypeParameters; |
| 160 final Map<TypeParameter, DartType> substitution; | 106 final Substitution substitution; |
| 161 | 107 |
| 162 FreshTypeParameters(this.freshTypeParameters, this.substitution); | 108 FreshTypeParameters(this.freshTypeParameters, this.substitution); |
| 163 | 109 |
| 164 DartType substitute(DartType type) => toplevel.substitute(type, substitution); | 110 DartType substitute(DartType type) => substitution.substituteType(type); |
| 111 |
| 112 Supertype substituteSuper(Supertype type) { |
| 113 return substitution.substituteSupertype(type); |
| 114 } |
| 165 } | 115 } |
| 166 | 116 |
| 167 // ------------------------------------------------------------------------ | 117 // ------------------------------------------------------------------------ |
| 168 // IMPLEMENTATION | 118 // IMPLEMENTATION |
| 169 // ------------------------------------------------------------------------ | 119 // ------------------------------------------------------------------------ |
| 170 | 120 |
| 171 class _TypeSubstitutor extends DartTypeVisitor<DartType> { | 121 abstract class Substitution { |
| 172 final Map<TypeParameter, DartType> upperBounds; | 122 /// Substitutes each parameter to the type it maps to in [map]. |
| 173 final Map<TypeParameter, DartType> lowerBounds; | 123 static Substitution fromMap(Map<TypeParameter, DartType> map) { |
| 124 if (map.isEmpty) return _NullSubstitution.instance; |
| 125 return new _MapSubstitution(map, map); |
| 126 } |
| 127 |
| 128 /// Substitutes all occurrences of the given type parameters with the |
| 129 /// corresponding upper or lower bound, depending on the variance of the |
| 130 /// context where it occurs. |
| 131 /// |
| 132 /// For example the type `(T) => T` with the bounds `bottom <: T <: num` |
| 133 /// becomes `(bottom) => num` (in this example, `num` is the upper bound, |
| 134 /// and `bottom` is the lower bound). |
| 135 /// |
| 136 /// This is a way to obtain an upper bound for a type while eliminating all |
| 137 /// references to certain type variables. |
| 138 static Substitution fromUpperAndLowerBounds( |
| 139 Map<TypeParameter, DartType> upper, Map<TypeParameter, DartType> lower) { |
| 140 if (upper.isEmpty && lower.isEmpty) return _NullSubstitution.instance; |
| 141 return new _MapSubstitution(upper, lower); |
| 142 } |
| 143 |
| 144 /// Substitutes the type parameters on the class of [supertype] with the |
| 145 /// type arguments provided in [supertype]. |
| 146 static Substitution fromSupertype(Supertype supertype) { |
| 147 if (supertype.typeArguments.isEmpty) return _NullSubstitution.instance; |
| 148 return fromMap(new Map<TypeParameter, DartType>.fromIterables( |
| 149 supertype.classNode.typeParameters, supertype.typeArguments)); |
| 150 } |
| 151 |
| 152 /// Substitutes the type parameters on the class of [type] with the |
| 153 /// type arguments provided in [type]. |
| 154 static Substitution fromInterfaceType(InterfaceType type) { |
| 155 if (type.typeArguments.isEmpty) return _NullSubstitution.instance; |
| 156 return fromMap(new Map<TypeParameter, DartType>.fromIterables( |
| 157 type.classNode.typeParameters, type.typeArguments)); |
| 158 } |
| 159 |
| 160 /// Substitutes the Nth parameter in [parameters] with the Nth type in |
| 161 /// [types]. |
| 162 static Substitution fromPairs( |
| 163 List<TypeParameter> parameters, List<DartType> types) { |
| 164 // TODO(asgerf): Investigate if it is more efficient to implement |
| 165 // substitution based on parallel pairwise lists instead of Maps. |
| 166 assert(parameters.length == types.length); |
| 167 if (parameters.isEmpty) return _NullSubstitution.instance; |
| 168 return fromMap( |
| 169 new Map<TypeParameter, DartType>.fromIterables(parameters, types)); |
| 170 } |
| 171 |
| 172 DartType getSubstitute(TypeParameter parameter, bool upperBound); |
| 173 |
| 174 DartType substituteType(DartType node) { |
| 175 return new _TopSubstitutor(this).visit(node); |
| 176 } |
| 177 |
| 178 Supertype substituteSupertype(Supertype node) { |
| 179 return new _TopSubstitutor(this).visitSupertype(node); |
| 180 } |
| 181 } |
| 182 |
| 183 class _NullSubstitution extends Substitution { |
| 184 static final _NullSubstitution instance = new _NullSubstitution(); |
| 185 |
| 186 DartType getSubstitute(TypeParameter parameter, bool upperBound) { |
| 187 return new TypeParameterType(parameter); |
| 188 } |
| 189 |
| 190 @override |
| 191 DartType substituteType(DartType node) => node; |
| 192 |
| 193 @override |
| 194 Supertype substituteSupertype(Supertype node) => node; |
| 195 } |
| 196 |
| 197 class _MapSubstitution extends Substitution { |
| 198 final Map<TypeParameter, DartType> upper; |
| 199 final Map<TypeParameter, DartType> lower; |
| 200 |
| 201 _MapSubstitution(this.upper, this.lower); |
| 202 |
| 203 DartType getSubstitute(TypeParameter parameter, bool upperBound) { |
| 204 return upperBound ? upper[parameter] : lower[parameter]; |
| 205 } |
| 206 } |
| 207 |
| 208 class _TopSubstitutor extends _TypeSubstitutor { |
| 209 final Substitution substitution; |
| 210 |
| 211 _TopSubstitutor(this.substitution) : super(null); |
| 212 |
| 213 DartType lookup(TypeParameter parameter, bool upperBound) { |
| 214 return substitution.getSubstitute(parameter, upperBound); |
| 215 } |
| 216 |
| 217 TypeParameter freshTypeParameter(TypeParameter node) { |
| 218 throw 'Create a fresh environment first'; |
| 219 } |
| 220 } |
| 221 |
| 222 class _InnerTypeSubstitutor extends _TypeSubstitutor { |
| 223 final Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{}; |
| 224 |
| 225 _InnerTypeSubstitutor(_TypeSubstitutor outer) : super(outer); |
| 226 |
| 227 DartType lookup(TypeParameter parameter, bool upperBound) { |
| 228 return substitution[parameter]; |
| 229 } |
| 230 |
| 231 TypeParameter freshTypeParameter(TypeParameter node) { |
| 232 var fresh = new TypeParameter(node.name); |
| 233 substitution[node] = new TypeParameterType(fresh); |
| 234 fresh.bound = visit(node.bound); |
| 235 return fresh; |
| 236 } |
| 237 } |
| 238 |
| 239 abstract class _TypeSubstitutor extends DartTypeVisitor<DartType> { |
| 174 final _TypeSubstitutor outer; | 240 final _TypeSubstitutor outer; |
| 175 bool covariantContext = true; | 241 bool covariantContext = true; |
| 176 | 242 |
| 243 _TypeSubstitutor(this.outer) { |
| 244 covariantContext = outer == null ? true : outer.covariantContext; |
| 245 } |
| 246 |
| 247 DartType lookup(TypeParameter parameter, bool upperBound); |
| 248 |
| 177 /// The number of times a variable from this environment has been used in | 249 /// The number of times a variable from this environment has been used in |
| 178 /// a substitution. | 250 /// a substitution. |
| 179 /// | 251 /// |
| 180 /// There is a strict requirement that we must return the same instance for | 252 /// There is a strict requirement that we must return the same instance for |
| 181 /// types that were not altered by the substitution. This counter lets us | 253 /// types that were not altered by the substitution. This counter lets us |
| 182 /// check quickly if anything happened in a substitution. | 254 /// check quickly if anything happened in a substitution. |
| 183 int useCounter = 0; | 255 int useCounter = 0; |
| 184 | 256 |
| 185 _TypeSubstitutor(this.upperBounds, this.lowerBounds, [this.outer]) { | 257 _InnerTypeSubstitutor newInnerEnvironment() { |
| 186 covariantContext = outer == null ? true : outer.covariantContext; | 258 return new _InnerTypeSubstitutor(this); |
| 187 } | |
| 188 | |
| 189 _TypeSubstitutor newInnerEnvironment() { | |
| 190 var map = <TypeParameter, DartType>{}; | |
| 191 return new _TypeSubstitutor(map, map, this); | |
| 192 } | 259 } |
| 193 | 260 |
| 194 void invertVariance() { | 261 void invertVariance() { |
| 195 covariantContext = !covariantContext; | 262 covariantContext = !covariantContext; |
| 196 } | 263 } |
| 197 | 264 |
| 265 Supertype visitSupertype(Supertype node) { |
| 266 if (node.typeArguments.isEmpty) return node; |
| 267 int before = useCounter; |
| 268 var typeArguments = node.typeArguments.map(visit).toList(); |
| 269 if (useCounter == before) return node; |
| 270 return new Supertype(node.classNode, typeArguments); |
| 271 } |
| 272 |
| 198 DartType visit(DartType node) => node.accept(this); | 273 DartType visit(DartType node) => node.accept(this); |
| 199 | 274 |
| 200 DartType visitInvalidType(InvalidType node) => node; | 275 DartType visitInvalidType(InvalidType node) => node; |
| 201 DartType visitDynamicType(DynamicType node) => node; | 276 DartType visitDynamicType(DynamicType node) => node; |
| 202 DartType visitVoidType(VoidType node) => node; | 277 DartType visitVoidType(VoidType node) => node; |
| 203 DartType visitBottomType(BottomType node) => node; | 278 DartType visitBottomType(BottomType node) => node; |
| 204 | 279 |
| 205 DartType visitInterfaceType(InterfaceType node) { | 280 DartType visitInterfaceType(InterfaceType node) { |
| 206 if (node.typeArguments.isEmpty) return node; | 281 if (node.typeArguments.isEmpty) return node; |
| 207 int before = useCounter; | 282 int before = useCounter; |
| 208 var typeArguments = node.typeArguments.map(visit).toList(); | 283 var typeArguments = node.typeArguments.map(visit).toList(); |
| 209 if (useCounter == before) return node; | 284 if (useCounter == before) return node; |
| 210 return new InterfaceType(node.classNode, typeArguments); | 285 return new InterfaceType(node.classNode, typeArguments); |
| 211 } | 286 } |
| 212 | 287 |
| 213 List<TypeParameter> freshTypeParameters(List<TypeParameter> parameters) { | 288 List<TypeParameter> freshTypeParameters(List<TypeParameter> parameters) { |
| 214 if (parameters.isEmpty) return const <TypeParameter>[]; | 289 if (parameters.isEmpty) return const <TypeParameter>[]; |
| 215 return parameters.map(freshTypeParameter).toList(); | 290 return parameters.map(freshTypeParameter).toList(); |
| 216 } | 291 } |
| 217 | 292 |
| 218 TypeParameter freshTypeParameter(TypeParameter node) { | 293 TypeParameter freshTypeParameter(TypeParameter node); |
| 219 var fresh = new TypeParameter(node.name); | |
| 220 upperBounds[node] = new TypeParameterType(fresh); | |
| 221 fresh.bound = visit(node.bound); | |
| 222 return fresh; | |
| 223 } | |
| 224 | 294 |
| 225 DartType visitFunctionType(FunctionType node) { | 295 DartType visitFunctionType(FunctionType node) { |
| 226 assert(!node.typeParameters.any(upperBounds.containsKey)); | |
| 227 // This is a bit tricky because we have to generate fresh type parameters | 296 // This is a bit tricky because we have to generate fresh type parameters |
| 228 // in order to change the bounds. At the same time, if the function type | 297 // in order to change the bounds. At the same time, if the function type |
| 229 // was unaltered, we have to return the [node] object (not a copy!). | 298 // was unaltered, we have to return the [node] object (not a copy!). |
| 230 // Substituting a type for a fresh type variable should not be confused with | 299 // Substituting a type for a fresh type variable should not be confused with |
| 231 // a "real" substitution. | 300 // a "real" substitution. |
| 232 // | 301 // |
| 233 // Create an inner environment to generate fresh type parameters. The use | 302 // Create an inner environment to generate fresh type parameters. The use |
| 234 // counter on the inner environment tells if the fresh type parameters have | 303 // counter on the inner environment tells if the fresh type parameters have |
| 235 // any uses, but does not tell if the resulting function type is distinct. | 304 // any uses, but does not tell if the resulting function type is distinct. |
| 236 // Our own use counter will get incremented if something from our | 305 // Our own use counter will get incremented if something from our |
| (...skipping 23 matching lines...) Expand all Loading... |
| 260 while (node != target) { | 329 while (node != target) { |
| 261 ++node.useCounter; | 330 ++node.useCounter; |
| 262 node = node.outer; | 331 node = node.outer; |
| 263 } | 332 } |
| 264 ++target.useCounter; | 333 ++target.useCounter; |
| 265 } | 334 } |
| 266 | 335 |
| 267 DartType getSubstitute(TypeParameter variable) { | 336 DartType getSubstitute(TypeParameter variable) { |
| 268 var environment = this; | 337 var environment = this; |
| 269 while (environment != null) { | 338 while (environment != null) { |
| 270 var replacement = covariantContext | 339 var replacement = environment.lookup(variable, covariantContext); |
| 271 ? environment.upperBounds[variable] | |
| 272 : environment.lowerBounds[variable]; | |
| 273 if (replacement != null) { | 340 if (replacement != null) { |
| 274 bumpCountersUntil(environment); | 341 bumpCountersUntil(environment); |
| 275 return replacement; | 342 return replacement; |
| 276 } | 343 } |
| 277 environment = environment.outer; | 344 environment = environment.outer; |
| 278 } | 345 } |
| 279 return null; | 346 return null; |
| 280 } | 347 } |
| 281 | 348 |
| 282 DartType visitTypeParameterType(TypeParameterType node) { | 349 DartType visitTypeParameterType(TypeParameterType node) { |
| 283 return getSubstitute(node.parameter) ?? node; | 350 return getSubstitute(node.parameter) ?? node; |
| 284 } | 351 } |
| 285 } | 352 } |
| 286 | 353 |
| 287 class _DeepTypeSubstitutor extends _TypeSubstitutor { | 354 class _DeepTypeSubstitutor extends _InnerTypeSubstitutor { |
| 288 int depth = 0; | 355 int depth = 0; |
| 289 bool isInfinite = false; | 356 bool isInfinite = false; |
| 290 | 357 |
| 291 _DeepTypeSubstitutor(Map<TypeParameter, DartType> substitution, | 358 _DeepTypeSubstitutor(Map<TypeParameter, DartType> substitution, |
| 292 [_DeepTypeSubstitutor outer]) | 359 [_DeepTypeSubstitutor outer]) |
| 293 : super(substitution, substitution, outer); | 360 : super(outer) { |
| 361 this.substitution.addAll(substitution); |
| 362 } |
| 294 | 363 |
| 295 @override | 364 @override |
| 296 _TypeSubstitutor newInnerEnvironment() { | 365 _TypeSubstitutor newInnerEnvironment() { |
| 297 return new _DeepTypeSubstitutor(<TypeParameter, DartType>{}, this); | 366 return new _DeepTypeSubstitutor(<TypeParameter, DartType>{}, this); |
| 298 } | 367 } |
| 299 | 368 |
| 300 @override | 369 @override |
| 301 DartType visitTypeParameterType(TypeParameterType node) { | 370 DartType visitTypeParameterType(TypeParameterType node) { |
| 302 DartType replacement = getSubstitute(node.parameter); | 371 DartType replacement = getSubstitute(node.parameter); |
| 303 if (replacement == null) return node; | 372 if (replacement == null) return node; |
| 304 if (isInfinite) return replacement; | 373 if (isInfinite) return replacement; |
| 305 ++depth; | 374 ++depth; |
| 306 if (depth > upperBounds.length) { | 375 if (depth > substitution.length) { |
| 307 isInfinite = true; | 376 isInfinite = true; |
| 308 --depth; | 377 --depth; |
| 309 return replacement; | 378 return replacement; |
| 310 } else { | 379 } else { |
| 311 replacement = visit(replacement); | 380 replacement = visit(replacement); |
| 312 // Update type to the fully fleshed-out type. | 381 // Update type to the fully fleshed-out type. |
| 313 upperBounds[node.parameter] = replacement; | 382 substitution[node.parameter] = replacement; |
| 314 --depth; | 383 --depth; |
| 315 return replacement; | 384 return replacement; |
| 316 } | 385 } |
| 317 } | 386 } |
| 318 } | 387 } |
| 319 | 388 |
| 320 class _TypeUnification { | 389 class _TypeUnification { |
| 321 // Acyclic invariant: There are no cycles in the map, that is, all types can | 390 // Acyclic invariant: There are no cycles in the map, that is, all types can |
| 322 // be resolved to finite types by substituting all contained type variables. | 391 // be resolved to finite types by substituting all contained type variables. |
| 323 // | 392 // |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 } | 576 } |
| 508 | 577 |
| 509 Map<dynamic/*=K*/, dynamic/*=W*/ > _mapValues/*<K,V,W>*/( | 578 Map<dynamic/*=K*/, dynamic/*=W*/ > _mapValues/*<K,V,W>*/( |
| 510 Map<dynamic/*=K*/, dynamic/*=V*/ > map, dynamic/*=W*/ fn(dynamic/*=V*/)) { | 579 Map<dynamic/*=K*/, dynamic/*=V*/ > map, dynamic/*=W*/ fn(dynamic/*=V*/)) { |
| 511 Map<dynamic/*=K*/, dynamic/*=W*/ > result = {}; | 580 Map<dynamic/*=K*/, dynamic/*=W*/ > result = {}; |
| 512 map.forEach((key, value) { | 581 map.forEach((key, value) { |
| 513 result[key] = fn(value); | 582 result[key] = fn(value); |
| 514 }); | 583 }); |
| 515 return result; | 584 return result; |
| 516 } | 585 } |
| OLD | NEW |