@@ -1222,6 +1222,13 @@ def expr_variable(tree, location, scope):
12221222 if in_dev_tree :
12231223 e = in_dev_tree
12241224 if e is None :
1225+ # TODO/HACK: The discard ref is exposed like this to allow it to be as
1226+ # keyword-like as possible while still allowing it to be shadowed.
1227+ # Once we remove support for discard_ref_shadowing the discard ref
1228+ # should become a proper keyword and its codegen be done via dedicated
1229+ # dispatch
1230+ if name == '_' and tree .site .dml_version () != (1 , 2 ):
1231+ return mkDiscardRef (tree .site )
12251232 raise EIDENT (tree .site , name )
12261233 return e
12271234
@@ -2331,14 +2338,25 @@ def try_codegen_invocation(site, init_ast, outargs, location, scope):
23312338 else :
23322339 return common_inline (site , meth_node , indices , inargs , outargs )
23332340
2341+ def codegen_src_for_nonvalue_target (site , tgt , src_ast , location , scope ):
2342+ if not tgt .writable :
2343+ raise EASSIGN (site , tgt )
2344+ if src_ast .kind != 'initializer_scalar' :
2345+ raise EDATAINIT (tgt .site ,
2346+ f'{ tgt } can only be used as the target '
2347+ + 'of an assignment if its initializer is a '
2348+ + 'simple expression or a return value of a '
2349+ + 'method call' )
2350+ return codegen_expression (src_ast .args [0 ], location , scope )
2351+
23342352@statement_dispatcher
23352353def stmt_assign (stmt , location , scope ):
23362354 (_ , site , tgt_ast , src_asts ) = stmt
23372355 assert tgt_ast .kind in {'assign_target_chain' , 'assign_target_tuple' }
2338- tgts = [codegen_expression (ast , location , scope )
2356+ tgts = [codegen_expression_maybe_nonvalue (ast , location , scope )
23392357 for ast in tgt_ast .args [0 ]]
23402358 for tgt in tgts :
2341- if deep_const (tgt .ctype ()):
2359+ if not isinstance ( tgt , NonValue ) and deep_const (tgt .ctype ()):
23422360 raise ECONST (tgt .site )
23432361 if tgt_ast .kind == 'assign_target_chain' :
23442362 method_tgts = [tgts [0 ]]
@@ -2360,14 +2378,21 @@ def stmt_assign(stmt, location, scope):
23602378 + f'initializer: Expected { src_asts } , got 1' ))
23612379 return []
23622380
2363- lscope = Symtab (scope )
2381+ if isinstance (tgts [- 1 ], NonValue ):
2382+ if len (tgts ) != 1 :
2383+ raise tgts [- 1 ].exc ()
2384+ expr = codegen_src_for_nonvalue_target (site , tgts [0 ], src_asts [0 ],
2385+ location , scope )
2386+ return [mkCopyData (site , expr , tgts [0 ])]
2387+
23642388 init_typ = tgts [- 1 ].ctype ()
23652389 init = eval_initializer (
23662390 tgts [- 1 ].site , init_typ , src_asts [0 ], location , scope , False )
23672391
23682392 if len (tgts ) == 1 :
23692393 return [mkAssignStatement (tgts [0 ].site , tgts [0 ], init )]
23702394
2395+ lscope = Symtab (scope )
23712396 sym = lscope .add_variable (
23722397 'tmp' , type = init_typ , site = init .site , init = init ,
23732398 stmt = True )
@@ -2396,22 +2421,27 @@ def stmt_assign(stmt, location, scope):
23962421
23972422 stmts = []
23982423 lscope = Symtab (scope )
2399- syms = []
2424+ stmt_pairs = []
24002425 for (i , (tgt , src_ast )) in enumerate (zip (tgts , src_asts )):
2401- init = eval_initializer (site , tgt .ctype (), src_ast , location ,
2402- scope , False )
2403- name = 'tmp%d' % (i ,)
2404- sym = lscope .add_variable (
2405- name , type = tgt .ctype (), site = tgt .site , init = init ,
2406- stmt = True )
2407- syms .append (sym )
2408-
2409- stmts .extend (sym_declaration (sym ) for sym in syms )
2410- stmts .extend (
2411- AssignStatement (
2412- tgt .site , tgt ,
2413- ExpressionInitializer (mkLocalVariable (tgt .site , sym )))
2414- for (tgt , sym ) in zip (tgts , syms ))
2426+ if isinstance (tgt , NonValue ):
2427+ expr = codegen_src_for_nonvalue_target (site , tgt , src_ast ,
2428+ location , scope )
2429+ stmt_pairs .append ((mkCopyData (tgt .site , expr , tgt ), None ))
2430+ else :
2431+ init = eval_initializer (site , tgt .ctype (), src_ast , location ,
2432+ scope , False )
2433+ name = 'tmp%d' % (i ,)
2434+ sym = lscope .add_variable (
2435+ name , type = tgt .ctype (), site = tgt .site , init = init ,
2436+ stmt = True )
2437+ write = AssignStatement (
2438+ tgt .site , tgt ,
2439+ ExpressionInitializer (mkLocalVariable (tgt .site , sym )))
2440+ stmt_pairs .append ((sym_declaration (sym ), write ))
2441+
2442+ stmts .extend (first for (first , _ ) in stmt_pairs )
2443+ stmts .extend (second for (_ , second ) in stmt_pairs
2444+ if second is not None )
24152445 return [mkCompound (site , stmts )]
24162446
24172447@statement_dispatcher
@@ -3633,7 +3663,7 @@ def codegen_inline(site, meth_node, indices, inargs, outargs,
36333663 parmtype if parmtype else arg .ctype (),
36343664 meth_node .name )
36353665 for (arg , var , (parmname , parmtype )) in zip (
3636- outargs , outvars , meth_node .outp )]
3666+ outargs , outvars , meth_node .outp )]
36373667 exit_handler = GotoExit_dml12 ()
36383668 with exit_handler :
36393669 code = [codegen_statement (meth_node .astcode ,
@@ -4063,15 +4093,20 @@ def copy_outarg(arg, var, parmname, parmtype, method_name):
40634093 an exception. We would be able to skip the proxy variable for
40644094 calls to non-throwing methods when arg.ctype() and parmtype are
40654095 equivalent types, but we don't do this today.'''
4066- argtype = arg .ctype ()
4067-
4068- if not argtype :
4069- raise ICE (arg .site , "unknown expression type" )
4096+ if isinstance (arg , NonValue ):
4097+ if not arg .writable :
4098+ raise arg .exc ()
40704099 else :
4071- ok , trunc , constviol = realtype (parmtype ).canstore (realtype (argtype ))
4072- if not ok :
4073- raise EARGT (arg .site , 'call' , method_name ,
4074- arg .ctype (), parmname , parmtype , 'output' )
4100+ argtype = arg .ctype ()
4101+
4102+ if not argtype :
4103+ raise ICE (arg .site , "unknown expression type" )
4104+ else :
4105+ ok , trunc , constviol = realtype (parmtype ).canstore (
4106+ realtype (argtype ))
4107+ if not ok :
4108+ raise EARGT (arg .site , 'call' , method_name ,
4109+ arg .ctype (), parmname , parmtype , 'output' )
40754110
40764111 return mkCopyData (var .site , var , arg )
40774112
0 commit comments