Skip to content

Commit e062459

Browse files
committed
Require data effects on non-copy parameters
1 parent c0bf9d0 commit e062459

3 files changed

Lines changed: 73 additions & 0 deletions

File tree

src/analyzer.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,25 @@ impl Analyzer<'_> {
118118
),
119119
);
120120
}
121+
if param.effect.is_none() && !param.ty.name.is_empty() && !is_copy_type(&param.ty) {
122+
self.diagnostics.push(
123+
Diagnostic::error(
124+
code::MISSING_PARAMETER_EFFECT,
125+
format!(
126+
"parameter `{}` in `{}` must declare `read`, `mut`, or `take`.",
127+
param.name, function.name
128+
),
129+
param.span.clone(),
130+
"missing parameter effect",
131+
)
132+
.with_cause("Non-Copy parameters must expose their data effect in the function signature.")
133+
.with_fix(
134+
"add_parameter_effect",
135+
format!("Write `{}: read {}` or another explicit effect.", param.name, type_ref_name(&param.ty)),
136+
"manual",
137+
),
138+
);
139+
}
121140
}
122141

123142
for effect in &function.effects {
@@ -542,3 +561,41 @@ fn duplicate_symbol_label(kind: DuplicateSymbolKind) -> &'static str {
542561
DuplicateSymbolKind::Field => "field",
543562
}
544563
}
564+
565+
fn is_copy_type(ty: &TypeRef) -> bool {
566+
ty.args.is_empty()
567+
&& matches!(
568+
ty.name.as_str(),
569+
"Bool"
570+
| "Byte"
571+
| "Char"
572+
| "Float"
573+
| "Float32"
574+
| "Float64"
575+
| "Int"
576+
| "Int8"
577+
| "Int16"
578+
| "Int32"
579+
| "Int64"
580+
| "UInt"
581+
| "UInt8"
582+
| "UInt16"
583+
| "UInt32"
584+
| "UInt64"
585+
| "Unit"
586+
)
587+
}
588+
589+
fn type_ref_name(ty: &TypeRef) -> String {
590+
if ty.args.is_empty() {
591+
return ty.name.clone();
592+
}
593+
594+
let args = ty
595+
.args
596+
.iter()
597+
.map(type_ref_name)
598+
.collect::<Vec<_>>()
599+
.join(", ");
600+
format!("{}<{args}>", ty.name)
601+
}

src/diagnostic.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod code {
88
pub const DUPLICATE_DECLARATION: &str = "RS0005";
99
pub const DUPLICATE_FILE_MODE: &str = "RS0006";
1010
pub const UNKNOWN_RETAINED_PARAMETER: &str = "RS0007";
11+
pub const MISSING_PARAMETER_EFFECT: &str = "RS0008";
1112
pub const FILE_MODE_VIOLATION: &str = "RS0101";
1213
pub const UNNAMED_ARGUMENT: &str = "RS0201";
1314
pub const MISSING_DATA_EFFECT: &str = "RS0202";
@@ -230,6 +231,11 @@ static DIAGNOSTIC_EXPLANATIONS: &[DiagnosticExplanation] = &[
230231
title: "unknown retained parameter",
231232
explanation: "`effects(retains(param))` must name a parameter declared by the function signature.",
232233
},
234+
DiagnosticExplanation {
235+
code: code::MISSING_PARAMETER_EFFECT,
236+
title: "missing parameter data effect",
237+
explanation: "Non-Copy parameters must declare `read`, `mut`, or `take` in the function signature so call effects are review-visible.",
238+
},
233239
DiagnosticExplanation {
234240
code: code::FILE_MODE_VIOLATION,
235241
title: "file mode violation",
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// expect: RS0008
2+
mode: managed
3+
4+
struct Image {
5+
pixels: Buffer
6+
}
7+
8+
fn inspect(image: Image) -> Unit {
9+
Image.inspect(image: read image)
10+
}

0 commit comments

Comments
 (0)