@@ -132,52 +132,63 @@ func evaluateIfConfig(
132
132
}
133
133
134
134
// Evaluate the left-hand side.
135
- let ( lhsActive, lhssyntaxErrorsAllowed , lhsDiagnostics) = evaluateIfConfig (
135
+ let ( lhsActive, lhsSyntaxErrorsAllowed , lhsDiagnostics) = evaluateIfConfig (
136
136
condition: binOp. leftOperand,
137
137
configuration: configuration,
138
138
outermostCondition: false
139
139
)
140
140
141
- // Short-circuit evaluation if we know the answer and the left-hand side
142
- // was syntaxErrorsAllowed.
143
- if lhssyntaxErrorsAllowed {
144
- switch ( lhsActive , op . operator . text ) {
145
- case ( true , " || " ) :
146
- return (
147
- active : true ,
148
- syntaxErrorsAllowed : lhssyntaxErrorsAllowed ,
149
- diagnostics : extraDiagnostics + lhsDiagnostics
150
- )
151
- case ( false , " && " ) :
152
- return (
153
- active : false ,
154
- syntaxErrorsAllowed : lhssyntaxErrorsAllowed ,
155
- diagnostics : extraDiagnostics + lhsDiagnostics
156
- )
157
- default :
158
- break
159
- }
141
+ // Short-circuit evaluation if we know the answer. We still recurse into
142
+ // the right-hand side, but with a dummy configuration that won't have
143
+ // side effects, so we only get validation-related errors.
144
+ let shortCircuitResult : Bool ?
145
+ switch ( lhsActive , op . operator . text ) {
146
+ case ( true , " || " ) : shortCircuitResult = true
147
+ case ( false , " && " ) : shortCircuitResult = false
148
+ default : shortCircuitResult = nil
149
+ }
150
+
151
+ // If we are supposed to short-circuit and the left-hand side of this
152
+ // operator with inactive &&, stop now: we shouldn't evaluate the right-
153
+ // hand side at all.
154
+ if let isActive = shortCircuitResult , lhsSyntaxErrorsAllowed {
155
+ return (
156
+ active : isActive ,
157
+ syntaxErrorsAllowed : lhsSyntaxErrorsAllowed ,
158
+ diagnostics : extraDiagnostics + lhsDiagnostics
159
+ )
160
160
}
161
161
162
162
// Evaluate the right-hand side.
163
- let ( rhsActive, rhssyntaxErrorsAllowed, rhsDiagnostics) = evaluateIfConfig (
164
- condition: binOp. rightOperand,
165
- configuration: configuration,
166
- outermostCondition: false
167
- )
163
+ let rhsActive : Bool
164
+ let rhsSyntaxErrorsAllowed : Bool
165
+ let rhsDiagnostics : [ Diagnostic ]
166
+ if shortCircuitResult != nil {
167
+ ( rhsActive, rhsSyntaxErrorsAllowed, rhsDiagnostics) = evaluateIfConfig (
168
+ condition: binOp. rightOperand,
169
+ configuration: CanImportSuppressingBuildConfiguration ( other: configuration) ,
170
+ outermostCondition: false
171
+ )
172
+ } else {
173
+ ( rhsActive, rhsSyntaxErrorsAllowed, rhsDiagnostics) = evaluateIfConfig (
174
+ condition: binOp. rightOperand,
175
+ configuration: configuration,
176
+ outermostCondition: false
177
+ )
178
+ }
168
179
169
180
switch op. operator. text {
170
181
case " || " :
171
182
return (
172
183
active: lhsActive || rhsActive,
173
- syntaxErrorsAllowed: lhssyntaxErrorsAllowed && rhssyntaxErrorsAllowed ,
184
+ syntaxErrorsAllowed: lhsSyntaxErrorsAllowed && rhsSyntaxErrorsAllowed ,
174
185
diagnostics: extraDiagnostics + lhsDiagnostics + rhsDiagnostics
175
186
)
176
187
177
188
case " && " :
178
189
return (
179
190
active: lhsActive && rhsActive,
180
- syntaxErrorsAllowed: lhssyntaxErrorsAllowed || rhssyntaxErrorsAllowed ,
191
+ syntaxErrorsAllowed: lhsSyntaxErrorsAllowed || rhsSyntaxErrorsAllowed ,
181
192
diagnostics: extraDiagnostics + lhsDiagnostics + rhsDiagnostics
182
193
)
183
194
@@ -674,3 +685,55 @@ extension ExprSyntaxProtocol {
674
685
return false
675
686
}
676
687
}
688
+
689
+ /// Build configuration adaptor that suppresses calls to canImport, which
690
+ /// can have side effects. This is somewhat of a hack for the compiler.
691
+ private struct CanImportSuppressingBuildConfiguration < Other: BuildConfiguration > : BuildConfiguration {
692
+ var other : Other
693
+
694
+ func isCustomConditionSet( name: String ) throws -> Bool {
695
+ return try other. isCustomConditionSet ( name: name)
696
+ }
697
+
698
+ func hasFeature( name: String ) throws -> Bool {
699
+ return try other. hasFeature ( name: name)
700
+ }
701
+
702
+ func hasAttribute( name: String ) throws -> Bool {
703
+ return try other. hasAttribute ( name: name)
704
+ }
705
+
706
+ func canImport( importPath: [ String ] , version: CanImportVersion ) throws -> Bool {
707
+ return false
708
+ }
709
+
710
+ func isActiveTargetOS( name: String ) throws -> Bool {
711
+ return try other. isActiveTargetOS ( name: name)
712
+ }
713
+
714
+ func isActiveTargetArchitecture( name: String ) throws -> Bool {
715
+ return try other. isActiveTargetArchitecture ( name: name)
716
+ }
717
+
718
+ func isActiveTargetEnvironment( name: String ) throws -> Bool {
719
+ return try other. isActiveTargetEnvironment ( name: name)
720
+ }
721
+
722
+ func isActiveTargetRuntime( name: String ) throws -> Bool {
723
+ return try other. isActiveTargetRuntime ( name: name)
724
+ }
725
+
726
+ func isActiveTargetPointerAuthentication( name: String ) throws -> Bool {
727
+ return try other. isActiveTargetPointerAuthentication ( name: name)
728
+ }
729
+
730
+ var targetPointerBitWidth : Int { return other. targetPointerBitWidth }
731
+
732
+ var targetAtomicBitWidths : [ Int ] { return other. targetAtomicBitWidths }
733
+
734
+ var endianness : Endianness { return other. endianness }
735
+
736
+ var languageVersion : VersionTuple { return other. languageVersion }
737
+
738
+ var compilerVersion : VersionTuple { return other. compilerVersion }
739
+ }
0 commit comments