GOAL P1-4: 작은 규칙 일곱을 정하고, 어긋난 둘을 고친다
일곱 중 다섯은 구현이 이미 옳게 답하고 있었다 -- match 는 enum 전용이고,
enum payload 에 소유 타입을 담을 수 있고, undefined 배열은 원소 단위로
추적하지 않고, 다른 유닛에서 private 필드가 있는 리터럴은 거부되고,
by-value self 의 부분 이동도 mem.replace 가 필요하다. SPEC §7.9 에 적었다.
나머지 둘은 그냥 통과하고 있었다.
defer { return 1; } 이 받아들여졌다. 지연 블록은 함수가 무엇을 반환할지 이미
정한 뒤 스코프 정리 중에 도는데 거기서 return 이 뜻할 것이 없다.
for x in xs { xs[0] = 9; } 도 받아들여졌다. x 가 xs 안을 가리키는 참조이니
순회 몸통에서 xs 에 쓰는 것은 그 참조가 가리키는 것을 옮기는 일이다 (R6).
순회는 이제 도는 동안 대여한다. 읽기는 공유 순회에서 그대로 된다.
240/240, 35/35.
This commit is contained in:
@@ -589,6 +589,20 @@ pub fn main() -> !void {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### 7.9 작은 규칙들
|
||||||
|
|
||||||
|
구현자가 임의로 정하면 갈라지는 것들. 각각 한 줄이면 끝나므로 여기 모아 둔다.
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| `match` | **enum 값에만 쓴다.** 정수와 `char`에는 쓸 수 없으므로 완전성 검사가 배리언트 목록 하나로 정해진다. 정수 분기는 `if`/`else if`로 쓴다 |
|
||||||
|
| enum payload | `^T`처럼 소유하는 타입을 담을 수 있다. 다만 v0.1은 **활성 배리언트의 payload를 자동으로 놓아주지 않는다** — 담았다면 꺼내서 직접 놓아야 한다 |
|
||||||
|
| `for x in xs` | 순회는 `xs`를 **순회 동안 대여한다**. `x`가 그 안을 가리키는 참조이므로 몸통에서 `xs`에 쓰는 것은 R6 위반이다. 읽는 것은 공유 순회에서 허용된다 |
|
||||||
|
| `defer` 안의 `return` | **컴파일 에러.** 지연 블록은 함수가 무엇을 반환할지 이미 정한 뒤 스코프 정리 중에 돈다 |
|
||||||
|
| `undefined` 배열 | 초기화 추적은 **변수 단위이며 원소 단위가 아니다.** `undefined`로 선언한 배열은 선언 시점부터 쓰기 가능하고, 읽기 전에 무엇을 채웠는지는 검사하지 않는다. 슬라이스로 넘겨 채우는 것이 의도된 사용법이다 |
|
||||||
|
| 다른 유닛의 struct 리터럴 | 모든 필드를 명시해야 하므로 **`pub`이 아닌 필드가 하나라도 있으면 밖에서 리터럴을 쓸 수 없다.** 생성자 함수를 두어야 한다 |
|
||||||
|
| by-value `self` | `self`를 값으로 받아도 필드를 꺼내는 것은 R7 그대로 `mem.replace`가 필요하다. 예외는 자기 `drop` 안뿐이다 |
|
||||||
|
|
||||||
## 8. 유닛
|
## 8. 유닛
|
||||||
|
|
||||||
파일 하나가 유닛 하나다. 유닛의 canonical identity는 fully-qualified dotted unit path이며
|
파일 하나가 유닛 하나다. 유닛의 canonical identity는 fully-qualified dotted unit path이며
|
||||||
|
|||||||
@@ -986,6 +986,11 @@ void check_stmt(FeCheckerState *s, FeNode *n)
|
|||||||
m7_check_match_stmt(s,n);
|
m7_check_match_stmt(s,n);
|
||||||
break;
|
break;
|
||||||
case FE_N_RETURN:
|
case FE_N_RETURN:
|
||||||
|
/* A deferred block runs during scope cleanup, on the way out of a
|
||||||
|
function that has already decided what it returns. There is nothing
|
||||||
|
for a `return` in there to mean. */
|
||||||
|
if (s->defer_depth != 0)
|
||||||
|
err(s->c, n->loc, "cannot return from inside defer");
|
||||||
expected=s->ret;
|
expected=s->ret;
|
||||||
if (n->a)
|
if (n->a)
|
||||||
stored=m7_check_expected(s,n->a,expected);
|
stored=m7_check_expected(s,n->a,expected);
|
||||||
|
|||||||
@@ -101,7 +101,18 @@ void check_for(FeCheckerState *s, FeNode *n)
|
|||||||
item_cname,n);
|
item_cname,n);
|
||||||
n->cname=item_cname;
|
n->cname=item_cname;
|
||||||
}
|
}
|
||||||
|
/* Walking a container borrows it for the length of the walk: the
|
||||||
|
item is a reference into it, so writing the container underneath
|
||||||
|
would move what that reference points at (SPEC 5 R6). */
|
||||||
|
if (iter_sym)
|
||||||
|
fe_own_access(s->c->diags,&iter_sym->own,
|
||||||
|
iter_mut ? FE_OWN_BORROW_MUT : FE_OWN_BORROW_SHARED,
|
||||||
|
n->loc);
|
||||||
check_stmt(s,n->b);
|
check_stmt(s,n->b);
|
||||||
|
if (iter_sym) {
|
||||||
|
if (iter_mut) fe_own_release_exclusive(&iter_sym->own);
|
||||||
|
else fe_own_release_shared(&iter_sym->own);
|
||||||
|
}
|
||||||
s->scope=old;
|
s->scope=old;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -459,6 +470,11 @@ void check_stmt_core(FeCheckerState *s, FeNode *n)
|
|||||||
if (!s->loop_depth) err(c,n->loc,"break or continue outside loop");
|
if (!s->loop_depth) err(c,n->loc,"break or continue outside loop");
|
||||||
break;
|
break;
|
||||||
case FE_N_RETURN:
|
case FE_N_RETURN:
|
||||||
|
/* A deferred block runs during scope cleanup, on the way out of a
|
||||||
|
function that has already decided what it returns. There is nothing
|
||||||
|
for a `return` in there to mean. */
|
||||||
|
if (s->defer_depth != 0)
|
||||||
|
err(c, n->loc, "cannot return from inside defer");
|
||||||
b = n->a ? check_expr(s, n->a) : fe_type_intern(&c->types, "void");
|
b = n->a ? check_expr(s, n->a) : fe_type_intern(&c->types, "void");
|
||||||
if (s->ret && fe_own_is_reference_like(s->ret) &&
|
if (s->ret && fe_own_is_reference_like(s->ret) &&
|
||||||
!own_return_from_allowed_root(s,n->a))
|
!own_return_from_allowed_root(s,n->a))
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// ERROR:9:borrow
|
||||||
|
unit badforwr;
|
||||||
|
|
||||||
|
// Walking a container borrows it: the item is a reference into it, so writing
|
||||||
|
// the container underneath moves what that reference points at.
|
||||||
|
|
||||||
|
fn bad(xs: []mut i32) -> void {
|
||||||
|
for x in xs {
|
||||||
|
xs[0] = 9;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:8:cannot return from inside defer
|
||||||
|
unit bdefret;
|
||||||
|
|
||||||
|
// A deferred block runs during scope cleanup, on the way out of a function
|
||||||
|
// that has already decided what it returns.
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
defer { return 1; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
unit okforrd;
|
||||||
|
|
||||||
|
// A shared walk still allows reading -- of the item and of the container.
|
||||||
|
|
||||||
|
fn ok(xs: []i32) -> i32 {
|
||||||
|
var sum: i32 = 0;
|
||||||
|
for x in xs {
|
||||||
|
sum = sum + x.^ + (xs.n as i32);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user