return
end
- # Is the class forbid constructors?
- if not mclassdef.mclass.kind.need_init then return
-
# Is there already a constructor defined?
var defined_init: nullable MMethodDef = null
for mpropdef in mclassdef.mpropdefs do
var initializers = new Array[MProperty]
for npropdef in nclassdef.n_propdefs do
if npropdef isa AMethPropdef then
+ if not npropdef.is_autoinit then continue # Skip non tagged autoinit
if npropdef.mpropdef == null then return # Skip broken method
- var at = npropdef.get_single_annotation("autoinit", self)
- if at == null then continue # Skip non tagged init
-
var sig = npropdef.mpropdef.msignature
if sig == null then continue # Skip broken method
- if not npropdef.mpropdef.is_intro then
- self.error(at, "Error: `autoinit` cannot be set on redefinitions.")
- continue
- end
-
for param in sig.mparameters do
var ret_type = param.mtype
- var mparameter = new MParameter(param.name, ret_type, false, ret_type isa MNullableType)
+ var mparameter = new MParameter(param.name, ret_type, false)
mparameters.add(mparameter)
end
initializers.add(npropdef.mpropdef.mproperty)
var mreadpropdef = npropdef.mreadpropdef
if mreadpropdef == null or mreadpropdef.msignature == null then return # Skip broken attribute
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
+ var atlateinit = npropdef.get_single_annotation("lateinit", self)
+ if atlateinit != null then
+ # For lateinit attributes, call the reader to force
# the lazy initialization of the attribute.
initializers.add(mreadpropdef.mproperty)
mreadpropdef.mproperty.is_autoinit = true
var paramname = mreadpropdef.mproperty.name
var ret_type = mreadpropdef.msignature.return_mtype
if ret_type == null then return
- var mparameter = new MParameter(paramname, ret_type, false, ret_type isa MNullableType)
+ var mparameter = new MParameter(paramname, ret_type, false)
mparameters.add(mparameter)
var msetter = npropdef.mwritepropdef
if msetter == null then
if pd isa MMethodDef then
# Get the signature resolved for the current receiver
var sig = pd.msignature.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mclassdef.mmodule, false)
- # Because the last parameter of setters is never default, try to default them for the autoinit.
- for param in sig.mparameters do
- if not param.is_default and param.mtype isa MNullableType then
- param = new MParameter(param.name, param.mtype, param.is_vararg, true)
- end
- mparameters.add(param)
- end
+ mparameters.add_all(sig.mparameters)
else
# TODO attributes?
abort
end
end
- else if noautoinit != null then
- if initializers.is_empty then
- warning(noautoinit, "useless-noautoinit", "Warning: the list of autoinit is already empty.")
- end
- # Just clear initializers
- mparameters.clear
- initializers.clear
else
# Search the longest-one and checks for conflict
var longest = spropdefs.first
if spropdefs.length > 1 then
- # Check for conflict in the order of initializers
- # Each initializer list must me a prefix of the longest list
# part 1. find the longest list
for spd in spropdefs do
if spd.initializers.length > longest.initializers.length then longest = spd
end
# part 2. compare
- for spd in spropdefs do
+ # Check for conflict in the order of initializers
+ # Each initializer list must me a prefix of the longest list
+ # If `noautoinit` is set, just ignore conflicts
+ if noautoinit == null then for spd in spropdefs do
var i = 0
for p in spd.initializers do
if p != longest.initializers[i] then
- self.error(nclassdef, "Error: conflict for inherited inits {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")})")
+ var proposal = new ArraySet[MProperty]
+ for spd2 in spropdefs do
+ proposal.add_all spd2.initializers
+ end
+ proposal.add_all initializers
+ self.error(nclassdef, "Error: cannot generate automatic init for class {mclassdef.mclass}. Conflict in the order in inherited initializers {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")}). Use `autoinit` to order initializers. eg `autoinit {proposal.join(", ")}`")
# TODO: invalidate the initializer to avoid more errors
return
end
end
end
- # Can we just inherit?
- if spropdefs.length == 1 and mparameters.is_empty and defined_init == null then
- self.toolcontext.info("{mclassdef} inherits the basic constructor {longest}", 3)
- mclassdef.mclass.root_init = longest
- return
- end
+ if noautoinit != null then
+ # If there is local or inherited initializers, then complain.
+ if initializers.is_empty and longest.initializers.is_empty then
+ warning(noautoinit, "useless-noautoinit", "Warning: the list of autoinit is already empty.")
+ end
+ # Just clear initializers
+ mparameters.clear
+ initializers.clear
+ else
+ # Can we just inherit?
+ if spropdefs.length == 1 and mparameters.is_empty and defined_init == null then
+ self.toolcontext.info("{mclassdef} inherits the basic constructor {longest}", 3)
+ mclassdef.mclass.root_init = longest
+ return
+ end
- # Combine the inherited list to what is collected
- if longest.initializers.length > 0 then
- mparameters.prepend longest.new_msignature.mparameters
- initializers.prepend longest.initializers
+ # Combine the inherited list to what is collected
+ if longest.initializers.length > 0 then
+ mparameters.prepend longest.new_msignature.mparameters
+ initializers.prepend longest.initializers
+ end
end
end
return false
end
- # Check for full-name conflicts in the project.
- # A public property should have a unique qualified name `project::class::prop`.
+ # Check for full-name conflicts in the package.
+ # A public property should have a unique qualified name `package::class::prop`.
if mprop.intro_mclassdef.mmodule.mgroup != null and mprop.visibility >= protected_visibility then
var others = modelbuilder.model.get_mproperties_by_name(mprop.name)
if others != null then for other in others do
- 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
+ if other != mprop and other.intro_mclassdef.mmodule.mgroup != null and other.intro_mclassdef.mmodule.mgroup.mpackage == mprop.intro_mclassdef.mmodule.mgroup.mpackage and other.intro_mclassdef.mclass.name == mprop.intro_mclassdef.mclass.name and other.visibility >= protected_visibility then
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}`.")
break
end
return true
end
+ # Checks for useless type in redef signatures.
+ private fun check_repeated_types(modelbuilder: ModelBuilder) do end
end
redef class ASignature
redef class AMethPropdef
redef type MPROPDEF: MMethodDef
+ # Is the method annotated `autoinit`?
+ var is_autoinit = false
# Can self be used as a root init?
private fun look_like_a_root_init(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
var mparameters = new Array[MParameter]
for i in [0..param_names.length[ do
- var is_default = false
- if vararg_rank == -1 and param_types[i] isa MNullableType then
- if i < param_names.length-1 or accept_special_last_parameter then
- is_default = true
- end
- end
- var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank, is_default)
+ var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
if nsig != null then nsig.n_params[i].mparameter = mparameter
mparameters.add(mparameter)
end
# Check annotations
var at = self.get_single_annotation("lazy", modelbuilder)
if at != null then modelbuilder.error(at, "Syntax Error: `lazy` must be used on attributes.")
+
+ var atautoinit = self.get_single_annotation("autoinit", modelbuilder)
+ if atautoinit != null then
+ if not mpropdef.is_intro then
+ modelbuilder.error(atautoinit, "Error: `autoinit` cannot be set on redefinitions.")
+ else if not mclassdef.is_intro then
+ modelbuilder.error(atautoinit, "Error: `autoinit` cannot be used in class refinements.")
+ else
+ self.is_autoinit = true
+ end
+ end
end
redef fun check_signature(modelbuilder)
var nt = nsig.n_type
if nt != null then modelbuilder.check_visibility(nt, nt.mtype.as(not null), mpropdef)
end
+ check_repeated_types(modelbuilder)
+ end
+
+ # For parameters, type is always useless in a redef.
+ # For return type, type is useless if not covariant with introduction.
+ redef fun check_repeated_types(modelbuilder) do
+ if mpropdef.is_intro or n_signature == null then return
+ # check params
+ for param in n_signature.n_params do
+ if param.n_type != null then
+ modelbuilder.advice(param.n_type, "useless-signature", "Warning: useless type repetition on parameter `{param.n_id.text}` for redefined method `{mpropdef.name}`")
+ end
+ end
+ # get intro
+ var intro = mpropdef.mproperty.intro
+ var n_intro = modelbuilder.mpropdef2npropdef.get_or_null(intro)
+ if n_intro == null or not n_intro isa AMethPropdef then return
+ # check return type
+ var ret_type = n_signature.ret_type
+ if ret_type != null and ret_type == n_intro.n_signature.ret_type then
+ modelbuilder.advice(n_signature.n_type, "useless-signature", "Warning: useless return type repetition for redefined method `{mpropdef.name}`")
+ end
end
end
redef class AAttrPropdef
redef type MPROPDEF: MAttributeDef
+ # The static type of the property (declared, inferred or inherited)
+ # This attribute is also used to check if the property was analyzed and is valid.
+ var mtype: nullable MType
+
# Is the node tagged `noinit`?
var noinit = false
return
end
if atabstract != null then
- modelbuilder.error(atnoinit, "Error: `noautoinit` attributes cannot be abstract.")
- return
+ modelbuilder.warning(atnoinit, "useless-noautoinit", "Warning: superfluous `noautoinit` on abstract attribute.")
end
end
var atlazy = self.get_single_annotation("lazy", modelbuilder)
- 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`.")
+ var atlateinit = self.get_single_annotation("lateinit", modelbuilder)
+ if atlazy != null or atlateinit != null then
+ if atlazy != null and atlateinit != null then
+ modelbuilder.error(atlazy, "Error: `lazy` incompatible with `lateinit`.")
return
end
if not has_value then
if atlazy != null then
modelbuilder.error(atlazy, "Error: `lazy` attributes need a value.")
- else if atautoinit != null then
- modelbuilder.error(atautoinit, "Error: `autoinit` attributes need a value.")
+ else if atlateinit != null then
+ modelbuilder.error(atlateinit, "Error: `lateinit` attributes need a value.")
end
has_value = true
return
if atwritable != null then
mvisibility = new_property_visibility(modelbuilder, mclassdef, atwritable.n_visibility)
else
- mvisibility = private_visibility
+ mvisibility = mreadprop.visibility
+ # By default, use protected visibility at most
+ if mvisibility > protected_visibility then mvisibility = protected_visibility
end
mwriteprop = new MMethod(mclassdef, writename, mvisibility)
if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef, false, mwriteprop) then return
modelbuilder.mpropdef2npropdef[mwritepropdef] = self
mwritepropdef.mdoc = mreadpropdef.mdoc
if atabstract != null then mwritepropdef.is_abstract = true
+
+ var atautoinit = self.get_single_annotation("autoinit", modelbuilder)
+ if atautoinit != null then
+ if has_value then
+ modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot have an initial value.")
+ else if not mwritepropdef.is_intro then
+ modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be set on redefinitions.")
+ else if not mclassdef.is_intro then
+ modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be used in class refinements.")
+ else if atabstract == null then
+ modelbuilder.warning(atautoinit, "useless-autoinit", "Warning: superfluous `autoinit` on attribute.")
+ end
+ else if atabstract != null then
+ # By default, abstract attribute are not autoinit
+ noinit = true
+ end
end
redef fun build_signature(modelbuilder)
if nexpr != null then
if nexpr isa ANewExpr then
mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, nexpr.n_type, true)
- else if nexpr isa AIntExpr then
- var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
+ else if nexpr isa AIntegerExpr then
+ var cla: nullable MClass = null
+ if nexpr.value isa Int then
+ cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
+ else if nexpr.value isa Byte then
+ cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Byte")
+ else if nexpr.value isa Int8 then
+ cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int8")
+ else if nexpr.value isa Int16 then
+ cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int16")
+ else if nexpr.value isa UInt16 then
+ cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "UInt16")
+ else if nexpr.value isa Int32 then
+ cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int32")
+ else if nexpr.value isa UInt32 then
+ cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "UInt32")
+ else
+ # Should not happen, and should be updated as new types are added
+ abort
+ end
if cla != null then mtype = cla.mclass_type
else if nexpr isa AFloatExpr then
var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Float")
return
end
+ self.mtype = mtype
+
if mpropdef != null then
mpropdef.static_mtype = mtype
end
if mwritepropdef != null then
var name: String
name = n_id2.text
- var mparameter = new MParameter(name, mtype, false, false)
+ var mparameter = new MParameter(name, mtype, false)
var msignature = new MSignature([mparameter], null)
mwritepropdef.msignature = msignature
end
if mlazypropdef != null then
mlazypropdef.static_mtype = modelbuilder.model.get_mclasses_by_name("Bool").first.mclass_type
end
+ check_repeated_types(modelbuilder)
end
redef fun check_signature(modelbuilder)
var mpropdef = self.mpropdef
if mpropdef == null then return # Error thus skipped
var ntype = self.n_type
- var mtype = self.mpropdef.static_mtype
+ var mtype = self.mtype
if mtype == null then return # Error thus skipped
var mclassdef = mpropdef.mclassdef
end
end
end
+
+ # Type is useless if the attribute type is the same thant the intro.
+ redef fun check_repeated_types(modelbuilder) do
+ if mreadpropdef.is_intro or n_type == null then return
+ # get intro
+ var intro = mreadpropdef.mproperty.intro
+ var n_intro = modelbuilder.mpropdef2npropdef.get_or_null(intro)
+ if n_intro == null then return
+ # get intro type
+ var ntype = null
+ if n_intro isa AMethPropdef then
+ ntype = n_intro.n_signature.ret_type
+ else if n_intro isa AAttrPropdef and n_intro.n_type != null then
+ ntype = n_intro.n_type.mtype
+ end
+ # check
+ if ntype ==null or ntype != n_type.mtype then return
+ modelbuilder.advice(n_type, "useless-signature", "Warning: useless type repetition on redefined attribute `{mpropdef.name}`")
+ end
end
redef class ATypePropdef