rta: do not enter in annotations
[nit.git] / src / rapid_type_analysis.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17
18 # Rapid type analysis on the AST with heterogenous generics and customization
19 #
20 # Rapid type analysis is an analyse that aproximates the set of live classes
21 # and the set of live methods starting from the entry point of the program.
22 # These two sets are interdependant and computed together.
23 # It is quite efficient but the type set is global and pollutes each call site.
24 #
25 # Heterogenous generics means that each intancied generic class is associated
26 # to a distinct rapid type.
27 # Heterogenous generics has the advantage to resolve the formal generic
28 # parameters types but increase the number of types.
29 # More important, heterogenous generics cannot deal with infinite number of rapid
30 # types since the analyse tries to list them all (so some programs will be badly refused)
31 #
32 # Customization means that each method definition is analyzed one per rapid
33 # type of receiver.
34 # Customization have the following advantages:
35 # * `self' is monomorphic
36 # * virtual types are all resolved
37 # * live attributes can be determined on each class
38 # But has the disadvantage to explode the number of rapid method: each method
39 # definition for each rapid type that need it
40 module rapid_type_analysis
41
42 import model
43 import modelbuilder
44 import typing
45 import auto_super_init
46
47 redef class ModelBuilder
48 fun do_rapid_type_analysis(mainmodule: MModule): RapidTypeAnalysis
49 do
50 var model = self.model
51 var analysis = new RapidTypeAnalysis(self, mainmodule)
52 var nmodule = self.nmodules.first
53 var maintype = mainmodule.sys_type
54 if maintype == null then return analysis # No entry point
55 analysis.add_type(maintype)
56 var initprop = mainmodule.try_get_primitive_method("init", maintype)
57 if initprop != null then
58 analysis.add_monomorphic_send(maintype, initprop)
59 end
60 var mainprop = mainmodule.try_get_primitive_method("main", maintype)
61 if mainprop != null then
62 analysis.add_monomorphic_send(maintype, mainprop)
63 end
64 analysis.run_analysis
65 return analysis
66 end
67 end
68
69 # RapidTypeAnalysis looks for alive rapid types in application.
70 # The entry point of the analysis is the mainmodule of the application.
71 class RapidTypeAnalysis
72 # The modelbuilder used to get the AST.
73 var modelbuilder: ModelBuilder
74
75 # The main module of the analysis.
76 # Used to perform types operations.
77 var mainmodule: MModule
78
79 # The pool to live types.
80 # During the analysis, new types are added and combined with
81 # live_send_sites to determine new customized_methoddefs to visit
82 var live_types: HashSet[MClassType] = new HashSet[MClassType]
83
84 # The pool of types used to perform type checks (isa and as).
85 var live_cast_types: HashSet[MClassType] = new HashSet[MClassType]
86
87 # Live method definitions.
88 # These method definitions are:
89 # * visited trough a add_send on an already known live_type
90 # * visited trough a add_type for an already known live_send_sites
91 # * visided by a add_monomorphic_send or a add_static_call
92 var live_methoddefs: HashSet[MMethodDef] = new HashSet[MMethodDef]
93
94 # The pool of live customized method definitions
95 var live_customized_methoddefs: HashSet[CustomizedMethodDef] = new HashSet[CustomizedMethodDef]
96
97 # The pool of live RTA send site
98 # During the analysis, new live_send_sites are added and combined with
99 # live_types to determine new live_customized_methoddefs to visit
100 var live_send_sites: HashSet[RTASendSite] = new HashSet[RTASendSite]
101
102 # The customized method definitions that remain to visit
103 private var todo: List[CustomizedMethodDef] = new List[CustomizedMethodDef]
104
105 # Adapt and remove nullable
106 # return null if we got the null type
107 fun cleanup_type(mtype: MType, recvtype: MClassType): nullable MClassType
108 do
109 mtype = mtype.anchor_to(self.mainmodule, recvtype)
110 if mtype isa MNullType then return null
111 if mtype isa MNullableType then mtype = mtype.mtype
112 assert mtype isa MClassType
113 assert not mtype.need_anchor
114 return mtype
115 end
116
117 # Add a live type to the pool
118 #
119 # If the types is already live, then do nothing.
120 #
121 # REQUIRE: not mtype.need_anchor
122 fun add_type(mtype: MClassType)
123 do
124 if self.live_types.has(mtype) then return
125
126 assert not mtype.need_anchor
127 self.live_types.add(mtype)
128 self.check_depth(mtype)
129
130 # Collect default attributes
131 for cd in mtype.collect_mclassdefs(self.mainmodule)
132 do
133 var nclassdef = self.modelbuilder.mclassdef2nclassdef[cd]
134 for npropdef in nclassdef.n_propdefs do
135 if not npropdef isa AAttrPropdef then continue
136 var nexpr = npropdef.n_expr
137 if nexpr == null then continue
138 var v = new RapidTypeVisitor(self, nclassdef, npropdef.mpropdef.as(not null), mtype)
139 v.enter_visit(nexpr)
140 end
141 end
142
143 for rss in self.live_send_sites do
144 if not mtype.is_subtype(self.mainmodule, null, rss.receiver) then continue
145 if mtype.has_mproperty(self.mainmodule, rss.mmethod) then
146 self.add_monomorphic_send(mtype, rss.mmethod)
147 end
148 end
149 end
150
151 # Add a send site to the pool
152 #
153 # If the send site is already live, then do nothing.
154 fun add_send(mtype: MClassType, mmethod: MMethod)
155 do
156 var rss = new RTASendSite(mmethod, mtype)
157 if self.live_send_sites.has(rss) then return
158
159 self.live_send_sites.add(rss)
160
161 for mtype2 in self.live_types do
162 if not mtype2.is_subtype(self.mainmodule, null, mtype) then continue
163 if mtype2.has_mproperty(self.mainmodule, mmethod) then
164 self.add_monomorphic_send(mtype2, mmethod)
165 end
166 end
167 end
168
169 # Add a monomoprhic send.
170 # The send site is not added to the pool.
171 # The method just determine the associated method definition then
172 # performs a static_call
173 fun add_monomorphic_send(mtype: MClassType, mmethod: MMethod)
174 do
175 assert self.live_types.has(mtype)
176 if not mtype.has_mproperty(self.mainmodule, mmethod) then return
177 var def = mmethod.lookup_first_definition(self.mainmodule, mtype)
178 self.add_static_call(mtype, def)
179 end
180
181 # Add a customized_methoddefs to the pool
182 # Is the customized_methoddefs is already live, then do nothing
183 fun add_static_call(mtype: MClassType, mmethoddef: MMethodDef)
184 do
185 assert self.live_types.has(mtype)
186 var rm = new CustomizedMethodDef(mmethoddef, mtype)
187 if self.live_customized_methoddefs.has(rm) then return
188 self.live_customized_methoddefs.add(rm)
189 self.todo.add(rm)
190 self.live_methoddefs.add(mmethoddef)
191 end
192
193 # Add mtype to the cast pool.
194 fun add_cast_type(mtype: MClassType)
195 do
196 if self.live_cast_types.has(mtype) then return
197
198 assert not mtype.need_anchor
199 self.live_cast_types.add(mtype)
200 self.check_depth(mtype)
201 end
202
203 fun check_depth(mtype: MClassType)
204 do
205 var d = mtype.depth
206 if d > 255 then
207 self.modelbuilder.toolcontext.fatal_error(null, "Fatal error: limitation in the rapidtype analysis engine: a type depth of {d} is too important, the problematic type is {mtype}.")
208 end
209 end
210
211 # Run the analysis until all visitable method definitions are visited.
212 fun run_analysis
213 do
214 # Force Bool
215 var classes = self.modelbuilder.model.get_mclasses_by_name("Bool")
216 if classes != null then for c in classes do self.add_type(c.mclass_type)
217
218 while not todo.is_empty do
219 var mr = todo.shift
220
221 var vararg_rank = mr.mmethoddef.msignature.vararg_rank
222 if vararg_rank > -1 then
223 var node = self.modelbuilder.mpropdef2npropdef[mr.mmethoddef]
224 var elttype = mr.mmethoddef.msignature.mparameters[vararg_rank].mtype
225 elttype = elttype.anchor_to(self.mainmodule, mr.receiver)
226 var vararg = self.mainmodule.get_primitive_class("Array").get_mtype([elttype])
227 self.add_type(vararg)
228 self.add_monomorphic_send(vararg, self.modelbuilder.force_get_primitive_method(node, "with_native", vararg, self.mainmodule))
229 var native = self.mainmodule.get_primitive_class("NativeArray").get_mtype([elttype])
230 self.add_type(native)
231 end
232
233 for i in [0..mr.mmethoddef.msignature.arity[ do
234 var origtype = mr.mmethoddef.mproperty.intro.msignature.mparameters[i].mtype
235 if not origtype.need_anchor then continue # skip non covariant stuff
236 var paramtype = mr.mmethoddef.msignature.mparameters[i].mtype
237 paramtype = self.cleanup_type(paramtype, mr.receiver).as(not null)
238 self.add_cast_type(paramtype)
239 end
240
241 if not self.modelbuilder.mpropdef2npropdef.has_key(mr.mmethoddef) then
242 # It is an init for a class?
243 if mr.mmethoddef.mproperty.name == "init" then
244 var nclassdef = self.modelbuilder.mclassdef2nclassdef[mr.mmethoddef.mclassdef]
245 var super_inits = nclassdef.super_inits
246 if super_inits != null then
247 #assert args.length == 1
248 for su in super_inits do
249 self.add_monomorphic_send(mr.receiver, su)
250 end
251 end
252
253 else
254 abort
255 end
256 continue
257 end
258 var npropdef = self.modelbuilder.mpropdef2npropdef[mr.mmethoddef]
259 if npropdef isa AConcreteMethPropdef then
260 #npropdef.debug("Visit {mr.mmethoddef} for {mr.receiver}")
261 var nclassdef = npropdef.parent.as(AClassdef)
262 var mmethoddef = npropdef.mpropdef.as(not null)
263 var auto_super_inits = npropdef.auto_super_inits
264 if auto_super_inits != null then
265 for auto_super_init in auto_super_inits do
266 self.add_monomorphic_send(mr.receiver, auto_super_init)
267 end
268 end
269 var v = new RapidTypeVisitor(self, nclassdef, mmethoddef, mr.receiver)
270 v.enter_visit(npropdef.n_block)
271 else if npropdef isa ADeferredMethPropdef then
272 # nothing to do (maybe add a waring?)
273 else if npropdef isa AAttrPropdef then
274 # nothing to do
275 else if npropdef isa AInternMethPropdef or npropdef isa AExternMethPropdef then
276 # UGLY: We force the "instantation" of the concrete return type if any
277 var ret = mr.mmethoddef.msignature.return_mtype
278 if ret != null and ret isa MClassType and ret.mclass.kind != abstract_kind and ret.mclass.kind != interface_kind then
279 ret = ret.anchor_to(self.mainmodule, mr.receiver)
280 self.add_type(ret)
281 end
282 else if npropdef isa AExternInitPropdef then
283 self.add_type(mr.receiver)
284 else
285 npropdef.debug("Not yet implemented")
286 abort
287 end
288 end
289 end
290 end
291
292 # A method definitions customized to a specific receiver
293 class CustomizedMethodDef
294 var mmethoddef: MMethodDef
295 var receiver: MClassType
296
297 redef fun to_s
298 do
299 return "{self.mmethoddef}({receiver})"
300 end
301
302 redef fun ==(o)
303 do
304 return o isa CustomizedMethodDef and o.mmethoddef == self.mmethoddef and o.receiver == self.receiver
305 end
306
307 redef fun hash
308 do
309 return self.mmethoddef.hash + self.receiver.hash
310 end
311 end
312
313 # A method invokation site bounded by a specific receiver
314 class RTASendSite
315 var mmethod: MMethod
316 var receiver: MClassType
317
318 redef fun ==(o)
319 do
320 return o isa RTASendSite and o.mmethod == self.mmethod and o.receiver == self.receiver
321 end
322
323 redef fun hash
324 do
325 return self.mmethod.hash + self.receiver.hash
326 end
327 end
328
329 private class RapidTypeVisitor
330 super Visitor
331
332 var analysis: RapidTypeAnalysis
333
334 var nclassdef: AClassdef
335
336 var mpropdef: MPropDef
337
338 var receiver: MClassType
339
340 init(analysis: RapidTypeAnalysis, nclassdef: AClassdef, mpropdef: MPropDef, receiver: MClassType)
341 do
342 self.analysis = analysis
343 self.nclassdef = nclassdef
344 self.mpropdef = mpropdef
345 self.receiver = receiver
346 end
347
348 # Adapt and remove nullable
349 # return null if we got the null type
350 fun cleanup_type(mtype: MType): nullable MClassType
351 do
352 mtype = mtype.anchor_to(self.analysis.mainmodule, self.receiver)
353 if mtype isa MNullType then return null
354 if mtype isa MNullableType then mtype = mtype.mtype
355 assert mtype isa MClassType
356 assert not mtype.need_anchor
357 return mtype
358 end
359
360 fun add_type(mtype: MType)
361 do
362 var rapidtype = cleanup_type(mtype)
363 if rapidtype == null then return # we do not care about null
364
365 self.analysis.add_type(rapidtype)
366 #self.current_node.debug("add_type {rapidtype}")
367 end
368
369 fun add_send(mtype: MType, mproperty: MMethod)
370 do
371 var rapidtype = cleanup_type(mtype)
372 if rapidtype == null then return # we do not care about null
373
374 analysis.add_send(rapidtype, mproperty)
375 #self.current_node.debug("add_send {mproperty}")
376 end
377
378 fun add_monomorphic_send(mtype: MType, mproperty: MMethod)
379 do
380 var rapidtype = cleanup_type(mtype)
381 if rapidtype == null then return # we do not care about null
382
383 self.analysis.add_monomorphic_send(rapidtype, mproperty)
384 #self.current_node.debug("add_monomorphic_send {rapidtype} {mproperty}")
385 end
386
387 fun add_cast_type(mtype: MType)
388 do
389 var rapidtype = cleanup_type(mtype)
390 if rapidtype == null then return # we do not care about null
391
392 self.analysis.add_cast_type(rapidtype)
393 #self.current_node.debug("add_cast_type {rapidtype}")
394 end
395
396 redef fun visit(node)
397 do
398 if node == null then return
399 node.accept_rapid_type_vistor(self)
400 if node isa AExpr then
401 var implicit_cast_to = node.implicit_cast_to
402 if implicit_cast_to != null then self.add_cast_type(implicit_cast_to)
403 end
404 # RTA does not enter in AAnnotations
405 if not node isa AAnnotations then
406 node.visit_all(self)
407 end
408 end
409
410 # Force to get the primitive class named `name' or abort
411 fun get_class(name: String): MClass
412 do
413 return self.analysis.mainmodule.get_primitive_class(name)
414 end
415
416 # Force to get the primitive property named `name' in the instance `recv' or abort
417 fun get_method(recv: MType, name: String): MMethod
418 do
419 var rapidtype = cleanup_type(recv)
420 if rapidtype == null then abort
421
422 return self.analysis.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, rapidtype, self.analysis.mainmodule)
423 end
424 end
425
426 ###
427
428 redef class ANode
429 private fun accept_rapid_type_vistor(v: RapidTypeVisitor)
430 do
431 end
432 end
433
434 redef class AIntExpr
435 redef fun accept_rapid_type_vistor(v)
436 do
437 v.add_type(self.mtype.as(not null))
438 end
439 end
440
441 redef class AFloatExpr
442 redef fun accept_rapid_type_vistor(v)
443 do
444 v.add_type(self.mtype.as(not null))
445 end
446 end
447
448 redef class ACharExpr
449 redef fun accept_rapid_type_vistor(v)
450 do
451 v.add_type(self.mtype.as(not null))
452 end
453 end
454
455 redef class AArrayExpr
456 redef fun accept_rapid_type_vistor(v)
457 do
458 var mtype = self.mtype.as(MClassType)
459 v.add_type(mtype)
460 var native = v.get_class("NativeArray").get_mtype([mtype.arguments.first])
461 v.add_type(native)
462 var prop = v.get_method(mtype, "with_native")
463 v.add_monomorphic_send(mtype, prop)
464 end
465 end
466
467 redef class AStringFormExpr
468 redef fun accept_rapid_type_vistor(v)
469 do
470 var mtype = self.mtype.as(not null)
471 v.add_type(mtype)
472 var native = v.get_class("NativeString").mclass_type
473 v.add_type(native)
474 var prop = v.get_method(mtype, "from_cstring")
475 v.add_monomorphic_send(mtype, prop)
476 end
477 end
478
479 redef class ASuperstringExpr
480 redef fun accept_rapid_type_vistor(v)
481 do
482 var arraytype = v.get_class("Array").get_mtype([v.get_class("Object").mclass_type])
483 v.add_type(arraytype)
484 v.add_type(v.get_class("NativeArray").get_mtype([v.get_class("Object").mclass_type]))
485 var prop = v.get_method(arraytype, "join")
486 v.add_monomorphic_send(arraytype, prop)
487 var prop2 = v.get_method(arraytype, "with_native")
488 v.add_monomorphic_send(arraytype, prop2)
489 end
490 end
491
492 redef class ACrangeExpr
493 redef fun accept_rapid_type_vistor(v)
494 do
495 var mtype = self.mtype.as(not null)
496 v.add_type(mtype)
497 var prop = v.get_method(mtype, "init")
498 v.add_monomorphic_send(mtype, prop)
499 end
500 end
501
502 redef class AOrangeExpr
503 redef fun accept_rapid_type_vistor(v)
504 do
505 var mtype = self.mtype.as(not null)
506 v.add_type(mtype)
507 var prop = v.get_method(mtype, "without_last")
508 v.add_monomorphic_send(mtype, prop)
509 end
510 end
511
512 redef class ATrueExpr
513 redef fun accept_rapid_type_vistor(v)
514 do
515 v.add_type(self.mtype.as(not null))
516 end
517 end
518
519 redef class AFalseExpr
520 redef fun accept_rapid_type_vistor(v)
521 do
522 v.add_type(self.mtype.as(not null))
523 end
524 end
525
526 redef class AIsaExpr
527 redef fun accept_rapid_type_vistor(v)
528 do
529 v.add_cast_type(self.cast_type.as(not null))
530 end
531 end
532
533 redef class AAsCastExpr
534 redef fun accept_rapid_type_vistor(v)
535 do
536 v.add_cast_type(self.mtype.as(not null))
537 end
538 end
539
540 #
541
542 redef class ASendExpr
543 redef fun accept_rapid_type_vistor(v)
544 do
545 var mproperty = self.mproperty.as(not null)
546 if n_expr isa ASelfExpr then
547 v.add_monomorphic_send(v.receiver, mproperty)
548 else
549 var recvtype = self.n_expr.mtype.as(not null)
550 v.add_send(recvtype, mproperty)
551 end
552 end
553 end
554
555 redef class ASendReassignFormExpr
556 redef fun accept_rapid_type_vistor(v)
557 do
558 v.add_send(self.read_type.as(not null), self.reassign_property.mproperty)
559 var mproperty = self.mproperty.as(not null)
560 var write_mproperty = self.write_mproperty.as(not null)
561 if n_expr isa ASelfExpr then
562 v.add_monomorphic_send(v.receiver, mproperty)
563 v.add_monomorphic_send(v.receiver, write_mproperty)
564 else
565 var recvtype = self.n_expr.mtype.as(not null)
566 v.add_send(recvtype, mproperty)
567 v.add_send(recvtype, write_mproperty)
568 end
569 end
570 end
571
572 redef class AVarReassignExpr
573 redef fun accept_rapid_type_vistor(v)
574 do
575 v.add_send(self.read_type.as(not null), self.reassign_property.mproperty)
576 end
577 end
578
579 redef class AAttrReassignExpr
580 redef fun accept_rapid_type_vistor(v)
581 do
582 v.add_send(self.read_type.as(not null), self.reassign_property.mproperty)
583 end
584 end
585
586 redef class ASuperExpr
587 redef fun accept_rapid_type_vistor(v)
588 do
589 var mproperty = self.mproperty
590 if mproperty != null then
591 v.add_monomorphic_send(v.receiver, mproperty)
592 return
593 end
594
595 #FIXME: we do not want an ugly static call!
596 var mpropdef = v.mpropdef
597 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
598 if mpropdefs.length != 1 then
599 debug("MPRODFEFS for super {mpropdef} for {v.receiver}: {mpropdefs.join(", ")}")
600 end
601 var msuperpropdef = mpropdefs.first
602 assert msuperpropdef isa MMethodDef
603 v.analysis.add_static_call(v.receiver, msuperpropdef)
604 end
605 end
606
607 redef class AForExpr
608 redef fun accept_rapid_type_vistor(v)
609 do
610 var recvtype = self.n_expr.mtype.as(not null)
611 var colltype = self.coltype.as(not null)
612 var itmeth = v.get_method(colltype, "iterator")
613 v.add_send(recvtype, itmeth)
614 var iteratortype = itmeth.intro.msignature.return_mtype.as(MClassType).mclass.intro.bound_mtype
615 var objtype = v.get_class("Object").mclass_type
616 v.add_send(objtype, v.get_method(iteratortype, "is_ok"))
617 if self.variables.length == 1 then
618 v.add_send(objtype, v.get_method(iteratortype, "item"))
619 else if self.variables.length == 2 then
620 v.add_send(objtype, v.get_method(iteratortype, "key"))
621 v.add_send(objtype, v.get_method(iteratortype, "item"))
622 else
623 abort
624 end
625 v.add_send(objtype, v.get_method(iteratortype, "next"))
626 end
627 end
628
629 redef class ANewExpr
630 redef fun accept_rapid_type_vistor(v)
631 do
632 var recvtype = self.mtype.as(not null)
633 v.add_type(recvtype)
634 v.add_monomorphic_send(recvtype, mproperty.as(not null))
635 end
636 end