Analysis and verification of property definitions to instantiate model element

Introduced classes

Redefined classes

redef class AAssignMethid

nitc :: modelize_property $ AAssignMethid

A setter method name with a simple identifier (with a =)
redef class AAttrPropdef

nitc :: modelize_property $ AAttrPropdef

A definition of an attribute
redef class ABraMethid

nitc :: modelize_property $ ABraMethid

A method name []
redef class ABraassignMethid

nitc :: modelize_property $ ABraassignMethid

A method name []=
redef abstract class AClassdef

nitc :: modelize_property $ AClassdef

A class definition
redef class AIdMethid

nitc :: modelize_property $ AIdMethid

A method name with a simple identifier
redef class AMethPropdef

nitc :: modelize_property $ AMethPropdef

A definition of all kind of method (including constructors)
redef abstract class AMethid

nitc :: modelize_property $ AMethid

The identifier of a method in a method declaration.
redef class AParam

nitc :: modelize_property $ AParam

A parameter definition in a signature. eg x:X
redef abstract class APropdef

nitc :: modelize_property $ APropdef

The definition of a property
redef class ASignature

nitc :: modelize_property $ ASignature

A signature in a method definition. eg (x,y:X,z:Z):T
redef class ATypePropdef

nitc :: modelize_property $ ATypePropdef

A definition of a virtual type
redef class MClass

nitc :: modelize_property $ MClass

A named class
redef class MClassDef

nitc :: modelize_property $ MClassDef

A definition (an introduction or a refinement) of a class in a module
redef abstract class MPropDef

nitc :: modelize_property $ MPropDef

A definition of a property (local property)
redef class ModelBuilder

nitc :: modelize_property $ ModelBuilder

A model builder knows how to load nit source files and build the associated model
redef class ToolContext

nitc :: modelize_property $ ToolContext

Global context for tools

All class definitions

redef class AAssignMethid

nitc :: modelize_property $ AAssignMethid

A setter method name with a simple identifier (with a =)
redef class AAttrPropdef

nitc :: modelize_property $ AAttrPropdef

A definition of an attribute
redef class ABraMethid

nitc :: modelize_property $ ABraMethid

A method name []
redef class ABraassignMethid

nitc :: modelize_property $ ABraassignMethid

A method name []=
redef abstract class AClassdef

nitc :: modelize_property $ AClassdef

A class definition
redef class AIdMethid

nitc :: modelize_property $ AIdMethid

A method name with a simple identifier
redef class AMethPropdef

nitc :: modelize_property $ AMethPropdef

A definition of all kind of method (including constructors)
redef abstract class AMethid

nitc :: modelize_property $ AMethid

The identifier of a method in a method declaration.
redef class AParam

nitc :: modelize_property $ AParam

A parameter definition in a signature. eg x:X
redef abstract class APropdef

nitc :: modelize_property $ APropdef

The definition of a property
redef class ASignature

nitc :: modelize_property $ ASignature

A signature in a method definition. eg (x,y:X,z:Z):T
redef class ATypePropdef

nitc :: modelize_property $ ATypePropdef

A definition of a virtual type
redef class MClass

nitc :: modelize_property $ MClass

A named class
redef class MClassDef

nitc :: modelize_property $ MClassDef

A definition (an introduction or a refinement) of a class in a module
redef abstract class MPropDef

nitc :: modelize_property $ MPropDef

A definition of a property (local property)
redef class ModelBuilder

nitc :: modelize_property $ ModelBuilder

A model builder knows how to load nit source files and build the associated model
redef class ToolContext

nitc :: modelize_property $ ToolContext

Global context for tools
package_diagram nitc::modelize_property modelize_property nitc::modelize_class modelize_class nitc::modelize_property->nitc::modelize_class nitc::annotation annotation nitc::modelize_property->nitc::annotation nitc::modelbuilder modelbuilder nitc::modelize_class->nitc::modelbuilder nitc::annotation->nitc::modelbuilder nitc::literal literal nitc::annotation->nitc::literal nitc::mmodule_data mmodule_data nitc::annotation->nitc::mmodule_data ...nitc::modelbuilder ... ...nitc::modelbuilder->nitc::modelbuilder ...nitc::literal ... ...nitc::literal->nitc::literal ...nitc::mmodule_data ... ...nitc::mmodule_data->nitc::mmodule_data nitc::modelize modelize nitc::modelize->nitc::modelize_property nitc::light_c light_c nitc::light_c->nitc::modelize_property nitc::parse_annotations parse_annotations nitc::parse_annotations->nitc::modelize_property nitc::actors_injection_phase actors_injection_phase nitc::actors_injection_phase->nitc::modelize_property nitc::modelize... ... nitc::modelize...->nitc::modelize nitc::c c nitc::c->nitc::light_c nitc::light_ffi light_ffi nitc::light_ffi->nitc::light_c nitc::c... ... nitc::c...->nitc::c nitc::light_ffi... ... nitc::light_ffi...->nitc::light_ffi nitc::frontend frontend nitc::frontend->nitc::parse_annotations nitc::frontend->nitc::actors_injection_phase nitc::contracts contracts nitc::contracts->nitc::parse_annotations nitc::model_filters model_filters nitc::model_filters->nitc::parse_annotations nitc::testing_suite testing_suite nitc::testing_suite->nitc::parse_annotations nitc::frontend... ... nitc::frontend...->nitc::frontend nitc::contracts... ... nitc::contracts...->nitc::contracts nitc::model_filters... ... nitc::model_filters...->nitc::model_filters nitc::testing_suite... ... nitc::testing_suite...->nitc::testing_suite nitc::actors_generation_phase actors_generation_phase nitc::actors_generation_phase->nitc::actors_injection_phase nitc::actors_generation_phase... ... nitc::actors_generation_phase...->nitc::actors_generation_phase

Ancestors

module abstract_collection

core :: abstract_collection

Abstract collection classes and services.
module abstract_text

core :: abstract_text

Abstract class for manipulation of sequences of characters
module array

core :: array

This module introduces the standard array structure.
module bitset

core :: bitset

Services to handle BitSet
module bytes

core :: bytes

Services for byte streams and arrays
module caching

serialization :: caching

Services for caching serialization engines
module circular_array

core :: circular_array

Efficient data structure to access both end of the sequence.
module codec_base

core :: codec_base

Base for codecs to use with streams
module codecs

core :: codecs

Group module for all codec-related manipulations
module collection

core :: collection

This module define several collection classes.
module console

console :: console

Defines some ANSI Terminal Control Escape Sequences.
module core

core :: core

Standard classes and methods used by default by Nit programs and libraries.
module digraph

graph :: digraph

Implementation of directed graphs, also called digraphs.
module engine_tools

serialization :: engine_tools

Advanced services for serialization engines
module environ

core :: environ

Access to the environment variables of the process
module error

core :: error

Standard error-management infrastructure.
module exec

core :: exec

Invocation and management of operating system sub-processes.
module file

core :: file

File manipulations (create, read, write, etc.)
module fixed_ints

core :: fixed_ints

Basic integers of fixed-precision
module fixed_ints_text

core :: fixed_ints_text

Text services to complement fixed_ints
module flat

core :: flat

All the array-based text representations
module gc

core :: gc

Access to the Nit internal garbage collection mechanism
module hash_collection

core :: hash_collection

Introduce HashMap and HashSet.
module ini

ini :: ini

Read and write INI configuration files
module inspect

serialization :: inspect

Refine Serializable::inspect to show more useful information
module iso8859_1

core :: iso8859_1

Codec for ISO8859-1 I/O
module kernel

core :: kernel

Most basic classes and methods.
module lexer

nitc :: lexer

Lexer and its tokens.
module lexer_work

nitc :: lexer_work

Internal algorithm and data structures for the Nit lexer
module list

core :: list

This module handle double linked lists
module literal

nitc :: literal

Parsing of literal values in the abstract syntax tree.
module loader

nitc :: loader

Loading of Nit source files
module location

nitc :: location

Nit source-file and locations in source-file
module math

core :: math

Mathematical operations
module mdoc

nitc :: mdoc

Documentation of model entities
module meta

meta :: meta

Simple user-defined meta-level to manipulate types of instances as object.
module mmodule

nitc :: mmodule

modules and module hierarchies in the metamodel
module mmodule_data

nitc :: mmodule_data

Define and retrieve data in modules
module model

nitc :: model

Classes, types and properties
module model_base

nitc :: model_base

The abstract concept of model and related common things
module modelbuilder_base

nitc :: modelbuilder_base

Load nit source files and build the associated model
module more_collections

more_collections :: more_collections

Highly specific, but useful, collections-related classes.
module mpackage

nitc :: mpackage

Modelisation of a Nit package
module native

core :: native

Native structures for text and bytes
module nitpm_shared

nitc :: nitpm_shared

Services related to the Nit package manager
module numeric

core :: numeric

Advanced services for Numeric types
module opts

opts :: opts

Management of options on the command line
module ordered_tree

ordered_tree :: ordered_tree

Manipulation and presentation of ordered trees.
module parser

nitc :: parser

Parser.
module parser_nodes

nitc :: parser_nodes

AST nodes of the Nit language
module parser_prod

nitc :: parser_prod

Production AST nodes full definition.
module parser_work

nitc :: parser_work

Internal algorithm and data structures for the Nit parser
module phase

nitc :: phase

Phases of the processing of nit programs
module poset

poset :: poset

Pre order sets and partial order set (ie hierarchies)
module protocol

core :: protocol

module queue

core :: queue

Queuing data structures and wrappers
module range

core :: range

Module for range of discrete objects.
module re

core :: re

Regular expression support for all services based on Pattern
module ropes

core :: ropes

