OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library dart2js.resolution.types; | 5 library dart2js.resolution.types; |
6 | 6 |
7 import '../common.dart'; | 7 import '../common.dart'; |
8 import '../common/resolution.dart' show | 8 import '../common/resolution.dart' show Feature, Resolution; |
9 Feature, | 9 import '../compiler.dart' show Compiler; |
10 Resolution; | 10 import '../dart_backend/dart_backend.dart' show DartBackend; |
11 import '../compiler.dart' show | |
12 Compiler; | |
13 import '../dart_backend/dart_backend.dart' show | |
14 DartBackend; | |
15 import '../dart_types.dart'; | 11 import '../dart_types.dart'; |
16 import '../elements/elements.dart' show | 12 import '../elements/elements.dart' |
17 AmbiguousElement, | 13 show |
18 ClassElement, | 14 AmbiguousElement, |
19 Element, | 15 ClassElement, |
20 Elements, | 16 Element, |
21 ErroneousElement, | 17 Elements, |
22 PrefixElement, | 18 ErroneousElement, |
23 TypedefElement, | 19 PrefixElement, |
24 TypeVariableElement; | 20 TypedefElement, |
25 import '../elements/modelx.dart' show | 21 TypeVariableElement; |
26 ErroneousElementX; | 22 import '../elements/modelx.dart' show ErroneousElementX; |
27 import '../tree/tree.dart'; | 23 import '../tree/tree.dart'; |
28 import '../util/util.dart' show | 24 import '../util/util.dart' show Link; |
29 Link; | |
30 | 25 |
31 import 'members.dart' show | 26 import 'members.dart' show lookupInScope; |
32 lookupInScope; | 27 import 'registry.dart' show ResolutionRegistry; |
33 import 'registry.dart' show | 28 import 'resolution_common.dart' show MappingVisitor; |
34 ResolutionRegistry; | 29 import 'scope.dart' show Scope; |
35 import 'resolution_common.dart' show | |
36 MappingVisitor; | |
37 import 'scope.dart' show | |
38 Scope; | |
39 | 30 |
40 class TypeResolver { | 31 class TypeResolver { |
41 final Compiler compiler; | 32 final Compiler compiler; |
42 | 33 |
43 TypeResolver(this.compiler); | 34 TypeResolver(this.compiler); |
44 | 35 |
45 DiagnosticReporter get reporter => compiler.reporter; | 36 DiagnosticReporter get reporter => compiler.reporter; |
46 | 37 |
47 Resolution get resolution => compiler.resolution; | 38 Resolution get resolution => compiler.resolution; |
48 | 39 |
49 /// Tries to resolve the type name as an element. | 40 /// Tries to resolve the type name as an element. |
50 Element resolveTypeName(Identifier prefixName, | 41 Element resolveTypeName( |
51 Identifier typeName, | 42 Identifier prefixName, Identifier typeName, Scope scope, |
52 Scope scope, | 43 {bool deferredIsMalformed: true}) { |
53 {bool deferredIsMalformed: true}) { | |
54 Element element; | 44 Element element; |
55 if (prefixName != null) { | 45 if (prefixName != null) { |
56 Element prefixElement = | 46 Element prefixElement = |
57 lookupInScope(reporter, prefixName, scope, prefixName.source); | 47 lookupInScope(reporter, prefixName, scope, prefixName.source); |
58 if (prefixElement != null && prefixElement.isPrefix) { | 48 if (prefixElement != null && prefixElement.isPrefix) { |
59 // The receiver is a prefix. Lookup in the imported members. | 49 // The receiver is a prefix. Lookup in the imported members. |
60 PrefixElement prefix = prefixElement; | 50 PrefixElement prefix = prefixElement; |
61 element = prefix.lookupLocalMember(typeName.source); | 51 element = prefix.lookupLocalMember(typeName.source); |
62 // TODO(17260, sigurdm): The test for DartBackend is there because | 52 // TODO(17260, sigurdm): The test for DartBackend is there because |
63 // dart2dart outputs malformed types with prefix. | 53 // dart2dart outputs malformed types with prefix. |
64 if (element != null && | 54 if (element != null && |
65 prefix.isDeferred && | 55 prefix.isDeferred && |
66 deferredIsMalformed && | 56 deferredIsMalformed && |
67 compiler.backend is! DartBackend) { | 57 compiler.backend is! DartBackend) { |
68 element = new ErroneousElementX(MessageKind.DEFERRED_TYPE_ANNOTATION, | 58 element = new ErroneousElementX(MessageKind.DEFERRED_TYPE_ANNOTATION, |
69 {'node': typeName}, | 59 {'node': typeName}, element.name, element); |
70 element.name, | |
71 element); | |
72 } | 60 } |
73 } else { | 61 } else { |
74 // The caller of this method will create the ErroneousElement for | 62 // The caller of this method will create the ErroneousElement for |
75 // the MalformedType. | 63 // the MalformedType. |
76 element = null; | 64 element = null; |
77 } | 65 } |
78 } else { | 66 } else { |
79 element = lookupInScope(reporter, typeName, scope, typeName.source); | 67 element = lookupInScope(reporter, typeName, scope, typeName.source); |
80 } | 68 } |
81 return element; | 69 return element; |
82 } | 70 } |
83 | 71 |
84 DartType resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node, | 72 DartType resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node, |
85 {bool malformedIsError: false, | 73 {bool malformedIsError: false, bool deferredIsMalformed: true}) { |
86 bool deferredIsMalformed: true}) { | |
87 ResolutionRegistry registry = visitor.registry; | 74 ResolutionRegistry registry = visitor.registry; |
88 | 75 |
89 Identifier typeName; | 76 Identifier typeName; |
90 DartType type; | 77 DartType type; |
91 | 78 |
92 DartType checkNoTypeArguments(DartType type) { | 79 DartType checkNoTypeArguments(DartType type) { |
93 List<DartType> arguments = new List<DartType>(); | 80 List<DartType> arguments = new List<DartType>(); |
94 bool hasTypeArgumentMismatch = resolveTypeArguments( | 81 bool hasTypeArgumentMismatch = |
95 visitor, node, const <DartType>[], arguments); | 82 resolveTypeArguments(visitor, node, const <DartType>[], arguments); |
96 if (hasTypeArgumentMismatch) { | 83 if (hasTypeArgumentMismatch) { |
97 return new MalformedType( | 84 return new MalformedType( |
98 new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH, | 85 new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH, |
99 {'type': node}, typeName.source, visitor.enclosingElement), | 86 {'type': node}, typeName.source, visitor.enclosingElement), |
100 type, arguments); | 87 type, |
| 88 arguments); |
101 } | 89 } |
102 return type; | 90 return type; |
103 } | 91 } |
104 | 92 |
105 Identifier prefixName; | 93 Identifier prefixName; |
106 Send send = node.typeName.asSend(); | 94 Send send = node.typeName.asSend(); |
107 if (send != null) { | 95 if (send != null) { |
108 // The type name is of the form [: prefix . identifier :]. | 96 // The type name is of the form [: prefix . identifier :]. |
109 prefixName = send.receiver.asIdentifier(); | 97 prefixName = send.receiver.asIdentifier(); |
110 typeName = send.selector.asIdentifier(); | 98 typeName = send.selector.asIdentifier(); |
111 } else { | 99 } else { |
112 typeName = node.typeName.asIdentifier(); | 100 typeName = node.typeName.asIdentifier(); |
113 if (identical(typeName.source, 'void')) { | 101 if (identical(typeName.source, 'void')) { |
114 type = const VoidType(); | 102 type = const VoidType(); |
115 checkNoTypeArguments(type); | 103 checkNoTypeArguments(type); |
116 registry.useType(node, type); | 104 registry.useType(node, type); |
117 return type; | 105 return type; |
118 } else if (identical(typeName.source, 'dynamic')) { | 106 } else if (identical(typeName.source, 'dynamic')) { |
119 type = const DynamicType(); | 107 type = const DynamicType(); |
120 checkNoTypeArguments(type); | 108 checkNoTypeArguments(type); |
121 registry.useType(node, type); | 109 registry.useType(node, type); |
122 return type; | 110 return type; |
123 } | 111 } |
124 } | 112 } |
125 | 113 |
126 Element element = resolveTypeName(prefixName, typeName, visitor.scope, | 114 Element element = resolveTypeName(prefixName, typeName, visitor.scope, |
127 deferredIsMalformed: deferredIsMalformed); | 115 deferredIsMalformed: deferredIsMalformed); |
128 | 116 |
129 DartType reportFailureAndCreateType( | 117 DartType reportFailureAndCreateType( |
130 MessageKind messageKind, | 118 MessageKind messageKind, Map messageArguments, |
131 Map messageArguments, | |
132 {DartType userProvidedBadType, | 119 {DartType userProvidedBadType, |
133 Element erroneousElement, | 120 Element erroneousElement, |
134 List<DiagnosticMessage> infos: const <DiagnosticMessage>[]}) { | 121 List<DiagnosticMessage> infos: const <DiagnosticMessage>[]}) { |
135 if (malformedIsError) { | 122 if (malformedIsError) { |
136 reporter.reportError( | 123 reporter.reportError( |
137 reporter.createMessage(node, messageKind, messageArguments), | 124 reporter.createMessage(node, messageKind, messageArguments), infos); |
138 infos); | |
139 } else { | 125 } else { |
140 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); | 126 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); |
141 reporter.reportWarning( | 127 reporter.reportWarning( |
142 reporter.createMessage(node, messageKind, messageArguments), | 128 reporter.createMessage(node, messageKind, messageArguments), infos); |
143 infos); | |
144 } | 129 } |
145 if (erroneousElement == null) { | 130 if (erroneousElement == null) { |
146 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); | 131 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); |
147 erroneousElement = new ErroneousElementX( | 132 erroneousElement = new ErroneousElementX(messageKind, messageArguments, |
148 messageKind, messageArguments, typeName.source, | 133 typeName.source, visitor.enclosingElement); |
149 visitor.enclosingElement); | |
150 } | 134 } |
151 List<DartType> arguments = <DartType>[]; | 135 List<DartType> arguments = <DartType>[]; |
152 resolveTypeArguments(visitor, node, const <DartType>[], arguments); | 136 resolveTypeArguments(visitor, node, const <DartType>[], arguments); |
153 return new MalformedType(erroneousElement, | 137 return new MalformedType( |
154 userProvidedBadType, arguments); | 138 erroneousElement, userProvidedBadType, arguments); |
155 } | 139 } |
156 | 140 |
157 // Try to construct the type from the element. | 141 // Try to construct the type from the element. |
158 if (element == null) { | 142 if (element == null) { |
159 type = reportFailureAndCreateType( | 143 type = reportFailureAndCreateType( |
160 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName}); | 144 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName}); |
161 } else if (element.isAmbiguous) { | 145 } else if (element.isAmbiguous) { |
162 AmbiguousElement ambiguous = element; | 146 AmbiguousElement ambiguous = element; |
163 type = reportFailureAndCreateType( | 147 type = reportFailureAndCreateType( |
164 ambiguous.messageKind, | 148 ambiguous.messageKind, ambiguous.messageArguments, |
165 ambiguous.messageArguments, | |
166 infos: ambiguous.computeInfos( | 149 infos: ambiguous.computeInfos( |
167 registry.mapping.analyzedElement, reporter)); | 150 registry.mapping.analyzedElement, reporter)); |
168 ; | 151 ; |
169 } else if (element.isMalformed) { | 152 } else if (element.isMalformed) { |
170 if (element is ErroneousElement) { | 153 if (element is ErroneousElement) { |
171 type = reportFailureAndCreateType( | 154 type = reportFailureAndCreateType( |
172 element.messageKind, element.messageArguments, | 155 element.messageKind, element.messageArguments, |
173 erroneousElement: element); | 156 erroneousElement: element); |
174 } else { | 157 } else { |
175 type = const DynamicType(); | 158 type = const DynamicType(); |
176 } | 159 } |
177 } else if (!element.impliesType) { | 160 } else if (!element.impliesType) { |
178 type = reportFailureAndCreateType( | 161 type = reportFailureAndCreateType( |
179 MessageKind.NOT_A_TYPE, {'node': node.typeName}); | 162 MessageKind.NOT_A_TYPE, {'node': node.typeName}); |
180 } else { | 163 } else { |
181 bool addTypeVariableBoundsCheck = false; | 164 bool addTypeVariableBoundsCheck = false; |
182 if (element.isClass) { | 165 if (element.isClass) { |
183 ClassElement cls = element; | 166 ClassElement cls = element; |
184 // TODO(johnniwinther): [ensureClassWillBeResolvedInternal] should imply | 167 // TODO(johnniwinther): [ensureClassWillBeResolvedInternal] should imply |
185 // [computeType]. | 168 // [computeType]. |
186 compiler.resolver.ensureClassWillBeResolvedInternal(cls); | 169 compiler.resolver.ensureClassWillBeResolvedInternal(cls); |
187 cls.computeType(resolution); | 170 cls.computeType(resolution); |
188 List<DartType> arguments = <DartType>[]; | 171 List<DartType> arguments = <DartType>[]; |
189 bool hasTypeArgumentMismatch = resolveTypeArguments( | 172 bool hasTypeArgumentMismatch = |
190 visitor, node, cls.typeVariables, arguments); | 173 resolveTypeArguments(visitor, node, cls.typeVariables, arguments); |
191 if (hasTypeArgumentMismatch) { | 174 if (hasTypeArgumentMismatch) { |
192 type = new BadInterfaceType(cls.declaration, | 175 type = new BadInterfaceType( |
193 new InterfaceType.forUserProvidedBadType(cls.declaration, | 176 cls.declaration, |
194 arguments)); | 177 new InterfaceType.forUserProvidedBadType( |
| 178 cls.declaration, arguments)); |
195 } else { | 179 } else { |
196 if (arguments.isEmpty) { | 180 if (arguments.isEmpty) { |
197 type = cls.rawType; | 181 type = cls.rawType; |
198 } else { | 182 } else { |
199 type = new InterfaceType( | 183 type = new InterfaceType( |
200 cls.declaration, arguments.toList(growable: false)); | 184 cls.declaration, arguments.toList(growable: false)); |
201 addTypeVariableBoundsCheck = true; | 185 addTypeVariableBoundsCheck = true; |
202 } | 186 } |
203 } | 187 } |
204 } else if (element.isTypedef) { | 188 } else if (element.isTypedef) { |
(...skipping 25 matching lines...) Expand all Loading... |
230 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); | 214 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); |
231 type = reportFailureAndCreateType( | 215 type = reportFailureAndCreateType( |
232 MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER, | 216 MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER, |
233 {'typeVariableName': node}, | 217 {'typeVariableName': node}, |
234 userProvidedBadType: typeVariable.type); | 218 userProvidedBadType: typeVariable.type); |
235 } else { | 219 } else { |
236 type = typeVariable.type; | 220 type = typeVariable.type; |
237 } | 221 } |
238 type = checkNoTypeArguments(type); | 222 type = checkNoTypeArguments(type); |
239 } else { | 223 } else { |
240 reporter.internalError(node, | 224 reporter.internalError( |
241 "Unexpected element kind ${element.kind}."); | 225 node, "Unexpected element kind ${element.kind}."); |
242 } | 226 } |
243 if (addTypeVariableBoundsCheck) { | 227 if (addTypeVariableBoundsCheck) { |
244 registry.registerFeature(Feature.TYPE_VARIABLE_BOUNDS_CHECK); | 228 registry.registerFeature(Feature.TYPE_VARIABLE_BOUNDS_CHECK); |
245 visitor.addDeferredAction( | 229 visitor.addDeferredAction(visitor.enclosingElement, |
246 visitor.enclosingElement, | |
247 () => checkTypeVariableBounds(node, type)); | 230 () => checkTypeVariableBounds(node, type)); |
248 } | 231 } |
249 } | 232 } |
250 registry.useType(node, type); | 233 registry.useType(node, type); |
251 return type; | 234 return type; |
252 } | 235 } |
253 | 236 |
254 /// Checks the type arguments of [type] against the type variable bounds. | 237 /// Checks the type arguments of [type] against the type variable bounds. |
255 void checkTypeVariableBounds(TypeAnnotation node, GenericType type) { | 238 void checkTypeVariableBounds(TypeAnnotation node, GenericType type) { |
256 void checkTypeVariableBound(_, DartType typeArgument, | 239 void checkTypeVariableBound(_, DartType typeArgument, |
257 TypeVariableType typeVariable, | 240 TypeVariableType typeVariable, DartType bound) { |
258 DartType bound) { | |
259 if (!compiler.types.isSubtype(typeArgument, bound)) { | 241 if (!compiler.types.isSubtype(typeArgument, bound)) { |
260 reporter.reportWarningMessage( | 242 reporter.reportWarningMessage( |
261 node, | 243 node, MessageKind.INVALID_TYPE_VARIABLE_BOUND, { |
262 MessageKind.INVALID_TYPE_VARIABLE_BOUND, | 244 'typeVariable': typeVariable, |
263 {'typeVariable': typeVariable, | 245 'bound': bound, |
264 'bound': bound, | 246 'typeArgument': typeArgument, |
265 'typeArgument': typeArgument, | 247 'thisType': type.element.thisType |
266 'thisType': type.element.thisType}); | 248 }); |
267 } | 249 } |
268 }; | 250 } |
| 251 ; |
269 | 252 |
270 compiler.types.checkTypeVariableBounds(type, checkTypeVariableBound); | 253 compiler.types.checkTypeVariableBounds(type, checkTypeVariableBound); |
271 } | 254 } |
272 | 255 |
273 /** | 256 /** |
274 * Resolves the type arguments of [node] and adds these to [arguments]. | 257 * Resolves the type arguments of [node] and adds these to [arguments]. |
275 * | 258 * |
276 * Returns [: true :] if the number of type arguments did not match the | 259 * Returns [: true :] if the number of type arguments did not match the |
277 * number of type variables. | 260 * number of type variables. |
278 */ | 261 */ |
279 bool resolveTypeArguments(MappingVisitor visitor, | 262 bool resolveTypeArguments(MappingVisitor visitor, TypeAnnotation node, |
280 TypeAnnotation node, | 263 List<DartType> typeVariables, List<DartType> arguments) { |
281 List<DartType> typeVariables, | |
282 List<DartType> arguments) { | |
283 if (node.typeArguments == null) { | 264 if (node.typeArguments == null) { |
284 return false; | 265 return false; |
285 } | 266 } |
286 int expectedVariables = typeVariables.length; | 267 int expectedVariables = typeVariables.length; |
287 int index = 0; | 268 int index = 0; |
288 bool typeArgumentCountMismatch = false; | 269 bool typeArgumentCountMismatch = false; |
289 for (Link<Node> typeArguments = node.typeArguments.nodes; | 270 for (Link<Node> typeArguments = node.typeArguments.nodes; |
290 !typeArguments.isEmpty; | 271 !typeArguments.isEmpty; |
291 typeArguments = typeArguments.tail, index++) { | 272 typeArguments = typeArguments.tail, index++) { |
292 if (index > expectedVariables - 1) { | 273 if (index > expectedVariables - 1) { |
293 reporter.reportWarningMessage( | 274 reporter.reportWarningMessage( |
294 typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT); | 275 typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT); |
295 typeArgumentCountMismatch = true; | 276 typeArgumentCountMismatch = true; |
296 } | 277 } |
297 DartType argType = resolveTypeAnnotation(visitor, typeArguments.head); | 278 DartType argType = resolveTypeAnnotation(visitor, typeArguments.head); |
298 // TODO(karlklose): rewrite to not modify [arguments]. | 279 // TODO(karlklose): rewrite to not modify [arguments]. |
299 arguments.add(argType); | 280 arguments.add(argType); |
300 } | 281 } |
301 if (index < expectedVariables) { | 282 if (index < expectedVariables) { |
302 reporter.reportWarningMessage( | 283 reporter.reportWarningMessage( |
303 node.typeArguments, MessageKind.MISSING_TYPE_ARGUMENT); | 284 node.typeArguments, MessageKind.MISSING_TYPE_ARGUMENT); |
304 typeArgumentCountMismatch = true; | 285 typeArgumentCountMismatch = true; |
305 } | 286 } |
306 return typeArgumentCountMismatch; | 287 return typeArgumentCountMismatch; |
307 } | 288 } |
308 } | 289 } |
OLD | NEW |