OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 | 4 |
5 class TypeCheckerTask extends CompilerTask { | 5 class TypeCheckerTask extends CompilerTask { |
6 TypeCheckerTask(Compiler compiler) : super(compiler); | 6 TypeCheckerTask(Compiler compiler) : super(compiler); |
7 String get name() => "Type checker"; | 7 String get name() => "Type checker"; |
8 | 8 |
9 static final bool LOG_FAILURES = false; | 9 static final bool LOG_FAILURES = false; |
10 | 10 |
11 void check(Node tree, TreeElements elements) { | 11 void check(Node tree, TreeElements elements) { |
12 measure(() { | 12 measure(() { |
13 Visitor visitor = | 13 Visitor visitor = |
14 new TypeCheckerVisitor(compiler, elements, compiler.types); | 14 new TypeCheckerVisitor(compiler, elements, compiler.types); |
15 try { | 15 try { |
16 tree.accept(visitor); | 16 tree.accept(visitor); |
17 } catch (CancelTypeCheckException e) { | 17 } catch (CancelTypeCheckException e) { |
18 if (LOG_FAILURES) { | 18 if (LOG_FAILURES) { |
19 // Do not warn about unimplemented features; log message instead. | 19 // Do not warn about unimplemented features; log message instead. |
20 compiler.log("'${e.node}': ${e.reason}"); | 20 compiler.log("'${e.node}': ${e.reason}"); |
21 } | 21 } |
22 } | 22 } |
23 }); | 23 }); |
24 } | 24 } |
25 } | 25 } |
26 | 26 |
27 interface Type { | 27 interface Type { |
28 SourceString get name(); | 28 SourceString get name(); |
29 Element get element(); | 29 Element get element(); |
| 30 |
| 31 /** |
| 32 * Performs the substitution [arguments[i]/parameters[i]]this. |
| 33 * The notation is known from this lambda calculus rule: |
| 34 * (lambda x.e0)e1 -> [e1/x]e0. |
| 35 * |
| 36 * See [TypeVariableType] for a motivation for this method. |
| 37 */ |
| 38 Type subst(Link<Type> arguments, List<Type> parameters); |
30 } | 39 } |
31 | 40 |
| 41 /** |
| 42 * Represents a type variable, that is the type parameters of a class |
| 43 * or interface type. For example, in class Array<E> { ... }`, |
| 44 * E is a type variable. |
| 45 * |
| 46 * Each class/interface should have its own unique type variables, |
| 47 * one for each type parameter. A class/interface with type parameters |
| 48 * is said to be parameterized or generic. |
| 49 * |
| 50 * Non-static members, constructors, and factories of generic |
| 51 * class/interface can refer to type variables of the current class |
| 52 * (not of supertypes). |
| 53 * |
| 54 * When using a generic type, also known as an application or |
| 55 * instantiation of the type, the actual type arguments should be |
| 56 * substituted for the type variables in the class declaration. |
| 57 * |
| 58 * For example, given a box, `class Box<T> { T value; }`, the |
| 59 * type of the expression `new Box<String>().value` is |
| 60 * [String] because we must substitute `String` for the |
| 61 * the type variable `T`. |
| 62 */ |
32 class TypeVariableType implements Type { | 63 class TypeVariableType implements Type { |
33 final SourceString name; | 64 final SourceString name; |
34 TypeVariableElement element; | 65 TypeVariableElement element; |
35 TypeVariableType(this.name, [this.element]); | 66 TypeVariableType(this.name, [this.element]); |
36 | 67 |
37 toString() => name.slowToString(); | 68 Type subst(Link<Type> arguments, List<Type> parameters) { |
| 69 if (arguments.isEmpty()) { |
| 70 // Return fast on empty substitutions. |
| 71 return this; |
| 72 } |
| 73 Link<Type> argumentLink = arguments; |
| 74 Iterator<Type> parameterIterator = parameters.iterator(); |
| 75 while (!argumentLink.isEmpty() && parameterIterator.hasNext()) { |
| 76 Type parameter = parameterIterator.next(); |
| 77 Type argument = argumentLink.head; |
| 78 if (parameter === this) { |
| 79 return argument; |
| 80 } |
| 81 argumentLink = argumentLink.tail; |
| 82 } |
| 83 // The type variable was not substituted. |
| 84 return this; |
| 85 } |
| 86 |
| 87 String toString() => name.slowToString(); |
38 } | 88 } |
39 | 89 |
40 /** | 90 /** |
41 * A statement type tracks whether a statement returns or may return. | 91 * A statement type tracks whether a statement returns or may return. |
42 */ | 92 */ |
43 class StatementType implements Type { | 93 class StatementType implements Type { |
44 final String stringName; | 94 final String stringName; |
45 Element get element() => null; | 95 Element get element() => null; |
46 | 96 |
47 SourceString get name() => new SourceString(stringName); | 97 SourceString get name() => new SourceString(stringName); |
48 | 98 |
49 const StatementType(this.stringName); | 99 const StatementType(this.stringName); |
50 | 100 |
51 static final RETURNING = const StatementType('<returning>'); | 101 static final RETURNING = const StatementType('<returning>'); |
52 static final NOT_RETURNING = const StatementType('<not returning>'); | 102 static final NOT_RETURNING = const StatementType('<not returning>'); |
53 static final MAYBE_RETURNING = const StatementType('<maybe returning>'); | 103 static final MAYBE_RETURNING = const StatementType('<maybe returning>'); |
54 | 104 |
55 /** Combine the information about two control-flow edges that are joined. */ | 105 /** Combine the information about two control-flow edges that are joined. */ |
56 StatementType join(StatementType other) { | 106 StatementType join(StatementType other) { |
57 return (this === other) ? this : MAYBE_RETURNING; | 107 return (this === other) ? this : MAYBE_RETURNING; |
58 } | 108 } |
59 | 109 |
| 110 Type subst(Link<Type> arguments, List<Type> parameters) { |
| 111 // Statement types are not substitutable. |
| 112 return this; |
| 113 } |
| 114 |
60 String toString() => stringName; | 115 String toString() => stringName; |
61 } | 116 } |
62 | 117 |
63 class VoidType implements Type { | 118 class VoidType implements Type { |
64 const VoidType(this.element); | 119 const VoidType(this.element); |
65 SourceString get name() => element.name; | 120 SourceString get name() => element.name; |
66 final VoidElement element; | 121 final VoidElement element; |
67 | 122 |
68 toString() => name.slowToString(); | 123 Type subst(Link<Type> arguments, List<Type> parameters) { |
| 124 // Void cannot be substituted. |
| 125 return this; |
| 126 } |
| 127 |
| 128 String toString() => name.slowToString(); |
69 } | 129 } |
70 | 130 |
71 class InterfaceType implements Type { | 131 class InterfaceType implements Type { |
72 final Element element; | 132 final Element element; |
73 final Link<Type> arguments; | 133 final Link<Type> arguments; |
74 | 134 |
75 const InterfaceType(this.element, | 135 const InterfaceType(this.element, |
76 [this.arguments = const EmptyLink<Type>()]); | 136 [this.arguments = const EmptyLink<Type>()]); |
77 | 137 |
78 SourceString get name() => element.name; | 138 SourceString get name() => element.name; |
79 | 139 |
80 toString() { | 140 Type subst(Link<Type> replacements, List<Type> parameters) { |
| 141 if (arguments.isEmpty()) { |
| 142 // Return fast on non-generic types. |
| 143 return this; |
| 144 } |
| 145 if (replacements.isEmpty()) { |
| 146 // Return fast on empty substitutions. |
| 147 return this; |
| 148 } |
| 149 bool changed = false; |
| 150 var argumentsBuilder = new LinkBuilder<Type>(); |
| 151 Link<Type> argument = arguments; |
| 152 while (!argument.isEmpty()) { |
| 153 var replacement = argument.head.subst(replacements, parameters); |
| 154 if (!changed && replacement !== argument.head) { |
| 155 changed = true; |
| 156 } |
| 157 argumentsBuilder.addLast(replacement); |
| 158 argument = argument.tail; |
| 159 } |
| 160 if (changed) { |
| 161 // Create a new type only if necessary. |
| 162 return new InterfaceType(element, argumentsBuilder.toLink()); |
| 163 } |
| 164 return this; |
| 165 } |
| 166 |
| 167 String toString() { |
81 StringBuffer sb = new StringBuffer(); | 168 StringBuffer sb = new StringBuffer(); |
82 sb.add(name.slowToString()); | 169 sb.add(name.slowToString()); |
83 if (!arguments.isEmpty()) { | 170 if (!arguments.isEmpty()) { |
84 sb.add('<'); | 171 sb.add('<'); |
85 arguments.printOn(sb, ', '); | 172 arguments.printOn(sb, ', '); |
86 sb.add('>'); | 173 sb.add('>'); |
87 } | 174 } |
88 return sb.toString(); | 175 return sb.toString(); |
89 } | 176 } |
90 } | 177 } |
91 | 178 |
92 class FunctionType implements Type { | 179 class FunctionType implements Type { |
93 final Element element; | 180 final Element element; |
94 final Type returnType; | 181 final Type returnType; |
95 final Link<Type> parameterTypes; | 182 final Link<Type> parameterTypes; |
96 | 183 |
97 const FunctionType(Type this.returnType, Link<Type> this.parameterTypes, | 184 const FunctionType(Type this.returnType, Link<Type> this.parameterTypes, |
98 Element this.element); | 185 Element this.element); |
99 | 186 |
100 toString() { | 187 Type subst(Link<Type> arguments, List<Type> parameters) { |
| 188 if (arguments.isEmpty()) { |
| 189 // Return fast on empty substitutions. |
| 190 return this; |
| 191 } |
| 192 var newReturnType = returnType.subst(arguments, parameters); |
| 193 bool changed = newReturnType !== returnType; |
| 194 var parameterBuilder = new LinkBuilder<Type>(); |
| 195 Link<Type> parameterType = parameterTypes; |
| 196 while (!parameterType.isEmpty()) { |
| 197 var replacement = parameterType.head.subst(arguments, parameters); |
| 198 if (!changed && replacement !== parameterType.head) { |
| 199 changed = true; |
| 200 } |
| 201 parameterBuilder.addLast(replacement); |
| 202 parameterType = parameterType.tail; |
| 203 } |
| 204 if (changed) { |
| 205 // Create a new type only if necessary. |
| 206 return new FunctionType(newReturnType, parameterBuilder.toLink(), |
| 207 element); |
| 208 } |
| 209 return this; |
| 210 } |
| 211 |
| 212 String toString() { |
101 StringBuffer sb = new StringBuffer(); | 213 StringBuffer sb = new StringBuffer(); |
102 bool first = true; | 214 bool first = true; |
103 sb.add('('); | 215 sb.add('('); |
104 parameterTypes.printOn(sb, ', '); | 216 parameterTypes.printOn(sb, ', '); |
105 sb.add(') -> ${returnType}'); | 217 sb.add(') -> ${returnType}'); |
106 return sb.toString(); | 218 return sb.toString(); |
107 } | 219 } |
108 | 220 |
109 SourceString get name() => const SourceString('Function'); | 221 SourceString get name() => const SourceString('Function'); |
110 | 222 |
(...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
772 } | 884 } |
773 | 885 |
774 visitCatchBlock(CatchBlock node) { | 886 visitCatchBlock(CatchBlock node) { |
775 return unhandledStatement(); | 887 return unhandledStatement(); |
776 } | 888 } |
777 | 889 |
778 visitTypedef(Typedef node) { | 890 visitTypedef(Typedef node) { |
779 return unhandledStatement(); | 891 return unhandledStatement(); |
780 } | 892 } |
781 } | 893 } |
OLD | NEW |