@@ -1207,6 +1207,13 @@ def expr_variable(tree, location, scope):
12071207 if in_dev_tree :
12081208 e = in_dev_tree
12091209 if e is None :
1210+ # TODO/HACK: The discard ref is exposed like this to allow it to be as
1211+ # keyword-like as possible while still allowing it to be shadowed.
1212+ # Once we remove support for discard_ref_shadowing the discard ref
1213+ # should become a proper keyword and its codegen be done via dedicated
1214+ # dispatch
1215+ if name == '_' and tree .site .dml_version () != (1 , 2 ):
1216+ return mkDiscardRef (tree .site )
12101217 raise EIDENT (tree .site , name )
12111218 return e
12121219
@@ -2340,14 +2347,25 @@ def try_codegen_invocation(site, init_ast, outargs, location, scope):
23402347 else :
23412348 return common_inline (site , meth_node , indices , inargs , outargs )
23422349
2350+ def codegen_src_for_nonvalue_target (site , tgt , src_ast , location , scope ):
2351+ if not tgt .writable :
2352+ raise EASSIGN (site , tgt )
2353+ if src_ast .kind != 'initializer_scalar' :
2354+ raise EDATAINIT (tgt .site ,
2355+ f'{ tgt } can only be used as the target '
2356+ + 'of an assignment if its initializer is a '
2357+ + 'simple expression or a return value of a '
2358+ + 'method call' )
2359+ return codegen_expression (src_ast .args [0 ], location , scope )
2360+
23432361@statement_dispatcher
23442362def stmt_assign (stmt , location , scope ):
23452363 (_ , site , tgt_ast , src_asts ) = stmt
23462364 assert tgt_ast .kind in ('assign_target_chain' , 'assign_target_tuple' )
2347- tgts = [codegen_expression (ast , location , scope )
2365+ tgts = [codegen_expression_maybe_nonvalue (ast , location , scope )
23482366 for ast in tgt_ast .args [0 ]]
23492367 for tgt in tgts :
2350- if deep_const (tgt .ctype ()):
2368+ if not isinstance ( tgt , NonValue ) and deep_const (tgt .ctype ()):
23512369 raise ECONST (tgt .site )
23522370 if tgt_ast .kind == 'assign_target_chain' :
23532371 method_tgts = [tgts [0 ]]
@@ -2369,14 +2387,21 @@ def stmt_assign(stmt, location, scope):
23692387 + f'initializer: Expected { src_asts } , got 1' ))
23702388 return []
23712389
2372- lscope = Symtab (scope )
2390+ if isinstance (tgts [- 1 ], NonValue ):
2391+ if len (tgts ) != 1 :
2392+ raise tgts [- 1 ].exc ()
2393+ expr = codegen_src_for_nonvalue_target (site , tgts [0 ], src_asts [0 ],
2394+ location , scope )
2395+ return [mkCopyData (site , expr , tgts [0 ])]
2396+
23732397 init_typ = tgts [- 1 ].ctype ()
23742398 init = eval_initializer (
23752399 tgts [- 1 ].site , init_typ , src_asts [0 ], location , scope , False )
23762400
23772401 if len (tgts ) == 1 :
23782402 return [mkAssignStatement (tgts [0 ].site , tgts [0 ], init )]
23792403
2404+ lscope = Symtab (scope )
23802405 sym = lscope .add_variable (
23812406 'tmp' , type = init_typ , site = init .site , init = init ,
23822407 stmt = True )
@@ -2405,22 +2430,27 @@ def stmt_assign(stmt, location, scope):
24052430
24062431 stmts = []
24072432 lscope = Symtab (scope )
2408- syms = []
2433+ stmt_pairs = []
24092434 for (i , (tgt , src_ast )) in enumerate (zip (tgts , src_asts )):
2410- init = eval_initializer (site , tgt .ctype (), src_ast , location ,
2411- scope , False )
2412- name = 'tmp%d' % (i ,)
2413- sym = lscope .add_variable (
2414- name , type = tgt .ctype (), site = tgt .site , init = init ,
2415- stmt = True )
2416- syms .append (sym )
2417-
2418- stmts .extend (sym_declaration (sym ) for sym in syms )
2419- stmts .extend (
2420- AssignStatement (
2421- tgt .site , tgt ,
2422- ExpressionInitializer (mkLocalVariable (tgt .site , sym )))
2423- for (tgt , sym ) in zip (tgts , syms ))
2435+ if isinstance (tgt , NonValue ):
2436+ expr = codegen_src_for_nonvalue_target (site , tgt , src_ast ,
2437+ location , scope )
2438+ stmt_pairs .append ((mkCopyData (tgt .site , expr , tgt ), None ))
2439+ else :
2440+ init = eval_initializer (site , tgt .ctype (), src_ast , location ,
2441+ scope , False )
2442+ name = 'tmp%d' % (i ,)
2443+ sym = lscope .add_variable (
2444+ name , type = tgt .ctype (), site = tgt .site , init = init ,
2445+ stmt = True )
2446+ write = AssignStatement (
2447+ tgt .site , tgt ,
2448+ ExpressionInitializer (mkLocalVariable (tgt .site , sym )))
2449+ stmt_pairs .append ((sym_declaration (sym ), write ))
2450+
2451+ stmts .extend (first for (first , _ ) in stmt_pairs )
2452+ stmts .extend (second for (_ , second ) in stmt_pairs
2453+ if second is not None )
24242454 return [mkCompound (site , stmts )]
24252455
24262456@statement_dispatcher
@@ -3615,7 +3645,7 @@ def codegen_inline(site, meth_node, indices, inargs, outargs,
36153645 parmtype if parmtype else arg .ctype (),
36163646 meth_node .name )
36173647 for (arg , var , (parmname , parmtype )) in zip (
3618- outargs , outvars , meth_node .outp )]
3648+ outargs , outvars , meth_node .outp )]
36193649 exit_handler = GotoExit_dml12 ()
36203650 with exit_handler :
36213651 code = [codegen_statement (meth_node .astcode ,
@@ -4039,15 +4069,20 @@ def copy_outarg(arg, var, parmname, parmtype, method_name):
40394069 an exception. We would be able to skip the proxy variable for
40404070 calls to non-throwing methods when arg.ctype() and parmtype are
40414071 equivalent types, but we don't do this today.'''
4042- argtype = arg .ctype ()
4043-
4044- if not argtype :
4045- raise ICE (arg .site , "unknown expression type" )
4072+ if isinstance (arg , NonValue ):
4073+ if not arg .writable :
4074+ raise arg .exc ()
40464075 else :
4047- ok , trunc , constviol = realtype (parmtype ).canstore (realtype (argtype ))
4048- if not ok :
4049- raise EARGT (arg .site , 'call' , method_name ,
4050- arg .ctype (), parmname , parmtype , 'output' )
4076+ argtype = arg .ctype ()
4077+
4078+ if not argtype :
4079+ raise ICE (arg .site , "unknown expression type" )
4080+ else :
4081+ ok , trunc , constviol = realtype (parmtype ).canstore (
4082+ realtype (argtype ))
4083+ if not ok :
4084+ raise EARGT (arg .site , 'call' , method_name ,
4085+ arg .ctype (), parmname , parmtype , 'output' )
40514086
40524087 return mkCopyData (var .site , var , arg )
40534088
0 commit comments