Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed up type checker #193

Merged
merged 6 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions lib/steep/ast/types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ def to_s(level = 0)
"masked(#{type}|#{mask})"
end

def free_variables(set = Set.new)
type.free_variables(set)
mask.free_variables(set)
def free_variables
@fvs ||= Set.new.tap do |set|
set.merge(type.free_variables)
set.merge(mask.free_variables)
end
end

def each_type(&block)
Expand Down
4 changes: 1 addition & 3 deletions lib/steep/ast/types/any.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ def to_s
"untyped"
end

def free_variables
Set.new
end
include Helper::NoFreeVariables

def level
[1]
Expand Down
4 changes: 1 addition & 3 deletions lib/steep/ast/types/boolean.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ def to_s
"bool"
end

def free_variables
Set.new
end
include Helper::NoFreeVariables

def level
[0]
Expand Down
4 changes: 1 addition & 3 deletions lib/steep/ast/types/bot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ def to_s
"⟘"
end

def free_variables
Set.new
end
include Helper::NoFreeVariables

def level
[2]
Expand Down
4 changes: 2 additions & 2 deletions lib/steep/ast/types/class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ def subst(s)
s.module_type or raise "Unexpected substitution: #{inspect}"
end

def free_variables
Set.new
def free_variables()
@fvs = Set.new([self])
end

def level
Expand Down
38 changes: 25 additions & 13 deletions lib/steep/ast/types/factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@ module Types
class Factory
attr_reader :definition_builder

attr_reader :type_name_cache
attr_reader :type_cache

def initialize(builder:)
@definition_builder = builder

@type_name_cache = {}
@type_cache = {}
end

def type_name_resolver
@type_name_resolver ||= RBS::TypeNameResolver.from_env(definition_builder.env)
end

def type(type)
case type
ty = type_cache[type] and return ty

type_cache[type] = case type
when RBS::Types::Bases::Any
Any.new(location: nil)
when RBS::Types::Bases::Class
Expand Down Expand Up @@ -144,14 +152,17 @@ def type_1(type)
end

def type_name(name)
case
when name.class?
Names::Module.new(name: name.name, namespace: namespace(name.namespace), location: nil)
when name.interface?
Names::Interface.new(name: name.name, namespace: namespace(name.namespace), location: nil)
when name.alias?
Names::Alias.new(name: name.name, namespace: namespace(name.namespace), location: nil)
end
n = type_name_cache[name] and return n

type_name_cache[name] =
(case
when name.class?
Names::Module.new(name: name.name, namespace: namespace(name.namespace), location: nil)
when name.interface?
Names::Interface.new(name: name.name, namespace: namespace(name.namespace), location: nil)
when name.alias?
Names::Alias.new(name: name.name, namespace: namespace(name.namespace), location: nil)
end)
end

def type_name_1(name)
Expand Down Expand Up @@ -190,7 +201,7 @@ def params(type)
)
end

def method_type(method_type, self_type:)
def method_type(method_type, self_type:, subst2: nil)
fvs = self_type.free_variables()

type_params = []
Expand All @@ -208,6 +219,7 @@ def method_type(method_type, self_type:)
end
end
subst = Interface::Substitution.build(alpha_vars, alpha_types)
subst.merge!(subst2) if subst2

