lib: fixed bad mallocs in socket
[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 AClassdef
162 var build_properties_is_done: Bool = false
163 # The list of super-constructor to call at the start of the free constructor
164 # 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
165 var super_inits: nullable Collection[MMethod] = null
166
167 # The free init (implicitely constructed by the class if required)
168 var mfree_init: nullable MMethodDef = null
169
170 # What is the `APropdef` associated to a `MProperty`?
171 # Used to check multiple definition of a property.
172 var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
173 end
174
175 redef class Prod
176 # Join the text of all tokens
177 # Used to get the 'real name' of method definitions.
178 fun collect_text: String
179 do
180 var v = new TextCollectorVisitor
181 v.enter_visit(self)
182 assert v.text != ""
183 return v.text
184 end
185 end
186
187 private class TextCollectorVisitor
188 super Visitor
189 var text: String = ""
190 redef fun visit(n)
191 do
192 if n isa Token then text += n.text
193 n.visit_all(self)
194 end
195 end
196
197 redef class APropdef
198 # The associated main model entity
199 type MPROPDEF: MPropDef
200
201 # The associated propdef once build by a `ModelBuilder`
202 var mpropdef: nullable MPROPDEF writable
203
204 private fun build_property(modelbuilder: ModelBuilder, nclassdef: AClassdef) is abstract
205 private fun build_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef) is abstract
206 private fun check_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef) is abstract
207 private fun new_property_visibility(modelbuilder: ModelBuilder, nclassdef: AClassdef, nvisibility: nullable AVisibility): MVisibility
208 do
209 var mvisibility = public_visibility
210 if nvisibility != null then
211 mvisibility = nvisibility.mvisibility
212 if mvisibility == intrude_visibility then
213 modelbuilder.error(nvisibility, "Error: intrude is not a legal visibility for properties.")
214 mvisibility = public_visibility
215 end
216 end
217 if nclassdef.mclassdef.mclass.visibility == private_visibility then
218 if mvisibility == protected_visibility then
219 assert nvisibility != null
220 modelbuilder.error(nvisibility, "Error: The only legal visibility for properties in a private class is private.")
221 else if mvisibility == private_visibility then
222 assert nvisibility != null
223 # Not yet
224 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
225 end
226 mvisibility = private_visibility
227 end
228 return mvisibility
229 end
230
231 private fun check_redef_property_visibility(modelbuilder: ModelBuilder, nclassdef: AClassdef, nvisibility: nullable AVisibility, mprop: MProperty)
232 do
233 if nvisibility == null then return
234 var mvisibility = nvisibility.mvisibility
235 if mvisibility != mprop.visibility and mvisibility != public_visibility then
236 modelbuilder.error(nvisibility, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
237 end
238 end
239
240 private fun check_redef_keyword(modelbuilder: ModelBuilder, nclassdef: AClassdef, kwredef: nullable Token, need_redef: Bool, mprop: MProperty): Bool
241 do
242 if nclassdef.mprop2npropdef.has_key(mprop) then
243 modelbuilder.error(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
244 return false
245 end
246 if kwredef == null then
247 if need_redef then
248 modelbuilder.error(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
249 return false
250 end
251 else
252 if not need_redef then
253 modelbuilder.error(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
254 return false
255 end
256 end
257 return true
258 end
259
260 end
261
262 redef class ASignature
263 # Is the model builder has correctly visited the signature
264 var is_visited = false
265 # Names of parameters from the AST
266 # REQUIRE: is_visited
267 var param_names = new Array[String]
268 # Types of parameters from the AST
269 # REQUIRE: is_visited
270 var param_types = new Array[MType]
271 # Rank of the vararg (of -1 if none)
272 # REQUIRE: is_visited
273 var vararg_rank: Int = -1
274 # Return type
275 var ret_type: nullable MType = null
276
277 # Visit and fill information about a signature
278 private fun visit_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef): Bool
279 do
280 var param_names = self.param_names
281 var param_types = self.param_types
282 for np in self.n_params do
283 param_names.add(np.n_id.text)
284 var ntype = np.n_type
285 if ntype != null then
286 var mtype = modelbuilder.resolve_mtype(nclassdef, ntype)
287 if mtype == null then return false # Skip error
288 for i in [0..param_names.length-param_types.length[ do
289 param_types.add(mtype)
290 end
291 if np.n_dotdotdot != null then
292 if self.vararg_rank != -1 then
293 modelbuilder.error(np, "Error: {param_names[self.vararg_rank]} is already a vararg")
294 return false
295 else
296 self.vararg_rank = param_names.length - 1
297 end
298 end
299 end
300 end
301 var ntype = self.n_type
302 if ntype != null then
303 self.ret_type = modelbuilder.resolve_mtype(nclassdef, ntype)
304 if self.ret_type == null then return false # Skip errir
305 end
306
307 for nclosure in self.n_closure_decls do
308 if not nclosure.n_signature.visit_signature(modelbuilder, nclassdef) then return false
309 end
310
311 self.is_visited = true
312 return true
313 end
314
315 # Build a visited signature
316 fun build_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef): nullable MSignature
317 do
318 if param_names.length != param_types.length then
319 # Some parameters are typed, other parameters are not typed.
320 modelbuilder.error(self.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
321 return null
322 end
323
324 var mparameters = new Array[MParameter]
325 for i in [0..param_names.length[ do
326 var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
327 self.n_params[i].mparameter = mparameter
328 mparameters.add(mparameter)
329 end
330
331 var msignature = new MSignature(mparameters, ret_type)
332 return msignature
333 end
334 end
335
336 redef class AParam
337 # The associated mparameter if any
338 var mparameter: nullable MParameter = null
339 end
340
341 redef class AMethPropdef
342 redef type MPROPDEF: MMethodDef
343
344 redef fun build_property(modelbuilder, nclassdef)
345 do
346 var is_init = self isa AInitPropdef
347 var mclassdef = nclassdef.mclassdef.as(not null)
348 var name: String
349 var amethodid = self.n_methid
350 var name_node: ANode
351 if amethodid == null then
352 if self isa AMainMethPropdef then
353 name = "main"
354 name_node = self
355 else if self isa AConcreteInitPropdef then
356 name = "init"
357 name_node = self.n_kwinit
358 else if self isa AExternInitPropdef then
359 name = "init"
360 name_node = self.n_kwnew
361 else
362 abort
363 end
364 else if amethodid isa AIdMethid then
365 name = amethodid.n_id.text
366 name_node = amethodid
367 else
368 # operator, bracket or assign
369 name = amethodid.collect_text
370 name_node = amethodid
371
372 if name == "-" and self.n_signature.n_params.length == 0 then
373 name = "unary -"
374 end
375 end
376
377 var mprop: nullable MMethod = null
378 if not is_init or n_kwredef != null then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
379 if mprop == null then
380 var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
381 mprop = new MMethod(mclassdef, name, mvisibility)
382 mprop.is_init = is_init
383 mprop.is_new = self isa AExternInitPropdef
384 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mprop) then return
385 else
386 if n_kwredef == null then
387 if self isa AMainMethPropdef then
388 # no warning
389 else
390 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mprop) then return
391 end
392 end
393 check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
394 end
395 nclassdef.mprop2npropdef[mprop] = self
396
397 var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
398
399 self.mpropdef = mpropdef
400 modelbuilder.mpropdef2npropdef[mpropdef] = self
401 if mpropdef.is_intro then
402 modelbuilder.toolcontext.info("{mpropdef} introduces new method {mprop.full_name}", 3)
403 else
404 modelbuilder.toolcontext.info("{mpropdef} redefines method {mprop.full_name}", 3)
405 end
406 end
407
408 redef fun build_signature(modelbuilder, nclassdef)
409 do
410 var mpropdef = self.mpropdef
411 if mpropdef == null then return # Error thus skiped
412 var mmodule = mpropdef.mclassdef.mmodule
413 var nsig = self.n_signature
414
415 # Retrieve info from the signature AST
416 var param_names = new Array[String] # Names of parameters from the AST
417 var param_types = new Array[MType] # Types of parameters from the AST
418 var vararg_rank = -1
419 var ret_type: nullable MType = null # Return type from the AST
420 if nsig != null then
421 if not nsig.visit_signature(modelbuilder, nclassdef) then return
422 param_names = nsig.param_names
423 param_types = nsig.param_types
424 vararg_rank = nsig.vararg_rank
425 ret_type = nsig.ret_type
426 end
427
428 # Look for some signature to inherit
429 # FIXME: do not inherit from the intro, but from the most specific
430 var msignature: nullable MSignature = null
431 if not mpropdef.is_intro then
432 msignature = mpropdef.mproperty.intro.msignature
433 if msignature == null then return # Skip error
434
435 # Check inherited signature arity
436 if param_names.length != msignature.arity then
437 var node: ANode
438 if nsig != null then node = nsig else node = self
439 modelbuilder.error(node, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
440 return
441 end
442 else if mpropdef.mproperty.is_init then
443 # FIXME UGLY: inherit signature from a super-constructor
444 for msupertype in nclassdef.mclassdef.supertypes do
445 msupertype = msupertype.anchor_to(mmodule, nclassdef.mclassdef.bound_mtype)
446 var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mpropdef.mproperty.name)
447 if candidate != null then
448 if msignature == null then
449 msignature = candidate.intro.as(MMethodDef).msignature
450 end
451 end
452 end
453 end
454
455
456 # Inherit the signature
457 if msignature != null and param_names.length != param_types.length and param_names.length == msignature.arity and param_types.length == 0 then
458 # Parameters are untyped, thus inherit them
459 param_types = new Array[MType]
460 for mparameter in msignature.mparameters do
461 param_types.add(mparameter.mtype)
462 end
463 vararg_rank = msignature.vararg_rank
464 end
465 if msignature != null and ret_type == null then
466 ret_type = msignature.return_mtype
467 end
468
469 if param_names.length != param_types.length then
470 # Some parameters are typed, other parameters are not typed.
471 modelbuilder.error(nsig.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
472 return
473 end
474
475 var mparameters = new Array[MParameter]
476 for i in [0..param_names.length[ do
477 var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
478 if nsig != null then nsig.n_params[i].mparameter = mparameter
479 mparameters.add(mparameter)
480 end
481
482 msignature = new MSignature(mparameters, ret_type)
483 mpropdef.msignature = msignature
484 mpropdef.is_abstract = self isa ADeferredMethPropdef
485
486 if nsig != null then
487 for nclosure in nsig.n_closure_decls do
488 var clos_signature = nclosure.n_signature.build_signature(modelbuilder, nclassdef)
489 if clos_signature == null then return
490 var mparameter = new MParameter(nclosure.n_id.text, clos_signature, false)
491 msignature.mclosures.add(mparameter)
492 end
493 end
494
495 end
496
497 redef fun check_signature(modelbuilder, nclassdef)
498 do
499 var mpropdef = self.mpropdef
500 if mpropdef == null then return # Error thus skiped
501 var mmodule = mpropdef.mclassdef.mmodule
502 var nsig = self.n_signature
503 var mysignature = self.mpropdef.msignature
504 if mysignature == null then return # Error thus skiped
505
506 # Lookup for signature in the precursor
507 # FIXME all precursors should be considered
508 if not mpropdef.is_intro then
509 var msignature = mpropdef.mproperty.intro.msignature
510 if msignature == null then return
511
512 var precursor_ret_type = msignature.return_mtype
513 var ret_type = mysignature.return_mtype
514 if ret_type != null and precursor_ret_type == null then
515 modelbuilder.error(nsig.n_type.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
516 return
517 end
518
519 if mysignature.arity > 0 then
520 # Check parameters types
521 for i in [0..mysignature.arity[ do
522 var myt = mysignature.mparameters[i].mtype
523 var prt = msignature.mparameters[i].mtype
524 if not myt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, prt) and
525 not prt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, myt) then
526 modelbuilder.error(nsig.n_params[i], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
527 end
528 end
529 end
530 if precursor_ret_type != null then
531 if ret_type == null then
532 # Inherit the return type
533 ret_type = precursor_ret_type
534 else if not ret_type.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, precursor_ret_type) then
535 modelbuilder.error(nsig.n_type.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
536 end
537 end
538 end
539 end
540 end
541
542 redef class AAttrPropdef
543 redef type MPROPDEF: MAttributeDef
544
545 # The associated getter (read accessor) if any
546 var mreadpropdef: nullable MMethodDef writable
547 # The associated setter (write accessor) if any
548 var mwritepropdef: nullable MMethodDef writable
549 redef fun build_property(modelbuilder, nclassdef)
550 do
551 var mclassdef = nclassdef.mclassdef.as(not null)
552 var mclass = mclassdef.mclass
553
554 var name: String
555 if self.n_id != null then
556 name = self.n_id.text
557 else
558 name = self.n_id2.text
559 end
560
561 if mclass.kind == interface_kind or mclassdef.mclass.kind == enum_kind then
562 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
563 else if mclass.kind == enum_kind then
564 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
565 else if mclass.kind == extern_kind then
566 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
567 end
568
569 var nid = self.n_id
570 if nid != null then
571 # Old attribute style
572 var mprop = modelbuilder.try_get_mproperty_by_name(nid, mclassdef, name)
573 if mprop == null then
574 var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
575 mprop = new MAttribute(mclassdef, name, mvisibility)
576 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) then return
577 else
578 assert mprop isa MAttribute
579 check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
580 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return
581 end
582 nclassdef.mprop2npropdef[mprop] = self
583
584 var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
585 self.mpropdef = mpropdef
586 modelbuilder.mpropdef2npropdef[mpropdef] = self
587
588 var nreadable = self.n_readable
589 if nreadable != null then
590 var readname = name.substring_from(1)
591 var mreadprop = modelbuilder.try_get_mproperty_by_name(nid, mclassdef, readname).as(nullable MMethod)
592 if mreadprop == null then
593 var mvisibility = new_property_visibility(modelbuilder, nclassdef, nreadable.n_visibility)
594 mreadprop = new MMethod(mclassdef, readname, mvisibility)
595 if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, false, mreadprop) then return
596 else
597 if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, true, mreadprop) then return
598 check_redef_property_visibility(modelbuilder, nclassdef, nreadable.n_visibility, mreadprop)
599 end
600 nclassdef.mprop2npropdef[mreadprop] = self
601
602 var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
603 self.mreadpropdef = mreadpropdef
604 modelbuilder.mpropdef2npropdef[mreadpropdef] = self
605 end
606
607 var nwritable = self.n_writable
608 if nwritable != null then
609 var writename = name.substring_from(1) + "="
610 var mwriteprop = modelbuilder.try_get_mproperty_by_name(nid, mclassdef, writename).as(nullable MMethod)
611 if mwriteprop == null then
612 var mvisibility = new_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility)
613 mwriteprop = new MMethod(mclassdef, writename, mvisibility)
614 if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, false, mwriteprop) then return
615 else
616 if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, true, mwriteprop) then return
617 check_redef_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility, mwriteprop)
618 end
619 nclassdef.mprop2npropdef[mwriteprop] = self
620
621 var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
622 self.mwritepropdef = mwritepropdef
623 modelbuilder.mpropdef2npropdef[mwritepropdef] = self
624 end
625 else
626 # New attribute style
627 var nid2 = self.n_id2.as(not null)
628 var mprop = new MAttribute(mclassdef, "@" + name, none_visibility)
629 var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
630 self.mpropdef = mpropdef
631 modelbuilder.mpropdef2npropdef[mpropdef] = self
632
633 var readname = name
634 var mreadprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, readname).as(nullable MMethod)
635 if mreadprop == null then
636 var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
637 mreadprop = new MMethod(mclassdef, readname, mvisibility)
638 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mreadprop) then return
639 else
640 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mreadprop) then return
641 check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mreadprop)
642 end
643 nclassdef.mprop2npropdef[mreadprop] = self
644
645 var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
646 self.mreadpropdef = mreadpropdef
647 modelbuilder.mpropdef2npropdef[mreadpropdef] = self
648
649 var writename = name + "="
650 var nwritable = self.n_writable
651 var mwriteprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, writename).as(nullable MMethod)
652 var nwkwredef: nullable Token = null
653 if nwritable != null then nwkwredef = nwritable.n_kwredef
654 if mwriteprop == null then
655 var mvisibility
656 if nwritable != null then
657 mvisibility = new_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility)
658 else
659 mvisibility = private_visibility
660 end
661 mwriteprop = new MMethod(mclassdef, writename, mvisibility)
662 if not self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, false, mwriteprop) then return
663 else
664 if not self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, true, mwriteprop) then return
665 if nwritable != null then
666 check_redef_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility, mwriteprop)
667 end
668 end
669 nclassdef.mprop2npropdef[mwriteprop] = self
670
671 var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
672 self.mwritepropdef = mwritepropdef
673 modelbuilder.mpropdef2npropdef[mwritepropdef] = self
674 end
675 end
676
677 redef fun build_signature(modelbuilder, nclassdef)
678 do
679 var mpropdef = self.mpropdef
680 if mpropdef == null then return # Error thus skiped
681 var mmodule = mpropdef.mclassdef.mmodule
682 var mtype: nullable MType = null
683
684 var ntype = self.n_type
685 if ntype != null then
686 mtype = modelbuilder.resolve_mtype(nclassdef, ntype)
687 if mtype == null then return
688 end
689
690 if mtype == null then
691 var nexpr = self.n_expr
692 if nexpr != null then
693 if nexpr isa ANewExpr then
694 mtype = modelbuilder.resolve_mtype(nclassdef, nexpr.n_type)
695 else if nexpr isa AIntExpr then
696 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
697 if cla != null then mtype = cla.mclass_type
698 else if nexpr isa AFloatExpr then
699 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Float")
700 if cla != null then mtype = cla.mclass_type
701 else if nexpr isa ACharExpr then
702 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Char")
703 if cla != null then mtype = cla.mclass_type
704 else if nexpr isa ABoolExpr then
705 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Bool")
706 if cla != null then mtype = cla.mclass_type
707 else if nexpr isa ASuperstringExpr then
708 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
709 if cla != null then mtype = cla.mclass_type
710 else if nexpr isa AStringFormExpr then
711 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
712 if cla != null then mtype = cla.mclass_type
713 else
714 modelbuilder.error(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
715 end
716
717 else
718 modelbuilder.error(self, "Error: Untyped attribute {mpropdef}")
719 end
720 end
721
722 if mtype == null then return
723
724 mpropdef.static_mtype = mtype
725
726 var mreadpropdef = self.mreadpropdef
727 if mreadpropdef != null then
728 var msignature = new MSignature(new Array[MParameter], mtype)
729 mreadpropdef.msignature = msignature
730 end
731
732 var msritepropdef = self.mwritepropdef
733 if mwritepropdef != null then
734 var name: String
735 if n_id != null then
736 name = n_id.text.substring_from(1)
737 else
738 name = n_id2.text
739 end
740 var mparameter = new MParameter(name, mtype, false)
741 var msignature = new MSignature([mparameter], null)
742 mwritepropdef.msignature = msignature
743 end
744 end
745
746 redef fun check_signature(modelbuilder, nclassdef)
747 do
748 var mpropdef = self.mpropdef
749 if mpropdef == null then return # Error thus skiped
750 var mmodule = mpropdef.mclassdef.mmodule
751 var ntype = self.n_type
752 var mtype = self.mpropdef.static_mtype
753 if mtype == null then return # Error thus skiped
754
755 # Lookup for signature in the precursor
756 # FIXME all precursors should be considered
757 if not mpropdef.is_intro then
758 var precursor_type = mpropdef.mproperty.intro.static_mtype
759 if precursor_type == null then return
760
761 if mtype != precursor_type then
762 modelbuilder.error(ntype.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
763 return
764 end
765 end
766
767 # Check getter and setter
768 var meth = self.mreadpropdef
769 if meth != null then self.check_method_signature(modelbuilder, nclassdef, meth)
770 meth = self.mwritepropdef
771 if meth != null then self.check_method_signature(modelbuilder, nclassdef, meth)
772 end
773
774 private fun check_method_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef, mpropdef: MMethodDef)
775 do
776 var mmodule = mpropdef.mclassdef.mmodule
777 var nsig = self.n_type
778 var mysignature = mpropdef.msignature
779 if mysignature == null then return # Error thus skiped
780
781 # Lookup for signature in the precursor
782 # FIXME all precursors should be considered
783 if not mpropdef.is_intro then
784 var msignature = mpropdef.mproperty.intro.msignature
785 if msignature == null then return
786
787 if mysignature.arity != msignature.arity then
788 var node: ANode
789 if nsig != null then node = nsig else node = self
790 modelbuilder.error(node, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
791 return
792 end
793 var precursor_ret_type = msignature.return_mtype
794 var ret_type = mysignature.return_mtype
795 if ret_type != null and precursor_ret_type == null then
796 var node: ANode
797 if nsig != null then node = nsig else node = self
798 modelbuilder.error(node, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
799 return
800 end
801
802 if mysignature.arity > 0 then
803 # Check parameters types
804 for i in [0..mysignature.arity[ do
805 var myt = mysignature.mparameters[i].mtype
806 var prt = msignature.mparameters[i].mtype
807 if not myt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, prt) and
808 not prt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, myt) then
809 var node: ANode
810 if nsig != null then node = nsig else node = self
811 modelbuilder.error(node, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
812 end
813 end
814 end
815 if precursor_ret_type != null then
816 if ret_type == null then
817 # Inherit the return type
818 ret_type = precursor_ret_type
819 else if not ret_type.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, precursor_ret_type) then
820 var node: ANode
821 if nsig != null then node = nsig else node = self
822 modelbuilder.error(node, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
823 end
824 end
825 end
826 end
827 end
828
829 redef class ATypePropdef
830 redef type MPROPDEF: MVirtualTypeDef
831
832 redef fun build_property(modelbuilder, nclassdef)
833 do
834 var mclassdef = nclassdef.mclassdef.as(not null)
835 var name = self.n_id.text
836 var mprop = modelbuilder.try_get_mproperty_by_name(self.n_id, mclassdef, name)
837 if mprop == null then
838 var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
839 mprop = new MVirtualTypeProp(mclassdef, name, mvisibility)
840 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) then return
841 else
842 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return
843 assert mprop isa MVirtualTypeProp
844 check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
845 end
846 nclassdef.mprop2npropdef[mprop] = self
847
848 var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
849 self.mpropdef = mpropdef
850 end
851
852 redef fun build_signature(modelbuilder, nclassdef)
853 do
854 var mpropdef = self.mpropdef
855 if mpropdef == null then return # Error thus skiped
856 var mmodule = mpropdef.mclassdef.mmodule
857 var mtype: nullable MType = null
858
859 var ntype = self.n_type
860 mtype = modelbuilder.resolve_mtype(nclassdef, ntype)
861 if mtype == null then return
862
863 mpropdef.bound = mtype
864 # print "{mpropdef}: {mtype}"
865 end
866
867 redef fun check_signature(modelbuilder, nclassdef)
868 do
869 var bound = self.mpropdef.bound
870
871 # Fast case: the bound is not a formal type
872 if not bound isa MVirtualType then return
873
874 var mmodule = nclassdef.mclassdef.mmodule
875 var anchor = nclassdef.mclassdef.bound_mtype
876
877 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
878 var seen = [self.mpropdef.mproperty.mvirtualtype]
879 loop
880 if seen.has(bound) then
881 seen.add(bound)
882 modelbuilder.error(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
883 return
884 end
885 seen.add(bound)
886 var next = bound.lookup_bound(mmodule, anchor)
887 if not next isa MVirtualType then return
888 bound = next
889 end
890 end
891 end