~singpolyma/dhall-ruby

1e9d4f30ec1c82cd7dbf2bbaf6c67d8fc6f0d97e — Stephen Paul Weber 3 years ago 0555a22
Refactor RecordProjection typecheck
2 files changed, 20 insertions(+), 10 deletions(-)

M lib/dhall/ast.rb
M lib/dhall/typecheck.rb
M lib/dhall/ast.rb => lib/dhall/ast.rb +12 -0
@@ 443,6 443,14 @@ module Dhall
			}.sort])
		end

		def keys
			record.keys
		end

		def slice(keys)
			RecordType.for(record.select { |k, _| keys.include?(k) })
		end

		def ==(other)
			other.respond_to?(:record) && record.to_a == other.record.to_a
		end


@@ 459,6 467,10 @@ module Dhall
	class EmptyRecordType < RecordType
		include(ValueSemantics.for_attributes {})

		def slice(*)
			self
		end

		def record
			{}
		end

M lib/dhall/typecheck.rb => lib/dhall/typecheck.rb +8 -10
@@ 587,25 587,23 @@ module Dhall
		class RecordProjection
			def initialize(projection)
				@projection = projection
				@record = projection.record
				@record = TypeChecker.for(projection.record)
				@selectors = projection.selectors
			end

			def annotate(context)
				arecord = TypeChecker.for(@record).annotate(context)
				arecord = @record.annotate(context)

				unless arecord.type.class == Dhall::RecordType
					raise TypeError, "RecordProjection on #{arecord.type}"
				end
				TypeChecker.assert arecord.type.class.name, "Dhall::RecordType",
				                   "RecordProjection on #{arecord.type}"

				slice = arecord.type.record.select { |k, _| @selectors.include?(k) }
				if slice.size != @selectors.length
					raise TypeError, "#{arecord.type} missing one of: #{@selectors}"
				end
				slice = arecord.type.slice(@selectors)
				TypeChecker.assert slice.keys, @selectors,
				                   "#{arecord.type} missing one of: #{@selectors}"

				Dhall::TypeAnnotation.new(
					value: @projection.with(record: arecord),
					type:  Dhall::RecordType.for(slice)
					type:  slice
				)
			end
		end