lang: Rename Linear marker to Once
b6abab3681d90482de5514902eca21b6d37680764ee6853ef815bfd47b0c4234
1 parent
702b8915
lib/std/lang/resolver.rad
+4 -4
| 168 | 168 | export record RecordType: Copy { |
|
| 169 | 169 | fields: *[RecordField], |
|
| 170 | 170 | labeled: bool, |
|
| 171 | 171 | /// Cached layout. |
|
| 172 | 172 | layout: Layout, |
|
| 173 | - | /// Whether the declaration explicitly carries the `Linear` marker. |
|
| 173 | + | /// Whether the declaration explicitly carries the `Once` marker. |
|
| 174 | 174 | declaredLinear: bool, |
|
| 175 | 175 | /// Whether the declaration explicitly carries the `Copy` marker. |
|
| 176 | 176 | declaredCopy: bool, |
|
| 177 | 177 | } |
|
| 178 | 178 |
| 183 | 183 | layout: Layout, |
|
| 184 | 184 | /// Cached payload offset within the union aggregate. |
|
| 185 | 185 | valOffset: u32, |
|
| 186 | 186 | /// If all variants have void payloads. |
|
| 187 | 187 | isAllVoid: bool, |
|
| 188 | - | /// Whether the declaration explicitly carries the `Linear` marker. |
|
| 188 | + | /// Whether the declaration explicitly carries the `Once` marker. |
|
| 189 | 189 | declaredLinear: bool, |
|
| 190 | 190 | /// Whether the declaration explicitly carries the `Copy` marker. |
|
| 191 | 191 | declaredCopy: bool, |
|
| 192 | 192 | } |
|
| 193 | 193 |
| 617 | 617 | LinearOverwrite, |
|
| 618 | 618 | /// `undefined` cannot initialize a linear type. |
|
| 619 | 619 | LinearUndefined, |
|
| 620 | 620 | /// A `Copy` declaration contains a non-copy field or variant. |
|
| 621 | 621 | CopyContainsNonCopy, |
|
| 622 | - | /// A declaration carries both `Copy` and `Linear`. |
|
| 622 | + | /// A declaration carries both `Copy` and `Once`. |
|
| 623 | 623 | ConflictingOwnershipMarkers, |
|
| 624 | 624 | /// A reference appears in a storable or escaping position. |
|
| 625 | 625 | InvalidRefPosition, |
|
| 626 | 626 | /// A reference cannot be bound to a local. |
|
| 627 | 627 | RefBinding, |
| 3462 | 3462 | throws (ResolveError) |
|
| 3463 | 3463 | { |
|
| 3464 | 3464 | let mut result = OwnershipMarkers { linear: false, copy: false }; |
|
| 3465 | 3465 | for derive in derives { |
|
| 3466 | 3466 | let name = try nodeName(self, derive); |
|
| 3467 | - | if mem::eq(name, "Linear") { |
|
| 3467 | + | if mem::eq(name, "Once") { |
|
| 3468 | 3468 | if result.linear { |
|
| 3469 | 3469 | throw emitError(self, derive, ErrorKind::DuplicateBinding(name)); |
|
| 3470 | 3470 | } |
|
| 3471 | 3471 | if result.copy { |
|
| 3472 | 3472 | throw emitError(self, derive, ErrorKind::ConflictingOwnershipMarkers); |
lib/std/lang/resolver/printer.rad
+1 -1
| 525 | 525 | } |
|
| 526 | 526 | case super::ErrorKind::CopyContainsNonCopy => { |
|
| 527 | 527 | io::print("`Copy` composite contains a non-copy value"); |
|
| 528 | 528 | } |
|
| 529 | 529 | case super::ErrorKind::ConflictingOwnershipMarkers => { |
|
| 530 | - | io::print("a composite cannot be both `Copy` and `Linear`"); |
|
| 530 | + | io::print("a composite cannot be both `Copy` and `Once`"); |
|
| 531 | 531 | } |
|
| 532 | 532 | case super::ErrorKind::InvalidRefPosition => { |
|
| 533 | 533 | io::print("reference type is only allowed as a function parameter"); |
|
| 534 | 534 | } |
|
| 535 | 535 | case super::ErrorKind::RefBinding => { |
lib/std/lang/resolver/tests.rad
+39 -39
| 5171 | 5171 | } |
|
| 5172 | 5172 | ||
| 5173 | 5173 | /// References cannot escape through return types. |
|
| 5174 | 5174 | @test fn testRefReturnRejected() throws (testing::TestError) { |
|
| 5175 | 5175 | let mut a = testResolver(); |
|
| 5176 | - | let program = "record Marker: Linear {} fn bad(value: &u32) -> &u32 { return value; }"; |
|
| 5176 | + | let program = "record Marker: Once {} fn bad(value: &u32) -> &u32 { return value; }"; |
|
| 5177 | 5177 | let result = try resolveProgramStr(&mut a, program); |
|
| 5178 | 5178 | try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition); |
|
| 5179 | 5179 | } |
|
| 5180 | 5180 | ||
| 5181 | 5181 | /// Case-pattern fallbacks must terminate instead of synthesizing bindings. |
| 5195 | 5195 | } |
|
| 5196 | 5196 | ||
| 5197 | 5197 | /// Unsafe pointer dereference requires an unsafe declaration. |
|
| 5198 | 5198 | @test fn testUnsafePointerOperationRejected() throws (testing::TestError) { |
|
| 5199 | 5199 | let mut a = testResolver(); |
|
| 5200 | - | let program = "record Marker: Linear {} fn load(pointer: *unsafe u32) -> u32 { return *pointer; }"; |
|
| 5200 | + | let program = "record Marker: Once {} fn load(pointer: *unsafe u32) -> u32 { return *pointer; }"; |
|
| 5201 | 5201 | let result = try resolveProgramStr(&mut a, program); |
|
| 5202 | 5202 | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5203 | 5203 | } |
|
| 5204 | 5204 | ||
| 5205 | 5205 | /// Unsafe pointers remain freely copyable inside an unsafe declaration. |
|
| 5206 | 5206 | @test fn testUnsafePointerOperationAllowed() throws (testing::TestError) { |
|
| 5207 | - | let program = "record Marker: Linear {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; }"; |
|
| 5207 | + | let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; }"; |
|
| 5208 | 5208 | try expectAnalyzeOk(program); |
|
| 5209 | 5209 | } |
|
| 5210 | 5210 | ||
| 5211 | 5211 | /// Safe code cannot call a function that accepts unsafe operations. |
|
| 5212 | 5212 | @test fn testUnsafeFunctionCallRejected() throws (testing::TestError) { |
|
| 5213 | 5213 | let mut a = testResolver(); |
|
| 5214 | - | let program = "record Marker: Linear {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; } fn run(pointer: *unsafe u32) -> u32 { return load(pointer); }"; |
|
| 5214 | + | let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; } fn run(pointer: *unsafe u32) -> u32 { return load(pointer); }"; |
|
| 5215 | 5215 | let result = try resolveProgramStr(&mut a, program); |
|
| 5216 | 5216 | try expectErrorKind(&result, super::ErrorKind::UnsafeCall); |
|
| 5217 | 5217 | } |
|
| 5218 | 5218 | ||
| 5219 | 5219 | /// Unsafe function values retain their call-site safety requirement. |
| 5225 | 5225 | } |
|
| 5226 | 5226 | ||
| 5227 | 5227 | /// References cannot be embedded in aggregate fields. |
|
| 5228 | 5228 | @test fn testRefFieldRejected() throws (testing::TestError) { |
|
| 5229 | 5229 | let mut a = testResolver(); |
|
| 5230 | - | let program = "record Marker: Linear {} record Bad { value: &u32 }"; |
|
| 5230 | + | let program = "record Marker: Once {} record Bad { value: &u32 }"; |
|
| 5231 | 5231 | let result = try resolveProgramStr(&mut a, program); |
|
| 5232 | 5232 | try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition); |
|
| 5233 | 5233 | } |
|
| 5234 | 5234 | ||
| 5235 | 5235 | /// Trait methods may use reference receivers. |
|
| 5236 | 5236 | @test fn testTraitRefReceiver() throws (testing::TestError) { |
|
| 5237 | - | let program = "record Marker: Linear {} record Value { number: i32 } trait Read { fn (&Read) get() -> i32; } instance Read for Value { fn (value: &Value) get() -> i32 { return value.number; } } fn inspect(object: &opaque Read) -> i32 { return object.get(); } fn call(value: &Value) -> i32 { return inspect(value); }"; |
|
| 5237 | + | let program = "record Marker: Once {} record Value { number: i32 } trait Read { fn (&Read) get() -> i32; } instance Read for Value { fn (value: &Value) get() -> i32 { return value.number; } } fn inspect(object: &opaque Read) -> i32 { return object.get(); } fn call(value: &Value) -> i32 { return inspect(value); }"; |
|
| 5238 | 5238 | try expectAnalyzeOk(program); |
|
| 5239 | 5239 | } |
|
| 5240 | 5240 | ||
| 5241 | 5241 | /// Trait implementations must preserve the receiver pointer class. |
|
| 5242 | 5242 | @test fn testTraitReceiverClassMismatch() throws (testing::TestError) { |
| 5281 | 5281 | } |
|
| 5282 | 5282 | ||
| 5283 | 5283 | /// A composite cannot carry conflicting ownership markers. |
|
| 5284 | 5284 | @test fn testConflictingOwnershipMarkersRejected() throws (testing::TestError) { |
|
| 5285 | 5285 | let mut a = testResolver(); |
|
| 5286 | - | let program = "record Value: Copy + Linear { number: u32 }"; |
|
| 5286 | + | let program = "record Value: Copy + Once { number: u32 }"; |
|
| 5287 | 5287 | let result = try resolveProgramStr(&mut a, program); |
|
| 5288 | 5288 | try expectErrorKind(&result, super::ErrorKind::ConflictingOwnershipMarkers); |
|
| 5289 | 5289 | } |
|
| 5290 | 5290 | ||
| 5291 | 5291 | /// Linear composites still require one consuming use. |
|
| 5292 | 5292 | @test fn testLinearCompositeMustBeConsumed() throws (testing::TestError) { |
|
| 5293 | 5293 | let mut a = testResolver(); |
|
| 5294 | - | let program = "record Token: Linear { number: u32 } fn run() { let token = Token { number: 1 }; }"; |
|
| 5294 | + | let program = "record Token: Once { number: u32 } fn run() { let token = Token { number: 1 }; }"; |
|
| 5295 | 5295 | let result = try resolveProgramStr(&mut a, program); |
|
| 5296 | 5296 | try expectErrorKind(&result, super::ErrorKind::LinearNotConsumed("token")); |
|
| 5297 | 5297 | } |
|
| 5298 | 5298 | ||
| 5299 | 5299 | /// The compiler-known marker cannot be derived more than once. |
|
| 5300 | - | @test fn testDuplicateLinearMarkerRejected() throws (testing::TestError) { |
|
| 5300 | + | @test fn testDuplicateOnceMarkerRejected() throws (testing::TestError) { |
|
| 5301 | 5301 | let mut a = testResolver(); |
|
| 5302 | - | let program = "record Token: Linear + Linear { value: u32 }"; |
|
| 5302 | + | let program = "record Token: Once + Once { value: u32 }"; |
|
| 5303 | 5303 | let result = try resolveProgramStr(&mut a, program); |
|
| 5304 | - | try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("Linear")); |
|
| 5304 | + | try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("Once")); |
|
| 5305 | 5305 | } |
|
| 5306 | 5306 | ||
| 5307 | - | /// A `Linear` marker does not change legacy pointer inference. |
|
| 5308 | - | @test fn testLinearMarkerKeepsLegacyPointerInference() throws (testing::TestError) { |
|
| 5309 | - | let program = "record Marker: Linear {} fn run() { let value: u32 = 0; let pointer: *u32 = &value; pointer; }"; |
|
| 5307 | + | /// A `Once` marker does not change legacy pointer inference. |
|
| 5308 | + | @test fn testOnceMarkerKeepsLegacyPointerInference() throws (testing::TestError) { |
|
| 5309 | + | let program = "record Marker: Once {} fn run() { let value: u32 = 0; let pointer: *u32 = &value; pointer; }"; |
|
| 5310 | 5310 | try expectAnalyzeOk(program); |
|
| 5311 | 5311 | } |
|
| 5312 | 5312 | ||
| 5313 | 5313 | /// References are rejected from every nested or storable type position. |
|
| 5314 | 5314 | @test fn testNestedRefPositionsRejected() throws (testing::TestError) { |
|
| 5315 | 5315 | { |
|
| 5316 | 5316 | let mut a = testResolver(); |
|
| 5317 | - | let program = "record Marker: Linear {} union Bad { Value(&u32) }"; |
|
| 5317 | + | let program = "record Marker: Once {} union Bad { Value(&u32) }"; |
|
| 5318 | 5318 | let result = try resolveProgramStr(&mut a, program); |
|
| 5319 | 5319 | try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition); |
|
| 5320 | 5320 | } { |
|
| 5321 | 5321 | let mut a = testResolver(); |
|
| 5322 | - | let program = "record Marker: Linear {} fn bad(value: ?&u32) {}"; |
|
| 5322 | + | let program = "record Marker: Once {} fn bad(value: ?&u32) {}"; |
|
| 5323 | 5323 | let result = try resolveProgramStr(&mut a, program); |
|
| 5324 | 5324 | try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition); |
|
| 5325 | 5325 | } { |
|
| 5326 | 5326 | let mut a = testResolver(); |
|
| 5327 | - | let program = "record Marker: Linear {} fn bad(value: [&u32; 1]) {}"; |
|
| 5327 | + | let program = "record Marker: Once {} fn bad(value: [&u32; 1]) {}"; |
|
| 5328 | 5328 | let result = try resolveProgramStr(&mut a, program); |
|
| 5329 | 5329 | try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition); |
|
| 5330 | 5330 | } { |
|
| 5331 | 5331 | let mut a = testResolver(); |
|
| 5332 | - | let program = "record Marker: Linear {} fn bad(value: *&u32) {}"; |
|
| 5332 | + | let program = "record Marker: Once {} fn bad(value: *&u32) {}"; |
|
| 5333 | 5333 | let result = try resolveProgramStr(&mut a, program); |
|
| 5334 | 5334 | try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition); |
|
| 5335 | 5335 | } { |
|
| 5336 | 5336 | let mut a = testResolver(); |
|
| 5337 | - | let program = "record Marker: Linear {} static BAD: &u32 = undefined;"; |
|
| 5337 | + | let program = "record Marker: Once {} static BAD: &u32 = undefined;"; |
|
| 5338 | 5338 | let result = try resolveProgramStr(&mut a, program); |
|
| 5339 | 5339 | try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition); |
|
| 5340 | 5340 | } { |
|
| 5341 | 5341 | let mut a = testResolver(); |
|
| 5342 | - | let program = "record Marker: Linear {} fn bad(callback: fn() -> &u32) {}"; |
|
| 5342 | + | let program = "record Marker: Once {} fn bad(callback: fn() -> &u32) {}"; |
|
| 5343 | 5343 | let result = try resolveProgramStr(&mut a, program); |
|
| 5344 | 5344 | try expectErrorKind(&result, super::ErrorKind::InvalidRefPosition); |
|
| 5345 | 5345 | } |
|
| 5346 | 5346 | } |
|
| 5347 | 5347 | ||
| 5348 | 5348 | /// Function pointer parameter references remain call-scoped and valid. |
|
| 5349 | 5349 | @test fn testFunctionPointerRefParameterAllowed() throws (testing::TestError) { |
|
| 5350 | - | let program = "record Marker: Linear {} fn invoke(callback: fn(&u32), value: &u32) { callback(value); }"; |
|
| 5350 | + | let program = "record Marker: Once {} fn invoke(callback: fn(&u32), value: &u32) { callback(value); }"; |
|
| 5351 | 5351 | try expectAnalyzeOk(program); |
|
| 5352 | 5352 | } |
|
| 5353 | 5353 | ||
| 5354 | 5354 | /// Pointer and slice casts cannot change reference ownership. |
|
| 5355 | 5355 | @test fn testRefCastClassPreserved() throws (testing::TestError) { |
|
| 5356 | 5356 | { |
|
| 5357 | 5357 | let mut a = testResolver(); |
|
| 5358 | - | let program = "record Marker: Linear {} fn cast(value: &u32) { value as *u32; }"; |
|
| 5358 | + | let program = "record Marker: Once {} fn cast(value: &u32) { value as *u32; }"; |
|
| 5359 | 5359 | let result = try resolveProgramStr(&mut a, program); |
|
| 5360 | 5360 | let err = try expectError(&result); |
|
| 5361 | 5361 | let case super::ErrorKind::InvalidAsCast(_) = err.kind |
|
| 5362 | 5362 | else throw testing::TestError::Failed; |
|
| 5363 | 5363 | } { |
|
| 5364 | 5364 | let mut a = testResolver(); |
|
| 5365 | - | let program = "record Marker: Linear {} fn cast(values: &[u32]) { values as *[u32]; }"; |
|
| 5365 | + | let program = "record Marker: Once {} fn cast(values: &[u32]) { values as *[u32]; }"; |
|
| 5366 | 5366 | let result = try resolveProgramStr(&mut a, program); |
|
| 5367 | 5367 | let err = try expectError(&result); |
|
| 5368 | 5368 | let case super::ErrorKind::InvalidAsCast(_) = err.kind |
|
| 5369 | 5369 | else throw testing::TestError::Failed; |
|
| 5370 | 5370 | } |
| 5372 | 5372 | ||
| 5373 | 5373 | /// Every operation that interprets an unsafe address requires an unsafe declaration. |
|
| 5374 | 5374 | @test fn testUnsafePointerOperationsRejected() throws (testing::TestError) { |
|
| 5375 | 5375 | { |
|
| 5376 | 5376 | let mut a = testResolver(); |
|
| 5377 | - | let program = "record Marker: Linear {} fn cast(pointer: *unsafe u32) -> u64 { return pointer as u64; }"; |
|
| 5377 | + | let program = "record Marker: Once {} fn cast(pointer: *unsafe u32) -> u64 { return pointer as u64; }"; |
|
| 5378 | 5378 | let result = try resolveProgramStr(&mut a, program); |
|
| 5379 | 5379 | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5380 | 5380 | } { |
|
| 5381 | 5381 | let mut a = testResolver(); |
|
| 5382 | - | let program = "record Marker: Linear {} fn compare(pointer: *unsafe u32) -> bool { return pointer == pointer; }"; |
|
| 5382 | + | let program = "record Marker: Once {} fn compare(pointer: *unsafe u32) -> bool { return pointer == pointer; }"; |
|
| 5383 | 5383 | let result = try resolveProgramStr(&mut a, program); |
|
| 5384 | 5384 | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5385 | 5385 | } { |
|
| 5386 | 5386 | let mut a = testResolver(); |
|
| 5387 | - | let program = "record Marker: Linear {} fn offset(pointer: *unsafe u32) -> *unsafe u32 { return pointer + 1; }"; |
|
| 5387 | + | let program = "record Marker: Once {} fn offset(pointer: *unsafe u32) -> *unsafe u32 { return pointer + 1; }"; |
|
| 5388 | 5388 | let result = try resolveProgramStr(&mut a, program); |
|
| 5389 | 5389 | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5390 | 5390 | } { |
|
| 5391 | 5391 | let mut a = testResolver(); |
|
| 5392 | - | let program = "record Marker: Linear {} fn index(values: *unsafe [u32]) -> u32 { return values[0]; }"; |
|
| 5392 | + | let program = "record Marker: Once {} fn index(values: *unsafe [u32]) -> u32 { return values[0]; }"; |
|
| 5393 | 5393 | let result = try resolveProgramStr(&mut a, program); |
|
| 5394 | 5394 | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5395 | 5395 | } { |
|
| 5396 | 5396 | let mut a = testResolver(); |
|
| 5397 | - | let program = "record Marker: Linear {} record Cell { value: u32 } fn field(cell: *unsafe Cell) -> u32 { return cell.value; }"; |
|
| 5397 | + | let program = "record Marker: Once {} record Cell { value: u32 } fn field(cell: *unsafe Cell) -> u32 { return cell.value; }"; |
|
| 5398 | 5398 | let result = try resolveProgramStr(&mut a, program); |
|
| 5399 | 5399 | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5400 | 5400 | } { |
|
| 5401 | 5401 | let mut a = testResolver(); |
|
| 5402 | - | let program = "record Marker: Linear {} fn store(pointer: *unsafe mut u32) { set *pointer = 1; }"; |
|
| 5402 | + | let program = "record Marker: Once {} fn store(pointer: *unsafe mut u32) { set *pointer = 1; }"; |
|
| 5403 | 5403 | let result = try resolveProgramStr(&mut a, program); |
|
| 5404 | 5404 | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5405 | 5405 | } { |
|
| 5406 | 5406 | let mut a = testResolver(); |
|
| 5407 | - | let program = "record Marker: Linear {} fn cast() { let value: u32 = 0; let pointer = &value as *unsafe u32; }"; |
|
| 5407 | + | let program = "record Marker: Once {} fn cast() { let value: u32 = 0; let pointer = &value as *unsafe u32; }"; |
|
| 5408 | 5408 | let result = try resolveProgramStr(&mut a, program); |
|
| 5409 | 5409 | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5410 | 5410 | } |
|
| 5411 | 5411 | } |
|
| 5412 | 5412 | ||
| 5413 | 5413 | /// Unsafe declarations may compose unsafe operations and calls. |
|
| 5414 | 5414 | @test fn testUnsafePointerOperationsAllowed() throws (testing::TestError) { |
|
| 5415 | - | let program = "record Marker: Linear {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; } unsafe fn run(pointer: *unsafe u32) -> u32 { let next = pointer + 1; let same = pointer == next; return load(pointer); }"; |
|
| 5415 | + | let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; } unsafe fn run(pointer: *unsafe u32) -> u32 { let next = pointer + 1; let same = pointer == next; return load(pointer); }"; |
|
| 5416 | 5416 | try expectAnalyzeOk(program); |
|
| 5417 | 5417 | } |
|
| 5418 | 5418 | ||
| 5419 | 5419 | /// Unsafe code may drop a checked reference to an unsafe pointer. |
|
| 5420 | 5420 | @test fn testUnsafePointerFromReference() throws (testing::TestError) { |
|
| 5421 | - | let program = "record Marker: Linear {} unsafe fn store(pointer: *unsafe mut u32) { set *pointer = 42; } unsafe fn run() { let mut value: u32 = 0; store(&mut value as *unsafe mut u32); }"; |
|
| 5421 | + | let program = "record Marker: Once {} unsafe fn store(pointer: *unsafe mut u32) { set *pointer = 42; } unsafe fn run() { let mut value: u32 = 0; store(&mut value as *unsafe mut u32); }"; |
|
| 5422 | 5422 | try expectAnalyzeOk(program); |
|
| 5423 | 5423 | } |
|
| 5424 | 5424 | ||
| 5425 | 5425 | /// Dropping a reference to an unsafe pointer cannot add mutability. |
|
| 5426 | 5426 | @test fn testUnsafePointerCastCannotAddMutability() throws (testing::TestError) { |
|
| 5427 | 5427 | let mut a = testResolver(); |
|
| 5428 | - | let program = "record Marker: Linear {} unsafe fn run(value: &u32) { value as *unsafe mut u32; }"; |
|
| 5428 | + | let program = "record Marker: Once {} unsafe fn run(value: &u32) { value as *unsafe mut u32; }"; |
|
| 5429 | 5429 | let result = try resolveProgramStr(&mut a, program); |
|
| 5430 | 5430 | let err = try expectError(&result); |
|
| 5431 | 5431 | let case super::ErrorKind::InvalidAsCast(_) = err.kind |
|
| 5432 | 5432 | else throw testing::TestError::Failed; |
|
| 5433 | 5433 | } |
|
| 5434 | 5434 | ||
| 5435 | 5435 | /// Recursive cast validation cannot hide a checked-to-unsafe transition. |
|
| 5436 | 5436 | @test fn testNestedUnsafePointerCastRejected() throws (testing::TestError) { |
|
| 5437 | 5437 | let mut a = testResolver(); |
|
| 5438 | - | let program = "record Marker: Linear {} fn run(value: **u32) { value as **unsafe u32; }"; |
|
| 5438 | + | let program = "record Marker: Once {} fn run(value: **u32) { value as **unsafe u32; }"; |
|
| 5439 | 5439 | let result = try resolveProgramStr(&mut a, program); |
|
| 5440 | 5440 | let err = try expectError(&result); |
|
| 5441 | 5441 | let case super::ErrorKind::InvalidAsCast(_) = err.kind |
|
| 5442 | 5442 | else throw testing::TestError::Failed; |
|
| 5443 | 5443 | } |
|
| 5444 | 5444 | ||
| 5445 | 5445 | /// Unsafe code may drop a checked slice reference to an unsafe slice. |
|
| 5446 | 5446 | @test fn testUnsafeSliceFromReference() throws (testing::TestError) { |
|
| 5447 | - | let program = "record Marker: Linear {} unsafe fn run(values: &[u32]) { let raw: *unsafe [u32] = values as *unsafe [u32]; }"; |
|
| 5447 | + | let program = "record Marker: Once {} unsafe fn run(values: &[u32]) { let raw: *unsafe [u32] = values as *unsafe [u32]; }"; |
|
| 5448 | 5448 | try expectAnalyzeOk(program); |
|
| 5449 | 5449 | } |
|
| 5450 | 5450 | ||
| 5451 | 5451 | /// Slice casts cannot add mutability. |
|
| 5452 | 5452 | @test fn testSliceCastCannotAddMutability() throws (testing::TestError) { |
|
| 5453 | 5453 | let mut a = testResolver(); |
|
| 5454 | - | let program = "record Marker: Linear {} fn run(values: &[u32]) { values as &mut [u32]; }"; |
|
| 5454 | + | let program = "record Marker: Once {} fn run(values: &[u32]) { values as &mut [u32]; }"; |
|
| 5455 | 5455 | let result = try resolveProgramStr(&mut a, program); |
|
| 5456 | 5456 | let err = try expectError(&result); |
|
| 5457 | 5457 | let case super::ErrorKind::InvalidAsCast(_) = err.kind |
|
| 5458 | 5458 | else throw testing::TestError::Failed; |
|
| 5459 | 5459 | } |
|
| 5460 | 5460 | ||
| 5461 | 5461 | /// Mutable unsafe receivers do not create checked exclusive loans. |
|
| 5462 | 5462 | @test fn testUnsafeReceiverDoesNotBorrowExclusively() throws (testing::TestError) { |
|
| 5463 | - | let program = "record Marker: Linear {} record Value { number: u32 } unsafe fn (value: *unsafe mut Value) update(other: *unsafe mut Value) {} unsafe fn run(value: *unsafe mut Value) { value.update(value); }"; |
|
| 5463 | + | let program = "record Marker: Once {} record Value { number: u32 } unsafe fn (value: *unsafe mut Value) update(other: *unsafe mut Value) {} unsafe fn run(value: *unsafe mut Value) { value.update(value); }"; |
|
| 5464 | 5464 | try expectAnalyzeOk(program); |
|
| 5465 | 5465 | } |
|
| 5466 | 5466 | ||
| 5467 | 5467 | /// Unsafe instance-method attributes enable unsafe operations in the body. |
|
| 5468 | 5468 | @test fn testUnsafeInstanceMethodBody() throws (testing::TestError) { |
|
| 5469 | - | let program = "record Marker: Linear {} record Value { number: u32 } trait Read { unsafe fn (*unsafe Read) get() -> u32; } instance Read for Value { unsafe fn (value: *unsafe Value) get() -> u32 { return value.number; } }"; |
|
| 5469 | + | let program = "record Marker: Once {} record Value { number: u32 } trait Read { unsafe fn (*unsafe Read) get() -> u32; } instance Read for Value { unsafe fn (value: *unsafe Value) get() -> u32 { return value.number; } }"; |
|
| 5470 | 5470 | try expectAnalyzeOk(program); |
|
| 5471 | 5471 | } |
|
| 5472 | 5472 | ||
| 5473 | 5473 | /// Unsafe instance methods cannot implement safe trait contracts. |
|
| 5474 | 5474 | @test fn testUnsafeInstanceMethodSafetyMismatch() throws (testing::TestError) { |
| 5479 | 5479 | } |
|
| 5480 | 5480 | ||
| 5481 | 5481 | /// Unsafe trait methods retain their call-site requirement through dispatch. |
|
| 5482 | 5482 | @test fn testUnsafeTraitMethodCallRejected() throws (testing::TestError) { |
|
| 5483 | 5483 | let mut a = testResolver(); |
|
| 5484 | - | let program = "record Marker: Linear {} record Value { number: u32 } trait Read { unsafe fn (&Read) get() -> u32; } instance Read for Value { unsafe fn (value: &Value) get() -> u32 { return value.number; } } fn inspect(object: &opaque Read) -> u32 { return object.get(); }"; |
|
| 5484 | + | let program = "record Marker: Once {} record Value { number: u32 } trait Read { unsafe fn (&Read) get() -> u32; } instance Read for Value { unsafe fn (value: &Value) get() -> u32 { return value.number; } } fn inspect(object: &opaque Read) -> u32 { return object.get(); }"; |
|
| 5485 | 5485 | let result = try resolveProgramStr(&mut a, program); |
|
| 5486 | 5486 | try expectErrorKind(&result, super::ErrorKind::UnsafeCall); |
|
| 5487 | 5487 | } |
test/tests/linear.ownership.rad
+1 -1
| 1 | 1 | //! returns: 42 |
|
| 2 | 2 | ||
| 3 | 3 | /// Linear token consumed by the test. |
|
| 4 | - | union Token: Linear { |
|
| 4 | + | union Token: Once { |
|
| 5 | 5 | /// Token payload. |
|
| 6 | 6 | Value(u32), |
|
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | /// Consume a token and return its payload. |
test/tests/linear.reference.rad
+1 -1
| 1 | 1 | //! returns: 42 |
|
| 2 | 2 | ||
| 3 | 3 | /// Linear counter borrowed and consumed by the test. |
|
| 4 | - | union Counter: Linear { |
|
| 4 | + | union Counter: Once { |
|
| 5 | 5 | /// Counter value. |
|
| 6 | 6 | Value(u32), |
|
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | /// Increment a borrowed counter. |
test/tests/linear.unsafe.rad
+2 -2
| 1 | 1 | //! returns: 42 |
|
| 2 | 2 | ||
| 3 | - | /// Linear marker used with unsafe pointer syntax. |
|
| 4 | - | record Marker: Linear {} |
|
| 3 | + | /// Once marker used with unsafe pointer syntax. |
|
| 4 | + | record Marker: Once {} |
|
| 5 | 5 | ||
| 6 | 6 | /// Load a value through an unsafe pointer. |
|
| 7 | 7 | unsafe fn load(pointer: *unsafe u32) -> u32 { |
|
| 8 | 8 | return *pointer; |
|
| 9 | 9 | } |
vim/radiance.vim
+1 -1
| 17 | 17 | " Keywords |
|
| 18 | 18 | syntax keyword radianceKeyword mod fn return if else while true false and or not case align static |
|
| 19 | 19 | syntax keyword radianceKeyword export break continue use loop in for match nil undefined |
|
| 20 | 20 | syntax keyword radianceKeyword let mut set as register device constant log record union trait instance |
|
| 21 | 21 | syntax keyword radianceKeyword throws throw try catch panic assert super unsafe |
|
| 22 | - | syntax keyword radianceType i8 i16 i32 i64 u8 u16 u32 u64 f32 void bool bit opaque Copy Linear |
|
| 22 | + | syntax keyword radianceType i8 i16 i32 i64 u8 u16 u32 u64 f32 void bool bit opaque Copy Once |
|
| 23 | 23 | ||
| 24 | 24 | " Double-quoted strings |
|
| 25 | 25 | syntax region radianceString start=/"/ skip=/\\"/ end=/"/ contains=radianceEscape |
|
| 26 | 26 | " Characters |
|
| 27 | 27 | syntax region radianceCharacter start=/'/ skip=/\\'|\\\\/ end=/'/ oneline contains=radianceEscape |