@@ -2897,4 +2897,223 @@ _2 = a[1]
28972897
28982898 assert_eq ! ( ws. expr_ty( "after_assign" ) , ws. ty( "Foo|Bar" ) ) ;
28992899 }
2900+
2901+ #[ test]
2902+ fn test_issue_1048 ( ) {
2903+ let mut ws = VirtualWorkspace :: new ( ) ;
2904+
2905+ ws. def (
2906+ r#"
2907+ --- @alias RunMode 'run'|'skip'
2908+
2909+ --- @class Suite
2910+ --- @field result string?
2911+ --- @field mode RunMode
2912+
2913+ --- @param a string
2914+ function TestSuite(a) end
2915+ "# ,
2916+ ) ;
2917+ assert ! ( ws. has_no_diagnostic(
2918+ DiagnosticCode :: ParamTypeMismatch ,
2919+ r#"
2920+ --- @type Suite
2921+ local suite
2922+
2923+ suite.result = 'a'
2924+ if suite.mode == "run" then
2925+ TestSuite(suite.result)
2926+ end
2927+ "# ,
2928+ ) ) ;
2929+ }
2930+
2931+ #[ test]
2932+ fn test_discriminant_narrowed_sibling_field_keeps_prior_assignment_flow ( ) {
2933+ let mut ws = VirtualWorkspace :: new ( ) ;
2934+
2935+ ws. def (
2936+ r#"
2937+ ---@class A
2938+ ---@field type "point"
2939+ ---@field handle string?
2940+
2941+ ---@class B
2942+ ---@field type "unit"
2943+ ---@field handle integer?
2944+
2945+ ---@param a string
2946+ function testA(a) end
2947+ "# ,
2948+ ) ;
2949+ assert ! ( ws. has_no_diagnostic(
2950+ DiagnosticCode :: ParamTypeMismatch ,
2951+ r#"
2952+ ---@param target A | B
2953+ function test(target)
2954+ target.handle = "ready"
2955+ if target.type == "point" then
2956+ testA(target.handle)
2957+ end
2958+ end
2959+ "# ,
2960+ ) ) ;
2961+ }
2962+
2963+ #[ test]
2964+ fn test_discriminant_narrowed_sibling_field_keeps_prior_truthiness_flow ( ) {
2965+ let mut ws = VirtualWorkspace :: new ( ) ;
2966+
2967+ ws. def (
2968+ r#"
2969+ ---@class A
2970+ ---@field type "point"
2971+ ---@field handle string?
2972+
2973+ ---@class B
2974+ ---@field type "unit"
2975+ ---@field handle integer?
2976+
2977+ ---@param a string
2978+ function testA(a) end
2979+ "# ,
2980+ ) ;
2981+ assert ! ( ws. has_no_diagnostic(
2982+ DiagnosticCode :: ParamTypeMismatch ,
2983+ r#"
2984+ ---@param target A | B
2985+ function test(target)
2986+ if target.handle then
2987+ if target.type == "point" then
2988+ testA(target.handle)
2989+ end
2990+ end
2991+ end
2992+ "# ,
2993+ ) ) ;
2994+ }
2995+
2996+ #[ test]
2997+ fn test_discriminant_narrowed_sibling_field_keeps_prior_nil_guard_flow ( ) {
2998+ let mut ws = VirtualWorkspace :: new ( ) ;
2999+
3000+ ws. def (
3001+ r#"
3002+ ---@class A
3003+ ---@field type "point"
3004+ ---@field handle string?
3005+
3006+ ---@class B
3007+ ---@field type "unit"
3008+ ---@field handle integer?
3009+
3010+ ---@param a string
3011+ function testA(a) end
3012+ "# ,
3013+ ) ;
3014+ assert ! ( ws. has_no_diagnostic(
3015+ DiagnosticCode :: ParamTypeMismatch ,
3016+ r#"
3017+ ---@param target A | B
3018+ function test(target)
3019+ if target.handle ~= nil then
3020+ if target.type == "point" then
3021+ testA(target.handle)
3022+ end
3023+ end
3024+ end
3025+ "# ,
3026+ ) ) ;
3027+ }
3028+
3029+ #[ test]
3030+ fn test_discriminant_narrowed_sibling_field_keeps_prior_literal_guard_flow ( ) {
3031+ let mut ws = VirtualWorkspace :: new ( ) ;
3032+
3033+ ws. def (
3034+ r#"
3035+ ---@class A
3036+ ---@field type "point"
3037+ ---@field handle string?
3038+
3039+ ---@class B
3040+ ---@field type "unit"
3041+ ---@field handle integer?
3042+
3043+ ---@param a string
3044+ function testA(a) end
3045+ "# ,
3046+ ) ;
3047+ assert ! ( ws. has_no_diagnostic(
3048+ DiagnosticCode :: ParamTypeMismatch ,
3049+ r#"
3050+ ---@param target A | B
3051+ function test(target)
3052+ if target.handle == "ready" then
3053+ if target.type == "point" then
3054+ testA(target.handle)
3055+ end
3056+ end
3057+ end
3058+ "# ,
3059+ ) ) ;
3060+ }
3061+
3062+ #[ test]
3063+ fn test_discriminant_false_branch_all_members_match_is_never ( ) {
3064+ let mut ws = VirtualWorkspace :: new ( ) ;
3065+
3066+ ws. def (
3067+ r#"
3068+ ---@class A
3069+ ---@field kind "foo"
3070+
3071+ ---@class B
3072+ ---@field kind "foo"
3073+ "# ,
3074+ ) ;
3075+
3076+ ws. def (
3077+ r#"
3078+ ---@param target A | B
3079+ function test(target)
3080+ if target.kind ~= "foo" then
3081+ impossible = target
3082+ end
3083+ end
3084+ "# ,
3085+ ) ;
3086+
3087+ assert_eq ! ( ws. expr_ty( "impossible" ) , ws. ty( "never" ) ) ;
3088+ }
3089+
3090+ #[ test]
3091+ fn test_discriminant_sibling_projection_preserves_missing_member_nil ( ) {
3092+ let mut ws = VirtualWorkspace :: new ( ) ;
3093+
3094+ ws. def (
3095+ r#"
3096+ ---@class A
3097+ ---@field type "point"
3098+ ---@field handle string
3099+
3100+ ---@class C
3101+ ---@field type "point"
3102+
3103+ ---@param a string
3104+ function testA(a) end
3105+ "# ,
3106+ ) ;
3107+ assert ! ( !ws. has_no_diagnostic(
3108+ DiagnosticCode :: ParamTypeMismatch ,
3109+ r#"
3110+ ---@param target A | C
3111+ function test(target)
3112+ if target.type == "point" then
3113+ testA(target.handle)
3114+ end
3115+ end
3116+ "# ,
3117+ ) ) ;
3118+ }
29003119}
0 commit comments