Tree-based representation of a String.
module serialization

serialization :: serialization

General serialization services
module serialization_core

serialization :: serialization_core

Abstract services to serialize Nit objects to different formats
module sorter

core :: sorter

This module contains classes used to compare things and sorts arrays.
module stream

core :: stream

Input and output streams of characters
module tables

nitc :: tables

Module that interfaces the parsing tables.
module template

template :: template

Basic template system
module text

core :: text

All the classes and methods related to the manipulation of text entities
module time

core :: time

Management of time and dates
module toolcontext

nitc :: toolcontext

Common command-line tool infrastructure than handle options and error messages
module union_find

core :: union_find

union–find algorithm using an efficient disjoint-set data structure
module utf8

core :: utf8

Codec for UTF-8 I/O
module version

nitc :: version

This file was generated by git-gen-version.sh

Parents

module annotation

nitc :: annotation

Management and utilities on annotations
module modelize_class

nitc :: modelize_class

Analysis and verification of class definitions to instantiate model element

Children

module actors_injection_phase

nitc :: actors_injection_phase

Injects model for the classes annotated with "is actor" so
module light_c

nitc :: light_c

Support for nesting C code within a Nit program using its FFI
module modelize

nitc :: modelize

Create a model from nit source files
module parse_annotations

nitc :: parse_annotations

Simple annotation parsing

Descendants

module a_star-m

a_star-m

module abstract_compiler

nitc :: abstract_compiler

Abstract compiler
module actors_generation_phase

nitc :: actors_generation_phase

Generate a support module for each module that contain a class annotated with is actor
module android

nitc :: android

Compile program for the Android platform
module android_annotations

nitc :: android_annotations

Additionnal annotations to gather metadata on Android projects
module api

nitc :: api

Components required to build a web server about the nit model.
module api_auth

nitc :: api_auth

module api_base

nitc :: api_base

Base classes used by nitweb.
module api_docdown

nitc :: api_docdown

Nitdoc specific Markdown format handling for Nitweb
module api_feedback

nitc :: api_feedback

Feedback related features
module api_light

nitc :: api_light

Highlight and collect messages from a piece of code
module api_model

nitc :: api_model

module app_annotations

nitc :: app_annotations

Annotations to gather metadata on app.nit projects
module astbuilder

nitc :: astbuilder

Instantiation and transformation of semantic nodes in the AST of expressions and statements
module auto_super_init

nitc :: auto_super_init

Computing of super-constructors that must be implicitly called at the begin of constructors.
module c

nitc :: c

Support for nesting C code within a Nit program using its FFI
module c_compiler_options

nitc :: c_compiler_options

Offers the annotations cflags and ldflags to specify
module catalog

nitc :: catalog

Basic catalog generator for Nit packages
module code_gen

nitc :: code_gen

Main frontend phases plus code generation phases
module commands_base

nitc :: commands_base

Documentation commands
module commands_catalog

nitc :: commands_catalog

Commands to retrieve Catalog related data
module commands_docdown

nitc :: commands_docdown

Doc down related queries
module commands_graph

nitc :: commands_graph

Graph commands
module commands_http

nitc :: commands_http

Initialize commands from HTTP requests
module commands_model

nitc :: commands_model

Doc commands about a Model or a MEntity
module commands_parser

nitc :: commands_parser

A parser that create DocCommand from a string
module commands_usage

nitc :: commands_usage

Commands about how mentities are used
module compilation

nitc :: compilation

The compilation module of the VirtualMachine
module compiler

nitc :: compiler

Compilation to C
module compiler_ffi

nitc :: compiler_ffi

Full FFI support for the compiler
module compiler_serialization

nitc :: compiler_serialization

Serialization support for the compiler
module contracts

nitc :: contracts

Module to build contract
module cpp

nitc :: cpp

Supports the use of the C++ language through the FFI
module deriving

nitc :: deriving

Injection of automatic method definitions for standard methods, based on the attributes of the classes
module detect_covariance

nitc :: detect_covariance

Detect the static usage of covariance in the code.
module div_by_zero

nitc :: div_by_zero

Detection of divisions by zero in obvious cases
module dynamic_loading_ffi

nitc :: dynamic_loading_ffi

Execute FFI code by creating and loading shared libraries
module emscripten

nitc :: emscripten

Compile to JavaScript using the Emscripten SDK
module explain_assert

nitc :: explain_assert

Explain failed assert to the console by modifying the AST.
module extern_classes

nitc :: extern_classes

Manages all extern classes and their associated foreign type.
module extra_java_files

nitc :: extra_java_files

Intro the annotation extra_java_files to compile extra java files
module ffi

nitc :: ffi

Full FFI support, independent of the compiler
module ffi_base

nitc :: ffi_base

Tools and utilities for implement FFI with different languages
module frontend

nitc :: frontend

Collect and orchestration of main frontend phases
module global_compiler

nitc :: global_compiler

Global compilation of a Nit program
module header_dependency

nitc :: header_dependency

Tracks which modules has public header code that must be imported
module highlight

nitc :: highlight

Highlighting of Nit AST
module html_commands

nitc :: html_commands

Render commands results as HTML
module html_model

nitc :: html_model

Translate mentities to html blocks.
module htmlight

nitc :: htmlight

Highlighting of Nit AST with HTML
module i18n_phase

nitc :: i18n_phase

Basic support of internationalization through the generation of id-to-string tables
module inheritance_metrics

nitc :: inheritance_metrics

Collect metrics about inheritance usage
module interpreter

nitc :: interpreter

Interpretation of Nit programs
module ios

nitc :: ios

Compile programs for the iOS platform
module java

nitc :: java

FFI support for the Java language
module java_compiler

nitc :: java_compiler

Compile Nit code to Java code
module json_commands

nitc :: json_commands

Translate command results to json
module json_model

nitc :: json_model

Make model entities Serializable.
module light

nitc :: light

Light FFI support for the compiler
module light_ffi

nitc :: light_ffi

Light FFI support, independent of the compiler
module light_only

nitc :: light_only

Compiler support for the light FFI only, detects unsupported usage of callbacks
module mclasses_metrics

nitc :: mclasses_metrics

Collect common metrics about mclasses
module md_commands

nitc :: md_commands

Render commands results as Markdown
module memory_logger

nitc :: memory_logger

Extension to inject memory-tracing instrumentation in code generated by nitc.
module mendel_metrics

nitc :: mendel_metrics

The Mendel model helps to understand class hierarchies.
module metrics

nitc :: metrics

Various statistics about Nit models and programs
module mmodules_metrics

nitc :: mmodules_metrics

Collect common metrics about modules
module model_collect

nitc :: model_collect

Collect things from the model.
module model_index

nitc :: model_index

Search things from the Model
module model_visitor

nitc :: model_visitor

Simple visitor framework for Nit models.
module naive_interpreter

nitc :: naive_interpreter

Interpretation of a Nit program directly on the AST
module nit

nitc :: nit

A naive Nit interpreter
module nitc

nitc :: nitc

A Nit compiler
module nitcatalog

nitc :: nitcatalog

Basic catalog generator for Nit packages
module nitdoc

nitc :: nitdoc

Generator of static API documentation for the Nit language
module nith

nitc :: nith

A ligHt Nit compiler
module nitj

nitc :: nitj

Compile Nit into Java code runnable on the Java Virtual Machine.
module nitlight

nitc :: nitlight

Tool that produces highlighting for Nit programs
module nitmetrics

nitc :: nitmetrics

A program that collects various metrics on nit programs and libraries
module nitni

nitc :: nitni

Native interface related services (used underneath the FFI)
module nitni_callbacks

nitc :: nitni_callbacks

nitni services related to callbacks (used underneath the FFI)
module nitpackage

nitc :: nitpackage

Helpful features about packages
module nitpick

nitc :: nitpick

A program that collect potential style and code issues
module nitrestful

nitc :: nitrestful

Tool generating boilerplate code linking RESTful actions to Nit methods
module nitsaf

nitc :: nitsaf

Nit Static Analysis Framework client example.
module nitserial

nitc :: nitserial

Serialization support compiler, a tool to support deserialization of live generic types
module nitsmells

nitc :: nitsmells

module nituml

nitc :: nituml

UML generator in dot format.
module nitunit

nitc :: nitunit

Testing tool.
module nitvm

nitc :: nitvm

The Nit virtual machine launcher
module nitweb

nitc :: nitweb

Runs a webserver based on nitcorn that render things from model.
module nitx

nitc :: nitx

nitx, a command tool that displays useful data about Nit code
module nullables_metrics

nitc :: nullables_metrics

Statistics about the usage of nullables
module objc

nitc :: objc

FFI support for Objective-C
module on_demand_compiler

nitc :: on_demand_compiler

Compiles extern code within a module to a static library, as needed
module parallelization_phase

nitc :: parallelization_phase

Phase generating threads for functions annotated with threaded annotation
module pkgconfig

nitc :: pkgconfig

Offers the PkgconfigPhase to use the external program "pkg-config" in order
module platform

nitc :: platform

Platform system, used to customize the behavior of the compiler.
module rapid_type_analysis

nitc :: rapid_type_analysis

Rapid type analysis on the AST
module readme_metrics

nitc :: readme_metrics

Collect common metrics about README files
module regex_phase

nitc :: regex_phase

Check for error in regular expressions from string literals
module rta_metrics

nitc :: rta_metrics

Metrics from RTA
module semantize

nitc :: semantize

Process bodies of methods in regard with the model.
module separate_compiler

nitc :: separate_compiler

Separate compilation of a Nit program
module separate_erasure_compiler

nitc :: separate_erasure_compiler

Separate compilation of a Nit program with generic type erasure
module serialization_code_gen_phase

