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