@@ -1997,6 +1997,16 @@ fn semaAccessFieldName(c: *cy.Chunk, rec_n: *ast.Node, rec: ExprResult, name: []
19971997 const mod = type_ .sym ().getMod ();
19981998
19991999 const sym = mod .getSym (name ) orelse {
2000+ if (type_ .has_embeddings ()) {
2001+ if (try get_embedded_sym (c , type_ .cast (.struct_t ), name , @ptrCast (field ))) | embedded_res | {
2002+ if (embedded_res .sym .type == .field ) {
2003+ const embedded_field = embedded_res .sym .cast (.field );
2004+ const final_rec = try semaField (c , rec , @ptrCast (field ), embedded_res .field_idx , embedded_res .embedded_t , @ptrCast (field ));
2005+ return semaField (c , final_rec , @ptrCast (field ), embedded_field .idx , embedded_field .type , @ptrCast (field ));
2006+ }
2007+ }
2008+ }
2009+
20002010 // TODO: This depends on @get being known, make sure @get is a nested declaration.
20012011
20022012 if (mod .getSym ("@get" )) | get_sym | {
@@ -4952,16 +4962,21 @@ pub fn lookupIdent(self: *cy.Chunk, name: []const u8, node: *ast.Node) !LookupId
49524962 return LookupIdentResult {
49534963 .capture = id ,
49544964 };
4955- } else {
4956- const res = (try lookupStaticIdent (self , name , node )) orelse {
4957- const resolve_ctx_idx = self .resolve_stack .items .len -1 ;
4958- const ctx = self .resolve_stack .items [resolve_ctx_idx ];
4959- const search_c = ctx .chunk ;
4960- _ = search_c ;
4961- return self .reportErrorFmt ("Undeclared variable `{}`." , &.{v (name )}, node );
4962- };
4965+ }
4966+
4967+ if (try lookupStaticIdent (self , name , node )) | res | {
49634968 return res ;
49644969 }
4970+
4971+ if (self .cur_sema_proc .isMethodBlock ) {
4972+ const base_t = self .cur_sema_proc .func .? .sig .params ()[0 ].get_type ().getBaseType ();
4973+ if (base_t .sym ().getMod ().getSym (name )) | sym | {
4974+ if (sym .type == .field ) {
4975+ return self .reportErrorFmt ("Expected explicit `${}` or `self.{}`." , &.{v (name ), v (name )}, node );
4976+ }
4977+ }
4978+ }
4979+ return self .reportErrorFmt ("Undeclared variable `{}`." , &.{v (name )}, node );
49654980}
49664981
49674982pub fn lookupStaticIdent (c : * cy.Chunk , name : []const u8 , node : * ast.Node ) ! ? LookupIdentResult {
@@ -7365,6 +7380,27 @@ pub fn semaExprNoCheck(c: *cy.Chunk, node: *ast.Node, cstr: Cstr) anyerror!ExprR
73657380 }
73667381}
73677382
7383+ const EmbeddedResult = struct {
7384+ field_idx : usize ,
7385+ embedded_t : * cy.Type ,
7386+ sym : * cy.Sym ,
7387+ };
7388+
7389+ fn get_embedded_sym (c : * cy.Chunk , rec_t : * cy.types.Struct , name : []const u8 , node : * ast.Node ) ! ? EmbeddedResult {
7390+ const fields = rec_t .getEmbeddedFields ();
7391+ for (fields ) | field | {
7392+ if (try c .getResolvedSym (& field .embedded_type .sym ().head , name , node )) | embedded_sym | {
7393+ // TODO: Cache result into the receiver type's module as a `EmbeddedField`.
7394+ return .{
7395+ .field_idx = field .field_idx ,
7396+ .embedded_t = field .embedded_type ,
7397+ .sym = embedded_sym ,
7398+ };
7399+ }
7400+ }
7401+ return null ;
7402+ }
7403+
73687404pub fn semaCallExpr (c : * cy.Chunk , node : * ast.Node , opt_target : ? * cy.Type ) ! ExprResult {
73697405 const call = node .cast (.callExpr );
73707406 if (call .hasNamedArg ) {
@@ -7373,7 +7409,7 @@ pub fn semaCallExpr(c: *cy.Chunk, node: *ast.Node, opt_target: ?*cy.Type) !ExprR
73737409
73747410 if (call .callee .type () == .accessExpr ) {
73757411 const callee = call .callee .cast (.accessExpr );
7376- const leftRes = try c .semaExprSkipSym (callee .left , .{});
7412+ var leftRes = try c .semaExprSkipSym (callee .left , .{});
73777413
73787414 const right_name = callee .right .name ();
73797415 if (leftRes .resType == .sym ) {
@@ -7385,7 +7421,18 @@ pub fn semaCallExpr(c: *cy.Chunk, node: *ast.Node, opt_target: ?*cy.Type) !ExprR
73857421
73867422 if (leftSym .isValue ()) {
73877423 // Look for sym under left type's module.
7388- const rightSym = try c .accessResolvedSymOrFail (leftRes .type , right_name , callee .right );
7424+ const rightSym = (try c .accessResolvedSym (leftRes .type , right_name , callee .right )) orelse b : {
7425+ if (leftRes .type .has_embeddings ()) {
7426+ if (try get_embedded_sym (c , leftRes .type .cast (.struct_t ), right_name , callee .right )) | embedded_res | {
7427+ leftRes = try semaField (c , leftRes , callee .right , embedded_res .field_idx , embedded_res .embedded_t , callee .right );
7428+ break :b embedded_res .sym ;
7429+ }
7430+ }
7431+ const type_name = try c .sema .allocTypeName (leftRes .type );
7432+ defer c .alloc .free (type_name );
7433+ return c .reportErrorFmt ("Can not find the symbol `{}` in `{}`." , &.{v (right_name ), v (type_name )}, callee .right );
7434+ };
7435+
73897436 if (rightSym .type == .func ) {
73907437 // Call method.
73917438 const func_sym = rightSym .cast (.func );
@@ -7408,7 +7455,17 @@ pub fn semaCallExpr(c: *cy.Chunk, node: *ast.Node, opt_target: ?*cy.Type) !ExprR
74087455 }
74097456 } else {
74107457 // Look for sym under left type's module.
7411- const rightSym = try c .accessResolvedSymOrFail (leftRes .type , right_name , callee .right );
7458+ const rightSym = (try c .accessResolvedSym (leftRes .type , right_name , callee .right )) orelse b : {
7459+ if (leftRes .type .has_embeddings ()) {
7460+ if (try get_embedded_sym (c , leftRes .type .cast (.struct_t ), right_name , callee .right )) | embedded_res | {
7461+ leftRes = try semaField (c , leftRes , callee .right , embedded_res .field_idx , embedded_res .embedded_t , callee .right );
7462+ break :b embedded_res .sym ;
7463+ }
7464+ }
7465+ const type_name = try c .sema .allocTypeName (leftRes .type );
7466+ defer c .alloc .free (type_name );
7467+ return c .reportErrorFmt ("Can not find the symbol `{}` in `{}`." , &.{v (right_name ), v (type_name )}, callee .right );
7468+ };
74127469
74137470 if (rightSym .type == .func ) {
74147471 return c .semaCallFuncSymRec (rightSym .cast (.func ), callee .left , leftRes , call .args .slice (), false , node );
0 commit comments