mirror of https://github.com/icsharpcode/ILSpy.git
Tree:
51d3d3c6e3
christophwille/closedhierarchies
christophwille/membench
compound-assignment-operators
fix/1982-params-attribute-args
fix/2040-invalid-xml-characters
fix/2093-navigateto-reference-assembly
fix/2362-xalz-references
fix/2372-address-taken-by
fix/3282-indexer-optional-arguments
fix/3568-record-member-order
fix/4059-deconstruct-out-slots
fix/lambda-parameter-syntax
fix/scroll-children-on-expand
gh-pages
ldmembertoken
master
natural-type-lambdas-methods
null-coalescing-assignment
release/10.1
release/6.2
release/7.1
release/7.2
release/8.1
substring-optimizations
tests/829-async-method-builder-override
tests/829-collection-expressions
tests/829-compound-assignment-operators
tests/829-coverage-audit
tests/829-expression-tree-named-optional-args
tests/829-expression-variables-in-initializers
tests/829-extended-property-patterns
tests/829-extension-members
tests/829-extension-operators
tests/829-file-local-types
tests/829-improved-definite-assignment
tests/829-improved-overload-candidates
tests/829-inline-arrays
tests/829-interpolated-string-improvements
tests/829-lambda-param-modifiers
tests/829-list-patterns
tests/829-lock-object
tests/829-mixed-deconstruction
tests/829-null-coalescing-assignment
tests/829-null-conditional-assignment
tests/829-object-initializer-indexer
tests/829-overload-resolution-priority
tests/829-params-collections
tests/829-pattern-matching-improvements
tests/829-primary-constructors
tests/829-ref-unsafe-in-iterators-async
tests/829-sealed-record-tostring
tests/829-target-typed-conditional
tests/829-tuple-comparison
win-a11y-textsize
1.0-Beta
1.0-M1
1.0-M2
1.0-M3
1.0.0
2.0.0
2.1
2.2
2.3
2.3.1
3.0-Preview1
3.0-Preview2
3.0.2
v10.0
v10.0-preview1
v10.0-preview2
v10.0-preview3
v10.0.1
v10.1
v10.1.1
v11.0
v11.0-preview1
v11.0-rc
v2.3.2
v2.4
v3.0
v3.0-beta1
v3.0-beta2
v3.0-beta2a
v3.0-beta3
v3.0-beta4
v3.0.1
v3.1-beta1
v3.1-final
v3.1-rc
v3.2-beta
v3.2-rc
v3.2.0
v4.0
v4.0-alpha1
v4.0-beta1
v4.0-beta2
v4.0-beta3
v4.0-rc1
v4.0-rc2
v4.0.1
v5.0
v5.0-preview1
v5.0-preview2
v5.0-preview3
v5.0-preview4
v5.0-rc1
v5.0.1
v5.0.2
v6.0
v6.0-preview1
v6.0-preview2
v6.0-preview3
v6.0-preview4
v6.0-rc1
v6.1
v6.2
v6.2-preview1
v6.2-preview2
v6.2.1
v7.0
v7.0-preview1
v7.0-preview2
v7.0-preview3
v7.0-rc1
v7.0-rc2
v7.1
v7.2
v7.2-preview1
v7.2-preview2
v7.2-preview3
v7.2-preview4
v7.2-rc
v7.2.1
v8.0
v8.0-preview1
v8.0-preview2
v8.0-preview3
v8.0-preview4
v8.0-rc1
v8.1
v8.1.1
v8.2
v9.0
v9.0-preview1
v9.0-preview2
v9.0-preview3
v9.0-rc
v9.1
${ noResults }
1 Commits (51d3d3c6e3d6c5b847fd793f48b60a5d38ac7ead)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
d22d4301e4 |
Expand nested conditional operators back into if-else
HandleConditionalOperator collapses `if (c) a = x; else a = y;` into a conditional operator, innermost first, and keeps going for as long as the chain does. A source else-if ladder therefore comes back as one expression, however long it was: the sample in #2027 decompiles to a single 2095-character statement, and one NLog method to 2230 characters nested 29 brackets deep. ExpandNestedConditionals undoes that past one level, so a statement keeps at most a single conditional operator. It runs at the end of the pipeline rather than inside ExpressionTransforms, because every transform that needs its input to be a single expression has to see the collapsed form first: object and collection initializers, `with`, switch expressions, interpolated string handlers, and the query lambdas the C# stage later rewrites into clauses. Cutting the chain earlier leaves an if-else between the statements they pattern-match on and they silently stop matching - an object initializer assigning an init-only member then does not even compile. The same reasoning ReduceNestingTransform gives for walking back ConditionDetection's aggressive else-inlining once the structure is settled. A chain already stored to a variable is expanded into that variable, so nothing has to be decided: the variable carries its own type. A chain in any other position - an argument, a return value, a field store - has nothing to expand into, and ILExtraction can give it one. The temporary ILExtraction creates is typed from the stack type though, where `I4` is `int`, `bool`, `char` and every enum at once, so extracting on that basis turned a bool into `int num` with `if (num == 0)` and an enum into `dbType = (IsFixedLength ? 22 : 0)`. InferExpectedType is the counterpart to InferType that answers this: where InferType asks what a value is, it asks what the position the value flows into says it should be - a parameter, a return type, a field, all of which carry their type in metadata. Extraction is done only where that question has an answer, and the temporary is typed from it. The receiver of a call then reads `XPathNavigator xPathNavigator`, not `object obj` with a cast back, and a field store keeps its enum's member names. The Pretty fixture covers what must NOT change: an array initializer, a query lambda, a ref local, a switch expression, an object initializer with an init-only member, a `with` expression, a catch-when filter and both constructor-initializer forms. The positive case is an ILPretty test, because a Pretty fixture is its own input and expected output, and a chain that round-trips through collapse and expansion has no fixed point there. The PdbGen test records the cost in breakpoints: the compiler's single sequence point for the collapsed statement becomes one per expanded statement, which is inherent to splitting a statement in two. #2027 Assisted-by: Claude:claude-opus-5:Claude Code |
2 weeks ago |