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