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