Module: Dhall::TypeChecker

Defined in:
lib/dhall/typecheck.rb

Defined Under Namespace

Classes: AnonymousType, Application, Assertion, Builtin, Context, EmptyAnonymousType, EmptyList, EmptyRecord, Enum, Forall, Function, If, LetIn, LetInAnnotated, List, Literal, Merge, Operator, OperatorEquivalent, OperatorListConcatenate, OperatorRecursiveRecordMerge, OperatorRecursiveRecordTypeMerge, OperatorRightBiasedRecordMerge, Optional, OptionalNone, Record, RecordProjection, RecordProjectionByExpression, RecordSelection, TextLiteral, ToMap, TypeAnnotation, Union, UnionType, Variable

Constant Summary collapse

KINDS =
[
	Builtins[:Type],
	Builtins[:Kind],
	Builtins[:Sort]
].freeze
BUILTIN_TYPES =
{
	"Bool"              => Builtins[:Type],
	"Type"              => Builtins[:Kind],
	"Kind"              => Builtins[:Sort],
	"Natural"           => Builtins[:Type],
	"Integer"           => Builtins[:Type],
	"Double"            => Builtins[:Type],
	"Text"              => Builtins[:Type],
	"List"              => Dhall::Forall.of_arguments(
		Builtins[:Type],
		body: Builtins[:Type]
	),
	"Optional"          => Dhall::Forall.of_arguments(
		Builtins[:Type],
		body: Builtins[:Type]
	),
	"None"              => Dhall::Forall.new(
		var:  "A",
		type: Builtins[:Type],
		body: Dhall::Application.new(
			function: Builtins[:Optional],
			argument: Dhall::Variable["A"]
		)
	),
	"Natural/build"     => Dhall::Forall.of_arguments(
		Dhall::Forall.new(
			var:  "natural",
			type: Builtins[:Type],
			body: Dhall::Forall.new(
				var:  "succ",
				type: Dhall::Forall.of_arguments(
					Dhall::Variable["natural"],
					body: Dhall::Variable["natural"]
				),
				body: Dhall::Forall.new(
					var:  "zero",
					type: Dhall::Variable["natural"],
					body: Dhall::Variable["natural"]
				)
			)
		),
		body: Builtins[:Natural]
	),
	"Natural/fold"      => Dhall::Forall.of_arguments(
		Builtins[:Natural],
		body: Dhall::Forall.new(
			var:  "natural",
			type: Builtins[:Type],
			body: Dhall::Forall.new(
				var:  "succ",
				type: Dhall::Forall.of_arguments(
					Dhall::Variable["natural"],
					body: Dhall::Variable["natural"]
				),
				body: Dhall::Forall.new(
					var:  "zero",
					type: Dhall::Variable["natural"],
					body: Dhall::Variable["natural"]
				)
			)
		)
	),
	"Natural/subtract"  => Dhall::Forall.of_arguments(
		Builtins[:Natural],
		Builtins[:Natural],
		body: Builtins[:Natural]
	),
	"Natural/isZero"    => Dhall::Forall.of_arguments(
		Builtins[:Natural],
		body: Builtins[:Bool]
	),
	"Natural/even"      => Dhall::Forall.of_arguments(
		Builtins[:Natural],
		body: Builtins[:Bool]
	),
	"Natural/odd"       => Dhall::Forall.of_arguments(
		Builtins[:Natural],
		body: Builtins[:Bool]
	),
	"Natural/toInteger" => Dhall::Forall.of_arguments(
		Builtins[:Natural],
		body: Builtins[:Integer]
	),
	"Natural/show"      => Dhall::Forall.of_arguments(
		Builtins[:Natural],
		body: Builtins[:Text]
	),
	"Text/show"         => Dhall::Forall.of_arguments(
		Builtins[:Text],
		body: Builtins[:Text]
	),
	"List/build"        => Dhall::Forall.new(
		var:  "a",
		type: Builtins[:Type],
		body: Dhall::Forall.of_arguments(
			Dhall::Forall.new(
				var:  "list",
				type: Builtins[:Type],
				body: Dhall::Forall.new(
					var:  "cons",
					type: Dhall::Forall.of_arguments(
						Dhall::Variable["a"],
						Dhall::Variable["list"],
						body: Dhall::Variable["list"]
					),
					body: Dhall::Forall.new(
						var:  "nil",
						type: Dhall::Variable["list"],
						body: Dhall::Variable["list"]
					)
				)
			),
			body: Dhall::Application.new(
				function: Builtins[:List],
				argument: Dhall::Variable["a"]
			)
		)
	),
	"List/fold"         => Dhall::Forall.new(
		var:  "a",
		type: Builtins[:Type],
		body: Dhall::Forall.of_arguments(
			Dhall::Application.new(
				function: Builtins[:List],
				argument: Dhall::Variable["a"]
			),
			body: Dhall::Forall.new(
				var:  "list",
				type: Builtins[:Type],
				body: Dhall::Forall.new(
					var:  "cons",
					type: Dhall::Forall.of_arguments(
						Dhall::Variable["a"],
						Dhall::Variable["list"],
						body: Dhall::Variable["list"]
					),
					body: Dhall::Forall.new(
						var:  "nil",
						type: Dhall::Variable["list"],
						body: Dhall::Variable["list"]
					)
				)
			)
		)
	),
	"List/length"       => Dhall::Forall.new(
		var:  "a",
		type: Builtins[:Type],
		body: Dhall::Forall.of_arguments(
			Dhall::Application.new(
				function: Builtins[:List],
				argument: Dhall::Variable["a"]
			),
			body: Builtins[:Natural]
		)
	),
	"List/head"         => Dhall::Forall.new(
		var:  "a",
		type: Builtins[:Type],
		body: Dhall::Forall.of_arguments(
			Dhall::Application.new(
				function: Builtins[:List],
				argument: Dhall::Variable["a"]
			),
			body: Dhall::Application.new(
				function: Builtins[:Optional],
				argument: Dhall::Variable["a"]
			)
		)
	),
	"List/last"         => Dhall::Forall.new(
		var:  "a",
		type: Builtins[:Type],
		body: Dhall::Forall.of_arguments(
			Dhall::Application.new(
				function: Builtins[:List],
				argument: Dhall::Variable["a"]
			),
			body: Dhall::Application.new(
				function: Builtins[:Optional],
				argument: Dhall::Variable["a"]
			)
		)
	),
	"List/indexed"      => Dhall::Forall.new(
		var:  "a",
		type: Builtins[:Type],
		body: Dhall::Forall.of_arguments(
			Dhall::Application.new(
				function: Builtins[:List],
				argument: Dhall::Variable["a"]
			),
			body: Dhall::Application.new(
				function: Builtins[:List],
				argument: Dhall::RecordType.new(
					record: {
						"index" => Builtins[:Natural],
						"value" => Dhall::Variable["a"]
					}
				)
			)
		)
	),
	"List/reverse"      => Dhall::Forall.new(
		var:  "a",
		type: Builtins[:Type],
		body: Dhall::Forall.of_arguments(
			Dhall::Application.new(
				function: Builtins[:List],
				argument: Dhall::Variable["a"]
			),
			body: Dhall::Application.new(
				function: Builtins[:List],
				argument: Dhall::Variable["a"]
			)
		)
	),
	"Optional/fold"     => Dhall::Forall.new(
		var:  "a",
		type: Builtins[:Type],
		body: Dhall::Forall.of_arguments(
			Dhall::Application.new(
				function: Builtins[:Optional],
				argument: Dhall::Variable["a"]
			),
			body: Dhall::Forall.new(
				var:  "optional",
				type: Builtins[:Type],
				body: Dhall::Forall.new(
					var:  "just",
					type: Dhall::Forall.of_arguments(
						Dhall::Variable["a"],
						body: Dhall::Variable["optional"]
					),
					body: Dhall::Forall.new(
						var:  "nothing",
						type: Dhall::Variable["optional"],
						body: Dhall::Variable["optional"]
					)
				)
			)
		)
	),
	"Optional/build"    => Dhall::Forall.new(
		var:  "a",
		type: Builtins[:Type],
		body: Dhall::Forall.of_arguments(
			Dhall::Forall.new(
				var:  "optional",
				type: Builtins[:Type],
				body: Dhall::Forall.new(
					var:  "just",
					type: Dhall::Forall.of_arguments(
						Dhall::Variable["a"],
						body: Dhall::Variable["optional"]
					),
					body: Dhall::Forall.new(
						var:  "nothing",
						type: Dhall::Variable["optional"],
						body: Dhall::Variable["optional"]
					)
				)
			),
			body: Dhall::Application.new(
				function: Builtins[:Optional],
				argument: Dhall::Variable["a"]
			)
		)
	),
	"Integer/show"      => Dhall::Forall.of_arguments(
		Builtins[:Integer],
		body: Builtins[:Text]
	),
	"Integer/toDouble"  => Dhall::Forall.of_arguments(
		Builtins[:Integer],
		body: Builtins[:Double]
	),
	"Double/show"       => Dhall::Forall.of_arguments(
		Builtins[:Double],
		body: Builtins[:Text]
	)
}.freeze

