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