Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Keep the main nominal type and constraint type(s) separated out at pa…
…rse time. This simplifies signature construction and also avoids creating a bunch of one-elements junctions that we don't really need. Between this and yesterday's refactor, we shave about 10% or so off Rakudo's startup time.
  • Loading branch information
jnthn committed Oct 7, 2009
1 parent 8d63378 commit cf8884d
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 91 deletions.
125 changes: 57 additions & 68 deletions src/classes/Signature.pir
Expand Up @@ -86,72 +86,50 @@ the Signature.
goto sigil_done
sigil_done:
# Get constraints list, which may have class and role types as well as
# subset types. If we have no unique role or class type, they all become
# constraints; otherwise, we find the unique type. Finally, we turn the
# list of constraints into a junction.
.local pmc cur_list, cur_list_iter, constraints, type, test_item
constraints = root_new ['parrot';'ResizablePMCArray']
type = null
cur_list = attr["type"]
if null cur_list goto cur_list_loop_end
have_type_attr:
cur_list = cur_list.'eigenstates'()
cur_list_iter = iter cur_list
cur_list_loop:
unless cur_list_iter goto cur_list_loop_end
test_item = shift cur_list_iter
$I0 = isa test_item, "Role"
if $I0 goto is_type
$P0 = getprop "subtype_realtype", test_item
if null $P0 goto not_refinement
unless null type goto all_constraints
type = $P0
push constraints, test_item
goto cur_list_loop
not_refinement:
$I0 = isa test_item, "P6protoobject"
if $I0 goto is_type
push constraints, test_item
goto cur_list_loop
is_type:
unless null type goto all_constraints
type = test_item
goto cur_list_loop
all_constraints:
type = null
constraints = cur_list
cur_list_loop_end:
# Set parametric type, if any.
unless null type goto have_type
# Handle the main, nominal type. The main thing to do is make sure we come
# out with a type that is not a constraint (but keep any constraint around
# for later application).
.local pmc nom_type, bonus_constraint
$I0 = attr['slurpy']
if $I0 goto object_type
unless null role_type goto simple_role_type
type = getattribute self, '$!default_type'
unless null type goto done_role_type
nom_type = attr['nom_type']
unless null nom_type goto have_nom_type
unless null role_type goto nom_type_done
nom_type = getattribute self, '$!default_type'
unless null nom_type goto nom_type_done
object_type:
type = get_hll_global 'Object'
nom_type = get_hll_global 'Object'
goto nom_type_done
have_nom_type:
$P0 = getprop "subtype_realtype", nom_type
if null $P0 goto nom_type_done
bonus_constraint = nom_type
nom_type = $P0
nom_type_done:
# Set parametric type, if any.
if null role_type goto done_role_type
if null nom_type goto simple_role_type
nom_type = role_type.'!select'(nom_type)
goto done_role_type
simple_role_type:
type = role_type
goto done_role_type
have_type:
if null role_type goto done_role_type
type = role_type.'!select'(type)
nom_type = role_type
done_role_type:
attr["nom_type"] = type
$I0 = elements constraints
if $I0 == 0 goto no_constraints
$P0 = 'infix:&'(type, constraints :flat)
attr["type"] = $P0
constraints = 'infix:&'(constraints :flat)
goto set_constraints
no_constraints:
null constraints
attr["type"] = type
set_constraints:
attr["cons_type"] = constraints
# Store main nominal type.
attr["nom_type"] = nom_type
# Do we have any constraint types?
.local pmc cons_type
cons_type = attr['cons_type']
if null cons_type goto empty_cons_type
if null bonus_constraint goto cons_type_done
cons_type = 'infix:&'(cons_type, bonus_constraint)
empty_cons_type:
if null bonus_constraint goto cons_type_done
cons_type = 'infix:&'(bonus_constraint)
cons_type_done:
attr["cons_type"] = cons_type
# Add to parameters list.
.local pmc params
Expand Down Expand Up @@ -368,8 +346,9 @@ lexicals as needed and performing type checks.
name = param['name']
if name == 'self' goto param_loop
sigil = substr name, 0, 1
.local pmc type, optional, orig, var
type = param['type']
.local pmc nom_type, cons_type, optional, orig, var
nom_type = param['nom_type']
cons_type = param['cons_type']
optional = param['optional']
orig = callerlex[name]
if sigil == '@' goto param_array
Expand All @@ -380,20 +359,30 @@ lexicals as needed and performing type checks.
$I0 = defined orig
unless $I0 goto param_val_done
not_optional:
if null type goto param_val_done
.lex '$/', $P99
$P0 = type.'ACCEPTS'(var)
$P0 = nom_type.'ACCEPTS'(var)
unless $P0 goto err_param_type
if null cons_type goto param_val_done
$P0 = cons_type.'ACCEPTS'(var)
unless $P0 goto err_param_type
goto param_val_done
param_array:
$P0 = type.'ACCEPTS'(orig)
$P0 = nom_type.'ACCEPTS'(orig)
unless $P0 goto err_param_type_non_scalar
if null cons_type goto param_array_types_done
$P0 = cons_type.'ACCEPTS'(orig)
unless $P0 goto err_param_type_non_scalar
param_array_types_done:
var = descalarref orig
var = '!CALLMETHOD'('Array', var)
goto param_val_done
param_hash:
$P0 = type.'ACCEPTS'(orig)
$P0 = nom_type.'ACCEPTS'(orig)
unless $P0 goto err_param_type_non_scalar
if null cons_type goto param_hash_types_done
$P0 = cons_type.'ACCEPTS'(orig)
unless $P0 goto err_param_type_non_scalar
param_hash_types_done:
var = descalarref orig
var = '!CALLMETHOD'('Hash', var)
goto param_val_done
Expand Down Expand Up @@ -424,7 +413,7 @@ lexicals as needed and performing type checks.
var = $P0
param_readtype_done:
## set any type properties
setprop var, 'type', type
setprop var, 'type', nom_type
## place the updated variable back into lex
callerlex[name] = var
goto param_loop
Expand All @@ -450,7 +439,7 @@ lexicals as needed and performing type checks.
'return'($P0)
not_junctional:
.local string errmsg, callername
errmsg = '!make_type_fail_message'('Parameter', orig, type)
errmsg = '!make_type_fail_message'('Parameter', orig, nom_type)
callername = callersub
if callername goto have_callername
callername = '<anon>'
Expand Down
39 changes: 22 additions & 17 deletions src/parser/actions.pm
Expand Up @@ -1054,7 +1054,8 @@ method signature($/, $key) {
:read_type( $readtype ),
:invocant( $invocant ),
:multi_invocant( $multi_inv_suppress ?? 0 !! 1 ),
:types( $var<type> )
:nom_type( $var<nom_type> ),
:cons_type( $var<cons_type> )
);

