build_properties(mclassdef2nclassdef[superclassdef])
end
+ mclassdef.build_self_type(self, nclassdef)
for nclassdef2 in nclassdef.all_defs do
for npropdef in nclassdef2.n_propdefs do
npropdef.build_property(self, mclassdef)
end
if npropdef isa AAttrPropdef then
if npropdef.mpropdef == null then return # Skip broken attribute
- var at = npropdef.get_single_annotation("noinit", self)
- if at != null then
- npropdef.noinit = true
- if npropdef.n_expr != null then
- self.error(at, "Error: `noinit` attributes cannot have an initial value")
- end
- continue # Skip noinit attributes
+ if npropdef.noinit then continue # Skip noinit attribute
+ var atautoinit = npropdef.get_single_annotation("autoinit", self)
+ if atautoinit != null then
+ # For autoinit attributes, call the reader to force
+ # the lazy initialization of the attribute.
+ initializers.add(npropdef.mreadpropdef.mproperty)
+ continue
end
- if npropdef.n_expr != null then continue
+ if npropdef.has_value then continue
var paramname = npropdef.mpropdef.mproperty.name.substring_from(1)
var ret_type = npropdef.mpropdef.static_mtype
if ret_type == null then return
# What is the `APropdef` associated to a `MProperty`?
# Used to check multiple definition of a property.
var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
+
+ # Build the virtual type `SELF` only for introduction `MClassDef`
+ fun build_self_type(modelbuilder: ModelBuilder, nclassdef: AClassdef)
+ do
+ if not is_intro then return
+
+ var name = "SELF"
+ var mprop = modelbuilder.try_get_mproperty_by_name(nclassdef, self, name)
+
+ # If SELF type is declared nowherer?
+ if mprop == null then return
+
+ # SELF is not a virtual type? it is weird but we ignore it
+ if not mprop isa MVirtualTypeProp then return
+
+ # Is this the intro of SELF in the library?
+ var intro = mprop.intro
+ var intro_mclassdef = intro.mclassdef
+ if intro_mclassdef == self then
+ var nintro = modelbuilder.mpropdef2npropdef[intro]
+
+ # SELF must be declared in Object, otherwise this will create conflicts
+ if intro_mclassdef.mclass.name != "Object" then
+ modelbuilder.error(nintro, "Error: the virtual type SELF must be declared in Object.")
+ end
+
+ # SELF must be public
+ if mprop.visibility != public_visibility then
+ modelbuilder.error(nintro, "Error: the virtual type SELF must be public.")
+ end
+
+ # SELF must not be fixed
+ if intro.is_fixed then
+ modelbuilder.error(nintro, "Error: the virtual type SELF cannot be fixed.")
+ end
+
+ return
+ end
+
+ # This class introduction inherits a SELF
+ # We insert an artificial property to update it
+ var mpropdef = new MVirtualTypeDef(self, mprop, self.location)
+ mpropdef.bound = mclass.mclass_type
+ end
end
redef class APropdef
# Can self be used as a root init?
- private fun look_like_a_root_init(modelbuilder: ModelBuilder): Bool
+ private fun look_like_a_root_init(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
do
# Need the `init` keyword
if n_kwinit == null then return false
# Need to by anonymous
if self.n_methid != null then return false
- # No parameters
- if self.n_signature.n_params.length > 0 then return false
- # Cannot be private or something
- if not self.n_visibility isa APublicVisibility then return false
# No annotation on itself
if get_single_annotation("old_style_init", modelbuilder) != null then return false
# Nor on its module
var old = amoddecl.get_single_annotation("old_style_init", modelbuilder)
if old != null then return false
end
+ # No parameters
+ if self.n_signature.n_params.length > 0 then
+ modelbuilder.advice(self, "old-init", "Warning: init with signature in {mclassdef}")
+ return false
+ end
+ # Cannot be private or something
+ if not self.n_visibility isa APublicVisibility then
+ modelbuilder.advice(self, "old-init", "Warning: non-public init in {mclassdef}")
+ return false
+ end
return true
end
end
end
+ var look_like_a_root_init = look_like_a_root_init(modelbuilder, mclassdef)
var mprop: nullable MMethod = null
if not is_init or n_kwredef != null then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
- if mprop == null and look_like_a_root_init(modelbuilder) then
+ if mprop == null and look_like_a_root_init then
mprop = modelbuilder.the_root_init_mmethod
var nb = n_block
if nb isa ABlockExpr and nb.n_expr.is_empty and n_doc == null then
if mprop == null then
var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
mprop = new MMethod(mclassdef, name, mvisibility)
- if look_like_a_root_init(modelbuilder) and modelbuilder.the_root_init_mmethod == null then
+ if look_like_a_root_init and modelbuilder.the_root_init_mmethod == null then
modelbuilder.the_root_init_mmethod = mprop
mprop.is_root_init = true
end
self.mpropdef = mpropdef
modelbuilder.mpropdef2npropdef[mpropdef] = self
if mpropdef.is_intro then
- modelbuilder.toolcontext.info("{mpropdef} introduces new method {mprop.full_name}", 3)
+ modelbuilder.toolcontext.info("{mpropdef} introduces new method {mprop.full_name}", 4)
else
- modelbuilder.toolcontext.info("{mpropdef} redefines method {mprop.full_name}", 3)
+ modelbuilder.toolcontext.info("{mpropdef} redefines method {mprop.full_name}", 4)
end
end
# Is the node tagged lazy?
var is_lazy = false
+ # Has the node a default value?
+ # Could be through `n_expr` or `n_block`
+ var has_value = false
+
# The guard associated to a lazy attribute.
# Because some engines does not have a working `isset`,
# this additional attribute is used to guard the lazy initialization.
set_doc(mreadpropdef, modelbuilder)
mpropdef.mdoc = mreadpropdef.mdoc
+ has_value = n_expr != null or n_block != null
+
+ var atnoinit = self.get_single_annotation("noinit", modelbuilder)
+ if atnoinit != null then
+ noinit = true
+ if has_value then
+ modelbuilder.error(atnoinit, "Error: `noinit` attributes cannot have an initial value")
+ return
+ end
+ end
+
var atlazy = self.get_single_annotation("lazy", modelbuilder)
- if atlazy != null then
- if n_expr == null then
- modelbuilder.error(atlazy, "Error: a lazy attribute needs a value")
+ var atautoinit = self.get_single_annotation("autoinit", modelbuilder)
+ if atlazy != null or atautoinit != null then
+ if atlazy != null and atautoinit != null then
+ modelbuilder.error(atlazy, "Error: lazy incompatible with autoinit")
+ return
+ end
+ if not has_value then
+ if atlazy != null then
+ modelbuilder.error(atlazy, "Error: a lazy attribute needs a value")
+ else if atautoinit != null then
+ modelbuilder.error(atautoinit, "Error: a autoinit attribute needs a value")
+ end
+ return
end
is_lazy = true
var mlazyprop = new MAttribute(mclassdef, "lazy _" + name, none_visibility)
var atreadonly = self.get_single_annotation("readonly", modelbuilder)
if atreadonly != null then
- if n_expr == null then
+ if not has_value then
modelbuilder.error(atreadonly, "Error: a readonly attribute needs a value")
end
# No setter, so just leave
if mtype == null then return
end
+ var inherited_type: nullable MType = null
# Inherit the type from the getter (usually an abstract getter)
- if mtype == null and mreadpropdef != null and not mreadpropdef.is_intro then
+ if mreadpropdef != null and not mreadpropdef.is_intro then
var msignature = mreadpropdef.mproperty.intro.msignature
if msignature == null then return # Error, thus skipped
- mtype = msignature.return_mtype
+ inherited_type = msignature.return_mtype
+ if mtype == null then mtype = inherited_type
end
var nexpr = self.n_expr
if mtype == null then return
end
- else if ntype != null then
+ else if ntype != null and inherited_type == mtype then
if nexpr isa ANewExpr then
var xmtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
if xmtype == mtype then