@@ -510,6 +510,8 @@ def execute(symtab); end
510510 def execute_unknown ( symtab ) ; end
511511 end
512512
513+ ExecutableAst = T . type_alias { T . all ( Executable , AstNode ) }
514+
513515 # interface for nodes that *might* return a value in a function body
514516 module Returns
515517 extend T ::Sig
@@ -1998,8 +2000,11 @@ def const_eval?(symtab)
19982000 end
19992001 end
20002002
2001- def lhs = @children [ 0 ]
2002- def rhs = @children [ 1 ]
2003+ sig { returns ( IdAst ) }
2004+ def lhs = T . cast ( @children . fetch ( 0 ) , IdAst )
2005+
2006+ sig { returns ( RvalueAst ) }
2007+ def rhs = T . cast ( @children . fetch ( 1 ) , RvalueAst )
20032008
20042009 def initialize ( input , interval , lhs_ast , rhs_ast )
20052010 super ( input , interval , [ lhs_ast , rhs_ast ] )
@@ -2009,9 +2014,14 @@ def initialize(input, interval, lhs_ast, rhs_ast)
20092014 # @!macro type_check
20102015 def type_check ( symtab )
20112016 lhs . type_check ( symtab )
2012- type_error "Cannot assign to a const" if lhs . type ( symtab ) . const?
2017+ lhs_var = symtab . get ( lhs . name )
2018+ type_error "Cannot assign to a const" if lhs_var . type . const? && !lhs_var . for_loop_iter?
20132019
20142020 rhs . type_check ( symtab )
2021+ if lhs_var . type . const? && lhs_var . for_loop_iter?
2022+ # also check that the rhs is const_eval
2023+ type_error "Assignment would make iteration variable non-const" unless rhs . type ( symtab ) . const?
2024+ end
20152025 unless rhs . type ( symtab ) . convertable_to? ( lhs . type ( symtab ) )
20162026 type_error "Incompatible type in assignment (#{ lhs . type ( symtab ) } , #{ rhs . type ( symtab ) } )"
20172027 end
@@ -2806,7 +2816,19 @@ def to_ast
28062816 ary_size_ast = send ( :ary_size ) . empty? ? nil : send ( :ary_size ) . expression . to_ast
28072817 VariableDeclarationWithInitializationAst . new (
28082818 input , interval ,
2809- send ( :type_name ) . to_ast , send ( :id ) . to_ast , ary_size_ast , send ( :rval ) . to_ast
2819+ send ( :type_name ) . to_ast , send ( :id ) . to_ast , ary_size_ast , send ( :rval ) . to_ast ,
2820+ false
2821+ )
2822+ end
2823+ end
2824+
2825+ class ForLoopIterationVariableDeclarationSyntaxNode < SyntaxNode
2826+ def to_ast
2827+ ary_size_ast = send ( :ary_size ) . empty? ? nil : send ( :ary_size ) . expression . to_ast
2828+ VariableDeclarationWithInitializationAst . new (
2829+ input , interval ,
2830+ send ( :type_name ) . to_ast , send ( :id ) . to_ast , ary_size_ast , send ( :rval ) . to_ast ,
2831+ true
28102832 )
28112833 end
28122834 end
@@ -2854,16 +2876,18 @@ def id = lhs.text_value
28542876 type_name_ast : TypeNameAst ,
28552877 var_write_ast : IdAst ,
28562878 ary_size : T . nilable ( RvalueAst ) ,
2857- rval_ast : RvalueAst
2879+ rval_ast : RvalueAst ,
2880+ is_for_loop_iteration_var : T ::Boolean
28582881 ) . void
28592882 }
2860- def initialize ( input , interval , type_name_ast , var_write_ast , ary_size , rval_ast )
2883+ def initialize ( input , interval , type_name_ast , var_write_ast , ary_size , rval_ast , is_for_loop_iteration_var )
28612884 if ary_size . nil?
28622885 super ( input , interval , [ type_name_ast , var_write_ast , rval_ast ] )
28632886 else
28642887 super ( input , interval , [ type_name_ast , var_write_ast , rval_ast , ary_size ] )
28652888 end
28662889 @global = false
2890+ @for_iter_var = is_for_loop_iteration_var
28672891 end
28682892
28692893 def make_global
@@ -2909,16 +2933,16 @@ def type_check(symtab)
29092933 if decl_type . const?
29102934 # this is a constant; ensure we are assigning a constant value
29112935 value_result = value_try do
2912- symtab . add ( lhs . text_value , Var . new ( lhs . text_value , decl_type . clone , rhs . value ( symtab ) ) )
2936+ symtab . add ( lhs . text_value , Var . new ( lhs . text_value , decl_type . clone , rhs . value ( symtab ) , for_loop_iter : @for_iter_var ) )
29132937 end
29142938 value_else ( value_result ) do
29152939 unless rhs . type ( symtab ) . const?
29162940 type_error "Declaring constant (#{ lhs . name } ) with a non-constant value (#{ rhs . text_value } )"
29172941 end
2918- symtab . add ( lhs . text_value , Var . new ( lhs . text_value , decl_type . clone ) )
2942+ symtab . add ( lhs . text_value , Var . new ( lhs . text_value , decl_type . clone , for_loop_iter : @for_iter_var ) )
29192943 end
29202944 else
2921- symtab . add ( lhs . text_value , Var . new ( lhs . text_value , decl_type . clone ) )
2945+ symtab . add ( lhs . text_value , Var . new ( lhs . text_value , decl_type . clone , for_loop_iter : @for_iter_var ) )
29222946 end
29232947
29242948 lhs . type_check ( symtab )
@@ -2935,21 +2959,21 @@ def add_symbol(symtab)
29352959 if lhs . text_value [ 0 ] == T . must ( lhs . text_value [ 0 ] ) . upcase
29362960 # const, add the value if it's known
29372961 value_result = value_try do
2938- symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , rhs . value ( symtab ) ) )
2962+ symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , rhs . value ( symtab ) , for_loop_iter : @for_iter_var ) )
29392963 end
29402964 value_else ( value_result ) do
2941- symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) ) )
2965+ symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , for_loop_iter : @for_iter_var ) )
29422966 end
29432967 else
29442968 # mutable globals never have a compile-time value
2945- symtab . add! ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) ) )
2969+ symtab . add! ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , for_loop_iter : @for_iter_var ) )
29462970 end
29472971 else
29482972 value_result = value_try do
2949- symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , rhs . value ( symtab ) ) )
2973+ symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , rhs . value ( symtab ) , for_loop_iter : @for_iter_var ) )
29502974 end
29512975 value_else ( value_result ) do
2952- symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) ) )
2976+ symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , for_loop_iter : @for_iter_var ) )
29532977 end
29542978 end
29552979 end
@@ -2964,15 +2988,15 @@ def execute(symtab)
29642988 rhs_value = rhs . value ( symtab )
29652989 end
29662990 value_else ( value_result ) do
2967- symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , nil ) )
2991+ symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , nil , for_loop_iter : @for_iter_var ) )
29682992 value_error "value of right-hand side of variable initialization is unknown"
29692993 end
29702994 symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , rhs_value ) )
29712995 end
29722996
29732997 # @!macro execute_unknown
29742998 def execute_unknown ( symtab )
2975- symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , nil ) )
2999+ symtab . add ( lhs . text_value , Var . new ( lhs . text_value , lhs_type ( symtab ) , nil , for_loop_iter : @for_iter_var ) )
29763000 end
29773001
29783002 # @!macro to_idl
@@ -3364,7 +3388,7 @@ def type_check(symtab)
33643388 lhs_type = lhs . type ( symtab )
33653389 type_error "Unsupported type for left shift: #{ lhs_type } " unless lhs_type . kind == :bits
33663390 type_error "Unsupported shift for left shift: #{ rhs_type } " unless rhs_type . kind == :bits
3367- type_error "Widening shift amount must be constant" unless rhs_type . const?
3391+ type_error "Widening shift amount must be constant (if it's not, the width of the result is unknowable). " unless rhs_type . const?
33683392 elsif [ ">>" , ">>>" ] . include? ( op )
33693393 rhs_type = rhs . type ( symtab )
33703394 lhs_type = lhs . type ( symtab )
@@ -4149,14 +4173,18 @@ class PostDecrementExpressionAst < AstNode
41494173 sig { override . params ( symtab : SymbolTable ) . returns ( T ::Boolean ) }
41504174 def const_eval? ( symtab ) = rval . const_eval? ( symtab )
41514175
4152- def rval = @children [ 0 ]
4176+ sig { returns ( T . any ( IntLiteralAst , BuiltinVariableAst , StringLiteralAst , IdAst ) ) }
4177+ def rval = T . cast ( @children . fetch ( 0 ) , T . any ( IntLiteralAst , BuiltinVariableAst , StringLiteralAst , IdAst ) )
41534178
41544179 def initialize ( input , interval , rval )
41554180 super ( input , interval , [ rval ] )
41564181 end
41574182
41584183 def type_check ( symtab )
41594184 rval . type_check ( symtab )
4185+ rval_immutable =
4186+ rval . is_a? ( IdAst ) && ( rval . type ( symtab ) . const? && !symtab . get ( T . cast ( rval , IdAst ) . name ) . for_loop_iter? )
4187+ type_error "Cannot decrement a const variable" if rval_immutable
41604188 type_error "Post decement must be integral" unless rval . type ( symtab ) . integral?
41614189 end
41624190
@@ -4268,6 +4296,9 @@ def initialize(input, interval, rval)
42684296 def type_check ( symtab )
42694297 rval . type_check ( symtab )
42704298 var = symtab . get ( rval . text_value )
4299+ rval_immutable =
4300+ rval . is_a? ( IdAst ) && ( rval . type ( symtab ) . const? && !var . for_loop_iter? )
4301+ type_error "Cannot increment a const variable" if rval_immutable
42714302 type_error "Post increment variable must be integral" unless var . type . integral?
42724303 end
42734304
@@ -6482,7 +6513,7 @@ class ForLoopSyntaxNode < SyntaxNode
64826513 def to_ast
64836514 ForLoopAst . new (
64846515 input , interval ,
6485- send ( :single_declaration_with_initialization ) . to_ast ,
6516+ send ( :for_loop_iteration_variable_declaration ) . to_ast ,
64866517 send ( :condition ) . to_ast ,
64876518 send ( :action ) . to_ast ,
64886519 send ( :stmts ) . elements . map ( &:s ) . map ( &:to_ast )
@@ -6502,10 +6533,17 @@ def const_eval?(symtab)
65026533 stmts . all? { |stmt | stmt . const_eval? ( symtab ) }
65036534 end
65046535
6505- def init = @children [ 0 ]
6506- def condition = @children [ 1 ]
6507- def update = @children [ 2 ]
6508- def stmts = @children [ 3 ..]
6536+ sig { returns ( VariableDeclarationWithInitializationAst ) }
6537+ def init = T . cast ( @children . fetch ( 0 ) , VariableDeclarationWithInitializationAst )
6538+
6539+ sig { returns ( RvalueAst ) }
6540+ def condition = T . cast ( @children . fetch ( 1 ) , RvalueAst )
6541+
6542+ sig { returns ( ExecutableAst ) }
6543+ def update = T . cast ( @children . fetch ( 2 ) , ExecutableAst )
6544+
6545+ sig { returns ( T ::Array [ T . any ( StatementAst , ReturnStatementAst , IfAst , ForLoopAst ) ] ) }
6546+ def stmts = T . cast ( @children [ 3 ..] , T ::Array [ T . any ( StatementAst , ReturnStatementAst , IfAst , ForLoopAst ) ] )
65096547
65106548 def initialize ( input , interval , init , condition , update , stmts )
65116549 super ( input , interval , [ init , condition , update ] + stmts )
@@ -6615,7 +6653,9 @@ def execute_unknown(symtab)
66156653 init . execute_unknown ( symtab )
66166654
66176655 stmts . each do |s |
6618- s . execute_unknown ( symtab )
6656+ unless s . is_a? ( ReturnStatementAst )
6657+ s . execute_unknown ( symtab )
6658+ end
66196659 end
66206660 update . execute_unknown ( symtab )
66216661 end
0 commit comments