diff --git a/src/typing/fields.ml b/src/typing/fields.ml index 913f92d5f91..32b551e81ce 100644 --- a/src/typing/fields.ml +++ b/src/typing/fields.ml @@ -655,7 +655,7 @@ let get_struct_init_anon_fields c tl = | TFun (args,_) -> Some (match cf.cf_expr with | Some { eexpr = TFunction fn } -> - List.map (fun (name,_,t) -> + List.map (fun (name,opt,t) -> let t = apply_params c.cl_params tl t in let p = try let v,_ = List.find (fun (v,_) -> v.v_name = name) fn.tf_args in @@ -663,17 +663,17 @@ let get_struct_init_anon_fields c tl = with Not_found -> cf.cf_name_pos in - name,t,p,extract_param_info name + name,opt,t,p,extract_param_info name ) args | _ -> List.map - (fun (name,_,t) -> + (fun (name,opt,t) -> let t = apply_params c.cl_params tl t in try let cf = PMap.find name c.cl_fields in - name,t,cf.cf_name_pos,gen_doc_text_opt cf.cf_doc + name,opt,t,cf.cf_name_pos,gen_doc_text_opt cf.cf_doc with Not_found -> - name,t,cf.cf_name_pos,extract_param_info name + name,opt,t,cf.cf_name_pos,extract_param_info name ) args ) | _ -> None @@ -682,8 +682,9 @@ let get_struct_init_anon_fields c tl = in match args with | Some args -> - List.fold_left (fun fields (name,t,p,doc) -> + List.fold_left (fun fields (name,opt,t,p,doc) -> let cf = mk_field name t p p in + if opt then cf.cf_meta <- [(Meta.Optional,[],null_pos)]; cf.cf_doc <- (doc_from_string_opt doc); PMap.add cf.cf_name cf fields ) PMap.empty args diff --git a/src/typing/typer.ml b/src/typing/typer.ml index 8c446e662f0..11c4386d756 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -786,6 +786,10 @@ and type_object_decl ctx fl with_type p = let fields = List.fold_left (fun acc ((n,opt,t),parg) -> let f = mk_field n t parg parg in if opt then f.cf_meta <- [(Meta.Optional,[],null_pos)]; + (try + let cf = PMap.find n c.cl_fields in + f.cf_doc <- cf.cf_doc + with Not_found -> ()); PMap.add n f acc ) PMap.empty args in let t,fl = type_fields fields in diff --git a/tests/server/src/cases/display/StructInit.hx b/tests/server/src/cases/display/StructInit.hx new file mode 100644 index 00000000000..7452ddf2501 --- /dev/null +++ b/tests/server/src/cases/display/StructInit.hx @@ -0,0 +1,133 @@ +package cases.display; + +class StructInit extends DisplayTestCase { + /** + @:structInit + class Foo { + var a:Int = null; + var b:Int; + } + class Main { + static function main() { + var foo:Foo = {{-1-} + } + } + **/ + function testRequiredAndOptionalFields(_) { + final fields = fields(1); + eq(true, hasField(fields, "a", "Null")); + eq(true, hasField(fields, "b", "Int")); + } + + /** + @:structInit + class Foo { + var a:Int = null; + var b:Int; + } + typedef Foo2 = { + ?a:Int, + b:Int, + } + class Main { + static function main() { + var foo:Foo = {{-1-}} + var foo2:Foo2 = {{-2-} + } + } + **/ + function testStructInitVsTypedef() { + // structInit: optional (a) and required (b) both present + final classFields = fields(1); + eq(true, hasField(classFields, "a", "Null")); + eq(true, hasField(classFields, "b", "Int")); + // typedef: same fields also present + final typedefFields = fields(2); + eq(true, hasField(typedefFields, "a", "Null")); + eq(true, hasField(typedefFields, "b", "Int")); + } + + /** + @:structInit + class Doc { + /** doctor doc **\/ + public var doctor:Int; + } + class Main { + static function main() { + final v:Doc = { + doc{-1-}tor: 1 + }; + } + } + **/ + function testFieldHoverDoc() { + eq("doctor doc", doc(1)); + } + + /** + @:structInit + class MultiDoc { + /** field a **\/ + public var a:Int; + /** field b **\/ + public var b:String; + } + class Main { + static function main() { + var v:MultiDoc = { + a{-1-}: 1, + b{-2-}: "x" + }; + } + } + **/ + function testMultiFieldHoverDoc() { + eq("field a", doc(1)); + eq("field b", doc(2)); + } + + /** + @:structInit + class Foo { + var b:Int; + var a:Int; + var z:Int; + var d:Int; + } + class Main { + static function main() { + var foo:Foo = {{-1-}}; + } + } + **/ + function testFieldDeclarationOrder() { + final fields = fields(1); + eq(4, fields.length); + eq(true, isField(fields[0], "b", "Int")); + eq(true, isField(fields[1], "a", "Int")); + eq(true, isField(fields[2], "z", "Int")); + eq(true, isField(fields[3], "d", "Int")); + } + + /** + @:structInit + class Ordered { + var first:Int; + var second:String; + var third:Bool; + } + class Main { + static function main() { + var v:Ordered = {{-1-}}; + } + } + **/ + function testFieldDeclarationOrderMoreTypes() { + final fields = fields(1); + eq(3, fields.length); + eq(true, isField(fields[0], "first", "Int")); + eq(true, isField(fields[1], "second", "String")); + eq(true, isField(fields[2], "third", "Bool")); + } +}