frontend: move `MPropDef::has_supercall` to `modelize_property`
[nit.git] / src / modelize_property.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 # Analysis and verification of property definitions to instantiate model element
18 module modelize_property
19
20 import modelize_class
21
22 redef class ToolContext
23 var modelize_property_phase: Phase = new ModelizePropertyPhase(self, [modelize_class_phase])
24 end
25
26 private class ModelizePropertyPhase
27 super Phase
28 redef fun process_nmodule(nmodule)
29 do
30 for nclassdef in nmodule.n_classdefs do
31 toolcontext.modelbuilder.build_properties(nclassdef)
32 end
33 end
34 end
35
36 redef class ModelBuilder
37 # Register the npropdef associated to each mpropdef
38 # FIXME: why not refine the `MPropDef` class with a nullable attribute?
39 var mpropdef2npropdef: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
40
41 # Build the properties of `nclassdef`.
42 # REQUIRE: all superclasses are built.
43 private fun build_properties(nclassdef: AClassdef)
44 do
45 # Force building recursively
46 if nclassdef.build_properties_is_done then return
47 nclassdef.build_properties_is_done = true
48 var mclassdef = nclassdef.mclassdef.as(not null)
49 if mclassdef.in_hierarchy == null then return # Skip error
50 for superclassdef in mclassdef.in_hierarchy.direct_greaters do
51 build_properties(mclassdef2nclassdef[superclassdef])
52 end
53
54 for npropdef in nclassdef.n_propdefs do
55 npropdef.build_property(self, nclassdef)
56 end
57 for npropdef in nclassdef.n_propdefs do
58 npropdef.build_signature(self, nclassdef)
59 end
60 for npropdef in nclassdef.n_propdefs do
61 npropdef.check_signature(self, nclassdef)
62 end
63 process_default_constructors(nclassdef)
64 end
65
66 # Introduce or inherit default constructor
67 # This is the last part of `build_properties`.
68 private fun process_default_constructors(nclassdef: AClassdef)
69 do
70 var mclassdef = nclassdef.mclassdef.as(not null)
71
72 # Are we a refinement
73 if not mclassdef.is_intro then return
74
75 # Is the class forbid constructors?
76 if not mclassdef.mclass.kind.need_init then return
77
78 # Is there already a constructor defined?
79 for mpropdef in mclassdef.mpropdefs do
80 if not mpropdef isa MMethodDef then continue
81 if mpropdef.mproperty.is_init then return
82 end
83
84 if not nclassdef isa AStdClassdef then return
85
86 var mmodule = nclassdef.mclassdef.mmodule
87 # Do we inherit for a constructor?
88 var combine = new Array[MMethod]
89 var inhc: nullable MClass = null
90 for st in mclassdef.supertypes do
91 var c = st.mclass
92 if not c.kind.need_init then continue
93 st = st.anchor_to(mmodule, nclassdef.mclassdef.bound_mtype)
94 var candidate = self.try_get_mproperty_by_name2(nclassdef, mmodule, st, "init").as(nullable MMethod)
95 if candidate != null and candidate.intro.msignature.arity == 0 then
96 combine.add(candidate)
97 continue
98 end
99 var inhc2 = c.inherit_init_from
100 if inhc2 == null then inhc2 = c
101 if inhc2 == inhc then continue
102 if inhc != null then
103 self.error(nclassdef, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
104 else
105 inhc = inhc2
106 end
107 end
108 if combine.is_empty and inhc != null then
109 # TODO: actively inherit the consturctor
110 self.toolcontext.info("{mclassdef} inherits all constructors from {inhc}", 3)
111 mclassdef.mclass.inherit_init_from = inhc
112 return
113 end
114 if not combine.is_empty and inhc != null then
115 self.error(nclassdef, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
116 return
117 end
118
119 if not combine.is_empty then
120 nclassdef.super_inits = combine
121 var mprop = new MMethod(mclassdef, "init", mclassdef.mclass.visibility)
122 var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
123 var mparameters = new Array[MParameter]
124 var msignature = new MSignature(mparameters, null)
125 mpropdef.msignature = msignature
126 mprop.is_init = true
127 nclassdef.mfree_init = mpropdef
128 self.toolcontext.info("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
129 return
130 end
131
132 # Collect undefined attributes
133 var mparameters = new Array[MParameter]
134 for npropdef in nclassdef.n_propdefs do
135 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
136 if npropdef.mpropdef == null then return # Skip broken attribute
137 var paramname = npropdef.mpropdef.mproperty.name.substring_from(1)
138 var ret_type = npropdef.mpropdef.static_mtype
139 if ret_type == null then return
140 var mparameter = new MParameter(paramname, ret_type, false)
141 mparameters.add(mparameter)
142 end
143 end
144
145 var mprop = new MMethod(mclassdef, "init", mclassdef.mclass.visibility)
146 var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
147 var msignature = new MSignature(mparameters, null)
148 mpropdef.msignature = msignature
149 mprop.is_init = true
150 nclassdef.mfree_init = mpropdef
151 self.toolcontext.info("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
152 end
153 end
154
155 redef class MClass
156 # The class whose self inherit all the constructors.
157 # FIXME: this is needed to implement the crazy constructor mixin thing of the of old compiler. We need to think what to do with since this cannot stay in the modelbuilder
158 var inherit_init_from: nullable MClass = null
159 end
160
161 redef class MClassDef
162 private var propdef_names = new HashSet[String]
163 end
164
165 redef class MPropDef
166 # Does the MPropDef contains a call to super or a call of a super-constructor?
167 # Subsequent phases of the frontend (esp. typing) set it if required
168 var has_supercall: Bool writable = false
169 end
170
171 redef class AClassdef
172 var build_properties_is_done: Bool = false
173 # The list of super-constructor to call at the start of the free constructor
174 # FIXME: this is needed to implement the crazy constructor thing of the of old compiler. We need to think what to do with since this cannot stay in the modelbuilder
175 var super_inits: nullable Collection[MMethod] = null
176
177 # The free init (implicitely constructed by the class if required)
178 var mfree_init: nullable MMethodDef = null
179
180 # What is the `APropdef` associated to a `MProperty`?
181 # Used to check multiple definition of a property.
182 var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
183 end
184
185 redef class Prod
186 # Join the text of all tokens
187 # Used to get the 'real name' of method definitions.
188 fun collect_text: String
189 do
190 var v = new TextCollectorVisitor
191 v.enter_visit(self)
192 assert v.text != ""
193 return v.text
194 end
195 end
196
197 private class TextCollectorVisitor
198 super Visitor
199 var text: String = ""
200 redef fun visit(n)
201 do
202 if n isa Token then text += n.text
203 n.visit_all(self)
204 end
205 end
206
207 redef class APropdef
208 # The associated main model entity
209 type MPROPDEF: MPropDef
210
211 # The associated propdef once build by a `ModelBuilder`
212 var mpropdef: nullable MPROPDEF writable
213
214 private fun build_property(modelbuilder: ModelBuilder, nclassdef: AClassdef) is abstract
215 private fun build_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef) is abstract
216 private fun check_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef) is abstract
217 private fun new_property_visibility(modelbuilder: ModelBuilder, nclassdef: AClassdef, nvisibility: nullable AVisibility): MVisibility
218 do
219 var mvisibility = public_visibility
220 if nvisibility != null then
221 mvisibility = nvisibility.mvisibility
222 if mvisibility == intrude_visibility then
223 modelbuilder.error(nvisibility, "Error: intrude is not a legal visibility for properties.")
224 mvisibility = public_visibility
225 end
226 end
227 if nclassdef.mclassdef.mclass.visibility == private_visibility then
228 if mvisibility == protected_visibility then
229 assert nvisibility != null
230 modelbuilder.error(nvisibility, "Error: The only legal visibility for properties in a private class is private.")
231 else if mvisibility == private_visibility then
232 assert nvisibility != null
233 # Not yet
234 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
235 end
236 mvisibility = private_visibility
237 end
238 return mvisibility
239 end
240
241 private fun check_redef_property_visibility(modelbuilder: ModelBuilder, nclassdef: AClassdef, nvisibility: nullable AVisibility, mprop: MProperty)
242 do
243 if nvisibility == null then return
244 var mvisibility = nvisibility.mvisibility
245 if mvisibility != mprop.visibility and mvisibility != public_visibility then
246 modelbuilder.error(nvisibility, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
247 end
248 end
249
250 private fun check_redef_keyword(modelbuilder: ModelBuilder, nclassdef: AClassdef, kwredef: nullable Token, need_redef: Bool, mprop: MProperty): Bool
251 do
252 if nclassdef.mprop2npropdef.has_key(mprop) then
253 modelbuilder.error(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
254 return false
255 end
256 if kwredef == null then
257 if need_redef then
258 modelbuilder.error(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
259 return false
260 end
261 else
262 if not need_redef then
263 modelbuilder.error(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
264 return false
265 end
266 end
267 return true
268 end
269
270 end
271
272 redef class ASignature
273 # Is the model builder has correctly visited the signature
274 var is_visited = false
275 # Names of parameters from the AST
276 # REQUIRE: is_visited
277 var param_names = new Array[String]
278 # Types of parameters from the AST
279 # REQUIRE: is_visited
280 var param_types = new Array[MType]
281 # Rank of the vararg (of -1 if none)
282 # REQUIRE: is_visited
283 var vararg_rank: Int = -1
284 # Return type
285 var ret_type: nullable MType = null
286
287 # Visit and fill information about a signature
288 private fun visit_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef): Bool
289 do
290 var param_names = self.param_names
291 var param_types = self.param_types
292 for np in self.n_params do
293 param_names.add(np.n_id.text)
294 var ntype = np.n_type
295 if ntype != null then
296 var mtype = modelbuilder.resolve_mtype(nclassdef, ntype)
297 if mtype == null then return false # Skip error
298 for i in [0..param_names.length-param_types.length[ do
299 param_types.add(mtype)
300 end
301 if np.n_dotdotdot != null then
302 if self.vararg_rank != -1 then
303 modelbuilder.error(np, "Error: {param_names[self.vararg_rank]} is already a vararg")
304 return false
305 else
306 self.vararg_rank = param_names.length - 1
307 end
308 end
309 end
310 end
311 var ntype = self.n_type
312 if ntype != null then
313 self.ret_type = modelbuilder.resolve_mtype(nclassdef, ntype)
314 if self.ret_type == null then return false # Skip errir
315 end
316
317 self.is_visited = true
318 return true
319 end
320
321 # Build a visited signature
322 fun build_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef): nullable MSignature
323 do
324 if param_names.length != param_types.length then
325 # Some parameters are typed, other parameters are not typed.
326 modelbuilder.error(self.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
327 return null
328 end
329
330 var mparameters = new Array[MParameter]
331 for i in [0..param_names.length[ do
332 var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
333 self.n_params[i].mparameter = mparameter
334 mparameters.add(mparameter)
335 end
336
337 var msignature = new MSignature(mparameters, ret_type)
338 return msignature
339 end
340 end
341
342 redef class AParam
343 # The associated mparameter if any
344 var mparameter: nullable MParameter = null
345 end
346
347 redef class AMethPropdef
348 redef type MPROPDEF: MMethodDef
349
350 redef fun build_property(modelbuilder, nclassdef)
351 do
352 var is_init = self isa AInitPropdef
353 var mclassdef = nclassdef.mclassdef.as(not null)
354 var name: String
355 var amethodid = self.n_methid
356 var name_node: ANode
357 if amethodid == null then
358 if self isa AMainMethPropdef then
359 name = "main"
360 name_node = self
361 else if self isa AConcreteInitPropdef then
362 name = "init"
363 name_node = self.n_kwinit
364 else if self isa AExternInitPropdef then
365 name = "init"
366 name_node = self.n_kwnew
367 else
368 abort
369 end
370 else if amethodid isa AIdMethid then
371 name = amethodid.n_id.text
372 name_node = amethodid
373 else
374 # operator, bracket or assign
375 name = amethodid.collect_text
376 name_node = amethodid
377
378 if name == "-" and self.n_signature.n_params.length == 0 then
379 name = "unary -"
380 end
381 end
382
383 var mprop: nullable MMethod = null
384 if not is_init or n_kwredef != null then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
385 if mprop == null then
386 var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
387 mprop = new MMethod(mclassdef, name, mvisibility)
388 mprop.is_init = is_init
389 mprop.is_new = self isa AExternInitPropdef
390 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mprop) then return
391 else
392 if n_kwredef == null then
393 if self isa AMainMethPropdef then
394 # no warning
395 else
396 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mprop) then return
397 end
398 end
399 check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
400 end
401 nclassdef.mprop2npropdef[mprop] = self
402
403 var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
404
405 if mclassdef.propdef_names.has(mprop.name) then
406 var loc: nullable Location = null
407 for i in mclassdef.mpropdefs do
408 if i.mproperty.name == mprop.name then
409 loc = i.location
410 break
411 end
412 end
413 if loc == null then abort
414 modelbuilder.error(self, "Error: a property {mprop} is already defined in class {mclassdef.mclass} at {loc}")
415 end
416
417 mclassdef.propdef_names.add(mpropdef.mproperty.name)
418
419 self.mpropdef = mpropdef
420 modelbuilder.mpropdef2npropdef[mpropdef] = self
421 if mpropdef.is_intro then
422 modelbuilder.toolcontext.info("{mpropdef} introduces new method {mprop.full_name}", 3)
423 else
424 modelbuilder.toolcontext.info("{mpropdef} redefines method {mprop.full_name}", 3)
425 end
426 end
427
428 redef fun build_signature(modelbuilder, nclassdef)
429 do
430 var mpropdef = self.mpropdef
431 if mpropdef == null then return # Error thus skiped
432 var mmodule = mpropdef.mclassdef.mmodule
433 var nsig = self.n_signature
434
435 # Retrieve info from the signature AST
436 var param_names = new Array[String] # Names of parameters from the AST
437 var param_types = new Array[MType] # Types of parameters from the AST
438 var vararg_rank = -1
439 var ret_type: nullable MType = null # Return type from the AST
440 if nsig != null then
441 if not nsig.visit_signature(modelbuilder, nclassdef) then return
442 param_names = nsig.param_names
443 param_types = nsig.param_types
444 vararg_rank = nsig.vararg_rank
445 ret_type = nsig.ret_type
446 end
447
448 # Look for some signature to inherit
449 # FIXME: do not inherit from the intro, but from the most specific
450 var msignature: nullable MSignature = null
451 if not mpropdef.is_intro then
452 msignature = mpropdef.mproperty.intro.msignature
453 if msignature == null then return # Skip error
454
455 # Check inherited signature arity
456 if param_names.length != msignature.arity then
457 var node: ANode
458 if nsig != null then node = nsig else node = self
459 modelbuilder.error(node, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
460 return
461 end
462 else if mpropdef.mproperty.is_init then
463 # FIXME UGLY: inherit signature from a super-constructor
464 for msupertype in nclassdef.mclassdef.supertypes do
465 msupertype = msupertype.anchor_to(mmodule, nclassdef.mclassdef.bound_mtype)
466 var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mpropdef.mproperty.name)
467 if candidate != null then
468 if msignature == null then
469 msignature = candidate.intro.as(MMethodDef).msignature
470 end
471 end
472 end
473 end
474
475
476 # Inherit the signature
477 if msignature != null and param_names.length != param_types.length and param_names.length == msignature.arity and param_types.length == 0 then
478 # Parameters are untyped, thus inherit them
479 param_types = new Array[MType]
480 for mparameter in msignature.mparameters do
481 param_types.add(mparameter.mtype)
482 end
483 vararg_rank = msignature.vararg_rank
484 end
485 if msignature != null and ret_type == null then
486 ret_type = msignature.return_mtype
487 end
488
489 if param_names.length != param_types.length then
490 # Some parameters are typed, other parameters are not typed.
491 modelbuilder.error(nsig.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
492 return
493 end
494
495 var mparameters = new Array[MParameter]
496 for i in [0..param_names.length[ do
497 var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
498 if nsig != null then nsig.n_params[i].mparameter = mparameter
499 mparameters.add(mparameter)
500 end
501
502 msignature = new MSignature(mparameters, ret_type)
503 mpropdef.msignature = msignature
504 mpropdef.is_abstract = self isa ADeferredMethPropdef
505 end
506
507 redef fun check_signature(modelbuilder, nclassdef)
508 do
509 var mpropdef = self.mpropdef
510 if mpropdef == null then return # Error thus skiped
511 var mmodule = mpropdef.mclassdef.mmodule
512 var nsig = self.n_signature
513 var mysignature = self.mpropdef.msignature
514 if mysignature == null then return # Error thus skiped
515
516 # Lookup for signature in the precursor
517 # FIXME all precursors should be considered
518 if not mpropdef.is_intro then
519 var msignature = mpropdef.mproperty.intro.msignature
520 if msignature == null then return
521
522 var precursor_ret_type = msignature.return_mtype
523 var ret_type = mysignature.return_mtype
524 if ret_type != null and precursor_ret_type == null then
525 modelbuilder.error(nsig.n_type.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
526 return
527 end
528
529 if mysignature.arity > 0 then
530 # Check parameters types
531 for i in [0..mysignature.arity[ do
532 var myt = mysignature.mparameters[i].mtype
533 var prt = msignature.mparameters[i].mtype
534 if not myt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, prt) or
535 not prt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, myt) then
536 modelbuilder.error(nsig.n_params[i], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt} as in {mpropdef.mproperty.intro}.")
537 end
538 end
539 end
540 if precursor_ret_type != null then
541 if ret_type == null then
542 # Inherit the return type
543 ret_type = precursor_ret_type
544 else if not ret_type.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, precursor_ret_type) then
545 modelbuilder.error(nsig.n_type.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type} as in {mpropdef.mproperty.intro}.")
546 end
547 end
548 end
549 end
550 end
551
552 redef class AAttrPropdef
553 redef type MPROPDEF: MAttributeDef
554
555 # The associated getter (read accessor) if any
556 var mreadpropdef: nullable MMethodDef writable
557 # The associated setter (write accessor) if any
558 var mwritepropdef: nullable MMethodDef writable
559 redef fun build_property(modelbuilder, nclassdef)
560 do
561 var mclassdef = nclassdef.mclassdef.as(not null)
562 var mclass = mclassdef.mclass
563
564 var name: String
565 if self.n_id != null then
566 name = self.n_id.text
567 else
568 name = self.n_id2.text
569 end
570
571 if mclass.kind == interface_kind or mclassdef.mclass.kind == enum_kind then
572 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
573 else if mclass.kind == enum_kind then
574 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
575 else if mclass.kind == extern_kind then
576 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
577 end
578
579 var nid = self.n_id
580 if nid != null then
581 # Old attribute style
582 var mprop = modelbuilder.try_get_mproperty_by_name(nid, mclassdef, name)
583 if mprop == null then
584 var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
585 mprop = new MAttribute(mclassdef, name, mvisibility)
586 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) then return
587 else
588 assert mprop isa MAttribute
589 check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
590 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return
591 end
592 nclassdef.mprop2npropdef[mprop] = self
593
594 var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
595 self.mpropdef = mpropdef
596 modelbuilder.mpropdef2npropdef[mpropdef] = self
597
598 var nreadable = self.n_readable
599 if nreadable != null then
600 var readname = name.substring_from(1)
601 var mreadprop = modelbuilder.try_get_mproperty_by_name(nid, mclassdef, readname).as(nullable MMethod)
602 if mreadprop == null then
603 var mvisibility = new_property_visibility(modelbuilder, nclassdef, nreadable.n_visibility)
604 mreadprop = new MMethod(mclassdef, readname, mvisibility)
605 if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, false, mreadprop) then return
606 else
607 if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, true, mreadprop) then return
608 check_redef_property_visibility(modelbuilder, nclassdef, nreadable.n_visibility, mreadprop)
609 end
610 nclassdef.mprop2npropdef[mreadprop] = self
611
612 var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
613 self.mreadpropdef = mreadpropdef
614 modelbuilder.mpropdef2npropdef[mreadpropdef] = self
615 end
616
617 var nwritable = self.n_writable
618 if nwritable != null then
619 var writename = name.substring_from(1) + "="
620 var mwriteprop = modelbuilder.try_get_mproperty_by_name(nid, mclassdef, writename).as(nullable MMethod)
621 if mwriteprop == null then
622 var mvisibility = new_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility)
623 mwriteprop = new MMethod(mclassdef, writename, mvisibility)
624 if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, false, mwriteprop) then return
625 else
626 if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, true, mwriteprop) then return
627 check_redef_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility, mwriteprop)
628 end
629 nclassdef.mprop2npropdef[mwriteprop] = self
630
631 var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
632 self.mwritepropdef = mwritepropdef
633 modelbuilder.mpropdef2npropdef[mwritepropdef] = self
634 end
635 else
636 # New attribute style
637 var nid2 = self.n_id2.as(not null)
638 var mprop = new MAttribute(mclassdef, "@" + name, none_visibility)
639 var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
640 self.mpropdef = mpropdef
641 modelbuilder.mpropdef2npropdef[mpropdef] = self
642
643 var readname = name
644 var mreadprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, readname).as(nullable MMethod)
645 if mreadprop == null then
646 var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
647 mreadprop = new MMethod(mclassdef, readname, mvisibility)
648 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mreadprop) then return
649 else
650 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mreadprop) then return
651 check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mreadprop)
652 end
653 nclassdef.mprop2npropdef[mreadprop] = self
654
655 var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
656 self.mreadpropdef = mreadpropdef
657 modelbuilder.mpropdef2npropdef[mreadpropdef] = self
658
659 var writename = name + "="
660 var nwritable = self.n_writable
661 var mwriteprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, writename).as(nullable MMethod)
662 var nwkwredef: nullable Token = null
663 if nwritable != null then nwkwredef = nwritable.n_kwredef
664 if mwriteprop == null then
665 var mvisibility
666 if nwritable != null then
667 mvisibility = new_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility)
668 else
669 mvisibility = private_visibility
670 end
671 mwriteprop = new MMethod(mclassdef, writename, mvisibility)
672 if not self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, false, mwriteprop) then return
673 else
674 if not self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, true, mwriteprop) then return
675 if nwritable != null then
676 check_redef_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility, mwriteprop)
677 end
678 end
679 nclassdef.mprop2npropdef[mwriteprop] = self
680
681 var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
682 self.mwritepropdef = mwritepropdef
683 modelbuilder.mpropdef2npropdef[mwritepropdef] = self
684 end
685 end
686
687 redef fun build_signature(modelbuilder, nclassdef)
688 do
689 var mpropdef = self.mpropdef
690 if mpropdef == null then return # Error thus skiped
691 var mmodule = mpropdef.mclassdef.mmodule
692 var mtype: nullable MType = null
693
694 var ntype = self.n_type
695 if ntype != null then
696 mtype = modelbuilder.resolve_mtype(nclassdef, ntype)
697 if mtype == null then return
698 end
699
700 var nexpr = self.n_expr
701 if mtype == null then
702 if nexpr != null then
703 if nexpr isa ANewExpr then
704 mtype = modelbuilder.resolve_mtype(nclassdef, nexpr.n_type)
705 else if nexpr isa AIntExpr then
706 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
707 if cla != null then mtype = cla.mclass_type
708 else if nexpr isa AFloatExpr then
709 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Float")
710 if cla != null then mtype = cla.mclass_type
711 else if nexpr isa ACharExpr then
712 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Char")
713 if cla != null then mtype = cla.mclass_type
714 else if nexpr isa ABoolExpr then
715 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Bool")
716 if cla != null then mtype = cla.mclass_type
717 else if nexpr isa ASuperstringExpr then
718 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
719 if cla != null then mtype = cla.mclass_type
720 else if nexpr isa AStringFormExpr then
721 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
722 if cla != null then mtype = cla.mclass_type
723 else
724 modelbuilder.error(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
725 end
726
727 else
728 modelbuilder.error(self, "Error: Untyped attribute {mpropdef}")
729 end
730 else
731 assert ntype != null
732 if nexpr isa ANewExpr then
733 var xmtype = modelbuilder.resolve_mtype(nclassdef, nexpr.n_type)
734 if xmtype == mtype and modelbuilder.toolcontext.opt_warn.value >= 2 then
735 modelbuilder.warning(ntype, "Warning: useless type definition")
736 end
737 end
738 end
739
740 if mtype == null then return
741
742 mpropdef.static_mtype = mtype
743
744 var mreadpropdef = self.mreadpropdef
745 if mreadpropdef != null then
746 var msignature = new MSignature(new Array[MParameter], mtype)
747 mreadpropdef.msignature = msignature
748 end
749
750 var msritepropdef = self.mwritepropdef
751 if mwritepropdef != null then
752 var name: String
753 if n_id != null then
754 name = n_id.text.substring_from(1)
755 else
756 name = n_id2.text
757 end
758 var mparameter = new MParameter(name, mtype, false)
759 var msignature = new MSignature([mparameter], null)
760 mwritepropdef.msignature = msignature
761 end
762 end
763
764 redef fun check_signature(modelbuilder, nclassdef)
765 do
766 var mpropdef = self.mpropdef
767 if mpropdef == null then return # Error thus skiped
768 var mmodule = mpropdef.mclassdef.mmodule
769 var ntype = self.n_type
770 var mtype = self.mpropdef.static_mtype
771 if mtype == null then return # Error thus skiped
772
773 # Lookup for signature in the precursor
774 # FIXME all precursors should be considered
775 if not mpropdef.is_intro then
776 var precursor_type = mpropdef.mproperty.intro.static_mtype
777 if precursor_type == null then return
778
779 if mtype != precursor_type then
780 modelbuilder.error(ntype.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
781 return
782 end
783 end
784
785 # Check getter and setter
786 var meth = self.mreadpropdef
787 if meth != null then self.check_method_signature(modelbuilder, nclassdef, meth)
788 meth = self.mwritepropdef
789 if meth != null then self.check_method_signature(modelbuilder, nclassdef, meth)
790 end
791
792 private fun check_method_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef, mpropdef: MMethodDef)
793 do
794 var mmodule = mpropdef.mclassdef.mmodule
795 var nsig = self.n_type
796 var mysignature = mpropdef.msignature
797 if mysignature == null then return # Error thus skiped
798
799 # Lookup for signature in the precursor
800 # FIXME all precursors should be considered
801 if not mpropdef.is_intro then
802 var msignature = mpropdef.mproperty.intro.msignature
803 if msignature == null then return
804
805 if mysignature.arity != msignature.arity then
806 var node: ANode
807 if nsig != null then node = nsig else node = self
808 modelbuilder.error(node, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
809 return
810 end
811 var precursor_ret_type = msignature.return_mtype
812 var ret_type = mysignature.return_mtype
813 if ret_type != null and precursor_ret_type == null then
814 var node: ANode
815 if nsig != null then node = nsig else node = self
816 modelbuilder.error(node, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
817 return
818 end
819
820 if mysignature.arity > 0 then
821 # Check parameters types
822 for i in [0..mysignature.arity[ do
823 var myt = mysignature.mparameters[i].mtype
824 var prt = msignature.mparameters[i].mtype
825 if not myt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, prt) and
826 not prt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, myt) then
827 var node: ANode
828 if nsig != null then node = nsig else node = self
829 modelbuilder.error(node, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
830 end
831 end
832 end
833 if precursor_ret_type != null then
834 if ret_type == null then
835 # Inherit the return type
836 ret_type = precursor_ret_type
837 else if not ret_type.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, precursor_ret_type) then
838 var node: ANode
839 if nsig != null then node = nsig else node = self
840 modelbuilder.error(node, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
841 end
842 end
843 end
844 end
845 end
846
847 redef class ATypePropdef
848 redef type MPROPDEF: MVirtualTypeDef
849
850 redef fun build_property(modelbuilder, nclassdef)
851 do
852 var mclassdef = nclassdef.mclassdef.as(not null)
853 var name = self.n_id.text
854 var mprop = modelbuilder.try_get_mproperty_by_name(self.n_id, mclassdef, name)
855 if mprop == null then
856 var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
857 mprop = new MVirtualTypeProp(mclassdef, name, mvisibility)
858 for c in name do if c >= 'a' and c<= 'z' then
859 modelbuilder.warning(n_id, "Warning: lowercase in the virtual type {name}")
860 break
861 end
862 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) then return
863 else
864 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return
865 assert mprop isa MVirtualTypeProp
866 check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
867 end
868 nclassdef.mprop2npropdef[mprop] = self
869
870 var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
871 self.mpropdef = mpropdef
872 end
873
874 redef fun build_signature(modelbuilder, nclassdef)
875 do
876 var mpropdef = self.mpropdef
877 if mpropdef == null then return # Error thus skiped
878 var mmodule = mpropdef.mclassdef.mmodule
879 var mtype: nullable MType = null
880
881 var ntype = self.n_type
882 mtype = modelbuilder.resolve_mtype(nclassdef, ntype)
883 if mtype == null then return
884
885 mpropdef.bound = mtype
886 # print "{mpropdef}: {mtype}"
887 end
888
889 redef fun check_signature(modelbuilder, nclassdef)
890 do
891 var mpropdef = self.mpropdef
892 if mpropdef == null then return # Error thus skiped
893
894 var bound = self.mpropdef.bound
895
896 # Fast case: the bound is not a formal type
897 if not bound isa MVirtualType then return
898
899 var mmodule = nclassdef.mclassdef.mmodule
900 var anchor = nclassdef.mclassdef.bound_mtype
901
902 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
903 var seen = [self.mpropdef.mproperty.mvirtualtype]
904 loop
905 if seen.has(bound) then
906 seen.add(bound)
907 modelbuilder.error(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
908 return
909 end
910 seen.add(bound)
911 var next = bound.lookup_bound(mmodule, anchor)
912 if not next isa MVirtualType then return
913 bound = next
914 end
915 end
916 end