-
Notifications
You must be signed in to change notification settings - Fork 9
TypeInference
About the type inference specification of plsense
The type inference is done by gathering substitute/return statement.
sub hoge () {
my $hoge = shift; # substitute statement
return $hoge; # return statement
}
Identify the type of Variable/Method by gathering them.
Can not analyze the file that has syntax error.
- Literal
- bless
- Array
- Hash
- Scope of variable
- Binomial operator
- Ternary operator
- Variable/Method in literal
- use/require
- Call of method
- Argument of method
- Grammar provided by module
For identify type, literal has most priority.
my $hoge = "hoge"; # SCALAR
my @hoge = ("ho", "ge"); # ARRAY
my %hoge = ( name => "hoge", ); # HASH
my $hoge = [ "ho", "ge" ]; # REFERENCE of ARRAY
my $hoge = { name => "hoge", }; # REFERENCE of HASH
If the context has multiple different literal like the following,
It can not be ensured that the type is identified.
my $hoge = [ "hoge" ];
my $fuga = {};
if ( $hoge ) { $fuga = $hoge; } # can't identify $fuga
If the module has the method named 'new',
The result of the method is considered as instance of the module.
It is not ensured that the type is identified by returning blessed reference.
package Hoge;
sub new { return; } # be instance of Hoge absolutely
sub get_instance { Fuga->new(); } # ensure instance of FUga
sub get_instance { my $cls=shift; my $r={}; bless $r, $cls; return $r; } # not ensure instance of $cls
Number of element is ignored. Each element of array is considered as same type.
$hoge[0] = Hoge->new();
$hoge[1] = \%fuga;
$hoge[0]-> # not ensure complete method of Hoge
The value can be discerned if the key is literal and match '[a-zA-Z0-9_-]+'.
$hoge{hoge} = Hoge->new();
$hoge{"fuga"} = \%fuga;
my ($foo, $bar) = ("foo", "bar");
$hoge{$foo} = Foo->new();
$hoge{$bar} = Bar->new(); # not discern $bar from $foo
$hoge{hoge}-> # ensure complete method of Hoge
$hoge{'fuga'}->{ # ensure complete key of %fuga
$hoge{$foo}-> # not ensure complete method of Foo
Variable can be discerned until sub scope.
package Hoge;
my $some = Fuga->new();
sub get_hoge {
my $some = Foo->new();
foreach my $e ( "foo", "bar" ) {
my $some = $e;
}
$some-> # not ensure complete method of Foo
}
$some-> # ensure complete method of Fuga
my $hoge = Hoge->new() || Fuga->new(); # $hoge is considered as instance of Hoge
my $fuga = Hoge->new() && Fuga->new(); # $fuga is considered as instance of Fuga
The first part is used.
my $some = $hoge ? Hoge->new()
: $fuga ? Fuga->new()
: Bar->new();
$some-> # ensure complete method of Hoge
Array or value of hash is identified only.
my @hoge = ( @fuga, @bar ); # if @fuga/@bar is identified, @hoge is identified.
my %hoge = ( fuga => get_fuga() ); # if get_fuga() is identified, $hoge{fuga} is identified.
my $hoge = { %fuga }; # can not identify
my $hoge = [ @fuga, @bar ]; # can not identify
Bare word is interpreted only.
use Hoge; # OK
require Hoge; # OK
require "Hoge"; # ignore
require $class; # ignore
Also, if pragma, the effect is not interpreted other than the following.
- vars
About the above pragmas, the plugin is implemented.
For detail, see Scalability.
my $hoge = new Hoge; # can not identify
my $hoge = Hoge->new; # can identify
my $hoge = myfunc $fuga; # $fuga is not considered as argument
my $hoge = myfunc($fuga); # $fuga is considered as argument
my $hoge = shift @fuga; # if builtin method, it's OK
But, can not identify if the builtin method is not handled.
At present, the handled builtin method is the following.
- bless
- eval (BLOCK only)
- grep
- first
- pop
- push
- reverse
- shift
- sort
- undef
- unshift
- values
Also, the handled external method is the following.
- List::Util::first
- List::AllUtils::first
- List::MoreUtils::uniq
- List::AllUtils::uniq
handled means that the plugin is implemented about the method in addition to normal.
For detail, see Scalability.
Normally, the type of argument can not be identified until found calling the method.
sub hoge {
my $hoge = shift;
$hoge-> # $hoge is unknown
}
hoge( Hoge->new() ); # if this statement exists、$hoge is identified above.
But, if the module that the method belongs to has the method named 'new',
the first argument of the method in the module is considered as instance of the module.
package Hoge;
sub new { my $r = {}; bless $r; return $r; }
sub hoge {
my $hoge = shift; # be instance of Hoge absolutely
my $fuga = shift;
$hoge-> # ensure complete method of Hoge
}
In the case, index of given argument move to back.
package main;
use Hoge;
Hoge->hoge( $arg ); # above $fuga is considered as $arg
By right, the word before arrow operator is the first argument.
But, plsense has not the idea.
Analyzing is done by reading default grammar of Perl.
If some module provide special grammar, it can be read.
For example, write the following by using Moose,
package Hoge;
use Moose;
has 'fuga' => ( is => 'rw', isa => 'Fuga' );
package main;
my $hoge = Hoge->new();
$hoge->fuga-> # return of fuga() is instance of Fuga
It is not identified.
But, at present, can read special grammar of the following module.
- Class::Std
It means that the plugin is implemented about the above module.
For detail, see Scalability.