nitc :: serialization_code_gen_phase

Phase generating methods (code) to serialize Nit objects
module serialization_model_phase

nitc :: serialization_model_phase

Phase generating methods (model-only) to serialize Nit objects
module ssa

nitc :: ssa

Single-Static Assignment algorithm from an AST
module static

nitc :: static

Nitdoc generation framework
module static_base

nitc :: static_base

Base entities shared by all the nitdoc code
module static_cards

nitc :: static_cards

Cards templates for the static documentation
module static_html

nitc :: static_html

Render documentation pages as HTML
module static_index

nitc :: static_index

Manage indexing of Nit model for Nitdoc QuickSearch.
module static_structure

nitc :: static_structure

Composes the pages of the static documentation
module static_types_metrics

nitc :: static_types_metrics

Metrics on the usage of explicit static types.
module term

nitc :: term

module term_model

nitc :: term_model

Markdown templates for Nit model MEntities.
module test_astbuilder

nitc :: test_astbuilder

Program used to test the clone method of the astbuilder tool
module test_highlight

nitc :: test_highlight

Program used to test the Nit highlighter
module test_model_visitor

nitc :: test_model_visitor

Example of model_visitor
module test_neo

nitc :: test_neo

Test for neo model saving and loading.
module test_test_phase

nitc :: test_test_phase

Example of simple module that aims to do some specific work on nit programs.
module testing

nitc :: testing

Test unit generation and execution for Nit.
module testing_base

nitc :: testing_base

Base options for testing tools.
module testing_doc

nitc :: testing_doc

Testing from code comments.
module testing_gen

nitc :: testing_gen

Test Suites generation.
module testing_suite

nitc :: testing_suite

Testing from external files.
module transform

nitc :: transform

Thansformations that simplify the AST of expressions
module typing

nitc :: typing

Intraprocedural resolution of static types and OO-services
module uml

nitc :: uml

Group head module for UML generation services
module uml_base

nitc :: uml_base

Exposes the base class for UML generation of a Model
module uml_class

nitc :: uml_class

Provides facilities of exporting a Model to a UML class diagram
module uml_module

nitc :: uml_module

Services for generation of a UML package diagram based on a Model
module variables_numbering

nitc :: variables_numbering

Handle all numbering operations related to local variables in the Nit virtual machine
module vim_autocomplete

nitc :: vim_autocomplete

Generate files used by the Vim plugin to autocomplete with doc
module virtual_machine

nitc :: virtual_machine

Implementation of the Nit virtual machine
module vm

nitc :: vm

Entry point of all vm components
module vm_optimizations

nitc :: vm_optimizations

Optimization of the nitvm
module xcode_templates

nitc :: xcode_templates

Templates and other services to create XCode projects
# Analysis and verification of property definitions to instantiate model element
module modelize_property

intrude import modelize_class
private import annotation

redef class ToolContext
	# Run `AClassdef::build_property` on the classdefs of each module
	var modelize_property_phase: Phase = new ModelizePropertyPhase(self, [modelize_class_phase])
end

private class ModelizePropertyPhase
	super Phase
	redef fun process_nmodule(nmodule)
	do
		for nclassdef in nmodule.n_classdefs do
			if nclassdef.all_defs == null then continue # skip non principal classdef
			toolcontext.modelbuilder.build_properties(nclassdef)
		end
	end
end

