ni_nitdoc: added fast copy past utility to signatures.
[nit.git] / src / auto_super_init.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 # Computing of super-constructors that must be implicitely called at the begin of constructors.
18 # The current rules are a bit crazy but whatever.
19 module auto_super_init
20
21 import typing
22 import modelbuilder
23 import phase
24
25 redef class ToolContext
26 var auto_super_init_phase: Phase = new AutoSuperInitPhase(self, [typing_phase])
27 end
28
29 private class AutoSuperInitPhase
30 super Phase
31 redef fun process_npropdef(npropdef) do if npropdef isa AConcreteMethPropdef then npropdef.do_auto_super_init(toolcontext.modelbuilder)
32 end
33
34 private class AutoSuperInitVisitor
35 super Visitor
36 init
37 do
38 end
39
40 redef fun visit(n)
41 do
42 if n == null then return
43 n.accept_auto_super_init(self)
44 n.visit_all(self)
45 end
46
47 var has_explicit_super_init: Bool = false
48 end
49
50
51 redef class AConcreteMethPropdef
52 # In case of constructor, the list of implicit auto super init constructors invoked (if needed)
53 var auto_super_inits: nullable Array[MMethod] = null
54
55 fun do_auto_super_init(modelbuilder: ModelBuilder)
56 do
57 var mclassdef = self.parent.as(AClassdef).mclassdef.as(not null)
58 var mpropdef = self.mpropdef.as(not null)
59 var mmodule = mpropdef.mclassdef.mmodule
60
61 # Collect only for constructors
62 if not mpropdef.mproperty.is_init then return
63
64 # FIXME: THIS IS STUPID (be here to keep the old code working)
65 if not mpropdef.mclassdef.is_intro then return
66
67 # Do we inherit for a constructor?
68 var skip = true
69 for cd in mclassdef.in_hierarchy.direct_greaters do
70 if cd.mclass.kind.need_init then skip = false
71 end
72 if skip then return
73
74 # Now we search for the absence of any explicit super-init invocation
75 # * via a "super"
76 # * via a call of an other init
77 var nblock = self.n_block
78 if nblock != null then
79 var v = new AutoSuperInitVisitor
80 v.enter_visit(nblock)
81 if v.has_explicit_super_init then return
82 end
83
84 # Still here? So it means that we must determine what super inits need to be automatically invoked
85
86 var auto_super_inits = new Array[MMethod]
87 for msupertype in mclassdef.supertypes do
88 # FIXME: the order is quite arbitrary
89 if not msupertype.mclass.kind.need_init then continue
90 msupertype = msupertype.anchor_to(mmodule, mclassdef.bound_mtype)
91 var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mpropdef.mproperty.name)
92 if candidate == null then
93 candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, "init")
94 end
95 if candidate == null then
96 modelbuilder.error(self, "Cannot do an implicit constructor call for {mpropdef}: there is no costructor named {mpropdef.mproperty.name} in {msupertype}.")
97 return
98 end
99 assert candidate isa MMethod
100 auto_super_inits.add(candidate)
101 end
102 if auto_super_inits.is_empty then
103 modelbuilder.error(self, "No constructors to call implicitely. Call one explicitely.")
104 return
105 end
106 for auto_super_init in auto_super_inits do
107 var auto_super_init_def = auto_super_init.intro
108 var msig = mpropdef.msignature.as(not null)
109 var supermsig = auto_super_init_def.msignature.as(not null)
110 if auto_super_init_def.msignature.arity != 0 and auto_super_init_def.msignature.arity != mpropdef.msignature.arity then
111 # TODO: Better check of the signature
112 modelbuilder.error(self, "Problem with signature of constructor {auto_super_init_def}{supermsig}. Expected {msig}")
113 end
114 end
115 self.auto_super_inits = auto_super_inits
116 end
117
118 end
119
120 redef class ANode
121 private fun accept_auto_super_init(v: AutoSuperInitVisitor) do end
122 end
123
124
125 redef class ASendExpr
126 redef fun accept_auto_super_init(v)
127 do
128 var mproperty = self.mproperty
129 if mproperty == null then return
130 if mproperty.is_init then
131 v.has_explicit_super_init = true
132 end
133 end
134 end
135
136 redef class ASuperExpr
137 redef fun accept_auto_super_init(v)
138 do
139 # If the super is a standard call-next-method then there it is considered am explicit super init call
140 # The the super is a "super int" then it is also an explicit super init call
141 v.has_explicit_super_init = true
142 end
143 end