## handle end of multi-invocant sequence
Expand Down Expand Up @@ -1155,8 +1156,6 @@ method parameter($/) {
}

## keep track of any type constraints
my $typelist := PAST::Op.new( :name('all'), :pasttype('call') );
$var<type> := $typelist;
if $<type_constraint> {
if $<type_constraint> != 1 {
$/.panic("Multiple prefix constraints not yet supported");
Expand All @@ -1177,7 +1176,8 @@ method parameter($/) {
@?BLOCK[0].symbol( $type_past.name(), :scope('lexical') );
}
else {
# we need to thunk it
# we need to thunk it - since it's a thunk, needs to be a
# constraint type really.
my $thunk := PAST::Op.new(
:name('ACCEPTS'), :pasttype('callmethod'),
$type_past,
Expand All @@ -1186,17 +1186,25 @@ method parameter($/) {
$thunk := PAST::Block.new($thunk, :blocktype('declaration'));
@?BLOCK[0].push($thunk);
$type_past := PAST::Val.new( :value($thunk) );
$typelist.push( $type_past );
$var<cons_type> := PAST::Op.new( :name('all'), :pasttype('call'), $type_past );
}
}
elsif $type_past.isa(PAST::Op) && $type_past.name() eq 'infix:,' {
# It's a literal value - implies both a nominal type and constraint type.
$var<nom_type> := $type_past[0];
$var<cons_type> := PAST::Op.new( :name('all'), :pasttype('call'), $type_past[1] );
}
else {
$typelist.push( $type_past );
$var<nom_type> := $type_past;
}
}
}
if $<post_constraint> {
unless $var<cons_type> {
$var<cons_type> := PAST::Op.new( :name('all'), :pasttype('call') );
}
for @($<post_constraint>) {
$typelist.push($_.ast);
$var<cons_type>.push($_.ast);
}
}

Expand Down Expand Up @@ -1707,11 +1715,8 @@ method scope_declarator($/) {
if $scope eq 'package' { $var.lvalue(1); }
my $init_value := $var.viviself();
my $type;
if +@($var<type>) == 1 {
$type := $var<type>[0];
}
elsif +@($var<type>) > 1 {
$/.panic("Multiple prefix constraints not yet supported");
if $var<nom_type> {
$type := $var<nom_type>;
}

# If the var has a '.' twigil, we need to create an
Expand Down Expand Up @@ -1960,9 +1965,11 @@ method scoped($/) {
elsif $<multi_declarator> {
$past := $<multi_declarator>.ast;
if $past.isa(PAST::Var) {
my $type := $past<type>;
for @($<fulltypename>) {
$type.push( $_.ast );
if +@($<fulltypename>) == 1 {
$past<nom_type> := $<fulltypename>[0].ast;
}
else {
$/.panic("Multiple prefix constraints are not yet supported");
}
if $past<sigil> eq '$' {
# Scalars auto-vivify to the proto of their type.
Expand Down Expand Up @@ -2015,7 +2022,6 @@ method variable_declarator($/) {
}
else {
$var.isdecl(1);
$var<type> := PAST::Op.new( :name('and'), :pasttype('call') );
$var<itype> := container_itype($<variable><sigil>);
$var<traitlist> := $<trait>;
}
Expand All @@ -2031,7 +2037,6 @@ method constant_declarator($/) {
:scope('lexical'),
);
$past<itype> := container_itype('Perl6Scalar');
$past<type> := PAST::Op.new( :name('and'), :pasttype('call') );
$/.add_type(~$<identifier>);
@?BLOCK[0].symbol(~$<identifier>, :scope('lexical'));
make $past;
Expand Down
15 changes: 9 additions & 6 deletions src/parser/signature.pm
Expand Up @@ -17,9 +17,8 @@ class Perl6::Compiler::Signature;

# Adds a parameter to the signature.
# - var_name is the name of the lexical that we bind to, if any
# - types is a list of the types, including constraints, that we take
# (for now, and for historical reasons, an all junction, but this
# may change)
# - nom_type is the main, nominal type of the parameter
# - cons_type is (at least for now) a junction of other type constraints
# - type_captures is a list of any lexical type names bound to the type of
# the incoming parameter
# - optional sets if the parameter is optional
Expand Down Expand Up @@ -116,9 +115,13 @@ method ast($high_level?) {
if $_<slurpy> { $add_param.push(PAST::Val.new( :value(1), :named('slurpy') )); }
if $_<invocant> { $add_param.push(PAST::Val.new( :value(1), :named('invocant') )); }
if $_<multi_invocant> eq "0" { $add_param.push(PAST::Val.new( :value(0), :named('multi_invocant') )); }
if $_<types> && +@($_<types>) && !$_<slurpy> {
$_<types>.named('type');
$add_param.push($_<types>);
if $_<nom_type> && !$_<slurpy> {
$_<nom_type>.named('nom_type');
$add_param.push($_<nom_type>);
}
if $_<cons_type> {
$_<cons_type>.named('cons_type');
$add_param.push($_<cons_type>);
}
if $_<read_type> {
$add_param.push(PAST::Val.new( :value(~$_<read_type>), :named('readtype') ));
Expand Down

0 comments on commit cf8884d

Please sign in to comment.