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