If there are no 'case' statements in the body let's try
to diagnose this situation via limited exhaustiveness check
before failing a builder transform, otherwise type-checker
might end up without any diagnostics which leads to crashes
in SILGen.
Resolves: rdar://problem/65983237
We used to apply builder transforms to regular
functions without using a constraint system,
which is what the assertion is primarily geared
towards. However we now use a constraint system
for such cases, with the lack of a constraint
system only being used to check if we can even
apply the transform in the first place.
The use of "if #available" in function builders can subvert availability
checking if the function builder carries all type information for the
values within the "then" block outside of the "else" block. Tighten up
the model in two ways:
* Check whether the type coming out of an "if #available" references
any declarations that are not available in the outer context, to close
up the model.
* If the function builder provides a buildLimitedAvailability(_:)
operation, call that on the result of the "then" block in an "if
that it cannot leak out of the "if #available"; if it doesn't, the
check above will still fire.
Stage this in with a warning so function builders out there in the wild
can adapt. We'll upgrade the warning to an error later.
Fixes rdar://problem/65021017.
`PreCheckFunctionBuilderRequest` applies `PreCheckExpression` to the
expressions inside the function body. Previously it used to receive only
`AnyFunctionRef` (`FunctionDecl` or `ClosureExpr`) as the parameter.
However, when fast-completion kicks-in, it replaces the body of the
function, then tries to call `PreCheckFunctionBuilderRequest` again, with
the same function decl as before. It used to return cached "Success"
result, but it didn't actually apply `PreCheckExpression`. So any
`UnresolvedDeclRefExpr` remained unresolved.
In this patch, make `PreCheckFunctionBuilderRequest` receive "body" of the
function as well, so it doesn't return the cached result for the *previous*
body.
rdar://problem/65692922
Before 09db2902d2, the function builder
transform used to try to detect when the builder type wasn't fully
resolved. In such a case, rather than fail the solution set as we do
currently, it would construct a null TypeLoc, then stash the type-
variable-laden builder type inside of a TypeExpr and rely on CSGen
to reinterpret that as a request to read the stashed type as it was
constructing the rest of the system. This used to rely on the ability to construct
an implicit TypeExpr node with a null type but now such a thing is
banned by the TypeExpr interface.
Instead, we have to detect this case and construct an *explicit*
TypeExpr node pointing to all the usual fake data. This node's type will
be used to resolve the build* member, but the final applied type of the
node will be the builder type we stashed earlier - hopefully with
outstanding type variables solved.
rdar://65116204
When a function body has had a function builder applied to it, make
sure that we run all of the syntactic diagnostics for expressions and
statements within the body.
Fixes rdar://problem/64493626.
Generalize the code used to generate constraints and apply solutions to
PatternBindingDecls so that it is handled directly by the constaint
system and solution, respectively, rather than as part of the function
builder transform. No functionality change, but this is a cleaner
abstraction.
Rather than storing the record of each pattern binding entry's solution
application targets as part of an applied function builder, store them
within the constraint system and solution using a newly-generalized
form of SolutionApplicationTargetsKey.
Introduce a new predicate, shouldTypeCheckInEnclosingExpression(), to
determine when the body of a closure should be checked as part of the
enclosing expression rather than separately, and use it in the various
places where "hasSingleExpressionBody()" was used for that purpose.
Rather than passing the result of buildBlock() into buildDo(), follow
the (better) design from the function builders pitch by passing in the
components from the block directly into buildDo(). This means that
buildDo() will need to take separate parameters for each component,
but allows buildDo() to treat the components separately.
Allow a protocol requirement for a function or property to declare
a function builder. A witness to such a protocol requirement will
infer that function builder when all of the following are two:
* The witness does not explicitly adopt a function builder
* The witness is declared within the same context that conforms to the
protocol requirement (e.g., same extension or primary type declaration)
* The witness's body does not contain a "return" statement (since those
disable the function builder transform).
Annotate the covered switches with `llvm_unreachable` to avoid the MSVC
warning which does not recognise the covered switches. This allows us
to avoid a spew of warnings.
that allows arbitrary `label: {}` suffixes after an initial
unlabeled closure.
Type-checking is not yet correct, as well as code-completion
and other kinds of tooling.
Accept trailing closures in following form:
```swift
foo {
<label-1>: { ... }
<label-2>: { ... }
...
<label-N>: { ... }
}
```
Consider each labeled block to be a regular argument to a call or subscript,
so the result of parser looks like this:
```swift
foo(<label-1>: { ... }, ..., <label-N>: { ... })
```
Note that in this example parens surrounding parameter list are implicit
and for the cases when they are given by the user e.g.
```swift
foo(bar) {
<label-1>: { ... }
...
}
```
location of `)` is changed to a location of `}` to make sure that call
"covers" all of the transformed arguments and parser result would look
like this:
```swift
foo(bar,
<label-1>: { ... }
)
```
Resolves: rdar://problem/59203764
Extend function builders with support for for..in loops, such as
for person in contacts {
"Hello \(person.name)"
}
The loop will be (eagerly) executed and all results will be collected
into an array. That array will be passed to a function `buildArray` to
produce the result from the loop. Specifically, the above will be
translated to the following when used with a function builder type
named `FunctionBuilder`,, where all $ names are introduced by the
compiler and are not user-visible:
let $a1: $T1
var $a2: [$T2] = []
for person in contacts {
let $a3: $T3
let $a4 = FunctionBuilder.buildExpression("Hello \(person.name)")
$a3 = FunctionBuilder.buildBlock($a4)
$a2.append($3)
}
$a1 = FunctionBuilder.buildArray($a2)
where `$a1` is the result of the for-each loop.
Remove duplication in the modeling of TypeExpr. The type of a TypeExpr
node is always a metatype corresponding to the contextual
type of the type it's referencing. For some reason, the instance type
was also stored in this TypeLoc at random points in semantic analysis.
Under the assumption that this instance type is always going to be the
instance type of the contextual type of the expression, introduce
a number of simplifications:
1) Explicit TypeExpr nodes must be created with a TypeRepr node
2) Implicit TypeExpr nodes must be created with a contextual type
3) The typing rules for implicit TypeExpr simply opens this type
Like switch cases, a catch clause may now include a comma-
separated list of patterns. The body will be executed if any
one of those patterns is matched.
This patch replaces `CatchStmt` with `CaseStmt` as the children
of `DoCatchStmt` in the AST. This necessitates a number of changes
throughout the compiler, including:
- Parser & libsyntax support for the new syntax and AST structure
- Typechecking of multi-pattern catches, including those which
contain bindings.
- SILGen support
- Code completion updates
- Profiler updates
- Name lookup changes
A request is intended to be a pure function of its inputs. That function could, in theory, fail. In practice, there were basically no requests taking advantage of this ability - the few that were using it to explicitly detect cycles can just return reasonable defaults instead of forwarding the error on up the stack.
This is because cycles are checked by *the Evaluator*, and are unwound by the Evaluator.
Therefore, restore the idea that the evaluate functions are themselves pure, but keep the idea that *evaluation* of those requests may fail. This model enables the best of both worlds: we not only keep the evaluator flexible enough to handle future use cases like cancellation and diagnostic invalidation, but also request-based dependencies using the values computed at the evaluation points. These aforementioned use cases would use the llvm::Expected interface and the regular evaluation-point interface respectively.
When present in a function builder, buildFinalResult() will be called on
the value of the outermost block to form the final result of the closure.
This allows one to collapse the full function builder computation into
a single result without having to do it in each buildBlock() call.
The normal type checking of switch statements checks the switch subject
first, without context, then evaluates the cases. Introduce a one-way
constraint into the type checking of switch statements within function
builders to provide this same behavior. The difference can be observed
in code such as:
enum E {
case a
case b(Int, String?)
}
enum E2 {
case b(Int, String?)
}
func getSomeEnumOverloaded(_: Double) -> E { return .a }
func getSomeEnumOverloaded(_: Int) -> E2 { return .b(0, nil) }
func f() {
switch getSomeEnumOverloaded(17) {
case .a: // error: no member named "a" in E2
print("a")
default:
print("default")
}
}
When the subject expression `getSomeEnumOverloaded(17)` is resolved
without consider cases, it will select the second
`getSomeEnumOverloaded(_:)`, because the literal 17 prefers to be
an `Int`. The type checking of the first case would then fail because E2
does not contain a member named "a".
Prior to this change, the same expression within a function
builder would succeed in type checking, because the lack of case named
"a" within "E2" would make the second getSomeEnumOverloaded() unusable.
Making this code work by considering the cases along with the subject
expression is not unreasonable, and may be the right long term
direction for the language. However, it's a feature that should be
discussed separately, and the semantics should agree between function
builders and normal statements.
Big thanks to John McCall for noting the missing one-way constraint!
Implement support for switch statements within function builders. Cases can
perform arbitrary pattern matches, e.g.,
tuplify(true) { c in
"testSwitchCombined"
switch e {
case .a:
"a"
case .b(let i, _?), .b(let i, nil):
i + 17
}
}
subject to the normal rules of switch statements. Cases within function
builders cannot, however, include “fallthrough” statements, because those
(like “break” and “continue”) are control flow.
The translation of performed for `switch` statements is similar to that of
`if` statements, using `buildEither(first:)` and `buildEither(second:)` on
the function builder type.
This is the bulk of switch support, tracked by rdar://problem/50426203.