modelize: check full-name conflicts for properties
[nit.git] / src / modelize / 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 intrude import modelize_class
21 private import annotation
22
23 redef class ToolContext
24 # Run `AClassdef::build_property` on the classdefs of each module
25 var modelize_property_phase: Phase = new ModelizePropertyPhase(self, [modelize_class_phase])
26 end
27
28 private class ModelizePropertyPhase
29 super Phase
30 redef fun process_nmodule(nmodule)
31 do
32 for nclassdef in nmodule.n_classdefs do
33 if nclassdef.all_defs == null then continue # skip non principal classdef
34 toolcontext.modelbuilder.build_properties(nclassdef)
35 end
36 end
37 end
38
39 redef class ModelBuilder
40 # Registration of the npropdef associated to each mpropdef.
41 #
42 # Public clients need to use `mpropdef2node` to access stuff.
43 private var mpropdef2npropdef = new HashMap[MPropDef, APropdef]
44
45 # Retrieve the associated AST node of a mpropertydef.
46 # This method is used to associate model entity with syntactic entities.
47 #
48 # If the property definition is not associated with a node, returns node.
49 fun mpropdef2node(mpropdef: MPropDef): nullable ANode
50 do
51 var res: nullable ANode = mpropdef2npropdef.get_or_null(mpropdef)
52 if res != null then return res
53 if mpropdef isa MMethodDef and mpropdef.mproperty.is_root_init then
54 res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
55 if res != null then return res
56 end
57 return null
58 end
59
60 # Retrieve all the attributes nodes localy definied
61 # FIXME think more about this method and how the separations separate/global and ast/model should be done.
62 fun collect_attr_propdef(mclassdef: MClassDef): Array[AAttrPropdef]
63 do
64 var res = new Array[AAttrPropdef]
65 var n = mclassdef2nclassdef.get_or_null(mclassdef)
66 if n == null then return res
67 for npropdef in n.n_propdefs do
68 if npropdef isa AAttrPropdef then
69 res.add(npropdef)
70 end
71 end
72 return res
73 end
74
75 # Build the properties of `nclassdef`.
76 # REQUIRE: all superclasses are built.
77 private fun build_properties(nclassdef: AClassdef)
78 do
79 # Force building recursively
80 if nclassdef.build_properties_is_done then return
81 nclassdef.build_properties_is_done = true
82 var mclassdef = nclassdef.mclassdef.as(not null)
83 if mclassdef.in_hierarchy == null then return # Skip error
84 for superclassdef in mclassdef.in_hierarchy.direct_greaters do
85 if not mclassdef2nclassdef.has_key(superclassdef) then continue
86 build_properties(mclassdef2nclassdef[superclassdef])
87 end
88
89 mclassdef.build_self_type(self, nclassdef)
90 for nclassdef2 in nclassdef.all_defs do
91 for npropdef in nclassdef2.n_propdefs do
92 npropdef.build_property(self, mclassdef)
93 end
94 for npropdef in nclassdef2.n_propdefs do
95 npropdef.build_signature(self)
96 end
97 for npropdef in nclassdef2.n_propdefs do
98 npropdef.check_signature(self)
99 end
100 end
101 process_default_constructors(nclassdef)
102 end
103
104 # the root init of the Object class
105 # Is usually implicitly defined
106 # Then explicit or implicit definitions of root-init are attached to it
107 var the_root_init_mmethod: nullable MMethod
108
109 # Introduce or inherit default constructor
110 # This is the last part of `build_properties`.
111 private fun process_default_constructors(nclassdef: AClassdef)
112 do
113 var mclassdef = nclassdef.mclassdef.as(not null)
114
115 # Are we a refinement
116 if not mclassdef.is_intro then return
117
118 # Look for the init in Object, or create it
119 if mclassdef.mclass.name == "Object" and the_root_init_mmethod == null then
120 # Create the implicit root-init method
121 var mprop = new MMethod(mclassdef, "init", mclassdef.mclass.visibility)
122 mprop.is_root_init = true
123 var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
124 var mparameters = new Array[MParameter]
125 var msignature = new MSignature(mparameters, null)
126 mpropdef.msignature = msignature
127 mpropdef.new_msignature = msignature
128 mprop.is_init = true
129 nclassdef.mfree_init = mpropdef
130 self.toolcontext.info("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
131 the_root_init_mmethod = mprop
132 return
133 end
134
135 # Is the class forbid constructors?
136 if not mclassdef.mclass.kind.need_init then return
137
138 # Is there already a constructor defined?
139 var defined_init: nullable MMethodDef = null
140 for mpropdef in mclassdef.mpropdefs do
141 if not mpropdef isa MMethodDef then continue
142 if not mpropdef.mproperty.is_init then continue
143 if mpropdef.mproperty.is_root_init then
144 assert defined_init == null
145 defined_init = mpropdef
146 else if mpropdef.mproperty.name == "init" then
147 # An explicit old-style init named "init", so return
148 return
149 end
150 end
151
152 if not nclassdef isa AStdClassdef then return
153
154 # Collect undefined attributes
155 var mparameters = new Array[MParameter]
156 var initializers = new Array[MProperty]
157 for npropdef in nclassdef.n_propdefs do
158 if npropdef isa AMethPropdef then
159 if npropdef.mpropdef == null then return # Skip broken attribute
160 var at = npropdef.get_single_annotation("autoinit", self)
161 if at == null then continue # Skip non tagged init
162
163 var sig = npropdef.mpropdef.msignature
164 if sig == null then continue # Skip broken method
165
166 if not npropdef.mpropdef.is_intro then
167 self.error(at, "Error: `autoinit` cannot be set on redefinitions")
168 continue
169 end
170
171 for param in sig.mparameters do
172 var ret_type = param.mtype
173 var mparameter = new MParameter(param.name, ret_type, false)
174 mparameters.add(mparameter)
175 end
176 initializers.add(npropdef.mpropdef.mproperty)
177 end
178 if npropdef isa AAttrPropdef then
179 if npropdef.mpropdef == null then return # Skip broken attribute
180 if npropdef.noinit then continue # Skip noinit attribute
181 var atautoinit = npropdef.get_single_annotation("autoinit", self)
182 if atautoinit != null then
183 # For autoinit attributes, call the reader to force
184 # the lazy initialization of the attribute.
185 initializers.add(npropdef.mreadpropdef.mproperty)
186 continue
187 end
188 if npropdef.has_value then continue
189 var paramname = npropdef.mpropdef.mproperty.name.substring_from(1)
190 var ret_type = npropdef.mpropdef.static_mtype
191 if ret_type == null then return
192 var mparameter = new MParameter(paramname, ret_type, false)
193 mparameters.add(mparameter)
194 var msetter = npropdef.mwritepropdef
195 if msetter == null then
196 # No setter, it is a old-style attribute, so just add it
197 initializers.add(npropdef.mpropdef.mproperty)
198 else
199 # Add the setter to the list
200 initializers.add(msetter.mproperty)
201 end
202 end
203 end
204
205 if the_root_init_mmethod == null then return
206
207 # Look for most-specific new-stype init definitions
208 var spropdefs = the_root_init_mmethod.lookup_super_definitions(mclassdef.mmodule, mclassdef.bound_mtype)
209 if spropdefs.is_empty then
210 toolcontext.error(nclassdef.location, "Error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
211 return
212 end
213
214 # Search the longest-one and checks for conflict
215 var longest = spropdefs.first
216 if spropdefs.length > 1 then
217 # Check for conflict in the order of initializers
218 # Each initializer list must me a prefix of the longest list
219 # part 1. find the longest list
220 for spd in spropdefs do
221 if spd.initializers.length > longest.initializers.length then longest = spd
222 end
223 # part 2. compare
224 for spd in spropdefs do
225 var i = 0
226 for p in spd.initializers do
227 if p != longest.initializers[i] then
228 self.error(nclassdef, "Error: conflict for inherited inits {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")})")
229 return
230 end
231 i += 1
232 end
233 end
234 end
235
236 # Can we just inherit?
237 if spropdefs.length == 1 and mparameters.is_empty and defined_init == null then
238 self.toolcontext.info("{mclassdef} inherits the basic constructor {longest}", 3)
239 mclassdef.mclass.root_init = longest
240 return
241 end
242
243 # Combine the inherited list to what is collected
244 if longest.initializers.length > 0 then
245 mparameters.prepend longest.new_msignature.mparameters
246 initializers.prepend longest.initializers
247 end
248
249 # If we already have a basic init definition, then setup its initializers
250 if defined_init != null then
251 defined_init.initializers.add_all(initializers)
252 var msignature = new MSignature(mparameters, null)
253 defined_init.new_msignature = msignature
254 self.toolcontext.info("{mclassdef} extends its basic constructor signature to {defined_init}{msignature}", 3)
255 mclassdef.mclass.root_init = defined_init
256 return
257 end
258
259 # Else create the local implicit basic init definition
260 var mprop = the_root_init_mmethod.as(not null)
261 var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
262 mpropdef.has_supercall = true
263 mpropdef.initializers.add_all(initializers)
264 var msignature = new MSignature(mparameters, null)
265 mpropdef.new_msignature = msignature
266 mpropdef.msignature = new MSignature(new Array[MParameter], null) # always an empty real signature
267 nclassdef.mfree_init = mpropdef
268 self.toolcontext.info("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
269 mclassdef.mclass.root_init = mpropdef
270 end
271
272 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
273 fun check_visibility(node: ANode, mtype: MType, mpropdef: MPropDef)
274 do
275 var mmodule = mpropdef.mclassdef.mmodule
276 var mproperty = mpropdef.mproperty
277
278 # Extract visibility information of the main part of `mtype`
279 # It is a case-by case
280 var vis_type: nullable MVisibility = null # The own visibility of the type
281 var mmodule_type: nullable MModule = null # The original module of the type
282 mtype = mtype.as_notnullable
283 if mtype isa MClassType then
284 vis_type = mtype.mclass.visibility
285 mmodule_type = mtype.mclass.intro.mmodule
286 else if mtype isa MVirtualType then
287 vis_type = mtype.mproperty.visibility
288 mmodule_type = mtype.mproperty.intro_mclassdef.mmodule
289 else if mtype isa MParameterType then
290 # nothing, always visible
291 else
292 node.debug "Unexpected type {mtype}"
293 abort
294 end
295
296 if vis_type != null then
297 assert mmodule_type != null
298 var vis_module_type = mmodule.visibility_for(mmodule_type) # the visibility of the original module
299 if mproperty.visibility > vis_type then
300 error(node, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
301 return
302 else if mproperty.visibility > vis_module_type then
303 error(node, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
304 return
305 end
306 end
307
308 # No error, try to go deeper in generic types
309 if node isa AType then
310 for a in node.n_types do
311 var t = a.mtype
312 if t == null then continue # Error, thus skipped
313 check_visibility(a, t, mpropdef)
314 end
315 else if mtype isa MGenericType then
316 for t in mtype.arguments do check_visibility(node, t, mpropdef)
317 end
318 end
319 end
320
321 redef class MPropDef
322 # Does the MPropDef contains a call to super or a call of a super-constructor?
323 # Subsequent phases of the frontend (esp. typing) set it if required
324 var has_supercall: Bool = false is writable
325 end
326
327 redef class AClassdef
328 # Marker used in `ModelBuilder::build_properties`
329 private var build_properties_is_done = false
330
331 # The free init (implicitely constructed by the class if required)
332 var mfree_init: nullable MMethodDef = null
333 end
334
335 redef class MClass
336 # The base init of the class.
337 # Used to get the common new_msignature and initializers
338 #
339 # TODO: Where to put this information is not clear because unlike other
340 # informations, the initialisers are stable in a same class.
341 var root_init: nullable MMethodDef = null
342 end
343
344 redef class MClassDef
345 # What is the `APropdef` associated to a `MProperty`?
346 # Used to check multiple definition of a property.
347 var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
348
349 # Build the virtual type `SELF` only for introduction `MClassDef`
350 fun build_self_type(modelbuilder: ModelBuilder, nclassdef: AClassdef)
351 do
352 if not is_intro then return
353
354 var name = "SELF"
355 var mprop = modelbuilder.try_get_mproperty_by_name(nclassdef, self, name)
356
357 # If SELF type is declared nowherer?
358 if mprop == null then return
359
360 # SELF is not a virtual type? it is weird but we ignore it
361 if not mprop isa MVirtualTypeProp then return
362
363 # Is this the intro of SELF in the library?
364 var intro = mprop.intro
365 var intro_mclassdef = intro.mclassdef
366 if intro_mclassdef == self then
367 var nintro = modelbuilder.mpropdef2npropdef[intro]
368
369 # SELF must be declared in Object, otherwise this will create conflicts
370 if intro_mclassdef.mclass.name != "Object" then
371 modelbuilder.error(nintro, "Error: the virtual type SELF must be declared in Object.")
372 end
373
374 # SELF must be public
375 if mprop.visibility != public_visibility then
376 modelbuilder.error(nintro, "Error: the virtual type SELF must be public.")
377 end
378
379 # SELF must not be fixed
380 if intro.is_fixed then
381 modelbuilder.error(nintro, "Error: the virtual type SELF cannot be fixed.")
382 end
383
384 return
385 end
386
387 # This class introduction inherits a SELF
388 # We insert an artificial property to update it
389 var mpropdef = new MVirtualTypeDef(self, mprop, self.location)
390 mpropdef.bound = mclass.mclass_type
391 end
392 end
393
394 redef class APropdef
395 # The associated main model entity
396 type MPROPDEF: MPropDef
397
398 # The associated propdef once build by a `ModelBuilder`
399 var mpropdef: nullable MPROPDEF is writable
400
401 private fun build_property(modelbuilder: ModelBuilder, mclassdef: MClassDef) is abstract
402 private fun build_signature(modelbuilder: ModelBuilder) is abstract
403 private fun check_signature(modelbuilder: ModelBuilder) is abstract
404 private fun new_property_visibility(modelbuilder: ModelBuilder, mclassdef: MClassDef, nvisibility: nullable AVisibility): MVisibility
405 do
406 var mvisibility = public_visibility
407 if nvisibility != null then
408 mvisibility = nvisibility.mvisibility
409 if mvisibility == intrude_visibility then
410 modelbuilder.error(nvisibility, "Error: intrude is not a legal visibility for properties.")
411 mvisibility = public_visibility
412 end
413 end
414 if mclassdef.mclass.visibility == private_visibility then
415 if mvisibility == protected_visibility then
416 assert nvisibility != null
417 modelbuilder.error(nvisibility, "Error: The only legal visibility for properties in a private class is private.")
418 else if mvisibility == private_visibility then
419 assert nvisibility != null
420 modelbuilder.advice(nvisibility, "useless-visibility", "Warning: private is superfluous since the only legal visibility for properties in a private class is private.")
421 end
422 mvisibility = private_visibility
423 end
424 return mvisibility
425 end
426
427 private fun set_doc(mpropdef: MPropDef, modelbuilder: ModelBuilder)
428 do
429 var ndoc = self.n_doc
430 if ndoc != null then
431 var mdoc = ndoc.to_mdoc
432 mpropdef.mdoc = mdoc
433 mdoc.original_mentity = mpropdef
434 else if mpropdef.is_intro and mpropdef.mproperty.visibility >= protected_visibility then
435 modelbuilder.advice(self, "missing-doc", "Documentation warning: Undocumented property `{mpropdef.mproperty}`")
436 end
437
438 var at_deprecated = get_single_annotation("deprecated", modelbuilder)
439 if at_deprecated != null then
440 if not mpropdef.is_intro then
441 modelbuilder.error(self, "Error: method redefinition cannot be deprecated.")
442 else
443 var info = new MDeprecationInfo
444 ndoc = at_deprecated.n_doc
445 if ndoc != null then info.mdoc = ndoc.to_mdoc
446 mpropdef.mproperty.deprecation = info
447 end
448 end
449 end
450
451 private fun check_redef_property_visibility(modelbuilder: ModelBuilder, nvisibility: nullable AVisibility, mprop: MProperty)
452 do
453 if nvisibility == null then return
454 var mvisibility = nvisibility.mvisibility
455 if mvisibility != mprop.visibility and mvisibility != public_visibility then
456 modelbuilder.error(nvisibility, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
457 end
458 end
459
460 private fun check_redef_keyword(modelbuilder: ModelBuilder, mclassdef: MClassDef, kwredef: nullable Token, need_redef: Bool, mprop: MProperty): Bool
461 do
462 if mclassdef.mprop2npropdef.has_key(mprop) then
463 modelbuilder.error(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
464 return false
465 end
466 if mprop isa MMethod and mprop.is_toplevel != (parent isa ATopClassdef) then
467 if mprop.is_toplevel then
468 modelbuilder.error(self, "Error: {mprop} is a top level method.")
469 else
470 modelbuilder.error(self, "Error: {mprop} is not a top level method.")
471 end
472 return false
473
474 end
475 if mprop isa MMethod and mprop.is_root_init then return true
476 if kwredef == null then
477 if need_redef then
478 modelbuilder.error(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
479 return false
480 end
481
482 # Check for full-name conflicts in the project.
483 # A public property should have a unique qualified name `project::class::prop`.
484 if mprop.intro_mclassdef.mmodule.mgroup != null and mprop.visibility >= protected_visibility then
485 var others = modelbuilder.model.get_mproperties_by_name(mprop.name)
486 if others != null then for other in others do
487 if other != mprop and other.intro_mclassdef.mmodule.mgroup != null and other.intro_mclassdef.mmodule.mgroup.mproject == mprop.intro_mclassdef.mmodule.mgroup.mproject and other.intro_mclassdef.mclass.name == mprop.intro_mclassdef.mclass.name and other.visibility >= protected_visibility then
488 modelbuilder.advice(self, "full-name-conflict", "Warning: A property named `{other.full_name}` is already defined in module `{other.intro_mclassdef.mmodule}` for the class `{other.intro_mclassdef.mclass.name}`.")
489 break
490 end
491 end
492 end
493 else
494 if not need_redef then
495 modelbuilder.error(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
496 return false
497 end
498 end
499 return true
500 end
501
502 end
503
504 redef class ASignature
505 # Is the model builder has correctly visited the signature
506 var is_visited = false
507 # Names of parameters from the AST
508 # REQUIRE: is_visited
509 var param_names = new Array[String]
510 # Types of parameters from the AST
511 # REQUIRE: is_visited
512 var param_types = new Array[MType]
513 # Rank of the vararg (of -1 if none)
514 # REQUIRE: is_visited
515 var vararg_rank: Int = -1
516 # Return type
517 var ret_type: nullable MType = null
518
519 # Visit and fill information about a signature
520 private fun visit_signature(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
521 do
522 var mmodule = mclassdef.mmodule
523 var param_names = self.param_names
524 var param_types = self.param_types
525 for np in self.n_params do
526 param_names.add(np.n_id.text)
527 var ntype = np.n_type
528 if ntype != null then
529 var mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
530 if mtype == null then return false # Skip error
531 for i in [0..param_names.length-param_types.length[ do
532 param_types.add(mtype)
533 end
534 if np.n_dotdotdot != null then
535 if self.vararg_rank != -1 then
536 modelbuilder.error(np, "Error: {param_names[self.vararg_rank]} is already a vararg")
537 return false
538 else
539 self.vararg_rank = param_names.length - 1
540 end
541 end
542 end
543 end
544 var ntype = self.n_type
545 if ntype != null then
546 self.ret_type = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
547 if self.ret_type == null then return false # Skip error
548 end
549
550 self.is_visited = true
551 return true
552 end
553
554 # Build a visited signature
555 fun build_signature(modelbuilder: ModelBuilder): nullable MSignature
556 do
557 if param_names.length != param_types.length then
558 # Some parameters are typed, other parameters are not typed.
559 modelbuilder.error(self.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
560 return null
561 end
562
563 var mparameters = new Array[MParameter]
564 for i in [0..param_names.length[ do
565 var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
566 self.n_params[i].mparameter = mparameter
567 mparameters.add(mparameter)
568 end
569
570 var msignature = new MSignature(mparameters, ret_type)
571 return msignature
572 end
573 end
574
575 redef class AParam
576 # The associated mparameter if any
577 var mparameter: nullable MParameter = null
578 end
579
580 redef class AMethPropdef
581 redef type MPROPDEF: MMethodDef
582
583
584 # Can self be used as a root init?
585 private fun look_like_a_root_init(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
586 do
587 # Need the `init` keyword
588 if n_kwinit == null then return false
589 # Need to by anonymous
590 if self.n_methid != null then return false
591 # No annotation on itself
592 if get_single_annotation("old_style_init", modelbuilder) != null then return false
593 # Nor on its module
594 var amod = self.parent.parent.as(AModule)
595 var amoddecl = amod.n_moduledecl
596 if amoddecl != null then
597 var old = amoddecl.get_single_annotation("old_style_init", modelbuilder)
598 if old != null then return false
599 end
600 # No parameters
601 if self.n_signature.n_params.length > 0 then
602 modelbuilder.advice(self, "old-init", "Warning: init with signature in {mclassdef}")
603 return false
604 end
605 # Cannot be private or something
606 if not self.n_visibility isa APublicVisibility then
607 modelbuilder.advice(self, "old-init", "Warning: non-public init in {mclassdef}")
608 return false
609 end
610
611 return true
612 end
613
614 redef fun build_property(modelbuilder, mclassdef)
615 do
616 var n_kwinit = n_kwinit
617 var n_kwnew = n_kwnew
618 var is_init = n_kwinit != null or n_kwnew != null
619 var name: String
620 var amethodid = self.n_methid
621 var name_node: ANode
622 if amethodid == null then
623 if not is_init then
624 name = "main"
625 name_node = self
626 else if n_kwinit != null then
627 name = "init"
628 name_node = n_kwinit
629 else if n_kwnew != null then
630 name = "new"
631 name_node = n_kwnew
632 else
633 abort
634 end
635 else if amethodid isa AIdMethid then
636 name = amethodid.n_id.text
637 name_node = amethodid
638 else
639 # operator, bracket or assign
640 name = amethodid.collect_text
641 name_node = amethodid
642
643 if name == "-" and self.n_signature.n_params.length == 0 then
644 name = "unary -"
645 end
646 end
647
648 var look_like_a_root_init = look_like_a_root_init(modelbuilder, mclassdef)
649 var mprop: nullable MMethod = null
650 if not is_init or n_kwredef != null then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
651 if mprop == null and look_like_a_root_init then
652 mprop = modelbuilder.the_root_init_mmethod
653 var nb = n_block
654 if nb isa ABlockExpr and nb.n_expr.is_empty and n_doc == null then
655 modelbuilder.advice(self, "useless-init", "Warning: useless empty init in {mclassdef}")
656 end
657 end
658 if mprop == null then
659 var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
660 mprop = new MMethod(mclassdef, name, mvisibility)
661 if look_like_a_root_init and modelbuilder.the_root_init_mmethod == null then
662 modelbuilder.the_root_init_mmethod = mprop
663 mprop.is_root_init = true
664 end
665 mprop.is_init = is_init
666 mprop.is_new = n_kwnew != null
667 if parent isa ATopClassdef then mprop.is_toplevel = true
668 self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop)
669 else
670 if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, not self isa AMainMethPropdef, mprop) then return
671 check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
672 end
673
674 # Check name conflicts in the local class for constructors.
675 if is_init then
676 for p, n in mclassdef.mprop2npropdef do
677 if p != mprop and p isa MMethod and p.name == name then
678 check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, p)
679 break
680 end
681 end
682 end
683
684 mclassdef.mprop2npropdef[mprop] = self
685
686 var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
687
688 set_doc(mpropdef, modelbuilder)
689
690 self.mpropdef = mpropdef
691 modelbuilder.mpropdef2npropdef[mpropdef] = self
692 if mpropdef.is_intro then
693 modelbuilder.toolcontext.info("{mpropdef} introduces new method {mprop.full_name}", 4)
694 else
695 modelbuilder.toolcontext.info("{mpropdef} redefines method {mprop.full_name}", 4)
696 end
697 end
698
699 redef fun build_signature(modelbuilder)
700 do
701 var mpropdef = self.mpropdef
702 if mpropdef == null then return # Error thus skiped
703 var mclassdef = mpropdef.mclassdef
704 var mmodule = mclassdef.mmodule
705 var nsig = self.n_signature
706
707 if mpropdef.mproperty.is_root_init and not mclassdef.is_intro then
708 var root_init = mclassdef.mclass.root_init
709 if root_init != null then
710 # Inherit the initializers by refinement
711 mpropdef.new_msignature = root_init.new_msignature
712 assert mpropdef.initializers.is_empty
713 mpropdef.initializers.add_all root_init.initializers
714 end
715 end
716
717 # Retrieve info from the signature AST
718 var param_names = new Array[String] # Names of parameters from the AST
719 var param_types = new Array[MType] # Types of parameters from the AST
720 var vararg_rank = -1
721 var ret_type: nullable MType = null # Return type from the AST
722 if nsig != null then
723 if not nsig.visit_signature(modelbuilder, mclassdef) then return
724 param_names = nsig.param_names
725 param_types = nsig.param_types
726 vararg_rank = nsig.vararg_rank
727 ret_type = nsig.ret_type
728 end
729
730 # Look for some signature to inherit
731 # FIXME: do not inherit from the intro, but from the most specific
732 var msignature: nullable MSignature = null
733 if not mpropdef.is_intro then
734 msignature = mpropdef.mproperty.intro.msignature
735 if msignature == null then return # Skip error
736
737 # The local signature is adapted to use the local formal types, if any.
738 msignature = msignature.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mmodule, false)
739
740 # Check inherited signature arity
741 if param_names.length != msignature.arity then
742 var node: ANode
743 if nsig != null then node = nsig else node = self
744 modelbuilder.error(node, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
745 return
746 end
747 else if mpropdef.mproperty.is_init and not mpropdef.mproperty.is_new then
748 # FIXME UGLY: inherit signature from a super-constructor
749 for msupertype in mclassdef.supertypes do
750 msupertype = msupertype.anchor_to(mmodule, mclassdef.bound_mtype)
751 var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mpropdef.mproperty.name)
752 if candidate != null then
753 if msignature == null then
754 msignature = candidate.intro.as(MMethodDef).msignature
755 end
756 end
757 end
758 end
759
760
761 # Inherit the signature
762 if msignature != null and param_names.length != param_types.length and param_names.length == msignature.arity and param_types.length == 0 then
763 # Parameters are untyped, thus inherit them
764 param_types = new Array[MType]
765 for mparameter in msignature.mparameters do
766 param_types.add(mparameter.mtype)
767 end
768 vararg_rank = msignature.vararg_rank
769 end
770 if msignature != null and ret_type == null then
771 ret_type = msignature.return_mtype
772 end
773
774 if param_names.length != param_types.length then
775 # Some parameters are typed, other parameters are not typed.
776 modelbuilder.error(nsig.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
777 return
778 end
779
780 var mparameters = new Array[MParameter]
781 for i in [0..param_names.length[ do
782 var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
783 if nsig != null then nsig.n_params[i].mparameter = mparameter
784 mparameters.add(mparameter)
785 end
786
787 # In `new`-factories, the return type is by default the classtype.
788 if ret_type == null and mpropdef.mproperty.is_new then ret_type = mclassdef.mclass.mclass_type
789
790 msignature = new MSignature(mparameters, ret_type)
791 mpropdef.msignature = msignature
792 mpropdef.is_abstract = self.get_single_annotation("abstract", modelbuilder) != null
793 mpropdef.is_intern = self.get_single_annotation("intern", modelbuilder) != null
794 mpropdef.is_extern = self.n_extern_code_block != null or self.get_single_annotation("extern", modelbuilder) != null
795 end
796
797 redef fun check_signature(modelbuilder)
798 do
799 var mpropdef = self.mpropdef
800 if mpropdef == null then return # Error thus skiped
801 var mclassdef = mpropdef.mclassdef
802 var mmodule = mclassdef.mmodule
803 var nsig = self.n_signature
804 var mysignature = self.mpropdef.msignature
805 if mysignature == null then return # Error thus skiped
806
807 # Lookup for signature in the precursor
808 # FIXME all precursors should be considered
809 if not mpropdef.is_intro then
810 var msignature = mpropdef.mproperty.intro.msignature
811 if msignature == null then return
812
813 var precursor_ret_type = msignature.return_mtype
814 var ret_type = mysignature.return_mtype
815 if ret_type != null and precursor_ret_type == null then
816 modelbuilder.error(nsig.n_type.as(not null), "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, mclassdef.bound_mtype, prt) or
826 not prt.is_subtype(mmodule, mclassdef.bound_mtype, myt) then
827 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}.")
828 end
829 end
830 end
831 if precursor_ret_type != null then
832 if ret_type == null then
833 # Inherit the return type
834 ret_type = precursor_ret_type
835 else if not ret_type.is_subtype(mmodule, mclassdef.bound_mtype, precursor_ret_type) then
836 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}.")
837 end
838 end
839 end
840
841 if mysignature.arity > 0 then
842 # Check parameters visibility
843 for i in [0..mysignature.arity[ do
844 var nt = nsig.n_params[i].n_type
845 if nt != null then modelbuilder.check_visibility(nt, nt.mtype.as(not null), mpropdef)
846 end
847 var nt = nsig.n_type
848 if nt != null then modelbuilder.check_visibility(nt, nt.mtype.as(not null), mpropdef)
849 end
850 end
851 end
852
853 redef class AAttrPropdef
854 redef type MPROPDEF: MAttributeDef
855
856 # Is the node tagged `noinit`?
857 var noinit = false
858
859 # Is the node tagged lazy?
860 var is_lazy = false
861
862 # Has the node a default value?
863 # Could be through `n_expr` or `n_block`
864 var has_value = false
865
866 # The guard associated to a lazy attribute.
867 # Because some engines does not have a working `isset`,
868 # this additional attribute is used to guard the lazy initialization.
869 # TODO: to remove once isset is correctly implemented
870 var mlazypropdef: nullable MAttributeDef
871
872 # The associated getter (read accessor) if any
873 var mreadpropdef: nullable MMethodDef is writable
874 # The associated setter (write accessor) if any
875 var mwritepropdef: nullable MMethodDef is writable
876
877 redef fun build_property(modelbuilder, mclassdef)
878 do
879 var mclass = mclassdef.mclass
880
881 var name: String
882 name = self.n_id2.text
883
884 if mclass.kind == interface_kind or mclassdef.mclass.kind == enum_kind then
885 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
886 else if mclass.kind == enum_kind then
887 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
888 else if mclass.kind == extern_kind then
889 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
890 end
891
892 # New attribute style
893 var nid2 = self.n_id2
894 var mprop = new MAttribute(mclassdef, "_" + name, private_visibility)
895 var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
896 self.mpropdef = mpropdef
897 modelbuilder.mpropdef2npropdef[mpropdef] = self
898
899 var readname = name
900 var mreadprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, readname).as(nullable MMethod)
901 if mreadprop == null then
902 var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
903 mreadprop = new MMethod(mclassdef, readname, mvisibility)
904 if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mreadprop) then return
905 mreadprop.deprecation = mprop.deprecation
906 else
907 if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, true, mreadprop) then return
908 check_redef_property_visibility(modelbuilder, self.n_visibility, mreadprop)
909 end
910 mclassdef.mprop2npropdef[mreadprop] = self
911
912 var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
913 self.mreadpropdef = mreadpropdef
914 modelbuilder.mpropdef2npropdef[mreadpropdef] = self
915 set_doc(mreadpropdef, modelbuilder)
916 mpropdef.mdoc = mreadpropdef.mdoc
917
918 has_value = n_expr != null or n_block != null
919
920 var atnoinit = self.get_single_annotation("noinit", modelbuilder)
921 if atnoinit != null then
922 noinit = true
923 if has_value then
924 modelbuilder.error(atnoinit, "Error: `noinit` attributes cannot have an initial value")
925 return
926 end
927 end
928
929 var atlazy = self.get_single_annotation("lazy", modelbuilder)
930 var atautoinit = self.get_single_annotation("autoinit", modelbuilder)
931 if atlazy != null or atautoinit != null then
932 if atlazy != null and atautoinit != null then
933 modelbuilder.error(atlazy, "Error: lazy incompatible with autoinit")
934 return
935 end
936 if not has_value then
937 if atlazy != null then
938 modelbuilder.error(atlazy, "Error: a lazy attribute needs a value")
939 else if atautoinit != null then
940 modelbuilder.error(atautoinit, "Error: a autoinit attribute needs a value")
941 end
942 return
943 end
944 is_lazy = true
945 var mlazyprop = new MAttribute(mclassdef, "lazy _" + name, none_visibility)
946 var mlazypropdef = new MAttributeDef(mclassdef, mlazyprop, self.location)
947 self.mlazypropdef = mlazypropdef
948 end
949
950 var atreadonly = self.get_single_annotation("readonly", modelbuilder)
951 if atreadonly != null then
952 if not has_value then
953 modelbuilder.error(atreadonly, "Error: a readonly attribute needs a value")
954 end
955 # No setter, so just leave
956 return
957 end
958
959 var writename = name + "="
960 var atwritable = self.get_single_annotation("writable", modelbuilder)
961 if atwritable != null then
962 if not atwritable.n_args.is_empty then
963 writename = atwritable.arg_as_id(modelbuilder) or else writename
964 end
965 end
966 var mwriteprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, writename).as(nullable MMethod)
967 var nwkwredef: nullable Token = null
968 if atwritable != null then nwkwredef = atwritable.n_kwredef
969 if mwriteprop == null then
970 var mvisibility
971 if atwritable != null then
972 mvisibility = new_property_visibility(modelbuilder, mclassdef, atwritable.n_visibility)
973 else
974 mvisibility = private_visibility
975 end
976 mwriteprop = new MMethod(mclassdef, writename, mvisibility)
977 if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef, false, mwriteprop) then return
978 mwriteprop.deprecation = mprop.deprecation
979 else
980 if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef or else n_kwredef, true, mwriteprop) then return
981 if atwritable != null then
982 check_redef_property_visibility(modelbuilder, atwritable.n_visibility, mwriteprop)
983 end
984 end
985 mclassdef.mprop2npropdef[mwriteprop] = self
986
987 var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
988 self.mwritepropdef = mwritepropdef
989 modelbuilder.mpropdef2npropdef[mwritepropdef] = self
990 mwritepropdef.mdoc = mpropdef.mdoc
991 end
992
993 redef fun build_signature(modelbuilder)
994 do
995 var mpropdef = self.mpropdef
996 if mpropdef == null then return # Error thus skipped
997 var mclassdef = mpropdef.mclassdef
998 var mmodule = mclassdef.mmodule
999 var mtype: nullable MType = null
1000
1001 var mreadpropdef = self.mreadpropdef
1002
1003 var ntype = self.n_type
1004 if ntype != null then
1005 mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
1006 if mtype == null then return
1007 end
1008
1009 var inherited_type: nullable MType = null
1010 # Inherit the type from the getter (usually an abstract getter)
1011 if mreadpropdef != null and not mreadpropdef.is_intro then
1012 var msignature = mreadpropdef.mproperty.intro.msignature
1013 if msignature == null then return # Error, thus skipped
1014 inherited_type = msignature.return_mtype
1015 if inherited_type != null then
1016 # The inherited type is adapted to use the local formal types, if any.
1017 inherited_type = inherited_type.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mmodule, false)
1018 if mtype == null then mtype = inherited_type
1019 end
1020 end
1021
1022 var nexpr = self.n_expr
1023 if mtype == null then
1024 if nexpr != null then
1025 if nexpr isa ANewExpr then
1026 mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
1027 else if nexpr isa AIntExpr then
1028 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
1029 if cla != null then mtype = cla.mclass_type
1030 else if nexpr isa AFloatExpr then
1031 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Float")
1032 if cla != null then mtype = cla.mclass_type
1033 else if nexpr isa ACharExpr then
1034 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Char")
1035 if cla != null then mtype = cla.mclass_type
1036 else if nexpr isa ABoolExpr then
1037 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Bool")
1038 if cla != null then mtype = cla.mclass_type
1039 else if nexpr isa ASuperstringExpr then
1040 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
1041 if cla != null then mtype = cla.mclass_type
1042 else if nexpr isa AStringFormExpr then
1043 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
1044 if cla != null then mtype = cla.mclass_type
1045 else
1046 modelbuilder.error(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1047 end
1048
1049 if mtype == null then return
1050 end
1051 else if ntype != null and inherited_type == mtype then
1052 if nexpr isa ANewExpr then
1053 var xmtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
1054 if xmtype == mtype then
1055 modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition")
1056 end
1057 end
1058 end
1059
1060 if mtype == null then
1061 modelbuilder.error(self, "Error: Untyped attribute {mpropdef}")
1062 return
1063 end
1064
1065 mpropdef.static_mtype = mtype
1066
1067 if mreadpropdef != null then
1068 var msignature = new MSignature(new Array[MParameter], mtype)
1069 mreadpropdef.msignature = msignature
1070 end
1071
1072 var mwritepropdef = self.mwritepropdef
1073 if mwritepropdef != null then
1074 var name: String
1075 name = n_id2.text
1076 var mparameter = new MParameter(name, mtype, false)
1077 var msignature = new MSignature([mparameter], null)
1078 mwritepropdef.msignature = msignature
1079 end
1080
1081 var mlazypropdef = self.mlazypropdef
1082 if mlazypropdef != null then
1083 mlazypropdef.static_mtype = modelbuilder.model.get_mclasses_by_name("Bool").first.mclass_type
1084 end
1085 end
1086
1087 redef fun check_signature(modelbuilder)
1088 do
1089 var mpropdef = self.mpropdef
1090 if mpropdef == null then return # Error thus skipped
1091 var ntype = self.n_type
1092 var mtype = self.mpropdef.static_mtype
1093 if mtype == null then return # Error thus skipped
1094
1095 # Lookup for signature in the precursor
1096 # FIXME all precursors should be considered
1097 if not mpropdef.is_intro then
1098 var precursor_type = mpropdef.mproperty.intro.static_mtype
1099 if precursor_type == null then return
1100
1101 if mtype != precursor_type then
1102 modelbuilder.error(ntype.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1103 return
1104 end
1105 end
1106
1107 # Check getter and setter
1108 var meth = self.mreadpropdef
1109 if meth != null then
1110 self.check_method_signature(modelbuilder, meth)
1111 var node: nullable ANode = ntype
1112 if node == null then node = self
1113 modelbuilder.check_visibility(node, mtype, meth)
1114 end
1115 meth = self.mwritepropdef
1116 if meth != null then
1117 self.check_method_signature(modelbuilder, meth)
1118 var node: nullable ANode = ntype
1119 if node == null then node = self
1120 modelbuilder.check_visibility(node, mtype, meth)
1121 end
1122 end
1123
1124 private fun check_method_signature(modelbuilder: ModelBuilder, mpropdef: MMethodDef)
1125 do
1126 var mclassdef = mpropdef.mclassdef
1127 var mmodule = mclassdef.mmodule
1128 var nsig = self.n_type
1129 var mysignature = mpropdef.msignature
1130 if mysignature == null then return # Error thus skiped
1131
1132 # Lookup for signature in the precursor
1133 # FIXME all precursors should be considered
1134 if not mpropdef.is_intro then
1135 var msignature = mpropdef.mproperty.intro.msignature
1136 if msignature == null then return
1137
1138 if mysignature.arity != msignature.arity then
1139 var node: ANode
1140 if nsig != null then node = nsig else node = self
1141 modelbuilder.error(node, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1142 return
1143 end
1144 var precursor_ret_type = msignature.return_mtype
1145 var ret_type = mysignature.return_mtype
1146 if ret_type != null and precursor_ret_type == null then
1147 var node: ANode
1148 if nsig != null then node = nsig else node = self
1149 modelbuilder.error(node, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1150 return
1151 end
1152
1153 if mysignature.arity > 0 then
1154 # Check parameters types
1155 for i in [0..mysignature.arity[ do
1156 var myt = mysignature.mparameters[i].mtype
1157 var prt = msignature.mparameters[i].mtype
1158 if not myt.is_subtype(mmodule, mclassdef.bound_mtype, prt) or
1159 not prt.is_subtype(mmodule, mclassdef.bound_mtype, myt) then
1160 var node: ANode
1161 if nsig != null then node = nsig else node = self
1162 modelbuilder.error(node, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1163 end
1164 end
1165 end
1166 if precursor_ret_type != null then
1167 if ret_type == null then
1168 # Inherit the return type
1169 ret_type = precursor_ret_type
1170 else if not ret_type.is_subtype(mmodule, mclassdef.bound_mtype, precursor_ret_type) then
1171 var node: ANode
1172 if nsig != null then node = nsig else node = self
1173 modelbuilder.error(node, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1174 end
1175 end
1176 end
1177 end
1178 end
1179
1180 redef class ATypePropdef
1181 redef type MPROPDEF: MVirtualTypeDef
1182
1183 redef fun build_property(modelbuilder, mclassdef)
1184 do
1185 var name = self.n_id.text
1186 var mprop = modelbuilder.try_get_mproperty_by_name(self.n_id, mclassdef, name)
1187 if mprop == null then
1188 var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
1189 mprop = new MVirtualTypeProp(mclassdef, name, mvisibility)
1190 for c in name.chars do if c >= 'a' and c<= 'z' then
1191 modelbuilder.warning(n_id, "bad-type-name", "Warning: lowercase in the virtual type {name}")
1192 break
1193 end
1194 if not self.check_redef_keyword(modelbuilder, mclassdef, self.n_kwredef, false, mprop) then return
1195 else
1196 if not self.check_redef_keyword(modelbuilder, mclassdef, self.n_kwredef, true, mprop) then return
1197 assert mprop isa MVirtualTypeProp
1198 check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
1199 end
1200 mclassdef.mprop2npropdef[mprop] = self
1201
1202 var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
1203 self.mpropdef = mpropdef
1204 modelbuilder.mpropdef2npropdef[mpropdef] = self
1205 if mpropdef.is_intro then
1206 modelbuilder.toolcontext.info("{mpropdef} introduces new type {mprop.full_name}", 4)
1207 else
1208 modelbuilder.toolcontext.info("{mpropdef} redefines type {mprop.full_name}", 4)
1209 end
1210 set_doc(mpropdef, modelbuilder)
1211
1212 var atfixed = get_single_annotation("fixed", modelbuilder)
1213 if atfixed != null then
1214 mpropdef.is_fixed = true
1215 end
1216 end
1217
1218 redef fun build_signature(modelbuilder)
1219 do
1220 var mpropdef = self.mpropdef
1221 if mpropdef == null then return # Error thus skipped
1222 var mclassdef = mpropdef.mclassdef
1223 var mmodule = mclassdef.mmodule
1224 var mtype: nullable MType = null
1225
1226 var ntype = self.n_type
1227 mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
1228 if mtype == null then return
1229
1230 mpropdef.bound = mtype
1231 # print "{mpropdef}: {mtype}"
1232 end
1233
1234 redef fun check_signature(modelbuilder)
1235 do
1236 var mpropdef = self.mpropdef
1237 if mpropdef == null then return # Error thus skipped
1238
1239 var bound = self.mpropdef.bound
1240 if bound == null then return # Error thus skipped
1241
1242 modelbuilder.check_visibility(n_type, bound, mpropdef)
1243
1244 var mclassdef = mpropdef.mclassdef
1245 var mmodule = mclassdef.mmodule
1246 var anchor = mclassdef.bound_mtype
1247
1248 # Check circularity
1249 if bound isa MVirtualType then
1250 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1251 var seen = [self.mpropdef.mproperty.mvirtualtype]
1252 loop
1253 if seen.has(bound) then
1254 seen.add(bound)
1255 modelbuilder.error(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1256 return
1257 end
1258 seen.add(bound)
1259 var next = bound.lookup_bound(mmodule, anchor)
1260 if not next isa MVirtualType then break
1261 bound = next
1262 end
1263 end
1264
1265 # Check redefinitions
1266 bound = mpropdef.bound.as(not null)
1267 for p in mpropdef.mproperty.lookup_super_definitions(mmodule, anchor) do
1268 var supbound = p.bound
1269 if supbound == null then break # broken super bound, skip error
1270 if p.is_fixed then
1271 modelbuilder.error(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
1272 break
1273 end
1274 if p.mclassdef.mclass == mclassdef.mclass then
1275 # Still a warning to pass existing bad code
1276 modelbuilder.warning(n_type, "refine-type", "Redef Error: a virtual type cannot be refined.")
1277 break
1278 end
1279 if not bound.is_subtype(mmodule, anchor, supbound) then
1280 modelbuilder.error(n_type, "Redef Error: Wrong bound type. Found {bound}, expected a subtype of {supbound}, as in {p}.")
1281 break
1282 end
1283 end
1284 end
1285 end