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