OLD | NEW |
---|---|
(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 library fasta.kernel_procedure_builder; | |
6 | |
7 import 'package:kernel/ast.dart' show | |
8 Arguments, | |
9 AsyncMarker, | |
10 Constructor, | |
11 DartType, | |
12 DynamicType, | |
13 EmptyStatement, | |
14 Expression, | |
15 FunctionNode, | |
16 Initializer, | |
17 Library, | |
18 LocalInitializer, | |
19 Member, | |
20 Name, | |
21 NamedExpression, | |
22 Procedure, | |
23 ProcedureKind, | |
24 RedirectingInitializer, | |
25 Statement, | |
26 SuperInitializer, | |
27 TypeParameter, | |
28 VariableDeclaration, | |
29 VariableGet, | |
30 VoidType, | |
31 setParents; | |
32 | |
33 import 'package:kernel/type_algebra.dart' show | |
34 containsTypeVariable, | |
35 substitute; | |
36 | |
37 import '../errors.dart' show | |
38 internalError; | |
39 | |
40 import '../modifier.dart' show | |
41 abstractMask; | |
42 | |
43 import 'kernel_builder.dart' show | |
44 ClassBuilder, | |
45 ConstructorReferenceBuilder, | |
46 FormalParameterBuilder, | |
47 KernelFormalParameterBuilder, | |
48 KernelTypeBuilder, | |
49 KernelTypeVariableBuilder, | |
50 MetadataBuilder, | |
51 ProcedureBuilder, | |
52 TypeBuilder, | |
53 TypeVariableBuilder, | |
54 memberError; | |
55 | |
56 abstract class KernelFunctionBuilder | |
57 extends ProcedureBuilder<KernelTypeBuilder> { | |
58 FunctionNode function; | |
59 | |
60 Statement actualBody; | |
61 | |
62 KernelFunctionBuilder( | |
63 List<MetadataBuilder> metadata, | |
64 int modifiers, KernelTypeBuilder returnType, String name, | |
65 List<TypeVariableBuilder> typeVariables, | |
66 List<FormalParameterBuilder> formals) | |
67 : super(metadata, modifiers, returnType, name, typeVariables, formals); | |
68 | |
69 void set body(Statement newBody) { | |
70 if (isAbstract && newBody != null) { | |
71 return internalError("Attempting to set body on abstract method."); | |
72 } | |
73 actualBody = newBody; | |
74 if (function != null) { | |
75 function.body = newBody; | |
76 newBody?.parent = function; | |
77 } | |
78 } | |
79 | |
80 Statement get body => actualBody ??= new EmptyStatement(); | |
81 | |
82 FunctionNode buildFunction() { | |
83 assert(function == null); | |
84 FunctionNode result = new FunctionNode(body, asyncMarker: asyncModifier); | |
85 if (typeVariables != null) { | |
86 for (KernelTypeVariableBuilder t in typeVariables) { | |
87 result.typeParameters.add(t.parameter); | |
88 } | |
89 setParents(result.typeParameters, result); | |
90 } | |
91 if (formals != null) { | |
92 for (KernelFormalParameterBuilder formal in formals) { | |
93 VariableDeclaration parameter = formal.build(); | |
94 if (formal.isNamed) { | |
95 result.namedParameters.add(parameter); | |
96 } else { | |
97 result.positionalParameters.add(parameter); | |
98 } | |
99 parameter.parent = result; | |
100 if (formal.isRequired) { | |
101 result.requiredParameterCount++; | |
102 } | |
103 } | |
104 } | |
105 if (returnType != null) { | |
106 result.returnType = returnType.build(); | |
107 } | |
108 if (!isConstructor && !isInstanceMember && parent is ClassBuilder) { | |
109 List<TypeParameter> typeParameters = parent.target.typeParameters; | |
110 if (typeParameters.isNotEmpty) { | |
111 Map<TypeParameter, DartType> substitution; | |
112 DartType removeTypeVariables(DartType type) { | |
113 if (substitution == null) { | |
114 substitution = <TypeParameter, DartType>{}; | |
115 for (TypeParameter parameter in typeParameters) { | |
116 substitution[parameter] = const DynamicType(); | |
117 } | |
118 } | |
119 print("Can only use type variables in instance methods."); | |
120 return substitute(type, substitution); | |
121 } | |
122 Set<TypeParameter> set = typeParameters.toSet(); | |
123 for (VariableDeclaration parameter in result.positionalParameters) { | |
124 if (containsTypeVariable(parameter.type, set)) { | |
125 parameter.type = removeTypeVariables(parameter.type); | |
126 } | |
127 } | |
128 for (VariableDeclaration parameter in result.namedParameters) { | |
129 if (containsTypeVariable(parameter.type, set)) { | |
130 parameter.type = removeTypeVariables(parameter.type); | |
131 } | |
132 } | |
133 if (containsTypeVariable(result.returnType, set)) { | |
134 result.returnType = removeTypeVariables(result.returnType); | |
135 } | |
136 } | |
137 } | |
138 return function = result; | |
139 } | |
140 | |
141 Member build(Library library); | |
142 } | |
143 | |
144 class KernelProcedureBuilder extends KernelFunctionBuilder { | |
145 final Procedure procedure; | |
146 | |
147 AsyncMarker actualAsyncModifier; | |
148 | |
149 final ConstructorReferenceBuilder redirectionTarget; | |
150 | |
151 KernelProcedureBuilder( | |
152 List<MetadataBuilder> metadata, | |
153 int modifiers, KernelTypeBuilder returnType, String name, | |
154 List<TypeVariableBuilder> typeVariables, | |
155 List<FormalParameterBuilder> formals, this.actualAsyncModifier, | |
156 ProcedureKind kind, [this.redirectionTarget]) | |
157 : procedure = new Procedure(null, kind, null), | |
158 super(metadata, modifiers, returnType, name, typeVariables, formals); | |
159 | |
160 ProcedureKind get kind => procedure.kind; | |
161 | |
162 AsyncMarker get asyncModifier => actualAsyncModifier; | |
163 | |
164 Statement get body { | |
165 if (actualBody == null && redirectionTarget == null && !isAbstract && | |
166 !isExternal) { | |
167 actualBody = new EmptyStatement(); | |
168 } | |
169 return actualBody; | |
170 } | |
171 | |
172 void set asyncModifier(AsyncMarker newModifier) { | |
173 actualAsyncModifier = newModifier; | |
174 if (function != null) { | |
175 // No parent, it's an enum. | |
176 function.asyncMarker = actualAsyncModifier; | |
177 } | |
178 } | |
179 | |
180 Procedure build(Library library) { | |
181 // TODO(ahe): I think we may call this twice on parts. Investigate. | |
182 if (procedure.name == null) { | |
183 procedure.function = buildFunction(); | |
184 procedure.function.parent = procedure; | |
185 procedure.isAbstract = isAbstract; | |
186 procedure.isStatic = isStatic; | |
187 procedure.isExternal = isExternal; | |
188 procedure.isConst = isConst; | |
189 procedure.name = new Name(name, library); | |
190 } | |
191 return procedure; | |
192 } | |
193 | |
194 KernelFunctionBuilder toConstructor(String name, | |
195 List<TypeVariableBuilder> classTypeVariables) { | |
196 assert(procedure.name == null); | |
197 assert(actualBody == null); | |
198 if (isFactory) { | |
199 if (this.typeVariables != null) { | |
200 return memberError(target, "Factories can't be generic."); | |
201 } | |
202 List<KernelTypeVariableBuilder> typeVariables; | |
203 KernelTypeBuilder returnType = this.returnType; | |
204 List<FormalParameterBuilder> formals; | |
205 if (classTypeVariables != null) { | |
206 typeVariables = <KernelTypeVariableBuilder>[]; | |
207 for (KernelTypeVariableBuilder variable in classTypeVariables) { | |
208 typeVariables.add(new KernelTypeVariableBuilder(variable.name)); | |
209 } | |
210 Map<TypeVariableBuilder, TypeBuilder> substitution = | |
211 <TypeVariableBuilder, TypeBuilder>{}; | |
212 int i = 0; | |
213 for (KernelTypeVariableBuilder variable in classTypeVariables) { | |
214 substitution[variable] = typeVariables[i++].asTypeBuilder(); | |
215 } | |
216 i = 0; | |
217 for (KernelTypeVariableBuilder variable in classTypeVariables) { | |
218 typeVariables[i++].bound = variable?.bound?.subst(substitution); | |
219 } | |
220 returnType = returnType?.subst(substitution); | |
221 i = 0; | |
222 if (this.formals != null) { | |
223 for (KernelFormalParameterBuilder formal in this.formals) { | |
224 KernelTypeBuilder type = formal.type?.subst(substitution); | |
225 if (type != formal.type) { | |
226 formals ??= this.formals.toList(); | |
227 formals[i] = new KernelFormalParameterBuilder(formal.metadata, | |
228 formal.modifiers, type, formal.name, formal.hasThis); | |
229 } | |
230 i++; | |
231 } | |
232 } | |
233 } | |
234 formals ??= this.formals; | |
235 return new KernelProcedureBuilder( | |
236 metadata, modifiers, returnType, name, typeVariables, formals, | |
237 actualAsyncModifier, kind, redirectionTarget) | |
238 ..parent = parent; | |
239 } else { | |
240 return new KernelConstructorBuilder(metadata, modifiers & ~abstractMask, | |
241 returnType, name, typeVariables, formals) | |
242 ..parent = parent; | |
243 } | |
244 } | |
245 | |
246 Procedure get target => procedure; | |
247 } | |
248 | |
249 // TODO(ahe): Move this to own file? | |
250 class KernelConstructorBuilder extends KernelFunctionBuilder { | |
251 final Constructor constructor = new Constructor(null); | |
252 | |
253 bool hasMovedSuperInitializer = false; | |
254 | |
255 SuperInitializer superInitializer; | |
256 | |
257 RedirectingInitializer redirectingInitializer; | |
258 | |
259 KernelConstructorBuilder( | |
260 List<MetadataBuilder> metadata, | |
261 int modifiers, KernelTypeBuilder returnType, String name, | |
262 List<TypeVariableBuilder> typeVariables, | |
263 List<FormalParameterBuilder> formals) | |
264 : super(metadata, modifiers, returnType, name, typeVariables, formals); | |
265 | |
266 bool get isInstanceMember => false; | |
267 | |
268 bool get isConstructor => true; | |
269 | |
270 AsyncMarker get asyncModifier => AsyncMarker.Sync; | |
271 | |
272 ProcedureKind get kind => null; | |
273 | |
274 Constructor build(Library library) { | |
275 if (constructor.name == null) { | |
276 constructor.function = buildFunction(); | |
277 constructor.function.parent = constructor; | |
278 constructor.isConst = isConst; | |
279 constructor.isExternal = isExternal; | |
280 constructor.name = new Name(name, library); | |
281 } | |
282 return constructor; | |
283 } | |
284 | |
285 FunctionNode buildFunction() { | |
286 // TODO(ahe): Should complain if another type is explicitly set. | |
287 return super.buildFunction() | |
288 ..returnType = const VoidType(); | |
289 } | |
290 | |
291 Constructor get target => constructor; | |
292 | |
293 void checkSuperOrThisInitializer(Initializer initializer) { | |
294 if (superInitializer != null || redirectingInitializer != null) { | |
295 memberError(target, | |
296 "Can't have more than one 'super' or 'this' initializer.", | |
297 initializer.fileOffset); | |
298 } | |
299 } | |
300 | |
301 void addInitializer(Initializer initializer) { | |
302 List<Initializer> initializers = constructor.initializers; | |
303 if (initializer is SuperInitializer) { | |
304 checkSuperOrThisInitializer(initializer); | |
305 superInitializer = initializer; | |
306 } else if (initializer is RedirectingInitializer) { | |
307 checkSuperOrThisInitializer(initializer); | |
308 redirectingInitializer = initializer; | |
309 if (constructor.initializers.isNotEmpty) { | |
310 memberError(target, "'this' initializer must be the only initializer.", | |
311 initializer.fileOffset); | |
312 } | |
313 } else if (redirectingInitializer != null) { | |
314 memberError(target, "'this' initializer must be the only initializer.", | |
315 initializer.fileOffset); | |
316 } else if (superInitializer != null && superInitializer != initializer) { | |
317 assert(initializers[initializers.length - 1] == superInitializer); | |
Johnni Winther
2017/01/18 12:42:40
Add documentation for what this case is.
ahe
2017/01/18 15:21:50
Done.
Writing the documentation made me realize a
| |
318 initializers[initializers.length - 1] = initializer..parent = constructor; | |
319 initializer = superInitializer; | |
320 if (!hasMovedSuperInitializer) { | |
321 hasMovedSuperInitializer = true; | |
322 Arguments arguments = superInitializer.arguments; | |
323 List<Expression> positional = arguments.positional; | |
324 for (int i = 0; i < positional.length; i++) { | |
Johnni Winther
2017/01/18 12:42:40
Add documentation for what you are doing here and
ahe
2017/01/18 15:21:50
Done.
| |
325 VariableDeclaration variable = | |
326 new VariableDeclaration.forValue(positional[i], isFinal: true); | |
327 initializers.add( | |
328 new LocalInitializer(variable)..parent = constructor); | |
329 positional[i] = new VariableGet(variable)..parent = arguments; | |
330 } | |
331 for (NamedExpression named in arguments.named) { | |
332 VariableDeclaration variable = | |
333 new VariableDeclaration.forValue(named.value, isFinal: true); | |
334 named.value = new VariableGet(variable)..parent = named; | |
335 initializers.add( | |
336 new LocalInitializer(variable)..parent = constructor); | |
337 } | |
338 } | |
339 } | |
340 initializers.add(initializer); | |
341 initializer.parent = constructor; | |
342 } | |
343 } | |
OLD | NEW |