GOAL P0-2: Name(args){...} 로 제네릭 인스턴스를 짓는다

Name{...} 과 binding.Name{...} 만 있고 호출 뒤의 { 를 아무도 받지 않았다.
그래서 타입 인자를 명시한 리터럴이 파싱되지 않았고, 제네릭의 인스턴스는
Self{...} 나 생성자 함수로만 만들 수 있었다.

파서는 호출 뒤의 { 를 struct 리터럴로 받고, 체커는 그것을 타입 표기와 똑같은
resolver 에 넘긴다 -- 같은 철자니 같은 답이어야 한다. { 의 애매함은 이미
Name{...} 에 있던 것과 같고 같은 guard 가 정리한다.

  hold.Cell(i32){ v: 7 }        다른 유닛의 제네릭
  hold.Handle(Node){ raw: 3 }   본문에서 T 를 안 쓰는 것
  Boxed(i32){ v: 9 }            이 유닛의 제네릭

미사용 타입 파라미터는 그대로 둔다. typed handle 이 바로 그 모양이고,
Handle(Node) 와 Handle(Kind) 가 실제로 다른 타입이라는 것은 badphant 가
거부로 고정한다.

233/233, 34/34.
This commit is contained in:
2026-08-17 15:59:08 +09:00
parent dacf1e1b1b
commit 32da64d7c1
7 changed files with 118 additions and 1 deletions
+11
View File
@@ -249,6 +249,17 @@ FeType *check_struct_init(FeCheckerState *s, FeNode *n)
} else if (n->children) err(s->c,n->loc,"empty enum variant cannot have payload");
n->sem_type=et; return et;
}
if (n->a && n->a->kind==FE_N_CALL) {
/* `Name(args){...}` -- the same spelling a type annotation uses, so
the same resolver answers it. */
int ok=0;
t=type_from_expr(s,n->a,&ok);
if (!ok || !t || t->kind!=FE_TYPE_STRUCT) {
err(s->c,n->a->loc,"unknown struct type");
return unknown(s->c);
}
return check_struct_fields(s,n,t);
}
t=fe_type_intern(&s->c->types,n->text ? n->text : "<unknown>");
if (!t || t->kind!=FE_TYPE_STRUCT) { err(s->c,n->loc,"unknown struct type"); return unknown(s->c); }
return check_struct_fields(s,n,t);
+16 -1
View File
@@ -121,7 +121,22 @@ static FeNode *postfix(FeParser *p)
FeNode *n=primary(p);
for(;;) {
FeToken t=p->current; FeNode *m;
if(eat(p,FE_TOK_LPAREN)) { m=toknode(p,FE_N_CALL,t); m->a=n; while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(m,delimited_expr(p));if(!eat(p,FE_TOK_COMMA))break;} want(p,FE_TOK_RPAREN,"expected ')' after call"); n=m; }
if(eat(p,FE_TOK_LPAREN)) { m=toknode(p,FE_N_CALL,t); m->a=n; while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(m,delimited_expr(p));if(!eat(p,FE_TOK_COMMA))break;} want(p,FE_TOK_RPAREN,"expected ')' after call"); n=m;
/* `Name(args){...}` builds an instance of a generic struct. Without
this the arguments have nowhere to go and only `Self{...}` or a
constructor can name one. Same `{` ambiguity as `Name{...}`
above, and the same guard settles it. */
if(is(p,FE_TOK_LBRACE) && !p->forbid_struct_literal) {
FeNode *s=toknode(p,FE_N_STRUCT_INIT,t); s->a=n; next(p);
while(!is(p,FE_TOK_RBRACE)&&!is(p,FE_TOK_EOF)) { FeNode *f;
if(!is_name(p)){error(p,"expected field name");recover(p);break;}
f=toknode(p,FE_N_FIELD,p->current);next(p);
want(p,FE_TOK_COLON,"expected ':' after field");
f->a=expr(p,0);fe_node_add(s,f);
if(!eat(p,FE_TOK_COMMA))break;
}
want(p,FE_TOK_RBRACE,"expected '}' in struct literal"); n=s;
} }
else if(eat(p,FE_TOK_LBRACKET)) {
m=toknode(p,FE_N_INDEX,t);m->a=n;
if(is(p,FE_TOK_DOTDOT)) { m->b=0; m->flags|=FE_NODE_SLICE; } else m->b=delimited_expr(p);