]> git.proxmox.com Git - rustc.git/blame - src/librustc_borrowck/borrowck/fragments.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / librustc_borrowck / borrowck / fragments.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Helper routines used for fragmenting structural paths due to moves for
12//! tracking drop obligations. Please see the extensive comments in the
c34b1796 13//! section "Structural fragments" in `README.md`.
1a4d82fc
JJ
14
15use self::Fragment::*;
16
85aaf69f 17use borrowck::InteriorKind::{InteriorField, InteriorElement};
c1a9b12d 18use borrowck::{self, LoanPath};
1a4d82fc
JJ
19use borrowck::LoanPathKind::{LpVar, LpUpvar, LpDowncast, LpExtend};
20use borrowck::LoanPathElem::{LpDeref, LpInterior};
c34b1796 21use borrowck::move_data::InvalidMovePathIndex;
1a4d82fc
JJ
22use borrowck::move_data::{MoveData, MovePathIndex};
23use rustc::middle::ty;
24use rustc::middle::mem_categorization as mc;
62682a34 25
1a4d82fc
JJ
26use std::mem;
27use std::rc::Rc;
28use syntax::ast;
1a4d82fc
JJ
29use syntax::attr::AttrMetaMethods;
30use syntax::codemap::Span;
31
32#[derive(PartialEq, Eq, PartialOrd, Ord)]
33enum Fragment {
34 // This represents the path described by the move path index
35 Just(MovePathIndex),
36
37 // This represents the collection of all but one of the elements
38 // from an array at the path described by the move path index.
39 // Note that attached MovePathIndex should have mem_categorization
85aaf69f 40 // of InteriorElement (i.e. array dereference `&foo[..]`).
1a4d82fc
JJ
41 AllButOneFrom(MovePathIndex),
42}
43
44impl Fragment {
62682a34
SL
45 fn loan_path_repr(&self, move_data: &MoveData) -> String {
46 let lp = |mpi| move_data.path_loan_path(mpi);
1a4d82fc 47 match *self {
62682a34
SL
48 Just(mpi) => format!("{:?}", lp(mpi)),
49 AllButOneFrom(mpi) => format!("$(allbutone {:?})", lp(mpi)),
1a4d82fc
JJ
50 }
51 }
52
62682a34
SL
53 fn loan_path_user_string(&self, move_data: &MoveData) -> String {
54 let lp = |mpi| move_data.path_loan_path(mpi);
1a4d82fc 55 match *self {
62682a34
SL
56 Just(mpi) => lp(mpi).to_string(),
57 AllButOneFrom(mpi) => format!("$(allbutone {})", lp(mpi)),
1a4d82fc
JJ
58 }
59 }
60}
61
c1a9b12d
SL
62pub fn build_unfragmented_map(this: &mut borrowck::BorrowckCtxt,
63 move_data: &MoveData,
64 id: ast::NodeId) {
65 let fr = &move_data.fragments.borrow();
66
67 // For now, don't care about other kinds of fragments; the precise
68 // classfication of all paths for non-zeroing *drop* needs them,
69 // but the loose approximation used by non-zeroing moves does not.
70 let moved_leaf_paths = fr.moved_leaf_paths();
71 let assigned_leaf_paths = fr.assigned_leaf_paths();
72
73 let mut fragment_infos = Vec::with_capacity(moved_leaf_paths.len());
74
75 let find_var_id = |move_path_index: MovePathIndex| -> Option<ast::NodeId> {
76 let lp = move_data.path_loan_path(move_path_index);
77 match lp.kind {
78 LpVar(var_id) => Some(var_id),
79 LpUpvar(ty::UpvarId { var_id, closure_expr_id }) => {
80 // The `var_id` is unique *relative to* the current function.
81 // (Check that we are indeed talking about the same function.)
82 assert_eq!(id, closure_expr_id);
83 Some(var_id)
84 }
85 LpDowncast(..) | LpExtend(..) => {
86 // This simple implementation of non-zeroing move does
87 // not attempt to deal with tracking substructure
88 // accurately in the general case.
89 None
90 }
91 }
92 };
93
94 let moves = move_data.moves.borrow();
95 for &move_path_index in moved_leaf_paths {
96 let var_id = match find_var_id(move_path_index) {
97 None => continue,
98 Some(var_id) => var_id,
99 };
100
101 move_data.each_applicable_move(move_path_index, |move_index| {
102 let info = ty::FragmentInfo::Moved {
103 var: var_id,
104 move_expr: moves[move_index.get()].id,
105 };
106 debug!("fragment_infos push({:?} \
107 due to move_path_index: {} move_index: {}",
108 info, move_path_index.get(), move_index.get());
109 fragment_infos.push(info);
110 true
111 });
112 }
113
114 for &move_path_index in assigned_leaf_paths {
115 let var_id = match find_var_id(move_path_index) {
116 None => continue,
117 Some(var_id) => var_id,
118 };
119
120 let var_assigns = move_data.var_assignments.borrow();
121 for var_assign in var_assigns.iter()
122 .filter(|&assign| assign.path == move_path_index)
123 {
124 let info = ty::FragmentInfo::Assigned {
125 var: var_id,
126 assign_expr: var_assign.id,
127 assignee_id: var_assign.assignee_id,
128 };
129 debug!("fragment_infos push({:?} due to var_assignment", info);
130 fragment_infos.push(info);
131 }
132 }
133
134 let mut fraginfo_map = this.tcx.fragment_infos.borrow_mut();
135 let fn_did = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
136 let prev = fraginfo_map.insert(fn_did, fragment_infos);
137 assert!(prev.is_none());
138}
139
1a4d82fc
JJ
140pub struct FragmentSets {
141 /// During move_data construction, `moved_leaf_paths` tracks paths
142 /// that have been used directly by being moved out of. When
143 /// move_data construction has been completed, `moved_leaf_paths`
144 /// tracks such paths that are *leaf fragments* (e.g. `a.j` if we
145 /// never move out any child like `a.j.x`); any parent paths
146 /// (e.g. `a` for the `a.j` example) are moved over to
147 /// `parents_of_fragments`.
148 moved_leaf_paths: Vec<MovePathIndex>,
149
150 /// `assigned_leaf_paths` tracks paths that have been used
151 /// directly by being overwritten, but is otherwise much like
152 /// `moved_leaf_paths`.
153 assigned_leaf_paths: Vec<MovePathIndex>,
154
155 /// `parents_of_fragments` tracks paths that are definitely
156 /// parents of paths that have been moved.
157 ///
158 /// FIXME(pnkfelix) probably do not want/need
159 /// `parents_of_fragments` at all, if we can avoid it.
160 ///
161 /// Update: I do not see a way to to avoid it. Maybe just remove
162 /// above fixme, or at least document why doing this may be hard.
163 parents_of_fragments: Vec<MovePathIndex>,
164
165 /// During move_data construction (specifically the
166 /// fixup_fragment_sets call), `unmoved_fragments` tracks paths
167 /// that have been "left behind" after a sibling has been moved or
168 /// assigned. When move_data construction has been completed,
169 /// `unmoved_fragments` tracks paths that were *only* results of
170 /// being left-behind, and never directly moved themselves.
171 unmoved_fragments: Vec<Fragment>,
172}
173
174impl FragmentSets {
175 pub fn new() -> FragmentSets {
176 FragmentSets {
177 unmoved_fragments: Vec::new(),
178 moved_leaf_paths: Vec::new(),
179 assigned_leaf_paths: Vec::new(),
180 parents_of_fragments: Vec::new(),
181 }
182 }
183
c1a9b12d
SL
184 pub fn moved_leaf_paths(&self) -> &[MovePathIndex] {
185 &self.moved_leaf_paths
186 }
187
188 pub fn assigned_leaf_paths(&self) -> &[MovePathIndex] {
189 &self.assigned_leaf_paths
190 }
191
1a4d82fc
JJ
192 pub fn add_move(&mut self, path_index: MovePathIndex) {
193 self.moved_leaf_paths.push(path_index);
194 }
195
196 pub fn add_assignment(&mut self, path_index: MovePathIndex) {
197 self.assigned_leaf_paths.push(path_index);
198 }
199}
200
201pub fn instrument_move_fragments<'tcx>(this: &MoveData<'tcx>,
202 tcx: &ty::ctxt<'tcx>,
203 sp: Span,
204 id: ast::NodeId) {
c34b1796
AL
205 let span_err = tcx.map.attrs(id).iter()
206 .any(|a| a.check_name("rustc_move_fragments"));
207 let print = tcx.sess.opts.debugging_opts.print_move_fragments;
1a4d82fc
JJ
208
209 if !span_err && !print { return; }
210
85aaf69f 211 let instrument_all_paths = |kind, vec_rc: &Vec<MovePathIndex>| {
1a4d82fc 212 for (i, mpi) in vec_rc.iter().enumerate() {
62682a34 213 let lp = || this.path_loan_path(*mpi);
1a4d82fc 214 if span_err {
62682a34 215 tcx.sess.span_err(sp, &format!("{}: `{}`", kind, lp()));
1a4d82fc
JJ
216 }
217 if print {
62682a34 218 println!("id:{} {}[{}] `{}`", id, kind, i, lp());
1a4d82fc
JJ
219 }
220 }
221 };
222
85aaf69f 223 let instrument_all_fragments = |kind, vec_rc: &Vec<Fragment>| {
1a4d82fc 224 for (i, f) in vec_rc.iter().enumerate() {
62682a34 225 let render = || f.loan_path_user_string(this);
1a4d82fc 226 if span_err {
c34b1796 227 tcx.sess.span_err(sp, &format!("{}: `{}`", kind, render()));
1a4d82fc
JJ
228 }
229 if print {
230 println!("id:{} {}[{}] `{}`", id, kind, i, render());
231 }
232 }
233 };
234
235 let fragments = this.fragments.borrow();
236 instrument_all_paths("moved_leaf_path", &fragments.moved_leaf_paths);
237 instrument_all_fragments("unmoved_fragment", &fragments.unmoved_fragments);
238 instrument_all_paths("parent_of_fragments", &fragments.parents_of_fragments);
239 instrument_all_paths("assigned_leaf_path", &fragments.assigned_leaf_paths);
240}
241
242/// Normalizes the fragment sets in `this`; i.e., removes duplicate entries, constructs the set of
243/// parents, and constructs the left-over fragments.
244///
245/// Note: "left-over fragments" means paths that were not directly referenced in moves nor
246/// assignments, but must nonetheless be tracked as potential drop obligations.
247pub fn fixup_fragment_sets<'tcx>(this: &MoveData<'tcx>, tcx: &ty::ctxt<'tcx>) {
248
249 let mut fragments = this.fragments.borrow_mut();
250
251 // Swap out contents of fragments so that we can modify the fields
252 // without borrowing the common fragments.
253 let mut unmoved = mem::replace(&mut fragments.unmoved_fragments, vec![]);
254 let mut parents = mem::replace(&mut fragments.parents_of_fragments, vec![]);
255 let mut moved = mem::replace(&mut fragments.moved_leaf_paths, vec![]);
256 let mut assigned = mem::replace(&mut fragments.assigned_leaf_paths, vec![]);
257
85aaf69f 258 let path_lps = |mpis: &[MovePathIndex]| -> Vec<String> {
62682a34 259 mpis.iter().map(|mpi| format!("{:?}", this.path_loan_path(*mpi))).collect()
1a4d82fc
JJ
260 };
261
85aaf69f 262 let frag_lps = |fs: &[Fragment]| -> Vec<String> {
62682a34 263 fs.iter().map(|f| f.loan_path_repr(this)).collect()
1a4d82fc
JJ
264 };
265
266 // First, filter out duplicates
267 moved.sort();
268 moved.dedup();
85aaf69f 269 debug!("fragments 1 moved: {:?}", path_lps(&moved[..]));
1a4d82fc
JJ
270
271 assigned.sort();
272 assigned.dedup();
85aaf69f 273 debug!("fragments 1 assigned: {:?}", path_lps(&assigned[..]));
1a4d82fc
JJ
274
275 // Second, build parents from the moved and assigned.
85aaf69f 276 for m in &moved {
1a4d82fc
JJ
277 let mut p = this.path_parent(*m);
278 while p != InvalidMovePathIndex {
279 parents.push(p);
280 p = this.path_parent(p);
281 }
282 }
85aaf69f 283 for a in &assigned {
1a4d82fc
JJ
284 let mut p = this.path_parent(*a);
285 while p != InvalidMovePathIndex {
286 parents.push(p);
287 p = this.path_parent(p);
288 }
289 }
290
291 parents.sort();
292 parents.dedup();
85aaf69f 293 debug!("fragments 2 parents: {:?}", path_lps(&parents[..]));
1a4d82fc
JJ
294
295 // Third, filter the moved and assigned fragments down to just the non-parents
85aaf69f
SL
296 moved.retain(|f| non_member(*f, &parents[..]));
297 debug!("fragments 3 moved: {:?}", path_lps(&moved[..]));
1a4d82fc 298
85aaf69f
SL
299 assigned.retain(|f| non_member(*f, &parents[..]));
300 debug!("fragments 3 assigned: {:?}", path_lps(&assigned[..]));
1a4d82fc
JJ
301
302 // Fourth, build the leftover from the moved, assigned, and parents.
85aaf69f 303 for m in &moved {
1a4d82fc
JJ
304 let lp = this.path_loan_path(*m);
305 add_fragment_siblings(this, tcx, &mut unmoved, lp, None);
306 }
85aaf69f 307 for a in &assigned {
1a4d82fc
JJ
308 let lp = this.path_loan_path(*a);
309 add_fragment_siblings(this, tcx, &mut unmoved, lp, None);
310 }
85aaf69f 311 for p in &parents {
1a4d82fc
JJ
312 let lp = this.path_loan_path(*p);
313 add_fragment_siblings(this, tcx, &mut unmoved, lp, None);
314 }
315
316 unmoved.sort();
317 unmoved.dedup();
85aaf69f 318 debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved[..]));
1a4d82fc
JJ
319
320 // Fifth, filter the leftover fragments down to its core.
321 unmoved.retain(|f| match *f {
322 AllButOneFrom(_) => true,
85aaf69f
SL
323 Just(mpi) => non_member(mpi, &parents[..]) &&
324 non_member(mpi, &moved[..]) &&
325 non_member(mpi, &assigned[..])
1a4d82fc 326 });
85aaf69f 327 debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved[..]));
1a4d82fc
JJ
328
329 // Swap contents back in.
330 fragments.unmoved_fragments = unmoved;
331 fragments.parents_of_fragments = parents;
332 fragments.moved_leaf_paths = moved;
333 fragments.assigned_leaf_paths = assigned;
334
335 return;
336
337 fn non_member(elem: MovePathIndex, set: &[MovePathIndex]) -> bool {
338 match set.binary_search(&elem) {
339 Ok(_) => false,
340 Err(_) => true,
341 }
342 }
343}
344
345/// Adds all of the precisely-tracked siblings of `lp` as potential move paths of interest. For
346/// example, if `lp` represents `s.x.j`, then adds moves paths for `s.x.i` and `s.x.k`, the
347/// siblings of `s.x.j`.
348fn add_fragment_siblings<'tcx>(this: &MoveData<'tcx>,
349 tcx: &ty::ctxt<'tcx>,
350 gathered_fragments: &mut Vec<Fragment>,
351 lp: Rc<LoanPath<'tcx>>,
352 origin_id: Option<ast::NodeId>) {
353 match lp.kind {
354 LpVar(_) | LpUpvar(..) => {} // Local variables have no siblings.
355
356 // Consuming a downcast is like consuming the original value, so propage inward.
357 LpDowncast(ref loan_parent, _) => {
358 add_fragment_siblings(this, tcx, gathered_fragments, loan_parent.clone(), origin_id);
359 }
360
361 // *LV for Unique consumes the contents of the box (at
362 // least when it is non-copy...), so propagate inward.
363 LpExtend(ref loan_parent, _, LpDeref(mc::Unique)) => {
364 add_fragment_siblings(this, tcx, gathered_fragments, loan_parent.clone(), origin_id);
365 }
366
367 // *LV for unsafe and borrowed pointers do not consume their loan path, so stop here.
368 LpExtend(_, _, LpDeref(mc::UnsafePtr(..))) |
369 LpExtend(_, _, LpDeref(mc::Implicit(..))) |
370 LpExtend(_, _, LpDeref(mc::BorrowedPtr(..))) => {}
371
85aaf69f 372 // FIXME (pnkfelix): LV[j] should be tracked, at least in the
1a4d82fc
JJ
373 // sense of we will track the remaining drop obligation of the
374 // rest of the array.
375 //
85aaf69f
SL
376 // Well, either that or LV[j] should be made illegal.
377 // But even then, we will need to deal with destructuring
378 // bind.
379 //
380 // Anyway, for now: LV[j] is not tracked precisely
381 LpExtend(_, _, LpInterior(InteriorElement(..))) => {
1a4d82fc
JJ
382 let mp = this.move_path(tcx, lp.clone());
383 gathered_fragments.push(AllButOneFrom(mp));
384 }
385
386 // field access LV.x and tuple access LV#k are the cases
387 // we are interested in
388 LpExtend(ref loan_parent, mc,
85aaf69f 389 LpInterior(InteriorField(ref field_name))) => {
1a4d82fc
JJ
390 let enum_variant_info = match loan_parent.kind {
391 LpDowncast(ref loan_parent_2, variant_def_id) =>
392 Some((variant_def_id, loan_parent_2.clone())),
393 LpExtend(..) | LpVar(..) | LpUpvar(..) =>
394 None,
395 };
396 add_fragment_siblings_for_extension(
397 this,
398 tcx,
399 gathered_fragments,
400 loan_parent, mc, field_name, &lp, origin_id, enum_variant_info);
401 }
402 }
403}
404
405/// We have determined that `origin_lp` destructures to LpExtend(parent, original_field_name).
406/// Based on this, add move paths for all of the siblings of `origin_lp`.
407fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>,
408 tcx: &ty::ctxt<'tcx>,
409 gathered_fragments: &mut Vec<Fragment>,
410 parent_lp: &Rc<LoanPath<'tcx>>,
411 mc: mc::MutabilityCategory,
412 origin_field_name: &mc::FieldName,
413 origin_lp: &Rc<LoanPath<'tcx>>,
414 origin_id: Option<ast::NodeId>,
415 enum_variant_info: Option<(ast::DefId,
416 Rc<LoanPath<'tcx>>)>) {
417 let parent_ty = parent_lp.to_type();
418
85aaf69f 419 let mut add_fragment_sibling_local = |field_name, variant_did| {
1a4d82fc
JJ
420 add_fragment_sibling_core(
421 this, tcx, gathered_fragments, parent_lp.clone(), mc, field_name, origin_lp,
422 variant_did);
423 };
424
425 match (&parent_ty.sty, enum_variant_info) {
62682a34 426 (&ty::TyTuple(ref v), None) => {
1a4d82fc
JJ
427 let tuple_idx = match *origin_field_name {
428 mc::PositionalField(tuple_idx) => tuple_idx,
429 mc::NamedField(_) =>
62682a34
SL
430 panic!("tuple type {:?} should not have named fields.",
431 parent_ty),
1a4d82fc
JJ
432 };
433 let tuple_len = v.len();
85aaf69f 434 for i in 0..tuple_len {
1a4d82fc
JJ
435 if i == tuple_idx { continue }
436 let field_name = mc::PositionalField(i);
437 add_fragment_sibling_local(field_name, None);
438 }
439 }
440
62682a34 441 (&ty::TyStruct(def_id, ref _substs), None) => {
c1a9b12d 442 let fields = tcx.lookup_struct_fields(def_id);
1a4d82fc
JJ
443 match *origin_field_name {
444 mc::NamedField(ast_name) => {
85aaf69f 445 for f in &fields {
1a4d82fc
JJ
446 if f.name == ast_name {
447 continue;
448 }
449 let field_name = mc::NamedField(f.name);
450 add_fragment_sibling_local(field_name, None);
451 }
452 }
453 mc::PositionalField(tuple_idx) => {
454 for (i, _f) in fields.iter().enumerate() {
455 if i == tuple_idx {
456 continue
457 }
458 let field_name = mc::PositionalField(i);
459 add_fragment_sibling_local(field_name, None);
460 }
461 }
462 }
463 }
464
62682a34 465 (&ty::TyEnum(enum_def_id, substs), ref enum_variant_info) => {
1a4d82fc 466 let variant_info = {
c1a9b12d 467 let mut variants = tcx.substd_enum_variants(enum_def_id, substs);
1a4d82fc
JJ
468 match *enum_variant_info {
469 Some((variant_def_id, ref _lp2)) =>
470 variants.iter()
471 .find(|variant| variant.id == variant_def_id)
472 .expect("enum_variant_with_id(): no variant exists with that ID")
473 .clone(),
474 None => {
475 assert_eq!(variants.len(), 1);
476 variants.pop().unwrap()
477 }
478 }
479 };
480 match *origin_field_name {
481 mc::NamedField(ast_name) => {
482 let variant_arg_names = variant_info.arg_names.as_ref().unwrap();
9346a6ac
AL
483 for &variant_arg_name in variant_arg_names {
484 if variant_arg_name == ast_name {
1a4d82fc
JJ
485 continue;
486 }
9346a6ac 487 let field_name = mc::NamedField(variant_arg_name);
1a4d82fc
JJ
488 add_fragment_sibling_local(field_name, Some(variant_info.id));
489 }
490 }
491 mc::PositionalField(tuple_idx) => {
492 let variant_arg_types = &variant_info.args;
493 for (i, _variant_arg_ty) in variant_arg_types.iter().enumerate() {
494 if tuple_idx == i {
495 continue;
496 }
497 let field_name = mc::PositionalField(i);
498 add_fragment_sibling_local(field_name, None);
499 }
500 }
501 }
502 }
503
504 ref sty_and_variant_info => {
62682a34
SL
505 let msg = format!("type {:?} ({:?}) is not fragmentable",
506 parent_ty, sty_and_variant_info);
1a4d82fc 507 let opt_span = origin_id.and_then(|id|tcx.map.opt_span(id));
85aaf69f 508 tcx.sess.opt_span_bug(opt_span, &msg[..])
1a4d82fc
JJ
509 }
510 }
511}
512
513/// Adds the single sibling `LpExtend(parent, new_field_name)` of `origin_lp` (the original
514/// loan-path).
515fn add_fragment_sibling_core<'tcx>(this: &MoveData<'tcx>,
516 tcx: &ty::ctxt<'tcx>,
517 gathered_fragments: &mut Vec<Fragment>,
518 parent: Rc<LoanPath<'tcx>>,
519 mc: mc::MutabilityCategory,
520 new_field_name: mc::FieldName,
521 origin_lp: &Rc<LoanPath<'tcx>>,
522 enum_variant_did: Option<ast::DefId>) -> MovePathIndex {
523 let opt_variant_did = match parent.kind {
524 LpDowncast(_, variant_did) => Some(variant_did),
525 LpVar(..) | LpUpvar(..) | LpExtend(..) => enum_variant_did,
526 };
527
85aaf69f 528 let loan_path_elem = LpInterior(InteriorField(new_field_name));
1a4d82fc
JJ
529 let new_lp_type = match new_field_name {
530 mc::NamedField(ast_name) =>
c1a9b12d 531 tcx.named_element_ty(parent.to_type(), ast_name, opt_variant_did),
1a4d82fc 532 mc::PositionalField(idx) =>
c1a9b12d 533 tcx.positional_element_ty(parent.to_type(), idx, opt_variant_did),
1a4d82fc
JJ
534 };
535 let new_lp_variant = LpExtend(parent, mc, loan_path_elem);
536 let new_lp = LoanPath::new(new_lp_variant, new_lp_type.unwrap());
62682a34
SL
537 debug!("add_fragment_sibling_core(new_lp={:?}, origin_lp={:?})",
538 new_lp, origin_lp);
1a4d82fc
JJ
539 let mp = this.move_path(tcx, Rc::new(new_lp));
540
541 // Do not worry about checking for duplicates here; we will sort
542 // and dedup after all are added.
543 gathered_fragments.push(Just(mp));
544
545 mp
546}