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:
Pavel Yaskevich
2023-01-03 00:55:43 -08:00
committed by GitHub
30 changed files with 263 additions and 212 deletions

View File

@@ -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();
}

View File

@@ -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)

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -1529,6 +1529,7 @@ PatternBindingDecl *PatternBindingDecl::createImplicit(
Pat, /*EqualLoc*/ SourceLoc(), nullptr, Parent);
Result->setImplicit();
Result->setInit(0, E);
Result->setOriginalInit(0, E);
return Result;
}

View File

@@ -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;
}

View File

@@ -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';
}

View File

@@ -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.

View File

@@ -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)

View File

@@ -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();

View File

@@ -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,

View File

@@ -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"

View File

@@ -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}}
()
}

View File

@@ -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]
}
})

View 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}}
()
}

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()
}
}

View File

@@ -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'}}
}
}

View File

@@ -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

View File

@@ -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), }}
}
}
}

View File

@@ -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'}}
}
}
}

View File

@@ -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

View File

@@ -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()
}
}

View File

@@ -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#>}}
}
}
}

View File

@@ -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'}}

View File

@@ -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() }
}