Class Method Summary collapse

Class Method Details

.annotate(expr) ⇒ Object



45
46
47
48
# File 'lib/dhall/typecheck.rb', line 45

def self.annotate(expr)
	return if expr.nil?
	TypeChecker.for(expr).annotate(TypeChecker::Context.new)
end

.assert(type, assertion, message) ⇒ Object

Raises:

  • (TypeError)


8
9
10
11
# File 'lib/dhall/typecheck.rb', line 8

def self.assert(type, assertion, message)
	raise TypeError, message unless assertion === type
	type
end

.assert_type(expr, assertion, message, context:) ⇒ Object

Raises:

  • (TypeError)


13
14
15
16
17
18
# File 'lib/dhall/typecheck.rb', line 13

def self.assert_type(expr, assertion, message, context:)
	aexpr = self.for(expr).annotate(context)
	type = aexpr.type.normalize
	raise TypeError, "#{message}: #{type}" unless assertion === type
	aexpr
end

.assert_types_match(a, b, message, context:) ⇒ Object



20
21
22
23
24
25
26
27
# File 'lib/dhall/typecheck.rb', line 20

def self.assert_types_match(a, b, message, context:)
	atype = self.for(a).annotate(context).type
	btype = self.for(b).annotate(context).type
	unless atype.normalize == btype.normalize
		raise TypeError, "#{message}: #{atype}, #{btype}"
	end
	atype
end

.for(expr) ⇒ Object

Raises:

  • (TypeError)


29
30
31
32
33
34
35
36
37
38
# File 'lib/dhall/typecheck.rb', line 29

def self.for(expr)
	@typecheckers.each do |node_matcher, (typechecker, extras)|
		if node_matcher === expr
			msg = [:call, :for, :new].find { |m| typechecker.respond_to?(m) }
			return typechecker.public_send(msg, expr, *extras)
		end
	end

	raise TypeError, "Unknown expression: #{expr.inspect}"
end

.register(typechecker, node_type, *extras) ⇒ Object



40
41
42
43
# File 'lib/dhall/typecheck.rb', line 40

def self.register(typechecker, node_type, *extras)
	@typecheckers ||= {}
	@typecheckers[node_type] ||= [typechecker, extras]
end

.type_of(expr) ⇒ Object



50
51
52
# File 'lib/dhall/typecheck.rb', line 50

def self.type_of(expr)
	annotate(expr)&.type
end