redef class ModelBuilder
	# Registration of the npropdef associated to each mpropdef.
	#
	# Public clients need to use `mpropdef2node` to access stuff.
	private var mpropdef2npropdef = new HashMap[MPropDef, APropdef]

	# Associate a `npropdef` with its `mpropdef`
	#
	# Be careful, this method is unsafe, no checking is done when it's used.
	# The safe way to add method it's to use the `build_property`
	#
	# See `mpropdef2npropdef`
	fun unsafe_add_mpropdef2npropdef(mpropdef: MPropDef,npropdef: APropdef)
	do
		mpropdef2npropdef[mpropdef] = npropdef
	end

	# Associate a `nclassdef` with its `mclassdef`
	#
	# Be careful, this method is unsafe, no checking is done when it's used.
	# The safe way to add mclass it's to use the `build_property`
	#
	# See `mclassdef2nclassdef`
	fun unsafe_add_mclassdef2nclassdef(mclassdef: MClassDef, nclassdef: AClassdef)
	do
		mclassdef2nclassdef[mclassdef] = nclassdef
	end

	# Retrieve the associated AST node of a mpropertydef.
	# This method is used to associate model entity with syntactic entities.
	#
	# If the property definition is not associated with a node, returns `null`.
	fun mpropdef2node(mpropdef: MPropDef): nullable ANode
	do
		var res
		res = mpropdef2npropdef.get_or_null(mpropdef)
		if res != null then
			# Run the phases on it
			toolcontext.run_phases_on_npropdef(res)
			return res
		end
		# Fall back to the class node if any.
		res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
		if res != null then return res
		return null
	end

	# Retrieve all the attributes nodes localy definied
	# FIXME think more about this method and how the separations separate/global and ast/model should be done.
	fun collect_attr_propdef(mclassdef: MClassDef): Array[AAttrPropdef]
	do
		var res = new Array[AAttrPropdef]
		var n = mclassdef2nclassdef.get_or_null(mclassdef)
		if n == null then return res
		for npropdef in n.n_propdefs do
			if npropdef isa AAttrPropdef then
				# Run the phases on it
				toolcontext.run_phases_on_npropdef(npropdef)
				res.add(npropdef)
			end
		end
		return res
	end

	# Build the properties of `nclassdef`.
	private fun build_properties(nclassdef: AClassdef)
	do
		# Force building recursively
		if nclassdef.build_properties_is_done then return
		nclassdef.build_properties_is_done = true
		var mclassdef = nclassdef.mclassdef
		if mclassdef == null then return # skip error
		if mclassdef.in_hierarchy == null then return # Skip error
		for superclassdef in mclassdef.in_hierarchy.direct_greaters do
			if not mclassdef2nclassdef.has_key(superclassdef) then continue
			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
			for npropdef in nclassdef2.n_propdefs do
				npropdef.build_signature(self)
			end
			for npropdef in nclassdef2.n_propdefs do
				if not npropdef isa ATypePropdef then continue
				# Check circularity
				var mpropdef = npropdef.mpropdef
				if mpropdef == null then continue
				if mpropdef.bound == null then continue
				if not check_virtual_types_circularity(npropdef, mpropdef.mproperty, mclassdef.bound_mtype, mclassdef.mmodule) then
					# Invalidate the bound
					mpropdef.is_broken = true
					mpropdef.bound = new MErrorType(mclassdef.mmodule.model)
				end
			end
			for npropdef in nclassdef2.n_propdefs do
				# Check ATypePropdef first since they may be required for the other properties
				if not npropdef isa ATypePropdef then continue
				npropdef.check_signature(self)
			end

			for npropdef in nclassdef2.n_propdefs do
				if npropdef isa ATypePropdef then continue
				npropdef.check_signature(self)
			end
		end
		process_default_constructors(nclassdef)
	end

	# the root init of the Object class
	# Is usually implicitly defined
	# Then explicit or implicit definitions of root-init are attached to it
	var the_root_init_mmethod: nullable MMethod

	# Introduce or inherit default constructor
	# This is the last part of `build_properties`.
	private fun process_default_constructors(nclassdef: AClassdef)
	do
		var mclassdef = nclassdef.mclassdef.as(not null)

		# Are we a refinement
		if not mclassdef.is_intro then
			# Set the default_init of the mclassdef with the intro default_init
			mclassdef.default_init = mclassdef.mclass.intro.default_init
			return
		end

		# Look for the init in Object, or create it
		if mclassdef.mclass.name == "Object" and the_root_init_mmethod == null then
			# Create the implicit root-init method
			var mprop = new MMethod(mclassdef, "init", nclassdef.location, mclassdef.mclass.visibility)
			mprop.is_root_init = true
			var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
			var mparameters = new Array[MParameter]
			var msignature = new MSignature(mparameters, null)
			mpropdef.msignature = msignature
			mprop.is_init = true
			self.toolcontext.info("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
			the_root_init_mmethod = mprop
		end

		# Is there already a constructor defined?
		var defined_init: nullable MMethodDef = null
		for mpropdef in mclassdef.mpropdefs do
			if not mpropdef isa MMethodDef then continue
			if not mpropdef.mproperty.is_init then continue
			if mpropdef.mproperty.is_root_init then
				assert defined_init == null
				defined_init = mpropdef
			else if mpropdef.name == "defaultinit" then
				return
			end
		end

		if mclassdef.default_init != null then return

		# If the class is not AStdClassdef or it's an enum just return. No defaultinit is need.
		if not nclassdef isa AStdClassdef or nclassdef.n_classkind isa AEnumClasskind then return

		# Collect undefined attributes
		var mparameters = new Array[MParameter]
		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
				var mpropdef = npropdef.mpropdef
				if mpropdef == null then return # Skip broken method
				var sig = mpropdef.msignature
				if sig == null then continue # Skip broken method
				mparameters.add_all sig.mparameters
				initializers.add(mpropdef.mproperty)
				mpropdef.mproperty.is_autoinit = true
			end
			if npropdef isa AAttrPropdef then
				var mreadpropdef = npropdef.mreadpropdef
				if mreadpropdef == null then return # Skip broken attribute
				var msignature = mreadpropdef.msignature
				if msignature == null then return # Skip broken attribute
				if npropdef.noinit then continue # Skip noinit attribute
				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
					continue
				end
				if npropdef.has_value and not npropdef.is_optional then continue
				var msetter = npropdef.mwritepropdef
				if msetter == null then
					# No setter, it is a readonly attribute, so just add it
					var paramname = mreadpropdef.mproperty.name
					var ret_type = msignature.return_mtype
					if ret_type == null then return
					var mparameter = new MParameter(paramname, ret_type, false)
					mparameters.add(mparameter)

					initializers.add(npropdef.mpropdef.mproperty)
					npropdef.mpropdef.mproperty.is_autoinit = true
				else
					# Add the setter to the list
					mparameters.add_all msetter.msignature.mparameters
					initializers.add(msetter.mproperty)
					msetter.mproperty.is_autoinit = true
				end
			end
		end

		var the_root_init_mmethod = self.the_root_init_mmethod
		if the_root_init_mmethod == null then return

		# Look for most-specific new-stype init definitions
		var spropdefs = new ArraySet[MMethodDef]

		for x in mclassdef.get_direct_supermtype do
			var y = x.mclass.intro.default_init
			if y == null then continue
			if y.is_broken or y.msignature == null then return
			spropdefs.add y
		end

		# Look at the autoinit class-annotation
		var autoinit = nclassdef.get_single_annotation("autoinit", self)
		var noautoinit = nclassdef.get_single_annotation("noautoinit", self)
		if autoinit != null then
			# Just throws the collected initializers
			mparameters.clear
			initializers.clear

			if noautoinit != null then
				error(autoinit, "Error: `autoinit` and `noautoinit` are incompatible.")
			end

			if autoinit.n_args.is_empty then
				error(autoinit, "Syntax Error: `autoinit` expects method identifiers, use `noautoinit` to clear all autoinits.")
			end

			# Get and check each argument
			for narg in autoinit.n_args do
				var id = narg.as_id
				if id == null then
					error(narg, "Syntax Error: `autoinit` expects method identifiers.")
					return
				end

				# Search the property.
				# To avoid bad surprises, try to get the setter first.
				var p = try_get_mproperty_by_name(narg, mclassdef, id + "=")
				if p == null then
					p = try_get_mproperty_by_name(narg, mclassdef, id)
				end
				if p == null then
					error(narg, "Error: unknown method `{id}`")
					return
				end
				if not p.is_autoinit then
					error(narg, "Error: `{p}` is not an autoinit method")
					return
				end

				# Register the initializer and the parameters
				initializers.add(p)
				var pd = p.intro
				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)
					mparameters.add_all(sig.mparameters)
				else
					# TODO attributes?
					abort
				end
			end
		else if spropdefs.not_empty then
			# Search for inherited manual defaultinit
			var manual = null
			for s in spropdefs do
				if mpropdef2npropdef.has_key(s) then
					self.toolcontext.info("{mclassdef} inherits a manual defaultinit {s}", 3)
					manual = s
				end
			end
			# Search the longest-one and checks for conflict
			var longest = spropdefs.first
			if spropdefs.length > 1 then
				# part 1. find the longest list
				for spd in spropdefs do
					if spd.initializers.length > longest.initializers.length then longest = spd

					if spd != manual and manual != null then
						self.toolcontext.info("{mclassdef} conflict between manual defaultinit {manual} and automatic defaultinit {spd}.", 3)
					end
				end
				# conflict with manual autoinit?
				if longest != manual and manual != null then
					self.error(nclassdef, "Error: conflict between manual defaultinit {manual} and automatic defaultinit {longest}.")
				end
				# part 2. compare
				# 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
							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
						i += 1
					end
				end
			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
				# Combine the inherited list to what is collected
				if longest.initializers.length > 0 then
					mparameters.prepend longest.msignature.mparameters
					initializers.prepend longest.initializers
				end
			end
		end

		# Create a specific new autoinit constructor
		do
			var mprop = new MMethod(mclassdef, "defaultinit", nclassdef.location, public_visibility)
			mprop.is_init = true
			var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
			mpropdef.initializers.add_all(initializers)
			var msignature = new MSignature(mparameters, null)
			mpropdef.msignature = msignature
			mclassdef.default_init = mpropdef
			self.toolcontext.info("{mclassdef} gets a free auto constructor `{mpropdef}{msignature}`. {spropdefs}", 3)
			mclassdef.mclass.the_root_init_mmethod = the_root_init_mmethod
		end
	end

	# Check the visibility of `mtype` as an element of the signature of `mpropdef`.
	fun check_visibility(node: ANode, mtype: MType, mpropdef: MPropDef)
	do
		var mmodule = mpropdef.mclassdef.mmodule
		var mproperty = mpropdef.mproperty

		# Extract visibility information of the main part of `mtype`
		# It is a case-by case
		var vis_type: nullable MVisibility = null # The own visibility of the type
		var mmodule_type: nullable MModule = null # The original module of the type
		mtype = mtype.undecorate
		if mtype isa MClassType then
			vis_type = mtype.mclass.visibility
			mmodule_type = mtype.mclass.intro_mmodule
		else if mtype isa MVirtualType then
			vis_type = mtype.mproperty.visibility
			mmodule_type = mtype.mproperty.intro_mclassdef.mmodule
		else if mtype isa MParameterType then
			# nothing, always visible
		else if mtype isa MNullType then
			# nothing to do.
		else if mtype isa MBottomType then
			# nothing to do.
		else if mtype isa MErrorType then
			# nothing to do.
		else
			node.debug "Unexpected type {mtype}"
			abort
		end

		if vis_type != null then
			assert mmodule_type != null
			var vis_module_type = mmodule.visibility_for(mmodule_type) # the visibility of the original module
			if mproperty.visibility > vis_type then
				error(node, "Error: the {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`.")
				return
			else if mproperty.visibility > vis_module_type then
				error(node, "Error: the {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`.")
				return
			end
		end

		# No error, try to go deeper in generic types
		if node isa AType then
			for a in node.n_types do
				var t = a.mtype
				if t == null then continue # Error, thus skipped
				check_visibility(a, t, mpropdef)
			end
		else if mtype isa MGenericType then
			for t in mtype.arguments do check_visibility(node, t, mpropdef)
		end
	end

	# Detect circularity errors for virtual types.
	fun check_virtual_types_circularity(node: ANode, mproperty: MVirtualTypeProp, recv: MType, mmodule: MModule): Bool
	do
		# Check circularity
		# Slow case: progress on each resolution until we visit all without getting a loop

		# The graph used to detect loops
		var mtype = mproperty.mvirtualtype
		var poset = new POSet[MType]

		# The work-list of types to resolve
		var todo = new List[MType]
		todo.add mtype

		while not todo.is_empty do
			# The visited type
			var t = todo.pop

			if not t.need_anchor then continue

			# Get the types derived of `t` (subtypes and bounds)
			var nexts
			if t isa MNullableType then
				nexts = [t.mtype]
			else if t isa MGenericType then
				nexts = t.arguments
			else if t isa MVirtualType then
				var vt = t.mproperty
				# Because `vt` is possibly unchecked, we have to do the bound-lookup manually
				var defs = vt.lookup_definitions(mmodule, recv)
				if defs.is_empty then return false
				nexts = new Array[MType]
				for d in defs do
					var next = defs.first.bound
					if next == null then return false
					nexts.add next
				end
			else if t isa MClassType then
				# Basic type, nothing to to
				continue
			else if t isa MParameterType then
				# Parameter types cannot depend on virtual types, so nothing to do
				continue
			else
				abort
			end

			# For each one
			for next in nexts do
				if poset.has_edge(next, t) then
					if mtype == next then
						error(node, "Error: circularity of virtual type definition: {next} <-> {t}.")
					else
						error(node, "Error: circularity of virtual type definition: {mtype} -> {next} <-> {t}.")
					end
					return false
				else
					poset.add_edge(t, next)
					todo.add next
				end
			end
		end
		return true
	end
end

redef class MPropDef
	# Does the MPropDef contains a call to super or a call of a super-constructor?
	# Subsequent phases of the frontend (esp. typing) set it if required
	var has_supercall: Bool = false is writable
end

redef class AClassdef
	# Marker used in `ModelBuilder::build_properties`
	private var build_properties_is_done = false
end

redef class MClass
	# The base init of the class.
	#
	# TODO: merge with `root_init` and `ModelBuilder::the_root_init_mmethod` if possible
	var the_root_init_mmethod: nullable MMethod = null
end

