mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #62734 from xedin/enable-result-builder-ast-transform-by-default-with-old-impl
[TypeChecker] Enable result builder AST transform by default
This commit is contained in:
@@ -1969,6 +1969,10 @@ public:
|
||||
getMutablePatternList()[i].setInit(E);
|
||||
}
|
||||
|
||||
void setOriginalInit(unsigned i, Expr *E) {
|
||||
getMutablePatternList()[i].setOriginalInit(E);
|
||||
}
|
||||
|
||||
Pattern *getPattern(unsigned i) const {
|
||||
return getPatternList()[i].getPattern();
|
||||
}
|
||||
|
||||
@@ -104,7 +104,6 @@ EXPERIMENTAL_FEATURE(FlowSensitiveConcurrencyCaptures, false)
|
||||
EXPERIMENTAL_FEATURE(MoveOnly, false)
|
||||
EXPERIMENTAL_FEATURE(OneWayClosureParameters, false)
|
||||
EXPERIMENTAL_FEATURE(TypeWitnessSystemInference, false)
|
||||
EXPERIMENTAL_FEATURE(ResultBuilderASTTransform, true)
|
||||
EXPERIMENTAL_FEATURE(LayoutPrespecialization, false)
|
||||
EXPERIMENTAL_FEATURE(ModuleInterfaceExportAs, true)
|
||||
|
||||
|
||||
@@ -6507,6 +6507,10 @@ public:
|
||||
Element->print(Out, SM, indent);
|
||||
}
|
||||
|
||||
/// Returns \c false if this conjunction element is known not to contain the
|
||||
/// code compleiton token.
|
||||
bool mightContainCodeCompletionToken(const ConstraintSystem &cs) const;
|
||||
|
||||
private:
|
||||
/// Find type variables referenced by this conjunction element.
|
||||
/// If this is a closure body element, it would look inside \c ASTNode.
|
||||
|
||||
@@ -3124,10 +3124,6 @@ static bool usesFeatureOneWayClosureParameters(Decl *decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool usesFeatureResultBuilderASTTransform(Decl *decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool usesFeatureTypeWitnessSystemInference(Decl *decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1529,6 +1529,7 @@ PatternBindingDecl *PatternBindingDecl::createImplicit(
|
||||
Pat, /*EqualLoc*/ SourceLoc(), nullptr, Parent);
|
||||
Result->setImplicit();
|
||||
Result->setInit(0, E);
|
||||
Result->setOriginalInit(0, E);
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ const USRBasedType *USRBasedType::fromType(Type Ty, USRBasedTypeArena &Arena) {
|
||||
Ty = Ty->getCanonicalType();
|
||||
|
||||
// For opaque types like 'some View', consider them equivalent to 'View'.
|
||||
if (auto OpaqueType = Ty->getAs<OpaqueTypeArchetypeType>()) {
|
||||
if (auto OpaqueType = Ty->getAs<ArchetypeType>()) {
|
||||
if (auto Existential = OpaqueType->getExistentialType()) {
|
||||
Ty = Existential;
|
||||
}
|
||||
|
||||
@@ -959,8 +959,8 @@ protected:
|
||||
VarDecl *captureExpr(Expr *expr, SmallVectorImpl<ASTNode> &container) {
|
||||
auto *var = builder.buildVar(expr->getStartLoc());
|
||||
Pattern *pattern = NamedPattern::createImplicit(ctx, var);
|
||||
auto *PB = PatternBindingDecl::createImplicit(ctx, StaticSpellingKind::None,
|
||||
pattern, expr, dc);
|
||||
auto *PB = PatternBindingDecl::createImplicit(
|
||||
ctx, StaticSpellingKind::None, pattern, expr, dc, var->getStartLoc());
|
||||
return recordVar(PB, container);
|
||||
}
|
||||
|
||||
@@ -972,7 +972,8 @@ protected:
|
||||
ctx, NamedPattern::createImplicit(ctx, var),
|
||||
type ? type : PlaceholderType::get(ctx, var));
|
||||
auto *PB = PatternBindingDecl::createImplicit(
|
||||
ctx, StaticSpellingKind::None, placeholder, /*init=*/initExpr, dc);
|
||||
ctx, StaticSpellingKind::None, placeholder, /*init=*/initExpr, dc,
|
||||
var->getStartLoc());
|
||||
return recordVar(PB, container);
|
||||
}
|
||||
|
||||
@@ -1058,11 +1059,20 @@ protected:
|
||||
{Identifier()});
|
||||
}
|
||||
|
||||
auto *capture = captureExpr(expr, newBody);
|
||||
// A reference to the synthesized variable is passed as an argument
|
||||
// to buildBlock.
|
||||
buildBlockArguments.push_back(
|
||||
builder.buildVarRef(capture, element.getStartLoc()));
|
||||
if (isa<CodeCompletionExpr>(expr)) {
|
||||
// Insert the CodeCompletionExpr directly into the buildBlock call. That
|
||||
// way, we can extract the contextual type of the code completion token
|
||||
// to rank code completion items that match the type expected by
|
||||
// buildBlock higher.
|
||||
buildBlockArguments.push_back(expr);
|
||||
} else {
|
||||
auto *capture = captureExpr(expr, newBody);
|
||||
// A reference to the synthesized variable is passed as an argument
|
||||
// to buildBlock.
|
||||
buildBlockArguments.push_back(
|
||||
builder.buildVarRef(capture, element.getStartLoc()));
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -2459,7 +2469,9 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
|
||||
return None;
|
||||
}
|
||||
|
||||
if (Context.LangOpts.hasFeature(Feature::ResultBuilderASTTransform)) {
|
||||
auto disableASTTransform = [&](NominalTypeDecl *builder) { return false; };
|
||||
|
||||
if (!disableASTTransform(builder)) {
|
||||
auto transformedBody = getBuilderTransformedBody(fn, builder);
|
||||
// If this builder transform has not yet been applied to this function,
|
||||
// let's do it and cache the result.
|
||||
@@ -2517,7 +2529,7 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
|
||||
auto &log = llvm::errs();
|
||||
auto indent = solverState ? solverState->getCurrentIndent() : 0;
|
||||
log.indent(indent) << "------- Transfomed Body -------\n";
|
||||
transformedBody->second->dump(log);
|
||||
transformedBody->second->dump(log, &getASTContext(), indent);
|
||||
log << '\n';
|
||||
}
|
||||
|
||||
|
||||
@@ -880,6 +880,17 @@ bool ConjunctionStep::attempt(const ConjunctionElement &element) {
|
||||
CS.Timer.emplace(element.getLocator(), CS);
|
||||
}
|
||||
|
||||
assert(!ModifiedOptions.hasValue() &&
|
||||
"Previously modified options should have been restored in resume");
|
||||
if (CS.isForCodeCompletion() &&
|
||||
!element.mightContainCodeCompletionToken(CS)) {
|
||||
ModifiedOptions.emplace(CS.Options);
|
||||
// If we know that this conjunction element doesn't contain the code
|
||||
// completion token, type check it in normal mode without any special
|
||||
// behavior that is intended for the code completion token.
|
||||
CS.Options -= ConstraintSystemFlags::ForCodeCompletion;
|
||||
}
|
||||
|
||||
auto success = element.attempt(CS);
|
||||
|
||||
// If element attempt has failed, mark whole conjunction
|
||||
@@ -891,6 +902,9 @@ bool ConjunctionStep::attempt(const ConjunctionElement &element) {
|
||||
}
|
||||
|
||||
StepResult ConjunctionStep::resume(bool prevFailed) {
|
||||
// Restore the old ConstraintSystemOptions if 'attempt' modified them.
|
||||
ModifiedOptions.reset();
|
||||
|
||||
// Return from the follow-up splitter step that
|
||||
// attempted to apply information gained from the
|
||||
// isolated constraint to the outer context.
|
||||
|
||||
@@ -966,6 +966,11 @@ class ConjunctionStep : public BindingStep<ConjunctionElementProducer> {
|
||||
/// in isolated mode.
|
||||
SmallVector<Solution, 4> IsolatedSolutions;
|
||||
|
||||
/// If \c ConjunctionStep::attempt modified the constraint system options,
|
||||
/// it will store the original options in this \c llvm::SaveAndRestore.
|
||||
/// Upon \c resume, these values will be restored.
|
||||
Optional<llvm::SaveAndRestore<ConstraintSystemOptions>> ModifiedOptions;
|
||||
|
||||
public:
|
||||
ConjunctionStep(ConstraintSystem &cs, Constraint *conjunction,
|
||||
SmallVectorImpl<Solution> &solutions)
|
||||
|
||||
@@ -1290,13 +1290,17 @@ public:
|
||||
virtual ~SyntacticElementSolutionApplication() {}
|
||||
|
||||
private:
|
||||
ASTNode visit(Stmt *S) {
|
||||
|
||||
ASTNode visit(Stmt *S, bool performSyntacticDiagnostics = true) {
|
||||
auto rewritten = ASTVisitor::visit(S);
|
||||
if (!rewritten)
|
||||
return {};
|
||||
|
||||
if (auto *stmt = getAsStmt(rewritten))
|
||||
performStmtDiagnostics(stmt, context.getAsDeclContext());
|
||||
if (performSyntacticDiagnostics) {
|
||||
if (auto *stmt = getAsStmt(rewritten)) {
|
||||
performStmtDiagnostics(stmt, context.getAsDeclContext());
|
||||
}
|
||||
}
|
||||
|
||||
return rewritten;
|
||||
}
|
||||
@@ -1819,8 +1823,9 @@ public:
|
||||
|
||||
private:
|
||||
ASTNode visitDoStmt(DoStmt *doStmt) override {
|
||||
if (auto transformed = transformDo(doStmt))
|
||||
return visit(transformed.get());
|
||||
if (auto transformed = transformDo(doStmt)) {
|
||||
return visit(transformed.get(), /*performSyntacticDiagnostics=*/false);
|
||||
}
|
||||
|
||||
auto newBody = visit(doStmt->getBody());
|
||||
if (!newBody)
|
||||
@@ -2201,6 +2206,21 @@ bool ConstraintSystem::applySolutionToBody(Solution &solution,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConjunctionElement::mightContainCodeCompletionToken(
|
||||
const ConstraintSystem &cs) const {
|
||||
if (Element->getKind() == ConstraintKind::SyntacticElement) {
|
||||
if (Element->getSyntacticElement().getSourceRange().isInvalid()) {
|
||||
return true;
|
||||
} else {
|
||||
return cs.containsIDEInspectionTarget(Element->getSyntacticElement());
|
||||
}
|
||||
} else {
|
||||
// All other constraint kinds are not handled yet. Assume that they might
|
||||
// contain the code completion token.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void ConjunctionElement::findReferencedVariables(
|
||||
ConstraintSystem &cs, SmallPtrSetImpl<TypeVariableType *> &typeVars) const {
|
||||
auto referencedVars = Element->getTypeVariables();
|
||||
|
||||
@@ -998,11 +998,6 @@ static Type replaceArchetypesWithTypeVariables(ConstraintSystem &cs,
|
||||
return found->second;
|
||||
|
||||
if (auto archetypeType = dyn_cast<ArchetypeType>(origType)) {
|
||||
// We leave opaque types and their nested associated types alone here.
|
||||
// They're globally available.
|
||||
if (isa<OpaqueTypeArchetypeType>(archetypeType))
|
||||
return origType;
|
||||
|
||||
auto root = archetypeType->getRoot();
|
||||
// For other nested types, fail here so the default logic in subst()
|
||||
// for nested types applies.
|
||||
@@ -1033,7 +1028,8 @@ static Type replaceArchetypesWithTypeVariables(ConstraintSystem &cs,
|
||||
types[origType] = replacement;
|
||||
return replacement;
|
||||
},
|
||||
MakeAbstractConformanceForGenericType());
|
||||
MakeAbstractConformanceForGenericType(),
|
||||
SubstFlags::SubstituteOpaqueArchetypes);
|
||||
}
|
||||
|
||||
bool TypeChecker::typesSatisfyConstraint(Type type1, Type type2,
|
||||
|
||||
@@ -6,7 +6,7 @@ enum Either<T,U> {
|
||||
}
|
||||
|
||||
@resultBuilder
|
||||
struct TupleBuilder { // expected-note 3 {{struct 'TupleBuilder' declared here}}
|
||||
struct TupleBuilder { // expected-note {{struct 'TupleBuilder' declared here}}
|
||||
static func buildBlock() -> () { }
|
||||
|
||||
static func buildBlock<T1>(_ t1: T1) -> T1 {
|
||||
@@ -78,7 +78,7 @@ struct TupleBuilderWithoutIf { // expected-note 3{{struct 'TupleBuilderWithoutIf
|
||||
static func buildDo<T>(_ value: T) -> T { return value }
|
||||
}
|
||||
|
||||
func tuplify<T>(_ cond: Bool, @TupleBuilder body: (Bool) -> T) { // expected-note {{in call to function 'tuplify(_:body:)'}}
|
||||
func tuplify<T>(_ cond: Bool, @TupleBuilder body: (Bool) -> T) {
|
||||
print(body(cond))
|
||||
}
|
||||
|
||||
@@ -99,15 +99,13 @@ func testDiags() {
|
||||
tuplify(true) { _ in
|
||||
17
|
||||
let x = 17
|
||||
let y: Int // expected-error{{local variable 'y' requires explicit initializer to be used with result builder 'TupleBuilder'}} {{15-15= = <#value#>}}
|
||||
let y: Int // Ok
|
||||
x + 25
|
||||
}
|
||||
|
||||
tuplify(true) { _ in
|
||||
17
|
||||
let y: Int, z: String
|
||||
// expected-error@-1 {{local variable 'y' requires explicit initializer to be used with result builder 'TupleBuilder'}} {{15-15= = <#value#>}}
|
||||
// expected-error@-2 {{local variable 'z' requires explicit initializer to be used with result builder 'TupleBuilder'}} {{26-26= = <#value#>}}
|
||||
let y: Int, z: String // Ok
|
||||
y + 25
|
||||
}
|
||||
|
||||
@@ -194,7 +192,7 @@ struct TupleP<U> : P {
|
||||
|
||||
@resultBuilder
|
||||
struct Builder {
|
||||
static func buildBlock<S0, S1>(_ stmt1: S0, _ stmt2: S1) // expected-note {{required by static method 'buildBlock' where 'S1' = 'Label<_>.Type'}}
|
||||
static func buildBlock<S0, S1>(_ stmt1: S0, _ stmt2: S1)
|
||||
-> TupleP<(S0, S1)> where S0: P, S1: P {
|
||||
return TupleP((stmt1, stmt2))
|
||||
}
|
||||
@@ -216,7 +214,7 @@ struct Label<L> : P where L : P { // expected-note 2 {{'L' declared as parameter
|
||||
}
|
||||
|
||||
func test_51167632() -> some P {
|
||||
AnyP(G { // expected-error {{type 'Label<_>.Type' cannot conform to 'P'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
|
||||
AnyP(G {
|
||||
Text("hello")
|
||||
Label // expected-error {{generic parameter 'L' could not be inferred}}
|
||||
// expected-note@-1 {{explicitly specify the generic arguments to fix this issue}} {{10-10=<<#L: P#>>}}
|
||||
@@ -509,7 +507,7 @@ enum E3 {
|
||||
}
|
||||
|
||||
func testCaseMutabilityMismatches(e: E3) {
|
||||
tuplify(true) { c in // expected-error {{generic parameter 'T' could not be inferred}}
|
||||
tuplify(true) { c in
|
||||
"testSwitch"
|
||||
switch e {
|
||||
case .a(let x, var y),
|
||||
@@ -527,12 +525,13 @@ func testCaseMutabilityMismatches(e: E3) {
|
||||
|
||||
// Check for type equivalence among different case variables with the same name.
|
||||
func testCaseVarTypes(e: E3) {
|
||||
// FIXME: Terrible diagnostic
|
||||
tuplify(true) { c in // expected-error{{type of expression is ambiguous without more context}}
|
||||
tuplify(true) { c in
|
||||
"testSwitch"
|
||||
switch e {
|
||||
case .a(let x, let y),
|
||||
.c(let x, let y):
|
||||
// expected-error@-1 {{pattern variable bound to type 'String', expected type 'Int'}}
|
||||
// expected-error@-2 {{pattern variable bound to type 'Int', expected type 'String'}}
|
||||
x
|
||||
y + "a"
|
||||
}
|
||||
@@ -659,6 +658,8 @@ struct MyView {
|
||||
}
|
||||
|
||||
@TupleBuilder var invalidCaseWithoutDot: some P {
|
||||
// expected-error@-1 {{return type of property 'invalidCaseWithoutDot' requires that 'Either<Int, Int>' conform to 'P'}}
|
||||
// expected-note@-2 {{opaque return type declared here}}
|
||||
switch Optional.some(1) {
|
||||
case none: 42 // expected-error {{cannot find 'none' in scope}}
|
||||
case .some(let x):
|
||||
@@ -666,7 +667,7 @@ struct MyView {
|
||||
}
|
||||
}
|
||||
|
||||
@TupleBuilder var invalidConversion: Int { // expected-error {{cannot convert value of type 'String' to specified type 'Int'}}
|
||||
@TupleBuilder var invalidConversion: Int { // expected-error {{cannot convert return expression of type 'String' to return type 'Int'}}
|
||||
""
|
||||
}
|
||||
}
|
||||
@@ -684,7 +685,7 @@ do {
|
||||
}
|
||||
|
||||
struct TuplifiedStructWithInvalidClosure {
|
||||
var condition: Bool
|
||||
var condition: Bool?
|
||||
|
||||
@TupleBuilder var unknownParameter: some Any {
|
||||
if let cond = condition {
|
||||
@@ -697,7 +698,7 @@ struct TuplifiedStructWithInvalidClosure {
|
||||
}
|
||||
|
||||
@TupleBuilder var unknownResult: some Any {
|
||||
if let cond = condition {
|
||||
if let _ = condition {
|
||||
let _ = { () -> UnknownType in // expected-error {{cannot find type 'UnknownType' in scope}}
|
||||
}
|
||||
42
|
||||
@@ -707,7 +708,7 @@ struct TuplifiedStructWithInvalidClosure {
|
||||
}
|
||||
|
||||
@TupleBuilder var multipleLevelsDeep: some Any {
|
||||
if let cond = condition {
|
||||
if let _ = condition {
|
||||
switch MyError.boom {
|
||||
case .boom:
|
||||
let _ = { () -> UnknownType in // expected-error {{cannot find type 'UnknownType' in scope}}
|
||||
@@ -721,7 +722,7 @@ struct TuplifiedStructWithInvalidClosure {
|
||||
}
|
||||
|
||||
@TupleBuilder var errorsDiagnosedByParser: some Any {
|
||||
if let cond = condition {
|
||||
if let _ = condition {
|
||||
tuplify { _ in
|
||||
self. // expected-error {{expected member name following '.'}}
|
||||
}
|
||||
@@ -759,9 +760,10 @@ func test_rdar65667992() {
|
||||
var entry: E
|
||||
|
||||
@Builder var body: S {
|
||||
switch entry { // expected-error {{type 'E' has no member 'unset'}}
|
||||
switch entry {
|
||||
case .set(_, _): S()
|
||||
case .unset(_): S() // expected-error {{'_' can only appear in a pattern or on the left side of an assignment}}
|
||||
case .unset(_): S() // expected-error {{type 'E' has no member 'unset'}}
|
||||
// expected-error@-1 {{'_' can only appear in a pattern or on the left side of an assignment}}
|
||||
default: S()
|
||||
}
|
||||
}
|
||||
@@ -796,7 +798,9 @@ func test_missing_member_in_optional_context() {
|
||||
if let prop = test?.prop { // expected-error {{value of type 'Test' has no member 'prop'}}
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
tuplify(true) { c in
|
||||
if let method = test?.method() { // expected-error {{value of type 'Test' has no member 'method'}}
|
||||
1
|
||||
}
|
||||
@@ -850,10 +854,10 @@ func test_invalid_result_is_diagnosed() {
|
||||
}
|
||||
}
|
||||
|
||||
struct S<T> {} // expected-note {{arguments to generic parameter 'T' ('Int' and 'String') are expected to be equal}}
|
||||
struct S<T> {}
|
||||
|
||||
@MyBuilder
|
||||
func test() -> S<String> { // expected-error {{cannot convert result builder result type 'S<Int>' to return type 'S<String>}}
|
||||
func test() -> S<String> { // expected-error {{conflicting arguments to generic parameter 'T1' ('S<Int>' vs. 'S<String>')}}
|
||||
S<Int>()
|
||||
}
|
||||
}
|
||||
@@ -887,6 +891,15 @@ func test_associated_values_dont_block_solver_when_unresolved() {
|
||||
// expected-note@-1 {{chain the optional using '?' to access member 'kind' only for non-'nil' base values}}
|
||||
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
|
||||
|
||||
switch v.kind {
|
||||
case .a(_): "a"
|
||||
case .b: "b"
|
||||
}
|
||||
}
|
||||
|
||||
@Builder var switchError: String {
|
||||
let v = container.prop!.kind
|
||||
|
||||
switch v.kind { // expected-error {{value of type 'Value.Kind' has no member 'kind'}}
|
||||
case .a(_): "a"
|
||||
case .b: "b"
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
@resultBuilder
|
||||
struct DummyBuilder { // expected-note 5 {{struct 'DummyBuilder' declared here}}
|
||||
static func buildBlock<T>(_ t: T) -> T {
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
func dummy<T>(@DummyBuilder _: () -> T) {}
|
||||
|
||||
dummy {
|
||||
var computedVar: Int { return 123 } // expected-error {{cannot declare local computed variable in result builder}}
|
||||
()
|
||||
}
|
||||
|
||||
dummy {
|
||||
lazy var lazyVar: Int = 123 // expected-error {{cannot declare local lazy variable in result builder}}
|
||||
()
|
||||
}
|
||||
|
||||
dummy {
|
||||
var observedVar: Int = 123 { // expected-error {{cannot declare local observed variable in result builder}}
|
||||
didSet {}
|
||||
}
|
||||
|
||||
()
|
||||
}
|
||||
|
||||
dummy {
|
||||
var observedVar: Int = 123 { // expected-error {{cannot declare local observed variable in result builder}}
|
||||
willSet {}
|
||||
}
|
||||
|
||||
()
|
||||
}
|
||||
|
||||
@propertyWrapper struct Wrapper {
|
||||
var wrappedValue: Int
|
||||
}
|
||||
|
||||
dummy {
|
||||
@Wrapper var wrappedVar: Int = 123 // expected-error {{cannot declare local wrapped variable in result builder}}
|
||||
()
|
||||
}
|
||||
|
||||
dummy {
|
||||
@resultBuilder var attributedVar: Int = 123 // expected-error {{@resultBuilder' attribute cannot be applied to this declaration}}
|
||||
// expected-warning@-1 {{variable 'attributedVar' was never used; consider replacing with '_' or removing it}}
|
||||
()
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
// RUN: %target-typecheck-verify-swift -debug-constraints > %t.log 2>&1
|
||||
// RUN: %FileCheck %s < %t.log
|
||||
|
||||
enum Either<T,U> {
|
||||
case first(T)
|
||||
case second(U)
|
||||
}
|
||||
|
||||
@resultBuilder
|
||||
struct TupleBuilder {
|
||||
static func buildBlock<T1>(_ t1: T1) -> T1 {
|
||||
return t1
|
||||
}
|
||||
|
||||
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
|
||||
return (t1, t2)
|
||||
}
|
||||
|
||||
static func buildBlock<T1, T2, T3>(_ t1: T1, _ t2: T2, _ t3: T3)
|
||||
-> (T1, T2, T3) {
|
||||
return (t1, t2, t3)
|
||||
}
|
||||
|
||||
static func buildBlock<T1, T2, T3, T4>(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4)
|
||||
-> (T1, T2, T3, T4) {
|
||||
return (t1, t2, t3, t4)
|
||||
}
|
||||
|
||||
static func buildBlock<T1, T2, T3, T4, T5>(
|
||||
_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5
|
||||
) -> (T1, T2, T3, T4, T5) {
|
||||
return (t1, t2, t3, t4, t5)
|
||||
}
|
||||
|
||||
static func buildDo<T>(_ value: T) -> T { return value }
|
||||
static func buildIf<T>(_ value: T?) -> T? { return value }
|
||||
|
||||
static func buildEither<T,U>(first value: T) -> Either<T,U> {
|
||||
return .first(value)
|
||||
}
|
||||
static func buildEither<T,U>(second value: U) -> Either<T,U> {
|
||||
return .second(value)
|
||||
}
|
||||
}
|
||||
|
||||
func tuplify<C: Collection, T>(_ collection: C, @TupleBuilder body: (C.Element) -> T) -> T {
|
||||
return body(collection.first!)
|
||||
}
|
||||
|
||||
// CHECK: ---Connected components---
|
||||
// CHECK-NEXT: 1: $T10 depends on 0
|
||||
// CHECK-NEXT: 0: $T1 $T2 $T3 $T5 $T6 $T7 $T8 $T82 $T83 depends on 3
|
||||
// CHECK-NEXT: 3: $T12 $T17 $T28 $T43 $T55 $T57 $T58 $T59 $T60 $T61 $T63 $T64 $T65 $T66 $T67 $T68 $T70 $T71 $T73 $T74 $T75 $T76 $T77 $T78 $T79 $T80 $T81 depends on 2, 4, 5, 7, 10
|
||||
// CHECK-NEXT: 10: $T49 $T51 $T52 $T53 $T54 depends on 9
|
||||
// CHECK-NEXT: 9: $T44 $T45 $T46 $T47 $T48
|
||||
// CHECK-NEXT: 7: $T31 $T35 $T37 $T38 $T39 $T40 $T41 $T42 depends on 6, 8
|
||||
// CHECK-NEXT: 8: $T32 $T33 $T34
|
||||
// CHECK-NEXT: 6: $T30
|
||||
// CHECK-NEXT: 5: $T18 $T19 $T20 $T21 $T22 $T23 $T24 $T25 $T26 $T27
|
||||
// CHECK-NEXT: 4: $T15 $T16
|
||||
// CHECK-NEXT: 2: $T11
|
||||
let names = ["Alice", "Bob", "Charlie"]
|
||||
let b = true
|
||||
var number = 17
|
||||
print(
|
||||
tuplify(names) { name in
|
||||
17
|
||||
number
|
||||
"Hello, \(name)"
|
||||
tuplify(["a", "b"]) { value in
|
||||
value.first!
|
||||
}
|
||||
if b {
|
||||
2.71828
|
||||
["if", "stmt"]
|
||||
} else {
|
||||
[1, 2, 3, 17]
|
||||
}
|
||||
})
|
||||
54
test/Constraints/result_builder_vars.swift
Normal file
54
test/Constraints/result_builder_vars.swift
Normal file
@@ -0,0 +1,54 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
@resultBuilder
|
||||
struct DummyBuilder {
|
||||
static func buildBlock<T>(_ t: T) -> T {
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
func dummy<T>(@DummyBuilder _: () -> T) {}
|
||||
|
||||
dummy {
|
||||
var computedVar: Int { return 123 }
|
||||
()
|
||||
}
|
||||
|
||||
dummy {
|
||||
lazy var lazyVar: Int = 123
|
||||
()
|
||||
}
|
||||
|
||||
dummy {
|
||||
var observedVar: Int = 123 {
|
||||
// expected-warning@-1 {{variable 'observedVar' was never used; consider replacing with '_' or removing it}}
|
||||
didSet {}
|
||||
}
|
||||
|
||||
()
|
||||
}
|
||||
|
||||
dummy {
|
||||
var observedVar: Int = 123 {
|
||||
// expected-warning@-1 {{variable 'observedVar' was never used; consider replacing with '_' or removing it}}
|
||||
willSet {}
|
||||
}
|
||||
|
||||
()
|
||||
}
|
||||
|
||||
@propertyWrapper struct Wrapper {
|
||||
var wrappedValue: Int
|
||||
}
|
||||
|
||||
dummy {
|
||||
@Wrapper var wrappedVar: Int = 123
|
||||
()
|
||||
}
|
||||
|
||||
dummy {
|
||||
@resultBuilder var attributedVar: Int = 123
|
||||
// expected-error@-1 {{'@resultBuilder' attribute cannot be applied to this declaration}}
|
||||
// expected-warning@-2 {{variable 'attributedVar' was never used; consider replacing with '_' or removing it}}
|
||||
()
|
||||
}
|
||||
@@ -184,7 +184,7 @@ func testAmbiguousResultBuilder() {
|
||||
// Results should only contain globalVar once
|
||||
// AMBIGOUS_RESULT_BUILER: Begin completions
|
||||
// AMBIGOUS_RESULT_BUILER-NOT: globalVar
|
||||
// AMBIGOUS_RESULT_BUILER-DAG: Decl[GlobalVar]/OtherModule[foo_swift_module]: globalVar[#Int#]; name=globalVar
|
||||
// AMBIGOUS_RESULT_BUILER-DAG: Decl[GlobalVar]/OtherModule[foo_swift_module]/TypeRelation[Convertible]: globalVar[#Int#]; name=globalVar
|
||||
// AMBIGOUS_RESULT_BUILER-NOT: globalVar
|
||||
// AMBIGOUS_RESULT_BUILER: End completions
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func testGlobalLookup() {
|
||||
@TupleBuilder<String> var x1 {
|
||||
#^GLOBAL_LOOKUP^#
|
||||
// GLOBAL_LOOKUP: Begin completions
|
||||
// GLOBAL_LOOKUP: Decl[GlobalVar]/CurrModule/TypeRelation[Convertible]: MyConstantString[#String#];
|
||||
// GLOBAL_LOOKUP: Decl[GlobalVar]/CurrModule/TypeRelation[Convertible]: MyConstantString[#String#]; name=MyConstantString
|
||||
// GLOBAL_LOOKUP: End completions
|
||||
}
|
||||
|
||||
@@ -81,6 +81,8 @@ func testStaticMemberLookup() {
|
||||
@TupleBuilder<String> var x1 {
|
||||
StringFactory.#^COMPLETE_STATIC_MEMBER^#
|
||||
// COMPLETE_STATIC_MEMBER: Begin completions
|
||||
// COMPLETE_STATIC_MEMBER: Keyword[self]/CurrNominal: self[#StringFactory.Type#]; name=self
|
||||
// COMPLETE_STATIC_MEMBER: Keyword/CurrNominal: Type[#StringFactory.Type#]; name=Type
|
||||
// COMPLETE_STATIC_MEMBER: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: makeString({#x: String#})[#String#];
|
||||
// COMPLETE_STATIC_MEMBER: End completions
|
||||
}
|
||||
@@ -248,3 +250,27 @@ func testTypeRelationInResultBuilder() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testAmbiguousInResultBuilder() {
|
||||
@resultBuilder
|
||||
struct MyViewBuilder {
|
||||
static func buildBlock(_ x: Int) -> Int { return x }
|
||||
}
|
||||
|
||||
struct QStack {
|
||||
init(@MyViewBuilder content: () -> Int) {}
|
||||
}
|
||||
|
||||
struct Foo {
|
||||
func qtroke(_ content: Int, style: Int) -> Int { return 1 }
|
||||
func qtroke(_ content: Int, lineWidth: Int = 1) -> Int { return 2 }
|
||||
}
|
||||
|
||||
QStack {
|
||||
Foo().qtroke(0, #^AMBIGUOUS_IN_RESULT_BUILDER^#)
|
||||
// AMBIGUOUS_IN_RESULT_BUILDER: Begin completions, 2 items
|
||||
// AMBIGUOUS_IN_RESULT_BUILDER-DAG: Pattern/Local/Flair[ArgLabels]: {#style: Int#}[#Int#];
|
||||
// AMBIGUOUS_IN_RESULT_BUILDER-DAG: Pattern/Local/Flair[ArgLabels]: {#lineWidth: Int#}[#Int#];
|
||||
// AMBIGUOUS_IN_RESULT_BUILDER: End completions
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,5 +39,5 @@ public struct ForEach2<Data, ID, Content>: View2 where Data : RandomAccessCollec
|
||||
|
||||
// CHECK: Begin completions, 2 items
|
||||
// CHECK-NEXT: Keyword[self]/CurrNominal: self[#Text2#];
|
||||
// CHECK-NEXT: Decl[InstanceMethod]/Super: font()[#View2#];
|
||||
// CHECK-NEXT: Decl[InstanceMethod]/Super/TypeRelation[Convertible]: font()[#View2#];
|
||||
// CHECK-NEXT: End completions
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token COMPLETE | %FileCheck %s
|
||||
|
||||
protocol View {}
|
||||
|
||||
@resultBuilder
|
||||
struct ViewBuilder {
|
||||
static func buildBlock(_ component: MyView) -> MyView {
|
||||
MyView()
|
||||
}
|
||||
}
|
||||
|
||||
struct QStack<Content> {
|
||||
init(@ViewBuilder content: () -> Content) {}
|
||||
|
||||
func qheet<Content>(@ViewBuilder content: @escaping () -> Content) -> some View {
|
||||
MyView()
|
||||
}
|
||||
}
|
||||
|
||||
struct MyView : View {
|
||||
func qag<V>(_ tag: V) -> MyView {
|
||||
MyView()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func foo() {
|
||||
QStack {
|
||||
// When solving for code completion, the constraint system doesn't increase the score for non-default literals.
|
||||
// This causes ambiguous results for this qag call if it's type checked for code completion, preventing results from showing up at the code completion token.
|
||||
// Solution is to do normal type checking for syntactic elements that don't contain the code completion token.
|
||||
MyView().qag(0)
|
||||
}
|
||||
.qheet() {
|
||||
MyView().#^COMPLETE^#
|
||||
}
|
||||
}
|
||||
// CHECK: Begin completions, 2 items
|
||||
// CHECK-DAG: Keyword[self]/CurrNominal: self[#MyView#];
|
||||
// CHECK-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Convertible]: qag({#(tag): V#})[#MyView#];
|
||||
// CHECK: End completions
|
||||
@@ -137,15 +137,14 @@ func testGenericReturn<T: MyProto>() -> T {
|
||||
return #^GENERIC_RETURN^#
|
||||
}
|
||||
|
||||
// FIXME: We don't support USR-based type comparison in generic contexts. MyProto, returnMyProto, makeFoo and FooBar should be 'Convertible'
|
||||
// GENERIC_RETURN: Begin completions
|
||||
// GENERIC_RETURN-DAG: Decl[Struct]/OtherModule[Lib]: Foo[#Foo#];
|
||||
// GENERIC_RETURN-DAG: Decl[GlobalVar]/OtherModule[Lib]: GLOBAL_FOO[#Foo#];
|
||||
// GENERIC_RETURN-DAG: Decl[Struct]/OtherModule[Lib]/TypeRelation[Convertible]: Foo[#Foo#];
|
||||
// GENERIC_RETURN-DAG: Decl[GlobalVar]/OtherModule[Lib]/TypeRelation[Convertible]: GLOBAL_FOO[#Foo#];
|
||||
// GENERIC_RETURN-DAG: Decl[Struct]/OtherModule[Lib]: Bar[#Bar#];
|
||||
// GENERIC_RETURN-DAG: Decl[Protocol]/OtherModule[Lib]/Flair[RareType]: MyProto[#MyProto#];
|
||||
// GENERIC_RETURN-DAG: Decl[FreeFunction]/OtherModule[Lib]: makeFoo()[#Foo#];
|
||||
// GENERIC_RETURN-DAG: Decl[Struct]/OtherModule[Lib]: FooBar[#FooBar#];
|
||||
// GENERIC_RETURN-DAG: Decl[FreeFunction]/OtherModule[Lib]: returnSomeMyProto()[#MyProto#];
|
||||
// GENERIC_RETURN-DAG: Decl[Protocol]/OtherModule[Lib]/Flair[RareType]/TypeRelation[Convertible]: MyProto[#MyProto#];
|
||||
// GENERIC_RETURN-DAG: Decl[FreeFunction]/OtherModule[Lib]/TypeRelation[Convertible]: makeFoo()[#Foo#];
|
||||
// GENERIC_RETURN-DAG: Decl[Struct]/OtherModule[Lib]/TypeRelation[Convertible]: FooBar[#FooBar#];
|
||||
// GENERIC_RETURN-DAG: Decl[FreeFunction]/OtherModule[Lib]/TypeRelation[Convertible]: returnSomeMyProto()[#MyProto#];
|
||||
// GENERIC_RETURN: End completions
|
||||
|
||||
// RUN: %empty-directory(%t/completion-cache)
|
||||
@@ -220,9 +219,9 @@ func protoWithAssocTypeInGenericContext<T: ProtoWithAssocType>() -> T {
|
||||
}
|
||||
|
||||
// PROTO_WITH_ASSOC_TYPE_GENERIC_RETURN_CONTEXT: Begin completions
|
||||
// PROTO_WITH_ASSOC_TYPE_GENERIC_RETURN_CONTEXT-DAG: Decl[Struct]/OtherModule[Lib]: StructWithAssocType[#StructWithAssocType#];
|
||||
// PROTO_WITH_ASSOC_TYPE_GENERIC_RETURN_CONTEXT-DAG: Decl[FreeFunction]/OtherModule[Lib]: makeProtoWithAssocType()[#ProtoWithAssocType#];
|
||||
// PROTO_WITH_ASSOC_TYPE_GENERIC_RETURN_CONTEXT-DAG: Decl[Protocol]/OtherModule[Lib]/Flair[RareType]: ProtoWithAssocType[#ProtoWithAssocType#];
|
||||
// PROTO_WITH_ASSOC_TYPE_GENERIC_RETURN_CONTEXT-DAG: Decl[Struct]/OtherModule[Lib]/TypeRelation[Convertible]: StructWithAssocType[#StructWithAssocType#];
|
||||
// PROTO_WITH_ASSOC_TYPE_GENERIC_RETURN_CONTEXT-DAG: Decl[FreeFunction]/OtherModule[Lib]/TypeRelation[Convertible]: makeProtoWithAssocType()[#ProtoWithAssocType#];
|
||||
// PROTO_WITH_ASSOC_TYPE_GENERIC_RETURN_CONTEXT-DAG: Decl[Protocol]/OtherModule[Lib]/Flair[RareType]/TypeRelation[Convertible]: ProtoWithAssocType[#ProtoWithAssocType#];
|
||||
// PROTO_WITH_ASSOC_TYPE_GENERIC_RETURN_CONTEXT: End completions
|
||||
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ class TestResultBuilder {
|
||||
// CHECK: closure_expr type='() -> ConcreteP'
|
||||
takesBuilder {
|
||||
// CHECK: return_stmt
|
||||
// CHECK-NEXT: load_expr implicit type='ConcreteP'
|
||||
// CHECK-NEXT: call_expr implicit type='ConcreteP'
|
||||
ConcreteP()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,11 @@
|
||||
import RegexBuilder
|
||||
|
||||
extension Regex where Output == Substring {
|
||||
init(_ x: String) {} // expected-note {{'init(_:)' declared here}}
|
||||
init(_ x: String) {}
|
||||
}
|
||||
|
||||
func foo() {
|
||||
// FIXME: This diagnostic could probably be better, it's not clear we should
|
||||
// be resolving to init(_ x: String) vs the result builder API and diagnosing
|
||||
// the fact that Int isn't a RegexComponent.
|
||||
_ = Regex { // expected-error {{trailing closure passed to parameter of type 'String' that does not accept a closure}}
|
||||
0
|
||||
_ = Regex {
|
||||
0 // expected-error {{static method 'buildExpression' requires that 'Int' conform to 'RegexComponent'}}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,6 @@ struct SplitView: View2 {
|
||||
}
|
||||
|
||||
// COMPLETE: Begin completions
|
||||
// COMPLETE-DAG: Decl[InstanceMethod]/Super: frame()[#Never#]; name=frame()
|
||||
// COMPLETE-DAG: Decl[InstanceMethod]/Super: frame({#width: Int?#}, {#height: Int?#})[#Never#]; name=frame(width:height:)
|
||||
// COMPLETE-DAG: Decl[InstanceMethod]/Super/TypeRelation[Convertible]: frame()[#Never#]; name=frame()
|
||||
// COMPLETE-DAG: Decl[InstanceMethod]/Super/TypeRelation[Convertible]: frame({#width: Int?#}, {#height: Int?#})[#Never#]; name=frame(width:height:)
|
||||
// COMPLETE: End completions
|
||||
|
||||
@@ -16,7 +16,6 @@ struct ContentView: View {
|
||||
DatePicker("Enter a date", selection: $date, displayedComponents: .date, in: Date())
|
||||
// expected-error@-1 {{argument 'in' must precede argument 'displayedComponents'}} {{78-90=}} {{52-52=in: Date(), }}
|
||||
DatePicker("Enter a date", selection: $date, displayedComponents: .date, in: Date() ... Date().addingTimeInterval(100))
|
||||
// expected-error@-1 {{argument 'in' must precede argument 'displayedComponents'}} {{78-125=}} {{52-52=in: Date() ... Date().addingTimeInterval(100), }}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,13 @@ import SwiftUI
|
||||
|
||||
struct Experiment: View {
|
||||
var body: some View {
|
||||
HStack { // expected-error {{generic parameter 'Content' could not be inferred}} expected-note {{explicitly specify the generic arguments to fix this issue}}emacs
|
||||
HStack {
|
||||
Slider(value: <#T##Binding<BinaryFloatingPoint>#>, in: <#T##ClosedRange<BinaryFloatingPoint>#>, label: <#T##() -> _#>) // expected-error 3 {{editor placeholder in source file}}
|
||||
// expected-error@-1 {{type 'any BinaryFloatingPoint' cannot conform to 'Comparable'}}
|
||||
// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}}
|
||||
// expected-error@-3 {{type 'any BinaryFloatingPoint' cannot conform to 'BinaryFloatingPoint'}}
|
||||
// expected-note@-4 {{only concrete types such as structs, enums and classes can conform to protocols}}
|
||||
// expected-note@-5 {{required by initializer 'init(value:in:label:onEditingChanged:)' where 'V' = 'any BinaryFloatingPoint'}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ struct MyView : View {
|
||||
switch (status) {
|
||||
case .complete:
|
||||
ForEach(items, id: \.self) { item in
|
||||
if let question = item.question,
|
||||
let answer = item.answer {
|
||||
if let question = item.question, // expected-error {{initializer for conditional binding must have Optional type, not 'String'}}
|
||||
let answer = item.answer { // expected-error {{initializer for conditional binding must have Optional type, not 'Int'}}
|
||||
ItemView {
|
||||
currItem.question = question
|
||||
currItem.answer = answer
|
||||
|
||||
@@ -22,7 +22,7 @@ struct S : View {
|
||||
EmptyView()
|
||||
}
|
||||
|
||||
if (check(self.test)) { // expected-error {{cannot convert value of type 'E' to expected argument type 'String'}} {{26-26=.rawValue}}
|
||||
if (check(self.test)) {
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ struct MyView: View {
|
||||
|
||||
var body: some View {
|
||||
Table(self.data) {
|
||||
// expected-error@-1 {{cannot infer return type of empty closure}} {{23-23=<#result#>}}
|
||||
// expected-error@-1 {{missing argument for parameter #1 in call}}
|
||||
// expected-error@-2 {{cannot infer return type of empty closure}} {{23-23=<#result#>}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ struct Generic<T> {
|
||||
|
||||
@resultBuilder
|
||||
struct Builder {
|
||||
static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) // expected-note 2 {{where 'C0' = 'Empty'}} expected-note {{where 'C1' = 'Test<Generic<(Empty, _)>>'}}
|
||||
static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) // expected-note {{where 'C0' = 'Empty'}}
|
||||
// expected-note@-1 {{'buildBlock' declared here}}
|
||||
-> Generic<(C0, C1)> where C0 : P, C1 : P {
|
||||
return Generic((c0, c1))
|
||||
@@ -30,8 +30,6 @@ struct Test<T> where T : P { // expected-note {{where 'T' = 'Generic<(Empty, _)>
|
||||
}
|
||||
|
||||
let x = G {
|
||||
// expected-error@-1 {{static method 'buildBlock' requires that 'Empty' conform to 'P'}}
|
||||
// expected-error@-2 {{static method 'buildBlock' requires that 'Test<Generic<(Empty, _)>>' conform to 'P'}}
|
||||
Empty()
|
||||
Test { Empty() }
|
||||
// expected-error@-1 {{static method 'buildBlock' requires that 'Empty' conform to 'P'}}
|
||||
|
||||
@@ -7,9 +7,9 @@ struct S {
|
||||
private func f() {}
|
||||
|
||||
func test() {
|
||||
// expected-error@+1 {{static method 'buildBlock' requires that 'ForEach<[String], ()>' conform to 'View'}}
|
||||
ForEach(data) { group in
|
||||
ForEach(group) { month in
|
||||
ForEach(group) { month in // expected-error {{type '()' cannot conform to 'View'}}
|
||||
// expected-note@-1 {{only concrete types such as structs, enums and classes can conform to protocols}}
|
||||
self.f()
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ struct Wrapper<T> {}
|
||||
protocol View {}
|
||||
|
||||
@resultBuilder struct Builder {
|
||||
// expected-note@+1 {{where 'Content' = 'ForEach<[String], ()>'}}
|
||||
// expected-note@+1 {{required by static method 'buildBlock' where 'Content' = '()'}}
|
||||
static func buildBlock<Content: View>(_ content: Content) -> Content { fatalError() }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user