@@ -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
@@ -2341,14 +2348,25 @@ def try_codegen_invocation(site, init_ast, outargs, location, scope):
23412348 else :
23422349 return common_inline (site , meth_node , indices , inargs , outargs )
23432350
2351+ def codegen_src_for_nonvalue_target (site , tgt , src_ast , location , scope ):
2352+ if not tgt .writable :
2353+ raise EASSIGN (site , tgt )
2354+ if src_ast .kind != 'initializer_scalar' :
2355+ raise EDATAINIT (tgt .site ,
2356+ f'{ tgt } can only be used as the target '
2357+ + 'of an assignment if its initializer is a '
2358+ + 'simple expression or a return value of a '
2359+ + 'method call' )
2360+ return codegen_expression (src_ast .args [0 ], location , scope )
2361+
23442362@statement_dispatcher
23452363def stmt_assign (stmt , location , scope ):
23462364 (_ , site , tgt_ast , src_asts ) = stmt
23472365 assert tgt_ast .kind in ('assign_target_chain' , 'assign_target_tuple' )
2348- tgts = [codegen_expression (ast , location , scope )
2366+ tgts = [codegen_expression_maybe_nonvalue (ast , location , scope )
23492367 for ast in tgt_ast .args [0 ]]
23502368 for tgt in tgts :
2351- if deep_const (tgt .ctype ()):
2369+ if not isinstance ( tgt , NonValue ) and deep_const (tgt .ctype ()):
23522370 raise ECONST (tgt .site )
23532371 if tgt_ast .kind == 'assign_target_chain' :
23542372 method_tgts = [tgts [0 ]]
@@ -2370,14 +2388,21 @@ def stmt_assign(stmt, location, scope):
23702388 + f'initializer: Expected { src_asts } , got 1' ))
23712389 return []
23722390
2373- lscope = Symtab (scope )
2391+ if isinstance (tgts [- 1 ], NonValue ):
2392+ if len (tgts ) != 1 :
2393+ raise tgts [- 1 ].exc ()
2394+ expr = codegen_src_for_nonvalue_target (site , tgts [0 ], src_asts [0 ],
2395+ location , scope )
2396+ return [mkCopyData (site , expr , tgts [0 ])]
2397+
23742398 init_typ = tgts [- 1 ].ctype ()
23752399 init = eval_initializer (
23762400 tgts [- 1 ].site , init_typ , src_asts [0 ], location , scope , False )
23772401
23782402 if len (tgts ) == 1 :
23792403 return [mkAssignStatement (tgts [0 ].site , tgts [0 ], init )]
23802404
2405+ lscope = Symtab (scope )
23812406 sym = lscope .add_variable (
23822407 'tmp' , type = init_typ , site = init .site , init = init ,
23832408 stmt = True )
@@ -2406,22 +2431,27 @@ def stmt_assign(stmt, location, scope):
24062431
24072432 stmts = []
24082433 lscope = Symtab (scope )
2409- syms = []
2434+ stmt_pairs = []
24102435 for (i , (tgt , src_ast )) in enumerate (zip (tgts , src_asts )):
2411- init = eval_initializer (site , tgt .ctype (), src_ast , location ,
2412- scope , False )
2413- name = 'tmp%d' % (i ,)
2414- sym = lscope .add_variable (
2415- name , type = tgt .ctype (), site = tgt .site , init = init ,
2416- stmt = True )
2417- syms .append (sym )
2418-
2419- stmts .extend (sym_declaration (sym ) for sym in syms )
2420- stmts .extend (
2421- AssignStatement (
2422- tgt .site , tgt ,
2423- ExpressionInitializer (mkLocalVariable (tgt .site , sym )))
2424- for (tgt , sym ) in zip (tgts , syms ))
2436+ if isinstance (tgt , NonValue ):
2437+ expr = codegen_src_for_nonvalue_target (site , tgt , src_ast ,
2438+ location , scope )
2439+ stmt_pairs .append ((mkCopyData (tgt .site , expr , tgt ), None ))
2440+ else :
2441+ init = eval_initializer (site , tgt .ctype (), src_ast , location ,
2442+ scope , False )
2443+ name = 'tmp%d' % (i ,)
2444+ sym = lscope .add_variable (
2445+ name , type = tgt .ctype (), site = tgt .site , init = init ,
2446+ stmt = True )
2447+ write = AssignStatement (
2448+ tgt .site , tgt ,
2449+ ExpressionInitializer (mkLocalVariable (tgt .site , sym )))
2450+ stmt_pairs .append ((sym_declaration (sym ), write ))
2451+
2452+ stmts .extend (first for (first , _ ) in stmt_pairs )
2453+ stmts .extend (second for (_ , second ) in stmt_pairs
2454+ if second is not None )
24252455 return [mkCompound (site , stmts )]
24262456
24272457@statement_dispatcher
@@ -3616,7 +3646,7 @@ def codegen_inline(site, meth_node, indices, inargs, outargs,
36163646 parmtype if parmtype else arg .ctype (),
36173647 meth_node .name )
36183648 for (arg , var , (parmname , parmtype )) in zip (
3619- outargs , outvars , meth_node .outp )]
3649+ outargs , outvars , meth_node .outp )]
36203650 exit_handler = GotoExit_dml12 ()
36213651 with exit_handler :
36223652 code = [codegen_statement (meth_node .astcode ,
@@ -4040,15 +4070,20 @@ def copy_outarg(arg, var, parmname, parmtype, method_name):
40404070 an exception. We would be able to skip the proxy variable for
40414071 calls to non-throwing methods when arg.ctype() and parmtype are
40424072 equivalent types, but we don't do this today.'''
4043- argtype = arg .ctype ()
4044-
4045- if not argtype :
4046- raise ICE (arg .site , "unknown expression type" )
4073+ if isinstance (arg , NonValue ):
4074+ if not arg .writable :
4075+ raise arg .exc ()
40474076 else :
4048- ok , trunc , constviol = realtype (parmtype ).canstore (realtype (argtype ))
4049- if not ok :
4050- raise EARGT (arg .site , 'call' , method_name ,
4051- arg .ctype (), parmname , parmtype , 'output' )
4077+ argtype = arg .ctype ()
4078+
4079+ if not argtype :
4080+ raise ICE (arg .site , "unknown expression type" )
4081+ else :
4082+ ok , trunc , constviol = realtype (parmtype ).canstore (
4083+ realtype (argtype ))
4084+ if not ok :
4085+ raise EARGT (arg .site , 'call' , method_name ,
4086+ arg .ctype (), parmname , parmtype , 'output' )
40524087
40534088 return mkCopyData (var .site , var , arg )
40544089
0 commit comments