OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'package:front_end/src/fasta/type_inference/local_type_inferrer.dart'; |
| 6 |
5 /// This file declares mixins which can be used to create a shadow hierarchy | 7 /// This file declares mixins which can be used to create a shadow hierarchy |
6 /// of either the kernel or the analyzer AST representations. | 8 /// of either the kernel or the analyzer AST representations. |
7 /// | 9 /// |
8 /// These classes are intended to be used by [BodyBuilder] as a form of | 10 /// These classes are intended to be used by [BodyBuilder] as a form of |
9 /// indirection so that it can manipulate either kernel or analyzer ASTs. | 11 /// indirection so that it can manipulate either kernel or analyzer ASTs. |
10 /// | 12 /// |
11 /// All methods, getters, and setters defined in this file start with the prefix | 13 /// All methods, getters, and setters defined in this file start with the prefix |
12 /// "shadow" in order to avoid naming conflicts with code in kernel or analyzer. | 14 /// "shadow" in order to avoid naming conflicts with code in kernel or analyzer. |
13 /// | 15 /// |
14 /// Note that the analyzer AST representation closely parallels Dart syntax, | 16 /// Note that the analyzer AST representation closely parallels Dart syntax, |
15 /// whereas the kernel AST representation is desugared. The classes in the | 17 /// whereas the kernel AST representation is desugared. The classes in the |
16 /// shadow hierarchy represent the full language (prior to desugaring). | 18 /// shadow hierarchy represent the full language (prior to desugaring). |
17 import 'package:kernel/ast.dart' show DartType; | 19 import 'package:kernel/ast.dart' show DartType, DynamicType, InterfaceType; |
| 20 import 'package:kernel/core_types.dart'; |
18 | 21 |
19 /// Shadow mixin representing a statement block. | 22 /// Shadow mixin representing a statement block. |
20 abstract class ShadowBlock implements ShadowStatement { | 23 abstract class ShadowBlock implements ShadowStatement { |
21 /// Iterates through the statements contained in the block. | 24 /// Iterates through the statements contained in the block. |
22 Iterable<ShadowStatement> get shadowStatements; | 25 Iterable<ShadowStatement> get shadowStatements; |
| 26 |
| 27 @override |
| 28 void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context) { |
| 29 for (var statement in shadowStatements) { |
| 30 statement.shadowInfer(inferrer, context); |
| 31 } |
| 32 } |
23 } | 33 } |
24 | 34 |
25 /// Common interface for shadow mixins representing expressions. | 35 /// Common interface for shadow mixins representing expressions. |
26 /// | 36 abstract class ShadowExpression { |
27 /// TODO(paulberry): add an abstract `shadowInfer` method here to do type | 37 DartType shadowInfer( |
28 /// inference. | 38 LocalTypeInferrer inferrer, DartType context, bool typeNeeded); |
29 abstract class ShadowExpression {} | 39 } |
30 | 40 |
31 /// Shadow mixin representing a function expression. | 41 /// Shadow mixin representing a function expression. |
32 abstract class ShadowFunctionExpression implements ShadowExpression { | 42 abstract class ShadowFunctionExpression implements ShadowExpression { |
33 /// Gets the body of the function expression. | 43 /// Gets the body of the function expression. |
34 ShadowStatement get shadowBody; | 44 ShadowStatement get shadowBody; |
35 | 45 |
36 /// Creates a [DartType] representing the type of the function expression. | 46 /// Creates a [DartType] representing the type of the function expression. |
37 /// | 47 /// |
38 /// If type inference has already been performed, returns the inferred type. | 48 /// If type inference has already been performed, returns the inferred type. |
39 /// Otherwise returns the declared type. | 49 /// Otherwise returns the declared type. |
40 DartType get shadowFunctionType; | 50 DartType get shadowFunctionType; |
41 | 51 |
42 /// Indicates whether the function is asynchronous (`async` or `async*`) | 52 /// Indicates whether the function is asynchronous (`async` or `async*`) |
43 bool get shadowIsAsync; | 53 bool get shadowIsAsync; |
44 | 54 |
45 /// Indicates whether the function was declared using `=>` syntax. | 55 /// Indicates whether the function was declared using `=>` syntax. |
46 bool get shadowIsExpressionFunction; | 56 bool get shadowIsExpressionFunction; |
47 | 57 |
48 /// Indicates whether the function is a generator (`sync*` or `async*`) | 58 /// Indicates whether the function is a generator (`sync*` or `async*`) |
49 bool get shadowIsGenerator; | 59 bool get shadowIsGenerator; |
50 | 60 |
51 /// Sets the return type of the function expression. | 61 /// Sets the return type of the function expression. |
52 /// | 62 /// |
53 /// Intended for use by type inference. | 63 /// Intended for use by type inference. |
54 void set shadowReturnType(DartType type); | 64 void set shadowReturnType(DartType type); |
| 65 |
| 66 @override |
| 67 DartType shadowInfer( |
| 68 LocalTypeInferrer inferrer, DartType context, bool typeNeeded) { |
| 69 // TODO(paulberry): infer argument types and type parameters. |
| 70 // TODO(paulberry): full support for generators. |
| 71 var body = shadowBody; |
| 72 // TODO(paulberry): Dart 1.0 rules say we only need to set the function |
| 73 // node's return type if it uses expression syntax. Does that make sense |
| 74 // for Dart 2.0? |
| 75 bool needToSetReturnType = shadowIsExpressionFunction; |
| 76 bool returnTypeNeeded = typeNeeded || needToSetReturnType; |
| 77 bool isAsync = shadowIsAsync; |
| 78 var functionContext = new FunctionContext( |
| 79 inferrer, returnTypeNeeded, isAsync, shadowIsGenerator); |
| 80 body.shadowInfer(inferrer, functionContext); |
| 81 DartType inferredReturnType; |
| 82 if (needToSetReturnType || typeNeeded) { |
| 83 inferredReturnType = functionContext.inferredReturnType; |
| 84 if (isAsync) { |
| 85 inferredReturnType = new InterfaceType( |
| 86 inferrer.coreTypes.futureClass, <DartType>[inferredReturnType]); |
| 87 } |
| 88 } |
| 89 if (needToSetReturnType) { |
| 90 this.shadowReturnType = inferredReturnType; |
| 91 } |
| 92 if (typeNeeded) { |
| 93 return shadowFunctionType; |
| 94 } else { |
| 95 return null; |
| 96 } |
| 97 } |
55 } | 98 } |
56 | 99 |
57 /// Shadow mixin representing an integer literal. | 100 /// Shadow mixin representing an integer literal. |
58 abstract class ShadowIntLiteral implements ShadowExpression {} | 101 abstract class ShadowIntLiteral implements ShadowExpression { |
| 102 @override |
| 103 DartType shadowInfer( |
| 104 LocalTypeInferrer inferrer, DartType context, bool typeNeeded) { |
| 105 return typeNeeded ? inferrer.coreTypes.intClass.rawType : null; |
| 106 } |
| 107 } |
59 | 108 |
60 /// Shadow mixin representing a list literal. | 109 /// Shadow mixin representing a list literal. |
61 abstract class ShadowListLiteral implements ShadowExpression { | 110 abstract class ShadowListLiteral implements ShadowExpression { |
62 /// Iterates through the expressions contained in the list literal. | 111 /// Iterates through the expressions contained in the list literal. |
63 Iterable<ShadowExpression> get shadowExpressions; | 112 Iterable<ShadowExpression> get shadowExpressions; |
64 | 113 |
65 /// Gets the type argument of the list literal. If type inference has not | 114 /// Gets the type argument of the list literal. If type inference has not |
66 /// been performed and no explicit type argument was specified, returns | 115 /// been performed and no explicit type argument was specified, returns |
67 /// `null`. | 116 /// `null`. |
68 DartType get shadowTypeArgument; | 117 DartType get shadowTypeArgument; |
69 | 118 |
70 /// Sets the type argument of the list literal. | 119 /// Sets the type argument of the list literal. |
71 /// | 120 /// |
72 /// Intended for use by type inference. | 121 /// Intended for use by type inference. |
73 void set shadowTypeArgument(DartType type); | 122 void set shadowTypeArgument(DartType type); |
| 123 |
| 124 @override |
| 125 DartType shadowInfer( |
| 126 LocalTypeInferrer inferrer, DartType context, bool typeNeeded) { |
| 127 DartType declaredTypeArgument = shadowTypeArgument; |
| 128 DartType typeArgumentContext = declaredTypeArgument; |
| 129 if (typeArgumentContext == null) { |
| 130 if (context is InterfaceType && |
| 131 context.classNode == inferrer.coreTypes.listClass && |
| 132 context.typeArguments.length == 1) { |
| 133 typeArgumentContext = context.typeArguments[0]; |
| 134 } else if (context != null) { |
| 135 // TODO(paulberry): report an error? |
| 136 throw new UnimplementedError('$context'); |
| 137 } |
| 138 } |
| 139 DartType inferredTypeArgument = typeArgumentContext; |
| 140 bool typeArgumentNeeded = inferredTypeArgument == null; |
| 141 for (ShadowExpression e in shadowExpressions) { |
| 142 DartType t = |
| 143 e.shadowInfer(inferrer, typeArgumentContext, typeArgumentNeeded); |
| 144 if (typeArgumentNeeded) { |
| 145 inferredTypeArgument = inferrer.union(inferredTypeArgument, t); |
| 146 } |
| 147 } |
| 148 if (inferredTypeArgument == null) { |
| 149 // Empty list. |
| 150 throw new UnimplementedError(); |
| 151 } |
| 152 if (declaredTypeArgument == null) { |
| 153 this.shadowTypeArgument = inferredTypeArgument; |
| 154 } |
| 155 if (typeNeeded) { |
| 156 return new InterfaceType( |
| 157 inferrer.coreTypes.listClass, <DartType>[inferredTypeArgument]); |
| 158 } else { |
| 159 return null; |
| 160 } |
| 161 } |
74 } | 162 } |
75 | 163 |
76 /// Shadow mixin representing a null literal. | 164 /// Shadow mixin representing a null literal. |
77 abstract class ShadowNullLiteral implements ShadowExpression {} | 165 abstract class ShadowNullLiteral implements ShadowExpression { |
| 166 @override |
| 167 DartType shadowInfer( |
| 168 LocalTypeInferrer inferrer, DartType context, bool typeNeeded) { |
| 169 return typeNeeded ? inferrer.coreTypes.nullClass.rawType : null; |
| 170 } |
| 171 } |
78 | 172 |
79 /// Shadow mixin representing a return statement. | 173 /// Shadow mixin representing a return statement. |
80 abstract class ShadowReturnStatement implements ShadowStatement { | 174 abstract class ShadowReturnStatement implements ShadowStatement { |
81 /// Gets the expression being returned, or `null` if this is a bare "return" | 175 /// Gets the expression being returned, or `null` if this is a bare "return" |
82 /// statement. | 176 /// statement. |
83 ShadowExpression get shadowExpression; | 177 ShadowExpression get shadowExpression; |
| 178 |
| 179 @override |
| 180 void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context) { |
| 181 DartType expressionContext = null; // TODO(paulberry): probably wrong. |
| 182 bool expressionTypeNeeded = |
| 183 context.returnTypeNeeded && !context.isGenerator; |
| 184 DartType expressionType = shadowExpression.shadowInfer( |
| 185 inferrer, expressionContext, expressionTypeNeeded); |
| 186 if (expressionTypeNeeded) { |
| 187 if (context.isAsync) { |
| 188 expressionType = _unwrapFuture(inferrer.coreTypes, expressionType); |
| 189 } |
| 190 context.recordReturnType(expressionType); |
| 191 } |
| 192 } |
| 193 |
| 194 DartType _unwrapFuture(CoreTypes coreTypes, DartType type) { |
| 195 // TODO(paulberry): replace with a full implementation of what's in the spec |
| 196 // (e.g. handle types derived from Future). Also probably move to Kernel. |
| 197 if (type is InterfaceType && type.classNode == coreTypes.futureClass) { |
| 198 return type.typeArguments[0]; |
| 199 } else { |
| 200 return type; |
| 201 } |
| 202 } |
84 } | 203 } |
85 | 204 |
86 /// Common interface for shadow mixins representing statements. | 205 /// Common interface for shadow mixins representing statements. |
87 /// | 206 abstract class ShadowStatement { |
88 /// TODO(paulberry): add an abstract `shadowInfer` method here to do type | 207 void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context); |
89 /// inference. | 208 } |
90 abstract class ShadowStatement {} | |
91 | 209 |
92 /// Shadow mixin representing a declaration of a single variable. | 210 /// Shadow mixin representing a declaration of a single variable. |
93 abstract class ShadowVariableDeclaration implements ShadowStatement { | 211 abstract class ShadowVariableDeclaration implements ShadowStatement { |
94 /// Gets the initializer expression for the variable, or `null` if the | 212 /// Gets the initializer expression for the variable, or `null` if the |
95 /// variable has no initializer. | 213 /// variable has no initializer. |
96 ShadowExpression get shadowInitializer; | 214 ShadowExpression get shadowInitializer; |
97 | 215 |
98 /// Gets the type of the variable. If type inference has not been performed | 216 /// Gets the type of the variable. If type inference has not been performed |
99 /// and no explicit type was specified, returns `null`. | 217 /// and no explicit type was specified, returns `null`. |
100 DartType get shadowType; | 218 DartType get shadowType; |
101 | 219 |
102 /// Sets the type of the variable. | 220 /// Sets the type of the variable. |
103 /// | 221 /// |
104 /// Intended for use by type inference. | 222 /// Intended for use by type inference. |
105 void set shadowType(DartType type); | 223 void set shadowType(DartType type); |
| 224 |
| 225 @override |
| 226 void shadowInfer(LocalTypeInferrer inferrer, FunctionContext context) { |
| 227 var initializer = shadowInitializer; |
| 228 if (initializer != null) { |
| 229 var type = shadowType; |
| 230 var inferredType = initializer.shadowInfer(inferrer, type, type == null); |
| 231 if (type == null) { |
| 232 this.shadowType = inferredType; |
| 233 } |
| 234 } |
| 235 } |
106 } | 236 } |
107 | 237 |
108 /// Shadow mixin representing a "read" reference to a variable. | 238 /// Shadow mixin representing a "read" reference to a variable. |
109 abstract class ShadowVariableGet implements ShadowExpression { | 239 abstract class ShadowVariableGet implements ShadowExpression { |
110 /// Gets the variable declaration which is being referenced. | 240 /// Gets the variable declaration which is being referenced. |
111 ShadowVariableDeclaration get shadowDeclaration; | 241 ShadowVariableDeclaration get shadowDeclaration; |
| 242 |
| 243 @override |
| 244 DartType shadowInfer( |
| 245 LocalTypeInferrer inferrer, DartType context, bool typeNeeded) { |
| 246 // TODO(paulberry): make the "?? const DynamicType()" unnecessary. |
| 247 return typeNeeded |
| 248 ? (shadowDeclaration.shadowType ?? const DynamicType()) |
| 249 : null; |
| 250 } |
112 } | 251 } |
OLD | NEW |