@@ -545,7 +545,6 @@ and has = {
545545}
546546and builder = (~input : val , ~selfSchema : internal ) => val
547547and val = {
548- mutable prev ?: val ,
549548 // We might have the same value, but different instances of the val object
550549 // Use the bond field, to connect the var call
551550 @as ("b" )
@@ -556,14 +555,15 @@ and val = {
556555 mutable var : unit => string ,
557556 @as ("i" )
558557 mutable inline : string ,
559- @as ("f" )
560- mutable flag : flag ,
561558 // The schema of the value that is being parsed
562559 @as ("s" )
563560 mutable schema : internal ,
564561 // The schema of the value that we expect to parse into
565562 @as ("e" )
566563 mutable expected : internal ,
564+ mutable prev ?: val ,
565+ @as ("f" )
566+ mutable flag : flag ,
567567 @as ("k" )
568568 mutable skipTo ?: bool ,
569569 @as ("d" )
@@ -1306,39 +1306,6 @@ module Builder = {
13061306 )
13071307 }
13081308
1309- let refineInPlace = (val : val , ~schema , ~validation ) => {
1310- // if val.prev !== None {
1311- // let inputVar = val.var()
1312- // if val.varsAllocation !== "" {
1313- // val.codeAfterValidation = val.codeAfterValidation ++ `let ${val.varsAllocation};`
1314- // val.varsAllocation = ""
1315- // val.allocate = initialAllocate
1316- // }
1317- // val.codeAfterValidation =
1318- // val.codeAfterValidation ++
1319- // `if(${validation(~inputVar, ~negative=true)}){${embedInvalidInput(
1320- // ~input=val,
1321- // ~expected=val.expected,
1322- // )}}`
1323- // } else {
1324-
1325- let prevValidation = val .validation
1326- val .validation = Some (
1327- (~inputVar , ~negative ) => {
1328- {
1329- switch prevValidation {
1330- | Some (prevValidation ) => prevValidation (~inputVar , ~negative ) ++ and_ (~negative )
1331- | None => ""
1332- }
1333- } ++
1334- validation (~inputVar , ~negative )
1335- },
1336- )
1337-
1338- // }
1339- val .schema = schema
1340- }
1341-
13421309 let next = (prev : val , initial : string , ~schema , ~expected = prev .expected ): val => {
13431310 {
13441311 // FIXME: vals and other object.val fields should be copied
@@ -2091,7 +2058,7 @@ let rec parse = (input: val, ~withEncoder: bool=false) => {
20912058 switch output .contents .expected {
20922059 | {parser } => output := parser (~input = output .contents , ~selfSchema = output .contents .expected )
20932060 | _ =>
2094- switch output .contents .expected .encoder {
2061+ switch output .contents .schema .encoder {
20952062 | Some (encoder ) if to .tag !== unknownTag =>
20962063 output := encoder (~input = output .contents , ~selfSchema = to )
20972064 | _ => ()
@@ -2421,6 +2388,7 @@ let rec makeObjectVal = (prev: val, ~schema): B.Val.Object.t => {
24212388 },
24222389 expected : prev .expected ,
24232390 vals : Js .Dict .empty (),
2391+ hasTransform : true ,
24242392 codeFromPrev : "" ,
24252393 codeAfterValidation : "" ,
24262394 varsAllocation : "" ,
@@ -2439,6 +2407,7 @@ and array = item => {
24392407 mut -> castToPublic
24402408}
24412409and arrayDecoder : builder = (~input as unknownInput , ~selfSchema as _ ) => {
2410+ let isUnion = unknownInput .isUnion -> X .Option .getUnsafe
24422411 let expectedSchema = unknownInput .expected
24432412 let unknownInputTagFlag = unknownInput .schema .tag -> TagFlag .get
24442413 let expectedItems = expectedSchema .items -> X .Option .getUnsafe
@@ -2477,7 +2446,9 @@ and arrayDecoder: builder = (~input as unknownInput, ~selfSchema as _) => {
24772446 }
24782447 switch validation .contents {
24792448 | Some (validation ) => unknownInput -> B .refine (~schema , ~validation )
2480- | None => unknownInput
2449+ // Apply refine also here,
2450+ // so literals for union cases don't mutate input
2451+ | None => unknownInput -> B .refine
24812452 }
24822453 } else {
24832454 unknownInput -> B .unsupportedConversion (~from = unknownInput .schema , ~target = expectedSchema )
@@ -2523,8 +2494,6 @@ and arrayDecoder: builder = (~input as unknownInput, ~selfSchema as _) => {
25232494 }
25242495 }
25252496 | _ =>
2526- let isUnion = input .isUnion -> X .Option .getUnsafe
2527-
25282497 let objectVal = input -> makeObjectVal (~schema = expectedSchema )
25292498 let shouldRecreateInput = ref (
25302499 switch expectedSchema .additionalItems -> X .Option .getUnsafe {
@@ -2549,19 +2518,20 @@ and arrayDecoder: builder = (~input as unknownInput, ~selfSchema as _) => {
25492518
25502519 switch itemOutput .validation {
25512520 | Some (validation ) if isUnion && schema -> isLiteral =>
2552- let _ = input -> B .refineInPlace (~schema = input .schema , ~validation = (~inputVar , ~negative ) => {
2553- validation (
2554- ~inputVar = inputVar ++ input .global -> B .inlineLocation (key )-> Path .fromInlinedLocation ,
2555- ~negative ,
2556- )
2557- })
2521+ input .validation =
2522+ input .validation -> B .appendValidation ((~inputVar , ~negative ) => {
2523+ validation (
2524+ ~inputVar = inputVar ++ input .global -> B .inlineLocation (key )-> Path .fromInlinedLocation ,
2525+ ~negative ,
2526+ )
2527+ })
25582528 itemOutput .validation = None
25592529 | _ => ()
25602530 }
25612531
25622532 objectVal -> B .Val .Object .add (~location = key , itemOutput )
25632533 if ! shouldRecreateInput .contents {
2564- shouldRecreateInput := itemOutput !== itemInput
2534+ shouldRecreateInput := itemOutput . hasTransform -> X . Option . getUnsafe
25652535 }
25662536 }
25672537
@@ -2578,6 +2548,7 @@ and arrayDecoder: builder = (~input as unknownInput, ~selfSchema as _) => {
25782548 }
25792549}
25802550and objectDecoder : Builder .t = (~input as unknownInput , ~selfSchema as _ ) => {
2551+ let isUnion = unknownInput .isUnion -> X .Option .getUnsafe
25812552 let expectedSchema = unknownInput .expected
25822553 let unknownInputTagFlag = unknownInput .schema .tag -> TagFlag .get
25832554
@@ -2613,7 +2584,9 @@ and objectDecoder: Builder.t = (~input as unknownInput, ~selfSchema as _) => {
26132584
26142585 switch validation .contents {
26152586 | Some (validation ) => unknownInput -> B .refine (~schema , ~validation )
2616- | None => unknownInput
2587+ // Apply refine also here,
2588+ // so literals for union cases don't mutate input
2589+ | None => unknownInput -> B .refine
26172590 }
26182591 } else {
26192592 unknownInput -> B .unsupportedConversion (~from = unknownInput .schema , ~target = expectedSchema )
@@ -2661,8 +2634,6 @@ and objectDecoder: Builder.t = (~input as unknownInput, ~selfSchema as _) => {
26612634 }
26622635 }
26632636 | _ => {
2664- let isUnion = input .isUnion -> X .Option .getUnsafe
2665-
26662637 let properties = expectedSchema .properties -> X .Option .getUnsafe
26672638 let keys = Js .Dict .keys (properties )
26682639 let keysCount = keys -> Js .Array2 .length
@@ -2694,22 +2665,20 @@ and objectDecoder: Builder.t = (~input as unknownInput, ~selfSchema as _) => {
26942665
26952666 switch itemOutput .validation {
26962667 | Some (validation ) if isUnion && schema -> isLiteral =>
2697- let _ = input -> B .refineInPlace (~schema = input .schema , ~validation = (
2698- ~inputVar ,
2699- ~negative ,
2700- ) => {
2701- validation (
2702- ~inputVar = inputVar ++ input .global -> B .inlineLocation (key )-> Path .fromInlinedLocation ,
2703- ~negative ,
2704- )
2705- })
2668+ input .validation =
2669+ input .validation -> B .appendValidation ((~inputVar , ~negative ) => {
2670+ validation (
2671+ ~inputVar = inputVar ++ input .global -> B .inlineLocation (key )-> Path .fromInlinedLocation ,
2672+ ~negative ,
2673+ )
2674+ })
27062675 itemOutput .validation = None
27072676 | _ => ()
27082677 }
27092678
27102679 objectVal -> B .Val .Object .add (~location = key , itemOutput )
27112680 if ! shouldRecreateInput .contents {
2712- shouldRecreateInput := itemOutput !== itemInput
2681+ shouldRecreateInput := itemOutput . hasTransform -> X . Option . getUnsafe
27132682 }
27142683 }
27152684
@@ -3349,7 +3318,12 @@ module Union = {
33493318
33503319 switch val .validation {
33513320 | Some (validation ) =>
3352- if val .hasTransform !== Some (true ) {
3321+ if (
3322+ val .hasTransform === Some (true )
3323+ ? (val .prev -> X .Option .getUnsafe ).hasTransform !== Some (true ) &&
3324+ val .codeFromPrev === ""
3325+ : true
3326+ ) {
33533327 // Validation must be used only when there's a prev value
33543328 let input = current .contents -> X .Option .getUnsafe
33553329 let inputVar = input .var ()
@@ -3511,12 +3485,13 @@ module Union = {
35113485 itemStart :=
35123486 itemStart .contents ++ if_ ++ ` (!(${itemNoop.contents})){${fail(caught.contents)}}`
35133487 } else {
3514- let _ = typeValidationOutput -> B .refineInPlace (
3515- ~schema = typeValidationOutput .schema ,
3516- ~validation = (~inputVar as _ , ~negative ) => {
3488+ typeValidationOutput .validation =
3489+ typeValidationOutput .validation -> B .appendValidation ((
3490+ ~inputVar as _ ,
3491+ ~negative ,
3492+ ) => {
35173493 ` ${B.exp(~negative)}(${itemNoop.contents})`
3518- },
3519- )
3494+ })
35203495 }
35213496 } else if withExhaustiveCheck .contents {
35223497 let errorCode = fail (caught .contents )
@@ -3652,16 +3627,23 @@ module Union = {
36523627 ],
36533628 )
36543629
3655- if (
3656- typeValidationInput .validation !== None || (
3657- typeValidationOutput .hasTransform === Some (true )
3658- ? typeValidationOutput .codeFromPrev === "" &&
3659- (typeValidationOutput .prev -> X .Option .getUnsafe ).hasTransform !== Some (true )
3660- : typeValidationOutput .validation !== None
3630+ let shouldDeopt = ref (true )
3631+ let valRef = ref (Some (typeValidationOutput ))
3632+ while valRef .contents !== None && shouldDeopt .contents {
3633+ let v = valRef .contents -> X .Option .getUnsafe
3634+ valRef := v .prev
3635+ shouldDeopt :=
3636+ ! (
3637+ v .validation !== None && (
3638+ v .hasTransform === Some (true )
3639+ ? (v .prev -> X .Option .getUnsafe ).hasTransform !== Some (true ) &&
3640+ v .codeFromPrev === ""
3641+ : true
3642+ )
36613643 )
3662- ) {
3663- ()
3664- } else {
3644+ }
3645+
3646+ if shouldDeopt . contents {
36653647 for keyIdx in 0 to keys .contents -> Stdlib .Array .length - 1 {
36663648 let key = keys .contents -> Stdlib .Array .getUnsafe (keyIdx )
36673649 if ! exit .contents {
@@ -3717,7 +3699,12 @@ module Union = {
37173699
37183700 switch val .validation {
37193701 | Some (validation ) =>
3720- if val .hasTransform !== Some (true ) {
3702+ if (
3703+ val .hasTransform === Some (true )
3704+ ? (val .prev -> X .Option .getUnsafe ).hasTransform !== Some (true ) &&
3705+ val .codeFromPrev === ""
3706+ : true
3707+ ) {
37213708 // Validation must be used only when there's a prev value
37223709 let input = current .contents -> X .Option .getUnsafe
37233710 let inputVar = input .var ()
0 commit comments