Skip to content

Commit

Permalink
RakuAST: detect illegal postdeclaration of dynamic variables
Browse files Browse the repository at this point in the history
Makes `say $*a; my $*a` fail the way it should.
  • Loading branch information
niner committed Apr 23, 2023
1 parent e1c49a4 commit 7ca567b
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Raku/ast/code.rakumod
Expand Up @@ -909,6 +909,7 @@ class RakuAST::Block

method clear-attachments() {
self.clear-handler-attachments();
self.clear-used-dynamic-variables();
self.clear-placeholder-attachments();
self.clear-phaser-attachments();
Nil
Expand Down Expand Up @@ -1350,6 +1351,7 @@ class RakuAST::Routine

method clear-attachments() {
self.clear-handler-attachments();
self.clear-used-dynamic-variables();
self.clear-placeholder-attachments();
self.clear-phaser-attachments();
Nil
Expand Down
1 change: 1 addition & 0 deletions src/Raku/ast/compunit.rakumod
Expand Up @@ -158,6 +158,7 @@ class RakuAST::CompUnit
nqp::setelems($!init-phasers, 0);
nqp::setelems($!end-phasers, 0);
self.clear-handler-attachments();
self.clear-used-dynamic-variables();
Nil
}

Expand Down
18 changes: 18 additions & 0 deletions src/Raku/ast/scoping.rakumod
Expand Up @@ -17,6 +17,8 @@ class RakuAST::LexicalScope
has Mu $!catch-handlers;
has Mu $!control-handlers;

has Hash $!used-dynamic-variables;

method IMPL-QAST-DECLS(RakuAST::IMPL::QASTContext $context) {
my $stmts := QAST::Stmts.new();

Expand Down Expand Up @@ -237,6 +239,22 @@ class RakuAST::LexicalScope
Nil
}

method add-used-dynamic-variable(RakuAST::Var::Dynamic $var) {
unless nqp::isconcrete($!used-dynamic-variables) {
nqp::bindattr(self, RakuAST::LexicalScope, '$!used-dynamic-variables', {});
}
$!used-dynamic-variables{$var.name} := $var;
}

method clear-used-dynamic-variables() {
nqp::bindattr(self, RakuAST::LexicalScope, '$!used-dynamic-variables', {});
}

method uses-dynamic-variable(str $name) {
nqp::isconcrete($!used-dynamic-variables)
&& nqp::existskey($!used-dynamic-variables, $name)
}

method IMPL-WRAP-SCOPE-HANDLER-QAST(RakuAST::IMPL::QASTContext $context, Mu $statements,
Bool :$is-handler) {
# If it's an exception handler, add rethrow logic.
Expand Down
5 changes: 5 additions & 0 deletions src/Raku/ast/variable-access.rakumod
Expand Up @@ -88,6 +88,7 @@ class RakuAST::Var::Lexical::Setting
class RakuAST::Var::Dynamic
is RakuAST::Var
is RakuAST::Lookup
is RakuAST::Attaching
{
has str $.name;

Expand All @@ -111,6 +112,10 @@ class RakuAST::Var::Dynamic
Nil
}

method attach(RakuAST::Resolver $resolver) {
$resolver.current-scope.add-used-dynamic-variable(self);
}

method IMPL-EXPR-QAST(RakuAST::IMPL::QASTContext $context) {
# If it's resolved in the current scope, just a lexical access.
if self.is-resolved {
Expand Down
13 changes: 13 additions & 0 deletions src/Raku/ast/variable-declaration.rakumod
Expand Up @@ -405,6 +405,7 @@ class RakuAST::VarDeclaration::Simple
is RakuAST::Meta
is RakuAST::Attaching
is RakuAST::BeginTime
is RakuAST::CheckTime
is RakuAST::Term
is RakuAST::Doc::DeclaratorTarget
{
Expand All @@ -417,6 +418,7 @@ class RakuAST::VarDeclaration::Simple
has RakuAST::SemiList $.shape;
has RakuAST::Package $!attribute-package;
has RakuAST::Method $!accessor;
has Bool $!is-illegal-postdeclaration;

has Mu $!container-initializer;
has Mu $!package;
Expand Down Expand Up @@ -532,6 +534,11 @@ class RakuAST::VarDeclaration::Simple
nqp::bindattr(self, RakuAST::VarDeclaration::Simple, '$!package',
$package);
}

nqp::bindattr(self, RakuAST::VarDeclaration::Simple, '$!is-illegal-postdeclaration', False);
if self.twigil eq '*' && $resolver.current-scope.uses-dynamic-variable(self.name) {
nqp::bindattr(self, RakuAST::VarDeclaration::Simple, '$!is-illegal-postdeclaration', True);
}
}

method PERFORM-BEGIN(RakuAST::Resolver $resolver, RakuAST::IMPL::QASTContext $context) {
Expand Down Expand Up @@ -660,6 +667,12 @@ class RakuAST::VarDeclaration::Simple
}
}

method PERFORM-CHECK(RakuAST::Resolver $resolver, RakuAST::IMPL::QASTContext $context) {
self.add-sorry: $resolver.build-exception:
'X::Dynamic::Postdeclaration', :symbol(self.name)
if $!is-illegal-postdeclaration;
}

method PRODUCE-IMPLICIT-LOOKUPS() {
my @lookups;
my str $scope := self.scope;
Expand Down

0 comments on commit 7ca567b

Please sign in to comment.