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

Side by Side Diff: pkg/kernel/runtime/reify/types.dart

Issue 2697873007: Merge the work on Generic Types Reification from 'dart-lang/reify' repo (Closed)
Patch Set: Get back parameter erroneously removed by previous commit Created 3 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 unified diff | Download patch
« no previous file with comments | « pkg/kernel/runtime/reify/interceptors.dart ('k') | pkg/kernel/test/closures/suite.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /// Notation:
6 ///
7 /// * `[[T]]` is the runtime representation of type `T` (that is, `T` reified).
8 library kernel.transformations.reify.runtime.types;
9
10 import 'declarations.dart' show Class;
11
12 export 'declarations.dart';
13
14 export 'interceptors.dart';
15
16 // The public interface of this library are static functions to access parts of
17 // reified type objects and the constructors on the ReifiedType subclasses.
18
19 bool isSubtypeOf(ReifiedType a, ReifiedType b) => a._isSubtypeOf(b);
20
21 bool isMoreSpecificThan(ReifiedType a, ReifiedType b) {
22 return a._isMoreSpecificThan(b);
23 }
24
25 Kind getKind(ReifiedType type) => type._kind;
26
27 ReifiedType asInstanceOf(Interface type, Class declaration) {
28 return type.asInstanceOf(declaration);
29 }
30
31 List<ReifiedType> getTypeArguments(Interface type) => type._typeArguments;
32
33 bool isDynamic(ReifiedType type) => type._isDynamic;
34
35 bool isFunction(ReifiedType type) => type._isFunction;
36
37 bool isInterface(ReifiedType type) => type._isInterface;
38
39 bool isIntersection(ReifiedType type) => type._isIntersection;
40
41 bool isVariable(ReifiedType type) => type._isVariable;
42
43 bool isVoid(ReifiedType type) => type._isVoid;
44
45 bool isObject(ReifiedType type) => false;
46
47 ReifiedType getSupertype(var type) => type._supertype;
48
49 Iterable<ReifiedType> getInterfaces(Interface type) => type._interfaces;
50
51 ReifiedType subst(ReifiedType type, List<ReifiedType> arguments,
52 List<ReifiedType> parameters) {
53 return type._subst(arguments, parameters);
54 }
55
56 // TODO(ahe): Do we need ReifiedNullType?
57
58 ReifiedType _intersection(ReifiedType a, ReifiedType b) {
59 if (a == null) return b;
60 if (b == null) return a;
61 if (a == b) return a;
62 return new Intersection(a, b);
63 }
64
65 enum Kind {
66 Bottom,
67 Dynamic,
68 Function,
69 Interface,
70 Intersection,
71 Variable,
72 Void,
73 }
74
75 abstract class ReifiedType {
76 // TODO(ahe): Should this be a getter to save memory? Which is faster?
77 final Kind _kind;
78
79 const ReifiedType(this._kind);
80
81 bool get _isDynamic => _kind == Kind.Dynamic;
82
83 bool get _isFunction => _kind == Kind.Function;
84
85 bool get _isInterface => _kind == Kind.Interface;
86
87 bool get _isIntersection => _kind == Kind.Intersection;
88
89 bool get _isVariable => _kind == Kind.Variable;
90
91 bool get _isVoid => _kind == Kind.Void;
92
93 bool get _isObject => false;
94
95 /// Returns true if [this] is more specific than [type].
96 bool _isMoreSpecificThan(ReifiedType type);
97
98 /// Performs the substitution `[arguments[i]/parameters[i]]this`.
99 ///
100 /// The notation is known from this lambda calculus rule:
101 ///
102 /// (lambda x.e0)e1 -> [e1/x]e0.
103 ///
104 /// Invariant: There must be the same number of [arguments] and [parameters].
105 ReifiedType _subst(List<ReifiedType> arguments, List<ReifiedType> parameters);
106
107 /// Returns true if [this] is a subtype of [type].
108 bool _isSubtypeOf(ReifiedType type) {
109 return _subst(const <ReifiedType>[const Bottom()],
110 const <ReifiedType>[const Dynamic()])._isMoreSpecificThan(type);
111 }
112
113 bool _isAssignableTo(ReifiedType type) {
114 if (type._isDynamic) return true;
115 return this._isSubtypeOf(type) || type._isSubtypeOf(this);
116 }
117 }
118
119 /// Represents the type `dynamic`.
120 class Dynamic extends ReifiedType {
121 const Dynamic() : super(Kind.Dynamic);
122
123 bool _isMoreSpecificThan(ReifiedType type) => type._isDynamic;
124
125 ReifiedType _subst(
126 List<ReifiedType> arguments, List<ReifiedType> parameters) {
127 int index = 0;
128 for (ReifiedType parameter in parameters) {
129 if (parameter._isDynamic) return arguments[index];
130 index++;
131 }
132 return this;
133 }
134
135 String toString() => "dynamic";
136 }
137
138 /// Represents the bottom type.
139 class Bottom extends ReifiedType {
140 const Bottom() : super(Kind.Bottom);
141
142 bool _isMoreSpecificThan(ReifiedType type) => true;
143
144 ReifiedType _subst(
145 List<ReifiedType> arguments, List<ReifiedType> parameters) {
146 return this;
147 }
148
149 String toString() => "<bottom>";
150 }
151
152 /// Represents the type `void`.
153 class Void extends ReifiedType {
154 const Void() : super(Kind.Void);
155
156 bool _isMoreSpecificThan(ReifiedType type) {
157 // `void` isn't more specific than anything but itself.
158 return type._isVoid;
159 }
160
161 bool _isSubtypeOf(ReifiedType type) {
162 // `void` isn't the subtype of anything besides `dynamic` and itself.
163 return type._isVoid || type._isDynamic;
164 }
165
166 ReifiedType _subst(
167 List<ReifiedType> arguments, List<ReifiedType> parameters) {
168 return this;
169 }
170
171 String toString() => "void";
172 }
173
174 /// Represents an interface type. That is, the type of any class.
175 ///
176 /// For example, the type
177 ///
178 /// String
179 ///
180 /// Would be represented as:
181 ///
182 /// new Interface(stringDeclaration);
183 ///
184 /// Where `stringDeclaration` is an instance of [Class] which contains
185 /// information about [String]'s supertype and implemented interfaces.
186 ///
187 /// A parameterized type, for example:
188 ///
189 /// Box<int>
190 ///
191 /// Would be represented as:
192 ///
193 /// new Interface(boxDeclaration,
194 /// [new Interface(intDeclaration)]);
195 ///
196 /// Implementation notes and considerations:
197 ///
198 /// * It's possible that we want to split this class in two to save memory: one
199 /// for non-generic classes and one for generic classes. Only the latter
200 /// would need [_typeArguments]. However, this must be weighed against the
201 /// additional polymorphism.
202 /// * Generally, we don't canonicalize types. However, simple types like `new
203 /// Interface(intDeclaration)` should be canonicalized to save
204 /// memory. Precisely how this canonicalization will happen is TBD, but it
205 /// may simply be by using compile-time constants.
206 class Interface extends ReifiedType implements Type {
207 final Class _declaration;
208
209 final List<ReifiedType> _typeArguments;
210
211 const Interface(this._declaration,
212 [this._typeArguments = const <ReifiedType>[]])
213 : super(Kind.Interface);
214
215 bool get _isObject => _declaration.supertype == null;
216
217 Interface get _supertype {
218 return _declaration.supertype
219 ?._subst(_typeArguments, _declaration.variables);
220 }
221
222 Iterable<Interface> get _interfaces {
223 return _declaration.interfaces.map((Interface type) {
224 return type._subst(_typeArguments, _declaration.variables);
225 });
226 }
227
228 FunctionType get _callableType {
229 return _declaration.callableType
230 ?._subst(_typeArguments, _declaration.variables);
231 }
232
233 bool _isMoreSpecificThan(ReifiedType type) {
234 if (type._isDynamic) return true;
235 // Intersection types can only occur as the result of calling
236 // [asInstanceOf], they should never be passed in to this method.
237 assert(!type._isIntersection);
238 if (type._isFunction) {
239 return _callableType?._isMoreSpecificThan(type) ?? false;
240 }
241 if (!type._isInterface) return false;
242 if (this == type) return true;
243 ReifiedType supertype = asInstanceOfType(type);
244 if (supertype == null) {
245 // Special case: A callable class is a subtype of [Function], regardless
246 // if it implements [Function]. It isn't more specific than
247 // [Function]. The type representing [Function] is the supertype of
248 // `declaration.callableType`.
249 return _declaration.callableType?._supertype?._isSubtypeOf(type) ?? false;
250 }
251 if (type == supertype) return true;
252 switch (supertype._kind) {
253 case Kind.Dynamic:
254 case Kind.Variable:
255 // Shouldn't happen. See switch in [asInstanceOf].
256 throw "internal error: $supertype";
257
258 case Kind.Interface:
259 Interface s = supertype;
260 Interface t = type;
261 for (int i = 0; i < s._typeArguments.length; i++) {
262 if (!s._typeArguments[i]._isMoreSpecificThan(t._typeArguments[i])) {
263 return false;
264 }
265 }
266 return true;
267
268 case Kind.Intersection:
269 return supertype._isMoreSpecificThan(type);
270
271 default:
272 throw "Internal error: unhandled kind '${type._kind}'";
273 }
274 }
275
276 bool _isSubtypeOf(ReifiedType type) {
277 if (type._isInterface) {
278 Interface interface = type;
279 if (interface._declaration != this._declaration) {
280 // This addition to the specified rules allows us to handle cases like
281 // class D extends A<dynamic> {}
282 // new D() is A<A>
283 // where directly going to `isMoreSpecific` would leave `dynamic` in the
284 // result of `asInstanceOf(A)` instead of bottom.
285 ReifiedType that = asInstanceOf(interface._declaration);
286 if (that != null) {
287 return that._isSubtypeOf(type);
288 }
289 }
290 }
291 return super._isSubtypeOf(type) ||
292 (_callableType?._isSubtypeOf(type) ?? false);
293 }
294
295 /// Returns [this] translated to [type] if [type] is a supertype of
296 /// [this]. Otherwise null.
297 ///
298 /// For example, given:
299 ///
300 /// class Box<T> {}
301 /// class BeatBox extends Box<Beat> {}
302 /// class Beat {}
303 ///
304 /// We have:
305 ///
306 /// [[BeatBox]].asInstanceOf([[Box]]) -> [[Box<Beat>]].
307 ReifiedType asInstanceOf(Class other) {
308 if (_declaration == other) return this;
309 ReifiedType result = _declaration.supertype
310 ?._subst(_typeArguments, _declaration.variables)
311 ?.asInstanceOf(other);
312 for (Interface interface in _declaration.interfaces) {
313 result = _intersection(
314 result,
315 interface
316 ._subst(_typeArguments, _declaration.variables)
317 .asInstanceOf(other));
318 }
319 return result;
320 }
321
322 ReifiedType asInstanceOfType(Interface type) {
323 return asInstanceOf(type._declaration);
324 }
325
326 Interface _subst(List<ReifiedType> arguments, List<ReifiedType> parameters) {
327 List<ReifiedType> copy;
328 int index = 0;
329 for (ReifiedType typeArgument in _typeArguments) {
330 ReifiedType substitution = typeArgument._subst(arguments, parameters);
331 if (substitution != typeArgument) {
332 if (copy == null) {
333 copy = new List<ReifiedType>.from(_typeArguments);
334 }
335 copy[index] = substitution;
336 }
337 index++;
338 }
339 return copy == null ? this : new Interface(_declaration, copy);
340 }
341
342 String toString() {
343 StringBuffer sb = new StringBuffer();
344 sb.write(_declaration.name);
345 if (_typeArguments.isNotEmpty) {
346 sb.write("<");
347 sb.writeAll(_typeArguments, ", ");
348 sb.write(">");
349 }
350 return "$sb";
351 }
352
353 int get hashCode {
354 int code = 23;
355 code = (71 * code + _declaration.hashCode) & 0x3fffffff;
356 for (ReifiedType typeArgument in _typeArguments) {
357 code = (71 * code + typeArgument.hashCode) & 0x3fffffff;
358 }
359 return code;
360 }
361
362 bool operator ==(other) {
363 if (other is Interface) {
364 if (_declaration != other._declaration) return false;
365 if (identical(_typeArguments, other._typeArguments)) return true;
366 assert(_typeArguments.length == other._typeArguments.length);
367 for (int i = 0; i < _typeArguments.length; i++) {
368 if (_typeArguments[i] != other._typeArguments[i]) {
369 return false;
370 }
371 }
372 return true;
373 }
374 return false;
375 }
376 }
377
378 /// Represents the intersection type of [typeA] and [typeB]. The intersection
379 /// type represents a type that is a subtype of both [typeA] and [typeB].
380 ///
381 /// This type is produced when a class implements the same interface twice with
382 /// different type arguments. For example:
383 ///
384 /// abstract class MyNumberList implements List<int>, List<double> {}
385 ///
386 /// Can lead to this intersection type:
387 ///
388 /// new Intersection([[List<int>]], [[List<double>]])
389 ///
390 /// For example,
391 ///
392 /// [[MyNumberList]].asInstanceOf([[List]]) ->
393 /// new Intersection([[List<int>]], [[List<double>]])
394 ///
395 /// Note: sometimes, people confuse this with union types. However the union
396 /// type of `A` and `B` would be anything that is a subtype of either `A` or
397 /// `B`.
398 ///
399 /// See [Intersection types]
400 /// (https://en.wikipedia.org/wiki/Type_system#Intersection_types).
401 class Intersection extends ReifiedType {
402 final ReifiedType typeA;
403 final ReifiedType typeB;
404
405 const Intersection(this.typeA, this.typeB) : super(Kind.Intersection);
406
407 bool _isMoreSpecificThan(ReifiedType type) {
408 // In the above example, `MyNumberList` is a subtype of List<int> *or*
409 // List<double>.
410 return typeA._isMoreSpecificThan(type) || typeB._isMoreSpecificThan(type);
411 }
412
413 ReifiedType _subst(
414 List<ReifiedType> arguments, List<ReifiedType> parameters) {
415 ReifiedType aSubstitution = typeA._subst(arguments, parameters);
416 ReifiedType bSubstitution = typeB._subst(arguments, parameters);
417 return (aSubstitution == typeA && bSubstitution == typeB)
418 ? this
419 : _intersection(aSubstitution, bSubstitution);
420 }
421
422 String toString() => "{ $typeA, $typeB }";
423 }
424
425 /// Represents a type variable aka type parameter.
426 ///
427 /// For example, this class:
428 ///
429 /// class Box<T> {}
430 ///
431 /// Defines one type variable. In the type `Box<int>`, there are no type
432 /// variables. However, `int` is a type argument to the the type
433 /// parameter/variable `T`.
434 class TypeVariable extends ReifiedType {
435 final int _id;
436
437 // TODO(ahe): Do we need to reify bounds?
438 ReifiedType bound;
439
440 TypeVariable(this._id) : super(Kind.Variable);
441
442 bool _isMoreSpecificThan(ReifiedType type) {
443 if (type == this || type._isDynamic || type._isObject) return true;
444 // The bounds of a type variable may contain a cycle, such as:
445 //
446 // class C<T extends S, S extends T> {}
447 //
448 // We use the [tortoise and hare algorithm]
449 // (https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare) to
450 // handle cycles.
451 ReifiedType tortoise = bound;
452 if (tortoise == type) return true;
453 ReifiedType hare = getBoundOrNull(bound);
454 while (tortoise != hare) {
455 tortoise = getBoundOrNull(tortoise);
456 if (tortoise == type) return true;
457 hare = getBoundOrNull(getBoundOrNull(hare));
458 }
459 // Here we know that `tortoise == hare`. Either they're both `null` or we
460 // detected a cycle.
461 if (tortoise != null) {
462 // There was a cycle of type variables in the bounds, but it didn't
463 // involve [type]. The variable [tortoise] visited all the type variables
464 // in the cycle (at least once), and each time we compared it to [type].
465 return false;
466 }
467 // There are no cycles and it's safe to recurse on [bound].
468 return bound._isMoreSpecificThan(type);
469 }
470
471 ReifiedType _subst(
472 List<ReifiedType> arguments, List<ReifiedType> parameters) {
473 int index = 0;
474 for (ReifiedType parameter in parameters) {
475 if (this == parameter) return arguments[index];
476 index++;
477 }
478 return this;
479 }
480
481 String toString() => "#$_id";
482 }
483
484 /// Represents a function type.
485 class FunctionType extends ReifiedType {
486 /// Normally, the [Interface] representing [Function]. But an
487 /// implementation-specific subtype of [Function] may also be used.
488 final ReifiedType _supertype;
489
490 final ReifiedType _returnType;
491
492 /// Encodes number of optional parameters and if the optional parameters are
493 /// named.
494 final int _data;
495
496 /// Encodes the argument types. Positional parameters use one element, the
497 /// type; named parameters use two, the name [String] and type. Named
498 /// parameters must be sorted by name.
499 final List _encodedParameters;
500
501 static const FunctionTypeRelation subtypeRelation =
502 const FunctionSubtypeRelation();
503
504 static const FunctionTypeRelation moreSpecificRelation =
505 const FunctionMoreSpecificRelation();
506
507 const FunctionType(
508 this._supertype, this._returnType, this._data, this._encodedParameters)
509 : super(Kind.Function);
510
511 bool get hasNamedParameters => (_data & 1) == 1;
512
513 int get optionalParameters => _data >> 1;
514
515 int get parameters {
516 return hasNamedParameters
517 ? _encodedParameters.length - optionalParameters
518 : _encodedParameters.length;
519 }
520
521 int get requiredParameters {
522 return hasNamedParameters
523 ? _encodedParameters.length - optionalParameters * 2
524 : _encodedParameters.length - optionalParameters;
525 }
526
527 bool _isSubtypeOf(ReifiedType type) => subtypeRelation.areRelated(this, type);
528
529 bool _isMoreSpecificThan(ReifiedType type) {
530 return moreSpecificRelation.areRelated(this, type);
531 }
532
533 FunctionType _subst(
534 List<ReifiedType> arguments, List<ReifiedType> parameters) {
535 List substitutedParameters;
536 int positionalParameters =
537 hasNamedParameters ? requiredParameters : this.parameters;
538 for (int i = 0; i < _encodedParameters.length; i++) {
539 if (i >= positionalParameters) {
540 // Skip the name of a named parameter.
541 i++;
542 }
543 ReifiedType type = _encodedParameters[i];
544 ReifiedType substitution = type._subst(arguments, parameters);
545 if (substitution != type) {
546 if (substitutedParameters == null) {
547 substitutedParameters = new List.from(_encodedParameters);
548 }
549 substitutedParameters[i] = substitution;
550 }
551 }
552 ReifiedType substitutedReturnType =
553 _returnType._subst(arguments, parameters);
554 if (substitutedParameters == null) {
555 if (_returnType == substitutedReturnType) return this;
556 substitutedParameters = _encodedParameters;
557 }
558 return new FunctionType(
559 _supertype, substitutedReturnType, _data, substitutedParameters);
560 }
561
562 String toString() {
563 StringBuffer sb = new StringBuffer();
564 sb.write("(");
565 bool first = true;
566 for (int i = 0; i < requiredParameters; i++) {
567 if (!first) {
568 sb.write(", ");
569 }
570 sb.write(_encodedParameters[i]);
571 first = false;
572 }
573 if (requiredParameters != parameters) {
574 if (!first) {
575 sb.write(", ");
576 }
577 if (hasNamedParameters) {
578 sb.write("{");
579 first = true;
580 for (int i = requiredParameters;
581 i < _encodedParameters.length;
582 i += 2) {
583 if (!first) {
584 sb.write(", ");
585 }
586 sb.write(_encodedParameters[i + 1]);
587 sb.write(" ");
588 sb.write(_encodedParameters[i]);
589 first = false;
590 }
591 sb.write("}");
592 } else {
593 sb.write("[");
594 first = true;
595 for (int i = requiredParameters; i < _encodedParameters.length; i++) {
596 if (!first) {
597 sb.write(", ");
598 }
599 sb.write(_encodedParameters[i]);
600 first = false;
601 }
602 sb.write("]");
603 }
604 }
605 sb.write(") -> ");
606 sb.write(_returnType);
607 return "$sb";
608 }
609 }
610
611 abstract class FunctionTypeRelation {
612 const FunctionTypeRelation();
613
614 bool areRelated(FunctionType self, ReifiedType type, {bool isMoreSpecific}) {
615 if (!type._isFunction) {
616 return arePartsRelated(self._supertype, type);
617 }
618 FunctionType other = type;
619 if (!other._returnType._isVoid) {
620 if (!arePartsRelated(self._returnType, other._returnType)) return false;
621 }
622 int positionalParameters =
623 self.hasNamedParameters ? self.requiredParameters : self.parameters;
624 int otherPositionalParameters =
625 other.hasNamedParameters ? other.requiredParameters : other.parameters;
626 if (self.requiredParameters > other.requiredParameters) return false;
627 if (positionalParameters < otherPositionalParameters) return false;
628
629 for (int i = 0; i < otherPositionalParameters; i++) {
630 if (!arePartsRelated(
631 self._encodedParameters[i], other._encodedParameters[i])) {
632 return false;
633 }
634 }
635
636 if (!other.hasNamedParameters) true;
637
638 int j = positionalParameters;
639 for (int i = otherPositionalParameters;
640 i < other._encodedParameters.length;
641 i += 2) {
642 String name = other._encodedParameters[i];
643 for (; j < self._encodedParameters.length; j += 2) {
644 if (self._encodedParameters[j] == name) break;
645 }
646 if (j == self._encodedParameters.length) return false;
647 if (!arePartsRelated(
648 self._encodedParameters[j + 1], other._encodedParameters[i + 1])) {
649 return false;
650 }
651 }
652
653 return true;
654 }
655
656 bool arePartsRelated(ReifiedType a, ReifiedType b);
657 }
658
659 class FunctionSubtypeRelation extends FunctionTypeRelation {
660 const FunctionSubtypeRelation();
661
662 bool arePartsRelated(ReifiedType a, ReifiedType b) => a._isAssignableTo(b);
663 }
664
665 class FunctionMoreSpecificRelation extends FunctionTypeRelation {
666 const FunctionMoreSpecificRelation();
667
668 bool arePartsRelated(ReifiedType a, ReifiedType b) =>
669 a._isMoreSpecificThan(b);
670 }
671
672 /// If [type] is a type variable, return its bound. Otherwise `null`.
673 ReifiedType getBoundOrNull(ReifiedType type) {
674 if (type == null) return null;
675 if (!type._isVariable) return null;
676 TypeVariable tv = type;
677 return tv.bound;
678 }
OLDNEW
« no previous file with comments | « pkg/kernel/runtime/reify/interceptors.dart ('k') | pkg/kernel/test/closures/suite.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698