Repository navigation
Conversation
|
Shepherd (Phase A — propose only): this PR's changed-file set overlaps >=0.6 Jaccard with #106, which carries the larger take. Proposing close as superseded. This is a proposal, not a close — nothing auto-closes while this comment is fresh. If this PR has unique content (a different rule, extra tests, a different fix), say so or push, and the label comes off. Cluster signal is a file-set heuristic; the verdict stays human. |
…, receives, and range loops (Fixes limitlessprojects#753)
…, none rebind, and new(alias) (limitlessprojects#753)
536d5c5 to
1fa49e8
Compare
|
Queue-reset sweep: this repo now runs a rolling conveyor, and open PRs This is not a verdict on the work. If this change still matters:
Wildcard holds (verdict window 2026-11-01) and Pareto land candidates are |
Fixes #753
Summary
In
hy-check/src/shape.rs,shape_of_typefoldsoption[T](TypeExpr::Generic { name: "option", args: [T] }) toshape_of_type(T)somatchunwrap and payload classification can inspect the inner shape directly. However, several expression and type shape helpers returned that unwrappedTypeShapewhile discarding the outeroption[...]TypeExpr:option[T]:expr_is_option(shape.rs) did not handleExpr::Index,Expr::Deref/Unary(Deref),Expr::Field,Expr::Paren, orExpr::Move, and checkedTypeExprforms syntactically (is_option_type_expr) without resolving type aliases (type opt_ch = option[chan int]).ty_of_exprdid not synthesizeTypeExprforExpr::Indexon slices/arrays/maps,Expr::Derefon pointers,Expr::Receiveon channels, orExpr::Fieldon structs.multi_value_shapesandmulti_value_tysdid not handleExpr::Receive(opt, ok := <-ch) or comma-okExpr::Index(v, ok := m[k]).SelectRecv(select { opt := <-ch: ... }) andForKind::Iterate(for _, opt in xs) passedNoneastytodefine_binding, erasing the outeroption[...]wrapper on the bound variable.opt = noneoverwrote a specificb.ty(such asoption[option[chan int]]) withoption[any], erasing nestedoptionwrappers on subsequentmatchunwraps.xs[0],m["k"],*p,h.opt,get_alias(),<-ch,select { opt := <-ch: ... }, andfor _, opt in xsof typeoption[chan int]oropt_chwere treated as barechan int(HYB-E3007andHYB-E2008bypassed) and asSendable(HYB-E3001bypassed on&xs[0],p,&h.opt,&opt).option[T]:shape_of_typeforSlice,Array,Map,Chan, andPointerrecursively calledshape_of_typeon their element/pointee types, turning[]option[int]intoSlice(Primitive)(sendable),map[string]option[atomic.int64]intoMap(Atomic), and*option[atomic.int64]intoPointer(Atomic)(sendable!).call_shapefornew(opt_alias)resolvedopt_aliasvianamed_shapetoTypeShape::Atomic, typingnew(opt_atomic)as*atomic.int64(Pointer(Atomic), sendable) instead ofPointer(Struct(None)).struct_is_sendablechecked field shapes viashape_of_type(&f.ty)without checking whetherf.tyresolves tooption[...], allowing astructwith anoption[int]oroption[chan int]field to be shared acrosstaskspawn withoutmove(HYB-E3001bypassed).Root Cause & Fix
shape.rs(is_option_type_resolved,element_type_shape,expr_is_option,ty_of_expr,multi_value_tys,iterate_var_tys,struct_is_sendable,call_shape):Checker::is_option_type_resolvedto resolve type aliases inself.typeswhen checking foroption[T].Checker::element_type_shapesoSlice,Array,Map,Chan,Pointer,make(...), andnew(...)representoption[T]element/pointee types as non-sendableTypeShape::Struct(None)instead of collapsing toT's shape.struct_is_sendableto reject fields whose resolvedTypeExprisoption[T].ty_of_expr,multi_value_shapes,multi_value_tys,iterate_var_tys, andexpr_is_optionto preserve and inspectTypeExpracrossExpr::Index,Expr::Deref/Unary(Deref),Expr::Receive,Expr::Field,Expr::Paren,Expr::Move, and comma-ok multi-value forms.lib.rs,closures.rs,emit_guard.rs,loans.rs:TypeExprs inSelectRecvandForKind::Iteratebindings acrosslib.rs,closures.rs, andemit_guard.rs.option[...]TypeExprwhen reassigningopt = noneinloans::rebind_assign_targets.Verification
compiler/crates/hy-check/tests/recv_operand_soundness.rs.cargo test -p hy-check -p hy-emit -p hy-syntax -p hy-diag) passes with 0 failures.