92ee003d4d4c2e0bfa02f73a8dcd8aa9759e9164
[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 AMethPropdef 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: nullable ANode = null
47 end
48
49
50 redef class AMethPropdef
51 # In case of constructor, the list of implicit auto super init constructors invoked (if needed)
52 var auto_super_inits: nullable Array[CallSite] = 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 var anchor = mclassdef.bound_mtype
60 var recvtype = mclassdef.mclass.mclass_type
61
62 # Get the annotation, but check its pertinence before returning
63 var nosuper = get_single_annotation("nosuper", modelbuilder)
64
65 # Collect only for constructors
66 if not mpropdef.mproperty.is_init then
67 if nosuper != null then modelbuilder.error(nosuper, "Error: nosuper only in `init`")
68 return
69 end
70
71 # FIXME: THIS IS STUPID (be here to keep the old code working)
72 if not mpropdef.mclassdef.is_intro then return
73
74 # Do we inherit for a constructor?
75 var skip = true
76 for cd in mclassdef.in_hierarchy.direct_greaters do
77 if cd.mclass.kind.need_init then skip = false
78 end
79 if skip then return
80
81 # Now we search for the absence of any explicit super-init invocation
82 # * via a "super"
83 # * via a call of an other init
84 var nblock = self.n_block
85 if nblock != null then
86 var v = new AutoSuperInitVisitor
87 v.enter_visit(nblock)
88 var anode = v.has_explicit_super_init
89 if anode != null then
90 if nosuper != null then modelbuilder.error(anode, "Error: method is annotated nosuper but a constructor call is present")
91 return
92 end
93 end
94
95 if nosuper != null then return
96
97 # Still here? So it means that we must determine what super inits need to be automatically invoked
98
99 var auto_super_inits = new Array[CallSite]
100 for msupertype in mclassdef.supertypes do
101 # FIXME: the order is quite arbitrary
102 if not msupertype.mclass.kind.need_init then continue
103 msupertype = msupertype.anchor_to(mmodule, mclassdef.bound_mtype)
104 var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mpropdef.mproperty.name)
105 if candidate == null then
106 candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, "init")
107 end
108 if candidate == null then
109 modelbuilder.error(self, "Error: Cannot do an implicit constructor call in {mpropdef}; there is no constructor named {mpropdef.mproperty.name} in {msupertype}.")
110 return
111 end
112 assert candidate isa MMethod
113
114 var candidatedefs = candidate.lookup_definitions(mmodule, anchor)
115 var candidatedef = candidatedefs.first
116 # TODO, we drop the others propdefs in the callsite, that is not great :(
117
118 var msignature = candidatedef.msignature
119 msignature = msignature.resolve_for(recvtype, anchor, mmodule, true)
120
121 var callsite = new CallSite(self, recvtype, mmodule, anchor, true, candidate, candidatedef, msignature, false)
122 auto_super_inits.add(callsite)
123 end
124 if auto_super_inits.is_empty then
125 modelbuilder.error(self, "Error: No constructors to call implicitely in {mpropdef}. Call one explicitely.")
126 return
127 end
128 for auto_super_init in auto_super_inits do
129 var auto_super_init_def = auto_super_init.mpropdef
130 var msig = mpropdef.msignature.as(not null)
131 var supermsig = auto_super_init.msignature
132 if supermsig.arity > msig.arity then
133 modelbuilder.error(self, "Error: Cannot do an implicit constructor call to {auto_super_init_def}{supermsig}. Expected at least {supermsig.arity} arguments, got {msig.arity}.")
134 continue
135 end
136 var i = 0
137 for sp in supermsig.mparameters do
138 var p = msig.mparameters[i]
139 var sub = p.mtype
140 var sup = sp.mtype
141 if not sub.is_subtype(mmodule, anchor, sup) then
142 modelbuilder.error(self, "Error: Cannot do an implicit constructor call to {auto_super_init_def}{supermsig}. Expected argument #{i} of type {sp.mtype}, got implicit argument {p.name} of type {p.mtype}.")
143 break
144 end
145 i += 1
146 end
147 end
148 self.auto_super_inits = auto_super_inits
149 end
150
151 end
152
153 redef class ANode
154 private fun accept_auto_super_init(v: AutoSuperInitVisitor) do end
155 end
156
157
158 redef class ASendExpr
159 redef fun accept_auto_super_init(v)
160 do
161 var mproperty = self.callsite.mproperty
162 if mproperty == null then return
163 if mproperty.is_init then
164 v.has_explicit_super_init = self
165 end
166 end
167 end
168
169 redef class ASuperExpr
170 redef fun accept_auto_super_init(v)
171 do
172 # If the super is a standard call-next-method then there it is considered am explicit super init call
173 # The the super is a "super int" then it is also an explicit super init call
174 v.has_explicit_super_init = self
175 end
176 end