GOAL P1-1..1-3: 리터럴이 자기 타입에 안 맞으면 거부한다

그리고 그 자리를 파다가 더 나쁜 것이 나왔다.

store 의 폭이 목적지가 아니라 값에서 왔다. 정수 리터럴은 더 좁은 것이
요구하기 전까지 i32 이므로 let b: u8 = 200; 은 4바이트가 1바이트 자리로
가는 것으로 도착하고, 4바이트를 쓰면 프레임이 그 옆에 놓은 것을 지운다.

  let a: i32 = 5;  let b: u8 = 300;  let d: u8 = 44;
  a 0 / b 0 / d 44        →   a 5 / b 44 / d 44

폭 넓은 지역 하나만 있으면 드러나지 않아서 여태 살아 있었다. exec/narrow.fe
가 폭이 섞인 지역을 나란히 두어 고정한다.

규칙 자체는 SPEC §3 에 넣었다: 리터럴의 타입은 문맥이 요구하는 정수 타입이고,
없으면 i32 다. 범위를 벗어나면 잘리는 것이 아니라 거부된다. 앞의 단항 -
는 리터럴의 일부로 보아 i8 = -128 은 되고 u8 = -1 은 안 된다.

같이 넣은 문장 둘:
- §9 미사용 타입 파라미터는 정상이다. typed handle 이 그 모양이고 구현은
  이미 그렇게 동작했다.
- §7.4 --no-checks 에서 오버플로는 랩어라운드로 정의된다. 타깃이 실제로
  하는 일이고 미정의로 두지 않는다.

237/237, 35/35.
This commit is contained in:
2026-08-17 16:07:45 +09:00
parent 32da64d7c1
commit 1a368dc13f
8 changed files with 152 additions and 247 deletions
+32
View File
@@ -0,0 +1,32 @@
// EXIT:0
// OUTPUT:a 5 b 200 c 44 d 9
// OUTPUT:e 5 f 1 g 65535
// OUTPUT:sum 253
unit narrow;
import std.io;
// How wide a store is belongs to the place, not to the value. An integer
// literal is `i32` until something narrower asks for it, so `let b: u8 = 200;`
// arrives at the store as four bytes going into one -- and writing four wipes
// out whatever the frame put beside it.
//
// Several locals of mixed width, next to each other, is what it takes to see
// it: each narrow store used to reach back over the one declared before it.
fn main() -> i32 {
let a: i32 = 5;
let b: u8 = 200;
let c: u8 = 44;
let d: i16 = 9;
@print("a {} b {} c {} d {}\n", a, b, c, d);
let e = 5; // no annotation: i32 (SPEC 4.1)
let f: i8 = 1;
let g: u16 = 65535;
@print("e {} f {} g {}\n", e, f as i32, g);
// And the values are still there after everything else was written.
@print("sum {}\n", (b as i32) + (c as i32) + (d as i32) + e - (a as i32));
return 0;
}