diff --git a/lib/laser/analysis/control_flow/constant_propagation.rb b/lib/laser/analysis/control_flow/constant_propagation.rb index 1f88922..759948d 100644 --- a/lib/laser/analysis/control_flow/constant_propagation.rb +++ b/lib/laser/analysis/control_flow/constant_propagation.rb @@ -394,10 +394,17 @@ def raisability_for_templates(possible_dispatches, cartesian, ignore_privacy) then Frequency::NEVER else Frequency.for_samples(seen_private, seen_public) end + if fails_privacy == Frequency::ALWAYS + raise_type = ClassRegistry['NoMethodError'].as_type + end + if fails_lookup > Frequency::NEVER + raise_type |= ClassRegistry['NoMethodError'].as_type + end raised = Frequency.for_samples(seen_raise, seen_succeed) raise_freq = [fails_privacy, raised, fails_lookup].max else raise_freq = Frequency::ALWAYS # no method! + raise_type = ClassRegistry['NoMethodError'].as_type end [raise_freq, raise_type] end diff --git a/lib/laser/standard_library/bignum.rb b/lib/laser/standard_library/bignum.rb index e3a8beb..e773b2b 100644 --- a/lib/laser/standard_library/bignum.rb +++ b/lib/laser/standard_library/bignum.rb @@ -74,6 +74,8 @@ def ===(num) # pure: true # builtin: true # returns: Boolean + # num: Numeric + # raises: never def >(num) end # pure: true diff --git a/lib/laser/standard_library/fixnum.rb b/lib/laser/standard_library/fixnum.rb index 651aa37..4c70424 100644 --- a/lib/laser/standard_library/fixnum.rb +++ b/lib/laser/standard_library/fixnum.rb @@ -73,6 +73,8 @@ def ===(num) # pure: true # builtin: true # returns: Boolean + # num: Numeric + # raises: never def >(num) end # pure: true diff --git a/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb b/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb index c9640de..867309c 100644 --- a/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb +++ b/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb @@ -165,5 +165,40 @@ def silly(x) [Types::FIXNUM], Types::NILCLASS).should == Frequency::ALWAYS end + + it 'can infer a guaranteed NoMethodError from privacy violations' do + g = cfg <<-EOF +class RInfer5 + def foo + end + private :foo + + def bar + self.foo # error! + end +end +EOF + method = ClassRegistry['RInfer5'].instance_method('bar') + method.raise_frequency_for_types( + Utilities.type_for(ClassRegistry['RInfer5'])).should == Frequency::ALWAYS + end + + it 'can infer a potential lookup failure when a successful one exists' do + g = cfg <<-EOF +class RInfer6 + def bar + if gets.size > 0 + x = 'hello' + else + x = 5 + end + x.intern # error sometimes + end +end +EOF + method = ClassRegistry['RInfer6'].instance_method('bar') + method.raise_frequency_for_types( + Utilities.type_for(ClassRegistry['RInfer6'])).should == Frequency::MAYBE + end end \ No newline at end of file diff --git a/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb b/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb index deb6aaf..10705bb 100644 --- a/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb +++ b/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb @@ -146,4 +146,41 @@ def silly(x) [Types::FIXNUM], Types::NILCLASS).should equal_type(ClassRegistry['NoMethodError'].as_type) end + + it 'can infer a guaranteed NoMethodError from privacy violations' do + g = cfg <<-EOF +class RTInfer5 + def foo + end + private :foo + + def bar + self.foo # error! + end +end +EOF + method = ClassRegistry['RTInfer5'].instance_method('bar') + method.raise_type_for_types( + Utilities.type_for(ClassRegistry['RTInfer5'])).should( + equal_type(ClassRegistry['NoMethodError'].as_type)) + end + + it 'can infer a potential lookup failure when a successful one exists' do + g = cfg <<-EOF +class RTInfer6 + def bar + if gets.size > 0 + x = 'hello' + else + x = 5 + end + x.intern # error sometimes + end +end +EOF + method = ClassRegistry['RTInfer6'].instance_method('bar') + method.raise_type_for_types( + Utilities.type_for(ClassRegistry['RTInfer6'])).should( + equal_type(ClassRegistry['NoMethodError'].as_type)) + end end \ No newline at end of file