GraphiteEditor/Graphite · warning

If `selection_shape` is a polygon then subpath is constructe

Error message

If `selection_shape` is a polygon then subpath is constructed beforehand.

What it means

select_intersecting_points builds polygon_subpath only when selection_shape is SelectionShape::Lasso (shape_editor.rs:2223-2231) and later unwraps it with .expect("If `selection_shape` is a polygon then subpath is constructed beforehand.") inside the Lasso arm of the segment-selection match (2256). The invariant 'Lasso implies Some(polygon)' holds only because the construction if-let and every access arm stay in lockstep — the compiler does not enforce it. Any edit that decouples them (new SelectionShape variant, access moved before construction, changed construction condition) panics on every lasso drag over segments.

Source

Thrown at editor/src/messages/tool/common_functionality/shape_editor.rs:2256

					let segment_bbox = transformed_segment.bounding_box();

					let select = match selection_shape {
						SelectionShape::Box(rect) => {
							let enclosed = rect.contains_rect(segment_bbox);
							match selection_mode {
								SelectionMode::Enclosed => enclosed,
								_ => {
									// Check for intersection with the segment
									enclosed
										|| rect
											.path_segments(DEFAULT_ACCURACY)
											.map(|seg| seg.as_line().unwrap())
											.any(|line| !transformed_segment.intersect_line(line).is_empty())
								}
							}
						}
						SelectionShape::Lasso(_) => {
							let polygon = polygon_subpath.as_ref().expect("If `selection_shape` is a polygon then subpath is constructed beforehand.");

							// Sample 10 points on the bezier and check if all or some lie inside the polygon
							let points = pathseg_compute_lookup_table(segment, Some(10), false);
							match selection_mode {
								SelectionMode::Enclosed => points.map(|p| transform.transform_point2(p)).all(|p| polygon.contains_point(p)),
								_ => points.map(|p| transform.transform_point2(p)).any(|p| polygon.contains_point(p)),
							}
						}
					};

					if select {
						segments_inside.entry(layer).or_default().insert(id);
					}
				}

				let segment_points = pathseg_points(segment);

				// Selecting handles

View on GitHub (pinned to c507b35645)

Solutions

  1. Restructure so the polygon is passed by reference into lasso-only code paths (e.g. compute the predicate via a closure taking &Subpath<PointId>), removing the Option entirely
  2. Keep construction and all accesses driven by one match on selection_shape so adding a variant is a compile error, not a runtime panic
  3. As a minimal fix, convert the expect to let-else that skips the segment instead of panicking

Example fix

// before
SelectionShape::Lasso(_) => {
	let polygon = polygon_subpath.as_ref().expect("If `selection_shape` is a polygon then subpath is constructed beforehand.");
	...
}
// after — pass the polygon in, no Option to unwrap
SelectionShape::Lasso(polygon) => {
	let polygon_subpath = Subpath::<PointId>::from_anchors(polygon.to_vec(), true);
	// polygon_subpath is now locally, provably constructed
	...
}
Defensive patterns

Strategy: validation

Validate before calling

// Make the invariant structural: derive polygon and access from one exhaustive match
let polygon_subpath = match selection_shape {
	SelectionShape::Lasso(polygon) if polygon.len() >= 2 => Some(Subpath::<PointId>::from_anchors(polygon.to_vec(), true)),
	SelectionShape::Lasso(_) => return (points_inside, segments_inside),
	SelectionShape::Box(_) => None,
};

Prevention

When it happens

Trigger: Regression edits: adding a SelectionShape variant whose arm reads polygon_subpath, moving the segment loop above the construction, or altering the polygon.len() < 2 early-return so a Lasso arm executes with None.

Common situations: Extending selection shapes (e.g. adding a lasso-variant or brush shape); refactoring the intersection code into helpers that lose the construction context; changing the Subpath construction to be lazy/conditional.

Related errors


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/1e85fe214846d46a. Report an issue: GitHub.