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.
Teach pattern matching involving "as" patterns to work properly in
function builders. The code almost handled this, but prematurely
prechecking expressions in patterns broke it.
Handle StmtCondition as part of SolutionApplicationTarget, so we can
generate constraints from it and rewrite directly as part of a solution,
rather than open-coding the operation in the function builder transform.
Use the generalized constraint generation and binding for patterns to
introduce support for if-let and if-case in function builders, handling
arbitrary patterns.
Part of function builder generalization, rdar://problem/50426203.
Rather than re-walk the pattern to create type bindings for the variables
that show up in the pattern, assign types to each of the variables as part
of constraint generation for the pattern. Only do this in contexts
where we will need the types, e.g., function builders.
This general notion of wiring up the types of variables that occur
within a pattern to the types in the produced pattern type is useful
outside of function builders, too.
Introduce support for initialized let/var declarations within function
builder closures, e.g.,
let (a, b) = c()
We generate constraints for the declarations as elsewhere, but the types of
the declared variables (a and b in this case) are bound to the type of the
pattern by one-way constraints, to describe the flow of type information
through the closure.
Implements rdar://problem/57330696.
When applying a function builder to a closure to produce the final,
type-checked closure, use the new rewriteTarget() so it’s performed on
a per-target basis. Use this to eliminate some duplicating in the handling
of return types.
if the closure had a function builder transform applied.
This way, function builder closures can have syntactic restrictions
diagnosed the same way as other expressions.
Fix a few related issues involving the interaction with
single-expression closures:
* A single-expression closure can have a "return" in it; in such
cases, disable the function-builder transform.
* Have the function builder constraint generator look through the
"return" statement in a single-expression closure the same way as
solution application does
Fixes rdar://problem/59045763, where we rejected some well-formed code
involving a single-expression closure with a "return" keyword.