type = Interface::MethodType.new(
type_params: type_params,
Expand Down Expand Up @@ -332,7 +344,7 @@ def interface(type, private:, self_type: type)

interface.methods[name] = Interface::Interface::Combination.overload(
method.method_types.map do |type|
method_type(type, self_type: self_type) {|ty| ty.subst(subst) }
method_type(type, self_type: self_type, subst2: subst)
end,
incompatible: name == :initialize || name == :new
)
Expand All @@ -353,7 +365,7 @@ def interface(type, private:, self_type: type)
definition.methods.each do |name, method|
interface.methods[name] = Interface::Interface::Combination.overload(
method.method_types.map do |type|
method_type(type, self_type: self_type) {|type| type.subst(subst) }
method_type(type, self_type: self_type, subst2: subst)
end,
incompatible: method.attributes.include?(:incompatible)
)
Expand All @@ -379,7 +391,7 @@ def interface(type, private:, self_type: type)

interface.methods[name] = Interface::Interface::Combination.overload(
method.method_types.map do |type|
method_type(type, self_type: self_type) {|type| type.subst(subst) }
method_type(type, self_type: self_type, subst2: subst)
end,
incompatible: method.attributes.include?(:incompatible)
)
Expand Down
6 changes: 6 additions & 0 deletions lib/steep/ast/types/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ def level_of_children(children)
end || []
end
end

module NoFreeVariables
def free_variables()
@fvs ||= Set.new
end
end
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/steep/ast/types/instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ def subst(s)
s.instance_type or raise "Unexpected substitution: #{inspect}"
end

def free_variables
Set.new
def free_variables()
@fvs = Set.new([self])
end

def to_s
Expand Down
12 changes: 8 additions & 4 deletions lib/steep/ast/types/intersection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,14 @@ def to_s
"(#{types.map(&:to_s).sort.join(" & ")})"
end

def free_variables
types.each.with_object(Set.new) do |type, set|
set.merge(type.free_variables)
end
def free_variables()
@fvs ||= begin
set = Set.new
types.each do |type|
set.merge(type.free_variables)
end
set
end
end

include Helper::ChildrenLevel
Expand Down
4 changes: 1 addition & 3 deletions lib/steep/ast/types/literal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ def to_s
value.inspect
end

def free_variables
Set.new
end
include Helper::NoFreeVariables

def level
[0]
Expand Down
22 changes: 13 additions & 9 deletions lib/steep/ast/types/name.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ def initialize(name:, location: nil)
@name = name
end

def free_variables
Set.new
end
include Helper::NoFreeVariables

def subst(s)
self
Expand Down Expand Up @@ -41,7 +39,7 @@ def ==(other)
alias eql? ==

def hash
self.class.hash ^ name.hash ^ args.hash
@hash ||= self.class.hash ^ name.hash ^ args.hash
end

def to_s
Expand All @@ -57,14 +55,20 @@ def with_location(new_location)
end

def subst(s)
self.class.new(location: location,
name: name,
args: args.map {|a| a.subst(s) })
if free_variables.intersect?(s.domain)
self.class.new(location: location,
name: name,
args: args.map {|a| a.subst(s) })
else
self
end
end

def free_variables
args.each.with_object(Set.new) do |type, vars|
vars.merge(type.free_variables)
@fvs ||= Set.new().tap do |set|
args.each do |type|
set.merge(type.free_variables)
end
end
end

Expand Down
4 changes: 1 addition & 3 deletions lib/steep/ast/types/nil.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ def to_s
"nil"
end

def free_variables
Set.new
end
include Helper::NoFreeVariables

def level
[0]
Expand Down
7 changes: 5 additions & 2 deletions lib/steep/ast/types/proc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ def to_s
"^#{params} -> #{return_type}"
end

def free_variables
params.free_variables + return_type.free_variables
def free_variables()
@fvs ||= Set.new.tap do |set|
set.merge(params.free_variables)
set.merge(return_type.free_variables)
end
end

def level
Expand Down
13 changes: 9 additions & 4 deletions lib/steep/ast/types/record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,17 @@ def subst(s)
end

def to_s
"{ #{elements.map {|key, value| "#{key.inspect} => #{value}" }.join(", ")} }"
strings = elements.keys.sort.map do |key|
"#{key.inspect} => #{elements[key]}"
end
"{ #{strings.join(", ")} }"
end

def free_variables
elements.each_value.with_object(Set.new) do |type, set|
set.merge(type.free_variables)
def free_variables()
@fvs ||= Set.new.tap do |set|
elements.each_value do |type|
set.merge(type.free_variables)
end
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/steep/ast/types/self.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def subst(s)
end

def free_variables
Set.new
@fvs ||= Set.new([self])
end

def level
Expand Down
4 changes: 1 addition & 3 deletions lib/steep/ast/types/top.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ def to_s
"⟙"
end

def free_variables
Set.new
end
include Helper::NoFreeVariables

def level
[2]
Expand Down
8 changes: 5 additions & 3 deletions lib/steep/ast/types/tuple.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ def to_s
"[#{types.join(", ")}]"
end

def free_variables
types.each.with_object(Set.new) do |type, set|
set.merge(type.free_variables)
def free_variables()
@fvs ||= Set.new.tap do |set|
types.each do |type|
set.merge(type.free_variables)
end
end
end

Expand Down
11 changes: 8 additions & 3 deletions lib/steep/ast/types/union.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ def initialize(types:, location: nil)
end

def self.build(types:, location: nil)
return AST::Types::Bot.new if types.empty?
return types.first if types.size == 1

types.flat_map do |type|
if type.is_a?(Union)
type.types
Expand All @@ -29,7 +32,7 @@ def self.build(types:, location: nil)
type
end
end.compact.uniq.yield_self do |tys|
case tys.length
case tys.size
when 0
AST::Types::Bot.new
when 1
Expand Down Expand Up @@ -61,8 +64,10 @@ def to_s
end

def free_variables
types.each.with_object(Set.new) do |type, set|
set.merge(type.free_variables)
@fvs ||= Set.new.tap do |set|
types.each do |type|
set.merge(type.free_variables)
end
end
end

Expand Down
4 changes: 2 additions & 2 deletions lib/steep/ast/types/var.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ def subst(s)
end
end

def free_variables
Set.new([name])
def free_variables()
@fvs ||= Set.new([name])
end

def level
Expand Down
4 changes: 1 addition & 3 deletions lib/steep/ast/types/void.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ def to_s
"void"
end

def free_variables
Set.new
end
include Helper::NoFreeVariables

def level
[0]
Expand Down
Loading