@@ -165,7 +165,7 @@ async fn extract_with(ctx: &DiscoverCtx<'_>, out: &mut Discovery, workspaces: bo
165165 . any ( |e| e. owner == Some ( ReplaceOwner :: Hosted ) ) ;
166166 let mut graph = Graph {
167167 required,
168- mains : Some ( vec ! [ MainModule :: new( go_mod. as_deref( ) . unwrap_or_default( ) ) ] ) ,
168+ mains : vec ! [ MainModule :: new( go_mod. as_deref( ) . unwrap_or_default( ) ) ] ,
169169 workspace : go_work. is_some ( ) ,
170170 } ;
171171 let mut sums = SumPins :: default ( ) ;
@@ -191,9 +191,8 @@ struct Graph {
191191 /// as a root-only reader can tell).
192192 required : HashMap < String , String > ,
193193 /// The main modules: the root module, or every readable in-root
194- /// `go.work` `use` member. `None` when a member is outside the root or
195- /// unreadable.
196- mains : Option < Vec < MainModule > > ,
194+ /// `go.work` `use` member.
195+ mains : Vec < MainModule > ,
197196 /// A `go.work` is in effect.
198197 workspace : bool ,
199198}
@@ -221,7 +220,7 @@ impl Graph {
221220 /// module past every `require` and sum line discovery reads. Only a
222221 /// higher version in that evidence proves the replace inert.
223222 fn select ( & self , module : & str , version : & str , zips : & [ & str ] ) -> Selection {
224- let mains = self . mains . as_deref ( ) . unwrap_or_default ( ) ;
223+ let mains = & self . mains ;
225224 let required = mains
226225 . iter ( )
227226 . filter_map ( |m| m. required . get ( module) . map ( String :: as_str) )
@@ -241,19 +240,20 @@ impl Graph {
241240
242241/// The `use` members of `go.work` as main modules, and the sum files go
243242/// verifies against in workspace mode: `go.work.sum` and each member's
244- /// `go.sum` (the root's only when `.` is a member). The main modules are
245- /// `None` when a member's go.mod is outside the root or unreadable.
243+ /// `go.sum` (the root's only when `.` is a member). A member whose go.mod
244+ /// is outside the root or unreadable adds no main module; the others still
245+ /// count, since in a workspace their `require`s only ever prove a replace
246+ /// inert, never selected.
246247async fn read_workspace (
247248 ctx : & DiscoverCtx < ' _ > ,
248249 out : & mut Discovery ,
249250 go_mod : Option < & str > ,
250251 go_work : & str ,
251- ) -> ( Option < Vec < MainModule > > , Vec < String > ) {
252- let mut mains = Some ( Vec :: new ( ) ) ;
252+ ) -> ( Vec < MainModule > , Vec < String > ) {
253+ let mut mains = Vec :: new ( ) ;
253254 let mut files = vec ! [ GO_WORK_SUM . to_string( ) ] ;
254255 for dir in go_mod_edit:: parse_use_dirs ( go_work) {
255256 let Some ( dir) = member_dir ( & dir) else {
256- mains = None ;
257257 continue ;
258258 } ;
259259 let text = if dir. is_empty ( ) {
@@ -265,10 +265,8 @@ async fn read_workspace(
265265 None => None ,
266266 }
267267 } ;
268- match ( text, mains. as_mut ( ) ) {
269- ( Some ( text) , Some ( mains) ) => mains. push ( MainModule :: new ( & text) ) ,
270- ( Some ( _) , None ) => { }
271- ( None , _) => mains = None ,
268+ if let Some ( text) = text {
269+ mains. push ( MainModule :: new ( & text) ) ;
272270 }
273271 let sum = member_file ( & dir, GO_SUM ) ;
274272 if !files. contains ( & sum) {
@@ -1219,6 +1217,41 @@ mod tests {
12191217 }
12201218 }
12211219
1220+ /// A member that cannot be read (outside the root, or missing its
1221+ /// go.mod) does not hide another member's higher require.
1222+ #[ tokio:: test]
1223+ async fn workspace_unreadable_member_keeps_other_members_requires ( ) {
1224+ let m = gopatch ( UUID_A ) ;
1225+ let sver = "v1.4.2-socketpatch.1" ;
1226+ for extra in [ "../outside" , "./missing" ] {
1227+ let p = Project :: new ( ) ;
1228+ p. write ( "go.mod" , BASE_GO_MOD )
1229+ . write (
1230+ "go.work" ,
1231+ format ! (
1232+ "go 1.21\n \n use (\n \t .\n \t {extra}\n \t ./svc\n )\n \n replace {MODULE} {VERSION} => {m} {sver}\n "
1233+ ) ,
1234+ )
1235+ . write (
1236+ "go.work.sum" ,
1237+ format ! ( "{m} {sver} {ZIP_H1}\n {m} {sver}/go.mod {MOD_H1}\n " ) ,
1238+ )
1239+ . write (
1240+ "svc/go.mod" ,
1241+ format ! ( "module example.com/svc\n \n go 1.21\n \n require {MODULE} v1.5.0\n " ) ,
1242+ ) ;
1243+ let out = run ( & p) . await ;
1244+ assert_refs ( & out, & [ ] ) ;
1245+ assert ! (
1246+ out. diagnostics
1247+ . iter( )
1248+ . any( |d| d. code == DIAG_REF_INVALID && d. detail. contains( "selects v1.5.0" ) ) ,
1249+ "{extra}: {:?}" ,
1250+ out. diagnostics
1251+ ) ;
1252+ }
1253+ }
1254+
12221255 /// go verifies against the sum files of the mode it builds in: in
12231256 /// workspace mode `go.work.sum` and the members' go.sum (the root's only
12241257 /// when `.` is a member); under `GOWORK=off` the root go.sum alone, with
0 commit comments