Skip to content

[Result Builders] Correct type witness substitution when computing inferred result builder attributes from protocol requirements. #39988

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions lib/Sema/TypeCheckRequestFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,17 @@ static Type inferResultBuilderType(ValueDecl *decl) {
if (witness != lookupDecl)
continue;

// Substitute into the result builder type.
auto subs =
conformance->getSubstitutions(lookupDecl->getModuleContext());
Type subResultBuilderType = resultBuilderType.subst(subs);
// Substitute Self and associated type witnesses into the
// result builder type. Then, map all type parameters from
// the conforming type into context. We don't want type
// parameters to appear in the result builder type, because
// the result builder type will only be used inside the body
// of this decl; it's not part of the interface type.
auto subs = SubstitutionMap::getProtocolSubstitutions(
protocol, dc->getSelfInterfaceType(),
ProtocolConformanceRef(conformance));
Type subResultBuilderType = dc->mapTypeIntoContext(
resultBuilderType.subst(subs));

matches.push_back(
Match::forConformance(
Expand Down
57 changes: 57 additions & 0 deletions test/Constraints/result_builder_generic_infer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// RUN: %target-swift-frontend -dump-ast %s | %FileCheck %s

protocol P {
associatedtype A

@Builder<A>
var x1: [S] { get }

@Builder<Self>
var x2: [S] { get }
}

@resultBuilder
enum Builder<T> {
static func buildBlock(_ args: S...) -> [S] { args }
}

struct S {}

// CHECK: struct_decl{{.*}}ProtocolSubstitution
struct ProtocolSubstitution: P {
typealias A = Int

// CHECK: var_decl{{.*}}x1
// CHECK: Builder.buildBlock{{.*}}(substitution_map generic_signature=<T> (substitution T -> Int))
var x1: [S] { S() }

// CHECK: var_decl{{.*}}x2
// CHECK: Builder.buildBlock{{.*}}(substitution_map generic_signature=<T> (substitution T -> ProtocolSubstitution))
var x2: [S] { S() }
}

// CHECK: struct_decl{{.*}}ArchetypeSubstitution
struct ArchetypeSubstitution<A>: P {
// CHECK: var_decl{{.*}}x1
// CHECK: Builder.buildBlock{{.*}}(substitution_map generic_signature=<T> (substitution T -> A))
var x1: [S] { S() }

// CHECK: var_decl{{.*}}x2
// CHECK: Builder.buildBlock{{.*}}(substitution_map generic_signature=<T> (substitution T -> ArchetypeSubstitution<A>))
var x2: [S] { S() }
}

// CHECK: struct_decl{{.*}}ConcreteTypeSubstitution
struct ConcreteTypeSubstitution<Value> {}

extension ConcreteTypeSubstitution: P where Value == Int {
typealias A = Value

// CHECK: var_decl{{.*}}x1
// CHECK: Builder.buildBlock{{.*}}(substitution_map generic_signature=<T> (substitution T -> Int))
var x1: [S] { S() }

// CHECK: var_decl{{.*}}x2
// CHECK: Builder.buildBlock{{.*}}(substitution_map generic_signature=<T> (substitution T -> ConcreteTypeSubstitution<Int>))
var x2: [S] { S() }
}