Detect circularity errors for virtual types.

Property definitions

nitc :: modelize_property $ ModelBuilder :: check_virtual_types_circularity
	# 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
src/modelize/modelize_property.nit:445,2--508,4