redef class MClassDef
	# 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
	# The associated main model entity
	type MPROPDEF: MPropDef

	# The associated propdef once build by a `ModelBuilder`
	var mpropdef: nullable MPROPDEF is writable

	private fun build_property(modelbuilder: ModelBuilder, mclassdef: MClassDef) do end
	private fun build_signature(modelbuilder: ModelBuilder) do end
	private fun check_signature(modelbuilder: ModelBuilder) do end
	private fun new_property_visibility(modelbuilder: ModelBuilder, mclassdef: MClassDef, nvisibility: nullable AVisibility): MVisibility
	do
		var mvisibility = public_visibility
		if nvisibility != null then
			mvisibility = nvisibility.mvisibility
			if mvisibility == intrude_visibility then
				modelbuilder.error(nvisibility, "Error: `intrude` is not a legal visibility for properties.")
				mvisibility = public_visibility
			end
		end
		if mclassdef.mclass.visibility == private_visibility then
			if mvisibility == protected_visibility then
				assert nvisibility != null
				modelbuilder.error(nvisibility, "Error: `private` is the only legal visibility for properties in a private class.")
			else if mvisibility == private_visibility then
				assert nvisibility != null
				modelbuilder.advice(nvisibility, "useless-visibility", "Warning: `private` is superfluous since the only legal visibility for properties in a private class is private.")
			end
			mvisibility = private_visibility
		end
		return mvisibility
	end

	private fun set_doc(mpropdef: MPropDef, modelbuilder: ModelBuilder)
	do
		var ndoc = self.n_doc
		if ndoc != null then
			var mdoc = ndoc.to_mdoc
			mpropdef.mdoc = mdoc
			mdoc.original_mentity = mpropdef
		else if mpropdef.is_intro and mpropdef.mproperty.visibility >= protected_visibility and mpropdef.name != "new" then
			modelbuilder.advice(self, "missing-doc", "Documentation warning: Undocumented property `{mpropdef.mproperty}`")
		end

		var at_deprecated = get_single_annotation("deprecated", modelbuilder)
		if at_deprecated != null then
			if not mpropdef.is_intro then
				modelbuilder.error(self, "Error: method redefinition cannot be deprecated.")
			else
				var info = new MDeprecationInfo
				ndoc = at_deprecated.n_doc
				if ndoc != null then info.mdoc = ndoc.to_mdoc
				mpropdef.mproperty.deprecation = info
			end
		end
	end

	private fun check_redef_property_visibility(modelbuilder: ModelBuilder, nvisibility: nullable AVisibility, mprop: MProperty)
	do
		if nvisibility == null then return
		var mvisibility = nvisibility.mvisibility
		if mvisibility != mprop.visibility and mvisibility != public_visibility then
				modelbuilder.error(nvisibility, "Error: redefinition changed the visibility from `{mprop.visibility}` to `{mvisibility}`.")
		end
	end

	private fun check_redef_keyword(modelbuilder: ModelBuilder, mclassdef: MClassDef, kwredef: nullable Token, need_redef: Bool, mprop: MProperty): Bool
	do
		if mclassdef.mprop2npropdef.has_key(mprop) then
			modelbuilder.error(self, "Error: a property `{mprop}` is already defined in class `{mclassdef.mclass}` at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
			return false
		end
		if mprop isa MMethod and mprop.is_root_init then return true
		if kwredef == null then
			if need_redef then
				modelbuilder.error(self, "Redef Error: `{mclassdef.mclass}::{mprop.name}` is an inherited property. To redefine it, add the `redef` keyword.")
				return false
			end

			# 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.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
				end
			end
		else
			if not need_redef then
				modelbuilder.error(self, "Error: no property `{mclassdef.mclass}::{mprop.name}` is inherited. Remove the `redef` keyword to define a new property.")
				return false
			end
		end
		return true
	end

	# Checks for useless type in redef signatures.
	private fun check_repeated_types(modelbuilder: ModelBuilder) do end
end

redef class ASignature
	# Is the model builder has correctly visited the signature
	var is_visited = false
	# Names of parameters from the AST
	# REQUIRE: is_visited
	var param_names = new Array[String]
	# Types of parameters from the AST
	# REQUIRE: is_visited
	var param_types = new Array[MType]
	# Rank of the vararg (of -1 if none)
	# REQUIRE: is_visited
	var vararg_rank: Int = -1
	# Return type
	var ret_type: nullable MType = null

	# Visit and fill information about a signature
	private fun visit_signature(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
	do
		var param_names = self.param_names
		var param_types = self.param_types
		for np in self.n_params do
			param_names.add(np.n_id.text)
			var ntype = np.n_type
			if ntype != null then
				var mtype = modelbuilder.resolve_mtype_unchecked(mclassdef, ntype, true)
				if mtype == null then return false # Skip error
				for i in [0..param_names.length-param_types.length[ do
					param_types.add(mtype)
				end
				if np.n_dotdotdot != null then
					if self.vararg_rank != -1 then
						modelbuilder.error(np, "Error: `{param_names[self.vararg_rank]}` is already a vararg")
						return false
					else
						self.vararg_rank = param_names.length - 1
					end
				end
			end
		end
		var ntype = self.n_type
		if ntype != null then
			self.ret_type = modelbuilder.resolve_mtype_unchecked(mclassdef, ntype, true)
			if self.ret_type == null then return false # Skip error
		end

		self.is_visited = true
		return true
	end

	private fun check_signature(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
	do
		var res = true
		for np in self.n_params do
			var ntype = np.n_type
			if ntype != null then
				if modelbuilder.resolve_mtype(mclassdef, ntype) == null then
					res = false
				end
			end
		end
		var ntype = self.n_type
		if ntype != null then
			if modelbuilder.resolve_mtype(mclassdef, ntype) == null then
				res = false
			end
		end
		if not res then is_broken = true
		return res
	end
end

redef class AParam
	# The associated mparameter if any
	var mparameter: nullable MParameter = null
end

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
	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 annotation on itself
		if get_single_annotation("old_style_init", modelbuilder) != null then return false
		# Nor on its module
		var amod = self.parent.parent.as(AModule)
		var amoddecl = amod.n_moduledecl
		if amoddecl != null then
			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

	redef fun build_property(modelbuilder, mclassdef)
	do
		var n_kwinit = n_kwinit
		var n_kwnew = n_kwnew
		var is_new = n_kwnew != null
		var is_init = n_kwinit != null or is_new
		var name: String
		var amethodid = self.n_methid
		var name_node: ANode
		var is_old_style_init = false
		if amethodid == null then
			if n_kwinit != null then
				name = "init"
				name_node = n_kwinit
				var old_style_annot = get_single_annotation("old_style_init", modelbuilder)
				if  old_style_annot != null or self.n_signature.n_params.not_empty then
					name = "defaultinit"
					if old_style_annot != null then is_old_style_init = true
				end
			else if n_kwnew != null then
				name = "new"
				name_node = n_kwnew
			else
				name = "main"
				name_node = self
			end
		else if amethodid isa AIdMethid then
			name = amethodid.n_id.text
			name_node = amethodid
		else
			# operator, bracket or assign
			name = amethodid.collect_text
			name_node = amethodid

			var arity = self.n_signature.n_params.length
			if name == "+" and arity == 0 then
				name = "unary +"
			else if name == "-" and arity == 0 then
				name = "unary -"
			else if name == "~" and arity == 0 then
				name = "unary ~"
			else
				if amethodid.is_binary and arity != 1 then
					modelbuilder.error(self.n_signature, "Syntax Error: binary operator `{name}` requires exactly one parameter; got {arity}.")
				else if amethodid.min_arity > arity then
					modelbuilder.error(self.n_signature, "Syntax Error: `{name}` requires at least {amethodid.min_arity} parameter(s); got {arity}.")
				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 or look_like_a_root_init then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
		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
				modelbuilder.advice(self, "useless-init", "Warning: useless empty init in {mclassdef}")
			end
		end
		if mprop == null then
			var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
			mprop = new MMethod(mclassdef, name, self.location, mvisibility)
			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
			mprop.is_init = is_init
			mprop.is_new = is_new
			if is_new then mclassdef.mclass.has_new_factory = true
			if name == "sys" then mprop.is_toplevel = true # special case for sys allowed in `new` factories
			if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop) then
				mprop.is_broken = true
				return
			end
		else
			if mprop.is_broken then return
			if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, not self isa AMainMethPropdef, mprop) then return
			check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
		end

		# Check name conflicts in the local class for constructors.
		if is_init then
			for p, n in mclassdef.mprop2npropdef do
				if p != mprop and p isa MMethod and p.name == name then
					if not check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, p) then
						mprop.is_broken = true
						return
					end
					break
				end
			end
		end

		mclassdef.mprop2npropdef[mprop] = self

		var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
		if mpropdef.name == "defaultinit" and mclassdef.is_intro then
			assert mclassdef.default_init == null
			mpropdef.is_old_style_init = is_old_style_init
			mclassdef.default_init = mpropdef
			# Set the initializers with the mproperty.
			# This point is need when a super class define this own default_init and inherited class use the default_init generated automaticlely.
			mpropdef.initializers.add mprop
			mpropdef.is_calling_init = true
		end

		set_doc(mpropdef, modelbuilder)

		self.mpropdef = mpropdef
		modelbuilder.mpropdef2npropdef[mpropdef] = self
		if mpropdef.is_intro then
			modelbuilder.toolcontext.info("{mpropdef} introduces new method {mprop.full_name}", 4)
		else
			modelbuilder.toolcontext.info("{mpropdef} redefines method {mprop.full_name}", 4)
		end
	end

	redef fun build_signature(modelbuilder)
	do
		var mpropdef = self.mpropdef
		if mpropdef == null then return # Error thus skiped
		var mproperty = mpropdef.mproperty
		var mclassdef = mpropdef.mclassdef
		var mmodule = mclassdef.mmodule
		var nsig = self.n_signature

		var accept_special_last_parameter = self.n_methid == null or self.n_methid.accept_special_last_parameter
		var return_is_mandatory = self.n_methid != null and self.n_methid.return_is_mandatory

		# Retrieve info from the signature AST
		var param_names = new Array[String] # Names of parameters from the AST
		var param_types = new Array[MType] # Types of parameters from the AST
		var vararg_rank = -1
		var ret_type: nullable MType = null # Return type from the AST
		if nsig != null then
			if not nsig.visit_signature(modelbuilder, mclassdef) then return
			param_names = nsig.param_names
			param_types = nsig.param_types
			vararg_rank = nsig.vararg_rank
			ret_type = nsig.ret_type
		end

		# Look for some signature to inherit
		# FIXME: do not inherit from the intro, but from the most specific
		var msignature: nullable MSignature = null
		if not mpropdef.is_intro then
			msignature = mproperty.intro.msignature
			if msignature == null then return # Skip error

			# The local signature is adapted to use the local formal types, if any.
			msignature = msignature.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mmodule, false)

			# Check inherited signature arity
			if param_names.length != msignature.arity then
				var node: ANode
				if nsig != null then node = nsig else node = self
				modelbuilder.error(node, "Redef Error: expected {msignature.arity} parameter(s) for `{mproperty.name}{msignature}`; got {param_names.length}. See introduction at `{mproperty.full_name}`.")
				return
			end
		else if mproperty.is_init and not mproperty.is_new then
			# FIXME UGLY: inherit signature from a super-constructor
			for msupertype in mclassdef.supertypes do
				msupertype = msupertype.anchor_to(mmodule, mclassdef.bound_mtype)
				var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mproperty.name)
				if candidate != null then
					if msignature == null then
						msignature = candidate.intro.as(MMethodDef).msignature
					end
				end
			end
		end


		# Inherit the signature
		if msignature != null and param_names.length != param_types.length and param_names.length == msignature.arity and param_types.length == 0 then
			# Parameters are untyped, thus inherit them
			param_types = new Array[MType]
			for mparameter in msignature.mparameters do
				param_types.add(mparameter.mtype)
			end
			vararg_rank = msignature.vararg_rank
		end
		if msignature != null and ret_type == null then
			ret_type = msignature.return_mtype
		end

		if param_names.length != param_types.length then
			# Some parameters are typed, other parameters are not typed.
			modelbuilder.error(nsig.n_params[param_types.length], "Error: untyped parameter `{param_names[param_types.length]}'.")
			return
		end

		var mparameters = new Array[MParameter]
		for i in [0..param_names.length[ do
			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

		# In `new`-factories, the return type is by default the classtype.
		if ret_type == null and mproperty.is_new then ret_type = mclassdef.mclass.mclass_type

		# Special checks for operator methods
		if not accept_special_last_parameter and mparameters.not_empty and mparameters.last.is_vararg then
			modelbuilder.error(self.n_signature.n_params.last, "Error: illegal variadic parameter `{mparameters.last}` for `{mproperty.name}`.")
		end
		if ret_type == null and return_is_mandatory then
			modelbuilder.error(self.n_methid, "Error: mandatory return type for `{mproperty.name}`.")
		end

		msignature = new MSignature(mparameters, ret_type)
		mpropdef.msignature = msignature
		mpropdef.is_abstract = self.get_single_annotation("abstract", modelbuilder) != null
		mpropdef.is_intern = self.get_single_annotation("intern", modelbuilder) != null
		mpropdef.is_extern = self.n_extern_code_block != null or self.get_single_annotation("extern", modelbuilder) != null

		# 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)
	do
		var mpropdef = self.mpropdef
		if mpropdef == null then return # Error thus skiped
		var mclassdef = mpropdef.mclassdef
		var mmodule = mclassdef.mmodule
		var nsig = self.n_signature
		var mysignature = mpropdef.msignature
		if mysignature == null then return # Error thus skiped

		# Check
		if nsig != null then
			if not nsig.check_signature(modelbuilder, mclassdef) then
				mpropdef.msignature = null # invalidate
				mpropdef.is_broken = true
				return # Forward error
			end
		end

		# Lookup for signature in the precursor
		# FIXME all precursors should be considered
		if not mpropdef.is_intro then
			var msignature = mpropdef.mproperty.intro.msignature
			if msignature == null then return

			var precursor_ret_type = msignature.return_mtype
			var ret_type = mysignature.return_mtype
			if ret_type != null and precursor_ret_type == null then
				modelbuilder.error(nsig.n_type, "Redef Error: `{mpropdef.mproperty}` is a procedure, not a function.")
				mpropdef.msignature = null
				mpropdef.is_broken = true
				return
			end

			if mysignature.arity > 0 then
				# Check parameters types
				for i in [0..mysignature.arity[ do
					var myt = mysignature.mparameters[i].mtype
					var prt = msignature.mparameters[i].mtype
					var node = nsig.n_params[i]
					if not modelbuilder.check_sametype(node, mmodule, mclassdef.bound_mtype, myt, prt) then
						modelbuilder.error(node, "Redef Error: expected `{prt}` for parameter `{mysignature.mparameters[i].name}'; got `{myt}`.")
						mpropdef.msignature = null
						mpropdef.is_broken = true
					end
				end
			end
			if precursor_ret_type != null then
				var node: nullable ANode = null
				if nsig != null then node = nsig.n_type
				if node == null then node = self
				if ret_type == null then
					# Inherit the return type
					ret_type = precursor_ret_type
				else if not modelbuilder.check_subtype(node, mmodule, mclassdef.bound_mtype, ret_type, precursor_ret_type) then
					modelbuilder.error(node, "Redef Error: expected `{precursor_ret_type}` for return type; got `{ret_type}`.")
					mpropdef.msignature = null
					mpropdef.is_broken = true
				end
			end
		end

		if nsig != null then
			# Check parameters visibility
			for i in [0..mysignature.arity[ do
				var nt = nsig.n_params[i].n_type
				if nt != null then modelbuilder.check_visibility(nt, nt.mtype.as(not null), mpropdef)
			end
			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
		var mpropdef = self.mpropdef
		if mpropdef == null then return
		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 AMethid
	# Is a return required?
	#
	# * True for operators and brackets.
	# * False for id and assignment.
	fun return_is_mandatory: Bool do return true

	# Can the last parameter be special like a vararg?
	#
	# * False for operators: the last one is in fact the only one.
	# * False for assignments: it is the right part of the assignment.
	# * True for ids and brackets.
	fun accept_special_last_parameter: Bool do return false

	# The minimum required number of parameters.
	#
	# * 1 for binary operators
	# * 1 for brackets
	# * 1 for assignments
	# * 2 for bracket assignments
	# * 0 for ids
	fun min_arity: Int do return 1

	# Is the `self` a binary operator?
	fun is_binary: Bool do return true
end

redef class AIdMethid
	redef fun return_is_mandatory do return false
	redef fun accept_special_last_parameter do return true
	redef fun min_arity do return 0
	redef fun is_binary do return false
end

redef class ABraMethid
	redef fun accept_special_last_parameter do return true
	redef fun is_binary do return false
end

redef class ABraassignMethid
	redef fun return_is_mandatory do return false
	redef fun min_arity do return 2
	redef fun is_binary do return false
end

redef class AAssignMethid
	redef fun return_is_mandatory do return false
	redef fun is_binary do return false
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

	# Is the node tagged lazy?
	var is_lazy = false

	# Is the node tagged optional?
	var is_optional = false

	# Does the node have a default value?
	# Could be through `n_expr`, `n_block` or `is_lazy`
	var has_value = false

	# The name of the attribute
	# Note: The name of the attribute is in reality the name of the mreadpropdef
	var name: String = n_id2.text is lazy

	# 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.
	# TODO: to remove once isset is correctly implemented
	var mlazypropdef: nullable MAttributeDef

	# The associated getter (read accessor) if any
	var mreadpropdef: nullable MMethodDef is writable
	# The associated setter (write accessor) if any
	var mwritepropdef: nullable MMethodDef is writable

	redef fun build_property(modelbuilder, mclassdef)
	do
		var mclass = mclassdef.mclass

		var atabstract = self.get_single_annotation("abstract", modelbuilder)

		if atabstract == null then build_attribute_property(modelbuilder, mclassdef)

		# Construction of the read property. If it's not correctly built just return.
		if not build_read_property(modelbuilder, mclassdef) then return

		if atabstract != null then mreadpropdef.is_abstract = true

		has_value = n_expr != null or n_block != null

		if atabstract != null and has_value then
			modelbuilder.error(atabstract, "Error: `abstract` attributes cannot have an initial value.")
			return
		end

		var atnoinit = self.get_single_annotation("noinit", modelbuilder)
		if atnoinit == null then atnoinit = self.get_single_annotation("noautoinit", modelbuilder)
		if atnoinit != null then
			noinit = true
			if has_value then
				modelbuilder.error(atnoinit, "Error: `noautoinit` attributes cannot have an initial value.")
				return
			end
			if atabstract != null then
				modelbuilder.warning(atnoinit, "useless-noautoinit", "Warning: superfluous `noautoinit` on abstract attribute.")
			end
		end

		# Construction of the read property. If it's not correctly built just return.
		if not build_lazy_property(modelbuilder, mclassdef) then return

		var atoptional = self.get_single_annotation("optional", modelbuilder)
		if atoptional != null then
			if not has_value then
				modelbuilder.error(atoptional, "Error: `optional` attributes need a default value.")
			end
			is_optional = true
		end

		var atreadonly = self.get_single_annotation("readonly", modelbuilder)
		if atreadonly != null then
			if not has_value then
				modelbuilder.error(atreadonly, "Error: `readonly` attributes need a value.")
			end
			# No setter, so just leave
			return
		end

		if not mclassdef.is_intro and not has_value and not noinit then
			modelbuilder.advice(self, "attr-in-refinement", "Warning: attributes in refinement need a value or `noautoinit`.")
		end

		# Construction of the read property. If it's not correctly built just return.
		if not build_write_property(modelbuilder, mclassdef, false) then return

		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

	# Build the attribute property
	fun build_attribute_property(modelbuilder: ModelBuilder, mclassdef: MClassDef)
	do
		var mclass = mclassdef.mclass
		var attribute_name = "_" + name

		if not mclass.kind.need_init then
			modelbuilder.error(self, "Error: attempt to define attribute `{name}` in the {mclass.kind} `{mclass}`.")
		end
		var mprop = new MAttribute(mclassdef, "_" + name, self.location, private_visibility)
		var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
		self.mpropdef = mpropdef
		modelbuilder.mpropdef2npropdef[mpropdef] = self
	end

	# Build the read method property to get the value of the attribute
	# Return `true` if the property was correctly created else return `false`.
	# Warning the signature of the property is not set. This step is done by `build_signature`.
	fun build_read_property(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
	do
		var mclass = mclassdef.mclass

		var readname = name
		var mreadprop = modelbuilder.try_get_mproperty_by_name(self, mclassdef, readname).as(nullable MMethod)
		if mreadprop == null then
			var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
			mreadprop = new MMethod(mclassdef, readname, self.location, mvisibility)
			if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mreadprop) then
				mreadprop.is_broken = true
				return false
			end
		else
			if mreadprop.is_broken then return false
			if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, true, mreadprop) then return false
			check_redef_property_visibility(modelbuilder, self.n_visibility, mreadprop)
		end
		mclassdef.mprop2npropdef[mreadprop] = self

		var attr_mpropdef = mpropdef
		if attr_mpropdef != null then
			mreadprop.getter_for = attr_mpropdef.mproperty
			attr_mpropdef.mproperty.getter = mreadprop
		end

		var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
		self.mreadpropdef = mreadpropdef
		modelbuilder.mpropdef2npropdef[mreadpropdef] = self
		set_doc(mreadpropdef, modelbuilder)
		if mpropdef != null then mpropdef.mdoc = mreadpropdef.mdoc

		return true
	end

	# Build the write method property to set the attribute value
	# Return `true` if the property was correctly created else return `false`.
	# Warning the signature of the property is not set.
	fun build_write_property(modelbuilder: ModelBuilder, mclassdef: MClassDef, is_same_visibility: Bool): Bool
	do
		var mclass = mclassdef.mclass

		var writename = name + "="
		var atwritable = self.get_single_annotation("writable", modelbuilder)
		if atwritable != null then
			if not atwritable.n_args.is_empty then
				writename = atwritable.arg_as_id(modelbuilder) or else writename
			end
		end
		var mwriteprop = modelbuilder.try_get_mproperty_by_name(self, mclassdef, writename).as(nullable MMethod)
		var nwkwredef: nullable Token = null
		if atwritable != null then nwkwredef = atwritable.n_kwredef
		if mwriteprop == null then
			var mvisibility
			if atwritable != null then
				mvisibility = new_property_visibility(modelbuilder, mclassdef, atwritable.n_visibility)
			else
				mvisibility = mreadpropdef.mproperty.visibility
				# By default, use protected visibility at most
				if mvisibility > protected_visibility and not is_same_visibility then mvisibility = protected_visibility
			end
			mwriteprop = new MMethod(mclassdef, writename, self.location, mvisibility)
			if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef, false, mwriteprop) then
				mwriteprop.is_broken = true
				return false
			end
			mwriteprop.deprecation = mreadpropdef.mproperty.deprecation
		else
			if mwriteprop.is_broken then return false
			if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef or else n_kwredef, true, mwriteprop) then return false
			if atwritable != null then
				check_redef_property_visibility(modelbuilder, atwritable.n_visibility, mwriteprop)
			end
		end
		mclassdef.mprop2npropdef[mwriteprop] = self

		var attr_mpropdef = mpropdef
		if attr_mpropdef != null then
			mwriteprop.setter_for = attr_mpropdef.mproperty
			attr_mpropdef.mproperty.setter = mwriteprop
		end

		var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
		self.mwritepropdef = mwritepropdef
		modelbuilder.mpropdef2npropdef[mwritepropdef] = self
		mwritepropdef.mdoc = mreadpropdef.mdoc

		return true
	end

	# Build the lazy attribute property
	# Return `true` if the property was correctly created else return `false`.
	fun build_lazy_property(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
	do
		var mclass = mclassdef.mclass

		var atlazy = self.get_single_annotation("lazy", modelbuilder)
		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 false
			end
			if not has_value then
				if atlazy != null then
					modelbuilder.error(atlazy, "Error: `lazy` attributes need a value.")
				else if atlateinit != null then
					modelbuilder.error(atlateinit, "Error: `lateinit` attributes need a value.")
				end
				has_value = true
				return false
			end
			create_lazy
		end
		return true
	end

	redef fun build_signature(modelbuilder)
	do
		var mreadpropdef = self.mreadpropdef
		var mpropdef = self.mpropdef
		if mreadpropdef == null then return # Error thus skipped
		var mclassdef = mreadpropdef.mclassdef
		var mmodule = mclassdef.mmodule
		var mtype: nullable MType = null


		var ntype = self.n_type
		if ntype != null then
			mtype = modelbuilder.resolve_mtype_unchecked(mclassdef, ntype, true)
			if mtype == null then return
		end

		var inherited_type: nullable MType = null
		# Inherit the type from the getter (usually an abstract getter)
		if not mreadpropdef.is_intro then
			var msignature = mreadpropdef.mproperty.intro.msignature
			if msignature == null then return # Error, thus skipped
			inherited_type = msignature.return_mtype
			if inherited_type != null then
				# The inherited type is adapted to use the local formal types, if any.
				inherited_type = inherited_type.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mmodule, false)
				if mtype == null then mtype = inherited_type
			end
		end

		var nexpr = self.n_expr
		if mtype == null then
			if nexpr != null then
				mtype = infer_static_type(modelbuilder, nexpr, mclassdef, mmodule, mreadpropdef)
				if mtype == null then return
			end
		else if ntype != null and inherited_type == mtype then
			if nexpr isa ANewExpr then
				var xmtype = modelbuilder.resolve_mtype_unchecked(mclassdef, nexpr.n_type, true)
				if xmtype == mtype then
					modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition")
				end
			end
		end

		if mtype == null then
			modelbuilder.error(self, "Error: untyped attribute `{mreadpropdef}`.")
			return
		end

		self.mtype = mtype

		if mpropdef != null then
			mpropdef.static_mtype = mtype
		end

		build_read_signature

		if self.mwritepropdef != null then build_write_signature

		var mlazypropdef = self.mlazypropdef
		if mlazypropdef != null then
			mlazypropdef.static_mtype = mmodule.bool_type
		end
		check_repeated_types(modelbuilder)
	end

	# Build the read method signature
	# `except`: mreadpropdef != null
	# `expect`: mtype != null
	fun build_read_signature
	is
		expect(mreadpropdef != null and mtype != null)
	do
		var msignature = new MSignature(new Array[MParameter], mtype)
		mreadpropdef.msignature = msignature
	end

	# Build the write method signature
	# `except`: mwritepropdef != null
	# `expect`: mtype != null
	fun build_write_signature
	is
		expect(mwritepropdef != null and mtype != null)
	do
		var mwritetype = mtype.as(not null)
		if is_optional then
			mwritetype = mwritetype.as_nullable
		end
		var mparameter = new MParameter(name, mwritetype, false)
		var msignature = new MSignature([mparameter], null)
		mwritepropdef.msignature = msignature
	end

	# Create a new setter for the attribute.
	#
	# `modelbuilder`: It's used to link the new `mwritepropdef` and `self`
	# `visibility`: Is the setter has the same visibilty of the `mreadpropdef`.
	#	If `not is_same_visibility and mreadpropdef.mproperty.visibility > protected_visibility` the `mwritepropdef` visibility will be set to protected.
	fun create_setter(modelbuilder: ModelBuilder, is_same_visibility: nullable Bool): AAttrPropdef
	is
		expect(mreadpropdef != null) # Use to define the visibility, the mclassdef and the doc of the `mwritepropdef`
	do
		if mwritepropdef != null then return self # Self already has a `mwritepropdef`
		var same_visibility = false
		if is_same_visibility != null then same_visibility = is_same_visibility

		self.build_write_property(modelbuilder, mreadpropdef.mclassdef, same_visibility)
		self.build_write_signature
		return self
	end

	# Set the default `self` value
	#
	# `expr`: Represents the default value of the attribute. If `expr isa ABlockExpr` `self.n_block` will be set.
	fun define_default(expr: AExpr): AAttrPropdef
	do
		self.has_value = true
		if expr isa ABlockExpr then
			self.n_block = expr
		else
			self.n_expr = expr
		end
		return self
	end

	# Set `self` as optional
	fun define_as_optional: AAttrPropdef
	is
		expect(has_value)
	do
		is_optional = true
		return self
	end

	# Create the lazy attribute.
	#
	# see `mlazypropdef` for more information about this property.
	fun create_lazy: AAttrPropdef
	is
		expect(has_value and mpropdef != null) # The only way to get a null `mpropdef` is when the attribute is defined as `abstract`. But if the attribute has a value, it cannot be abstract.
	do
		if self.mlazypropdef != null then return self # Self already has a `mlazypropdef`
		is_lazy = true
		var mlazyprop = new MAttribute(mpropdef.mclassdef, "lazy _" + name, self.location, none_visibility)
		mlazyprop.is_fictive = true
		var mlazypropdef = new MAttributeDef(mpropdef.mclassdef, mlazyprop, self.location)
		mlazypropdef.is_fictive = true
		self.mlazypropdef = mlazypropdef
		return self
	end

	# Detect the static type from the value assigned to the attribute `self`
	#
	# Return the static type if it can be safely inferred.
	private fun infer_static_type(modelbuilder: ModelBuilder, nexpr: AExpr,
		mclassdef: MClassDef, mmodule: MModule, mreadpropdef: MPropDef): nullable MType
	do
		var mtype = null
		if nexpr isa ANewExpr then
			mtype = modelbuilder.resolve_mtype_unchecked(mclassdef, nexpr.n_type, true)
		else if nexpr isa AAsCastExpr then
			mtype = modelbuilder.resolve_mtype_unchecked(mclassdef, nexpr.n_type, true)
		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")
			if cla != null then mtype = cla.mclass_type
		else if nexpr isa ACharExpr then
			var cla: nullable MClass
			if nexpr.is_code_point then
				cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
			else
				cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Char")
			end
			if cla != null then mtype = cla.mclass_type
		else if nexpr isa ABoolExpr then
			var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Bool")
			if cla != null then mtype = cla.mclass_type
		else if nexpr isa ASuperstringExpr then
			var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
			if cla != null then mtype = cla.mclass_type
		else if nexpr isa AStringFormExpr then
			var cla: nullable MClass
			if nexpr.is_bytestring then
				cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Bytes")
			else if nexpr.is_re then
				cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Regex")
			else if nexpr.is_string then
				cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
			else
				abort
			end
			if cla != null then mtype = cla.mclass_type
		else if nexpr isa AArrayExpr and nexpr.n_type == null and nexpr.n_exprs.not_empty then
			# Non-empty arrays without an explicit type

			var item_mtypes = new Set[MType]
			var fails = false
			for node in nexpr.n_exprs do
				var item_mtype = infer_static_type(modelbuilder, node, mclassdef, mmodule, mreadpropdef)
				if item_mtype == null then
					fails = true
				else
					item_mtypes.add item_mtype
				end
			end

			if fails then return null # Failed to infer some types

			if item_mtypes.length > 1 then
				modelbuilder.error(self, "Type Error: ambiguous array type {item_mtypes.join(" ")}")
			end

			mtype = mmodule.array_type(item_mtypes.first)
		else if nexpr isa AUminusExpr and (nexpr.n_expr isa AIntegerExpr or nexpr.n_expr isa AFloatExpr) then
			# The Int and Float unary - is defined in `kernel`, so this may
			# result in an invalid behavior when using a custom kernel.
			# A workaround is to declare the attribute static type.
			# This is still very useful, especially to novice programmers.
			mtype = infer_static_type(modelbuilder, nexpr.n_expr, mclassdef, mmodule, mreadpropdef)
		else if nexpr isa AOnceExpr then
			mtype = infer_static_type(modelbuilder, nexpr.n_expr, mclassdef, mmodule, mreadpropdef)
		else
			modelbuilder.error(self, "Error: untyped attribute `{mreadpropdef}`. Implicit typing allowed only for literals and new.")
		end
		return mtype
	end

	redef fun check_signature(modelbuilder)
	do
		var mpropdef = self.mpropdef
		if mpropdef == null then return # Error thus skipped
		var ntype = self.n_type
		var mtype = self.mtype
		if mtype == null then return # Error thus skipped

		var mclassdef = mpropdef.mclassdef
		var mmodule = mclassdef.mmodule

		# Check types
		if ntype != null then
			if modelbuilder.resolve_mtype(mclassdef, ntype) == null then return
		end
		var nexpr = n_expr
		if nexpr isa ANewExpr then
			if modelbuilder.resolve_mtype(mclassdef, nexpr.n_type) == null then return
		end

		# Lookup for signature in the precursor
		# FIXME all precursors should be considered
		if not mpropdef.is_intro then
			var precursor_type = mpropdef.mproperty.intro.static_mtype
			if precursor_type == null then return

			if mtype != precursor_type then
				modelbuilder.error(ntype.as(not null), "Redef Error: expected `{precursor_type}` type as a bound; got `{mtype}`.")
				return
			end
		end

		# Check getter and setter
		var meth = self.mreadpropdef
		if meth != null then
			self.check_method_signature(modelbuilder, meth)
			var node: nullable ANode = ntype
			if node == null then node = self
			modelbuilder.check_visibility(node, mtype, meth)
		end
		meth = self.mwritepropdef
		if meth != null then
			self.check_method_signature(modelbuilder, meth)
			var node: nullable ANode = ntype
			if node == null then node = self
			modelbuilder.check_visibility(node, mtype, meth)
		end
	end

	private fun check_method_signature(modelbuilder: ModelBuilder, mpropdef: MMethodDef)
	do
		var mclassdef = mpropdef.mclassdef
		var mmodule = mclassdef.mmodule
		var nsig = self.n_type
		var mysignature = mpropdef.msignature
		if mysignature == null then return # Error thus skiped

		# Lookup for signature in the precursor
		# FIXME all precursors should be considered
		if not mpropdef.is_intro then
			var msignature = mpropdef.mproperty.intro.msignature
			if msignature == null then return

			if mysignature.arity != msignature.arity then
				var node: ANode
				if nsig != null then node = nsig else node = self
				modelbuilder.error(node, "Redef Error: expected {msignature.arity} parameter(s) for `{mpropdef.mproperty.name}{msignature}`; got {mysignature.arity}. See introduction at `{mpropdef.mproperty.full_name}`.")
				return
			end
			var precursor_ret_type = msignature.return_mtype
			var ret_type = mysignature.return_mtype
			if ret_type != null and precursor_ret_type == null then
				var node: ANode
				if nsig != null then node = nsig else node = self
				modelbuilder.error(node, "Redef Error: `{mpropdef.mproperty}` is a procedure, not a function.")
				return
			end

			if mysignature.arity > 0 then
				# Check parameters types
				for i in [0..mysignature.arity[ do
					var myt = mysignature.mparameters[i].mtype
					var prt = msignature.mparameters[i].mtype
					var node: ANode
					if nsig != null then node = nsig else node = self
					if not modelbuilder.check_sametype(node, mmodule, mclassdef.bound_mtype, myt, prt) then
						modelbuilder.error(node, "Redef Error: expected `{prt}` type for parameter `{mysignature.mparameters[i].name}'; got `{myt}`.")
					end
				end
			end
			if precursor_ret_type != null then
				var node: ANode
				if nsig != null then node = nsig else node = self
				if ret_type == null then
					# Inherit the return type
					ret_type = precursor_ret_type
				else if not modelbuilder.check_subtype(node, mmodule, mclassdef.bound_mtype, ret_type, precursor_ret_type) then
					modelbuilder.error(node, "Redef Error: expected `{precursor_ret_type}` return type; got `{ret_type}`.")
				end
			end
		end
	end

	# Type is useless if the attribute type is the same thant the intro.
	redef fun check_repeated_types(modelbuilder) do
		var mreadpropdef = self.mreadpropdef
		if mreadpropdef == null then return
		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 or mpropdef == null then return
		modelbuilder.advice(n_type, "useless-signature", "Warning: useless type repetition on redefined attribute `{mpropdef.name}`")
	end
end

redef class ATypePropdef
	redef type MPROPDEF: MVirtualTypeDef

	redef fun build_property(modelbuilder, mclassdef)
	do
		var name = self.n_qid.n_id.text
		var mprop = modelbuilder.try_get_mproperty_by_name(self.n_qid, mclassdef, name)
		if mprop == null then
			var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
			mprop = new MVirtualTypeProp(mclassdef, name, self.location, mvisibility)
			for c in name.chars do if c >= 'a' and c<= 'z' then
				modelbuilder.warning(n_qid, "bad-type-name", "Warning: lowercase in the virtual type `{name}`.")
				break
			end
		else
			if mprop.is_broken then return
			assert mprop isa MVirtualTypeProp
			check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
		end

		var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
		self.mpropdef = mpropdef
		if mpropdef.is_intro then
			modelbuilder.toolcontext.info("{mpropdef} introduces new type {mprop.full_name}", 4)
		else
			modelbuilder.toolcontext.info("{mpropdef} redefines type {mprop.full_name}", 4)
		end
		if not self.check_redef_keyword(modelbuilder, mclassdef, self.n_kwredef, not mpropdef.is_intro, mprop) then
			mpropdef.is_broken =true
		end
		mclassdef.mprop2npropdef[mprop] = self
		modelbuilder.mpropdef2npropdef[mpropdef] = self
		set_doc(mpropdef, modelbuilder)

		var atfixed = get_single_annotation("fixed", modelbuilder)
		if atfixed != null then
			mpropdef.is_fixed = true
		end
	end

	redef fun build_signature(modelbuilder)
	do
		var mpropdef = self.mpropdef
		if mpropdef == null then return # Error thus skipped
		var mclassdef = mpropdef.mclassdef
		var mtype: nullable MType = null

		var ntype = self.n_type
		mtype = modelbuilder.resolve_mtype_unchecked(mclassdef, ntype, true)
		if mtype == null then return

		mpropdef.bound = mtype
		# print "{mpropdef}: {mtype}"
	end

	redef fun check_signature(modelbuilder)
	do
		var mpropdef = self.mpropdef
		if mpropdef == null then return # Error thus skipped

		var bound = mpropdef.bound
		if bound == null then return # Error thus skipped

		modelbuilder.check_visibility(n_type, bound, mpropdef)

		var mclassdef = mpropdef.mclassdef
		var mmodule = mclassdef.mmodule
		var anchor = mclassdef.bound_mtype

		var ntype = self.n_type
		if modelbuilder.resolve_mtype(mclassdef, ntype) == null then
			mpropdef.bound = null
			return
		end

		# Check redefinitions
		for p in mpropdef.mproperty.lookup_super_definitions(mmodule, anchor) do
			var supbound = p.bound
			if supbound == null or supbound isa MBottomType or p.is_broken then break # broken super bound, skip error
			if p.is_fixed then
				modelbuilder.error(self, "Redef Error: virtual type `{mpropdef.mproperty}` is fixed in super-class `{p.mclassdef.mclass}`.")
				break
			end
			if p.mclassdef.mclass == mclassdef.mclass then
				modelbuilder.error(n_type, "Redef Error: a virtual type cannot be refined.")
				break
			end
			if not modelbuilder.check_subtype(n_type, mmodule, anchor, bound, supbound) then
				modelbuilder.error(n_type, "Redef Error: expected `{supbound}` bound type; got `{bound}`.")
				break
			end
		end
	end
end
src/modelize/modelize_property.nit:17,1--1889,3